summaryrefslogtreecommitdiff
path: root/resize
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2004-12-24 01:34:29 -0500
committerTheodore Ts'o <tytso@mit.edu>2004-12-24 01:34:29 -0500
commit9213a93b22accd2a27064b12f6bc5f1221ca6a70 (patch)
treeb8be7e8180de8e10d5d86a008e5e90ab6377f112 /resize
parent71669d0541f0d3db64792c60a28abddba78382e2 (diff)
downloade2fsprogs-9213a93b22accd2a27064b12f6bc5f1221ca6a70.tar.gz
Fix resize2fs so that it properly handles filesystems with the resize_inode
feature enabled.
Diffstat (limited to 'resize')
-rw-r--r--resize/ChangeLog7
-rw-r--r--resize/resize2fs.c102
2 files changed, 99 insertions, 10 deletions
diff --git a/resize/ChangeLog b/resize/ChangeLog
index 10aacd21..838abaf2 100644
--- a/resize/ChangeLog
+++ b/resize/ChangeLog
@@ -1,3 +1,10 @@
+2004-12-16 Theodore Ts'o <tytso@mit.edu>
+
+ * resize2fs.c (resize_fs): Call ext2fs_create_resize_inode to
+ fill in the necessary fields in the resize inode.
+ (adjust_superblock): Reserve blocks that are needed for
+ on-line resizing if that feature is enabled.
+
2004-12-14 Theodore Ts'o <tytso@mit.edu>
* Makefile.in: Move strip command to install-strip target.
diff --git a/resize/resize2fs.c b/resize/resize2fs.c
index 3befbaaf..5ad77d62 100644
--- a/resize/resize2fs.c
+++ b/resize/resize2fs.c
@@ -46,6 +46,7 @@ static errcode_t block_mover(ext2_resize_t rfs);
static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
static errcode_t inode_ref_fix(ext2_resize_t rfs);
static errcode_t move_itables(ext2_resize_t rfs);
+static errcode_t fix_resize_inode(ext2_filsys fs);
static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
/*
@@ -133,6 +134,10 @@ errcode_t resize_fs(ext2_filsys fs, blk_t *new_size, int flags,
if (retval)
goto errout;
+ retval = fix_resize_inode(rfs->new_fs);
+ if (retval)
+ goto errout;
+
retval = ext2fs_close(rfs->new_fs);
if (retval)
goto errout;
@@ -205,12 +210,13 @@ retry:
* includes the superblock backup, the group descriptor
* backups, the inode bitmap, the block bitmap, and the inode
* table.
- *
- * XXX Not all block groups need the descriptor blocks, but
- * being clever is tricky...
*/
- overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
-
+ overhead = (int) (2 + fs->inode_blocks_per_group);
+
+ if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
+ overhead += 1 + fs->desc_blocks +
+ fs->super->s_reserved_gdt_blocks;
+
/*
* See if the last group is big enough to support the
* necessary data structures. If not, we need to get rid of
@@ -288,6 +294,29 @@ retry:
}
/*
+ * If the resize_inode feature is set, and we are changing the
+ * number of descriptor blocks, then adjust
+ * s_reserved_gdt_blocks if possible to avoid needing to move
+ * the inode table either now or in the future.
+ */
+ if ((fs->super->s_feature_compat &
+ EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
+ (rfs->old_fs->desc_blocks != fs->desc_blocks)) {
+ int new;
+
+ new = ((int) fs->super->s_reserved_gdt_blocks) +
+ (rfs->old_fs->desc_blocks - fs->desc_blocks);
+ if (new < 0)
+ new = 0;
+ if (new > fs->blocksize/4)
+ new = fs->blocksize/4;
+ fs->super->s_reserved_gdt_blocks = new;
+ if (new == 0)
+ fs->super->s_feature_compat &=
+ ~EXT2_FEATURE_COMPAT_RESIZE_INODE;
+ }
+
+ /*
* If we are shrinking the number block groups, we're done and
* can exit now.
*/
@@ -346,7 +375,8 @@ retry:
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
old_desc_blocks = fs->super->s_first_meta_bg;
else
- old_desc_blocks = fs->desc_blocks;
+ old_desc_blocks = fs->desc_blocks +
+ fs->super->s_reserved_gdt_blocks;
for (i = rfs->old_fs->group_desc_count;
i < fs->group_desc_count; i++) {
memset(&fs->group_desc[i], 0,
@@ -466,7 +496,8 @@ static errcode_t mark_table_blocks(ext2_filsys fs,
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
old_desc_blocks = fs->super->s_first_meta_bg;
else
- old_desc_blocks = fs->desc_blocks;
+ old_desc_blocks = fs->desc_blocks +
+ fs->super->s_reserved_gdt_blocks;
for (i = 0; i < fs->group_desc_count; i++) {
has_super = ext2fs_bg_has_super(fs, i);
if (has_super)
@@ -613,8 +644,8 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
old_blocks = old_fs->super->s_first_meta_bg;
new_blocks = fs->super->s_first_meta_bg;
} else {
- old_blocks = old_fs->desc_blocks;
- new_blocks = fs->desc_blocks;
+ old_blocks = old_fs->desc_blocks + old_fs->super->s_reserved_gdt_blocks;
+ new_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
}
if (old_blocks == new_blocks) {
@@ -1100,7 +1131,7 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
if (!ino)
break;
- if (inode.i_links_count == 0)
+ if (inode.i_links_count == 0 && ino != EXT2_RESIZE_INO)
continue; /* inode not in use */
pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
@@ -1428,6 +1459,57 @@ errout:
}
/*
+ * Fix the resize inode
+ */
+static errcode_t fix_resize_inode(ext2_filsys fs)
+{
+ struct ext2_inode inode;
+ errcode_t retval;
+ char * block_buf;
+
+ if (!(fs->super->s_feature_compat &
+ EXT2_FEATURE_COMPAT_RESIZE_INODE))
+ return 0;
+
+ retval = ext2fs_get_mem(fs->blocksize, &block_buf);
+ if (retval) goto errout;
+
+ retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
+ if (retval) goto errout;
+
+ inode.i_blocks = fs->blocksize/512;
+
+ retval = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
+ if (retval) goto errout;
+
+ if (!inode.i_block[EXT2_DIND_BLOCK]) {
+ /*
+ * Avoid zeroing out block #0; that's rude. This
+ * should never happen anyway since the filesystem
+ * should be fsck'ed and we assume it is consistent.
+ */
+ fprintf(stderr,
+ _("Should never happen resize inode corrupt!\n"));
+ exit(1);
+ }
+
+ memset(block_buf, 0, fs->blocksize);
+
+ retval = io_channel_write_blk(fs->io, inode.i_block[EXT2_DIND_BLOCK],
+ 1, block_buf);
+ if (retval) goto errout;
+
+ retval = ext2fs_create_resize_inode(fs);
+ if (retval)
+ goto errout;
+
+errout:
+ if (block_buf)
+ ext2fs_free_mem(&block_buf);
+ return retval;
+}
+
+/*
* Finally, recalculate the summary information
*/
static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)