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