[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: resize2fs on LVM on MD raid on Fedora Core 3 - inode table conflicts in fsck



On Sat, Dec 11, 2004 at 12:57:08AM -0700, Andreas Dilger wrote:
> You could either do a full e2fsck on it (it should be able to recover this
> since the metadata that the inode table is overlapping is unused and e2fsck
> will make a copy of the duplicate blocks) or you could use resize2fs to
> shrink it back to the original size (that should also make the problem go
> away).  Best to do this before doing any writes to the filesystem, and I
> would suggest making a backup, but since this is already a backup...

Actually, this can (fairly often) fail since the new group descriptor
blocks + the GDT reserved blocks can overlap with the inode table, and
e2fsck doesn't deal well with relocating the inode table if there
aren't enough contiguous blocks.  At that point, e2fsck will fail to
to correct things.

Shrinking the filesystem *should* work, at least in most cases, but
the method which I have tested involves applying the following patch
to e2fsprogs:

http://e2fsprogs.bkbits.net:8080/e2fsprogs/gnupatch 41c232c9j54wXA9ZNSaEuTwkzJI5QQ

and then running the commands:

	debugfs -w /dev/hdXXX -R "features ^resize_inode"
	e2fsck -f /dev/hdXXXX

To remove the resize_inode feature.  If you want on-line resizing, you
can then run ext2prepare and that should restore the resize_inode
safely.

I have a patch to resize2fs (attached) to make it be aware of the
resize_inode feature, but I'm still testing it for 100% correctness,
so it's for review and examination purposes only at this point; it
hasn't been committed into my sources yet.

						- Ted
===== resize/resize2fs.c 1.33 vs edited =====
--- 1.33/resize/resize2fs.c	2004-09-17 17:10:17 -04:00
+++ edited/resize/resize2fs.c	2004-12-23 08:24:47 -05:00
@@ -46,6 +46,7 @@
 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 @@
 	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 @@
 	 * 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 @@
 	}
 
 	/*
+	 * 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 @@
 	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 @@
 	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 @@
 		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 @@
 		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);
@@ -1424,6 +1455,57 @@
 	return 0;
 	
 errout:
+	return retval;
+}
+
+/*
+ * 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;
 }
 

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]