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