2 * resize2fs.c --- ext2 main routine
4 * Copyright (C) 1997 Theodore Ts'o
12 * Resizing a filesystem consists of the following phases:
14 * 1. Adjust superblock and (*) write out new parts of the inode
16 * 2. Determine blocks which need to be relocated.
17 * 3. (*) Relocate blocks which must be moved, adjusting entries
18 * in the filesystem in the process.
19 * 4. (*) Move inodes which must be moved (only when shrinking a
21 * 5. (*) Move the inode tables, if necessary.
23 #include "resize2fs.h"
26 * This routine adjusts the superblock and other data structures...
28 static errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size)
35 blk_t blk, group_block;
37 struct ext2_group_desc *new;
38 int old_numblocks, numblocks, adjblocks;
39 ext2_sim_progmeter progress = 0;
42 fs->super->s_blocks_count = new_size;
43 ext2fs_mark_super_dirty(fs);
44 ext2fs_mark_bb_dirty(fs);
45 ext2fs_mark_ib_dirty(fs);
48 fs->group_desc_count = (fs->super->s_blocks_count -
49 fs->super->s_first_data_block +
50 EXT2_BLOCKS_PER_GROUP(fs->super) - 1)
51 / EXT2_BLOCKS_PER_GROUP(fs->super);
52 if (fs->group_desc_count == 0)
53 return EXT2_ET_TOOSMALL;
54 fs->desc_blocks = (fs->group_desc_count +
55 EXT2_DESC_PER_BLOCK(fs->super) - 1)
56 / EXT2_DESC_PER_BLOCK(fs->super);
59 * Overhead is the number of bookkeeping blocks per group. It
60 * includes the superblock backup, the group descriptor
61 * backups, the inode bitmap, the block bitmap, and the inode
64 * XXX Not all block groups need the descriptor blocks, but
65 * being clever is tricky...
67 overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
70 * See if the last group is big enough to support the
71 * necessary data structures. If not, we need to get rid of
74 rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) %
75 fs->super->s_blocks_per_group;
76 if ((fs->group_desc_count == 1) && rem && (rem < overhead))
77 return EXT2_ET_TOOSMALL;
78 if (rem && (rem < overhead+50)) {
79 fs->super->s_blocks_count -= rem;
83 * Adjust the number of inodes
85 fs->super->s_inodes_count = fs->super->s_inodes_per_group *
89 * Adjust the number of free blocks
91 blk = rfs->old_fs->super->s_blocks_count;
92 if (blk > fs->super->s_blocks_count)
93 fs->super->s_free_blocks_count -=
94 (blk - fs->super->s_blocks_count);
96 fs->super->s_free_blocks_count +=
97 (fs->super->s_blocks_count - blk);
100 * Adjust the number of reserved blocks
102 blk = rfs->old_fs->super->s_r_blocks_count * 100 /
103 rfs->old_fs->super->s_blocks_count;
104 fs->super->s_r_blocks_count = ((fs->super->s_blocks_count * blk)
108 * Adjust the bitmaps for size
110 retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
111 fs->super->s_inodes_count,
113 if (retval) goto errout;
115 real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
116 * fs->group_desc_count)) - 1 +
117 fs->super->s_first_data_block;
118 retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
119 real_end, fs->block_map);
121 if (retval) goto errout;
124 * Reallocate the group descriptors as necessary.
126 if (rfs->old_fs->desc_blocks != fs->desc_blocks) {
127 new = realloc(fs->group_desc,
128 fs->desc_blocks * fs->blocksize);
131 fs->group_desc = new;
135 * Fix the count of the last (old) block group
137 if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
141 old_numblocks = (rfs->old_fs->super->s_blocks_count -
142 rfs->old_fs->super->s_first_data_block) %
143 rfs->old_fs->super->s_blocks_per_group;
145 old_numblocks = rfs->old_fs->super->s_blocks_per_group;
146 if (rfs->old_fs->group_desc_count == fs->group_desc_count) {
147 numblocks = (rfs->new_fs->super->s_blocks_count -
148 rfs->new_fs->super->s_first_data_block) %
149 rfs->new_fs->super->s_blocks_per_group;
151 numblocks = rfs->new_fs->super->s_blocks_per_group;
153 numblocks = rfs->new_fs->super->s_blocks_per_group;
154 i = rfs->old_fs->group_desc_count - 1;
155 fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
158 * Initialize the new block group descriptors
160 if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
164 rfs->itable_buf = malloc(fs->blocksize * fs->inode_blocks_per_group);
165 if (!rfs->itable_buf) {
169 memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
170 group_block = fs->super->s_first_data_block +
171 rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
173 if (rfs->flags & RESIZE_PERCENT_COMPLETE) {
174 adj = rfs->old_fs->group_desc_count;
175 retval = ext2fs_progress_init(&progress,
176 "Initializing inode table", 30, 40,
177 fs->group_desc_count - adj, 0);
178 if (retval) goto errout;
180 for (i = rfs->old_fs->group_desc_count;
181 i < fs->group_desc_count; i++) {
182 memset(&fs->group_desc[i], 0,
183 sizeof(struct ext2_group_desc));
186 if (i == fs->group_desc_count-1) {
187 numblocks = (fs->super->s_blocks_count -
188 fs->super->s_first_data_block) %
189 fs->super->s_blocks_per_group;
191 numblocks = fs->super->s_blocks_per_group;
193 numblocks = fs->super->s_blocks_per_group;
195 if (ext2fs_bg_has_super(fs, i)) {
196 for (j=0; j < fs->desc_blocks+1; j++)
197 ext2fs_mark_block_bitmap(fs->block_map,
199 adjblocks = 1 + fs->desc_blocks;
201 adjblocks += 2 + fs->inode_blocks_per_group;
203 numblocks -= adjblocks;
204 fs->super->s_free_blocks_count -= adjblocks;
205 fs->super->s_free_inodes_count +=
206 fs->super->s_inodes_per_group;
207 fs->group_desc[i].bg_free_blocks_count = numblocks;
208 fs->group_desc[i].bg_free_inodes_count =
209 fs->super->s_inodes_per_group;
210 fs->group_desc[i].bg_used_dirs_count = 0;
212 retval = ext2fs_allocate_group_table(fs, i, 0);
213 if (retval) goto errout;
216 * Write out the new inode table
218 retval = io_channel_write_blk(fs->io,
219 fs->group_desc[i].bg_inode_table,
220 fs->inode_blocks_per_group,
222 if (retval) goto errout;
224 /* io_channel_flush(fs->io); */
226 ext2fs_progress_update(progress, i - adj + 1);
228 group_block += fs->super->s_blocks_per_group;
230 io_channel_flush(fs->io);
235 ext2fs_progress_close(progress);
240 * This helper function creates a block bitmap with all of the
241 * filesystem meta-data blocks.
243 static errcode_t mark_table_blocks(ext2_filsys fs,
244 ext2fs_block_bitmap *ret_bmap)
248 ext2fs_block_bitmap bmap;
251 retval = ext2fs_allocate_block_bitmap(fs, "meta-data blocks", &bmap);
255 block = fs->super->s_first_data_block;
256 for (i = 0; i < fs->group_desc_count; i++) {
257 if (ext2fs_bg_has_super(fs, i)) {
259 * Mark this group's copy of the superblock
261 ext2fs_mark_block_bitmap(bmap, block);
264 * Mark this group's copy of the descriptors
266 for (j = 0; j < fs->desc_blocks; j++)
267 ext2fs_mark_block_bitmap(bmap, block + j + 1);
271 * Mark the blocks used for the inode table
273 for (j = 0, b = fs->group_desc[i].bg_inode_table;
274 j < fs->inode_blocks_per_group;
276 ext2fs_mark_block_bitmap(bmap, b);
279 * Mark block used for the block bitmap
281 ext2fs_mark_block_bitmap(bmap,
282 fs->group_desc[i].bg_block_bitmap);
284 * Mark block used for the inode bitmap
286 ext2fs_mark_block_bitmap(bmap,
287 fs->group_desc[i].bg_inode_bitmap);
288 block += fs->super->s_blocks_per_group;
297 * Some helper CPP macros
299 #define FS_BLOCK_BM(fs, i) ((fs)->group_desc[(i)].bg_block_bitmap)
300 #define FS_INODE_BM(fs, i) ((fs)->group_desc[(i)].bg_inode_bitmap)
301 #define FS_INODE_TB(fs, i) ((fs)->group_desc[(i)].bg_inode_table)
303 #define IS_BLOCK_BM(fs, i, blk) ((blk) == FS_BLOCK_BM((fs),(i)))
304 #define IS_INODE_BM(fs, i, blk) ((blk) == FS_INODE_BM((fs),(i)))
306 #define IS_INODE_TB(fs, i, blk) (((blk) >= FS_INODE_TB((fs), (i))) && \
307 ((blk) < (FS_INODE_TB((fs), (i)) + \
308 (fs)->inode_blocks_per_group)))
311 * This routine marks and unmarks reserved blocks in the new block
312 * bitmap. It also determines which blocks need to be moved and
313 * places this information into the move_blocks bitmap.
315 static errcode_t blocks_to_move(ext2_resize_t rfs)
318 blk_t blk, group_blk;
319 unsigned long old_blocks, new_blocks;
321 ext2_filsys fs, old_fs;
322 ext2fs_block_bitmap meta_bmap;
325 old_fs = rfs->old_fs;
326 if (old_fs->super->s_blocks_count > fs->super->s_blocks_count)
329 retval = ext2fs_allocate_block_bitmap(fs, "reserved blocks",
330 &rfs->reserve_blocks);
334 retval = ext2fs_allocate_block_bitmap(fs, "blocks to be moved",
339 retval = mark_table_blocks(fs, &meta_bmap);
346 * If we're shrinking the filesystem, we need to move all of
347 * the blocks that don't fit any more
349 for (blk = fs->super->s_blocks_count;
350 blk < old_fs->super->s_blocks_count; blk++) {
351 if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
352 !ext2fs_test_block_bitmap(meta_bmap, blk)) {
353 ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
354 rfs->needed_blocks++;
356 ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
359 old_blocks = old_fs->desc_blocks;
360 new_blocks = fs->desc_blocks;
362 if (old_blocks == new_blocks) {
367 max = fs->group_desc_count;
368 if (max > old_fs->group_desc_count)
369 max = old_fs->group_desc_count;
370 group_blk = old_fs->super->s_first_data_block;
372 * If we're reducing the number of descriptor blocks, this
373 * makes life easy. :-) We just have to mark some extra
376 if (old_blocks > new_blocks) {
377 for (i = 0; i < max; i++) {
378 if (!ext2fs_bg_has_super(fs, i)) {
379 group_blk += fs->super->s_blocks_per_group;
382 for (blk = group_blk+1+new_blocks;
383 blk < group_blk+1+old_blocks; blk++) {
384 ext2fs_unmark_block_bitmap(fs->block_map,
386 rfs->needed_blocks--;
388 group_blk += fs->super->s_blocks_per_group;
394 * If we're increasing the number of descriptor blocks, life
395 * gets interesting....
397 for (i = 0; i < max; i++) {
398 if (!ext2fs_bg_has_super(fs, i))
401 for (blk = group_blk;
402 blk < group_blk + 1 + new_blocks; blk++) {
403 ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
404 ext2fs_mark_block_bitmap(fs->block_map, blk);
407 * Check to see if we overlap with the inode
408 * or block bitmap, or the inode tables. If
409 * not, and the block is in use, then mark it
410 * as a block to be moved.
412 if (IS_BLOCK_BM(fs, i, blk)) {
413 FS_BLOCK_BM(fs, i) = 0;
414 rfs->needed_blocks++;
415 } else if (IS_INODE_BM(fs, i, blk)) {
416 FS_INODE_BM(fs, i) = 0;
417 rfs->needed_blocks++;
418 } else if (IS_INODE_TB(fs, i, blk)) {
419 FS_INODE_TB(fs, i) = 0;
420 rfs->needed_blocks++;
421 } else if (ext2fs_test_block_bitmap(old_fs->block_map,
423 !ext2fs_test_block_bitmap(meta_bmap, blk)) {
424 ext2fs_mark_block_bitmap(rfs->move_blocks,
426 rfs->needed_blocks++;
429 if (fs->group_desc[i].bg_inode_table &&
430 fs->group_desc[i].bg_inode_bitmap &&
431 fs->group_desc[i].bg_block_bitmap)
435 * Reserve the existing meta blocks that we know
436 * aren't to be moved.
438 if (fs->group_desc[i].bg_block_bitmap)
439 ext2fs_mark_block_bitmap(rfs->reserve_blocks,
440 fs->group_desc[i].bg_block_bitmap);
441 if (fs->group_desc[i].bg_inode_bitmap)
442 ext2fs_mark_block_bitmap(rfs->reserve_blocks,
443 fs->group_desc[i].bg_inode_bitmap);
444 if (fs->group_desc[i].bg_inode_table)
445 for (blk = fs->group_desc[i].bg_inode_table, j=0;
446 j < fs->inode_blocks_per_group ; j++, blk++)
447 ext2fs_mark_block_bitmap(rfs->reserve_blocks,
451 * Allocate the missing data structures
453 retval = ext2fs_allocate_group_table(fs, i,
454 rfs->reserve_blocks);
459 * For those structures that have changed, we need to
462 if (FS_BLOCK_BM(old_fs, i) !=
463 (blk = FS_BLOCK_BM(fs, i))) {
464 ext2fs_mark_block_bitmap(fs->block_map, blk);
465 if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
466 !ext2fs_test_block_bitmap(meta_bmap, blk))
467 ext2fs_mark_block_bitmap(rfs->move_blocks,
470 if (FS_INODE_BM(old_fs, i) !=
471 (blk = FS_INODE_BM(fs, i))) {
472 ext2fs_mark_block_bitmap(fs->block_map, blk);
473 if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
474 !ext2fs_test_block_bitmap(meta_bmap, blk))
475 ext2fs_mark_block_bitmap(rfs->move_blocks,
480 * The inode table, if we need to relocate it, is
481 * handled specially. We have to reserve the blocks
482 * for both the old and the new inode table, since we
483 * can't have the inode table be destroyed during the
484 * block relocation phase.
486 if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
487 goto next_group; /* inode table not moved */
489 rfs->needed_blocks += fs->inode_blocks_per_group;
492 * Mark the new inode table as in use in the new block
493 * allocation bitmap, and move any blocks that might
496 for (blk = fs->group_desc[i].bg_inode_table, j=0;
497 j < fs->inode_blocks_per_group ; j++, blk++) {
498 ext2fs_mark_block_bitmap(fs->block_map, blk);
499 if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
500 !ext2fs_test_block_bitmap(meta_bmap, blk))
501 ext2fs_mark_block_bitmap(rfs->move_blocks,
506 * Make sure the old inode table is reserved in the
507 * block reservation bitmap.
509 for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
510 j < fs->inode_blocks_per_group ; j++, blk++)
511 ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
514 group_blk += rfs->new_fs->super->s_blocks_per_group;
520 ext2fs_free_block_bitmap(meta_bmap);
527 * A very scary routine --- this one moves the inode table around!!!
529 * After this you have to use the rfs->new_fs file handle to read and
532 static errcode_t move_itables(ext2_resize_t rfs)
534 int i, n, num, max, size, diff;
535 ext2_filsys fs = rfs->new_fs;
538 errcode_t retval, err;
539 ext2_sim_progmeter progress = 0;
542 max = fs->group_desc_count;
543 if (max > rfs->old_fs->group_desc_count)
544 max = rfs->old_fs->group_desc_count;
546 size = fs->blocksize * fs->inode_blocks_per_group;
547 if (!rfs->itable_buf) {
548 rfs->itable_buf = malloc(size);
549 if (!rfs->itable_buf)
554 * Figure out how many inode tables we need to move
557 for (i=0; i < max; i++)
558 if (rfs->old_fs->group_desc[i].bg_inode_table !=
559 fs->group_desc[i].bg_inode_table)
565 if (rfs->flags & RESIZE_PERCENT_COMPLETE) {
566 retval = ext2fs_progress_init(&progress,
567 "Moving inode table", 30, 40, to_move, 0);
572 for (i=0; i < max; i++) {
573 old = rfs->old_fs->group_desc[i].bg_inode_table;
574 new = fs->group_desc[i].bg_inode_table;
577 #ifdef RESIZE2FS_DEBUG
578 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
579 printf("Itable move group %d block "
580 "%u->%u (diff %d)\n",
587 retval = io_channel_read_blk(fs->io, old,
588 fs->inode_blocks_per_group,
593 * The end of the inode table segment often contains
594 * all zeros. Find out if we have several blocks of
595 * zeros so we can optimize the write.
597 for (cp = rfs->itable_buf+size, n=0; n < size; n++, cp--)
600 n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
601 #ifdef RESIZE2FS_DEBUG
602 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
603 printf("%d blocks of zeros...\n", n);
605 num = fs->inode_blocks_per_group;
609 retval = io_channel_write_blk(fs->io, new,
610 num, rfs->itable_buf);
612 io_channel_write_blk(fs->io, old,
613 num, rfs->itable_buf);
617 retval = io_channel_write_blk(fs->io,
618 old + fs->inode_blocks_per_group,
619 diff, rfs->itable_buf - fs->blocksize * diff);
623 io_channel_flush(fs->io);
625 ext2fs_progress_update(progress, ++moved);
627 ext2fs_flush(rfs->new_fs);
628 io_channel_flush(fs->io);
629 #ifdef RESIZE2FS_DEBUG
630 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
631 printf("Inode table move finished.\n");
634 ext2fs_progress_close(progress);
639 ext2fs_progress_close(progress);
640 #ifdef RESIZE2FS_DEBUG
641 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
642 printf("Error: %s; now backing out!\n", error_message(retval));
645 #ifdef RESIZE2FS_DEBUG
646 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
647 printf("Group %d block %u->%u\n", i, new, old);
649 old = rfs->old_fs->group_desc[i].bg_inode_table;
650 new = fs->group_desc[i].bg_inode_table;
652 err = io_channel_read_blk(fs->io, new,
653 fs->inode_blocks_per_group,
657 err = io_channel_write_blk(fs->io, old,
658 fs->inode_blocks_per_group,
665 * Finally, recalculate the summary information
667 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
677 * First calculate the block statistics
679 for (blk = fs->super->s_first_data_block;
680 blk < fs->super->s_blocks_count; blk++) {
681 if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
686 if ((count == fs->super->s_blocks_per_group) ||
687 (blk == fs->super->s_blocks_count-1)) {
688 fs->group_desc[group++].bg_free_blocks_count =
694 fs->super->s_free_blocks_count = total_free;
697 * Next, calculate the inode statistics
703 for (ino = 1; ino <= fs->super->s_inodes_count; ino++) {
704 if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
709 if ((count == fs->super->s_inodes_per_group) ||
710 (ino == fs->super->s_inodes_count)) {
711 fs->group_desc[group++].bg_free_inodes_count =
717 fs->super->s_free_inodes_count = total_free;
718 ext2fs_mark_super_dirty(fs);
725 * This is the top-level routine which does the dirty deed....
727 errcode_t resize_fs(ext2_filsys fs, blk_t new_size, int flags)
732 retval = ext2fs_read_bitmaps(fs);
737 * Create the data structure
739 rfs = malloc(sizeof(struct ext2_resize_struct));
742 memset(rfs, 0, sizeof(struct ext2_resize_struct));
747 retval = ext2fs_dup_handle(fs, &rfs->new_fs);
751 retval = adjust_superblock(rfs, new_size);
755 retval = blocks_to_move(rfs);
759 #ifdef RESIZE2FS_DEBUG
760 if (rfs->flags & RESIZE_DEBUG_BMOVE)
761 printf("Number of free blocks: %d/%d, Needed: %d\n",
762 rfs->old_fs->super->s_free_blocks_count,
763 rfs->new_fs->super->s_free_blocks_count,
767 retval = ext2fs_block_move(rfs);
771 retval = ext2fs_inode_move(rfs);
775 retval = move_itables(rfs);
779 retval = ext2fs_calculate_summary_stats(rfs->new_fs);
783 retval = ext2fs_close(rfs->new_fs);
789 ext2fs_free(rfs->old_fs);
791 free(rfs->itable_buf);
798 ext2fs_free(rfs->new_fs);
800 free(rfs->itable_buf);