Add support for the meta_bg feature flag to the resize2fs program.

Fix bug in meta_bg support in mke2fs, e2fsck, and dumpe2fs; we were 
incorrectly reserving the legacy block groups desriptor blocks.

diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index 9de2cdd..f781678 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,3 +1,9 @@
+2002-10-30  Theodore Ts'o  <tytso@mit.edu>
+
+	* pass1.c (mark_table_blocks): Fix bug in meta_bg support; only
+		mark blocks legacy group descriptor blocks up to 
+		s_first_meta_bg.
+
 2002-10-20  Theodore Ts'o  <tytso@valinux.com>
 
 	* pass1.c (mark_table_blocks): Add support for the meta_blockgroup
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index c685581..f25be76 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -1793,12 +1793,16 @@
 {
 	ext2_filsys fs = ctx->fs;
 	blk_t	block, b;
-	int	i, j, has_super, meta_bg, meta_bg_size;
+	int	i, j, has_super, meta_bg, meta_bg_size, old_desc_blocks;
 	struct problem_context pctx;
 	
 	clear_problem_context(&pctx);
 	
 	block = fs->super->s_first_data_block;
+	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;
 	for (i = 0; i < fs->group_desc_count; i++) {
 		pctx.group = i;
 
@@ -1819,7 +1823,7 @@
 				/*
 				 * Mark this group's copy of the descriptors
 				 */
-				for (j = 0; j < fs->desc_blocks; j++) {
+				for (j = 0; j < old_desc_blocks; j++) {
 					ext2fs_mark_block_bitmap(ctx->block_found_map,
 							 block + j + 1);
 				}
diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog
index 079615c..57e1d85 100644
--- a/lib/ext2fs/ChangeLog
+++ b/lib/ext2fs/ChangeLog
@@ -1,3 +1,13 @@
+2002-10-30  Theodore Ts'o  <tytso@mit.edu>
+
+	* alloc_tables.c (ext2fs_allocate_group_table): Allocate the inode
+		table so that it buts up against the bitmap blocks, to
+		avoid block fragmentation.
+
+	* closefs.c (write_bgdesc), initalize.c (ext2fs_initialize): Fix
+		bug; only allocate group descriptor blocks up to
+		s_first_meta_bg.
+
 2002-10-25  Theodore Ts'o  <tytso@mit.edu>
 
 	* ext2_fs.h: Add a new superblock field, s_mkfs_time, so that we
diff --git a/lib/ext2fs/alloc_tables.c b/lib/ext2fs/alloc_tables.c
index ca274cc..0326321 100644
--- a/lib/ext2fs/alloc_tables.c
+++ b/lib/ext2fs/alloc_tables.c
@@ -41,38 +41,17 @@
 	if (last_blk >= fs->super->s_blocks_count)
 		last_blk = fs->super->s_blocks_count - 1;
 
-	start_blk = group_blk + 3 + fs->desc_blocks;
-	if (start_blk > last_blk)
-		start_blk = group_blk;
-
 	if (!bmap)
 		bmap = fs->block_map;
 	
 	/*
-	 * Allocate the inode table
-	 */
-	if (!fs->group_desc[group].bg_inode_table) {
-		retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
-						fs->inode_blocks_per_group,
-						bmap, &new_blk);
-		if (retval)
-			return retval;
-		for (j=0, blk = new_blk;
-		     j < fs->inode_blocks_per_group;
-		     j++, blk++)
-			ext2fs_mark_block_bitmap(bmap, blk);
-		fs->group_desc[group].bg_inode_table = new_blk;
-	}
-
-	/*
 	 * Allocate the block and inode bitmaps, if necessary
 	 */
 	if (fs->stride) {
-		start_blk += fs->inode_blocks_per_group;
+		start_blk = group_blk + fs->inode_blocks_per_group;
 		start_blk += ((fs->stride * group) %
 			      (last_blk - start_blk));
 		if (start_blk > last_blk)
-			/* should never happen */
 			start_blk = group_blk;
 	} else
 		start_blk = group_blk;
@@ -100,6 +79,24 @@
 		ext2fs_mark_block_bitmap(bmap, new_blk);
 		fs->group_desc[group].bg_inode_bitmap = new_blk;
 	}
+
+	/*
+	 * Allocate the inode table
+	 */
+	if (!fs->group_desc[group].bg_inode_table) {
+		retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
+						fs->inode_blocks_per_group,
+						bmap, &new_blk);
+		if (retval)
+			return retval;
+		for (j=0, blk = new_blk;
+		     j < fs->inode_blocks_per_group;
+		     j++, blk++)
+			ext2fs_mark_block_bitmap(bmap, blk);
+		fs->group_desc[group].bg_inode_table = new_blk;
+	}
+
+	
 	return 0;
 }
 
diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c
index dcf244b..c96b7ab 100644
--- a/lib/ext2fs/closefs.c
+++ b/lib/ext2fs/closefs.c
@@ -122,18 +122,21 @@
 {
 	errcode_t	retval;
 	char		*group_ptr = (char *) group_shadow;
-	int		j;
+	int		j, old_desc_blocks;
 	int		has_super = ext2fs_bg_has_super(fs, group);
 	dgrp_t		meta_bg_size, meta_bg;
-	blk_t		blk;
 
 	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
 	meta_bg = group / meta_bg_size;
+	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;
 	if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
 	    (meta_bg < fs->super->s_first_meta_bg)) {
 		if (!has_super)
 			return 0;
-		for (j=0; j < fs->desc_blocks; j++) {
+		for (j=0; j < old_desc_blocks; j++) {
 			retval = io_channel_write_blk(fs->io,
 						      group_block+1+j, 1,
 						      group_ptr);
@@ -180,7 +183,6 @@
 	dgrp_t		i,j,maxgroup;
 	blk_t		group_block;
 	errcode_t	retval;
-	char		*group_ptr;
 	unsigned long	fs_state;
 	struct ext2_super_block *super_shadow = 0;
 	struct ext2_group_desc *group_shadow = 0;
@@ -277,7 +279,6 @@
 						   group_shadow)))
 				goto errout;
 		}
-	next_group:
 		group_block += EXT2_BLOCKS_PER_GROUP(fs->super);
 	}
 	fs->super->s_block_group_nr = 0;
diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
index ecb27d7..f5552e6 100644
--- a/lib/ext2fs/initialize.c
+++ b/lib/ext2fs/initialize.c
@@ -67,7 +67,7 @@
 	int		i, j;
 	blk_t		numblocks;
 	char		*buf;
-	int		meta_bg_size, meta_bg, has_super;
+	int		meta_bg_size, meta_bg, has_super, old_desc_blocks;
 
 	if (!param || !param->s_blocks_count)
 		return EXT2_ET_INVALID_ARGUMENT;
@@ -293,6 +293,10 @@
 	 */
 	group_block = super->s_first_data_block;
 	super->s_free_blocks_count = 0;
+	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;
 	for (i = 0; i < fs->group_desc_count; i++) {
 		if (i == fs->group_desc_count-1) {
 			numblocks = (fs->super->s_blocks_count -
@@ -317,10 +321,10 @@
 		      EXT2_FEATURE_INCOMPAT_META_BG) ||
 		    (meta_bg < fs->super->s_first_meta_bg)) {
 			if (has_super) {
-				for (j=0; j < fs->desc_blocks; j++)
+				for (j=0; j < old_desc_blocks; j++)
 					ext2fs_mark_block_bitmap(fs->block_map,
 							 group_block + j + 1);
-				numblocks -= fs->desc_blocks;
+				numblocks -= old_desc_blocks;
 			}
 		} else {
 			if (has_super)
@@ -357,6 +361,3 @@
 	ext2fs_free(fs);
 	return retval;
 }
-	
-
-
diff --git a/misc/ChangeLog b/misc/ChangeLog
index 6f6d29f..57e6bc1 100644
--- a/misc/ChangeLog
+++ b/misc/ChangeLog
@@ -1,3 +1,12 @@
+2002-10-30  Theodore Ts'o  <tytso@mit.edu>
+
+	* dumpe2fs.c (list_desc): Fix bug in algorithm which determined
+		which blocks are used as backup superblock and block group
+		descriptors.
+
+	* mke2fs.c (PRS): Fix bug which checked the tmp pointer
+		erreoneously (and needlessly).
+
 2002-10-28    <tytso@snap.thunk.org>
 
 	* fsck.c (main): Fix bug reported by Gregory Mutt.  Multiple
diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
index d1308ef..073238e 100644
--- a/misc/dumpe2fs.c
+++ b/misc/dumpe2fs.c
@@ -87,8 +87,7 @@
 	long diff;
 	blk_t	group_blk, next_blk;
 	char *block_bitmap=NULL, *inode_bitmap=NULL;
-	int inode_blocks_per_group;
-	int group_desc_blocks;
+	int inode_blocks_per_group, old_desc_blocks;
 	int meta_bg, meta_bg_size, has_super;
 
 	if (fs->block_map)
@@ -100,15 +99,12 @@
 				   EXT2_INODE_SIZE(fs->super)) +
 				  EXT2_BLOCK_SIZE(fs->super) - 1) /
 				 EXT2_BLOCK_SIZE(fs->super);
-	group_desc_blocks = ((fs->super->s_blocks_count -
-			      fs->super->s_first_data_block +
-			      EXT2_BLOCKS_PER_GROUP(fs->super) - 1) /
-			     EXT2_BLOCKS_PER_GROUP(fs->super) +
-			     EXT2_DESC_PER_BLOCK(fs->super) - 1) /
-			    EXT2_DESC_PER_BLOCK(fs->super);
-
 	fputc('\n', stdout);
 	group_blk = fs->super->s_first_data_block;
+	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;
 	for (i = 0; i < fs->group_desc_count; i++) {
 		next_blk = group_blk + fs->super->s_blocks_per_group;
 		if (next_blk > fs->super->s_blocks_count)
@@ -128,11 +124,12 @@
 		if (!(fs->super->s_feature_incompat &
 		      EXT2_FEATURE_INCOMPAT_META_BG) ||
 		    (meta_bg < fs->super->s_first_meta_bg)) {
-			fputc(has_super ? ',' : ' ', stdout);
-			printf(_(" Group descriptors at "));
-			printf(range_format, group_blk+1,
-			       group_blk + group_desc_blocks);
-			fputc('\n', stdout);
+			if (has_super) {
+				printf(_(", Group descriptors at "));
+				printf(range_format, group_blk+1,
+				       group_blk + old_desc_blocks);
+				fputc('\n', stdout);
+			}
 		} else {
 			if (has_super)
 				has_super = 1;
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 1c83d9f..0371c37 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -1175,7 +1175,7 @@
 
 	if (param.s_blocks_per_group) {
 		if (param.s_blocks_per_group < 256 ||
-		    param.s_blocks_per_group > group_blk_max || *tmp) {
+		    param.s_blocks_per_group > group_blk_max) {
 			com_err(program_name, 0,
 				_("blocks per group count out of range"));
 			exit(1);
diff --git a/resize/ChangeLog b/resize/ChangeLog
index 5c6f663..54f0ae9 100644
--- a/resize/ChangeLog
+++ b/resize/ChangeLog
@@ -1,3 +1,13 @@
+2002-10-30  Theodore Ts'o  <tytso@mit.edu>
+
+	* resize2fs.c (adjust_superblock, mark_table_blocks,
+		blocks_to_move): Add support for resizing filesystems that
+		use the meta block group layout.
+
+	* main.c (main): Fixed bug that erroneously (and
+		needlessly) checked the incompat feature flag field
+		against the supported ro_compat feature set.
+
 2002-10-03  Theodore Ts'o  <tytso@mit.edu>
 
 	* resize2fs.8.in: Fix typo in man page.
diff --git a/resize/main.c b/resize/main.c
index 7808b1d..841f4bd 100644
--- a/resize/main.c
+++ b/resize/main.c
@@ -204,8 +204,7 @@
 	 * Check for compatibility with the feature sets.  We need to
 	 * be more stringent than ext2fs_open().
 	 */
-	if ((fs->super->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
-	    (fs->super->s_feature_incompat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
+	if (fs->super->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) {
 		com_err(program_name, EXT2_ET_UNSUPP_FEATURE,
 			"(%s)", device_name);
 		exit(1);
diff --git a/resize/resize2fs.c b/resize/resize2fs.c
index 4dd2b33..cc2fda4 100644
--- a/resize/resize2fs.c
+++ b/resize/resize2fs.c
@@ -179,6 +179,7 @@
 	blk_t		blk, group_block;
 	unsigned long	i, j;
 	int		old_numblocks, numblocks, adjblocks;
+	int		has_super, meta_bg, meta_bg_size, old_desc_blocks;
 	unsigned long	max_group;
 	
 	fs = rfs->new_fs;
@@ -341,6 +342,10 @@
 		if (retval)
 			goto errout;
 	}
+	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;
 	for (i = rfs->old_fs->group_desc_count;
 	     i < fs->group_desc_count; i++) {
 		memset(&fs->group_desc[i], 0,
@@ -356,12 +361,33 @@
 		} else
 			numblocks = fs->super->s_blocks_per_group;
 
-		if (ext2fs_bg_has_super(fs, i)) {
-			for (j=0; j < fs->desc_blocks+1; j++)
-				ext2fs_mark_block_bitmap(fs->block_map,
-							 group_block + j);
-			adjblocks = 1 + fs->desc_blocks;
+		has_super = ext2fs_bg_has_super(fs, i);
+		if (has_super) {
+			ext2fs_mark_block_bitmap(fs->block_map, group_block);
+			adjblocks++;
 		}
+		meta_bg_size = (fs->blocksize /
+				sizeof (struct ext2_group_desc));
+		meta_bg = i / meta_bg_size;
+		if (!(fs->super->s_feature_incompat &
+		      EXT2_FEATURE_INCOMPAT_META_BG) ||
+		    (meta_bg < fs->super->s_first_meta_bg)) {
+			if (has_super) {
+				for (j=0; j < old_desc_blocks; j++)
+					ext2fs_mark_block_bitmap(fs->block_map,
+							 group_block + 1 + j);
+				adjblocks += old_desc_blocks;
+			}
+		} else {
+			if (has_super)
+				has_super = 1;
+			if (((i % meta_bg_size) == 0) ||
+			    ((i % meta_bg_size) == 1) ||
+			    ((i % meta_bg_size) == (meta_bg_size-1)))
+				ext2fs_mark_block_bitmap(fs->block_map,
+						 group_block + has_super);
+		}
+		
 		adjblocks += 2 + fs->inode_blocks_per_group;
 		
 		numblocks -= adjblocks;
@@ -421,7 +447,8 @@
 				   ext2fs_block_bitmap *ret_bmap)
 {
 	blk_t			block, b;
-	int			i,j;
+	int			i,j, has_super, meta_bg, meta_bg_size;
+	int			old_desc_blocks;
 	ext2fs_block_bitmap	bmap;
 	errcode_t		retval;
 
@@ -430,21 +457,43 @@
 	if (retval)
 		return retval;
 	
+	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
 	block = fs->super->s_first_data_block;
+	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;
 	for (i = 0; i < fs->group_desc_count; i++) {
-		if (ext2fs_bg_has_super(fs, i)) {
+		has_super = ext2fs_bg_has_super(fs, i);
+		if (has_super)
 			/*
 			 * Mark this group's copy of the superblock
 			 */
 			ext2fs_mark_block_bitmap(bmap, block);
 		
-			/*
-			 * Mark this group's copy of the descriptors
-			 */
-			for (j = 0; j < fs->desc_blocks; j++)
-				ext2fs_mark_block_bitmap(bmap, block + j + 1);
-		}
+		meta_bg = i / meta_bg_size;
 		
+		if (!(fs->super->s_feature_incompat &
+		      EXT2_FEATURE_INCOMPAT_META_BG) ||
+		    (meta_bg < fs->super->s_first_meta_bg)) {
+			if (has_super) {
+				/*
+				 * Mark this group's copy of the descriptors
+				 */
+				for (j = 0; j < old_desc_blocks; j++)
+					ext2fs_mark_block_bitmap(bmap,
+							 block + j + 1);
+			}
+		} else {
+			if (has_super)
+				has_super = 1;
+			if (((i % meta_bg_size) == 0) ||
+			    ((i % meta_bg_size) == 1) ||
+			    ((i % meta_bg_size) == (meta_bg_size-1)))
+				ext2fs_mark_block_bitmap(bmap,
+							 block + has_super);
+		}
+	
 		/*
 		 * Mark the blocks used for the inode table
 		 */
@@ -470,13 +519,49 @@
 }
 
 /*
+ * This function checks to see if a particular block (either a
+ * superblock or a block group descriptor) overlaps with an inode or
+ * block bitmap block, or with the inode table.
+ */
+static void mark_fs_metablock(ext2_resize_t rfs,
+			      ext2fs_block_bitmap meta_bmap,
+			      int group, blk_t blk)
+{
+	ext2_filsys 	fs = rfs->new_fs;
+	
+	ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
+	ext2fs_mark_block_bitmap(fs->block_map, blk);
+
+	/*
+	 * Check to see if we overlap with the inode or block bitmap,
+	 * or the inode tables.  If not, and the block is in use, then
+	 * mark it as a block to be moved.
+	 */
+	if (IS_BLOCK_BM(fs, group, blk)) {
+		FS_BLOCK_BM(fs, group) = 0;
+		rfs->needed_blocks++;
+	} else if (IS_INODE_BM(fs, group, blk)) {
+		FS_INODE_BM(fs, group) = 0;
+		rfs->needed_blocks++;
+	} else if (IS_INODE_TB(fs, group, blk)) {
+		FS_INODE_TB(fs, group) = 0;
+		rfs->needed_blocks++;
+	} else if (ext2fs_test_block_bitmap(rfs->old_fs->block_map, blk) &&
+		   !ext2fs_test_block_bitmap(meta_bmap, blk)) {
+		ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
+		rfs->needed_blocks++;
+	}
+}
+
+
+/*
  * This routine marks and unmarks reserved blocks in the new block
  * bitmap.  It also determines which blocks need to be moved and
  * places this information into the move_blocks bitmap.
  */
 static errcode_t blocks_to_move(ext2_resize_t rfs)
 {
-	int	i, j, max_groups;
+	int	i, j, max_groups, has_super, meta_bg, meta_bg_size;
 	blk_t	blk, group_blk;
 	unsigned long old_blocks, new_blocks;
 	errcode_t	retval;
@@ -518,9 +603,14 @@
 		ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
 	}
 	
-	old_blocks = old_fs->desc_blocks;
-	new_blocks = fs->desc_blocks;
-
+	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) {
+		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;
+	}
+	
 	if (old_blocks == new_blocks) {
 		retval = 0;
 		goto errout;
@@ -556,38 +646,29 @@
 	 * If we're increasing the number of descriptor blocks, life
 	 * gets interesting....  
 	 */
+	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
 	for (i = 0; i < max_groups; i++) {
-		if (!ext2fs_bg_has_super(fs, i))
-			goto next_group;
+		has_super = ext2fs_bg_has_super(fs, i);
+		if (has_super)
+			mark_fs_metablock(rfs, meta_bmap, i, group_blk);
 
-		for (blk = group_blk;
-		     blk < group_blk + 1 + new_blocks; blk++) {
-			ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
-			ext2fs_mark_block_bitmap(fs->block_map, blk);
-
-			/*
-			 * Check to see if we overlap with the inode
-			 * or block bitmap, or the inode tables.  If
-			 * not, and the block is in use, then mark it
-			 * as a block to be moved.
-			 */
-			if (IS_BLOCK_BM(fs, i, blk)) {
-				FS_BLOCK_BM(fs, i) = 0;
-				rfs->needed_blocks++;
-			} else if (IS_INODE_BM(fs, i, blk)) {
-				FS_INODE_BM(fs, i) = 0;
-				rfs->needed_blocks++;
-			} else if (IS_INODE_TB(fs, i, blk)) {
-				FS_INODE_TB(fs, i) = 0;
-				rfs->needed_blocks++;
-			} else if (ext2fs_test_block_bitmap(old_fs->block_map,
-							    blk) &&
-				   !ext2fs_test_block_bitmap(meta_bmap, blk)) {
-				ext2fs_mark_block_bitmap(rfs->move_blocks,
-							 blk);
-				rfs->needed_blocks++;
-			}
+		meta_bg = i / meta_bg_size;
+		if (!(fs->super->s_feature_incompat &
+		      EXT2_FEATURE_INCOMPAT_META_BG) ||
+		    (meta_bg < fs->super->s_first_meta_bg)) {
+			for (blk = group_blk+1;
+			     blk < group_blk + 1 + new_blocks; blk++)
+				mark_fs_metablock(rfs, meta_bmap, i, blk);
+		} else {
+			if (has_super)
+				has_super = 1;
+			if (((i % meta_bg_size) == 0) ||
+			    ((i % meta_bg_size) == 1) ||
+			    ((i % meta_bg_size) == (meta_bg_size-1)))
+				mark_fs_metablock(rfs, meta_bmap, i,
+						  group_blk + has_super);
 		}
+
 		if (fs->group_desc[i].bg_inode_table &&
 		    fs->group_desc[i].bg_inode_bitmap &&
 		    fs->group_desc[i].bg_block_bitmap)