Add support for EXT2_FEATURE_COMPAT_LAZY_BG

This feature is initially intended for testing purposes; it allows an
ext2/ext3 developer to create very large filesystems using sparse files
where most of the block groups are not initialized and so do not require
much disk space.  Eventually it could be used as a way of speeding up
mke2fs and e2fsck for large filesystem, but that would be best done by 
adding an RO_COMPAT extension to the filesystem to allow the inode table
to be lazily initialized on a per-block basis, instead of being entirely initialized
or entirely unused on a per-blockgroup basis.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>

diff --git a/debugfs/ChangeLog b/debugfs/ChangeLog
index a9fb8a4..0425d22 100644
--- a/debugfs/ChangeLog
+++ b/debugfs/ChangeLog
@@ -1,3 +1,8 @@
+2006-05-08  Theodore Tso  <tytso@mit.edu>
+
+	* debugfs.c (do_show_super_stats): Print out the block group flags
+		if they are set.
+
 2006-04-27  Theodore Ts'o  <tytso@mit.edu>
 
 	* htree.c (do_htree_dump, do_dx_hash), ls.c (do_list_dir): Add
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 12ef00c..25d52d7 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -266,13 +266,26 @@
 	fputs("\n", f);
 }
 
+static void print_bg_opts(struct ext2_group_desc *gdp, int mask,
+			  const char *str, int *first, FILE *f)
+{
+	if (gdp->bg_flags & mask) {
+		if (*first) {
+			fputs("           [", f);
+			*first = 0;
+		} else
+			fputs(", ", f);
+		fputs(str, f);
+	}
+}
+
 void do_show_super_stats(int argc, char *argv[])
 {
 	dgrp_t	i;
 	FILE 	*out;
 	struct ext2_group_desc *gdp;
 	int	c, header_only = 0;
-	int	numdirs = 0;
+	int	numdirs = 0, first;
 
 	reset_getopt();
 	while ((c = getopt (argc, argv, "h")) != EOF) {
@@ -302,7 +315,7 @@
 	}
 	
 	gdp = &current_fs->group_desc[0];
-	for (i = 0; i < current_fs->group_desc_count; i++, gdp++)
+	for (i = 0; i < current_fs->group_desc_count; i++, gdp++) {
 		fprintf(out, " Group %2d: block bitmap at %u, "
 		        "inode bitmap at %u, "
 		        "inode table at %u\n"
@@ -318,6 +331,14 @@
 		        gdp->bg_used_dirs_count,
 		        gdp->bg_used_dirs_count != 1 ? "directories"
 				: "directory");
+		first = 1;
+		print_bg_opts(gdp, EXT2_BG_INODE_UNINIT, "Inode not init",
+			      &first, out);
+		print_bg_opts(gdp, EXT2_BG_BLOCK_UNINIT, "Block not init",
+			      &first, out);
+		if (!first)
+			fputs("]\n", out);
+	}
 	close_pager(out);
 	return;
 print_usage:
diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index 3b408fa..545dafc 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,3 +1,11 @@
+2006-05-08  Theodore Tso  <tytso@mit.edu>
+
+	* pass5.c (check_block_bitmaps, check_inode_bitmaps): Add support
+		for the lazy_bg feature; if the block group does not have
+		an initialized block or inode bitmaps/table, emulate what
+		the allocation bitmap would look like if no blocks or
+		inodes have been allocated.
+
 2006-03-27  Theodore Ts'o  <tytso@mit.edu>
 
 	* e2fsck.8.in: Add badblocks(8) to the See Also section.
diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c
index e708fa4..eb3ebf0 100644
--- a/e2fsck/pass5.c
+++ b/e2fsck/pass5.c
@@ -111,7 +111,7 @@
 static void check_block_bitmaps(e2fsck_t ctx)
 {
 	ext2_filsys fs = ctx->fs;
-	blk_t	i;
+	blk_t	i, super;
 	int	*free_array;
 	int	group = 0;
 	unsigned int	blocks = 0;
@@ -121,6 +121,8 @@
 	struct problem_context	pctx;
 	int	problem, save_problem, fixit, had_problem;
 	errcode_t	retval;
+	int		lazy_bg = 0;
+	int		skip_group = 0;
 	
 	clear_problem_context(&pctx);
 	free_array = (int *) e2fsck_allocate_memory(ctx,
@@ -156,19 +158,45 @@
 		return;
 	}
 		       
+	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
+				    EXT2_FEATURE_COMPAT_LAZY_BG))
+		lazy_bg++;
+
 redo_counts:
 	had_problem = 0;
 	save_problem = 0;
 	pctx.blk = pctx.blk2 = NO_BLK;
+	if (lazy_bg && (fs->group_desc[group].bg_flags &
+			EXT2_BG_BLOCK_UNINIT))
+		skip_group++;
+	super = fs->super->s_first_data_block;
 	for (i = fs->super->s_first_data_block;
 	     i < fs->super->s_blocks_count;
 	     i++) {
 		actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
-		bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
+
+		if (skip_group) {
+			if ((i >= super) &&
+			    (i <= super + fs->desc_blocks) &&
+			    ext2fs_bg_has_super(fs, group))
+				bitmap = 1;
+			else if (i == fs->group_desc[group].bg_block_bitmap)
+				bitmap = 1;
+			else if (i == fs->group_desc[group].bg_inode_bitmap)
+				bitmap = 1;
+			else if (i >= fs->group_desc[group].bg_inode_table &&
+				 (i < fs->group_desc[group].bg_inode_table
+				  + fs->inode_blocks_per_group))
+				bitmap = 1;
+			else
+				bitmap = 0;
+			actual = (actual != 0);
+		} else
+			bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
 		
 		if (actual == bitmap)
 			goto do_counts;
-		
+
 		if (!actual && bitmap) {
 			/*
 			 * Block not used, but marked in use in the bitmap.
@@ -197,7 +225,7 @@
 		had_problem++;
 		
 	do_counts:
-		if (!bitmap) {
+		if (!bitmap && !skip_group) {
 			group_free++;
 			free_blocks++;
 		}
@@ -208,10 +236,17 @@
 			group ++;
 			blocks = 0;
 			group_free = 0;
+			skip_group = 0;
+			super += fs->super->s_blocks_per_group;
 			if (ctx->progress)
 				if ((ctx->progress)(ctx, 5, group,
 						    fs->group_desc_count*2))
 					return;
+			if (lazy_bg &&
+			    (i != fs->super->s_blocks_count-1) &&
+			    (fs->group_desc[group].bg_flags &
+			     EXT2_BG_BLOCK_UNINIT))
+				skip_group++;
 		}
 	}
 	if (pctx.blk != NO_BLK)
@@ -286,6 +321,8 @@
 	errcode_t	retval;
 	struct problem_context	pctx;
 	int		problem, save_problem, fixit, had_problem;
+	int		lazy_bg = 0;
+	int		skip_group = 0;
 	
 	clear_problem_context(&pctx);
 	free_array = (int *) e2fsck_allocate_memory(ctx,
@@ -321,14 +358,24 @@
 		return;
 	}
 
+	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
+				    EXT2_FEATURE_COMPAT_LAZY_BG))
+		lazy_bg++;
+
 redo_counts:
 	had_problem = 0;
 	save_problem = 0;
 	pctx.ino = pctx.ino2 = 0;
+	if (lazy_bg && (fs->group_desc[group].bg_flags &
+			EXT2_BG_INODE_UNINIT))
+		skip_group++;
+
 	for (i = 1; i <= fs->super->s_inodes_count; i++) {
 		actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
-		bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
-		
+		if (skip_group) 
+			bitmap = 0;
+		else
+			bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
 		if (actual == bitmap)
 			goto do_counts;
 		
@@ -360,12 +407,12 @@
 		had_problem++;
 		
 do_counts:
-		if (!bitmap) {
-			group_free++;
-			free_inodes++;
-		} else {
+		if (bitmap) {
 			if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
 				dirs_count++;
+		} else if (!skip_group) {
+			group_free++;
+			free_inodes++;
 		}
 		inodes++;
 		if ((inodes == fs->super->s_inodes_per_group) ||
@@ -374,6 +421,7 @@
 			dir_array[group] = dirs_count;
 			group ++;
 			inodes = 0;
+			skip_group = 0;
 			group_free = 0;
 			dirs_count = 0;
 			if (ctx->progress)
@@ -381,6 +429,11 @@
 					    group + fs->group_desc_count,
 					    fs->group_desc_count*2))
 					return;
+			if (lazy_bg &&
+			    (i != fs->super->s_inodes_count) &&
+			    (fs->group_desc[group].bg_flags &
+			     EXT2_BG_INODE_UNINIT))
+				skip_group++;
 		}
 	}
 	if (pctx.ino)
diff --git a/lib/e2p/ChangeLog b/lib/e2p/ChangeLog
index 358e108..641e7d8 100644
--- a/lib/e2p/ChangeLog
+++ b/lib/e2p/ChangeLog
@@ -1,3 +1,7 @@
+2006-05-08  Theodore Tso  <tytso@mit.edu>
+
+	* feature.c: Add support for EXT2_FEATURE_COMPAT_LAZY_BG feature.
+
 2006-04-18  Theodore Ts'o  <tytso@mit.edu>
 
 	* uuid.c (e2p_is_null_uuid): Fix really stupid bug which could
diff --git a/lib/e2p/feature.c b/lib/e2p/feature.c
index 50f1ef3..e8f6729 100644
--- a/lib/e2p/feature.c
+++ b/lib/e2p/feature.c
@@ -35,6 +35,8 @@
 			"dir_index" },
 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,
 			"resize_inode" },
+	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_LAZY_BG,
+			"lazy_bg" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
 			"sparse_super" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog
index 7da3fe2..512ef3f 100644
--- a/lib/ext2fs/ChangeLog
+++ b/lib/ext2fs/ChangeLog
@@ -1,3 +1,29 @@
+2006-05-08  Theodore Tso  <tytso@mit.edu>
+
+	* rw_bitmaps.c (write_bitmaps, read_bitmaps): Added support for
+		lazy blockgroups.  If a block group has flags indicating
+		that its block or inode data structures have not been
+		initialized, skip reading or writing that portion of the
+		bitmap.
+
+	* inode.c (ext2fs_open_inode_scan, ext2fs_read_inode_full): When
+		scanning a filesystem with lazy blockgroups, skip
+		uninitialized portions of the inode table when iterating
+		over the block group.
+
+	* swapfs.c (ext2fs_swap_group_desc): Byte swap the bg_flags field.
+
+	* ext2fs.h: Define the a new internal flag, EXT2_SF_DO_LAZY, so
+		that the inode interator knows compat_lazy_bg feature is
+		enabled.  Declare that this version of e2fsprogs supports
+		the EXT2_FEATURE_COMPAY_LAZY_BG feature.
+
+	* ext2_fs.h (struct ext2_group_desc): Use the bg_pad field for
+		bg_flags, and define the flags EXT2_BG_INODE_UNINIT and
+		EXT2_BG_BLOCK_UNINIT.  These flags are only honored if
+		EXT2_FEATURE_COMPAT_LAZY_BG feature is enabled (also
+		added).
+
 2006-04-23  Theodore Ts'o  <tytso@mit.edu>
 
 	* rw_bitmaps.c (write_bitmaps, ext2fs_write_inode_bitmap,
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index e427add..1cfbc35 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -143,10 +143,13 @@
 	__u16	bg_free_blocks_count;	/* Free blocks count */
 	__u16	bg_free_inodes_count;	/* Free inodes count */
 	__u16	bg_used_dirs_count;	/* Directories count */
-	__u16	bg_pad;
+	__u16	bg_flags;
 	__u32	bg_reserved[3];
 };
 
+#define EXT2_BG_INODE_UNINIT	0x0001 /* Inode table/bitmap not initialized */
+#define EXT2_BG_BLOCK_UNINIT	0x0002 /* Block bitmap not initialized */
+
 /*
  * Data structures used by the directory indexing feature
  *
@@ -568,6 +571,7 @@
 #define EXT2_FEATURE_COMPAT_EXT_ATTR		0x0008
 #define EXT2_FEATURE_COMPAT_RESIZE_INODE	0x0010
 #define EXT2_FEATURE_COMPAT_DIR_INDEX		0x0020
+#define EXT2_FEATURE_COMPAT_LAZY_BG		0x0040
 
 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index c3d0428..8618fe2 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -341,6 +341,7 @@
 #define EXT2_SF_BAD_INODE_BLK	0x0002
 #define EXT2_SF_BAD_EXTRA_BYTES	0x0004
 #define EXT2_SF_SKIP_MISSING_ITABLE	0x0008
+#define EXT2_SF_DO_LAZY		0x0010
 
 /*
  * ext2fs_check_if_mounted flags
@@ -437,6 +438,7 @@
 					 EXT3_FEATURE_COMPAT_HAS_JOURNAL|\
 					 EXT2_FEATURE_COMPAT_RESIZE_INODE|\
 					 EXT2_FEATURE_COMPAT_DIR_INDEX|\
+					 EXT2_FEATURE_COMPAT_LAZY_BG|\
 					 EXT2_FEATURE_COMPAT_EXT_ATTR)
 
 /* This #ifdef is temporary until compression is fully supported */
diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
index 222568e..8d528b4 100644
--- a/lib/ext2fs/inode.c
+++ b/lib/ext2fs/inode.c
@@ -164,6 +164,9 @@
 	}
 	if (scan->fs->badblocks && scan->fs->badblocks->num)
 		scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
+	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
+				    EXT2_FEATURE_COMPAT_LAZY_BG))
+		scan->scan_flags |= EXT2_SF_DO_LAZY;
 	*ret_scan = scan;
 	return 0;
 }
@@ -407,9 +410,13 @@
 			return retval;
 	}
 	/*
-	 * This is done outside the above if statement so that the
-	 * check can be done for block group #0.
+	 * These checks are done outside the above if statement so 
+	 * they can be done for block group #0.
 	 */
+	if ((scan->scan_flags & EXT2_SF_DO_LAZY) &&
+	    (scan->fs->group_desc[scan->current_group].bg_flags &
+	     EXT2_BG_INODE_UNINIT))
+		goto force_new_group;
 	if (scan->current_block == 0) {
 		if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
 			goto force_new_group;
diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c
index 7ab0a4d..cb470b8 100644
--- a/lib/ext2fs/rw_bitmaps.c
+++ b/lib/ext2fs/rw_bitmaps.c
@@ -60,12 +60,16 @@
 	errcode_t	retval;
 	char 		*block_bitmap, *inode_bitmap;
 	char 		*block_buf, *inode_buf;
+	int		lazy_flag = 0;
 	blk_t		blk;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
 	if (!(fs->flags & EXT2_FLAG_RW))
 		return EXT2_ET_RO_FILSYS;
+	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
+				    EXT2_FEATURE_COMPAT_LAZY_BG))
+		lazy_flag = 1;
 	inode_nbytes = block_nbytes = 0;
 	block_bitmap = inode_bitmap = 0;
 	if (do_block) {
@@ -89,6 +93,10 @@
 	for (i = 0; i < fs->group_desc_count; i++) {
 		if (!block_bitmap || !do_block)
 			goto skip_block_bitmap;
+
+		if (lazy_flag && fs->group_desc[i].bg_flags &
+		    EXT2_BG_BLOCK_UNINIT) 
+			goto skip_this_block_bitmap;
  
 		memcpy(block_buf, block_bitmap, block_nbytes);
 		if (i == fs->group_desc_count - 1) {
@@ -113,12 +121,17 @@
 			if (retval)
 				return EXT2_ET_BLOCK_BITMAP_WRITE;
 		}
+	skip_this_block_bitmap:
 		block_bitmap += block_nbytes;
 	skip_block_bitmap:
 
 		if (!inode_bitmap || !do_inode)
 			continue;
 
+		if (lazy_flag && fs->group_desc[i].bg_flags &
+		    EXT2_BG_INODE_UNINIT) 
+			goto skip_this_inode_bitmap;
+ 
 		memcpy(inode_buf, inode_bitmap, inode_nbytes);
 		blk = fs->group_desc[i].bg_inode_bitmap;
 		if (blk) {
@@ -133,6 +146,7 @@
 			if (retval)
 				return EXT2_ET_INODE_BITMAP_WRITE;
 		}
+	skip_this_inode_bitmap:
 		inode_bitmap += inode_nbytes;
 
 	}
@@ -155,12 +169,17 @@
 	errcode_t retval;
 	int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
 	int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8;
+	int lazy_flag = 0;
 	blk_t	blk;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
 	fs->write_bitmaps = ext2fs_write_bitmaps;
 
+	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
+				    EXT2_FEATURE_COMPAT_LAZY_BG))
+		lazy_flag = 1;
+
 	retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
 	if (retval)
 		return retval;
@@ -209,6 +228,9 @@
 	for (i = 0; i < fs->group_desc_count; i++) {
 		if (block_bitmap) {
 			blk = fs->group_desc[i].bg_block_bitmap;
+			if (lazy_flag && fs->group_desc[i].bg_flags &
+			    EXT2_BG_BLOCK_UNINIT)
+				blk = 0;
 			if (blk) {
 				retval = io_channel_read_blk(fs->io, blk,
 					     -block_nbytes, block_bitmap);
@@ -222,11 +244,14 @@
 					ext2fs_swap_bitmap(fs, block_bitmap, block_nbytes);
 #endif
 			} else
-				memset(block_bitmap, 0, block_nbytes);
+				memset(block_bitmap, 0xff, block_nbytes);
 			block_bitmap += block_nbytes;
 		}
 		if (inode_bitmap) {
 			blk = fs->group_desc[i].bg_inode_bitmap;
+			if (lazy_flag && fs->group_desc[i].bg_flags &
+			    EXT2_BG_INODE_UNINIT)
+				blk = 0;
 			if (blk) {
 				retval = io_channel_read_blk(fs->io, blk,
 					     -inode_nbytes, inode_bitmap);
@@ -240,7 +265,7 @@
 					ext2fs_swap_bitmap(fs, inode_bitmap, inode_nbytes);
 #endif
 			} else
-				memset(inode_bitmap, 0, inode_nbytes);
+				memset(inode_bitmap, 0xff, inode_nbytes);
 			inode_bitmap += inode_nbytes;
 		}
 	}
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index 9081701..a4c6698 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -78,6 +78,7 @@
 	gdp->bg_free_blocks_count = ext2fs_swab16(gdp->bg_free_blocks_count);
 	gdp->bg_free_inodes_count = ext2fs_swab16(gdp->bg_free_inodes_count);
 	gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count);
+	gdp->bg_flags = ext2fs_swab16(gdp->bg_flags);
 }
 
 void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
diff --git a/misc/ChangeLog b/misc/ChangeLog
index 605928a..0cb0389 100644
--- a/misc/ChangeLog
+++ b/misc/ChangeLog
@@ -1,3 +1,14 @@
+2006-05-08  Theodore Tso  <tytso@mit.edu>
+
+	* mke2fs.c (write_inode_tables, setup_lazy_bg, main): Add support
+		for the COMPAT_LAZY_BG feature.  This is currently
+		intended for debugging purposes only, as a way to create
+		very large filesystems stored on sparse files for testing
+		purposes.
+
+	* dumpe2fs.c (list_desc): Print out the block group flags if they
+		are set.
+
 2006-04-22  Theodore Ts'o  <tytso@mit.edu>
 
 	* filefrag.c: Make filefrag 32-bit clean, so that it works on 
diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
index 2e42cb3..58c9869 100644
--- a/misc/dumpe2fs.c
+++ b/misc/dumpe2fs.c
@@ -96,6 +96,36 @@
 		}
 }
 
+static void print_bg_opt(int bg_flags, int mask,
+			  const char *str, int *first)
+{
+	if (bg_flags & mask) {
+		if (*first) {
+			fputs(" [", stdout);
+			*first = 0;
+		} else
+			fputs(", ", stdout);
+		fputs(str, stdout);
+	}
+}
+static void print_bg_opts(ext2_filsys fs, dgrp_t i)
+{
+	int first = 1, bg_flags;
+
+	if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_LAZY_BG)
+		bg_flags = fs->group_desc[i].bg_flags;
+	else
+		bg_flags = 0;
+
+	print_bg_opt(bg_flags, EXT2_BG_INODE_UNINIT, "Inode not init",
+ 		     &first);
+	print_bg_opt(bg_flags, EXT2_BG_BLOCK_UNINIT, "Block not init",
+ 		     &first);
+	if (!first)
+		fputc(']', stdout);
+	fputc('\n', stdout);
+}
+
 static void list_desc (ext2_filsys fs)
 {
 	unsigned long i;
@@ -130,7 +160,8 @@
 			next_blk = fs->super->s_blocks_count;
 		printf (_("Group %lu: (Blocks "), i);
 		print_range(group_blk, next_blk - 1);
-		fputs(")\n", stdout);
+		fputs(")", stdout);
+		print_bg_opts(fs, i);
 		has_super = ((i==0) || super_blk);
 		if (has_super) {
 			printf (_("  %s superblock at "),
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 6fd5540..9f23ea5 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -403,6 +403,7 @@
 	dgrp_t		i;
 	int		num;
 	struct progress_struct progress;
+	int		lazy_flag = 0;
 
 	if (quiet)
 		memset(&progress, 0, sizeof(progress));
@@ -410,18 +411,25 @@
 		progress_init(&progress, _("Writing inode tables: "),
 			      fs->group_desc_count);
 
+	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
+				    EXT2_FEATURE_COMPAT_LAZY_BG))
+		lazy_flag = 1;
+
 	for (i = 0; i < fs->group_desc_count; i++) {
 		progress_update(&progress, i);
 		
 		blk = fs->group_desc[i].bg_inode_table;
 		num = fs->inode_blocks_per_group;
 
-		retval = zero_blocks(fs, blk, num, 0, &blk, &num);
-		if (retval) {
-			fprintf(stderr, _("\nCould not write %d blocks "
-				"in inode table starting at %u: %s\n"),
-				num, blk, error_message(retval));
-			exit(1);
+		if (!(lazy_flag &&
+		      (fs->group_desc[i].bg_flags & EXT2_BG_INODE_UNINIT))) {
+			retval = zero_blocks(fs, blk, num, 0, &blk, &num);
+			if (retval) {
+				fprintf(stderr, _("\nCould not write %d "
+				"blocks in inode table starting at %u: %s\n"),
+					num, blk, error_message(retval));
+				exit(1);
+			}
 		}
 		if (sync_kludge) {
 			if (sync_kludge == 1)
@@ -434,6 +442,37 @@
 	progress_close(&progress);
 }
 
+static void setup_lazy_bg(ext2_filsys fs)
+{
+	dgrp_t i;
+	int blks;
+	struct ext2_super_block *sb = fs->super;
+	struct ext2_group_desc *bg = fs->group_desc;
+
+	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
+				    EXT2_FEATURE_COMPAT_LAZY_BG)) {
+		for (i = 0; i < fs->group_desc_count; i++, bg++) {
+			if ((i == 0) ||
+			    (i == fs->group_desc_count-1))
+				continue;
+			if (bg->bg_free_inodes_count ==
+			    sb->s_inodes_per_group) {
+				bg->bg_free_inodes_count = 0;
+				bg->bg_flags |= EXT2_BG_INODE_UNINIT;
+				sb->s_free_inodes_count -= 
+					sb->s_inodes_per_group;
+			}
+			blks = ext2fs_super_and_bgd_loc(fs, i, 0, 0, 0, 0);
+			if (bg->bg_free_blocks_count == blks) {
+				bg->bg_free_blocks_count = 0;
+				bg->bg_flags |= EXT2_BG_BLOCK_UNINIT;
+				sb->s_free_blocks_count -= blks;
+			}
+		}
+	}
+}
+
+
 static void create_root_dir(ext2_filsys fs)
 {
 	errcode_t	retval;
@@ -814,7 +853,8 @@
 static __u32 ok_features[3] = {
 	EXT3_FEATURE_COMPAT_HAS_JOURNAL |
 		EXT2_FEATURE_COMPAT_RESIZE_INODE |
-		EXT2_FEATURE_COMPAT_DIR_INDEX,	/* Compat */
+		EXT2_FEATURE_COMPAT_DIR_INDEX |
+		EXT2_FEATURE_COMPAT_LAZY_BG,	/* Compat */
 	EXT2_FEATURE_INCOMPAT_FILETYPE|		/* Incompat */
 		EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
 		EXT2_FEATURE_INCOMPAT_META_BG,
@@ -1557,6 +1597,7 @@
 				_("while zeroing block %u at end of filesystem"),
 				ret_blk);
 		}
+		setup_lazy_bg(fs);
 		write_inode_tables(fs);
 		create_root_dir(fs);
 		create_lost_and_found(fs);