]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - resize/resize2fs.c
resize2fs: correctly account for clusters when calculating summary stats
[thirdparty/e2fsprogs.git] / resize / resize2fs.c
CommitLineData
24b2c7a7
TT
1/*
2 * resize2fs.c --- ext2 main routine
3 *
0cee8a5c
TT
4 * Copyright (C) 1997, 1998 by Theodore Ts'o and
5 * PowerQuest, Inc.
6 *
7 * Copyright (C) 1999, 2000 by Theosore Ts'o
efc6f628 8 *
24b2c7a7 9 * %Begin-Header%
0cee8a5c
TT
10 * This file may be redistributed under the terms of the GNU Public
11 * License.
24b2c7a7
TT
12 * %End-Header%
13 */
14
05e112a1
TT
15/*
16 * Resizing a filesystem consists of the following phases:
17 *
a8519a2d 18 * 1. Adjust superblock and write out new parts of the inode
05e112a1 19 * table
a8519a2d
TT
20 * 2. Determine blocks which need to be relocated, and copy the
21 * contents of blocks from their old locations to the new ones.
22 * 3. Scan the inode table, doing the following:
23 * a. If blocks have been moved, update the block
24 * pointers in the inodes and indirect blocks to
25 * point at the new block locations.
26 * b. If parts of the inode table need to be evacuated,
27 * copy inodes from their old locations to their
28 * new ones.
29 * c. If (b) needs to be done, note which blocks contain
30 * directory information, since we will need to
31 * update the directory information.
32 * 4. Update the directory blocks with the new inode locations.
33 * 5. Move the inode tables, if necessary.
05e112a1 34 */
a8519a2d 35
d1154eb4 36#include "config.h"
24b2c7a7 37#include "resize2fs.h"
b969b1b8 38#include <time.h>
24b2c7a7 39
546a1ff1 40#ifdef __linux__ /* Kludge for debugging */
a8519a2d
TT
41#define RESIZE2FS_DEBUG
42#endif
43
86acdebd 44static void fix_uninit_block_bitmaps(ext2_filsys fs);
8728d506 45static errcode_t adjust_superblock(ext2_resize_t rfs, blk64_t new_size);
a8519a2d
TT
46static errcode_t blocks_to_move(ext2_resize_t rfs);
47static errcode_t block_mover(ext2_resize_t rfs);
48static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
49static errcode_t inode_ref_fix(ext2_resize_t rfs);
50static errcode_t move_itables(ext2_resize_t rfs);
9213a93b 51static errcode_t fix_resize_inode(ext2_filsys fs);
a8519a2d 52static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
8a6ede8b 53static errcode_t fix_sb_journal_backup(ext2_filsys fs);
a8519a2d
TT
54
55/*
56 * Some helper CPP macros
57 */
d7cca6b0
VAH
58#define IS_BLOCK_BM(fs, i, blk) ((blk) == ext2fs_block_bitmap_loc((fs),(i)))
59#define IS_INODE_BM(fs, i, blk) ((blk) == ext2fs_inode_bitmap_loc((fs),(i)))
a8519a2d 60
d7cca6b0
VAH
61#define IS_INODE_TB(fs, i, blk) (((blk) >= ext2fs_inode_table_loc((fs), (i))) && \
62 ((blk) < (ext2fs_inode_table_loc((fs), (i)) + \
a8519a2d
TT
63 (fs)->inode_blocks_per_group)))
64
1773c87c
TT
65/* Some bigalloc helper macros which are more succint... */
66#define B2C(x) EXT2FS_B2C(fs, (x))
67#define C2B(x) EXT2FS_C2B(fs, (x))
68#define EQ_CLSTR(x, y) (B2C(x) == B2C(y))
69#define LE_CLSTR(x, y) (B2C(x) <= B2C(y))
70#define LT_CLSTR(x, y) (B2C(x) < B2C(y))
71#define GE_CLSTR(x, y) (B2C(x) >= B2C(y))
72#define GT_CLSTR(x, y) (B2C(x) > B2C(y))
73
2d8c0c8a
TT
74int lazy_itable_init;
75
a8519a2d
TT
76/*
77 * This is the top-level routine which does the dirty deed....
78 */
8728d506 79errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
3346084b 80 errcode_t (*progress)(ext2_resize_t rfs, int pass,
86acdebd
TT
81 unsigned long cur,
82 unsigned long max_val))
a8519a2d
TT
83{
84 ext2_resize_t rfs;
85 errcode_t retval;
1eb31c48 86 struct resource_track rtrack, overall_track;
96cdb37e 87
a8519a2d
TT
88 /*
89 * Create the data structure
90 */
c4e3d3f3 91 retval = ext2fs_get_mem(sizeof(struct ext2_resize_struct), &rfs);
a8519a2d
TT
92 if (retval)
93 return retval;
a8519a2d 94
1eb31c48 95 memset(rfs, 0, sizeof(struct ext2_resize_struct));
7f9c96ee 96 fs->priv_data = rfs;
a8519a2d
TT
97 rfs->old_fs = fs;
98 rfs->flags = flags;
99 rfs->itable_buf = 0;
100 rfs->progress = progress;
1eb31c48
TT
101
102 init_resource_track(&overall_track, "overall resize2fs", fs->io);
103 init_resource_track(&rtrack, "read_bitmaps", fs->io);
104 retval = ext2fs_read_bitmaps(fs);
105 if (retval)
106 goto errout;
107 print_resource_track(rfs, &rtrack, fs->io);
108
109 fs->super->s_state |= EXT2_ERROR_FS;
110 ext2fs_mark_super_dirty(fs);
111 ext2fs_flush(fs);
112
113 init_resource_track(&rtrack, "fix_uninit_block_bitmaps 1", fs->io);
114 fix_uninit_block_bitmaps(fs);
115 print_resource_track(rfs, &rtrack, fs->io);
a8519a2d
TT
116 retval = ext2fs_dup_handle(fs, &rfs->new_fs);
117 if (retval)
118 goto errout;
119
1eb31c48 120 init_resource_track(&rtrack, "adjust_superblock", fs->io);
116db1b5 121 retval = adjust_superblock(rfs, *new_size);
a8519a2d
TT
122 if (retval)
123 goto errout;
1eb31c48 124 print_resource_track(rfs, &rtrack, fs->io);
a8519a2d 125
1eb31c48
TT
126
127 init_resource_track(&rtrack, "fix_uninit_block_bitmaps 2", fs->io);
86acdebd 128 fix_uninit_block_bitmaps(rfs->new_fs);
1eb31c48 129 print_resource_track(rfs, &rtrack, fs->io);
86acdebd 130 /* Clear the block bitmap uninit flag for the last block group */
e633b58a 131 ext2fs_bg_flags_clear(rfs->new_fs, rfs->new_fs->group_desc_count - 1,
732c8cd5 132 EXT2_BG_BLOCK_UNINIT);
86acdebd 133
4efbac6f 134 *new_size = ext2fs_blocks_count(rfs->new_fs->super);
116db1b5 135
1eb31c48 136 init_resource_track(&rtrack, "blocks_to_move", fs->io);
a8519a2d
TT
137 retval = blocks_to_move(rfs);
138 if (retval)
139 goto errout;
1eb31c48 140 print_resource_track(rfs, &rtrack, fs->io);
a8519a2d
TT
141
142#ifdef RESIZE2FS_DEBUG
143 if (rfs->flags & RESIZE_DEBUG_BMOVE)
8728d506 144 printf("Number of free blocks: %llu/%llu, Needed: %llu\n",
4efbac6f
VAH
145 ext2fs_free_blocks_count(rfs->old_fs->super),
146 ext2fs_free_blocks_count(rfs->new_fs->super),
a8519a2d
TT
147 rfs->needed_blocks);
148#endif
efc6f628 149
1eb31c48 150 init_resource_track(&rtrack, "block_mover", fs->io);
a8519a2d
TT
151 retval = block_mover(rfs);
152 if (retval)
153 goto errout;
1eb31c48 154 print_resource_track(rfs, &rtrack, fs->io);
a8519a2d 155
1eb31c48 156 init_resource_track(&rtrack, "inode_scan_and_fix", fs->io);
a8519a2d
TT
157 retval = inode_scan_and_fix(rfs);
158 if (retval)
159 goto errout;
1eb31c48 160 print_resource_track(rfs, &rtrack, fs->io);
a8519a2d 161
1eb31c48 162 init_resource_track(&rtrack, "inode_ref_fix", fs->io);
a8519a2d
TT
163 retval = inode_ref_fix(rfs);
164 if (retval)
165 goto errout;
1eb31c48 166 print_resource_track(rfs, &rtrack, fs->io);
a8519a2d 167
1eb31c48 168 init_resource_track(&rtrack, "move_itables", fs->io);
a8519a2d
TT
169 retval = move_itables(rfs);
170 if (retval)
171 goto errout;
1eb31c48 172 print_resource_track(rfs, &rtrack, fs->io);
a8519a2d 173
1eb31c48 174 init_resource_track(&rtrack, "calculate_summary_stats", fs->io);
64ad98ac
TT
175 retval = ext2fs_calculate_summary_stats(rfs->new_fs);
176 if (retval)
177 goto errout;
1eb31c48 178 print_resource_track(rfs, &rtrack, fs->io);
efc6f628 179
1eb31c48 180 init_resource_track(&rtrack, "fix_resize_inode", fs->io);
9213a93b
TT
181 retval = fix_resize_inode(rfs->new_fs);
182 if (retval)
183 goto errout;
1eb31c48 184 print_resource_track(rfs, &rtrack, fs->io);
9213a93b 185
1eb31c48 186 init_resource_track(&rtrack, "fix_sb_journal_backup", fs->io);
8a6ede8b
ES
187 retval = fix_sb_journal_backup(rfs->new_fs);
188 if (retval)
189 goto errout;
1eb31c48 190 print_resource_track(rfs, &rtrack, fs->io);
8a6ede8b 191
96cdb37e 192 rfs->new_fs->super->s_state &= ~EXT2_ERROR_FS;
efc6f628 193 rfs->new_fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
1eb31c48
TT
194
195 print_resource_track(rfs, &overall_track, fs->io);
a8519a2d
TT
196 retval = ext2fs_close(rfs->new_fs);
197 if (retval)
198 goto errout;
199
200 rfs->flags = flags;
efc6f628 201
a8519a2d
TT
202 ext2fs_free(rfs->old_fs);
203 if (rfs->itable_buf)
c4e3d3f3 204 ext2fs_free_mem(&rfs->itable_buf);
e2ca097f
TT
205 if (rfs->reserve_blocks)
206 ext2fs_free_block_bitmap(rfs->reserve_blocks);
207 if (rfs->move_blocks)
208 ext2fs_free_block_bitmap(rfs->move_blocks);
c4e3d3f3 209 ext2fs_free_mem(&rfs);
efc6f628 210
a8519a2d
TT
211 return 0;
212
213errout:
214 if (rfs->new_fs)
215 ext2fs_free(rfs->new_fs);
216 if (rfs->itable_buf)
c4e3d3f3
TT
217 ext2fs_free_mem(&rfs->itable_buf);
218 ext2fs_free_mem(&rfs);
a8519a2d
TT
219 return retval;
220}
221
86acdebd
TT
222/*
223 * Clean up the bitmaps for unitialized bitmaps
224 */
225static void fix_uninit_block_bitmaps(ext2_filsys fs)
226{
a0ba54ec 227 blk64_t blk, lblk;
86acdebd 228 dgrp_t g;
a0ba54ec 229 int i;
86acdebd
TT
230
231 if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
232 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
233 return;
234
235 for (g=0; g < fs->group_desc_count; g++) {
cd65a24e 236 if (!(ext2fs_bg_flags_test(fs, g, EXT2_BG_BLOCK_UNINIT)))
86acdebd
TT
237 continue;
238
5d3a88fb 239 blk = ext2fs_group_first_block2(fs, g);
a0ba54ec
TT
240 lblk = ext2fs_group_last_block2(fs, g);
241 ext2fs_unmark_block_bitmap_range2(fs->block_map, blk,
242 lblk - blk + 1);
243
244 ext2fs_reserve_super_and_bgd(fs, g, fs->block_map);
245 ext2fs_mark_block_bitmap2(fs->block_map,
246 ext2fs_block_bitmap_loc(fs, g));
247 ext2fs_mark_block_bitmap2(fs->block_map,
248 ext2fs_inode_bitmap_loc(fs, g));
249 for (i = 0, blk = ext2fs_inode_table_loc(fs, g);
250 i < (unsigned int) fs->inode_blocks_per_group;
251 i++, blk++)
252 ext2fs_mark_block_bitmap2(fs->block_map, blk);
86acdebd
TT
253 }
254}
255
a8519a2d
TT
256/* --------------------------------------------------------------------
257 *
258 * Resize processing, phase 1.
259 *
260 * In this phase we adjust the in-memory superblock information, and
261 * initialize any new parts of the inode table. The new parts of the
262 * inode table are created in virgin disk space, so we can abort here
263 * without any side effects.
264 * --------------------------------------------------------------------
265 */
266
9227c5bb
TT
267/*
268 * If the group descriptor's bitmap and inode table blocks are valid,
c09043f1
TT
269 * release them in the new filesystem data structure, and mark them as
270 * reserved so the old inode table blocks don't get overwritten.
9227c5bb 271 */
c09043f1
TT
272static void free_gdp_blocks(ext2_filsys fs,
273 ext2fs_block_bitmap reserve_blocks,
274 struct ext2_group_desc *gdp)
9227c5bb
TT
275{
276 blk_t blk;
277 int j;
278
279 if (gdp->bg_block_bitmap &&
4efbac6f 280 (gdp->bg_block_bitmap < ext2fs_blocks_count(fs->super))) {
9227c5bb 281 ext2fs_block_alloc_stats(fs, gdp->bg_block_bitmap, -1);
3346084b 282 ext2fs_mark_block_bitmap2(reserve_blocks,
c09043f1
TT
283 gdp->bg_block_bitmap);
284 }
9227c5bb
TT
285
286 if (gdp->bg_inode_bitmap &&
4efbac6f 287 (gdp->bg_inode_bitmap < ext2fs_blocks_count(fs->super))) {
9227c5bb 288 ext2fs_block_alloc_stats(fs, gdp->bg_inode_bitmap, -1);
3346084b 289 ext2fs_mark_block_bitmap2(reserve_blocks,
c09043f1
TT
290 gdp->bg_inode_bitmap);
291 }
9227c5bb
TT
292
293 if (gdp->bg_inode_table == 0 ||
4efbac6f 294 (gdp->bg_inode_table >= ext2fs_blocks_count(fs->super)))
9227c5bb
TT
295 return;
296
297 for (blk = gdp->bg_inode_table, j = 0;
298 j < fs->inode_blocks_per_group; j++, blk++) {
4efbac6f 299 if (blk >= ext2fs_blocks_count(fs->super))
9227c5bb
TT
300 break;
301 ext2fs_block_alloc_stats(fs, blk, -1);
3346084b 302 ext2fs_mark_block_bitmap2(reserve_blocks, blk);
9227c5bb
TT
303 }
304}
305
24b2c7a7 306/*
bf69235a
TT
307 * This routine is shared by the online and offline resize routines.
308 * All of the information which is adjusted in memory is done here.
c09043f1
TT
309 *
310 * The reserve_blocks parameter is only needed when shrinking the
311 * filesystem.
24b2c7a7 312 */
c09043f1 313errcode_t adjust_fs_info(ext2_filsys fs, ext2_filsys old_fs,
8728d506 314 ext2fs_block_bitmap reserve_blocks, blk64_t new_size)
24b2c7a7 315{
24b2c7a7 316 errcode_t retval;
8728d506
VAH
317 blk64_t overhead = 0;
318 blk64_t rem;
319 blk64_t blk, group_block;
2696f250 320 blk64_t real_end;
5e27a274
TT
321 blk64_t old_numblocks, numblocks, adjblocks;
322 unsigned long i, j, old_desc_blocks;
54434927 323 unsigned int meta_bg, meta_bg_size;
74128f8d 324 int has_super, csum_flag;
de8f3a76 325 unsigned long long new_inodes; /* u64 to check for overflow */
9ff8ece5 326 double percent;
bf69235a 327
4efbac6f 328 ext2fs_blocks_count_set(fs->super, new_size);
24b2c7a7
TT
329
330retry:
4efbac6f 331 fs->group_desc_count = ext2fs_div64_ceil(ext2fs_blocks_count(fs->super) -
69022e02
TT
332 fs->super->s_first_data_block,
333 EXT2_BLOCKS_PER_GROUP(fs->super));
24b2c7a7
TT
334 if (fs->group_desc_count == 0)
335 return EXT2_ET_TOOSMALL;
efc6f628 336 fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
69022e02 337 EXT2_DESC_PER_BLOCK(fs->super));
24b2c7a7
TT
338
339 /*
340 * Overhead is the number of bookkeeping blocks per group. It
341 * includes the superblock backup, the group descriptor
342 * backups, the inode bitmap, the block bitmap, and the inode
343 * table.
24b2c7a7 344 */
9213a93b
TT
345 overhead = (int) (2 + fs->inode_blocks_per_group);
346
347 if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
efc6f628 348 overhead += 1 + fs->desc_blocks +
9213a93b
TT
349 fs->super->s_reserved_gdt_blocks;
350
24b2c7a7
TT
351 /*
352 * See if the last group is big enough to support the
353 * necessary data structures. If not, we need to get rid of
354 * it.
355 */
4efbac6f 356 rem = (ext2fs_blocks_count(fs->super) - fs->super->s_first_data_block) %
24b2c7a7
TT
357 fs->super->s_blocks_per_group;
358 if ((fs->group_desc_count == 1) && rem && (rem < overhead))
359 return EXT2_ET_TOOSMALL;
515e555a 360 if ((fs->group_desc_count > 1) && rem && (rem < overhead+50)) {
4efbac6f
VAH
361 ext2fs_blocks_count_set(fs->super,
362 ext2fs_blocks_count(fs->super) - rem);
24b2c7a7
TT
363 goto retry;
364 }
365 /*
366 * Adjust the number of inodes
367 */
de8f3a76 368 new_inodes =(unsigned long long) fs->super->s_inodes_per_group * fs->group_desc_count;
f3358643
ES
369 if (new_inodes > ~0U) {
370 fprintf(stderr, _("inodes (%llu) must be less than %u"),
371 new_inodes, ~0U);
372 return EXT2_ET_TOO_MANY_INODES;
373 }
24b2c7a7
TT
374 fs->super->s_inodes_count = fs->super->s_inodes_per_group *
375 fs->group_desc_count;
376
377 /*
378 * Adjust the number of free blocks
379 */
4efbac6f
VAH
380 blk = ext2fs_blocks_count(old_fs->super);
381 if (blk > ext2fs_blocks_count(fs->super))
382 ext2fs_free_blocks_count_set(fs->super,
383 ext2fs_free_blocks_count(fs->super) -
384 (blk - ext2fs_blocks_count(fs->super)));
24b2c7a7 385 else
4efbac6f
VAH
386 ext2fs_free_blocks_count_set(fs->super,
387 ext2fs_free_blocks_count(fs->super) +
388 (ext2fs_blocks_count(fs->super) - blk));
24b2c7a7 389
c762c8e6
TT
390 /*
391 * Adjust the number of reserved blocks
392 */
4efbac6f
VAH
393 percent = (ext2fs_r_blocks_count(old_fs->super) * 100.0) /
394 ext2fs_blocks_count(old_fs->super);
395 ext2fs_r_blocks_count_set(fs->super,
396 (percent * ext2fs_blocks_count(fs->super) /
397 100.0));
c762c8e6 398
24b2c7a7
TT
399 /*
400 * Adjust the bitmaps for size
401 */
3346084b 402 retval = ext2fs_resize_inode_bitmap2(fs->super->s_inodes_count,
24b2c7a7
TT
403 fs->super->s_inodes_count,
404 fs->inode_map);
c762c8e6 405 if (retval) goto errout;
efc6f628 406
2696f250
TT
407 real_end = (((blk64_t) EXT2_BLOCKS_PER_GROUP(fs->super) *
408 fs->group_desc_count)) - 1 +
409 fs->super->s_first_data_block;
4efbac6f 410 retval = ext2fs_resize_block_bitmap2(ext2fs_blocks_count(fs->super)-1,
24b2c7a7
TT
411 real_end, fs->block_map);
412
c762c8e6 413 if (retval) goto errout;
24b2c7a7
TT
414
415 /*
416 * Reallocate the group descriptors as necessary.
417 */
bf69235a
TT
418 if (old_fs->desc_blocks != fs->desc_blocks) {
419 retval = ext2fs_resize_mem(old_fs->desc_blocks *
76f875da
TT
420 fs->blocksize,
421 fs->desc_blocks * fs->blocksize,
c4e3d3f3 422 &fs->group_desc);
ca8abba7 423 if (retval)
a8519a2d 424 goto errout;
efc6f628
TT
425 if (fs->desc_blocks > old_fs->desc_blocks)
426 memset((char *) fs->group_desc +
bf69235a
TT
427 (old_fs->desc_blocks * fs->blocksize), 0,
428 (fs->desc_blocks - old_fs->desc_blocks) *
2787276e 429 fs->blocksize);
24b2c7a7 430 }
1e1da29f 431
9213a93b
TT
432 /*
433 * If the resize_inode feature is set, and we are changing the
434 * number of descriptor blocks, then adjust
435 * s_reserved_gdt_blocks if possible to avoid needing to move
436 * the inode table either now or in the future.
437 */
efc6f628 438 if ((fs->super->s_feature_compat &
9213a93b 439 EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
bf69235a 440 (old_fs->desc_blocks != fs->desc_blocks)) {
9213a93b
TT
441 int new;
442
efc6f628 443 new = ((int) fs->super->s_reserved_gdt_blocks) +
bf69235a 444 (old_fs->desc_blocks - fs->desc_blocks);
9213a93b
TT
445 if (new < 0)
446 new = 0;
de8f3a76 447 if (new > (int) fs->blocksize/4)
9213a93b
TT
448 new = fs->blocksize/4;
449 fs->super->s_reserved_gdt_blocks = new;
9213a93b
TT
450 }
451
a8519a2d 452 /*
c09043f1
TT
453 * If we are shrinking the number of block groups, we're done
454 * and can exit now.
1e1da29f 455 */
bf69235a 456 if (old_fs->group_desc_count > fs->group_desc_count) {
9227c5bb
TT
457 /*
458 * Check the block groups that we are chopping off
459 * and free any blocks associated with their metadata
460 */
461 for (i = fs->group_desc_count;
462 i < old_fs->group_desc_count; i++) {
c09043f1 463 free_gdp_blocks(fs, reserve_blocks,
d7cca6b0
VAH
464 ext2fs_group_desc(old_fs,
465 old_fs->group_desc, i));
9227c5bb 466 }
c762c8e6
TT
467 retval = 0;
468 goto errout;
469 }
bf69235a 470
a8519a2d
TT
471 /*
472 * Fix the count of the last (old) block group
473 */
4efbac6f 474 old_numblocks = (ext2fs_blocks_count(old_fs->super) -
bf69235a
TT
475 old_fs->super->s_first_data_block) %
476 old_fs->super->s_blocks_per_group;
1e1da29f 477 if (!old_numblocks)
bf69235a
TT
478 old_numblocks = old_fs->super->s_blocks_per_group;
479 if (old_fs->group_desc_count == fs->group_desc_count) {
4efbac6f 480 numblocks = (ext2fs_blocks_count(fs->super) -
bf69235a
TT
481 fs->super->s_first_data_block) %
482 fs->super->s_blocks_per_group;
1e1da29f 483 if (!numblocks)
bf69235a 484 numblocks = fs->super->s_blocks_per_group;
1e1da29f 485 } else
bf69235a
TT
486 numblocks = fs->super->s_blocks_per_group;
487 i = old_fs->group_desc_count - 1;
d7cca6b0 488 ext2fs_bg_free_blocks_count_set(fs, i, ext2fs_bg_free_blocks_count(fs, i) + (numblocks - old_numblocks));
236efede
JS
489 ext2fs_group_desc_csum_set(fs, i);
490
1e1da29f 491 /*
a8519a2d
TT
492 * If the number of block groups is staying the same, we're
493 * done and can exit now. (If the number block groups is
494 * shrinking, we had exited earlier.)
1e1da29f 495 */
bf69235a 496 if (old_fs->group_desc_count >= fs->group_desc_count) {
c762c8e6
TT
497 retval = 0;
498 goto errout;
499 }
bf69235a 500
a8519a2d
TT
501 /*
502 * Initialize the new block group descriptors
503 */
027b0577
TT
504 group_block = ext2fs_group_first_block2(fs,
505 old_fs->group_desc_count);
74128f8d
TT
506 csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
507 EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
2d8c0c8a
TT
508 if (access("/sys/fs/ext4/features/lazy_itable_init", F_OK) == 0)
509 lazy_itable_init = 1;
76dd5e5c
TT
510 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
511 old_desc_blocks = fs->super->s_first_meta_bg;
512 else
efc6f628 513 old_desc_blocks = fs->desc_blocks +
9213a93b 514 fs->super->s_reserved_gdt_blocks;
bf69235a 515 for (i = old_fs->group_desc_count;
1e1da29f 516 i < fs->group_desc_count; i++) {
d7cca6b0 517 memset(ext2fs_group_desc(fs, fs->group_desc, i), 0,
1e1da29f
TT
518 sizeof(struct ext2_group_desc));
519 adjblocks = 0;
520
e633b58a 521 ext2fs_bg_flags_zap(fs, i);
2d8c0c8a
TT
522 if (csum_flag) {
523 ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);
524 if (!lazy_itable_init)
525 ext2fs_bg_flags_set(fs, i,
526 EXT2_BG_INODE_ZEROED);
527 ext2fs_bg_itable_unused_set(fs, i,
528 fs->super->s_inodes_per_group);
529 }
98f45471
ES
530
531 numblocks = ext2fs_group_blocks_count(fs, i);
532 if ((i < fs->group_desc_count - 1) && csum_flag)
533 ext2fs_bg_flags_set(fs, i, EXT2_BG_BLOCK_UNINIT);
1e1da29f 534
76dd5e5c
TT
535 has_super = ext2fs_bg_has_super(fs, i);
536 if (has_super) {
48f23054 537 ext2fs_block_alloc_stats2(fs, group_block, +1);
76dd5e5c
TT
538 adjblocks++;
539 }
f2de1d38 540 meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
76dd5e5c
TT
541 meta_bg = i / meta_bg_size;
542 if (!(fs->super->s_feature_incompat &
543 EXT2_FEATURE_INCOMPAT_META_BG) ||
544 (meta_bg < fs->super->s_first_meta_bg)) {
545 if (has_super) {
546 for (j=0; j < old_desc_blocks; j++)
48f23054 547 ext2fs_block_alloc_stats2(fs,
74128f8d 548 group_block + 1 + j, +1);
76dd5e5c
TT
549 adjblocks += old_desc_blocks;
550 }
551 } else {
552 if (has_super)
553 has_super = 1;
554 if (((i % meta_bg_size) == 0) ||
555 ((i % meta_bg_size) == 1) ||
556 ((i % meta_bg_size) == (meta_bg_size-1)))
48f23054 557 ext2fs_block_alloc_stats2(fs,
74128f8d 558 group_block + has_super, +1);
24b2c7a7 559 }
efc6f628 560
1e1da29f 561 adjblocks += 2 + fs->inode_blocks_per_group;
efc6f628 562
1e1da29f 563 numblocks -= adjblocks;
4efbac6f
VAH
564 ext2fs_free_blocks_count_set(fs->super,
565 ext2fs_free_blocks_count(fs->super) - adjblocks);
1e1da29f
TT
566 fs->super->s_free_inodes_count +=
567 fs->super->s_inodes_per_group;
d7cca6b0
VAH
568 ext2fs_bg_free_blocks_count_set(fs, i, numblocks);
569 ext2fs_bg_free_inodes_count_set(fs, i,
570 fs->super->s_inodes_per_group);
571 ext2fs_bg_used_dirs_count_set(fs, i, 0);
236efede 572 ext2fs_group_desc_csum_set(fs, i);
24b2c7a7 573
1e1da29f 574 retval = ext2fs_allocate_group_table(fs, i, 0);
c762c8e6 575 if (retval) goto errout;
24b2c7a7 576
bf69235a
TT
577 group_block += fs->super->s_blocks_per_group;
578 }
579 retval = 0;
580
581errout:
582 return (retval);
583}
584
585/*
586 * This routine adjusts the superblock and other data structures, both
587 * in disk as well as in memory...
588 */
8728d506 589static errcode_t adjust_superblock(ext2_resize_t rfs, blk64_t new_size)
bf69235a
TT
590{
591 ext2_filsys fs;
592 int adj = 0;
593 errcode_t retval;
8728d506 594 blk64_t group_block;
bf69235a
TT
595 unsigned long i;
596 unsigned long max_group;
efc6f628 597
bf69235a
TT
598 fs = rfs->new_fs;
599 ext2fs_mark_super_dirty(fs);
600 ext2fs_mark_bb_dirty(fs);
601 ext2fs_mark_ib_dirty(fs);
602
c09043f1
TT
603 retval = ext2fs_allocate_block_bitmap(fs, _("reserved blocks"),
604 &rfs->reserve_blocks);
605 if (retval)
606 return retval;
607
608 retval = adjust_fs_info(fs, rfs->old_fs, rfs->reserve_blocks, new_size);
bf69235a
TT
609 if (retval)
610 goto errout;
611
612 /*
613 * Check to make sure there are enough inodes
614 */
615 if ((rfs->old_fs->super->s_inodes_count -
616 rfs->old_fs->super->s_free_inodes_count) >
617 rfs->new_fs->super->s_inodes_count) {
618 retval = ENOSPC;
619 goto errout;
620 }
621
622 /*
623 * If we are shrinking the number block groups, we're done and
624 * can exit now.
625 */
626 if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
627 retval = 0;
628 goto errout;
629 }
630
631 /*
632 * If the number of block groups is staying the same, we're
633 * done and can exit now. (If the number block groups is
634 * shrinking, we had exited earlier.)
635 */
636 if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
637 retval = 0;
638 goto errout;
639 }
640
641 /*
2d8c0c8a
TT
642 * If we are using uninit_bg (aka GDT_CSUM) and the kernel
643 * supports lazy inode initialization, we can skip
644 * initializing the inode table.
645 */
646 if (lazy_itable_init &&
647 EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
648 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
649 retval = 0;
650 goto errout;
651 }
652
653 /*
654 * Initialize the inode table
bf69235a 655 */
e5aace90 656 retval = ext2fs_get_array(fs->blocksize, fs->inode_blocks_per_group,
bf69235a
TT
657 &rfs->itable_buf);
658 if (retval)
659 goto errout;
660
661 memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
027b0577
TT
662 group_block = ext2fs_group_first_block2(fs,
663 rfs->old_fs->group_desc_count);
bf69235a
TT
664 adj = rfs->old_fs->group_desc_count;
665 max_group = fs->group_desc_count - adj;
666 if (rfs->progress) {
667 retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
668 0, max_group);
669 if (retval)
670 goto errout;
671 }
672 for (i = rfs->old_fs->group_desc_count;
673 i < fs->group_desc_count; i++) {
05e112a1
TT
674 /*
675 * Write out the new inode table
676 */
24a117ab 677 retval = io_channel_write_blk64(fs->io,
d7cca6b0 678 ext2fs_inode_table_loc(fs, i),
24a117ab
VAH
679 fs->inode_blocks_per_group,
680 rfs->itable_buf);
c762c8e6
TT
681 if (retval) goto errout;
682
a8519a2d 683 io_channel_flush(fs->io);
3b627e8d
TT
684 if (rfs->progress) {
685 retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
686 i - adj + 1, max_group);
687 if (retval)
688 goto errout;
689 }
1e1da29f 690 group_block += fs->super->s_blocks_per_group;
24b2c7a7 691 }
c762c8e6
TT
692 io_channel_flush(fs->io);
693 retval = 0;
694
695errout:
c762c8e6
TT
696 return retval;
697}
698
a8519a2d
TT
699/* --------------------------------------------------------------------
700 *
701 * Resize processing, phase 2.
702 *
703 * In this phase we adjust determine which blocks need to be moved, in
704 * blocks_to_move(). We then copy the blocks to their ultimate new
705 * destinations using block_mover(). Since we are copying blocks to
706 * their new locations, again during this pass we can abort without
707 * any problems.
708 * --------------------------------------------------------------------
709 */
710
c762c8e6
TT
711/*
712 * This helper function creates a block bitmap with all of the
713 * filesystem meta-data blocks.
714 */
715static errcode_t mark_table_blocks(ext2_filsys fs,
64ad98ac 716 ext2fs_block_bitmap bmap)
c762c8e6 717{
54434927 718 dgrp_t i;
c762c8e6 719
c762c8e6 720 for (i = 0; i < fs->group_desc_count; i++) {
64ad98ac 721 ext2fs_reserve_super_and_bgd(fs, i, bmap);
efc6f628 722
c762c8e6
TT
723 /*
724 * Mark the blocks used for the inode table
725 */
a0ba54ec
TT
726 ext2fs_mark_block_bitmap_range2(bmap,
727 ext2fs_inode_table_loc(fs, i),
728 fs->inode_blocks_per_group);
efc6f628 729
c762c8e6 730 /*
efc6f628 731 * Mark block used for the block bitmap
c762c8e6 732 */
3346084b 733 ext2fs_mark_block_bitmap2(bmap,
d7cca6b0 734 ext2fs_block_bitmap_loc(fs, i));
64ad98ac 735
c762c8e6 736 /*
efc6f628 737 * Mark block used for the inode bitmap
c762c8e6 738 */
3346084b 739 ext2fs_mark_block_bitmap2(bmap,
d7cca6b0 740 ext2fs_inode_bitmap_loc(fs, i));
c762c8e6 741 }
1e1da29f 742 return 0;
24b2c7a7
TT
743}
744
76dd5e5c
TT
745/*
746 * This function checks to see if a particular block (either a
747 * superblock or a block group descriptor) overlaps with an inode or
748 * block bitmap block, or with the inode table.
749 */
750static void mark_fs_metablock(ext2_resize_t rfs,
751 ext2fs_block_bitmap meta_bmap,
8728d506 752 int group, blk64_t blk)
76dd5e5c
TT
753{
754 ext2_filsys fs = rfs->new_fs;
efc6f628 755
3346084b 756 ext2fs_mark_block_bitmap2(rfs->reserve_blocks, blk);
48f23054 757 ext2fs_block_alloc_stats2(fs, blk, +1);
76dd5e5c
TT
758
759 /*
760 * Check to see if we overlap with the inode or block bitmap,
761 * or the inode tables. If not, and the block is in use, then
762 * mark it as a block to be moved.
763 */
764 if (IS_BLOCK_BM(fs, group, blk)) {
d7cca6b0 765 ext2fs_block_bitmap_loc_set(fs, group, 0);
76dd5e5c 766 rfs->needed_blocks++;
ddcf1dbf
TT
767 return;
768 }
769 if (IS_INODE_BM(fs, group, blk)) {
d7cca6b0 770 ext2fs_inode_bitmap_loc_set(fs, group, 0);
76dd5e5c 771 rfs->needed_blocks++;
ddcf1dbf
TT
772 return;
773 }
774 if (IS_INODE_TB(fs, group, blk)) {
d7cca6b0 775 ext2fs_inode_table_loc_set(fs, group, 0);
76dd5e5c 776 rfs->needed_blocks++;
ddcf1dbf
TT
777 return;
778 }
779 if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) {
780 dgrp_t i;
781
782 for (i=0; i < rfs->old_fs->group_desc_count; i++) {
783 if (IS_BLOCK_BM(fs, i, blk)) {
784 ext2fs_block_bitmap_loc_set(fs, i, 0);
785 rfs->needed_blocks++;
786 return;
787 }
788 if (IS_INODE_BM(fs, i, blk)) {
789 ext2fs_inode_bitmap_loc_set(fs, i, 0);
790 rfs->needed_blocks++;
791 return;
792 }
793 if (IS_INODE_TB(fs, i, blk)) {
794 ext2fs_inode_table_loc_set(fs, i, 0);
795 rfs->needed_blocks++;
796 return;
797 }
798 }
799 }
800 if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
801 EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
cd65a24e 802 (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT))) {
86acdebd
TT
803 /*
804 * If the block bitmap is uninitialized, which means
805 * nothing other than standard metadata in use.
806 */
807 return;
3346084b
VAH
808 } else if (ext2fs_test_block_bitmap2(rfs->old_fs->block_map, blk) &&
809 !ext2fs_test_block_bitmap2(meta_bmap, blk)) {
810 ext2fs_mark_block_bitmap2(rfs->move_blocks, blk);
76dd5e5c
TT
811 rfs->needed_blocks++;
812 }
813}
814
815
24b2c7a7
TT
816/*
817 * This routine marks and unmarks reserved blocks in the new block
818 * bitmap. It also determines which blocks need to be moved and
819 * places this information into the move_blocks bitmap.
820 */
c762c8e6 821static errcode_t blocks_to_move(ext2_resize_t rfs)
24b2c7a7 822{
54434927 823 int j, has_super;
86acdebd 824 dgrp_t i, max_groups, g;
8728d506
VAH
825 blk64_t blk, group_blk;
826 blk64_t old_blocks, new_blocks;
54434927 827 unsigned int meta_bg, meta_bg_size;
24b2c7a7 828 errcode_t retval;
c762c8e6
TT
829 ext2_filsys fs, old_fs;
830 ext2fs_block_bitmap meta_bmap;
4b04fb30 831 int flex_bg;
24b2c7a7 832
c762c8e6
TT
833 fs = rfs->new_fs;
834 old_fs = rfs->old_fs;
4efbac6f 835 if (ext2fs_blocks_count(old_fs->super) > ext2fs_blocks_count(fs->super))
c762c8e6 836 fs = rfs->old_fs;
efc6f628 837
a13575f4 838 retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
c762c8e6
TT
839 &rfs->move_blocks);
840 if (retval)
841 return retval;
842
efc6f628 843 retval = ext2fs_allocate_block_bitmap(fs, _("meta-data blocks"),
64ad98ac
TT
844 &meta_bmap);
845 if (retval)
846 return retval;
efc6f628 847
64ad98ac 848 retval = mark_table_blocks(old_fs, meta_bmap);
c762c8e6
TT
849 if (retval)
850 return retval;
851
852 fs = rfs->new_fs;
efc6f628 853
1e1da29f
TT
854 /*
855 * If we're shrinking the filesystem, we need to move all of
856 * the blocks that don't fit any more
857 */
4efbac6f
VAH
858 for (blk = ext2fs_blocks_count(fs->super);
859 blk < ext2fs_blocks_count(old_fs->super); blk++) {
6493f8e8 860 g = ext2fs_group_of_blk2(fs, blk);
86acdebd
TT
861 if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
862 EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
cd65a24e 863 ext2fs_bg_flags_test(old_fs, g, EXT2_BG_BLOCK_UNINIT)) {
86acdebd
TT
864 /*
865 * The block bitmap is uninitialized, so skip
866 * to the next block group.
867 */
5d3a88fb 868 blk = ext2fs_group_first_block2(fs, g+1) - 1;
86acdebd
TT
869 continue;
870 }
3346084b
VAH
871 if (ext2fs_test_block_bitmap2(old_fs->block_map, blk) &&
872 !ext2fs_test_block_bitmap2(meta_bmap, blk)) {
873 ext2fs_mark_block_bitmap2(rfs->move_blocks, blk);
1e1da29f 874 rfs->needed_blocks++;
c762c8e6 875 }
3346084b 876 ext2fs_mark_block_bitmap2(rfs->reserve_blocks, blk);
1e1da29f 877 }
efc6f628 878
76dd5e5c
TT
879 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) {
880 old_blocks = old_fs->super->s_first_meta_bg;
881 new_blocks = fs->super->s_first_meta_bg;
882 } else {
9213a93b
TT
883 old_blocks = old_fs->desc_blocks + old_fs->super->s_reserved_gdt_blocks;
884 new_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
76dd5e5c 885 }
efc6f628 886
c762c8e6
TT
887 if (old_blocks == new_blocks) {
888 retval = 0;
889 goto errout;
890 }
24b2c7a7 891
1333fe93
TT
892 max_groups = fs->group_desc_count;
893 if (max_groups > old_fs->group_desc_count)
894 max_groups = old_fs->group_desc_count;
c762c8e6 895 group_blk = old_fs->super->s_first_data_block;
24b2c7a7
TT
896 /*
897 * If we're reducing the number of descriptor blocks, this
898 * makes life easy. :-) We just have to mark some extra
899 * blocks as free.
900 */
901 if (old_blocks > new_blocks) {
1333fe93 902 for (i = 0; i < max_groups; i++) {
1e1da29f
TT
903 if (!ext2fs_bg_has_super(fs, i)) {
904 group_blk += fs->super->s_blocks_per_group;
24b2c7a7
TT
905 continue;
906 }
c762c8e6
TT
907 for (blk = group_blk+1+new_blocks;
908 blk < group_blk+1+old_blocks; blk++) {
48f23054 909 ext2fs_block_alloc_stats2(fs, blk, -1);
052db4b7
TT
910 rfs->needed_blocks--;
911 }
1e1da29f 912 group_blk += fs->super->s_blocks_per_group;
24b2c7a7 913 }
c762c8e6
TT
914 retval = 0;
915 goto errout;
24b2c7a7
TT
916 }
917 /*
918 * If we're increasing the number of descriptor blocks, life
efc6f628 919 * gets interesting....
24b2c7a7 920 */
f2de1d38 921 meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
4b04fb30
TT
922 flex_bg = fs->super->s_feature_incompat &
923 EXT4_FEATURE_INCOMPAT_FLEX_BG;
2ebaeb35 924 /* first reserve all of the existing fs meta blocks */
1333fe93 925 for (i = 0; i < max_groups; i++) {
76dd5e5c
TT
926 has_super = ext2fs_bg_has_super(fs, i);
927 if (has_super)
928 mark_fs_metablock(rfs, meta_bmap, i, group_blk);
929
930 meta_bg = i / meta_bg_size;
931 if (!(fs->super->s_feature_incompat &
932 EXT2_FEATURE_INCOMPAT_META_BG) ||
933 (meta_bg < fs->super->s_first_meta_bg)) {
424cb7b6
TT
934 if (has_super) {
935 for (blk = group_blk+1;
936 blk < group_blk + 1 + new_blocks; blk++)
efc6f628 937 mark_fs_metablock(rfs, meta_bmap,
424cb7b6
TT
938 i, blk);
939 }
76dd5e5c
TT
940 } else {
941 if (has_super)
942 has_super = 1;
943 if (((i % meta_bg_size) == 0) ||
944 ((i % meta_bg_size) == 1) ||
945 ((i % meta_bg_size) == (meta_bg_size-1)))
946 mark_fs_metablock(rfs, meta_bmap, i,
947 group_blk + has_super);
24b2c7a7 948 }
76dd5e5c 949
1e1da29f 950 /*
c762c8e6
TT
951 * Reserve the existing meta blocks that we know
952 * aren't to be moved.
4b04fb30
TT
953 *
954 * For flex_bg file systems, in order to avoid
955 * overwriting fs metadata (especially inode table
956 * blocks) belonging to a different block group when
957 * we are relocating the inode tables, we need to
958 * reserve all existing fs metadata blocks.
1e1da29f 959 */
d7cca6b0 960 if (ext2fs_block_bitmap_loc(fs, i))
3346084b 961 ext2fs_mark_block_bitmap2(rfs->reserve_blocks,
d7cca6b0 962 ext2fs_block_bitmap_loc(fs, i));
4b04fb30
TT
963 else if (flex_bg && i < old_fs->group_desc_count)
964 ext2fs_mark_block_bitmap2(rfs->reserve_blocks,
965 ext2fs_block_bitmap_loc(old_fs, i));
966
d7cca6b0 967 if (ext2fs_inode_bitmap_loc(fs, i))
3346084b 968 ext2fs_mark_block_bitmap2(rfs->reserve_blocks,
d7cca6b0 969 ext2fs_inode_bitmap_loc(fs, i));
4b04fb30
TT
970 else if (flex_bg && i < old_fs->group_desc_count)
971 ext2fs_mark_block_bitmap2(rfs->reserve_blocks,
972 ext2fs_inode_bitmap_loc(old_fs, i));
973
d7cca6b0 974 if (ext2fs_inode_table_loc(fs, i))
a0ba54ec
TT
975 ext2fs_mark_block_bitmap_range2(rfs->reserve_blocks,
976 ext2fs_inode_table_loc(fs, i),
977 fs->inode_blocks_per_group);
4b04fb30 978 else if (flex_bg && i < old_fs->group_desc_count)
a0ba54ec
TT
979 ext2fs_mark_block_bitmap_range2(rfs->reserve_blocks,
980 ext2fs_inode_table_loc(old_fs, i),
981 old_fs->inode_blocks_per_group);
24b2c7a7 982
2ebaeb35
TT
983 group_blk += rfs->new_fs->super->s_blocks_per_group;
984 }
985
986 /* Allocate the missing data structures */
987 for (i = 0; i < max_groups; i++) {
988 if (ext2fs_inode_table_loc(fs, i) &&
989 ext2fs_inode_bitmap_loc(fs, i) &&
990 ext2fs_block_bitmap_loc(fs, i))
991 continue;
992
1e1da29f
TT
993 retval = ext2fs_allocate_group_table(fs, i,
994 rfs->reserve_blocks);
995 if (retval)
c762c8e6 996 goto errout;
24b2c7a7 997
1e1da29f 998 /*
c762c8e6
TT
999 * For those structures that have changed, we need to
1000 * do bookkeepping.
1e1da29f 1001 */
d7cca6b0
VAH
1002 if (ext2fs_block_bitmap_loc(old_fs, i) !=
1003 (blk = ext2fs_block_bitmap_loc(fs, i))) {
48f23054 1004 ext2fs_block_alloc_stats2(fs, blk, +1);
3346084b
VAH
1005 if (ext2fs_test_block_bitmap2(old_fs->block_map, blk) &&
1006 !ext2fs_test_block_bitmap2(meta_bmap, blk))
1007 ext2fs_mark_block_bitmap2(rfs->move_blocks,
c762c8e6
TT
1008 blk);
1009 }
d7cca6b0
VAH
1010 if (ext2fs_inode_bitmap_loc(old_fs, i) !=
1011 (blk = ext2fs_inode_bitmap_loc(fs, i))) {
48f23054 1012 ext2fs_block_alloc_stats2(fs, blk, +1);
3346084b
VAH
1013 if (ext2fs_test_block_bitmap2(old_fs->block_map, blk) &&
1014 !ext2fs_test_block_bitmap2(meta_bmap, blk))
1015 ext2fs_mark_block_bitmap2(rfs->move_blocks,
c762c8e6
TT
1016 blk);
1017 }
24b2c7a7 1018
052db4b7
TT
1019 /*
1020 * The inode table, if we need to relocate it, is
1021 * handled specially. We have to reserve the blocks
1022 * for both the old and the new inode table, since we
1023 * can't have the inode table be destroyed during the
1024 * block relocation phase.
1025 */
d7cca6b0 1026 if (ext2fs_inode_table_loc(fs, i) == ext2fs_inode_table_loc(old_fs, i))
2ebaeb35 1027 continue; /* inode table not moved */
052db4b7 1028
c762c8e6 1029 rfs->needed_blocks += fs->inode_blocks_per_group;
052db4b7
TT
1030
1031 /*
1032 * Mark the new inode table as in use in the new block
efc6f628 1033 * allocation bitmap, and move any blocks that might
c762c8e6 1034 * be necessary.
052db4b7 1035 */
d7cca6b0 1036 for (blk = ext2fs_inode_table_loc(fs, i), j=0;
c762c8e6 1037 j < fs->inode_blocks_per_group ; j++, blk++) {
48f23054 1038 ext2fs_block_alloc_stats2(fs, blk, +1);
3346084b
VAH
1039 if (ext2fs_test_block_bitmap2(old_fs->block_map, blk) &&
1040 !ext2fs_test_block_bitmap2(meta_bmap, blk))
1041 ext2fs_mark_block_bitmap2(rfs->move_blocks,
c762c8e6
TT
1042 blk);
1043 }
efc6f628 1044
1e1da29f 1045 /*
052db4b7
TT
1046 * Make sure the old inode table is reserved in the
1047 * block reservation bitmap.
1e1da29f 1048 */
d7cca6b0 1049 for (blk = ext2fs_inode_table_loc(rfs->old_fs, i), j=0;
052db4b7 1050 j < fs->inode_blocks_per_group ; j++, blk++)
3346084b 1051 ext2fs_mark_block_bitmap2(rfs->reserve_blocks, blk);
1e1da29f 1052 }
c762c8e6
TT
1053 retval = 0;
1054
1055errout:
1056 if (meta_bmap)
1057 ext2fs_free_block_bitmap(meta_bmap);
efc6f628 1058
c762c8e6 1059 return retval;
1e1da29f 1060}
24b2c7a7 1061
a8519a2d
TT
1062/*
1063 * This helper function tries to allocate a new block. We try to
1064 * avoid hitting the original group descriptor blocks at least at
1065 * first, since we want to make it possible to recover from a badly
1066 * aborted resize operation as much as possible.
1067 *
1068 * In the future, I may further modify this routine to balance out
1069 * where we get the new blocks across the various block groups.
1070 * Ideally we would allocate blocks that corresponded with the block
1071 * group of the containing inode, and keep contiguous blocks
1072 * together. However, this very difficult to do efficiently, since we
1073 * don't have the necessary information up front.
1074 */
1075
1076#define AVOID_OLD 1
1077#define DESPERATION 2
1078
1079static void init_block_alloc(ext2_resize_t rfs)
1080{
1081 rfs->alloc_state = AVOID_OLD;
1082 rfs->new_blk = rfs->new_fs->super->s_first_data_block;
2bc4d4f7
TT
1083#if 0
1084 /* HACK for testing */
4efbac6f
VAH
1085 if (ext2fs_blocks_count(rfs->new_fs->super) >
1086 ext2fs_blocks_count(rfs->old_fs->super))
1087 rfs->new_blk = ext2fs_blocks_count(rfs->old_fs->super);
2bc4d4f7 1088#endif
a8519a2d
TT
1089}
1090
8728d506 1091static blk64_t get_new_block(ext2_resize_t rfs)
a8519a2d
TT
1092{
1093 ext2_filsys fs = rfs->new_fs;
efc6f628 1094
a8519a2d 1095 while (1) {
4efbac6f 1096 if (rfs->new_blk >= ext2fs_blocks_count(fs->super)) {
a8519a2d
TT
1097 if (rfs->alloc_state == DESPERATION)
1098 return 0;
1099
1100#ifdef RESIZE2FS_DEBUG
1101 if (rfs->flags & RESIZE_DEBUG_BMOVE)
f35fd3d5
TT
1102 printf("Going into desperation mode "
1103 "for block allocations\n");
efc6f628 1104#endif
a8519a2d
TT
1105 rfs->alloc_state = DESPERATION;
1106 rfs->new_blk = fs->super->s_first_data_block;
1107 continue;
1108 }
3346084b
VAH
1109 if (ext2fs_test_block_bitmap2(fs->block_map, rfs->new_blk) ||
1110 ext2fs_test_block_bitmap2(rfs->reserve_blocks,
a8519a2d
TT
1111 rfs->new_blk) ||
1112 ((rfs->alloc_state == AVOID_OLD) &&
4efbac6f 1113 (rfs->new_blk < ext2fs_blocks_count(rfs->old_fs->super)) &&
3346084b 1114 ext2fs_test_block_bitmap2(rfs->old_fs->block_map,
a8519a2d
TT
1115 rfs->new_blk))) {
1116 rfs->new_blk++;
1117 continue;
1118 }
1119 return rfs->new_blk;
1120 }
1121}
1122
7f9c96ee
TT
1123static errcode_t resize2fs_get_alloc_block(ext2_filsys fs, blk64_t goal,
1124 blk64_t *ret)
1125{
1126 ext2_resize_t rfs = (ext2_resize_t) fs->priv_data;
8728d506 1127 blk64_t blk;
7f9c96ee
TT
1128
1129 blk = get_new_block(rfs);
1130 if (!blk)
1131 return ENOSPC;
1132
1133#ifdef RESIZE2FS_DEBUG
1134 if (rfs->flags & 0xF)
8728d506 1135 printf("get_alloc_block allocating %llu\n", blk);
7f9c96ee
TT
1136#endif
1137
3346084b
VAH
1138 ext2fs_mark_block_bitmap2(rfs->old_fs->block_map, blk);
1139 ext2fs_mark_block_bitmap2(rfs->new_fs->block_map, blk);
7f9c96ee
TT
1140 *ret = (blk64_t) blk;
1141 return 0;
1142}
1143
a8519a2d
TT
1144static errcode_t block_mover(ext2_resize_t rfs)
1145{
8728d506 1146 blk64_t blk, old_blk, new_blk;
a8519a2d
TT
1147 ext2_filsys fs = rfs->new_fs;
1148 ext2_filsys old_fs = rfs->old_fs;
1149 errcode_t retval;
8728d506
VAH
1150 __u64 size;
1151 int c;
a8519a2d 1152 int to_move, moved;
7d7bdd57
TT
1153 ext2_badblocks_list badblock_list = 0;
1154 int bb_modified = 0;
efc6f628 1155
7f9c96ee
TT
1156 fs->get_alloc_block = resize2fs_get_alloc_block;
1157 old_fs->get_alloc_block = resize2fs_get_alloc_block;
1158
7d7bdd57
TT
1159 retval = ext2fs_read_bb_inode(old_fs, &badblock_list);
1160 if (retval)
1161 return retval;
a8519a2d
TT
1162
1163 new_blk = fs->super->s_first_data_block;
1164 if (!rfs->itable_buf) {
e5aace90 1165 retval = ext2fs_get_array(fs->blocksize,
a8519a2d 1166 fs->inode_blocks_per_group,
c4e3d3f3 1167 &rfs->itable_buf);
a8519a2d
TT
1168 if (retval)
1169 return retval;
1170 }
1171 retval = ext2fs_create_extent_table(&rfs->bmap, 0);
1172 if (retval)
1173 return retval;
1174
1175 /*
1176 * The first step is to figure out where all of the blocks
1177 * will go.
1178 */
1179 to_move = moved = 0;
1180 init_block_alloc(rfs);
1181 for (blk = old_fs->super->s_first_data_block;
4efbac6f 1182 blk < ext2fs_blocks_count(old_fs->super); blk++) {
3346084b 1183 if (!ext2fs_test_block_bitmap2(old_fs->block_map, blk))
a8519a2d 1184 continue;
3346084b 1185 if (!ext2fs_test_block_bitmap2(rfs->move_blocks, blk))
a8519a2d 1186 continue;
7d7bdd57
TT
1187 if (ext2fs_badblocks_list_test(badblock_list, blk)) {
1188 ext2fs_badblocks_list_del(badblock_list, blk);
1189 bb_modified++;
1190 continue;
1191 }
a8519a2d
TT
1192
1193 new_blk = get_new_block(rfs);
1194 if (!new_blk) {
1195 retval = ENOSPC;
1196 goto errout;
1197 }
48f23054 1198 ext2fs_block_alloc_stats2(fs, new_blk, +1);
a8519a2d
TT
1199 ext2fs_add_extent_entry(rfs->bmap, blk, new_blk);
1200 to_move++;
1201 }
efc6f628 1202
a8519a2d 1203 if (to_move == 0) {
cefbf487
TT
1204 if (rfs->bmap) {
1205 ext2fs_free_extent_table(rfs->bmap);
1206 rfs->bmap = 0;
1207 }
a8519a2d
TT
1208 retval = 0;
1209 goto errout;
1210 }
1211
1212 /*
1213 * Step two is to actually move the blocks
1214 */
1215 retval = ext2fs_iterate_extent(rfs->bmap, 0, 0, 0);
1216 if (retval) goto errout;
1217
3b627e8d
TT
1218 if (rfs->progress) {
1219 retval = (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS,
1220 0, to_move);
1221 if (retval)
1222 goto errout;
1223 }
a8519a2d
TT
1224 while (1) {
1225 retval = ext2fs_iterate_extent(rfs->bmap, &old_blk, &new_blk, &size);
1226 if (retval) goto errout;
1227 if (!size)
1228 break;
1229#ifdef RESIZE2FS_DEBUG
1230 if (rfs->flags & RESIZE_DEBUG_BMOVE)
8728d506 1231 printf("Moving %llu blocks %llu->%llu\n",
f35fd3d5 1232 size, old_blk, new_blk);
a8519a2d
TT
1233#endif
1234 do {
1235 c = size;
1236 if (c > fs->inode_blocks_per_group)
1237 c = fs->inode_blocks_per_group;
24a117ab
VAH
1238 retval = io_channel_read_blk64(fs->io, old_blk, c,
1239 rfs->itable_buf);
a8519a2d 1240 if (retval) goto errout;
24a117ab
VAH
1241 retval = io_channel_write_blk64(fs->io, new_blk, c,
1242 rfs->itable_buf);
a8519a2d
TT
1243 if (retval) goto errout;
1244 size -= c;
1245 new_blk += c;
1246 old_blk += c;
1247 moved += c;
1248 if (rfs->progress) {
1249 io_channel_flush(fs->io);
3b627e8d
TT
1250 retval = (rfs->progress)(rfs,
1251 E2_RSZ_BLOCK_RELOC_PASS,
a8519a2d 1252 moved, to_move);
3b627e8d
TT
1253 if (retval)
1254 goto errout;
a8519a2d
TT
1255 }
1256 } while (size > 0);
1257 io_channel_flush(fs->io);
1258 }
1259
1260errout:
7d7bdd57
TT
1261 if (badblock_list) {
1262 if (!retval && bb_modified)
1263 retval = ext2fs_update_bb_inode(old_fs,
1264 badblock_list);
1265 ext2fs_badblocks_list_free(badblock_list);
1266 }
a8519a2d
TT
1267 return retval;
1268}
1269
1270
1271/* --------------------------------------------------------------------
1272 *
1273 * Resize processing, phase 3
1274 *
1275 * --------------------------------------------------------------------
1276 */
1277
1278
1279struct process_block_struct {
1280 ext2_resize_t rfs;
dfcdc32f 1281 ext2_ino_t ino;
a8519a2d
TT
1282 struct ext2_inode * inode;
1283 errcode_t error;
1284 int is_dir;
1285 int changed;
1286};
1287
8728d506 1288static int process_block(ext2_filsys fs, blk64_t *block_nr,
efc6f628 1289 e2_blkcnt_t blockcnt,
8728d506 1290 blk64_t ref_block EXT2FS_ATTR((unused)),
54434927 1291 int ref_offset EXT2FS_ATTR((unused)), void *priv_data)
a8519a2d
TT
1292{
1293 struct process_block_struct *pb;
1294 errcode_t retval;
8728d506 1295 blk64_t block, new_block;
a8519a2d
TT
1296 int ret = 0;
1297
1298 pb = (struct process_block_struct *) priv_data;
1299 block = *block_nr;
1300 if (pb->rfs->bmap) {
1301 new_block = ext2fs_extent_translate(pb->rfs->bmap, block);
1302 if (new_block) {
1303 *block_nr = new_block;
1304 ret |= BLOCK_CHANGED;
1305 pb->changed = 1;
1306#ifdef RESIZE2FS_DEBUG
1307 if (pb->rfs->flags & RESIZE_DEBUG_BMOVE)
8728d506 1308 printf("ino=%u, blockcnt=%lld, %llu->%llu\n",
a8519a2d
TT
1309 pb->ino, blockcnt, block, new_block);
1310#endif
1311 block = new_block;
1312 }
1313 }
1314 if (pb->is_dir) {
8728d506
VAH
1315 retval = ext2fs_add_dir_block2(fs->dblist, pb->ino,
1316 block, (int) blockcnt);
a8519a2d
TT
1317 if (retval) {
1318 pb->error = retval;
1319 ret |= BLOCK_ABORT;
1320 }
1321 }
1322 return ret;
1323}
1324
1325/*
1326 * Progress callback
1327 */
efc6f628 1328static errcode_t progress_callback(ext2_filsys fs,
54434927 1329 ext2_inode_scan scan EXT2FS_ATTR((unused)),
a8519a2d
TT
1330 dgrp_t group, void * priv_data)
1331{
1332 ext2_resize_t rfs = (ext2_resize_t) priv_data;
3b627e8d 1333 errcode_t retval;
a8519a2d
TT
1334
1335 /*
f4b2a6db
TT
1336 * This check is to protect against old ext2 libraries. It
1337 * shouldn't be needed against new libraries.
a8519a2d 1338 */
f4b2a6db 1339 if ((group+1) == 0)
a8519a2d
TT
1340 return 0;
1341
1342 if (rfs->progress) {
1343 io_channel_flush(fs->io);
3b627e8d
TT
1344 retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
1345 group+1, fs->group_desc_count);
1346 if (retval)
1347 return retval;
a8519a2d 1348 }
efc6f628 1349
a8519a2d
TT
1350 return 0;
1351}
1352
1353static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
1354{
1355 struct process_block_struct pb;
dfcdc32f 1356 ext2_ino_t ino, new_inode;
edfd9b0a 1357 struct ext2_inode *inode = NULL;
a8519a2d
TT
1358 ext2_inode_scan scan = NULL;
1359 errcode_t retval;
a8519a2d 1360 char *block_buf = 0;
dfcdc32f 1361 ext2_ino_t start_to_move;
8728d506
VAH
1362 blk64_t orig_size;
1363 blk64_t new_block;
4ef28824 1364 int inode_size;
efc6f628 1365
a8519a2d
TT
1366 if ((rfs->old_fs->group_desc_count <=
1367 rfs->new_fs->group_desc_count) &&
1368 !rfs->bmap)
1369 return 0;
1370
2bc4d4f7
TT
1371 /*
1372 * Save the original size of the old filesystem, and
1373 * temporarily set the size to be the new size if the new size
1374 * is larger. We need to do this to avoid catching an error
1375 * by the block iterator routines
1376 */
4efbac6f
VAH
1377 orig_size = ext2fs_blocks_count(rfs->old_fs->super);
1378 if (orig_size < ext2fs_blocks_count(rfs->new_fs->super))
1379 ext2fs_blocks_count_set(rfs->old_fs->super,
1380 ext2fs_blocks_count(rfs->new_fs->super));
2bc4d4f7 1381
a8519a2d
TT
1382 retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
1383 if (retval) goto errout;
1384
1385 retval = ext2fs_init_dblist(rfs->old_fs, 0);
1386 if (retval) goto errout;
e5aace90 1387 retval = ext2fs_get_array(rfs->old_fs->blocksize, 3, &block_buf);
a8519a2d
TT
1388 if (retval) goto errout;
1389
1390 start_to_move = (rfs->new_fs->group_desc_count *
1391 rfs->new_fs->super->s_inodes_per_group);
efc6f628 1392
3b627e8d
TT
1393 if (rfs->progress) {
1394 retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
1395 0, rfs->old_fs->group_desc_count);
1396 if (retval)
1397 goto errout;
1398 }
a8519a2d
TT
1399 ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
1400 pb.rfs = rfs;
edfd9b0a 1401 pb.inode = inode;
a8519a2d
TT
1402 pb.error = 0;
1403 new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
4ef28824 1404 inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
edfd9b0a
TT
1405 inode = malloc(inode_size);
1406 if (!inode) {
4ef28824
ES
1407 retval = ENOMEM;
1408 goto errout;
1409 }
a8519a2d
TT
1410 /*
1411 * First, copy all of the inodes that need to be moved
1412 * elsewhere in the inode table
1413 */
1414 while (1) {
edfd9b0a 1415 retval = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
a8519a2d
TT
1416 if (retval) goto errout;
1417 if (!ino)
1418 break;
1419
edfd9b0a 1420 if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
a8519a2d
TT
1421 continue; /* inode not in use */
1422
edfd9b0a 1423 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
a8519a2d
TT
1424 pb.changed = 0;
1425
0c80c44b 1426 if (ext2fs_file_acl_block(rfs->old_fs, inode) && rfs->bmap) {
efc6f628 1427 new_block = ext2fs_extent_translate(rfs->bmap,
0c80c44b 1428 ext2fs_file_acl_block(rfs->old_fs, inode));
ed909bbe 1429 if (new_block) {
0c80c44b
TT
1430 ext2fs_file_acl_block_set(rfs->old_fs, inode,
1431 new_block);
efc6f628 1432 retval = ext2fs_write_inode_full(rfs->old_fs,
edfd9b0a 1433 ino, inode, inode_size);
ed909bbe
TT
1434 if (retval) goto errout;
1435 }
1436 }
efc6f628 1437
0c80c44b 1438 if (ext2fs_inode_has_valid_blocks2(rfs->old_fs, inode) &&
a8519a2d
TT
1439 (rfs->bmap || pb.is_dir)) {
1440 pb.ino = ino;
8728d506 1441 retval = ext2fs_block_iterate3(rfs->old_fs,
a8519a2d
TT
1442 ino, 0, block_buf,
1443 process_block, &pb);
1444 if (retval)
1445 goto errout;
1446 if (pb.error) {
1447 retval = pb.error;
1448 goto errout;
1449 }
1450 }
1451
1452 if (ino <= start_to_move)
1453 continue; /* Don't need to move it. */
1454
1455 /*
1456 * Find a new inode
1457 */
86acdebd
TT
1458 retval = ext2fs_new_inode(rfs->new_fs, 0, 0, 0, &new_inode);
1459 if (retval)
1460 goto errout;
1461
74128f8d
TT
1462 ext2fs_inode_alloc_stats2(rfs->new_fs, new_inode, +1,
1463 pb.is_dir);
a8519a2d
TT
1464 if (pb.changed) {
1465 /* Get the new version of the inode */
4ef28824 1466 retval = ext2fs_read_inode_full(rfs->old_fs, ino,
edfd9b0a 1467 inode, inode_size);
a8519a2d
TT
1468 if (retval) goto errout;
1469 }
edfd9b0a 1470 inode->i_ctime = time(0);
4ef28824 1471 retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
edfd9b0a 1472 inode, inode_size);
a8519a2d
TT
1473 if (retval) goto errout;
1474
a8519a2d
TT
1475#ifdef RESIZE2FS_DEBUG
1476 if (rfs->flags & RESIZE_DEBUG_INODEMAP)
f35fd3d5 1477 printf("Inode moved %u->%u\n", ino, new_inode);
a8519a2d
TT
1478#endif
1479 if (!rfs->imap) {
1480 retval = ext2fs_create_extent_table(&rfs->imap, 0);
1481 if (retval)
1482 goto errout;
1483 }
1484 ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
1485 }
1486 io_channel_flush(rfs->old_fs->io);
1487
1488errout:
4efbac6f 1489 ext2fs_blocks_count_set(rfs->old_fs->super, orig_size);
a8519a2d
TT
1490 if (rfs->bmap) {
1491 ext2fs_free_extent_table(rfs->bmap);
1492 rfs->bmap = 0;
1493 }
1494 if (scan)
1495 ext2fs_close_inode_scan(scan);
1496 if (block_buf)
c4e3d3f3 1497 ext2fs_free_mem(&block_buf);
45e338f5 1498 free(inode);
a8519a2d
TT
1499 return retval;
1500}
1501
1502/* --------------------------------------------------------------------
1503 *
1504 * Resize processing, phase 4.
1505 *
1506 * --------------------------------------------------------------------
1507 */
1508
1509struct istruct {
1510 ext2_resize_t rfs;
3b627e8d 1511 errcode_t err;
03fa6f8a
TT
1512 unsigned int max_dirs;
1513 unsigned int num;
a8519a2d
TT
1514};
1515
efc6f628 1516static int check_and_change_inodes(ext2_ino_t dir,
54434927 1517 int entry EXT2FS_ATTR((unused)),
a8519a2d 1518 struct ext2_dir_entry *dirent, int offset,
54434927 1519 int blocksize EXT2FS_ATTR((unused)),
efc6f628 1520 char *buf EXT2FS_ATTR((unused)),
54434927 1521 void *priv_data)
a8519a2d
TT
1522{
1523 struct istruct *is = (struct istruct *) priv_data;
085d2a83
TT
1524 struct ext2_inode inode;
1525 ext2_ino_t new_inode;
1526 errcode_t retval;
a8519a2d
TT
1527
1528 if (is->rfs->progress && offset == 0) {
1529 io_channel_flush(is->rfs->old_fs->io);
3b627e8d
TT
1530 is->err = (is->rfs->progress)(is->rfs,
1531 E2_RSZ_INODE_REF_UPD_PASS,
1333fe93 1532 ++is->num, is->max_dirs);
3b627e8d
TT
1533 if (is->err)
1534 return DIRENT_ABORT;
a8519a2d
TT
1535 }
1536
1537 if (!dirent->inode)
1538 return 0;
1539
1540 new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
1541
1542 if (!new_inode)
1543 return 0;
1544#ifdef RESIZE2FS_DEBUG
1545 if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
f35fd3d5 1546 printf("Inode translate (dir=%u, name=%.*s, %u->%u)\n",
06191693 1547 dir, dirent->name_len&0xFF, dirent->name,
a8519a2d
TT
1548 dirent->inode, new_inode);
1549#endif
1550
1551 dirent->inode = new_inode;
1552
085d2a83
TT
1553 /* Update the directory mtime and ctime */
1554 retval = ext2fs_read_inode(is->rfs->old_fs, dir, &inode);
1555 if (retval == 0) {
1556 inode.i_mtime = inode.i_ctime = time(0);
d2b2a488
BB
1557 is->err = ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
1558 if (is->err)
1559 return DIRENT_ABORT;
085d2a83
TT
1560 }
1561
a8519a2d
TT
1562 return DIRENT_CHANGED;
1563}
1564
1565static errcode_t inode_ref_fix(ext2_resize_t rfs)
1566{
1567 errcode_t retval;
1568 struct istruct is;
efc6f628 1569
a8519a2d
TT
1570 if (!rfs->imap)
1571 return 0;
efc6f628 1572
a8519a2d
TT
1573 /*
1574 * Now, we iterate over all of the directories to update the
1575 * inode references
1576 */
1577 is.num = 0;
8728d506 1578 is.max_dirs = ext2fs_dblist_count2(rfs->old_fs->dblist);
a8519a2d 1579 is.rfs = rfs;
3b627e8d 1580 is.err = 0;
a8519a2d 1581
3b627e8d
TT
1582 if (rfs->progress) {
1583 retval = (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
1333fe93 1584 0, is.max_dirs);
3b627e8d
TT
1585 if (retval)
1586 goto errout;
1587 }
efc6f628 1588
a8519a2d
TT
1589 retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
1590 DIRENT_FLAG_INCLUDE_EMPTY, 0,
1591 check_and_change_inodes, &is);
3b627e8d
TT
1592 if (retval)
1593 goto errout;
1594 if (is.err) {
1595 retval = is.err;
1596 goto errout;
1597 }
a8519a2d 1598
88dbf828
TT
1599 if (rfs->progress && (is.num < is.max_dirs))
1600 (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
1601 is.max_dirs, is.max_dirs);
1602
3b627e8d 1603errout:
a8519a2d
TT
1604 ext2fs_free_extent_table(rfs->imap);
1605 rfs->imap = 0;
1606 return retval;
1607}
1608
1609
1610/* --------------------------------------------------------------------
1611 *
1612 * Resize processing, phase 5.
1613 *
1614 * In this phase we actually move the inode table around, and then
1615 * update the summary statistics. This is scary, since aborting here
1616 * will potentially scramble the filesystem. (We are moving the
1617 * inode tables around in place, and so the potential for lost data,
1618 * or at the very least scrambling the mapping between filenames and
1619 * inode numbers is very high in case of a power failure here.)
1620 * --------------------------------------------------------------------
1621 */
1622
24b2c7a7 1623
052db4b7
TT
1624/*
1625 * A very scary routine --- this one moves the inode table around!!!
1626 *
1627 * After this you have to use the rfs->new_fs file handle to read and
1628 * write inodes.
1629 */
c762c8e6 1630static errcode_t move_itables(ext2_resize_t rfs)
052db4b7 1631{
8728d506
VAH
1632 int n, num, size;
1633 long long diff;
54434927 1634 dgrp_t i, max_groups;
052db4b7 1635 ext2_filsys fs = rfs->new_fs;
05e112a1 1636 char *cp;
8728d506 1637 blk64_t old_blk, new_blk, blk;
a8519a2d 1638 errcode_t retval;
64ad98ac 1639 int j, to_move, moved;
052db4b7 1640
1333fe93
TT
1641 max_groups = fs->group_desc_count;
1642 if (max_groups > rfs->old_fs->group_desc_count)
1643 max_groups = rfs->old_fs->group_desc_count;
052db4b7 1644
05e112a1
TT
1645 size = fs->blocksize * fs->inode_blocks_per_group;
1646 if (!rfs->itable_buf) {
c4e3d3f3 1647 retval = ext2fs_get_mem(size, &rfs->itable_buf);
ca8abba7
TT
1648 if (retval)
1649 return retval;
05e112a1 1650 }
c762c8e6
TT
1651
1652 /*
1653 * Figure out how many inode tables we need to move
1654 */
1655 to_move = moved = 0;
1333fe93 1656 for (i=0; i < max_groups; i++)
d7cca6b0
VAH
1657 if (ext2fs_inode_table_loc(rfs->old_fs, i) !=
1658 ext2fs_inode_table_loc(fs, i))
c762c8e6
TT
1659 to_move++;
1660
1661 if (to_move == 0)
1662 return 0;
1663
3b627e8d
TT
1664 if (rfs->progress) {
1665 retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
1666 0, to_move);
1667 if (retval)
1668 goto errout;
1669 }
63b44fbe 1670
a8519a2d
TT
1671 rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
1672
1333fe93 1673 for (i=0; i < max_groups; i++) {
d7cca6b0
VAH
1674 old_blk = ext2fs_inode_table_loc(rfs->old_fs, i);
1675 new_blk = ext2fs_inode_table_loc(fs, i);
ca8abba7 1676 diff = new_blk - old_blk;
efc6f628 1677
80c0fc34 1678#ifdef RESIZE2FS_DEBUG
efc6f628 1679 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
8728d506 1680 printf("Itable move group %d block %llu->%llu (diff %lld)\n",
ca8abba7 1681 i, old_blk, new_blk, diff);
80c0fc34 1682#endif
efc6f628 1683
05e112a1 1684 if (!diff)
052db4b7
TT
1685 continue;
1686
24a117ab
VAH
1687 retval = io_channel_read_blk64(fs->io, old_blk,
1688 fs->inode_blocks_per_group,
1689 rfs->itable_buf);
efc6f628 1690 if (retval)
a8519a2d 1691 goto errout;
05e112a1
TT
1692 /*
1693 * The end of the inode table segment often contains
a8519a2d
TT
1694 * all zeros, and we're often only moving the inode
1695 * table down a block or two. If so, we can optimize
1696 * things by not rewriting blocks that we know to be zero
1697 * already.
05e112a1 1698 */
2787276e 1699 for (cp = rfs->itable_buf+size-1, n=0; n < size; n++, cp--)
05e112a1
TT
1700 if (*cp)
1701 break;
1702 n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
80c0fc34 1703#ifdef RESIZE2FS_DEBUG
efc6f628 1704 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
f35fd3d5 1705 printf("%d blocks of zeros...\n", n);
80c0fc34 1706#endif
05e112a1
TT
1707 num = fs->inode_blocks_per_group;
1708 if (n > diff)
1709 num -= n;
1710
24a117ab
VAH
1711 retval = io_channel_write_blk64(fs->io, new_blk,
1712 num, rfs->itable_buf);
052db4b7 1713 if (retval) {
24a117ab
VAH
1714 io_channel_write_blk64(fs->io, old_blk,
1715 num, rfs->itable_buf);
a8519a2d 1716 goto errout;
052db4b7 1717 }
05e112a1 1718 if (n > diff) {
24a117ab 1719 retval = io_channel_write_blk64(fs->io,
ca8abba7 1720 old_blk + fs->inode_blocks_per_group,
a8519a2d
TT
1721 diff, (rfs->itable_buf +
1722 (fs->inode_blocks_per_group - diff) *
1723 fs->blocksize));
05e112a1 1724 if (retval)
a8519a2d 1725 goto errout;
c762c8e6 1726 }
64ad98ac 1727
d7cca6b0 1728 for (blk = ext2fs_inode_table_loc(rfs->old_fs, i), j=0;
64ad98ac 1729 j < fs->inode_blocks_per_group ; j++, blk++)
48f23054 1730 ext2fs_block_alloc_stats2(fs, blk, -1);
64ad98ac 1731
d7cca6b0 1732 ext2fs_inode_table_loc_set(rfs->old_fs, i, new_blk);
236efede 1733 ext2fs_group_desc_csum_set(rfs->old_fs, i);
a8519a2d 1734 ext2fs_mark_super_dirty(rfs->old_fs);
64ad98ac
TT
1735 ext2fs_flush(rfs->old_fs);
1736
a8519a2d 1737 if (rfs->progress) {
3b627e8d
TT
1738 retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
1739 ++moved, to_move);
1740 if (retval)
1741 goto errout;
a8519a2d 1742 }
052db4b7 1743 }
64ad98ac 1744 mark_table_blocks(fs, fs->block_map);
a8519a2d 1745 ext2fs_flush(fs);
80c0fc34 1746#ifdef RESIZE2FS_DEBUG
efc6f628 1747 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
f35fd3d5 1748 printf("Inode table move finished.\n");
80c0fc34 1749#endif
052db4b7 1750 return 0;
efc6f628 1751
a8519a2d 1752errout:
052db4b7
TT
1753 return retval;
1754}
1755
9213a93b 1756/*
efc6f628 1757 * Fix the resize inode
9213a93b
TT
1758 */
1759static errcode_t fix_resize_inode(ext2_filsys fs)
1760{
1761 struct ext2_inode inode;
1762 errcode_t retval;
5e27a274 1763 char *block_buf = NULL;
9213a93b 1764
efc6f628 1765 if (!(fs->super->s_feature_compat &
9213a93b
TT
1766 EXT2_FEATURE_COMPAT_RESIZE_INODE))
1767 return 0;
1768
1769 retval = ext2fs_get_mem(fs->blocksize, &block_buf);
1770 if (retval) goto errout;
1771
1772 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
1773 if (retval) goto errout;
1774
1ca1059f 1775 ext2fs_iblk_set(fs, &inode, 1);
9213a93b
TT
1776
1777 retval = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
1778 if (retval) goto errout;
1779
1780 if (!inode.i_block[EXT2_DIND_BLOCK]) {
efc6f628 1781 /*
9213a93b
TT
1782 * Avoid zeroing out block #0; that's rude. This
1783 * should never happen anyway since the filesystem
1784 * should be fsck'ed and we assume it is consistent.
1785 */
efc6f628 1786 fprintf(stderr,
f35fd3d5 1787 _("Should never happen: resize inode corrupt!\n"));
9213a93b
TT
1788 exit(1);
1789 }
1790
1791 memset(block_buf, 0, fs->blocksize);
1792
24a117ab
VAH
1793 retval = io_channel_write_blk64(fs->io, inode.i_block[EXT2_DIND_BLOCK],
1794 1, block_buf);
9213a93b 1795 if (retval) goto errout;
efc6f628 1796
9213a93b
TT
1797 retval = ext2fs_create_resize_inode(fs);
1798 if (retval)
1799 goto errout;
1800
1801errout:
1802 if (block_buf)
1803 ext2fs_free_mem(&block_buf);
1804 return retval;
1805}
1806
052db4b7
TT
1807/*
1808 * Finally, recalculate the summary information
1809 */
1810static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1811{
8728d506 1812 blk64_t blk;
dfcdc32f 1813 ext2_ino_t ino;
54434927
TT
1814 unsigned int group = 0;
1815 unsigned int count = 0;
2279fd78
TT
1816 blk64_t total_blocks_free = 0;
1817 int total_inodes_free = 0;
dfcdc32f 1818 int group_free = 0;
74128f8d 1819 int uninit = 0;
8728d506 1820 blk64_t super_blk, old_desc_blk, new_desc_blk;
74128f8d 1821 int old_desc_blocks;
052db4b7
TT
1822
1823 /*
1824 * First calculate the block statistics
1825 */
cd65a24e 1826 uninit = ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT);
8728d506
VAH
1827 ext2fs_super_and_bgd_loc2(fs, group, &super_blk, &old_desc_blk,
1828 &new_desc_blk, 0);
74128f8d
TT
1829 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
1830 old_desc_blocks = fs->super->s_first_meta_bg;
1831 else
1832 old_desc_blocks = fs->desc_blocks +
1833 fs->super->s_reserved_gdt_blocks;
1773c87c
TT
1834 for (blk = B2C(fs->super->s_first_data_block);
1835 blk < ext2fs_blocks_count(fs->super);
1836 blk += EXT2FS_CLUSTER_RATIO(fs)) {
74128f8d 1837 if ((uninit &&
1773c87c 1838 !(EQ_CLSTR(blk, super_blk) ||
74128f8d 1839 ((old_desc_blk && old_desc_blocks &&
1773c87c
TT
1840 GE_CLSTR(blk, old_desc_blk) &&
1841 LT_CLSTR(blk, old_desc_blk + old_desc_blocks))) ||
1842 ((new_desc_blk && EQ_CLSTR(blk, new_desc_blk))) ||
1843 EQ_CLSTR(blk, ext2fs_block_bitmap_loc(fs, group)) ||
1844 EQ_CLSTR(blk, ext2fs_inode_bitmap_loc(fs, group)) ||
1845 ((GE_CLSTR(blk, ext2fs_inode_table_loc(fs, group)) &&
1846 LT_CLSTR(blk, ext2fs_inode_table_loc(fs, group)
1847 + fs->inode_blocks_per_group))))) ||
3346084b 1848 (!ext2fs_fast_test_block_bitmap2(fs->block_map, blk))) {
052db4b7 1849 group_free++;
2279fd78 1850 total_blocks_free++;
052db4b7
TT
1851 }
1852 count++;
1773c87c
TT
1853 if ((count == fs->super->s_clusters_per_group) ||
1854 EQ_CLSTR(blk, ext2fs_blocks_count(fs->super)-1)) {
d7cca6b0 1855 ext2fs_bg_free_blocks_count_set(fs, group, group_free);
236efede
JS
1856 ext2fs_group_desc_csum_set(fs, group);
1857 group++;
4828bbe9
TT
1858 if (group >= fs->group_desc_count)
1859 break;
052db4b7
TT
1860 count = 0;
1861 group_free = 0;
8728d506
VAH
1862 uninit = ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT);
1863 ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
1864 &old_desc_blk,
1865 &new_desc_blk, 0);
74128f8d
TT
1866 if (fs->super->s_feature_incompat &
1867 EXT2_FEATURE_INCOMPAT_META_BG)
1868 old_desc_blocks = fs->super->s_first_meta_bg;
1869 else
1870 old_desc_blocks = fs->desc_blocks +
1871 fs->super->s_reserved_gdt_blocks;
052db4b7
TT
1872 }
1873 }
1773c87c 1874 total_blocks_free = C2B(total_blocks_free);
2279fd78 1875 ext2fs_free_blocks_count_set(fs->super, total_blocks_free);
efc6f628 1876
052db4b7
TT
1877 /*
1878 * Next, calculate the inode statistics
1879 */
1880 group_free = 0;
052db4b7
TT
1881 count = 0;
1882 group = 0;
5830d6be
ES
1883
1884 /* Protect loop from wrap-around if s_inodes_count maxed */
cd65a24e 1885 uninit = ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT);
5830d6be 1886 for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
74128f8d 1887 if (uninit ||
3346084b 1888 !ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
052db4b7 1889 group_free++;
2279fd78 1890 total_inodes_free++;
052db4b7
TT
1891 }
1892 count++;
1893 if ((count == fs->super->s_inodes_per_group) ||
1894 (ino == fs->super->s_inodes_count)) {
d7cca6b0 1895 ext2fs_bg_free_inodes_count_set(fs, group, group_free);
236efede
JS
1896 ext2fs_group_desc_csum_set(fs, group);
1897 group++;
4828bbe9
TT
1898 if (group >= fs->group_desc_count)
1899 break;
052db4b7
TT
1900 count = 0;
1901 group_free = 0;
cd65a24e 1902 uninit = ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT);
052db4b7
TT
1903 }
1904 }
2279fd78 1905 fs->super->s_free_inodes_count = total_inodes_free;
052db4b7
TT
1906 ext2fs_mark_super_dirty(fs);
1907 return 0;
1908}
199ddaaa 1909
8a6ede8b
ES
1910/*
1911 * Journal may have been relocated; update the backup journal blocks
1912 * in the superblock.
1913 */
1914static errcode_t fix_sb_journal_backup(ext2_filsys fs)
1915{
1916 errcode_t retval;
1917 struct ext2_inode inode;
1918
1919 if (!(fs->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
1920 return 0;
1921
d93d5bbf
ES
1922 /* External journal? Nothing to do. */
1923 if (fs->super->s_journal_dev && !fs->super->s_journal_inum)
1924 return 0;
1925
8a6ede8b
ES
1926 retval = ext2fs_read_inode(fs, fs->super->s_journal_inum, &inode);
1927 if (retval)
1928 return retval;
1929 memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
931b58e1 1930 fs->super->s_jnl_blocks[15] = inode.i_size_high;
8a6ede8b
ES
1931 fs->super->s_jnl_blocks[16] = inode.i_size;
1932 fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
1933 ext2fs_mark_super_dirty(fs);
1934 return 0;
1935}
1936
7f820344
TT
1937static int calc_group_overhead(ext2_filsys fs, blk64_t grp,
1938 int old_desc_blocks)
1939{
1940 blk64_t super_blk, old_desc_blk, new_desc_blk;
1941 int overhead;
1942
1943 /* inode table blocks plus allocation bitmaps */
1944 overhead = fs->inode_blocks_per_group + 2;
1945
1946 ext2fs_super_and_bgd_loc2(fs, grp, &super_blk,
1947 &old_desc_blk, &new_desc_blk, 0);
1948 if ((grp == 0) || super_blk)
1949 overhead++;
1950 if (old_desc_blk)
1951 overhead += old_desc_blocks;
1952 else if (new_desc_blk)
1953 overhead++;
1954 return overhead;
1955}
1956
1957
199ddaaa
JB
1958/*
1959 * calcluate the minimum number of blocks the given fs can be resized to
1960 */
8728d506 1961blk64_t calculate_minimum_resize_size(ext2_filsys fs)
199ddaaa 1962{
8728d506
VAH
1963 ext2_ino_t inode_count;
1964 blk64_t blks_needed, groups, data_blocks;
1965 blk64_t grp, data_needed, last_start;
1966 blk64_t overhead = 0;
7f820344 1967 int old_desc_blocks;
2884d208
PT
1968 int extra_groups = 0;
1969 int flexbg_size = 1 << fs->super->s_log_groups_per_flex;
199ddaaa
JB
1970
1971 /*
1972 * first figure out how many group descriptors we need to
1973 * handle the number of inodes we have
1974 */
1975 inode_count = fs->super->s_inodes_count -
1976 fs->super->s_free_inodes_count;
1977 blks_needed = ext2fs_div_ceil(inode_count,
1978 fs->super->s_inodes_per_group) *
1979 EXT2_BLOCKS_PER_GROUP(fs->super);
8728d506
VAH
1980 groups = ext2fs_div64_ceil(blks_needed,
1981 EXT2_BLOCKS_PER_GROUP(fs->super));
199ddaaa
JB
1982
1983 /*
7f820344 1984 * number of old-style block group descriptor blocks
199ddaaa 1985 */
7f820344
TT
1986 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
1987 old_desc_blocks = fs->super->s_first_meta_bg;
1988 else
1989 old_desc_blocks = fs->desc_blocks +
1990 fs->super->s_reserved_gdt_blocks;
199ddaaa
JB
1991
1992 /* calculate how many blocks are needed for data */
4efbac6f
VAH
1993 data_needed = ext2fs_blocks_count(fs->super) -
1994 ext2fs_free_blocks_count(fs->super);
199ddaaa 1995
7f820344
TT
1996 for (grp = 0; grp < fs->group_desc_count; grp++)
1997 data_needed -= calc_group_overhead(fs, grp, old_desc_blocks);
1998
1999 /*
2000 * For ext4 we need to allow for up to a flex_bg worth of
2001 * inode tables of slack space so the resize operation can be
2002 * guaranteed to finish.
2003 */
c09043f1 2004 if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) {
c09043f1 2005 extra_groups = flexbg_size - (groups & (flexbg_size - 1));
7f820344 2006 data_needed += fs->inode_blocks_per_group * extra_groups;
2884d208 2007 extra_groups = groups % flexbg_size;
c09043f1
TT
2008 }
2009
199ddaaa
JB
2010 /*
2011 * figure out how many data blocks we have given the number of groups
2012 * we need for our inodes
2013 */
2014 data_blocks = groups * EXT2_BLOCKS_PER_GROUP(fs->super);
2015 last_start = 0;
2016 for (grp = 0; grp < groups; grp++) {
7f820344 2017 overhead = calc_group_overhead(fs, grp, old_desc_blocks);
199ddaaa
JB
2018
2019 /*
2020 * we want to keep track of how much data we can store in
2021 * the groups leading up to the last group so we can determine
2022 * how big the last group needs to be
2023 */
2024 if (grp != (groups - 1))
2025 last_start += EXT2_BLOCKS_PER_GROUP(fs->super) -
2026 overhead;
2027
2028 data_blocks -= overhead;
2029 }
2030
2031 /*
2032 * if we need more group descriptors in order to accomodate our data
2033 * then we need to add them here
2034 */
2035 while (data_needed > data_blocks) {
8728d506
VAH
2036 blk64_t remainder = data_needed - data_blocks;
2037 blk64_t extra_grps;
199ddaaa
JB
2038
2039 /* figure out how many more groups we need for the data */
8728d506
VAH
2040 extra_grps = ext2fs_div64_ceil(remainder,
2041 EXT2_BLOCKS_PER_GROUP(fs->super));
199ddaaa
JB
2042
2043 data_blocks += extra_grps * EXT2_BLOCKS_PER_GROUP(fs->super);
2044
2045 /* ok we have to account for the last group */
7f820344 2046 overhead = calc_group_overhead(fs, groups-1, old_desc_blocks);
199ddaaa
JB
2047 last_start += EXT2_BLOCKS_PER_GROUP(fs->super) - overhead;
2048
2049 for (grp = groups; grp < groups+extra_grps; grp++) {
7f820344
TT
2050 overhead = calc_group_overhead(fs, grp,
2051 old_desc_blocks);
199ddaaa
JB
2052
2053 /*
2054 * again, we need to see how much data we cram into
2055 * all of the groups leading up to the last group
2056 */
2057 if (grp != (groups + extra_grps - 1))
2058 last_start += EXT2_BLOCKS_PER_GROUP(fs->super)
2059 - overhead;
2060
2061 data_blocks -= overhead;
2062 }
2063
2064 groups += extra_grps;
2884d208
PT
2065 extra_groups += extra_grps;
2066 if (fs->super->s_feature_incompat
2067 & EXT4_FEATURE_INCOMPAT_FLEX_BG
2068 && extra_groups > flexbg_size) {
2069 /*
2070 * For ext4 we need to allow for up to a flex_bg worth
2071 * of inode tables of slack space so the resize
2072 * operation can be guaranteed to finish.
2073 */
2074 extra_groups = flexbg_size -
2075 (groups & (flexbg_size - 1));
7f820344
TT
2076 data_needed += (fs->inode_blocks_per_group *
2077 extra_groups);
2884d208
PT
2078 extra_groups = groups % flexbg_size;
2079 }
199ddaaa
JB
2080 }
2081
2082 /* now for the fun voodoo */
7f820344 2083 overhead = calc_group_overhead(fs, groups-1, old_desc_blocks);
199ddaaa
JB
2084
2085 /*
2086 * if this is the case then the last group is going to have data in it
2087 * so we need to adjust the size of the last group accordingly
2088 */
2089 if (last_start < data_needed) {
8728d506 2090 blk64_t remainder = data_needed - last_start;
199ddaaa
JB
2091
2092 /*
2093 * 50 is a magic number that mkfs/resize uses to see if its
2094 * even worth making/resizing the fs. basically you need to
2095 * have at least 50 blocks in addition to the blocks needed
2096 * for the metadata in the last group
2097 */
2098 if (remainder > 50)
2099 overhead += remainder;
2100 else
2101 overhead += 50;
2102 } else
2103 overhead += 50;
2104
ba8bfa1a 2105 overhead += fs->super->s_first_data_block;
199ddaaa
JB
2106
2107 /*
2108 * since our last group doesn't have to be BLOCKS_PER_GROUP large, we
2109 * only do groups-1, and then add the number of blocks needed to
2110 * handle the group descriptor metadata+data that we need
2111 */
2112 blks_needed = (groups-1) * EXT2_BLOCKS_PER_GROUP(fs->super);
2113 blks_needed += overhead;
2114
69f7c80e
ES
2115 /*
2116 * If at this point we've already added up more "needed" than
2117 * the current size, just return current size as minimum.
2118 */
4efbac6f
VAH
2119 if (blks_needed >= ext2fs_blocks_count(fs->super))
2120 return ext2fs_blocks_count(fs->super);
793a04a0
TT
2121 /*
2122 * We need to reserve a few extra blocks if extents are
2123 * enabled, in case we need to grow the extent tree. The more
2124 * we shrink the file system, the more space we need.
2125 */
2126 if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)
4efbac6f
VAH
2127 blks_needed += (ext2fs_blocks_count(fs->super) -
2128 blks_needed)/500;
793a04a0 2129
199ddaaa
JB
2130 return blks_needed;
2131}