2 ext2_resize.c -- ext2 resizer
3 Copyright (C) 1998-2000, 2007, 2009-2011 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 static int ext2_add_group(struct ext2_fs *fs, blk_t groupsize)
36 fputs ("ext2_add_group\n", stderr);
38 if (!ped_realloc ((void*) &fs->gd,
39 (fs->numgroups+1) * sizeof(struct ext2_group_desc)
45 if (EXT2_SUPER_BLOCKS_COUNT(fs->sb) !=
46 EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
47 + fs->numgroups * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
49 fputs ("ext2_add_group: last (existing) group "
50 "isn't complete!\n", stderr);
56 group = fs->numgroups;
57 sparse = ext2_is_group_sparse(fs, group);
58 groupstart = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
59 + group * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
61 admin = fs->adminblocks;
63 admin -= fs->gdblocks + 1;
67 if (groupsize < fs->adminblocks ||
68 groupsize > EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
71 "ext2_add_group: groups of %i blocks are "
72 "impossible!\n", groupsize);
78 newgdblocks = ped_div_round_up((fs->numgroups + 1)
79 * sizeof(struct ext2_group_desc),
81 if (newgdblocks != fs->gdblocks)
85 for (i=0;i<fs->numgroups;i++)
86 if (ext2_is_group_sparse(fs, i))
90 start = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
91 + i * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
92 ext2_set_block_state(fs,
93 start + fs->gdblocks + 1, 1, 1);
104 fs->sb.s_inodes_count = PED_CPU_TO_LE32(
105 EXT2_SUPER_INODES_COUNT(fs->sb)
106 + EXT2_SUPER_INODES_PER_GROUP(fs->sb));
107 fs->sb.s_blocks_count = PED_CPU_TO_LE32(
108 EXT2_SUPER_BLOCKS_COUNT(fs->sb) + groupsize);
109 fs->sb.s_free_blocks_count = PED_CPU_TO_LE32(
110 EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) + groupsize - admin);
111 fs->sb.s_free_inodes_count = PED_CPU_TO_LE32(
112 EXT2_SUPER_FREE_INODES_COUNT(fs->sb)
113 + EXT2_SUPER_INODES_PER_GROUP(fs->sb));
114 fs->metadirty |= EXT2_META_SB;
121 sparseoff = off + fs->itoffset - 2;
125 fs->gd[group].bg_block_bitmap
126 = PED_CPU_TO_LE32(sparseoff);
127 fs->gd[group].bg_inode_bitmap
128 = PED_CPU_TO_LE32(sparseoff + 1);
132 fs->gd[group].bg_block_bitmap
133 = PED_CPU_TO_LE32(off);
134 fs->gd[group].bg_inode_bitmap
135 = PED_CPU_TO_LE32(off + 1);
138 /* Hey, I don't know _why_ either */
139 fs->gd[group].bg_inode_table = PED_CPU_TO_LE32(sparseoff + 2);
142 fs->gd[group].bg_free_blocks_count = PED_CPU_TO_LE16(groupsize - admin);
143 fs->gd[group].bg_free_inodes_count = PED_CPU_TO_LE16(
144 EXT2_SUPER_INODES_PER_GROUP(fs->sb));
145 fs->gd[group].bg_used_dirs_count = 0;
146 fs->metadirty |= EXT2_META_SB | EXT2_META_GD;
149 struct ext2_buffer_head *bh;
152 bh = ext2_bcreate(fs, EXT2_GROUP_BLOCK_BITMAP(fs->gd[group]));
158 bh->data[0] |= _bitmap[0];
159 for (i=1;i<=fs->gdblocks;i++)
160 bh->data[i>>3] |= _bitmap[i&7];
163 i = EXT2_GROUP_BLOCK_BITMAP(fs->gd[group]) - groupstart;
164 bh->data[i>>3] |= _bitmap[i&7];
166 i = EXT2_GROUP_INODE_BITMAP(fs->gd[group]) - groupstart;
167 bh->data[i>>3] |= _bitmap[i&7];
169 for (i=0;i<fs->inodeblocks;i++)
173 j = EXT2_GROUP_INODE_TABLE(fs->gd[group])
175 bh->data[j>>3] |= _bitmap[j&7];
178 for (i=groupsize;i<EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);i++)
179 bh->data[i>>3] |= _bitmap[i&7];
181 ext2_brelse(bh, 0); /* this is a block bitmap */
184 if (!ext2_zero_blocks(fs, EXT2_GROUP_INODE_BITMAP(fs->gd[group]), 1))
186 if (!ext2_zero_blocks(fs, EXT2_GROUP_INODE_TABLE(fs->gd[group]),
197 static int ext2_del_group(struct ext2_fs *fs)
206 fputs ("ext2_del_group\n", stderr);
208 group = fs->numgroups - 1;
209 sparse = ext2_is_group_sparse(fs, group);
211 admin = fs->adminblocks;
213 admin -= fs->gdblocks + 1;
215 groupsize = EXT2_SUPER_BLOCKS_COUNT(fs->sb)
216 - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
217 - group * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
219 if (EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) < groupsize - admin)
221 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
222 _("File system is too full to remove a group!"));
227 if (EXT2_SUPER_FREE_INODES_COUNT(fs->sb)
228 < EXT2_SUPER_INODES_PER_GROUP(fs->sb))
230 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
231 _("File system has too many allocated inodes to "
238 if (EXT2_GROUP_FREE_INODES_COUNT(fs->gd[group]) !=
239 EXT2_SUPER_INODES_PER_GROUP(fs->sb))
241 fputs ("ext2_del_group: this should not "
242 "happen anymore!\n", stderr);
248 newgdblocks = ped_div_round_up((fs->numgroups - 1) *
249 sizeof(struct ext2_group_desc), fs->blocksize);
251 if (newgdblocks != fs->gdblocks)
255 for (i=0;i<fs->numgroups;i++)
256 if (ext2_is_group_sparse(fs, i))
260 start = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb) +
261 i * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
262 ext2_set_block_state(fs,
263 start + fs->gdblocks,
275 if (EXT2_GROUP_FREE_BLOCKS_COUNT(fs->gd[group])
276 != groupsize - admin)
282 offset = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb) +
283 group * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
284 num = EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
287 if (ext2_is_data_block(fs, offset+i) &&
288 ext2_get_block_state(fs, offset+i))
291 "error: block relocator "
292 "should have relocated "
303 fs->sb.s_inodes_count = PED_CPU_TO_LE32(
304 EXT2_SUPER_INODES_COUNT(fs->sb)
305 - EXT2_SUPER_INODES_PER_GROUP(fs->sb));
306 fs->sb.s_blocks_count = PED_CPU_TO_LE32(
307 EXT2_SUPER_BLOCKS_COUNT(fs->sb) - groupsize);
308 fs->sb.s_free_blocks_count = PED_CPU_TO_LE32(
309 EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) - (groupsize - admin));
310 fs->sb.s_free_inodes_count = PED_CPU_TO_LE32(
311 EXT2_SUPER_FREE_INODES_COUNT(fs->sb)
312 - EXT2_SUPER_INODES_PER_GROUP(fs->sb));
313 fs->metadirty |= EXT2_META_SB;
318 ped_realloc ((void*) &fs->gd,
319 fs->numgroups * sizeof(struct ext2_group_desc)
325 static int ext2_grow_group(struct ext2_fs *fs, blk_t newsize)
333 fputs ("ext2_grow_group\n", stderr);
335 group = fs->numgroups - 1;
336 groupoff = group * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb)
337 + EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);
338 gblocks = EXT2_SUPER_BLOCKS_COUNT(fs->sb) - groupoff;
342 if (newsize < gblocks)
344 fputs ("ext2_grow_group: called to shrink group!\n",
350 if (gblocks == newsize)
352 fputs ("ext2_grow_group: nothing to do!\n", stderr);
357 for (i=gblocks;i<newsize;i++)
358 ext2_set_block_state(fs, groupoff + i, 0, 1);
360 fs->sb.s_blocks_count = PED_CPU_TO_LE32(
361 EXT2_SUPER_BLOCKS_COUNT(fs->sb) + newsize - gblocks);
362 fs->metadirty |= EXT2_META_SB;
370 static int ext2_shrink_group(struct ext2_fs *fs, blk_t newsize)
379 fputs ("ext2_shrink_group\n", stderr);
381 group = fs->numgroups - 1;
383 admin = fs->adminblocks;
384 if (!ext2_is_group_sparse(fs, group))
385 admin -= fs->gdblocks + 1;
387 groupoff = group * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb)
388 + EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);
389 gblocks = EXT2_SUPER_BLOCKS_COUNT(fs->sb) - groupoff;
396 "ext2_shrink_group: cant shrink a group "
397 "to %i blocks\n", newsize);
402 if (newsize > gblocks)
404 fputs ("ext2_shrink_group: called to grow group!\n",
410 if (gblocks == newsize)
412 fputs ("ext2_shrink_group: nothing to do!\n",
419 for (i=newsize;i<gblocks;i++)
421 if (fs->opt_debug && ext2_get_block_state(fs, groupoff + i))
424 "error: block relocator should have relocated "
431 ext2_set_block_state(fs, groupoff + i, 1, 0);
434 i = gblocks - newsize;
435 fs->sb.s_blocks_count = PED_CPU_TO_LE32(
436 EXT2_SUPER_BLOCKS_COUNT(fs->sb) - i);
437 fs->sb.s_free_blocks_count = PED_CPU_TO_LE32(
438 EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) - i);
439 fs->gd[group].bg_free_blocks_count = PED_CPU_TO_LE16(
440 EXT2_GROUP_FREE_BLOCKS_COUNT(fs->gd[group]) - i);
442 fs->metadirty |= EXT2_META_SB | EXT2_META_GD;
455 static int ext2_grow_fs(struct ext2_fs *fs, blk_t newsize, PedTimer* timer)
459 blk_t origsize = EXT2_SUPER_BLOCKS_COUNT(fs->sb);
462 fputs ("ext2_grow_fs\n", stderr);
464 if (!ext2_block_relocate(fs, newsize))
467 if (!ext2_metadata_push(fs, newsize))
470 diff = newsize - EXT2_SUPER_BLOCKS_COUNT(fs->sb);
471 sizelast = EXT2_SUPER_BLOCKS_COUNT(fs->sb)
472 - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
473 - (fs->numgroups-1) * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
475 if (sizelast != EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
479 growto = sizelast + diff;
480 if (growto > EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
481 growto = EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
483 if (!ext2_grow_group(fs, growto))
486 diff -= growto - sizelast;
489 ped_timer_reset (timer);
490 ped_timer_set_state_name (timer, _("adding groups"));
494 ped_timer_update (timer,
495 1.0 - 1.0 * diff / (newsize - origsize));
497 sizelast = PED_MIN(diff, EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb));
498 if (!ext2_add_group(fs, sizelast))
504 ped_timer_update (timer, 1.0);
509 static int ext2_shrink_fs(struct ext2_fs *fs, blk_t newsize,
512 blk_t origsize = EXT2_SUPER_BLOCKS_COUNT (fs->sb);
518 fputs ("ext2_shrink_fs\n", stderr);
520 newgroups = ped_div_round_up (newsize
521 - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb),
522 EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb));
523 if (EXT2_SUPER_BLOCKS_COUNT(fs->sb)
524 - EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) > newsize)
526 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
527 _("Your file system is too full to resize it to %i "
528 "blocks. Sorry."), newsize);
532 if (EXT2_SUPER_INODES_COUNT(fs->sb)
533 - EXT2_SUPER_FREE_INODES_COUNT(fs->sb)
534 > newgroups * EXT2_SUPER_INODES_PER_GROUP(fs->sb))
536 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
537 _("Your file system has too many occupied inodes to "
538 "resize it to %i blocks. Sorry."), newsize);
542 if (!ext2_inode_relocate(fs, newgroups))
545 if (!ext2_block_relocate(fs, newsize))
548 diff = EXT2_SUPER_BLOCKS_COUNT(fs->sb) - newsize;
550 ped_timer_reset (timer);
551 ped_timer_set_state_name (timer, _("shrinking"));
555 ped_timer_update (timer,
556 1.0 - 1.0 * diff / (origsize - newsize));
558 sizelast = EXT2_SUPER_BLOCKS_COUNT(fs->sb)
559 - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb) -
561 * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
565 if (!ext2_shrink_group(fs, sizelast - diff))
572 if (!ext2_del_group(fs))
579 ped_timer_update (timer, 1.0);
584 int ext2_determine_itoffset(struct ext2_fs *fs)
588 fs->itoffset = EXT2_GROUP_INODE_TABLE(fs->gd[0])
589 - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);
591 /*PED_DEBUG (0x20, "itoffset is %d", fs->itoffset);
593 PED_DEBUG (0x20, "walking %d groups", fs->numgroups);*/
595 for (i=0;i<fs->numgroups;i++)
602 start = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
603 + (i * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb));
604 it = start + fs->itoffset;
606 /*PED_DEBUG (0x21, "start = %d, it = %d", start, it);*/
608 if (ext2_is_group_sparse(fs, i))
610 /*PED_DEBUG (0x21, "%d has a superblock copy", i);*/
616 /*PED_DEBUG (0x21, "%d doesn't have a superblock copy",
622 if (EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]) != bb ||
623 EXT2_GROUP_INODE_BITMAP(fs->gd[i]) != ib ||
624 EXT2_GROUP_INODE_TABLE(fs->gd[i]) != it)
626 /* ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
627 PED_EXCEPTION_CANCEL,
628 _("This ext2 file system has a rather strange layout! "
629 "Parted can't resize this (yet)."));*/
631 /* PED_DEBUG (0x21, "calculated block bitmap to be %d, "
632 "but fs says %d.", bb,
633 EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]));
634 PED_DEBUG (0x21, "calculated inode bitmap to be %d, "
635 "but fs says %d.", ib,
636 EXT2_GROUP_INODE_BITMAP(fs->gd[i]));
637 PED_DEBUG (0x21, "calculated inode table to be %d, "
638 "but fs says %d.", it,
639 EXT2_GROUP_INODE_TABLE(fs->gd[i]));*/
648 int ext2_resize_fs(struct ext2_fs *fs, blk_t newsize, PedTimer* timer)
653 if (EXT2_SUPER_STATE(fs->sb) & EXT2_ERROR_FS)
655 ped_exception_throw (
656 PED_EXCEPTION_WARNING, PED_EXCEPTION_CANCEL,
657 _("File system has errors! You should run e2fsck."));
661 if (!(EXT2_SUPER_STATE(fs->sb) & EXT2_VALID_FS))
663 ped_exception_throw (
664 PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
665 _("File system was not cleanly unmounted! "
666 "You should run e2fsck."));
670 if (EXT2_SUPER_FEATURE_COMPAT(fs->sb)
671 & EXT2_FEATURE_COMPAT_HAS_DIR_INDEX) {
672 if (ped_exception_throw (
673 PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE_CANCEL,
674 _("The file system has the 'dir_index' feature "
675 "enabled. Parted can only resize the file system "
676 "if it disables this feature. You can enable it "
677 "later by running 'tune2fs -O dir_index DEVICE' "
678 "and then 'e2fsck -fD DEVICE'."))
679 != PED_EXCEPTION_IGNORE)
681 fs->sb.s_feature_compat
682 = PED_CPU_TO_LE32(EXT2_SUPER_FEATURE_COMPAT(fs->sb)
683 & ~EXT2_FEATURE_COMPAT_HAS_DIR_INDEX);
684 fs->metadirty |= EXT2_META_SB;
687 if (!ext2_determine_itoffset(fs) && ped_exception_throw (
688 PED_EXCEPTION_WARNING,
689 PED_EXCEPTION_OK_CANCEL,
690 _("A resize operation on this file system will "
691 "use EXPERIMENTAL code\n"
692 "that MAY CORRUPT it (although no one has "
693 "reported any such damage yet).\n"
694 "You should at least backup your data first, "
695 "and run 'e2fsck -f' afterwards."))
696 == PED_EXCEPTION_CANCEL)
702 fputs ("ext2_resize_fs\n", stderr);
704 residue = (newsize - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb))
705 % EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
706 if (residue && residue <= fs->adminblocks)
709 if (newsize == EXT2_SUPER_BLOCKS_COUNT(fs->sb))
713 = (unsigned char *)ped_malloc(ext2_relocator_pool_size << 10);
714 if (!fs->relocator_pool)
716 fs->relocator_pool_end
717 = fs->relocator_pool + (ext2_relocator_pool_size << 10);
719 if (newsize < EXT2_SUPER_BLOCKS_COUNT(fs->sb))
720 status = ext2_shrink_fs(fs, newsize, timer);
722 status = ext2_grow_fs(fs, newsize, timer);
724 free(fs->relocator_pool);
725 fs->relocator_pool = NULL;
726 fs->relocator_pool_end = NULL;
730 #endif /* !DISCOVER_ONLY */