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