Coverage Report

Created: 2023-09-25 06:05

/src/e2fsprogs/lib/ext2fs/fallocate.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * fallocate.c -- Allocate large chunks of file.
3
 *
4
 * Copyright (C) 2014 Oracle.
5
 *
6
 * %Begin-Header%
7
 * This file may be redistributed under the terms of the GNU Library
8
 * General Public License, version 2.
9
 * %End-Header%
10
 */
11
12
#include "config.h"
13
14
#if HAVE_SYS_TYPES_H
15
#include <sys/types.h>
16
#endif
17
18
#include "ext2_fs.h"
19
#include "ext2fs.h"
20
0
#define min(a, b) ((a) < (b) ? (a) : (b))
21
22
#undef DEBUG
23
24
#ifdef DEBUG
25
# define dbg_printf(f, a...)  do {printf(f, ## a); fflush(stdout); } while (0)
26
#else
27
# define dbg_printf(f, a...)
28
#endif
29
30
/*
31
 * Extent-based fallocate code.
32
 *
33
 * Find runs of unmapped logical blocks by starting at start and walking the
34
 * extents until we reach the end of the range we want.
35
 *
36
 * For each run of unmapped blocks, try to find the extents on either side of
37
 * the range.  If there's a left extent that can grow by at least a cluster and
38
 * there are lblocks between start and the next lcluster after start, see if
39
 * there's an implied cluster allocation; if so, zero the blocks (if the left
40
 * extent is initialized) and adjust the extent.  Ditto for the blocks between
41
 * the end of the last full lcluster and end, if there's a right extent.
42
 *
43
 * Try to attach as much as we can to the left extent, then try to attach as
44
 * much as we can to the right extent.  For the remainder, try to allocate the
45
 * whole range; map in whatever we get; and repeat until we're done.
46
 *
47
 * To attach to a left extent, figure out the maximum amount we can add to the
48
 * extent and try to allocate that much, and append if successful.  To attach
49
 * to a right extent, figure out the max we can add to the extent, try to
50
 * allocate that much, and prepend if successful.
51
 *
52
 * We need an alloc_range function that tells us how much we can allocate given
53
 * a maximum length and one of a suggested start, a fixed start, or a fixed end
54
 * point.
55
 *
56
 * Every time we modify the extent tree we also need to update the block stats.
57
 *
58
 * At the end, update i_blocks and i_size appropriately.
59
 */
60
61
static void dbg_print_extent(const char *desc EXT2FS_ATTR((unused)),
62
    const struct ext2fs_extent *extent EXT2FS_ATTR((unused)))
63
0
{
64
#ifdef DEBUG
65
  if (desc)
66
    printf("%s: ", desc);
67
  printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
68
         extent->e_lblk, extent->e_lblk + extent->e_len - 1,
69
         extent->e_len, extent->e_pblk);
70
  if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
71
    fputs("LEAF ", stdout);
72
  if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
73
    fputs("UNINIT ", stdout);
74
  if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
75
    fputs("2ND_VISIT ", stdout);
76
  if (!extent->e_flags)
77
    fputs("(none)", stdout);
78
  fputc('\n', stdout);
79
  fflush(stdout);
80
#endif
81
0
}
82
83
static errcode_t claim_range(ext2_filsys fs, struct ext2_inode *inode,
84
           blk64_t blk, blk64_t len)
85
0
{
86
0
  blk64_t clusters;
87
88
0
  clusters = (len + EXT2FS_CLUSTER_RATIO(fs) - 1) /
89
0
       EXT2FS_CLUSTER_RATIO(fs);
90
0
  ext2fs_block_alloc_stats_range(fs, blk,
91
0
      clusters * EXT2FS_CLUSTER_RATIO(fs), +1);
92
0
  return ext2fs_iblk_add_blocks(fs, inode, clusters);
93
0
}
94
95
static errcode_t ext_falloc_helper(ext2_filsys fs,
96
           int flags,
97
           ext2_ino_t ino,
98
           struct ext2_inode *inode,
99
           ext2_extent_handle_t handle,
100
           struct ext2fs_extent *left_ext,
101
           struct ext2fs_extent *right_ext,
102
           blk64_t range_start, blk64_t range_len,
103
           blk64_t alloc_goal)
104
0
{
105
0
  struct ext2fs_extent  newex, ex;
106
0
  int     op;
107
0
  blk64_t     fillable, pblk, plen, x, y;
108
0
  blk64_t     eof_blk = 0, cluster_fill = 0;
109
0
  errcode_t   err;
110
0
  blk_t     max_extent_len, max_uninit_len, max_init_len;
111
112
#ifdef DEBUG
113
  printf("%s: ", __func__);
114
  if (left_ext)
115
    printf("left_ext=%llu--%llu, ", left_ext->e_lblk,
116
           left_ext->e_lblk + left_ext->e_len - 1);
117
  if (right_ext)
118
    printf("right_ext=%llu--%llu, ", right_ext->e_lblk,
119
           right_ext->e_lblk + right_ext->e_len - 1);
120
  printf("start=%llu len=%llu, goal=%llu\n", range_start, range_len,
121
         alloc_goal);
122
  fflush(stdout);
123
#endif
124
  /* Can't create initialized extents past EOF? */
125
0
  if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF))
126
0
    eof_blk = EXT2_I_SIZE(inode) / fs->blocksize;
127
128
  /* The allocation goal must be as far into a cluster as range_start. */
129
0
  alloc_goal = (alloc_goal & ~EXT2FS_CLUSTER_MASK(fs)) |
130
0
         (range_start & EXT2FS_CLUSTER_MASK(fs));
131
132
0
  max_uninit_len = EXT_UNINIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs);
133
0
  max_init_len = EXT_INIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs);
134
135
  /* We must lengthen the left extent to the end of the cluster */
136
0
  if (left_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) {
137
    /* How many more blocks can be attached to left_ext? */
138
0
    if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
139
0
      fillable = max_uninit_len - left_ext->e_len;
140
0
    else
141
0
      fillable = max_init_len - left_ext->e_len;
142
143
0
    if (fillable > range_len)
144
0
      fillable = range_len;
145
0
    if (fillable == 0)
146
0
      goto expand_right;
147
148
    /*
149
     * If range_start isn't on a cluster boundary, try an
150
     * implied cluster allocation for left_ext.
151
     */
152
0
    cluster_fill = EXT2FS_CLUSTER_RATIO(fs) -
153
0
             (range_start & EXT2FS_CLUSTER_MASK(fs));
154
0
    cluster_fill &= EXT2FS_CLUSTER_MASK(fs);
155
0
    if (cluster_fill == 0)
156
0
      goto expand_right;
157
158
0
    if (cluster_fill > fillable)
159
0
      cluster_fill = fillable;
160
161
    /* Don't expand an initialized left_ext beyond EOF */
162
0
    if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) {
163
0
      x = left_ext->e_lblk + left_ext->e_len - 1;
164
0
      dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n",
165
0
           __func__, x, x + cluster_fill, eof_blk);
166
0
      if (eof_blk >= x && eof_blk <= x + cluster_fill)
167
0
        cluster_fill = eof_blk - x;
168
0
      if (cluster_fill == 0)
169
0
        goto expand_right;
170
0
    }
171
172
0
    err = ext2fs_extent_goto(handle, left_ext->e_lblk);
173
0
    if (err)
174
0
      goto expand_right;
175
0
    left_ext->e_len += cluster_fill;
176
0
    range_start += cluster_fill;
177
0
    range_len -= cluster_fill;
178
0
    alloc_goal += cluster_fill;
179
180
0
    dbg_print_extent("ext_falloc clus left+", left_ext);
181
0
    err = ext2fs_extent_replace(handle, 0, left_ext);
182
0
    if (err)
183
0
      goto out;
184
0
    err = ext2fs_extent_fix_parents(handle);
185
0
    if (err)
186
0
      goto out;
187
188
    /* Zero blocks */
189
0
    if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) {
190
0
      err = ext2fs_zero_blocks2(fs, left_ext->e_pblk +
191
0
              left_ext->e_len -
192
0
              cluster_fill, cluster_fill,
193
0
              NULL, NULL);
194
0
      if (err)
195
0
        goto out;
196
0
    }
197
0
  }
198
199
0
expand_right:
200
  /* We must lengthen the right extent to the beginning of the cluster */
201
0
  if (right_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) {
202
    /* How much can we attach to right_ext? */
203
0
    if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
204
0
      fillable = max_uninit_len - right_ext->e_len;
205
0
    else
206
0
      fillable = max_init_len - right_ext->e_len;
207
208
0
    if (fillable > range_len)
209
0
      fillable = range_len;
210
0
    if (fillable == 0)
211
0
      goto try_merge;
212
213
    /*
214
     * If range_end isn't on a cluster boundary, try an implied
215
     * cluster allocation for right_ext.
216
     */
217
0
    cluster_fill = right_ext->e_lblk & EXT2FS_CLUSTER_MASK(fs);
218
0
    if (cluster_fill == 0)
219
0
      goto try_merge;
220
221
0
    err = ext2fs_extent_goto(handle, right_ext->e_lblk);
222
0
    if (err)
223
0
      goto out;
224
225
0
    if (cluster_fill > fillable)
226
0
      cluster_fill = fillable;
227
0
    right_ext->e_lblk -= cluster_fill;
228
0
    right_ext->e_pblk -= cluster_fill;
229
0
    right_ext->e_len += cluster_fill;
230
0
    range_len -= cluster_fill;
231
232
0
    dbg_print_extent("ext_falloc clus right+", right_ext);
233
0
    err = ext2fs_extent_replace(handle, 0, right_ext);
234
0
    if (err)
235
0
      goto out;
236
0
    err = ext2fs_extent_fix_parents(handle);
237
0
    if (err)
238
0
      goto out;
239
240
    /* Zero blocks if necessary */
241
0
    if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) {
242
0
      err = ext2fs_zero_blocks2(fs, right_ext->e_pblk,
243
0
              cluster_fill, NULL, NULL);
244
0
      if (err)
245
0
        goto out;
246
0
    }
247
0
  }
248
249
0
try_merge:
250
  /* Merge both extents together, perhaps? */
251
0
  if (left_ext && right_ext) {
252
    /* Are the two extents mergeable? */
253
0
    if ((left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) !=
254
0
        (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))
255
0
      goto try_left;
256
257
    /* User requires init/uninit but extent is uninit/init. */
258
0
    if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
259
0
         (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
260
0
        ((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
261
0
         !(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
262
0
      goto try_left;
263
264
    /*
265
     * Skip initialized extent unless user wants to zero blocks
266
     * or requires init extent.
267
     */
268
0
    if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
269
0
        (!(flags & EXT2_FALLOCATE_ZERO_BLOCKS) ||
270
0
         !(flags & EXT2_FALLOCATE_FORCE_INIT)))
271
0
      goto try_left;
272
273
    /* Will it even fit? */
274
0
    x = left_ext->e_len + range_len + right_ext->e_len;
275
0
    if (x > (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT ?
276
0
        max_uninit_len : max_init_len))
277
0
      goto try_left;
278
279
0
    err = ext2fs_extent_goto(handle, left_ext->e_lblk);
280
0
    if (err)
281
0
      goto try_left;
282
283
    /* Allocate blocks */
284
0
    y = left_ext->e_pblk + left_ext->e_len;
285
0
    err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
286
0
               EXT2_NEWRANGE_MIN_LENGTH, y,
287
0
               right_ext->e_pblk - y + 1, NULL,
288
0
               &pblk, &plen);
289
0
    if (err)
290
0
      goto try_left;
291
0
    if (pblk + plen != right_ext->e_pblk)
292
0
      goto try_left;
293
0
    err = claim_range(fs, inode, pblk, plen);
294
0
    if (err)
295
0
      goto out;
296
297
    /* Modify extents */
298
0
    left_ext->e_len = x;
299
0
    dbg_print_extent("ext_falloc merge", left_ext);
300
0
    err = ext2fs_extent_replace(handle, 0, left_ext);
301
0
    if (err)
302
0
      goto out;
303
0
    err = ext2fs_extent_fix_parents(handle);
304
0
    if (err)
305
0
      goto out;
306
0
    err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &newex);
307
0
    if (err)
308
0
      goto out;
309
0
    err = ext2fs_extent_delete(handle, 0);
310
0
    if (err)
311
0
      goto out;
312
0
    err = ext2fs_extent_fix_parents(handle);
313
0
    if (err)
314
0
      goto out;
315
0
    *right_ext = *left_ext;
316
317
    /* Zero blocks */
318
0
    if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
319
0
        (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
320
0
      err = ext2fs_zero_blocks2(fs, range_start, range_len,
321
0
              NULL, NULL);
322
0
      if (err)
323
0
        goto out;
324
0
    }
325
326
0
    return 0;
327
0
  }
328
329
0
try_left:
330
  /* Extend the left extent */
331
0
  if (left_ext) {
332
    /* How many more blocks can be attached to left_ext? */
333
0
    if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
334
0
      fillable = max_uninit_len - left_ext->e_len;
335
0
    else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS)
336
0
      fillable = max_init_len - left_ext->e_len;
337
0
    else
338
0
      fillable = 0;
339
340
    /* User requires init/uninit but extent is uninit/init. */
341
0
    if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
342
0
         (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
343
0
        ((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
344
0
         !(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
345
0
      goto try_right;
346
347
0
    if (fillable > range_len)
348
0
      fillable = range_len;
349
350
    /* Don't expand an initialized left_ext beyond EOF */
351
0
    x = left_ext->e_lblk + left_ext->e_len - 1;
352
0
    if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) {
353
0
      dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n",
354
0
           __func__, x, x + fillable, eof_blk);
355
0
      if (eof_blk >= x && eof_blk <= x + fillable)
356
0
        fillable = eof_blk - x;
357
0
    }
358
359
0
    if (fillable == 0)
360
0
      goto try_right;
361
362
    /* Test if the right edge of the range is already mapped? */
363
0
    if (EXT2FS_CLUSTER_RATIO(fs) > 1) {
364
0
      err = ext2fs_map_cluster_block(fs, ino, inode,
365
0
          x + fillable, &pblk);
366
0
      if (err)
367
0
        goto out;
368
0
      if (pblk)
369
0
        fillable -= 1 + ((x + fillable)
370
0
             & EXT2FS_CLUSTER_MASK(fs));
371
0
      if (fillable == 0)
372
0
        goto try_right;
373
0
    }
374
375
    /* Allocate range of blocks */
376
0
    x = left_ext->e_pblk + left_ext->e_len;
377
0
    err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
378
0
        EXT2_NEWRANGE_MIN_LENGTH,
379
0
        x, fillable, NULL, &pblk, &plen);
380
0
    if (err)
381
0
      goto try_right;
382
0
    err = claim_range(fs, inode, pblk, plen);
383
0
    if (err)
384
0
      goto out;
385
386
    /* Modify left_ext */
387
0
    err = ext2fs_extent_goto(handle, left_ext->e_lblk);
388
0
    if (err)
389
0
      goto out;
390
0
    range_start += plen;
391
0
    range_len -= plen;
392
0
    left_ext->e_len += plen;
393
0
    dbg_print_extent("ext_falloc left+", left_ext);
394
0
    err = ext2fs_extent_replace(handle, 0, left_ext);
395
0
    if (err)
396
0
      goto out;
397
0
    err = ext2fs_extent_fix_parents(handle);
398
0
    if (err)
399
0
      goto out;
400
401
    /* Zero blocks if necessary */
402
0
    if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
403
0
        (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
404
0
      err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL);
405
0
      if (err)
406
0
        goto out;
407
0
    }
408
0
  }
409
410
0
try_right:
411
  /* Extend the right extent */
412
0
  if (right_ext) {
413
    /* How much can we attach to right_ext? */
414
0
    if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
415
0
      fillable = max_uninit_len - right_ext->e_len;
416
0
    else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS)
417
0
      fillable = max_init_len - right_ext->e_len;
418
0
    else
419
0
      fillable = 0;
420
421
    /* User requires init/uninit but extent is uninit/init. */
422
0
    if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
423
0
         (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
424
0
        ((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
425
0
         !(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
426
0
      goto try_anywhere;
427
428
0
    if (fillable > range_len)
429
0
      fillable = range_len;
430
0
    if (fillable == 0)
431
0
      goto try_anywhere;
432
433
    /* Test if the left edge of the range is already mapped? */
434
0
    if (EXT2FS_CLUSTER_RATIO(fs) > 1) {
435
0
      err = ext2fs_map_cluster_block(fs, ino, inode,
436
0
          right_ext->e_lblk - fillable, &pblk);
437
0
      if (err)
438
0
        goto out;
439
0
      if (pblk)
440
0
        fillable -= EXT2FS_CLUSTER_RATIO(fs) -
441
0
            ((right_ext->e_lblk - fillable)
442
0
             & EXT2FS_CLUSTER_MASK(fs));
443
0
      if (fillable == 0)
444
0
        goto try_anywhere;
445
0
    }
446
447
    /*
448
     * FIXME: It would be nice if we could handle allocating a
449
     * variable range from a fixed end point instead of just
450
     * skipping to the general allocator if the whole range is
451
     * unavailable.
452
     */
453
0
    err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
454
0
        EXT2_NEWRANGE_MIN_LENGTH,
455
0
        right_ext->e_pblk - fillable,
456
0
        fillable, NULL, &pblk, &plen);
457
0
    if (err)
458
0
      goto try_anywhere;
459
0
    err = claim_range(fs, inode,
460
0
            pblk & ~EXT2FS_CLUSTER_MASK(fs),
461
0
            plen + (pblk & EXT2FS_CLUSTER_MASK(fs)));
462
0
    if (err)
463
0
      goto out;
464
465
    /* Modify right_ext */
466
0
    err = ext2fs_extent_goto(handle, right_ext->e_lblk);
467
0
    if (err)
468
0
      goto out;
469
0
    range_len -= plen;
470
0
    right_ext->e_lblk -= plen;
471
0
    right_ext->e_pblk -= plen;
472
0
    right_ext->e_len += plen;
473
0
    dbg_print_extent("ext_falloc right+", right_ext);
474
0
    err = ext2fs_extent_replace(handle, 0, right_ext);
475
0
    if (err)
476
0
      goto out;
477
0
    err = ext2fs_extent_fix_parents(handle);
478
0
    if (err)
479
0
      goto out;
480
481
    /* Zero blocks if necessary */
482
0
    if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
483
0
        (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
484
0
      err = ext2fs_zero_blocks2(fs, pblk,
485
0
          plen + cluster_fill, NULL, NULL);
486
0
      if (err)
487
0
        goto out;
488
0
    }
489
0
  }
490
491
0
try_anywhere:
492
  /* Try implied cluster alloc on the left and right ends */
493
0
  if (range_len > 0 && (range_start & EXT2FS_CLUSTER_MASK(fs))) {
494
0
    cluster_fill = EXT2FS_CLUSTER_RATIO(fs) -
495
0
             (range_start & EXT2FS_CLUSTER_MASK(fs));
496
0
    cluster_fill &= EXT2FS_CLUSTER_MASK(fs);
497
0
    if (cluster_fill > range_len)
498
0
      cluster_fill = range_len;
499
0
    newex.e_lblk = range_start;
500
0
    err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk,
501
0
                 &pblk);
502
0
    if (err)
503
0
      goto out;
504
0
    if (pblk == 0)
505
0
      goto try_right_implied;
506
0
    newex.e_pblk = pblk;
507
0
    newex.e_len = cluster_fill;
508
0
    newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 :
509
0
         EXT2_EXTENT_FLAGS_UNINIT);
510
0
    dbg_print_extent("ext_falloc iclus left+", &newex);
511
0
    ext2fs_extent_goto(handle, newex.e_lblk);
512
0
    err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
513
0
          &ex);
514
0
    if (err == EXT2_ET_NO_CURRENT_NODE)
515
0
      ex.e_lblk = 0;
516
0
    else if (err)
517
0
      goto out;
518
519
0
    if (ex.e_lblk > newex.e_lblk)
520
0
      op = 0; /* insert before */
521
0
    else
522
0
      op = EXT2_EXTENT_INSERT_AFTER;
523
0
    dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
524
0
         __func__, op ? "after" : "before", ex.e_lblk,
525
0
         newex.e_lblk);
526
0
    err = ext2fs_extent_insert(handle, op, &newex);
527
0
    if (err)
528
0
      goto out;
529
0
    err = ext2fs_extent_fix_parents(handle);
530
0
    if (err)
531
0
      goto out;
532
533
0
    if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
534
0
        (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
535
0
      err = ext2fs_zero_blocks2(fs, newex.e_pblk,
536
0
              newex.e_len, NULL, NULL);
537
0
      if (err)
538
0
        goto out;
539
0
    }
540
541
0
    range_start += cluster_fill;
542
0
    range_len -= cluster_fill;
543
0
  }
544
545
0
try_right_implied:
546
0
  y = range_start + range_len;
547
0
  if (range_len > 0 && (y & EXT2FS_CLUSTER_MASK(fs))) {
548
0
    cluster_fill = y & EXT2FS_CLUSTER_MASK(fs);
549
0
    if (cluster_fill > range_len)
550
0
      cluster_fill = range_len;
551
0
    newex.e_lblk = y & ~EXT2FS_CLUSTER_MASK(fs);
552
0
    err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk,
553
0
                 &pblk);
554
0
    if (err)
555
0
      goto out;
556
0
    if (pblk == 0)
557
0
      goto no_implied;
558
0
    newex.e_pblk = pblk;
559
0
    newex.e_len = cluster_fill;
560
0
    newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 :
561
0
         EXT2_EXTENT_FLAGS_UNINIT);
562
0
    dbg_print_extent("ext_falloc iclus right+", &newex);
563
0
    ext2fs_extent_goto(handle, newex.e_lblk);
564
0
    err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
565
0
          &ex);
566
0
    if (err == EXT2_ET_NO_CURRENT_NODE)
567
0
      ex.e_lblk = 0;
568
0
    else if (err)
569
0
      goto out;
570
571
0
    if (ex.e_lblk > newex.e_lblk)
572
0
      op = 0; /* insert before */
573
0
    else
574
0
      op = EXT2_EXTENT_INSERT_AFTER;
575
0
    dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
576
0
         __func__, op ? "after" : "before", ex.e_lblk,
577
0
         newex.e_lblk);
578
0
    err = ext2fs_extent_insert(handle, op, &newex);
579
0
    if (err)
580
0
      goto out;
581
0
    err = ext2fs_extent_fix_parents(handle);
582
0
    if (err)
583
0
      goto out;
584
585
0
    if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
586
0
        (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
587
0
      err = ext2fs_zero_blocks2(fs, newex.e_pblk,
588
0
              newex.e_len, NULL, NULL);
589
0
      if (err)
590
0
        goto out;
591
0
    }
592
593
0
    range_len -= cluster_fill;
594
0
  }
595
596
0
no_implied:
597
0
  if (range_len == 0)
598
0
    return 0;
599
600
0
  newex.e_lblk = range_start;
601
0
  if (flags & EXT2_FALLOCATE_FORCE_INIT) {
602
0
    max_extent_len = max_init_len;
603
0
    newex.e_flags = 0;
604
0
  } else {
605
0
    max_extent_len = max_uninit_len;
606
0
    newex.e_flags = EXT2_EXTENT_FLAGS_UNINIT;
607
0
  }
608
0
  pblk = alloc_goal;
609
0
  y = range_len;
610
0
  for (x = 0; x < y;) {
611
0
    cluster_fill = newex.e_lblk & EXT2FS_CLUSTER_MASK(fs);
612
0
    fillable = min(range_len + cluster_fill, max_extent_len);
613
0
    err = ext2fs_new_range(fs, 0, pblk & ~EXT2FS_CLUSTER_MASK(fs),
614
0
               fillable,
615
0
               NULL, &pblk, &plen);
616
0
    if (err)
617
0
      goto out;
618
0
    err = claim_range(fs, inode, pblk, plen);
619
0
    if (err)
620
0
      goto out;
621
622
    /* Create extent */
623
0
    newex.e_pblk = pblk + cluster_fill;
624
0
    newex.e_len = plen - cluster_fill;
625
0
    dbg_print_extent("ext_falloc create", &newex);
626
0
    ext2fs_extent_goto(handle, newex.e_lblk);
627
0
    err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
628
0
          &ex);
629
0
    if (err == EXT2_ET_NO_CURRENT_NODE)
630
0
      ex.e_lblk = 0;
631
0
    else if (err)
632
0
      goto out;
633
634
0
    if (ex.e_lblk > newex.e_lblk)
635
0
      op = 0; /* insert before */
636
0
    else
637
0
      op = EXT2_EXTENT_INSERT_AFTER;
638
0
    dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
639
0
         __func__, op ? "after" : "before", ex.e_lblk,
640
0
         newex.e_lblk);
641
0
    err = ext2fs_extent_insert(handle, op, &newex);
642
0
    if (err)
643
0
      goto out;
644
0
    err = ext2fs_extent_fix_parents(handle);
645
0
    if (err)
646
0
      goto out;
647
648
0
    if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
649
0
        (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
650
0
      err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL);
651
0
      if (err)
652
0
        goto out;
653
0
    }
654
655
    /* Update variables at end of loop */
656
0
    x += plen - cluster_fill;
657
0
    range_len -= plen - cluster_fill;
658
0
    newex.e_lblk += plen - cluster_fill;
659
0
    pblk += plen - cluster_fill;
660
0
    if (pblk >= ext2fs_blocks_count(fs->super))
661
0
      pblk = fs->super->s_first_data_block;
662
0
  }
663
664
0
out:
665
0
  return err;
666
0
}
667
668
static errcode_t extent_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino,
669
              struct ext2_inode *inode, blk64_t goal,
670
              blk64_t start, blk64_t len)
671
0
{
672
0
  ext2_extent_handle_t  handle;
673
0
  struct ext2fs_extent  left_extent, right_extent;
674
0
  struct ext2fs_extent  *left_adjacent, *right_adjacent;
675
0
  errcode_t   err;
676
0
  blk64_t     range_start, range_end = 0, end, next;
677
0
  blk64_t     count, goal_distance;
678
679
0
  end = start + len - 1;
680
0
  err = ext2fs_extent_open2(fs, ino, inode, &handle);
681
0
  if (err)
682
0
    return err;
683
684
  /*
685
   * Find the extent closest to the start of the alloc range.  We don't
686
   * check the return value because _goto() sets the current node to the
687
   * next-lowest extent if 'start' is in a hole; or the next-highest
688
   * extent if there aren't any lower ones; or doesn't set a current node
689
   * if there was a real error reading the extent tree.  In that case,
690
   * _get() will error out.
691
   */
692
0
start_again:
693
0
  ext2fs_extent_goto(handle, start);
694
0
  err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &left_extent);
695
0
  if (err == EXT2_ET_NO_CURRENT_NODE) {
696
0
    blk64_t max_blocks = ext2fs_blocks_count(fs->super);
697
698
0
    if (goal == ~0ULL)
699
0
      goal = ext2fs_find_inode_goal(fs, ino, inode, start);
700
0
    err = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
701
0
            goal, max_blocks - 1, &goal);
702
0
    goal += start;
703
0
    err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL,
704
0
          NULL, start, len, goal);
705
0
    goto errout;
706
0
  } else if (err)
707
0
    goto errout;
708
709
0
  dbg_print_extent("ext_falloc initial", &left_extent);
710
0
  next = left_extent.e_lblk + left_extent.e_len;
711
0
  if (left_extent.e_lblk > start) {
712
    /* The nearest extent we found was beyond start??? */
713
0
    goal = left_extent.e_pblk - (left_extent.e_lblk - start);
714
0
    err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL,
715
0
          &left_extent, start,
716
0
          left_extent.e_lblk - start, goal);
717
0
    if (err)
718
0
      goto errout;
719
720
0
    goto start_again;
721
0
  } else if (next >= start) {
722
0
    range_start = next;
723
0
    left_adjacent = &left_extent;
724
0
  } else {
725
0
    range_start = start;
726
0
    left_adjacent = NULL;
727
0
  }
728
0
  goal = left_extent.e_pblk + (range_start - left_extent.e_lblk);
729
730
0
  do {
731
0
    err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF,
732
0
             &right_extent);
733
0
    dbg_printf("%s: ino=%d get next =%d\n", __func__, ino,
734
0
         (int)err);
735
0
    dbg_print_extent("ext_falloc next", &right_extent);
736
    /* Stop if we've seen this extent before */
737
0
    if (!err && right_extent.e_lblk <= left_extent.e_lblk)
738
0
      err = EXT2_ET_EXTENT_NO_NEXT;
739
740
0
    if (err && err != EXT2_ET_EXTENT_NO_NEXT)
741
0
      goto errout;
742
0
    if (err == EXT2_ET_EXTENT_NO_NEXT ||
743
0
        right_extent.e_lblk > end + 1) {
744
0
      range_end = end;
745
0
      right_adjacent = NULL;
746
0
    } else {
747
      /* Handle right_extent.e_lblk <= end */
748
0
      range_end = right_extent.e_lblk - 1;
749
0
      right_adjacent = &right_extent;
750
0
    }
751
0
    goal_distance = range_start - next;
752
0
    if (err != EXT2_ET_EXTENT_NO_NEXT &&
753
0
        goal_distance > (range_end - right_extent.e_lblk))
754
0
      goal = right_extent.e_pblk -
755
0
          (right_extent.e_lblk - range_start);
756
757
0
    dbg_printf("%s: ino=%d rstart=%llu rend=%llu\n", __func__, ino,
758
0
         range_start, range_end);
759
0
    err = 0;
760
0
    if (range_start <= range_end) {
761
0
      count = range_end - range_start + 1;
762
0
      err = ext_falloc_helper(fs, flags, ino, inode, handle,
763
0
            left_adjacent, right_adjacent,
764
0
            range_start, count, goal);
765
0
      if (err)
766
0
        goto errout;
767
0
    }
768
769
0
    if (range_end == end)
770
0
      break;
771
772
0
    err = ext2fs_extent_goto(handle, right_extent.e_lblk);
773
0
    if (err)
774
0
      goto errout;
775
0
    next = right_extent.e_lblk + right_extent.e_len;
776
0
    left_extent = right_extent;
777
0
    left_adjacent = &left_extent;
778
0
    range_start = next;
779
0
    goal = left_extent.e_pblk + (range_start - left_extent.e_lblk);
780
0
  } while (range_end < end);
781
782
0
errout:
783
0
  ext2fs_extent_free(handle);
784
0
  return err;
785
0
}
786
787
/*
788
 * Map physical blocks to a range of logical blocks within a file.  The range
789
 * of logical blocks are (start, start + len).  If there are already extents,
790
 * the mappings will try to extend the mappings; otherwise, it will try to map
791
 * start as if logical block 0 points to goal.  If goal is ~0ULL, then the goal
792
 * is calculated based on the inode group.
793
 *
794
 * Flags:
795
 * - EXT2_FALLOCATE_ZERO_BLOCKS: Zero the blocks that are allocated.
796
 * - EXT2_FALLOCATE_FORCE_INIT: Create only initialized extents.
797
 * - EXT2_FALLOCATE_FORCE_UNINIT: Create only uninitialized extents.
798
 * - EXT2_FALLOCATE_INIT_BEYOND_EOF: Create extents beyond EOF.
799
 *
800
 * If neither FORCE_INIT nor FORCE_UNINIT are specified, this function will
801
 * try to expand any extents it finds, zeroing blocks as necessary.
802
 */
803
errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino,
804
         struct ext2_inode *inode, blk64_t goal,
805
         blk64_t start, blk64_t len)
806
0
{
807
0
  struct ext2_inode inode_buf;
808
0
  blk64_t     blk, x, zero_blk, last = 0;
809
0
  int     zero_len = 0;
810
0
  errcode_t   err;
811
812
0
  if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
813
0
      (flags & EXT2_FALLOCATE_FORCE_UNINIT)) ||
814
0
     (flags & ~EXT2_FALLOCATE_ALL_FLAGS))
815
0
    return EXT2_ET_INVALID_ARGUMENT;
816
817
0
  if (len > ext2fs_blocks_count(fs->super))
818
0
    return EXT2_ET_BLOCK_ALLOC_FAIL;
819
0
  else if (len == 0)
820
0
    return 0;
821
822
  /* Read inode structure if necessary */
823
0
  if (!inode) {
824
0
    err = ext2fs_read_inode(fs, ino, &inode_buf);
825
0
    if (err)
826
0
      return err;
827
0
    inode = &inode_buf;
828
0
  }
829
0
  dbg_printf("%s: ino=%d start=%llu len=%llu goal=%llu\n", __func__, ino,
830
0
       start, len, goal);
831
832
0
  if (inode->i_flags & EXT4_EXTENTS_FL) {
833
0
    err = extent_fallocate(fs, flags, ino, inode, goal, start, len);
834
0
    goto out;
835
0
  }
836
837
  /* XXX: Allocate a bunch of blocks the slow way */
838
0
  for (blk = start; blk < start + len; blk++) {
839
0
    err = ext2fs_bmap2(fs, ino, inode, NULL, 0, blk, 0, &x);
840
0
    if (err)
841
0
      return err;
842
0
    if (x)
843
0
      continue;
844
845
0
    err = ext2fs_bmap2(fs, ino, inode, NULL, BMAP_ALLOC,
846
0
           blk, 0, &x);
847
0
    if (err)
848
0
      goto errout;
849
0
    if ((zero_len && (x != last+1)) ||
850
0
        (zero_len >= 65536)) {
851
0
      err = ext2fs_zero_blocks2(fs, zero_blk, zero_len,
852
0
              NULL, NULL);
853
0
      zero_len = 0;
854
0
      if (err)
855
0
        goto errout;
856
0
    }
857
0
    if (zero_len == 0) {
858
0
      zero_blk = x;
859
0
      zero_len = 1;
860
0
    } else {
861
0
      zero_len++;
862
0
    }
863
0
    last = x;
864
0
  }
865
866
0
out:
867
0
  if (inode == &inode_buf)
868
0
    ext2fs_write_inode(fs, ino, inode);
869
0
errout:
870
0
  if (zero_len)
871
0
    ext2fs_zero_blocks2(fs, zero_blk, zero_len, NULL, NULL);
872
0
  return err;
873
0
}