Add support for on-line resizing ala the resize inode.  This patch
is taken from Fedora Core 3's e2fsprogs 1.35-11.2.src.rpm's 
e2fsprogs-resize.patch.

diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
index 2ee06b5..3b80f46 100644
--- a/lib/ext2fs/initialize.c
+++ b/lib/ext2fs/initialize.c
@@ -58,6 +58,35 @@
 #endif
 #define EXT2_DFL_CHECKINTERVAL (86400L * 180L)
 
+/*
+ * Calculate the number of GDT blocks to reserve for online filesystem growth.
+ * The absolute maximum number of GDT blocks we can reserve is determined by
+ * the number of block pointers that can fit into a single block.
+ */
+static int calc_reserved_gdt_blocks(ext2_filsys fs)
+{
+	struct ext2_super_block *sb = fs->super;
+	unsigned long bpg = sb->s_blocks_per_group;
+	unsigned int gdpb = fs->blocksize / sizeof(struct ext2_group_desc);
+	unsigned long max_blocks = 0xffffffff;
+	unsigned long rsv_groups;
+	int rsv_gdb;
+
+	/* We set it at 1024x the current filesystem size, or
+	 * the upper block count limit (2^32), whichever is lower.
+	 */
+	if (sb->s_blocks_count < max_blocks / 1024)
+		max_blocks = sb->s_blocks_count * 1024;
+	rsv_groups = (max_blocks - sb->s_first_data_block + bpg - 1) / bpg;
+	rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - fs->desc_blocks;
+	if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
+		rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
+	printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %lu\n",
+	       max_blocks, rsv_groups, rsv_gdb);
+
+	return rsv_gdb;
+}
+
 errcode_t ext2fs_initialize(const char *name, int flags,
 			    struct ext2_super_block *param,
 			    io_manager manager, ext2_filsys *ret_fs)
@@ -72,6 +101,7 @@
 	unsigned int	ipg;
 	dgrp_t		i;
 	blk_t		numblocks;
+	int		rsv_gdt;
 	char		*buf;
 
 	if (!param || !param->s_blocks_count)
@@ -120,10 +150,14 @@
 	set_field(s_feature_incompat, 0);
 	set_field(s_feature_ro_compat, 0);
 	set_field(s_first_meta_bg, 0);
-	if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)
-		return EXT2_ET_UNSUPP_FEATURE;
-	if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)
-		return EXT2_ET_RO_UNSUPP_FEATURE;
+	if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
+		retval = EXT2_ET_UNSUPP_FEATURE;
+		goto cleanup;
+	}
+	if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
+		retval = EXT2_ET_RO_UNSUPP_FEATURE;
+		goto cleanup;
+	}
 
 	set_field(s_rev_level, EXT2_GOOD_OLD_REV);
 	if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
@@ -157,8 +191,7 @@
 	 * If we're creating an external journal device, we don't need
 	 * to bother with the rest.
 	 */
-	if (super->s_feature_incompat &
-	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+	if (super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
 		fs->group_desc_count = 0;
 		ext2fs_mark_super_dirty(fs);
 		*ret_fs = fs;
@@ -170,8 +203,10 @@
 				super->s_first_data_block +
 				EXT2_BLOCKS_PER_GROUP(super) - 1)
 		/ EXT2_BLOCKS_PER_GROUP(super);
-	if (fs->group_desc_count == 0)
-		return EXT2_ET_TOOSMALL;
+	if (fs->group_desc_count == 0) {
+		retval = EXT2_ET_TOOSMALL;
+		goto cleanup;
+	}
 	fs->desc_blocks = (fs->group_desc_count +
 			   EXT2_DESC_PER_BLOCK(super) - 1)
 		/ EXT2_DESC_PER_BLOCK(super);
@@ -244,15 +279,29 @@
 	super->s_free_inodes_count = super->s_inodes_count;
 
 	/*
+	 * check the number of reserved group descriptor table blocks
+	 */
+	if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)
+		rsv_gdt = calc_reserved_gdt_blocks(fs);
+	else
+		rsv_gdt = 0;
+	set_field(s_reserved_gdt_blocks, rsv_gdt);
+	if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
+		retval = EXT2_ET_RES_GDT_BLOCKS;
+		goto cleanup;
+	}
+
+	/*
 	 * Overhead is the number of bookkeeping blocks per group.  It
 	 * 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 = (int) (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 + super->s_reserved_gdt_blocks;
 
 	/* This can only happen if the user requested too many inodes */
 	if (overhead > super->s_blocks_per_group)