public inbox for linux-ext4@vger.kernel.org
 help / color / mirror / Atom feed
* ext2/3 create large filesystem takes too much time; solutions
@ 2006-09-12 11:07 Pavel Mironchik
  2006-09-15 21:20 ` Theodore Tso
  0 siblings, 1 reply; 6+ messages in thread
From: Pavel Mironchik @ 2006-09-12 11:07 UTC (permalink / raw)
  To: linux-ext4

[-- Attachment #1: Type: text/plain, Size: 1540 bytes --]

Hi,

Ext2/3 does erase of inode tables, when do creation of new systems.
This is very very long operation when the target file system volume is more than
2Tb. Other filesystem are not affected by such huge delay on creation of
filesystem. My concern was to improve design of ext3 to decrease time
consuption of creation large ext3 volumes on storage servers.
In general to solve problem, we should defer job of cleaning nodes to
kernel. In e2fsprogs there is LAZY_BG options but it  just avoids doing
erase of inodes only.

I see several solutions for that problem:
1) Add special bitmaps into fs header (inode groups descriptors?).
By looking at those bitmaps kernel could determine if inode is not cleaned, and
that inode will be propertly initialized.
2) Add special identifiers into inodes. If super block id != inode id
-> inode is dirty
and should be cleaned in kernel, where super block id is generated on
creation stage.

I choosed second (much easier - just few lines of code)
and implemented patch for e2fsprogs, kernel ext3. It is just proof of a concept.
With the help of this patch I could create  terrabytes volumes fast.
Of cource this patch will broke compatibility for existing filesystem.
More correctly is to choose first way and do not broke compatibility.

Writing this mail, I just want check if there is any interest for this problem
from community.
I would like to see that future ext4 filesystem will be created fast.
and I would be appreciate for  thoughts, remarks.
---------------------------
Pavel S. Mironchik

[-- Attachment #2: ext3-kernel.patch --]
[-- Type: text/x-patch, Size: 3426 bytes --]

diff -ruN upload/fs/ext3/inode.c l1/linux-2.6.17/fs/ext3/inode.c
--- upload/fs/ext3/inode.c	2006-08-24 00:16:33 +0300
+++ linux-2.6.17/fs/ext3/inode.c	2006-09-06 16:22:17 +0300
@@ -2576,6 +2576,17 @@
 		inode->i_flags |= S_DIRSYNC;
 }
 
+void ext3_check_uuid_inode(struct ext3_inode *rinode, struct inode *vinode) 
+{
+  struct ext3_sb_info* sbi = (struct ext3_sb_info*)(vinode->i_sb)->s_fs_info;
+  int length = sizeof(u8)*16;
+
+  if(memcmp(rinode->i_uuid,sbi->s_uuid, length)) {
+    memset(rinode,0,sizeof(struct ext3_inode));
+    memcpy(rinode->i_uuid,sbi->s_uuid, length);
+  }
+}
+
 void ext3_read_inode(struct inode * inode)
 {
 	struct ext3_iloc iloc;
@@ -2594,6 +2605,9 @@
 		goto bad_inode;
 	bh = iloc.bh;
 	raw_inode = ext3_raw_inode(&iloc);
+	
+	ext3_check_uuid_inode(raw_inode,inode);
+
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
 	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
 	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
@@ -2713,6 +2727,8 @@
 	return;
 }
 
+
+
 /*
  * Post the struct inode info into an on-disk inode location in the
  * buffer-cache.  This gobbles the caller's reference to the
@@ -2725,6 +2741,7 @@
 				struct ext3_iloc *iloc)
 {
 	struct ext3_inode *raw_inode = ext3_raw_inode(iloc);
+	struct ext3_sb_info* sbi = (struct ext3_sb_info*)(inode->i_sb)->s_fs_info;
 	struct ext3_inode_info *ei = EXT3_I(inode);
 	struct buffer_head *bh = iloc->bh;
 	int err = 0, rc, block;
@@ -2773,6 +2790,8 @@
 	raw_inode->i_fsize = ei->i_frag_size;
 #endif
 	raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);
+	memcpy(raw_inode->i_uuid, sbi->s_uuid, sizeof(u8)*16);
+
 	if (!S_ISREG(inode->i_mode)) {
 		raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
 	} else {
@@ -2832,7 +2851,7 @@
 }
 
 /*
- * ext3_write_inode()
+ * ext3_write_inode
  *
  * We are called from a few places:
  *
diff -ruN upload/fs/ext3/super.c l1/linux-2.6.17/fs/ext3/super.c
--- upload/fs/ext3/super.c	2006-08-24 00:16:33 +0300
+++ linux-2.6.17/fs/ext3/super.c	2006-09-06 16:03:25 +0300
@@ -1464,6 +1425,8 @@
 	sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
 	sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
 
+	memcpy(sbi->s_uuid,es->s_uuid, sizeof(u8)*16);
+
 	set_opt(sbi->s_mount_opt, RESERVATION);
 
 	if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
diff -ruN upload/include/linux/ext3_fs.h l1/linux-2.6.17/include/linux/ext3_fs.h
--- upload/include/linux/ext3_fs.h	2006-08-24 00:16:33 +0300
+++ l1/linux-2.6.17/include/linux/ext3_fs.h	2006-09-06 16:20:53 +0300
@@ -284,6 +284,7 @@
 	__le32	i_file_acl;	/* File ACL */
 	__le32	i_dir_acl;	/* Directory ACL */
 	__le32	i_faddr;	/* Fragment address */
+        __le16   i_uuid[8];
 	union {
 		struct {
 			__u8	l_i_frag;	/* Fragment number */
@@ -531,7 +532,7 @@
 #define EXT3_CURRENT_REV	EXT3_GOOD_OLD_REV
 #define EXT3_MAX_SUPP_REV	EXT3_DYNAMIC_REV
 
-#define EXT3_GOOD_OLD_INODE_SIZE 128
+#define EXT3_GOOD_OLD_INODE_SIZE (128+(8*16))
 
 /*
  * Feature set definitions
diff -ruN upload/include/linux/ext3_fs_sb.h l1/linux-2.6.17/include/linux/ext3_fs_sb.h
--- upload/include/linux/ext3_fs_sb.h	2006-08-24 00:16:33 +0300
+++ l1/linux-2.6.17/include/linux/ext3_fs_sb.h	2006-09-06 15:59:35 +0300
@@ -78,6 +78,7 @@
 	char *s_qf_names[MAXQUOTAS];		/* Names of quota files with journalled quota */
 	int s_jquota_fmt;			/* Format of quota to use */
 #endif
+        u8 s_uuid[16]; 
 };
 
 #endif	/* _LINUX_EXT3_FS_SB */

[-- Attachment #3: mkfs_and_fsck.patch --]
[-- Type: text/x-patch, Size: 4632 bytes --]

diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 1cfbc35..7008826 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -296,7 +296,8 @@ struct ext2_inode {
 	__u32	i_generation;	/* File version (for NFS) */
 	__u32	i_file_acl;	/* File ACL */
 	__u32	i_dir_acl;	/* Directory ACL */
-	__u32	i_faddr;	/* Fragment address */
+	__u32	i_faddr;	/* Fragment address */        
+        __u8    s_uuid[16];
 	union {
 		struct {
 			__u8	l_i_frag;	/* Fragment number */
@@ -354,6 +355,7 @@ struct ext2_inode_large {
 	__u32	i_file_acl;	/* File ACL */
 	__u32	i_dir_acl;	/* Directory ACL */
 	__u32	i_faddr;	/* Fragment address */
+        __u8    s_uuid[16];
 	union {
 		struct {
 			__u8	l_i_frag;	/* Fragment number */
@@ -547,7 +549,7 @@ #define EXT2_DYNAMIC_REV	1	/* V2 format 
 #define EXT2_CURRENT_REV	EXT2_GOOD_OLD_REV
 #define EXT2_MAX_SUPP_REV	EXT2_DYNAMIC_REV
 
-#define EXT2_GOOD_OLD_INODE_SIZE 128
+#define EXT2_GOOD_OLD_INODE_SIZE (128+(16*8))
 
 /*
  * Journal inode backup types
diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
index 8d528b4..af3b87f 100644
--- a/lib/ext2fs/inode.c
+++ b/lib/ext2fs/inode.c
@@ -381,6 +381,8 @@ static inline int is_empty_scan(ext2_ino
 }
 #endif
 
+errcode_t ext2fs_check_inode_uuid(ext2_filsys fs, struct ext2_inode* inode);
+
 errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
 				     struct ext2_inode *inode, int bufsize)
 {
@@ -452,7 +454,7 @@ #endif
 		       scan->inode_size - extra_bytes);
 		scan->ptr += scan->inode_size - extra_bytes;
 		scan->bytes_left -= scan->inode_size - extra_bytes;
-
+		/* CHECK */
 #ifdef EXT2FS_ENABLE_SWAPFS
 		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
 		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
@@ -463,10 +465,12 @@ #ifdef EXT2FS_ENABLE_SWAPFS
 		else
 #endif
 			*inode = *((struct ext2_inode *) scan->temp_buffer);
+		ext2fs_check_inode_uuid(scan->fs,inode);
 		if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
 			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
 		scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
 	} else {
+	  /* CHECK */
 #ifdef EXT2FS_ENABLE_SWAPFS
 		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
 		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
@@ -477,6 +481,7 @@ #ifdef EXT2FS_ENABLE_SWAPFS
 		else
 #endif
 			memcpy(inode, scan->ptr, bufsize);
+		ext2fs_check_inode_uuid(scan->fs,inode);
 		scan->ptr += scan->inode_size;
 		scan->bytes_left -= scan->inode_size;
 		if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
@@ -496,6 +501,17 @@ errcode_t ext2fs_get_next_inode(ext2_ino
 						sizeof(struct ext2_inode));
 }
 
+errcode_t ext2fs_update_inode_uuid(ext2_filsys fs, struct ext2_inode* inode);
+
+errcode_t ext2fs_check_inode_uuid(ext2_filsys fs, struct ext2_inode* inode)  
+{
+  if(memcmp(inode->s_uuid,fs->super->s_uuid,sizeof(__u8)*16)) {
+    memset(inode, 0, sizeof(struct ext2_inode));
+    ext2fs_update_inode_uuid(fs, inode);
+  }
+  return 0;
+}
+
 /*
  * Functions to read and write a single inode.
  */
@@ -589,6 +605,9 @@ #ifdef EXT2FS_ENABLE_SWAPFS
 				       0, length);
 #endif
 
+
+	ext2fs_check_inode_uuid(fs,inode);
+	
 	/* Update the inode cache */
 	fs->icache->cache_last = (fs->icache->cache_last + 1) %
 		fs->icache->cache_size;
@@ -605,6 +624,18 @@ errcode_t ext2fs_read_inode(ext2_filsys 
 					sizeof(struct ext2_inode));
 }
 
+
+/* 
+   NODE CONNECTIVITY!!!
+ */
+errcode_t ext2fs_update_inode_uuid(ext2_filsys fs, struct ext2_inode* inode) 
+{
+  
+         memcpy(inode->s_uuid,fs->super->s_uuid, sizeof(__u8) * 16);
+         return 0;
+}
+
+
 errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
 				  struct ext2_inode * inode, int bufsize)
 {
@@ -615,6 +646,8 @@ errcode_t ext2fs_write_inode_full(ext2_f
 	int clen, i, length;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+	
+	ext2fs_update_inode_uuid(fs,inode);
 
 	/* Check to see if user provided an override function */
 	if (fs->write_inode) {
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index d008e15..e786938 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -398,7 +398,7 @@ static errcode_t zero_blocks(ext2_filsys
 
 static void write_inode_tables(ext2_filsys fs)
 {
-	errcode_t	retval;
+	errcode_t	retval = 0;
 	blk_t		blk;
 	dgrp_t		i;
 	int		num;
@@ -423,7 +423,7 @@ static void write_inode_tables(ext2_fils
 
 		if (!(lazy_flag &&
 		      (fs->group_desc[i].bg_flags & EXT2_BG_INODE_UNINIT))) {
-			retval = zero_blocks(fs, blk, num, 0, &blk, &num);
+		//	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"),

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: ext2/3 create large filesystem takes too much time; solutions
  2006-09-12 11:07 ext2/3 create large filesystem takes too much time; solutions Pavel Mironchik
@ 2006-09-15 21:20 ` Theodore Tso
  2006-09-16 14:56   ` Pavel Mironchik
  0 siblings, 1 reply; 6+ messages in thread
From: Theodore Tso @ 2006-09-15 21:20 UTC (permalink / raw)
  To: Pavel Mironchik; +Cc: linux-ext4

On Tue, Sep 12, 2006 at 02:07:34PM +0300, Pavel Mironchik wrote:
> 
> Ext2/3 does erase of inode tables, when do creation of new systems.
> This is very very long operation when the target file system volume is more 
> than
> 2Tb. Other filesystem are not affected by such huge delay on creation of
> filesystem. My concern was to improve design of ext3 to decrease time
> consuption of creation large ext3 volumes on storage servers.
> In general to solve problem, we should defer job of cleaning nodes to
> kernel. In e2fsprogs there is LAZY_BG options but it  just avoids doing
> erase of inodes only.

Hi Pavel,

	Apologies that no one responded right away; I think a lot of
people have been incredibly busy.  I've been doing a huge amount of
travel myself personally, and so my e-mail latency has been larger
than normal.

	The problem of long mke2fs problems is one that we've
considered, and we do want to do something with it, but it's not been
as high priority as some of the other problems on our hit list.
Certainly, given that inode space is very precious, I'm not convinced
that breaking backwards compatibility and burning an extra 16 bytes
per inode is worth the net gain --- although there are other solutions
that don't have that particular cost.  Yes, they take more lines of
code to support, but given the hopefully large number of people that
will be using ext4, I'd must rather spend an extra amount of
development time getting it right, than doing something fast and dirty
which then everyone pays for, over and over, again and again and again
across millions and millions of machines!


> I see several solutions for that problem:
> 1) Add special bitmaps into fs header (inode groups descriptors?).
> By looking at those bitmaps kernel could determine if inode is not cleaned, 
> and that inode will be propertly initialized.

Actually, you don't need a bitmap; a much simpler solution is to have
an integer field in the block group descriptors which indicates the
number of inods that have been initialized in that block group.  The
problem though is that what if the block group descriptors (or the
bitmaps) get corrupted?  So what we also want to do is to add support
for checksums in the individual inodes and in the block group
descriptors themselves, as a double-check.   

These are useful features in and of themselves, and there are some
sample implementations of them (for example, in the Iron ext2 paper).
So my thinking is that we should get that work into ext4, and then
it's not hard to add the support for fields in the block group
descriptors that would allow for fast mke2fs support.

Regards,

						- Ted

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: ext2/3 create large filesystem takes too much time; solutions
  2006-09-15 21:20 ` Theodore Tso
@ 2006-09-16 14:56   ` Pavel Mironchik
  2006-09-16 20:06     ` Theodore Tso
  0 siblings, 1 reply; 6+ messages in thread
From: Pavel Mironchik @ 2006-09-16 14:56 UTC (permalink / raw)
  To: Theodore Tso; +Cc: linux-ext4

Hi Ted,

Thanks for the responce...
I agree with you and I would prefer to send something more
serious on that list than those previous patches - I like your
idea with counters. Btw I assume crc is more preferable than
just control sum for block group descriptors....

Pavel
p.mironchik@velesys.com
tibor@altlinux.org

On 9/16/06, Theodore Tso <tytso@mit.edu> wrote:
> On Tue, Sep 12, 2006 at 02:07:34PM +0300, Pavel Mironchik wrote:
> >
> > Ext2/3 does erase of inode tables, when do creation of new systems.
> > This is very very long operation when the target file system volume is more
> > than
> > 2Tb. Other filesystem are not affected by such huge delay on creation of
> > filesystem. My concern was to improve design of ext3 to decrease time
> > consuption of creation large ext3 volumes on storage servers.
> > In general to solve problem, we should defer job of cleaning nodes to
> > kernel. In e2fsprogs there is LAZY_BG options but it  just avoids doing
> > erase of inodes only.
>
> Hi Pavel,
>
>         Apologies that no one responded right away; I think a lot of
> people have been incredibly busy.  I've been doing a huge amount of
> travel myself personally, and so my e-mail latency has been larger
> than normal.
>
>         The problem of long mke2fs problems is one that we've
> considered, and we do want to do something with it, but it's not been
> as high priority as some of the other problems on our hit list.
> Certainly, given that inode space is very precious, I'm not convinced
> that breaking backwards compatibility and burning an extra 16 bytes
> per inode is worth the net gain --- although there are other solutions
> that don't have that particular cost.  Yes, they take more lines of
> code to support, but given the hopefully large number of people that
> will be using ext4, I'd must rather spend an extra amount of
> development time getting it right, than doing something fast and dirty
> which then everyone pays for, over and over, again and again and again
> across millions and millions of machines!
>
>
> > I see several solutions for that problem:
> > 1) Add special bitmaps into fs header (inode groups descriptors?).
> > By looking at those bitmaps kernel could determine if inode is not cleaned,
> > and that inode will be propertly initialized.
>
> Actually, you don't need a bitmap; a much simpler solution is to have
> an integer field in the block group descriptors which indicates the
> number of inods that have been initialized in that block group.  The
> problem though is that what if the block group descriptors (or the
> bitmaps) get corrupted?  So what we also want to do is to add support
> for checksums in the individual inodes and in the block group
> descriptors themselves, as a double-check.
>
> These are useful features in and of themselves, and there are some
> sample implementations of them (for example, in the Iron ext2 paper).
> So my thinking is that we should get that work into ext4, and then
> it's not hard to add the support for fields in the block group
> descriptors that would allow for fast mke2fs support.
>
> Regards,
>
>                                                 - Ted

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: ext2/3 create large filesystem takes too much time; solutions
  2006-09-16 14:56   ` Pavel Mironchik
@ 2006-09-16 20:06     ` Theodore Tso
  2006-09-17  7:57       ` Andreas Dilger
  0 siblings, 1 reply; 6+ messages in thread
From: Theodore Tso @ 2006-09-16 20:06 UTC (permalink / raw)
  To: Pavel Mironchik; +Cc: linux-ext4

On Sat, Sep 16, 2006 at 05:56:02PM +0300, Pavel Mironchik wrote:
> Hi Ted,
> 
> Thanks for the responce...
> I agree with you and I would prefer to send something more
> serious on that list than those previous patches - I like your
> idea with counters. Btw I assume crc is more preferable than
> just control sum for block group descriptors....

Yes, when I said checksum I meant a cyclic redundancy checksum, and
not an additive checksum...  (and one of the things we can do is to
build in the superblock UUID into the CRC, so that if the filesystem
gets recreated we can distinguish an old inode from a new one).

						- Ted

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: ext2/3 create large filesystem takes too much time; solutions
  2006-09-16 20:06     ` Theodore Tso
@ 2006-09-17  7:57       ` Andreas Dilger
  2006-09-18 19:51         ` Andreas Dilger
  0 siblings, 1 reply; 6+ messages in thread
From: Andreas Dilger @ 2006-09-17  7:57 UTC (permalink / raw)
  To: Theodore Tso; +Cc: Pavel Mironchik, linux-ext4

[-- Attachment #1: Type: text/plain, Size: 2110 bytes --]

On Sep 16, 2006  16:06 -0400, Theodore Tso wrote:
> On Sat, Sep 16, 2006 at 05:56:02PM +0300, Pavel Mironchik wrote:
> > I agree with you and I would prefer to send something more
> > serious on that list than those previous patches - I like your
> > idea with counters. Btw I assume crc is more preferable than
> > just control sum for block group descriptors....
> 
> Yes, when I said checksum I meant a cyclic redundancy checksum, and
> not an additive checksum...  (and one of the things we can do is to
> build in the superblock UUID into the CRC, so that if the filesystem
> gets recreated we can distinguish an old inode from a new one).

Just to avoid duplication of effort, I'm attaching the current
work-in-progress patches for the uninitialized groups (kernel + e2fsprogs).
They are really at the "barely compile" stage (if that), but at least
people can look at them and start improving them instead of starting from
scratch.  The patches are based on work done by Anshu Goel
<anshu@linsyssoft.com>, but have been reworked a fair amount since they
were given to me (i.e. bugs added are mine).  I've been sitting on them
for too long and they should see the light of day instead of continuing
to stagnate.

I also just incorporated Ted's suggestion to include the filesystem UUID
into the checksum.  I previously had added in the group number, so that
if the block is written out to the wrong location it wouldn't verify
correctly.

Things that need to be done:
- the kernel block/inode allocation needs to be reworked:
  - initialize a whole block worth of inodes at one time instead
    of single inodes.
  - I don't think we need to zero out the unused inodes - the kernel
    should already be doing this if the inode block is unused
  - find a happy medium between using existing groups (inodes/blocks)
    and initializing new ones
- we likely need to verify the checksum in more places in e2fsck before
  trusting the UNINIT flags

I won't be able to work more on this for a while, so have at it :-).

Cheers, Andreas
--
Andreas Dilger
Principal Software Engineer
Cluster File Systems, Inc.


[-- Attachment #2: ext3-uninit_groups-2.6.12.patch --]
[-- Type: text/plain, Size: 19918 bytes --]

Index: linux-stage/fs/ext3/mballoc.c
===================================================================
--- linux-stage.orig/fs/ext3/mballoc.c	2006-09-17 00:59:44.000000000 -0600
+++ linux-stage/fs/ext3/mballoc.c	2006-09-17 00:59:44.000000000 -0600
@@ -198,7 +198,8 @@
 void ext3_mb_release_blocks(struct super_block *, int);
 void ext3_mb_poll_new_transaction(struct super_block *, handle_t *);
 void ext3_mb_free_committed_blocks(struct super_block *);
-
+unsigned long free_blks_after_init(struct super_block *,
+						struct ext3_group_desc *, int);
 #if BITS_PER_LONG == 64
 #define mb_correct_addr_and_bit(bit,addr)		\
 {							\
@@ -527,7 +528,12 @@
 			unlock_buffer(bh[i]);
 			continue;
 		}
-
+		if (desc->bg_flags & EXT3_BG_BLOCK_UNINIT) {
+			init_block_bitmap(sb, bh[i], desc, first_group + i);
+			set_buffer_uptodate(bh[i]);
+			unlock_buffer(bh[i]);
+			continue;
+		}
 		get_bh(bh[i]);
 		bh[i]->b_end_io = end_buffer_read_sync;
 		submit_bh(READ, bh[i]);
@@ -1525,9 +1531,16 @@
 	mb_set_bits(bitmap_bh->b_data, ac.ac_b_ex.fe_start, ac.ac_b_ex.fe_len);
 
 	spin_lock(sb_bgl_lock(sbi, ac.ac_b_ex.fe_group));
+	if (gdp->bg_flags & EXT3_BG_BLOCK_UNINIT) {
+		gdp->bg_flags &= ~EXT3_BG_BLOCK_UNINIT;
+		gdp->bg_free_blocks_count =
+			cpu_to_le16(free_blks_after_init(sb, gdp,
+				ac.ac_b_ex.fe_group));
+	}
 	gdp->bg_free_blocks_count =
 			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)
 					- ac.ac_b_ex.fe_len);
+	gdp->bg_checksum = ext3_group_desc_csum(es, gdp, ac.ac_b_ex.fe_group);
 	spin_unlock(sb_bgl_lock(sbi, ac.ac_b_ex.fe_group));
 	percpu_counter_mod(&sbi->s_freeblocks_counter, - ac.ac_b_ex.fe_len);
 
@@ -2377,6 +2390,7 @@
 	spin_lock(sb_bgl_lock(sbi, block_group));
 	gdp->bg_free_blocks_count =
 		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + count);
+	gdp->bg_checksum = ext3_group_desc_csum(es, gdp, block_group);
 	spin_unlock(sb_bgl_lock(sbi, block_group));
 	percpu_counter_mod(&sbi->s_freeblocks_counter, count);
 
Index: linux-stage/fs/ext3/ialloc.c
===================================================================
--- linux-stage.orig/fs/ext3/ialloc.c	2006-09-17 00:59:44.000000000 -0600
+++ linux-stage/fs/ext3/ialloc.c	2006-09-17 00:59:44.000000000 -0600
@@ -23,7 +23,6 @@
 #include <linux/buffer_head.h>
 #include <linux/random.h>
 #include <linux/bitops.h>
-
 #include <asm/byteorder.h>
 
 #include "xattr.h"
@@ -59,8 +58,14 @@
 	desc = ext3_get_group_desc(sb, block_group, NULL);
 	if (!desc)
 		goto error_out;
-
-	bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
+	if (desc->bg_flags & EXT3_BG_INODE_UNINIT) {
+		bh = sb_getblk(sb, le32_to_cpu(desc->bg_inode_bitmap));
+		if (!buffer_uptodate(bh)) {
+			memset(bh->b_data,0,bh->b_size);
+			set_buffer_uptodate(bh);
+		}
+	} else
+		bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
 	if (!bh)
 		ext3_error(sb, "read_inode_bitmap",
 			    "Cannot read inode bitmap - "
@@ -169,6 +174,8 @@
 			if (is_directory)
 				gdp->bg_used_dirs_count = cpu_to_le16(
 				  le16_to_cpu(gdp->bg_used_dirs_count) - 1);
+			gdp->bg_checksum = ext3_group_desc_csum(es, gdp,
+								block_group);
 			spin_unlock(sb_bgl_lock(sbi, block_group));
 			percpu_counter_inc(&sbi->s_freeinodes_counter);
 			if (is_directory)
@@ -202,7 +209,7 @@
 static int find_group_dir(struct super_block *sb, struct inode *parent)
 {
 	int ngroups = EXT3_SB(sb)->s_groups_count;
-	int freei, avefreei;
+	int freei, avefreei, freeb = 0, best_freeb = 0;
 	struct ext3_group_desc *desc, *best_desc = NULL;
 	struct buffer_head *bh;
 	int group, best_group = -1;
@@ -212,15 +219,17 @@
 
 	for (group = 0; group < ngroups; group++) {
 		desc = ext3_get_group_desc (sb, group, &bh);
-		if (!desc || !desc->bg_free_inodes_count)
+		freei = EXT3_FREE_INODES_COUNT(desc);
+		freeb = EXT3_FREE_BLOCKS_COUNT(desc);
+		if (!desc || !freei)
 			continue;
-		if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei)
+		if (le16_to_cpu(freei) < avefreei)
 			continue;
-		if (!best_desc || 
-		    (le16_to_cpu(desc->bg_free_blocks_count) >
-		     le16_to_cpu(best_desc->bg_free_blocks_count))) {
+		if (!best_desc ||
+		    (le16_to_cpu(freeb) > le16_to_cpu(best_freeb))) {
 			best_group = group;
-			best_desc = desc;
+			best_desc  = desc;
+			best_freeb = freeb;
 		}
 	}
 	return best_group;
@@ -284,14 +293,16 @@
 		parent_group = (unsigned)group % ngroups;
 		for (i = 0; i < ngroups; i++) {
 			group = (parent_group + i) % ngroups;
-			desc = ext3_get_group_desc (sb, group, &bh);
-			if (!desc || !desc->bg_free_inodes_count)
+			desc = ext3_get_group_desc(sb, group, &bh);
+			freei = EXT3_FREE_INODES_COUNT(desc);
+			if (!desc || !freei)
 				continue;
 			if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir)
 				continue;
-			if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei)
+			if (le16_to_cpu(freei) < avefreei)
 				continue;
-			if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb)
+			freeb = EXT3_FREE_BLOCKS_COUNT(desc);
+			if (le16_to_cpu(freeb) < avefreeb)
 				continue;
 			best_group = group;
 			best_ndir = le16_to_cpu(desc->bg_used_dirs_count);
@@ -318,13 +329,15 @@
 	for (i = 0; i < ngroups; i++) {
 		group = (parent_group + i) % ngroups;
 		desc = ext3_get_group_desc (sb, group, &bh);
-		if (!desc || !desc->bg_free_inodes_count)
+		freei = EXT3_FREE_INODES_COUNT(desc);
+		freeb = EXT3_FREE_BLOCKS_COUNT(desc);
+		if (!desc || !freei)
 			continue;
 		if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs)
 			continue;
-		if (le16_to_cpu(desc->bg_free_inodes_count) < min_inodes)
+		if (le16_to_cpu(freei) < min_inodes)
 			continue;
-		if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks)
+		if (le16_to_cpu(freeb) < min_blocks)
 			continue;
 		return group;
 	}
@@ -333,9 +346,10 @@
 	for (i = 0; i < ngroups; i++) {
 		group = (parent_group + i) % ngroups;
 		desc = ext3_get_group_desc (sb, group, &bh);
-		if (!desc || !desc->bg_free_inodes_count)
+		freei = EXT3_FREE_INODES_COUNT(desc);
+		if (!desc || !freei)
 			continue;
-		if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei)
+		if (le16_to_cpu(freei) >= avefreei)
 			return group;
 	}
 
@@ -362,6 +376,7 @@
 	int group, i;
 	int best_group = -1;
 	int avefreeb, freeb, best_group_freeb = 0;
+	int freei;
 
 	/*
 	 * Try to place the inode in its parent directory
@@ -392,11 +407,13 @@
 		if (group >= ngroups)
 			group -= ngroups;
 		desc = ext3_get_group_desc (sb, group, &bh);
-		if (!desc || !desc->bg_free_inodes_count)
+		freei = EXT3_FREE_INODES_COUNT(desc);
+		if (!desc || !freei)
 			continue;
 		if (!S_ISREG(mode))
 			return group;
-		if (le16_to_cpu(desc->bg_free_blocks_count) >= avefreeb)
+		freeb = EXT3_FREE_BLOCKS_COUNT(desc);
+		if (freeb >= avefreeb)
 			return group;
 	}
 
@@ -413,9 +430,10 @@
 		if (++group >= ngroups)
 			group = 0;
 		desc = ext3_get_group_desc (sb, group, &bh);
-		if (!desc || !desc->bg_free_inodes_count)
+		freei = EXT3_FREE_INODES_COUNT(desc);
+		if (!desc || !freei)
 			continue;
-		freeb = le16_to_cpu(desc->bg_free_blocks_count);
+		freeb = EXT3_FREE_BLOCKS_COUNT(desc);
 		if (freeb > best_group_freeb) {
 			best_group_freeb = freeb;
 			best_group = group;
@@ -453,6 +471,7 @@
 	int err = 0;
 	struct inode *ret;
 	int i;
+	int unused_flag = 0;
 
 	/* Cannot create files in a deleted directory */
 	if (!dir || !dir->i_nlink)
@@ -582,18 +601,33 @@
 	err = ext3_journal_get_write_access(handle, bh2);
 	if (err) goto fail;
 	spin_lock(sb_bgl_lock(sbi, group));
-	gdp->bg_free_inodes_count =
-		cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
+	if (gdp->bg_free_inodes_count == 0) {
+		if (gdp->bg_flags & EXT3_BG_INODE_UNINIT) {
+			gdp->bg_itable_unused =
+				cpu_to_le16(le16_to_cpu(es->s_inodes_per_group));
+			gdp->bg_flags &= ~EXT3_BG_INODE_UNINIT;
+		}
+		/* If we didn't allocate from free initialized inodes,
+		 * then we allocated from uninitialized inodes. In which
+		 * case initialize one inode. */
+		gdp->bg_itable_unused =
+			cpu_to_le16(le16_to_cpu(gdp->bg_itable_unused) - 1);
+		unused_flag = 1;
+	} else
+		gdp->bg_free_inodes_count =
+			cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) -1);
 	if (S_ISDIR(mode)) {
 		gdp->bg_used_dirs_count =
 			cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
 	}
+	gdp->bg_checksum = ext3_group_desc_csum(es, gdp, group);
 	spin_unlock(sb_bgl_lock(sbi, group));
 	BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata");
 	err = ext3_journal_dirty_metadata(handle, bh2);
 	if (err) goto fail;
 
-	percpu_counter_dec(&sbi->s_freeinodes_counter);
+	if (!unused_flag)
+		percpu_counter_dec(&sbi->s_freeinodes_counter);
 	if (S_ISDIR(mode))
 		percpu_counter_inc(&sbi->s_dirs_counter);
 	sb->s_dirt = 1;
Index: linux-stage/fs/ext3/balloc.c
===================================================================
--- linux-stage.orig/fs/ext3/balloc.c	2006-09-17 00:59:44.000000000 -0600
+++ linux-stage/fs/ext3/balloc.c	2006-09-17 01:07:33.000000000 -0600
@@ -73,6 +73,88 @@
 	return desc + offset;
 }
 
+unsigned long free_blks_after_init(struct super_block *sb,
+				    struct ext3_group_desc *desc,
+				    int block_group)
+{
+	struct ext3_sb_info *sbi = EXT3_SB(sb);
+	unsigned long blks;
+	unsigned long first_meta_bg;
+	int yes_super;
+
+	first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
+
+	/* Last and first groups are always initialized */
+	blks = le32_to_cpu(EXT3_BLOCKS_PER_GROUP(sb));
+	/* Account for for sb, gdt */
+	yes_super = ext3_bg_has_super(sb, block_group);
+	if (yes_super)
+		blks--;
+
+	if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) ||
+	    block_group < first_meta_bg) {
+		if (yes_super) {
+			blks -= le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
+			blks -= ext3_bg_num_gdb(sb, block_group);
+		}
+	} else { /* For META_BG BLOCK GROUPS*/
+		int group_rel = (block_group - first_meta_bg) %
+				EXT3_DESC_PER_BLOCK(sb);
+		if (group_rel == 0 || group_rel == 1 ||
+		    (group_rel == EXT3_DESC_PER_BLOCK(sb) - 1))
+			blks--;
+	}
+
+	/* Account for bitmaps and inode table */
+	blks -= sbi->s_itb_per_group + 2;
+	return blks;
+}
+
+/* Initializes an uninitialized block bitmap */
+void init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
+		       struct ext3_group_desc *desc, int block_group)
+{
+	unsigned startblk;
+	int bit, bit_max;
+	struct ext3_sb_info *sbi = EXT3_SB(sb);
+	unsigned long first_data_block, first_meta_bg;
+
+	first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
+	first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
+	memset(bh->b_data, 0, bh->b_size);
+
+	/* Set bits for sb, gdt */
+	startblk = block_group * EXT3_BLOCKS_PER_GROUP(sb) +
+		le32_to_cpu(sbi->s_es->s_first_data_block);
+
+	bit = 0;
+	bit_max = ext3_bg_has_super(sb, block_group);
+
+	if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) ||
+	    block_group < first_meta_bg) {
+		if (bit_max) {
+			bit_max += ext3_bg_num_gdb(sb, block_group);
+			bit_max +=le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
+		}
+	} else { /* For META_BG_BLOCK_GROUPS */
+		int group_rel = (block_group - first_meta_bg) %
+				EXT3_DESC_PER_BLOCK(sb);
+		if (group_rel == 0 || group_rel == 1 ||
+		    (group_rel == EXT3_DESC_PER_BLOCK(sb) - 1))
+			bit_max += 1;
+	}
+	for (; bit < bit_max; bit++)
+		ext3_set_bit(bit, bh->b_data);
+
+	/* Set bits for bitmaps and inode table */
+	ext3_set_bit(le32_to_cpu(desc->bg_block_bitmap) - startblk, bh->b_data);
+	ext3_set_bit(le32_to_cpu(desc->bg_inode_bitmap) - startblk, bh->b_data);
+	bit_max = bit + sbi->s_itb_per_group;
+	for (bit = le32_to_cpu(desc->bg_inode_table) - startblk;
+	     bit < bit_max; bit++)
+		ext3_set_bit(bit, bh->b_data);
+}
+
 /*
  * Read the bitmap for a given block_group, reading into the specified 
  * slot in the superblock's bitmap cache.
@@ -88,7 +170,18 @@
 	desc = ext3_get_group_desc (sb, block_group, NULL);
 	if (!desc)
 		goto error_out;
-	bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
+	if (desc->bg_flags & EXT3_BG_BLOCK_UNINIT) {
+		bh = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap));
+		if (!buffer_uptodate(bh)) {
+			lock_buffer(bh);
+			if (!buffer_uptodate(bh)) {
+				init_block_bitmap(sb, bh, desc, block_group);
+				set_buffer_uptodate(bh);
+			}
+			unlock_buffer(bh);
+		}
+	} else
+		bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
 	if (!bh)
 		ext3_error (sb, "read_block_bitmap",
 			    "Cannot read block bitmap - "
@@ -465,6 +558,7 @@
 	desc->bg_free_blocks_count =
 		cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) +
 			group_freed);
+	desc->bg_checksum = ext3_group_desc_csum(es, desc, block_group);
 	spin_unlock(sb_bgl_lock(sbi, block_group));
 	percpu_counter_mod(&sbi->s_freeblocks_counter, count);
 
@@ -1168,6 +1262,7 @@
 	static int goal_hits, goal_attempts;
 #endif
 	unsigned long ngroups;
+	unsigned long free_blks;
 
 	*errp = -ENOSPC;
 	sb = inode->i_sb;
@@ -1218,7 +1313,10 @@
 
 	goal_group = group_no;
 retry:
-	free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
+	if (gdp->bg_flags & EXT3_BG_BLOCK_UNINIT)
+		free_blocks = free_blks_after_init(sb, gdp, group_no);
+	else
+		free_blocks = EXT3_FREE_BLOCKS_COUNT(gdp);
 	/*
 	 * if there is not enough free blocks to make a new resevation
 	 * turn off reservation for this allocation
@@ -1257,7 +1355,11 @@
 			*errp = -EIO;
 			goto out;
 		}
-		free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
+		if (gdp->bg_flags & EXT3_BG_BLOCK_UNINIT)
+			free_blocks = cpu_to_le16(free_blks_after_init(sb, gdp,
+								     group_no));
+		else
+			free_blocks = EXT3_FREE_BLOCKS_COUNT(gdp);
 		/*
 		 * skip this group if the number of
 		 * free blocks is less than half of the reservation
@@ -1362,11 +1464,18 @@
 			ret_block, goal_hits, goal_attempts);
 
 	spin_lock(sb_bgl_lock(sbi, group_no));
+	free_blks = 0;
+	if (gdp->bg_flags & EXT3_BG_BLOCK_UNINIT) {
+		gdp->bg_flags &= ~EXT3_BG_BLOCK_UNINIT;
+		free_blks = cpu_to_le16(free_blks_after_init(sb, gdp,group_no));
+		gdp->bg_free_blocks_count = free_blks;
+	}
 	gdp->bg_free_blocks_count =
 			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);
+	gdp->bg_checksum = ext3_group_desc_csum(es, gdp, group_no);
 	spin_unlock(sb_bgl_lock(sbi, group_no));
 	percpu_counter_mod(&sbi->s_freeblocks_counter, -1);
-
+	percpu_counter_mod(&sbi->s_freeblocks_counter, free_blks);
 	BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor");
 	err = ext3_journal_dirty_metadata(handle, gdp_bh);
 	if (!fatal)
Index: linux-stage/fs/ext3/super.c
===================================================================
--- linux-stage.orig/fs/ext3/super.c	2006-09-17 00:59:44.000000000 -0600
+++ linux-stage/fs/ext3/super.c	2006-09-17 01:13:43.000000000 -0600
@@ -1093,6 +1093,51 @@
 	return res;
 }
 
+static __u16 crc16(__u16 crc, const u8 *buf, size_t len)
+{
+	__u16 tmp;
+
+	while (len--) {
+		crc ^= *buf++;
+		crc ^= (u8)crc >> 4;
+		tmp = (u8)crc;
+		crc ^= (tmp ^ (tmp << 1)) << 4;
+	}
+	return crc;
+}
+
+__u16 ext3_group_desc_csum(struct ext3_super_block *sb,
+			   struct ext3_group_desc *desc, __u32 group)
+{
+	__u16 crc = 0;
+
+	if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+		int offset = offsetof(struct ext3_group_desc, bg_checksum);
+
+		group = cpu_to_le32(group);
+		crc = crc16(~0, (__u8 *)&group, sizeof(group));
+		crc = crc16(crc, (__u8 *)desc, offset);
+		offset += sizeof(desc->bg_checksum); /* skip checksum */
+		BUG_ON(offset != sizeof(*desc)); /* XXX handle s_desc_size */
+		/*
+		if (offset < sb->s_desc_size) {
+			crc = crc16(crc, (__u8 *)desc + offset,
+				    sb->s_desc_size - offset);
+		 */
+	}
+
+	return cpu_to_le16(crc);
+}
+
+int ext3_group_desc_csum_verify(struct ext3_super_block *sb,
+				struct ext3_group_desc *desc, __u32 group)
+{
+	if (desc->bg_checksum != ext3_group_desc_csum(sb, desc, group))
+		return 0;
+
+	return 1;
+}
+
 /* Called at mount-time, super-block is locked */
 static int ext3_check_descriptors (struct super_block * sb)
 {
@@ -1142,6 +1187,13 @@
 					le32_to_cpu(gdp->bg_inode_table));
 			return 0;
 		}
+		if (!ext3_group_desc_csum_verify(sb, gdp, i)) {
+			ext3_error(sb, __FUNCTION__,
+				   "Checksum for group %d failed (%u != %u)\n",
+				   i, ext3_group_desc_csum(sb, gdp, i),
+				   gdp->bg_checksum);
+			return 0;
+		}
 		block += EXT3_BLOCKS_PER_GROUP(sb);
 		gdp++;
 	}
Index: linux-stage/fs/ext3/resize.c
===================================================================
--- linux-stage.orig/fs/ext3/resize.c	2006-09-17 00:59:44.000000000 -0600
+++ linux-stage/fs/ext3/resize.c	2006-09-17 00:59:44.000000000 -0600
@@ -19,7 +19,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 
-
 #define outside(b, first, last)	((b) < (first) || (b) >= (last))
 #define inside(b, first, last)	((b) >= (first) && (b) < (last))
 
@@ -807,6 +806,7 @@
 	gdp->bg_inode_table = cpu_to_le32(input->inode_table);
 	gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count);
 	gdp->bg_free_inodes_count = cpu_to_le16(EXT3_INODES_PER_GROUP(sb));
+	gdp->bg_checksum = ext3_group_desc_csum(es, gdp, input->group);
 
 	/*
 	 * Make the new blocks and inodes valid next.  We do this before
Index: linux-stage/include/linux/ext3_fs.h
===================================================================
--- linux-stage.orig/include/linux/ext3_fs.h	2006-09-17 00:59:44.000000000 -0600
+++ linux-stage/include/linux/ext3_fs.h	2006-09-17 01:02:00.000000000 -0600
@@ -118,6 +118,16 @@
 				 (s)->s_first_ino)
 #endif
 
+//Macro-instructions used to calculate Free inodes and blocks count
+
+#define EXT3_FREE_INODES_COUNT(desc)	(desc->bg_flags &EXT3_BG_INODE_UNINIT)?\
+					EXT3_INODES_PER_GROUP(sb) : \
+					(desc->bg_free_inodes_count + \
+					desc->bg_itable_unused)
+#define EXT3_FREE_BLOCKS_COUNT(desc)	(desc->bg_flags &EXT3_BG_BLOCK_UNINIT)?\
+					EXT3_BLOCKS_PER_GROUP(sb) : \
+					(desc->bg_free_blocks_count)
+
 /*
  * Macro-instructions used to manage fragments
  */
@@ -137,16 +147,21 @@
  */
 struct ext3_group_desc
 {
-	__le32	bg_block_bitmap;		/* Blocks bitmap block */
-	__le32	bg_inode_bitmap;		/* Inodes bitmap block */
+	__le32	bg_block_bitmap;	/* Blocks bitmap block */
+	__le32	bg_inode_bitmap;	/* Inodes bitmap block */
 	__le32	bg_inode_table;		/* Inodes table block */
 	__le16	bg_free_blocks_count;	/* Free blocks count */
 	__le16	bg_free_inodes_count;	/* Free inodes count */
 	__le16	bg_used_dirs_count;	/* Directories count */
-	__u16	bg_pad;
-	__le32	bg_reserved[3];
+	__le16  bg_flags;
+	__le32	bg_reserved[2];
+	__le16	bg_itable_unused;	/*Unused inodes count*/
+	__le16	bg_checksum;
 };
 
+#define EXT3_BG_INODE_UNINIT	0x0001 /* Inode table/bitmap not initialized */
+#define EXT3_BG_BLOCK_UNINIT	0x0002 /* Block bitmap not initialized */
+
 /*
  * Macro-instructions used to manage group descriptors
  */
@@ -565,6 +580,7 @@
 #define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
 #define EXT3_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
 #define EXT3_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM		0x0010 /* Descriptor checksum */
 
 #define EXT3_FEATURE_INCOMPAT_COMPRESSION	0x0001
 #define EXT3_FEATURE_INCOMPAT_FILETYPE		0x0002
@@ -580,7 +596,8 @@
 					 EXT3_FEATURE_INCOMPAT_EXTENTS)
 #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
 					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
-					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
+					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR|\
+					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
 
 /*
  * Default values for user and/or group using reserved blocks
@@ -830,6 +847,10 @@
 extern void ext3_warning (struct super_block *, const char *, const char *, ...)
 	__attribute__ ((format (printf, 3, 4)));
 extern void ext3_update_dynamic_rev (struct super_block *sb);
+extern __u16 ext3_group_desc_csum(struct ext3_super_block *sb,
+				  struct ext3_group_desc *desc, __u32 group);
+extern int ext2fs_group_desc_csum_verify(struct ext2_super_block *sb,
+				  struct ext2_group_desc *desc, __u32 group);
 
 #define ext3_std_error(sb, errno)				\
 do {								\

[-- Attachment #3: e2fsprogs-uninit.patch --]
[-- Type: text/plain, Size: 29586 bytes --]

Index: e2fsprogs/debugfs/debugfs.c
===================================================================
--- e2fsprogs.orig/debugfs/debugfs.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/debugfs/debugfs.c	2006-09-16 17:31:15.000000000 -0600
@@ -321,7 +321,8 @@ void do_show_super_stats(int argc, char 
 		        "inode table at %u\n"
 		        "           %d free %s, "
 		        "%d free %s, "
-		        "%d used %s\n",
+		        "%d used %s, "
+		        "%d unused %s\n",
 		        i, gdp->bg_block_bitmap,
 		        gdp->bg_inode_bitmap, gdp->bg_inode_table,
 		        gdp->bg_free_blocks_count,
@@ -330,7 +331,9 @@ void do_show_super_stats(int argc, char 
 		        gdp->bg_free_inodes_count != 1 ? "inodes" : "inode",
 		        gdp->bg_used_dirs_count,
 		        gdp->bg_used_dirs_count != 1 ? "directories"
-				: "directory");
+				: "directory",
+		        gdp->bg_itable_unused,
+		        gdp->bg_itable_unused != 1 ? "inodes" : "inode");
 		first = 1;
 		print_bg_opts(gdp, EXT2_BG_INODE_UNINIT, "Inode not init",
 			      &first, out);
Index: e2fsprogs/e2fsck/journal.c
===================================================================
--- e2fsprogs.orig/e2fsck/journal.c	2006-05-18 02:45:07.000000000 -0600
+++ e2fsprogs/e2fsck/journal.c	2006-09-16 23:37:04.000000000 -0600
@@ -950,6 +950,8 @@ void e2fsck_move_ext3_journal(e2fsck_t c
 	ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
 	ext2fs_mark_ib_dirty(fs);
 	fs->group_desc[group].bg_free_inodes_count++;
+	fs->group_desc[group].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[group],group);
 	fs->super->s_free_inodes_count++;
 	return;
 
Index: e2fsprogs/e2fsck/pass5.c
===================================================================
--- e2fsprogs.orig/e2fsck/pass5.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/e2fsck/pass5.c	2006-09-16 23:55:49.000000000 -0600
@@ -167,7 +167,9 @@ redo_counts:
 	save_problem = 0;
 	pctx.blk = pctx.blk2 = NO_BLK;
 	if (lazy_bg && (fs->group_desc[group].bg_flags &
-			EXT2_BG_BLOCK_UNINIT))
+			EXT2_BG_BLOCK_UNINIT) &&
+	    ext2fs_group_desc_csum_verify(fs->super, &fs->group_desc[group],
+					  group))
 		skip_group++;
 	super = fs->super->s_first_data_block;
 	for (i = fs->super->s_first_data_block;
@@ -245,7 +247,10 @@ redo_counts:
 			if (lazy_bg &&
 			    (i != fs->super->s_blocks_count-1) &&
 			    (fs->group_desc[group].bg_flags &
-			     EXT2_BG_BLOCK_UNINIT))
+			     EXT2_BG_BLOCK_UNINIT) &&
+			    ext2fs_group_desc_csum_verify(fs->super,
+							 &fs->group_desc[group],
+							 group))
 				skip_group++;
 		}
 	}
@@ -287,6 +292,9 @@ redo_counts:
 					&pctx)) {
 				fs->group_desc[i].bg_free_blocks_count =
 					free_array[i];
+				fs->group_desc[i].bg_checksum =
+					ext2fs_group_desc_csum(fs->super,
+							&fs->group_desc[i], i);
 				ext2fs_mark_super_dirty(fs);
 			} else
 				ext2fs_unmark_valid(fs);
@@ -323,6 +331,8 @@ static void check_inode_bitmaps(e2fsck_t
 	int		problem, save_problem, fixit, had_problem;
 	int		lazy_bg = 0;
 	int		skip_group = 0;
+	int		first_unused_inode = 0;
+	int		unused_inode_count = 0; 
 	
 	clear_problem_context(&pctx);
 	free_array = (int *) e2fsck_allocate_memory(ctx,
@@ -367,13 +377,17 @@ redo_counts:
 	save_problem = 0;
 	pctx.ino = pctx.ino2 = 0;
 	if (lazy_bg && (fs->group_desc[group].bg_flags &
-			EXT2_BG_INODE_UNINIT))
+			EXT2_BG_INODE_UNINIT) &&
+	    ext2fs_group_desc_csum_verify(fs->super, &fs->group_desc[group],
+					  group))
 		skip_group++;
-
+	first_unused_inode = (fs->super->s_inodes_per_group -
+			      fs->group_desc[group].bg_itable_unused) +
+			     (group * fs->super->s_inodes_per_group + 1);
 	/* Protect loop from wrap-around if inodes_count is maxed */
 	for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
 		actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
-		if (skip_group) 
+		if (skip_group || (i >= first_unused_inode))
 			bitmap = 0;
 		else
 			bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
@@ -425,6 +439,7 @@ do_counts:
 			skip_group = 0;
 			group_free = 0;
 			dirs_count = 0;
+			first_unused_inode = 0;
 			if (ctx->progress)
 				if ((ctx->progress)(ctx, 5,
 					    group + fs->group_desc_count,
@@ -433,8 +448,16 @@ do_counts:
 			if (lazy_bg &&
 			    (i != fs->super->s_inodes_count) &&
 			    (fs->group_desc[group].bg_flags &
-			     EXT2_BG_INODE_UNINIT))
+			     EXT2_BG_INODE_UNINIT) &&
+			    ext2fs_group_desc_csum_verify(fs->super,
+							 &fs->group_desc[group],
+							 group))
 				skip_group++;
+			first_unused_inode =
+				(fs->super->s_inodes_per_group - 
+				 fs->group_desc[group].bg_itable_unused) +
+				(group * fs->super->s_inodes_per_group + 1);
+
 		}
 	}
 	if (pctx.ino)
@@ -469,14 +492,20 @@ do_counts:
 		ext2fs_unmark_valid(fs);
 	
 	for (i = 0; i < fs->group_desc_count; i++) {
-		if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
+		unused_inode_count += 	fs->group_desc[i].bg_itable_unused;
+		if (free_array[i] != fs->group_desc[i].bg_free_inodes_count +
+				     fs->group_desc[i].bg_itable_unused) {
 			pctx.group = i;
-			pctx.ino = fs->group_desc[i].bg_free_inodes_count;
+			pctx.ino = fs->group_desc[i].bg_free_inodes_count +
+					fs->group_desc[i].bg_itable_unused;
 			pctx.ino2 = free_array[i];
 			if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
 					&pctx)) {
 				fs->group_desc[i].bg_free_inodes_count =
 					free_array[i];
+				fs->group_desc[i].bg_checksum =
+					ext2fs_group_desc_csum(fs->super,
+							&fs->group_desc[i], i);
 				ext2fs_mark_super_dirty(fs);
 			} else
 				ext2fs_unmark_valid(fs);
@@ -490,12 +519,16 @@ do_counts:
 					&pctx)) {
 				fs->group_desc[i].bg_used_dirs_count =
 					dir_array[i];
+				fs->group_desc[i].bg_checksum =
+					ext2fs_group_desc_csum(fs->super,
+						       &fs->group_desc[i], i);
 				ext2fs_mark_super_dirty(fs);
 			} else
 				ext2fs_unmark_valid(fs);
 		}
 	}
-	if (free_inodes != fs->super->s_free_inodes_count) {
+	if (free_inodes != (fs->super->s_free_inodes_count +
+			    unused_inode_count)) {
 		pctx.group = -1;
 		pctx.ino = fs->super->s_free_inodes_count;
 		pctx.ino2 = free_inodes;
Index: e2fsprogs/e2fsck/super.c
===================================================================
--- e2fsprogs.orig/e2fsck/super.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/e2fsck/super.c	2006-09-16 23:39:48.000000000 -0600
@@ -576,8 +576,11 @@ void check_super_block(e2fsck_t ctx)
 		if ((gd->bg_block_bitmap < first_block) ||
 		    (gd->bg_block_bitmap > last_block)) {
 			pctx.blk = gd->bg_block_bitmap;
-			if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
+			if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx)) {
 				gd->bg_block_bitmap = 0;
+				gd->bg_checksum =
+					ext2fs_group_desc_csum(fs->super, gd,i);
+			}
 		}
 		if (gd->bg_block_bitmap == 0) {
 			ctx->invalid_block_bitmap_flag[i]++;
@@ -586,8 +589,11 @@ void check_super_block(e2fsck_t ctx)
 		if ((gd->bg_inode_bitmap < first_block) ||
 		    (gd->bg_inode_bitmap > last_block)) {
 			pctx.blk = gd->bg_inode_bitmap;
-			if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
+			if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx)) {
 				gd->bg_inode_bitmap = 0;
+				gd->bg_checksum =
+					ext2fs_group_desc_csum(fs->super, gd,i);
+			}
 		}
 		if (gd->bg_inode_bitmap == 0) {
 			ctx->invalid_inode_bitmap_flag[i]++;
@@ -597,8 +603,11 @@ void check_super_block(e2fsck_t ctx)
 		    ((gd->bg_inode_table +
 		      fs->inode_blocks_per_group - 1) > last_block)) {
 			pctx.blk = gd->bg_inode_table;
-			if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
+			if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx)) {
 				gd->bg_inode_table = 0;
+				gd->bg_checksum =
+					ext2fs_group_desc_csum(fs->super, gd,i);
+			}
 		}
 		if (gd->bg_inode_table == 0) {
 			ctx->invalid_inode_table_flag[i]++;
@@ -612,6 +621,12 @@ void check_super_block(e2fsck_t ctx)
 		    (gd->bg_used_dirs_count > sb->s_inodes_per_group))
 			ext2fs_unmark_valid(fs);
 
+		if (ext2fs_group_desc_csum_verify(sb, gd, i) &&
+		    fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
+			gd->bg_checksum =
+				ext2fs_group_desc_csum(fs->super, gd, i);
+		else
+			ext2fs_unmark_valid(fs);
 	}
 
 	/*
Index: e2fsprogs/lib/e2p/feature.c
===================================================================
--- e2fsprogs.orig/lib/e2p/feature.c	2006-05-18 02:45:07.000000000 -0600
+++ e2fsprogs/lib/e2p/feature.c	2006-09-16 17:31:15.000000000 -0600
@@ -41,6 +41,8 @@ static struct feature feature_list[] = {
 			"sparse_super" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
 			"large_file" },
+	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
+			"gdt_csum" },
 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
 			"compression" },
 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
Index: e2fsprogs/lib/ext2fs/Makefile.in
===================================================================
--- e2fsprogs.orig/lib/ext2fs/Makefile.in	2006-09-16 17:31:09.000000000 -0600
+++ e2fsprogs/lib/ext2fs/Makefile.in	2006-09-17 01:33:13.000000000 -0600
@@ -66,7 +66,9 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_O
 	unix_io.o \
 	unlink.o \
 	valid_blk.o \
-	version.o
+	version.o \
+	crc16.o \
+	csum.o
 
 SRCS= ext2_err.c \
 	$(srcdir)/alloc.c \
@@ -135,7 +137,10 @@ SRCS= ext2_err.c \
 	$(srcdir)/tst_byteswap.c \
 	$(srcdir)/tst_getsize.c \
 	$(srcdir)/tst_types.c \
-	$(srcdir)/tst_iscan.c
+	$(srcdir)/tst_iscan.c \
+	$(srcdir)/tst_csum.c \
+	$(srcdir)/crc16.c \
+	$(srcdir)/csum.c
 
 HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h block.h \
 	ext4_extents.h
@@ -228,16 +233,21 @@ tst_types: tst_types.o ext2_types.h 
 	@echo "	LD $@"
 	@$(CC) -o tst_types tst_types.o 
 
+tst_csum: tst_csum.o csum.o crc16.o
+	@echo "	LD $@"
+	@$(CC) -o tst_csum csum.o tst_csum.o crc16.o
+
 mkjournal: mkjournal.c $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
 	@$(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS)
 
-check:: tst_bitops tst_badblocks tst_iscan @SWAPFS_CMT@ tst_byteswap tst_types
+check:: tst_bitops tst_badblocks tst_iscan tst_types @SWAPFS_CMT@ tst_byteswap
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_bitops
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_badblocks
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_iscan
 @SWAPFS_CMT@	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_byteswap
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_types
+	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_csum
 
 installdirs::
 	@echo "	MKINSTALLDIRS $(libdir) $(includedir)/ext2fs"
@@ -344,6 +354,8 @@ cmp_bitmaps.o: $(srcdir)/cmp_bitmaps.c $
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+csum.o: $(srcdir)/csum.c $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h
 dblist.o: $(srcdir)/dblist.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h \
Index: e2fsprogs/lib/ext2fs/alloc.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/alloc.c	2006-02-09 14:08:13.000000000 -0700
+++ e2fsprogs/lib/ext2fs/alloc.c	2006-09-16 17:31:15.000000000 -0600
@@ -77,6 +77,7 @@ errcode_t ext2fs_new_block(ext2_filsys f
 			   ext2fs_block_bitmap map, blk_t *ret)
 {
 	blk_t	i;
+	int     group;	
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -87,14 +88,30 @@ errcode_t ext2fs_new_block(ext2_filsys f
 	if (!goal || (goal >= fs->super->s_blocks_count))
 		goal = fs->super->s_first_data_block;
 	i = goal;
+	group = ext2fs_group_of_blk(fs, goal);
 	do {
+		if (fs->group_desc[group].bg_flags & EXT2_BG_BLOCK_UNINIT) {
+			group++;
+
+			/*
+			 * Move to start of next group
+			 */
+			i = group * fs->super->s_blocks_per_group +
+				fs->super->s_first_data_block;
+			continue;
+		}
 		if (!ext2fs_fast_test_block_bitmap(map, i)) {
 			*ret = i;
 			return 0;
 		}
 		i++;
-		if (i >= fs->super->s_blocks_count)
+		if (i >= ((group + 1) * fs->super->s_blocks_per_group +
+			  fs->super->s_first_data_block))
+			group++;
+		if (i >= fs->super->s_blocks_count) {
 			i = fs->super->s_first_data_block;
+			group = 0;
+		}
 	} while (i != goal);
 	return EXT2_ET_BLOCK_ALLOC_FAIL;
 }
Index: e2fsprogs/lib/ext2fs/alloc_stats.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/alloc_stats.c	2006-02-09 14:08:13.000000000 -0700
+++ e2fsprogs/lib/ext2fs/alloc_stats.c	2006-09-16 23:33:59.000000000 -0600
@@ -27,6 +27,8 @@ void ext2fs_inode_alloc_stats2(ext2_fils
 	fs->group_desc[group].bg_free_inodes_count -= inuse;
 	if (isdir)
 		fs->group_desc[group].bg_used_dirs_count += inuse;
+	fs->group_desc[group].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[group],group);
 	fs->super->s_free_inodes_count -= inuse;
 	ext2fs_mark_super_dirty(fs);
 	ext2fs_mark_ib_dirty(fs);
@@ -46,6 +48,8 @@ void ext2fs_block_alloc_stats(ext2_filsy
 	else
 		ext2fs_unmark_block_bitmap(fs->block_map, blk);
 	fs->group_desc[group].bg_free_blocks_count -= inuse;
+	fs->group_desc[group].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[group],group);
 	fs->super->s_free_blocks_count -= inuse;
 	ext2fs_mark_super_dirty(fs);
 	ext2fs_mark_bb_dirty(fs);
Index: e2fsprogs/lib/ext2fs/alloc_tables.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/alloc_tables.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/lib/ext2fs/alloc_tables.c	2006-09-16 23:36:25.000000000 -0600
@@ -95,13 +95,12 @@ errcode_t ext2fs_allocate_group_table(ex
 			ext2fs_mark_block_bitmap(bmap, blk);
 		fs->group_desc[group].bg_inode_table = new_blk;
 	}
+	fs->group_desc[group].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[group],group);
 
-	
 	return 0;
 }
 
-	
-
 errcode_t ext2fs_allocate_tables(ext2_filsys fs)
 {
 	errcode_t	retval;
Index: e2fsprogs/lib/ext2fs/crc16.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/crc16.c	2006-09-06 05:35:19.060515568 -0600
+++ e2fsprogs/lib/ext2fs/crc16.c	2006-09-16 17:31:15.000000000 -0600
@@ -0,0 +1,60 @@
+/*
+ *      crc16.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/types.h>
+#include "crc16.h"
+
+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
+uint16_t const crc16_table[256] = {
+	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+/**
+ * Compute the CRC-16 for the data buffer
+ *
+ * @param crc     previous CRC value
+ * @param buffer  data pointer
+ * @param len     number of bytes in the buffer
+ * @return        the updated CRC value
+ */
+uint16_t crc16(uint16_t crc, unsigned char const *buffer, size_t len)
+{
+	while (len--)
+		crc = crc16_byte(crc, *buffer++);
+	return crc;
+}
Index: e2fsprogs/lib/ext2fs/crc16.h
===================================================================
--- e2fsprogs.orig/lib/ext2fs/crc16.h	2006-09-06 05:35:19.060515568 -0600
+++ e2fsprogs/lib/ext2fs/crc16.h	2006-09-16 17:31:15.000000000 -0600
@@ -0,0 +1,29 @@
+/*
+ *	crc16.h - CRC-16 routine
+ *
+ * Implements the standard CRC-16:
+ *   Width 16
+ *   Poly  0x8005 (x^16 + x^15 + x^2 + 1)
+ *   Init  0
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#ifndef __CRC16_H
+#define __CRC16_H
+
+#include <linux/types.h>
+
+extern uint16_t const crc16_table[256];
+
+extern uint16_t crc16(uint16_t crc, const unsigned char *buffer, size_t len);
+
+static inline uint16_t crc16_byte(uint16_t crc, const unsigned char data)
+{
+	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
+}
+
+#endif /* __CRC16_H */
Index: e2fsprogs/lib/ext2fs/csum.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/csum.c	2006-09-06 05:35:19.060515568 -0600
+++ e2fsprogs/lib/ext2fs/csum.c	2006-09-17 01:46:35.000000000 -0600
@@ -0,0 +1,51 @@
+/*
+ * csum.c --- checksumming of ext3 structures
+ *
+ * Copyright (C) 2006 Cluster File Systems, Inc.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include <assert.h>
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+__u16 ext2fs_group_desc_csum(struct ext2_super_block *sb,
+			     struct ext2_group_desc *desc, __u32 group)
+{
+	__u16 crc = 0;
+
+	if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+		int offset = offsetof(struct ext2_group_desc, bg_checksum);
+
+		crc = crc16(~0, sb->s_uuid, sizeof(sb->s_uuid));
+		crc = crc16(crc16, &group, sizeof(group));
+		crc = crc16(crc, desc, offset);
+		offset += sizeof(desc->bg_checksum); /* skip checksum */
+		assert(offset == sizeof(*desc)); /* XXX handle s_desc_size */
+		/*
+		if (offset < sb->s_desc_size) {
+			crc = crc16(crc, (char *)desc + offset,
+				    sb->s_desc_size - offset);
+		 */
+	}
+
+	return crc;
+}
+
+int ext2fs_group_desc_csum_verify(struct ext2_super_block *sb,
+				  struct ext2_group_desc *desc, __u32 group)
+{
+	if (desc->bg_checksum != ext2fs_group_desc_csum(sb, desc, group))
+		return 0;
+
+	return 1;
+}
+
Index: e2fsprogs/lib/ext2fs/ext2_fs.h
===================================================================
--- e2fsprogs.orig/lib/ext2fs/ext2_fs.h	2006-09-16 17:31:12.000000000 -0600
+++ e2fsprogs/lib/ext2fs/ext2_fs.h	2006-09-16 17:31:15.000000000 -0600
@@ -144,7 +144,10 @@ struct ext2_group_desc
 	__u16	bg_free_inodes_count;	/* Free inodes count */
 	__u16	bg_used_dirs_count;	/* Directories count */
 	__u16	bg_flags;
-	__u32	bg_reserved[3];
+	__u32	bg_reserved[2];
+	__u16   bg_itable_unused;       /*Unused inode count*/
+	__u16   bg_checksum;
+
 };
 
 #define EXT2_BG_INODE_UNINIT	0x0001 /* Inode table/bitmap not initialized */
@@ -576,6 +579,7 @@ struct ext2_super_block {
 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
 /* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR	0x0004 not used */
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM		0x0010 /* Descriptor checksum */
 
 #define EXT2_FEATURE_INCOMPAT_COMPRESSION	0x0001
 #define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002
Index: e2fsprogs/lib/ext2fs/ext2_fs.h.orig
===================================================================
--- e2fsprogs.orig/lib/ext2fs/ext2_fs.h.orig	2006-09-13 13:03:18.000000000 -0600
+++ e2fsprogs/lib/ext2fs/ext2_fs.h.orig	2006-09-16 17:31:15.000000000 -0600
@@ -144,7 +144,10 @@ struct ext2_group_desc
 	__u16	bg_free_inodes_count;	/* Free inodes count */
 	__u16	bg_used_dirs_count;	/* Directories count */
 	__u16	bg_flags;
-	__u32	bg_reserved[3];
+	__u32	bg_reserved[2];
+	__u16   bg_itable_unused;       /*Unused inode count*/
+	__u16   bg_checksum;
+
 };
 
 #define EXT2_BG_INODE_UNINIT	0x0001 /* Inode table/bitmap not initialized */
Index: e2fsprogs/lib/ext2fs/ext2fs.h
===================================================================
--- e2fsprogs.orig/lib/ext2fs/ext2fs.h	2006-09-16 17:31:13.000000000 -0600
+++ e2fsprogs/lib/ext2fs/ext2fs.h	2006-09-17 01:25:52.000000000 -0600
@@ -463,7 +463,8 @@ typedef struct ext2_icount *ext2_icount_
 					 EXT3_FEATURE_INCOMPAT_EXTENTS)
 #endif
 #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
-					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
+					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE |\
+					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
 /*
  * function prototypes
  */
@@ -625,6 +626,12 @@ extern errcode_t ext2fs_compare_block_bi
 extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
 					     ext2fs_inode_bitmap bm2);
 
+/* csum.c */
+extern __u16 ext2fs_group_desc_csum(struct ext2_super_block *sb,
+				    struct ext2_group_desc *desc, __u32 group);
+extern int ext2fs_group_desc_csum_verify(struct ext2_super_block *sb,
+				    struct ext2_group_desc *desc, __u32 group);
+
 /* dblist.c */
 
 extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
Index: e2fsprogs/lib/ext2fs/inode.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/inode.c	2006-05-18 02:45:07.000000000 -0600
+++ e2fsprogs/lib/ext2fs/inode.c	2006-09-16 23:04:49.000000000 -0600
@@ -229,6 +229,10 @@ static errcode_t get_next_blockgroup(ext
 
 	scan->bytes_left = 0;
 	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
+	if (scan->fs->super->s_feature_ro_compat &
+	    EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
+		scan->inodes_left -=
+		     scan->fs->group_desc[scan->current_group].bg_itable_unused;
 	scan->blocks_left = scan->fs->inode_blocks_per_group;
 	return 0;
 }
Index: e2fsprogs/lib/ext2fs/openfs.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/openfs.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/lib/ext2fs/openfs.c	2006-09-16 23:00:17.000000000 -0600
@@ -279,8 +279,8 @@ errcode_t ext2fs_open2(const char *name,
 #ifdef EXT2FS_ENABLE_SWAPFS
 		if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
 			gdp = (struct ext2_group_desc *) dest;
-			for (j=0; j < groups_per_block; j++)
-				ext2fs_swap_group_desc(gdp++);
+			for (j = 0; j < groups_per_block; j++)
+				ext2fs_swap_group_desc(gdp);
 		}
 #endif
 		dest += fs->blocksize;
Index: e2fsprogs/misc/mke2fs.c
===================================================================
--- e2fsprogs.orig/misc/mke2fs.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/misc/mke2fs.c	2006-09-16 23:50:15.000000000 -0600
@@ -262,6 +262,10 @@ _("Warning: the backup superblock/group 
 				group_bad++;
 				group = ext2fs_group_of_blk(fs, group_block+j);
 				fs->group_desc[group].bg_free_blocks_count++;
+				fs->group_desc[group].bg_checksum =
+					ext2fs_group_desc_csum(fs->super,
+							&fs->group_desc[group],
+							group);
 				fs->super->s_free_blocks_count++;
 			}
 		}
@@ -450,8 +454,7 @@ static void setup_lazy_bg(ext2_filsys fs
 	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)) {
+	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))
@@ -469,6 +472,8 @@ static void setup_lazy_bg(ext2_filsys fs
 				bg->bg_flags |= EXT2_BG_BLOCK_UNINIT;
 				sb->s_free_blocks_count -= blks;
 			}
+			bg->bg_checksum =
+				ext2fs_group_desc_csum(fs->super, bg, i);
 		}
 	}
 }
@@ -544,6 +549,8 @@ static void create_bad_block_inode(ext2_
 	
 	ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO);
 	fs->group_desc[0].bg_free_inodes_count--;
+	fs->group_desc[0].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[0], 0);
 	fs->super->s_free_inodes_count--;
 	retval = ext2fs_update_bb_inode(fs, bb_list);
 	if (retval) {
@@ -563,6 +570,9 @@ static void reserve_inodes(ext2_filsys f
 		ext2fs_mark_inode_bitmap(fs->inode_map, i);
 		group = ext2fs_group_of_ino(fs, i);
 		fs->group_desc[group].bg_free_inodes_count--;
+		fs->group_desc[group].bg_checksum =
+			ext2fs_group_desc_csum(fs->super,
+					       &fs->group_desc[group], group);
 		fs->super->s_free_inodes_count--;
 	}
 	ext2fs_mark_ib_dirty(fs);
@@ -859,7 +869,8 @@ static __u32 ok_features[3] = {
 	EXT2_FEATURE_INCOMPAT_FILETYPE|		/* Incompat */
 		EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
 		EXT2_FEATURE_INCOMPAT_META_BG,
-	EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	/* R/O compat */
+	EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|	/* R/O compat */
+		EXT4_FEATURE_RO_COMPAT_GDT_CSUM
 };
 
 
Index: e2fsprogs/misc/tune2fs.c
===================================================================
--- e2fsprogs.orig/misc/tune2fs.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/misc/tune2fs.c	2006-09-16 23:41:10.000000000 -0600
@@ -213,6 +213,8 @@ static int release_blocks_proc(ext2_fils
 	ext2fs_unmark_block_bitmap(fs->block_map,block);
 	group = ext2fs_group_of_blk(fs, block);
 	fs->group_desc[group].bg_free_blocks_count++;
+	fs->group_desc[group].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[group],group);
 	fs->super->s_free_blocks_count++;
 	return 0;
 }
Index: e2fsprogs/resize/resize2fs.c
===================================================================
--- e2fsprogs.orig/resize/resize2fs.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/resize/resize2fs.c	2006-09-17 01:42:14.000000000 -0600
@@ -338,7 +338,9 @@ retry:
 		numblocks = fs->super->s_blocks_per_group;
 	i = old_fs->group_desc_count - 1;
 	fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
-		
+	fs->group_desc[i].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[i], i);
+
 	/*
 	 * If the number of block groups is staying the same, we're
 	 * done and can exit now.  (If the number block groups is
@@ -414,7 +416,8 @@ retry:
 		fs->group_desc[i].bg_free_inodes_count =
 			fs->super->s_inodes_per_group;
 		fs->group_desc[i].bg_used_dirs_count = 0;
-
+		fs->group_desc[i].bg_checksum =
+			ext2fs_group_desc_csum(fs->super, &fs->group_desc[i],i);
 		retval = ext2fs_allocate_group_table(fs, i, 0);
 		if (retval) goto errout;
 
@@ -1222,9 +1225,14 @@ static errcode_t inode_scan_and_fix(ext2
 		if (retval) goto errout;
 
 		group = (new_inode-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
-		if (LINUX_S_ISDIR(inode.i_mode))
+		if (LINUX_S_ISDIR(inode.i_mode)) {
 			rfs->new_fs->group_desc[group].bg_used_dirs_count++;
-		
+			rfs->new_fs->group_desc[group].bg_checksum =
+				ext2fs_group_desc_csum(rfs->new_fs->super,
+						&rfs->new_fs->group_desc[group],
+						group);
+		}
+
 #ifdef RESIZE2FS_DEBUG
 		if (rfs->flags & RESIZE_DEBUG_INODEMAP)
 			printf("Inode moved %u->%u\n", ino, new_inode);
@@ -1475,6 +1483,9 @@ static errcode_t move_itables(ext2_resiz
 			ext2fs_unmark_block_bitmap(fs->block_map, blk);
 
 		rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
+		rfs->old_fs->group_desc[i].bg_checksum =
+			ext2fs_group_desc_csum(rfs->old_fs->super,
+					       &rfs->old_fs->group_desc[i], i);
 		ext2fs_mark_super_dirty(rfs->old_fs);
 		ext2fs_flush(rfs->old_fs);
 
@@ -1572,8 +1583,13 @@ static errcode_t ext2fs_calculate_summar
 		count++;
 		if ((count == fs->super->s_blocks_per_group) ||
 		    (blk == fs->super->s_blocks_count-1)) {
-			fs->group_desc[group++].bg_free_blocks_count =
+			fs->group_desc[group].bg_free_blocks_count =
 				group_free;
+			fs->group_desc[group].bg_checksum =
+				ext2fs_group_desc_csum(fs->super,
+						       &fs->group_desc[group],
+						       group);
+			group++;
 			count = 0;
 			group_free = 0;
 		}
@@ -1597,8 +1613,13 @@ static errcode_t ext2fs_calculate_summar
 		count++;
 		if ((count == fs->super->s_inodes_per_group) ||
 		    (ino == fs->super->s_inodes_count)) {
-			fs->group_desc[group++].bg_free_inodes_count =
+			fs->group_desc[group].bg_free_inodes_count =
 				group_free;
+			fs->group_desc[group].bg_checksum =
+				ext2fs_group_desc_csum(fs->super,
+						       &fs->group_desc[group],
+						       group);
+			group++;
 			count = 0;
 			group_free = 0;
 		}

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: ext2/3 create large filesystem takes too much time; solutions
  2006-09-17  7:57       ` Andreas Dilger
@ 2006-09-18 19:51         ` Andreas Dilger
  0 siblings, 0 replies; 6+ messages in thread
From: Andreas Dilger @ 2006-09-18 19:51 UTC (permalink / raw)
  To: Theodore Tso; +Cc: Pavel Mironchik, linux-ext4

[-- Attachment #1: Type: text/plain, Size: 2154 bytes --]

On Sep 17, 2006  01:57 -0600, Andreas Dilger wrote:
> Things that need to be done:
> - the kernel block/inode allocation needs to be reworked:
>   - initialize a whole block worth of inodes at one time instead
>     of single inodes.
>   - I don't think we need to zero out the unused inodes - the kernel
>     should already be doing this if the inode block is unused
>   - find a happy medium between using existing groups (inodes/blocks)
>     and initializing new ones
> - we likely need to verify the checksum in more places in e2fsck before
>   trusting the UNINIT flags
  - need to decide what to do if UNINIT flag is set but checksum is wrong.
    this has possibility of getting a LOT of garbage from the disk, including
    old "valid" inodes, garbage for bitmaps, etc.
  - should kernel and/or e2fsck zero the unused parts of the inode table
    asynchronously to avoid such problems?  It could optionally only write
    out the blocks if they are not already zero (to avoid consuming space
    on sparse filesystems) but this would require an additional read of each
    block (maybe can be done slowly to avoid overloading system)?  Could also
    have another flag which indicates if group data is aready zeroed
  - need to clear UNINIT flags if we detect a bitmap/inode is in use in group;
    this would possibly also force a restart of e2fsck so that it checks the
    whole group (with caveat for above).
  - need to zero itable blocks if allocating from an UNINIT group in e2fsprogs
  - need to zero ibitmap/bbitmap if using UNINIT group in e2fsprogs
  - should we drop bg_itable_unused to minimum possible value on e2fsck?
    this would reduce subsequent e2fsck time a bit.
  - need to handle proper big endian machines in e2fsprogs when computing
    checksum.  kernel will always do crc on little-endian disk data, and
    little endian e2fsprogs will do same.

Attached is a slightly-improved version, it at least passes "make check"
in tests, though I haven't gotten the "tst_csum" program to build & run
automatically (passes by hand).


Cheers, Andreas
--
Andreas Dilger
Principal Software Engineer
Cluster File Systems, Inc.


[-- Attachment #2: e2fsprogs-uninit.patch --]
[-- Type: text/plain, Size: 34313 bytes --]

Index: e2fsprogs/debugfs/debugfs.c
===================================================================
--- e2fsprogs.orig/debugfs/debugfs.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/debugfs/debugfs.c	2006-09-18 10:59:16.000000000 -0600
@@ -321,7 +321,8 @@ void do_show_super_stats(int argc, char 
 		        "inode table at %u\n"
 		        "           %d free %s, "
 		        "%d free %s, "
-		        "%d used %s\n",
+		        "%d used %s, "
+		        "%d unused %s\n",
 		        i, gdp->bg_block_bitmap,
 		        gdp->bg_inode_bitmap, gdp->bg_inode_table,
 		        gdp->bg_free_blocks_count,
@@ -330,7 +331,9 @@ void do_show_super_stats(int argc, char 
 		        gdp->bg_free_inodes_count != 1 ? "inodes" : "inode",
 		        gdp->bg_used_dirs_count,
 		        gdp->bg_used_dirs_count != 1 ? "directories"
-				: "directory");
+				: "directory",
+		        gdp->bg_itable_unused,
+		        gdp->bg_itable_unused != 1 ? "inodes" : "inode");
 		first = 1;
 		print_bg_opts(gdp, EXT2_BG_INODE_UNINIT, "Inode not init",
 			      &first, out);
Index: e2fsprogs/e2fsck/journal.c
===================================================================
--- e2fsprogs.orig/e2fsck/journal.c	2006-05-18 02:45:07.000000000 -0600
+++ e2fsprogs/e2fsck/journal.c	2006-09-18 10:59:16.000000000 -0600
@@ -950,6 +950,8 @@ void e2fsck_move_ext3_journal(e2fsck_t c
 	ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
 	ext2fs_mark_ib_dirty(fs);
 	fs->group_desc[group].bg_free_inodes_count++;
+	fs->group_desc[group].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[group],group);
 	fs->super->s_free_inodes_count++;
 	return;
 
Index: e2fsprogs/e2fsck/pass5.c
===================================================================
--- e2fsprogs.orig/e2fsck/pass5.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/e2fsck/pass5.c	2006-09-18 13:37:05.000000000 -0600
@@ -167,7 +167,9 @@ redo_counts:
 	save_problem = 0;
 	pctx.blk = pctx.blk2 = NO_BLK;
 	if (lazy_bg && (fs->group_desc[group].bg_flags &
-			EXT2_BG_BLOCK_UNINIT))
+			EXT2_BG_BLOCK_UNINIT) &&
+	    ext2fs_group_desc_csum_verify(fs->super, &fs->group_desc[group],
+					  group))
 		skip_group++;
 	super = fs->super->s_first_data_block;
 	for (i = fs->super->s_first_data_block;
@@ -207,6 +209,7 @@ redo_counts:
 			 * Block used, but not marked in use in the bitmap.
 			 */
 			problem = PR_5_BLOCK_USED;
+			/* XXX clear bbitmap UNINIT flag */
 		}
 		if (pctx.blk == NO_BLK) {
 			pctx.blk = pctx.blk2 = i;
@@ -245,7 +248,10 @@ redo_counts:
 			if (lazy_bg &&
 			    (i != fs->super->s_blocks_count-1) &&
 			    (fs->group_desc[group].bg_flags &
-			     EXT2_BG_BLOCK_UNINIT))
+			     EXT2_BG_BLOCK_UNINIT) &&
+			    ext2fs_group_desc_csum_verify(fs->super,
+							 &fs->group_desc[group],
+							 group))
 				skip_group++;
 		}
 	}
@@ -287,6 +293,10 @@ redo_counts:
 					&pctx)) {
 				fs->group_desc[i].bg_free_blocks_count =
 					free_array[i];
+				fs->group_desc[i].bg_checksum =
+					ext2fs_group_desc_csum(fs->super,
+							&fs->group_desc[i], i);
+				/* XXX clear bbitmap UNINIT flag */
 				ext2fs_mark_super_dirty(fs);
 			} else
 				ext2fs_unmark_valid(fs);
@@ -323,6 +333,8 @@ static void check_inode_bitmaps(e2fsck_t
 	int		problem, save_problem, fixit, had_problem;
 	int		lazy_bg = 0;
 	int		skip_group = 0;
+	int		first_unused_inode = 0;
+	int		unused_inode_count = 0;
 	
 	clear_problem_context(&pctx);
 	free_array = (int *) e2fsck_allocate_memory(ctx,
@@ -367,13 +379,17 @@ redo_counts:
 	save_problem = 0;
 	pctx.ino = pctx.ino2 = 0;
 	if (lazy_bg && (fs->group_desc[group].bg_flags &
-			EXT2_BG_INODE_UNINIT))
+			EXT2_BG_INODE_UNINIT) &&
+	    ext2fs_group_desc_csum_verify(fs->super, &fs->group_desc[group],
+					  group))
 		skip_group++;
-
+	first_unused_inode = (fs->super->s_inodes_per_group -
+			      fs->group_desc[group].bg_itable_unused) +
+			     (group * fs->super->s_inodes_per_group + 1);
 	/* Protect loop from wrap-around if inodes_count is maxed */
 	for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
 		actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
-		if (skip_group) 
+		if (skip_group || (i >= first_unused_inode))
 			bitmap = 0;
 		else
 			bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
@@ -390,6 +406,7 @@ redo_counts:
 			 * Inode used, but not in bitmap
 			 */
 			problem = PR_5_INODE_USED;
+			/* XXX clear ibitmap UNINIT flag and/or unused count */
 		}
 		if (pctx.ino == 0) {
 			pctx.ino = pctx.ino2 = i;
@@ -425,6 +442,7 @@ do_counts:
 			skip_group = 0;
 			group_free = 0;
 			dirs_count = 0;
+			first_unused_inode = 0;
 			if (ctx->progress)
 				if ((ctx->progress)(ctx, 5,
 					    group + fs->group_desc_count,
@@ -433,8 +451,16 @@ do_counts:
 			if (lazy_bg &&
 			    (i != fs->super->s_inodes_count) &&
 			    (fs->group_desc[group].bg_flags &
-			     EXT2_BG_INODE_UNINIT))
+			     EXT2_BG_INODE_UNINIT) &&
+			    ext2fs_group_desc_csum_verify(fs->super,
+							 &fs->group_desc[group],
+							 group))
 				skip_group++;
+			first_unused_inode =
+				(fs->super->s_inodes_per_group -
+				 fs->group_desc[group].bg_itable_unused) +
+				(group * fs->super->s_inodes_per_group + 1);
+
 		}
 	}
 	if (pctx.ino)
@@ -469,14 +495,22 @@ do_counts:
 		ext2fs_unmark_valid(fs);
 	
 	for (i = 0; i < fs->group_desc_count; i++) {
-		if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
+		unused_inode_count += fs->group_desc[i].bg_itable_unused;
+		if (free_array[i] != fs->group_desc[i].bg_free_inodes_count +
+				     fs->group_desc[i].bg_itable_unused) {
 			pctx.group = i;
-			pctx.ino = fs->group_desc[i].bg_free_inodes_count;
+			pctx.ino = fs->group_desc[i].bg_free_inodes_count +
+					fs->group_desc[i].bg_itable_unused;
 			pctx.ino2 = free_array[i];
 			if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
 					&pctx)) {
 				fs->group_desc[i].bg_free_inodes_count =
 					free_array[i];
+				/* XXX clear ibitmap UNINIT flag? */
+				/* XXX reset unused count */
+				fs->group_desc[i].bg_checksum =
+					ext2fs_group_desc_csum(fs->super,
+							&fs->group_desc[i], i);
 				ext2fs_mark_super_dirty(fs);
 			} else
 				ext2fs_unmark_valid(fs);
@@ -490,12 +524,18 @@ do_counts:
 					&pctx)) {
 				fs->group_desc[i].bg_used_dirs_count =
 					dir_array[i];
+				/* XXX clear ibitmap UNINIT flag? */
+				/* XXX reset unused count */
+				fs->group_desc[i].bg_checksum =
+					ext2fs_group_desc_csum(fs->super,
+						       &fs->group_desc[i], i);
 				ext2fs_mark_super_dirty(fs);
 			} else
 				ext2fs_unmark_valid(fs);
 		}
 	}
-	if (free_inodes != fs->super->s_free_inodes_count) {
+	if (free_inodes != (fs->super->s_free_inodes_count +
+			    unused_inode_count)) {
 		pctx.group = -1;
 		pctx.ino = fs->super->s_free_inodes_count;
 		pctx.ino2 = free_inodes;
Index: e2fsprogs/e2fsck/problem.c
===================================================================
--- e2fsprogs.orig/e2fsck/problem.c	2006-09-16 17:31:13.000000000 -0600
+++ e2fsprogs/e2fsck/problem.c	2006-09-18 12:22:07.000000000 -0600
@@ -346,8 +346,12 @@ static struct e2fsck_problem problem_tab
 	  N_("@S hint for external superblock @s %X.  "),
 	     PROMPT_FIX, PR_PREEN_OK },
 
+	{ PR_0_GDT_CSUM,
+	  N_("@g %g descriptor checksum is invalid.  "),
+	     PROMPT_FIX, PR_PREEN_OK },
+
 	/* Pass 1 errors */
-	
+
 	/* Pass 1: Checking inodes, blocks, and sizes */
 	{ PR_1_PASS_HEADER,
 	  N_("Pass 1: Checking @is, @bs, and sizes\n"),
Index: e2fsprogs/e2fsck/problem.h
===================================================================
--- e2fsprogs.orig/e2fsck/problem.h	2006-09-16 17:31:09.000000000 -0600
+++ e2fsprogs/e2fsck/problem.h	2006-09-18 12:22:37.000000000 -0600
@@ -194,6 +194,9 @@ struct problem_context {
 /* Superblock hint for external journal incorrect */
 #define PR_0_EXTERNAL_JOURNAL_HINT		0x000033
 
+/* Group descriptor checksum is invalid */
+#define PR_0_GDT_CSUM				0x000034
+
 /*
  * Pass 1 errors
  */
Index: e2fsprogs/e2fsck/super.c
===================================================================
--- e2fsprogs.orig/e2fsck/super.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/e2fsck/super.c	2006-09-18 12:21:08.000000000 -0600
@@ -568,6 +568,7 @@ void check_super_block(e2fsck_t ctx)
 	first_block =  sb->s_first_data_block;
 
 	for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
+		int do_csum = 0;
 		pctx.group = i;
 
 		first_block = ext2fs_group_first_block(fs, i);
@@ -576,8 +577,10 @@ void check_super_block(e2fsck_t ctx)
 		if ((gd->bg_block_bitmap < first_block) ||
 		    (gd->bg_block_bitmap > last_block)) {
 			pctx.blk = gd->bg_block_bitmap;
-			if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
+			if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx)) {
 				gd->bg_block_bitmap = 0;
+				do_csum = 1;
+			}
 		}
 		if (gd->bg_block_bitmap == 0) {
 			ctx->invalid_block_bitmap_flag[i]++;
@@ -586,8 +589,10 @@ void check_super_block(e2fsck_t ctx)
 		if ((gd->bg_inode_bitmap < first_block) ||
 		    (gd->bg_inode_bitmap > last_block)) {
 			pctx.blk = gd->bg_inode_bitmap;
-			if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
+			if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx)) {
 				gd->bg_inode_bitmap = 0;
+				do_csum = 1;
+			}
 		}
 		if (gd->bg_inode_bitmap == 0) {
 			ctx->invalid_inode_bitmap_flag[i]++;
@@ -597,8 +602,10 @@ void check_super_block(e2fsck_t ctx)
 		    ((gd->bg_inode_table +
 		      fs->inode_blocks_per_group - 1) > last_block)) {
 			pctx.blk = gd->bg_inode_table;
-			if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
+			if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx)) {
 				gd->bg_inode_table = 0;
+				do_csum = 1;
+			}
 		}
 		if (gd->bg_inode_table == 0) {
 			ctx->invalid_inode_table_flag[i]++;
@@ -612,6 +619,14 @@ void check_super_block(e2fsck_t ctx)
 		    (gd->bg_used_dirs_count > sb->s_inodes_per_group))
 			ext2fs_unmark_valid(fs);
 
+		if (!ext2fs_group_desc_csum_verify(sb, gd, i)) {
+			if (fix_problem(ctx, PR_0_GDT_CSUM, &pctx))
+				do_csum = 1;
+			/* XXX do something about UNINT flags? */
+		}
+		if (do_csum)
+			gd->bg_checksum =
+				ext2fs_group_desc_csum(fs->super, gd, i);
 	}
 
 	/*
Index: e2fsprogs/lib/e2p/feature.c
===================================================================
--- e2fsprogs.orig/lib/e2p/feature.c	2006-05-18 02:45:07.000000000 -0600
+++ e2fsprogs/lib/e2p/feature.c	2006-09-18 10:59:16.000000000 -0600
@@ -41,6 +41,8 @@ static struct feature feature_list[] = {
 			"sparse_super" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
 			"large_file" },
+	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
+			"gdt_csum" },
 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
 			"compression" },
 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
Index: e2fsprogs/lib/ext2fs/Makefile.in
===================================================================
--- e2fsprogs.orig/lib/ext2fs/Makefile.in	2006-09-16 17:31:09.000000000 -0600
+++ e2fsprogs/lib/ext2fs/Makefile.in	2006-09-18 10:59:16.000000000 -0600
@@ -66,7 +66,9 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_O
 	unix_io.o \
 	unlink.o \
 	valid_blk.o \
-	version.o
+	version.o \
+	crc16.o \
+	csum.o
 
 SRCS= ext2_err.c \
 	$(srcdir)/alloc.c \
@@ -135,7 +137,10 @@ SRCS= ext2_err.c \
 	$(srcdir)/tst_byteswap.c \
 	$(srcdir)/tst_getsize.c \
 	$(srcdir)/tst_types.c \
-	$(srcdir)/tst_iscan.c
+	$(srcdir)/tst_iscan.c \
+	$(srcdir)/tst_csum.c \
+	$(srcdir)/crc16.c \
+	$(srcdir)/csum.c
 
 HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h block.h \
 	ext4_extents.h
@@ -228,16 +233,21 @@ tst_types: tst_types.o ext2_types.h 
 	@echo "	LD $@"
 	@$(CC) -o tst_types tst_types.o 
 
+tst_csum: tst_csum.o csum.o crc16.o
+	@echo "	LD $@"
+	@$(CC) -o tst_csum csum.o tst_csum.o crc16.o
+
 mkjournal: mkjournal.c $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
 	@$(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS)
 
-check:: tst_bitops tst_badblocks tst_iscan @SWAPFS_CMT@ tst_byteswap tst_types
+check:: tst_bitops tst_badblocks tst_iscan tst_types @SWAPFS_CMT@ tst_byteswap
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_bitops
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_badblocks
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_iscan
 @SWAPFS_CMT@	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_byteswap
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_types
+	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_csum
 
 installdirs::
 	@echo "	MKINSTALLDIRS $(libdir) $(includedir)/ext2fs"
@@ -344,6 +354,8 @@ cmp_bitmaps.o: $(srcdir)/cmp_bitmaps.c $
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+csum.o: $(srcdir)/csum.c $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h
 dblist.o: $(srcdir)/dblist.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h \
Index: e2fsprogs/lib/ext2fs/alloc.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/alloc.c	2006-02-09 14:08:13.000000000 -0700
+++ e2fsprogs/lib/ext2fs/alloc.c	2006-09-18 10:59:16.000000000 -0600
@@ -77,6 +77,7 @@ errcode_t ext2fs_new_block(ext2_filsys f
 			   ext2fs_block_bitmap map, blk_t *ret)
 {
 	blk_t	i;
+	int     group;	
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -87,14 +88,30 @@ errcode_t ext2fs_new_block(ext2_filsys f
 	if (!goal || (goal >= fs->super->s_blocks_count))
 		goal = fs->super->s_first_data_block;
 	i = goal;
+	group = ext2fs_group_of_blk(fs, goal);
 	do {
+		if (fs->group_desc[group].bg_flags & EXT2_BG_BLOCK_UNINIT) {
+			group++;
+
+			/*
+			 * Move to start of next group
+			 */
+			i = group * fs->super->s_blocks_per_group +
+				fs->super->s_first_data_block;
+			continue;
+		}
 		if (!ext2fs_fast_test_block_bitmap(map, i)) {
 			*ret = i;
 			return 0;
 		}
 		i++;
-		if (i >= fs->super->s_blocks_count)
+		if (i >= ((group + 1) * fs->super->s_blocks_per_group +
+			  fs->super->s_first_data_block))
+			group++;
+		if (i >= fs->super->s_blocks_count) {
 			i = fs->super->s_first_data_block;
+			group = 0;
+		}
 	} while (i != goal);
 	return EXT2_ET_BLOCK_ALLOC_FAIL;
 }
Index: e2fsprogs/lib/ext2fs/alloc_stats.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/alloc_stats.c	2006-02-09 14:08:13.000000000 -0700
+++ e2fsprogs/lib/ext2fs/alloc_stats.c	2006-09-18 12:26:15.000000000 -0600
@@ -27,6 +27,9 @@ void ext2fs_inode_alloc_stats2(ext2_fils
 	fs->group_desc[group].bg_free_inodes_count -= inuse;
 	if (isdir)
 		fs->group_desc[group].bg_used_dirs_count += inuse;
+	fs->group_desc[group].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[group],group);
+	/* XXX clear ibitmap UNINIT flag, decrease unused count */
 	fs->super->s_free_inodes_count -= inuse;
 	ext2fs_mark_super_dirty(fs);
 	ext2fs_mark_ib_dirty(fs);
@@ -46,6 +49,9 @@ void ext2fs_block_alloc_stats(ext2_filsy
 	else
 		ext2fs_unmark_block_bitmap(fs->block_map, blk);
 	fs->group_desc[group].bg_free_blocks_count -= inuse;
+	fs->group_desc[group].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[group],group);
+	/* XXX clear bbitmap UNINIT flag, initialize bitmap? */
 	fs->super->s_free_blocks_count -= inuse;
 	ext2fs_mark_super_dirty(fs);
 	ext2fs_mark_bb_dirty(fs);
Index: e2fsprogs/lib/ext2fs/alloc_tables.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/alloc_tables.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/lib/ext2fs/alloc_tables.c	2006-09-18 10:59:16.000000000 -0600
@@ -95,13 +95,12 @@ errcode_t ext2fs_allocate_group_table(ex
 			ext2fs_mark_block_bitmap(bmap, blk);
 		fs->group_desc[group].bg_inode_table = new_blk;
 	}
+	fs->group_desc[group].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[group],group);
 
-	
 	return 0;
 }
 
-	
-
 errcode_t ext2fs_allocate_tables(ext2_filsys fs)
 {
 	errcode_t	retval;
Index: e2fsprogs/lib/ext2fs/crc16.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/crc16.c	2006-09-06 05:35:19.060515568 -0600
+++ e2fsprogs/lib/ext2fs/crc16.c	2006-09-18 10:59:16.000000000 -0600
@@ -0,0 +1,60 @@
+/*
+ *      crc16.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/types.h>
+#include "crc16.h"
+
+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
+uint16_t const crc16_table[256] = {
+	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+/**
+ * Compute the CRC-16 for the data buffer
+ *
+ * @param crc     previous CRC value
+ * @param buffer  data pointer
+ * @param len     number of bytes in the buffer
+ * @return        the updated CRC value
+ */
+uint16_t crc16(uint16_t crc, unsigned char const *buffer, size_t len)
+{
+	while (len--)
+		crc = crc16_byte(crc, *buffer++);
+	return crc;
+}
Index: e2fsprogs/lib/ext2fs/crc16.h
===================================================================
--- e2fsprogs.orig/lib/ext2fs/crc16.h	2006-09-06 05:35:19.060515568 -0600
+++ e2fsprogs/lib/ext2fs/crc16.h	2006-09-18 10:59:16.000000000 -0600
@@ -0,0 +1,29 @@
+/*
+ *	crc16.h - CRC-16 routine
+ *
+ * Implements the standard CRC-16:
+ *   Width 16
+ *   Poly  0x8005 (x^16 + x^15 + x^2 + 1)
+ *   Init  0
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#ifndef __CRC16_H
+#define __CRC16_H
+
+#include <linux/types.h>
+
+extern uint16_t const crc16_table[256];
+
+extern uint16_t crc16(uint16_t crc, const unsigned char *buffer, size_t len);
+
+static inline uint16_t crc16_byte(uint16_t crc, const unsigned char data)
+{
+	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
+}
+
+#endif /* __CRC16_H */
Index: e2fsprogs/lib/ext2fs/csum.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/csum.c	2006-09-06 05:35:19.060515568 -0600
+++ e2fsprogs/lib/ext2fs/csum.c	2006-09-18 10:59:16.000000000 -0600
@@ -0,0 +1,51 @@
+/*
+ * csum.c --- checksumming of ext3 structures
+ *
+ * Copyright (C) 2006 Cluster File Systems, Inc.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include <assert.h>
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+__u16 ext2fs_group_desc_csum(struct ext2_super_block *sb,
+			     struct ext2_group_desc *desc, __u32 group)
+{
+	__u16 crc = 0;
+
+	if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+		int offset = offsetof(struct ext2_group_desc, bg_checksum);
+
+		crc = crc16(~0, sb->s_uuid, sizeof(sb->s_uuid));
+		crc = crc16(crc16, &group, sizeof(group));
+		crc = crc16(crc, desc, offset);
+		offset += sizeof(desc->bg_checksum); /* skip checksum */
+		assert(offset == sizeof(*desc)); /* XXX handle s_desc_size */
+		/*
+		if (offset < sb->s_desc_size) {
+			crc = crc16(crc, (char *)desc + offset,
+				    sb->s_desc_size - offset);
+		 */
+	}
+
+	return crc;
+}
+
+int ext2fs_group_desc_csum_verify(struct ext2_super_block *sb,
+				  struct ext2_group_desc *desc, __u32 group)
+{
+	if (desc->bg_checksum != ext2fs_group_desc_csum(sb, desc, group))
+		return 0;
+
+	return 1;
+}
+
Index: e2fsprogs/lib/ext2fs/ext2_fs.h
===================================================================
--- e2fsprogs.orig/lib/ext2fs/ext2_fs.h	2006-09-16 17:31:12.000000000 -0600
+++ e2fsprogs/lib/ext2fs/ext2_fs.h	2006-09-18 10:59:16.000000000 -0600
@@ -144,7 +144,10 @@ struct ext2_group_desc
 	__u16	bg_free_inodes_count;	/* Free inodes count */
 	__u16	bg_used_dirs_count;	/* Directories count */
 	__u16	bg_flags;
-	__u32	bg_reserved[3];
+	__u32	bg_reserved[2];
+	__u16   bg_itable_unused;       /*Unused inode count*/
+	__u16   bg_checksum;
+
 };
 
 #define EXT2_BG_INODE_UNINIT	0x0001 /* Inode table/bitmap not initialized */
@@ -576,6 +579,7 @@ struct ext2_super_block {
 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
 /* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR	0x0004 not used */
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM		0x0010 /* Descriptor checksum */
 
 #define EXT2_FEATURE_INCOMPAT_COMPRESSION	0x0001
 #define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002
Index: e2fsprogs/lib/ext2fs/ext2fs.h
===================================================================
--- e2fsprogs.orig/lib/ext2fs/ext2fs.h	2006-09-16 17:31:13.000000000 -0600
+++ e2fsprogs/lib/ext2fs/ext2fs.h	2006-09-18 10:59:16.000000000 -0600
@@ -463,7 +463,8 @@ typedef struct ext2_icount *ext2_icount_
 					 EXT3_FEATURE_INCOMPAT_EXTENTS)
 #endif
 #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
-					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
+					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE |\
+					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
 /*
  * function prototypes
  */
@@ -625,6 +626,12 @@ extern errcode_t ext2fs_compare_block_bi
 extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
 					     ext2fs_inode_bitmap bm2);
 
+/* csum.c */
+extern __u16 ext2fs_group_desc_csum(struct ext2_super_block *sb,
+				    struct ext2_group_desc *desc, __u32 group);
+extern int ext2fs_group_desc_csum_verify(struct ext2_super_block *sb,
+				    struct ext2_group_desc *desc, __u32 group);
+
 /* dblist.c */
 
 extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
Index: e2fsprogs/lib/ext2fs/initialize.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/initialize.c	2006-09-18 10:43:59.000000000 -0600
+++ e2fsprogs/lib/ext2fs/initialize.c	2006-09-18 10:59:16.000000000 -0600
@@ -371,8 +371,10 @@ ipg_retry:
 		fs->group_desc[i].bg_free_inodes_count =
 			fs->super->s_inodes_per_group;
 		fs->group_desc[i].bg_used_dirs_count = 0;
+		fs->group_desc[i].bg_checksum =
+			ext2fs_group_desc_csum(fs->super, &fs->group_desc[i],i);
 	}
-	
+
 	ext2fs_mark_super_dirty(fs);
 	ext2fs_mark_bb_dirty(fs);
 	ext2fs_mark_ib_dirty(fs);
Index: e2fsprogs/lib/ext2fs/inode.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/inode.c	2006-05-18 02:45:07.000000000 -0600
+++ e2fsprogs/lib/ext2fs/inode.c	2006-09-18 10:59:16.000000000 -0600
@@ -229,6 +229,10 @@ static errcode_t get_next_blockgroup(ext
 
 	scan->bytes_left = 0;
 	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
+	if (scan->fs->super->s_feature_ro_compat &
+	    EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
+		scan->inodes_left -=
+		     scan->fs->group_desc[scan->current_group].bg_itable_unused;
 	scan->blocks_left = scan->fs->inode_blocks_per_group;
 	return 0;
 }
Index: e2fsprogs/lib/ext2fs/rw_bitmaps.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/rw_bitmaps.c	2006-09-18 10:49:55.000000000 -0600
+++ e2fsprogs/lib/ext2fs/rw_bitmaps.c	2006-09-18 10:59:16.000000000 -0600
@@ -229,7 +229,9 @@ static errcode_t read_bitmaps(ext2_filsy
 		if (block_bitmap) {
 			blk = fs->group_desc[i].bg_block_bitmap;
 			if (lazy_flag && fs->group_desc[i].bg_flags &
-			    EXT2_BG_BLOCK_UNINIT)
+			    EXT2_BG_BLOCK_UNINIT &&
+			    ext2fs_group_desc_csum_verify(fs->super,
+							  &fs->group_desc[i],i))
 				blk = 0;
 			if (blk) {
 				retval = io_channel_read_blk(fs->io, blk,
@@ -250,7 +252,9 @@ static errcode_t read_bitmaps(ext2_filsy
 		if (inode_bitmap) {
 			blk = fs->group_desc[i].bg_inode_bitmap;
 			if (lazy_flag && fs->group_desc[i].bg_flags &
-			    EXT2_BG_INODE_UNINIT)
+			    EXT2_BG_INODE_UNINIT &&
+			    ext2fs_group_desc_csum_verify(fs->super,
+							  &fs->group_desc[i],i))
 				blk = 0;
 			if (blk) {
 				retval = io_channel_read_blk(fs->io, blk,
Index: e2fsprogs/lib/ext2fs/swapfs.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/swapfs.c	2006-09-18 10:46:10.000000000 -0600
+++ e2fsprogs/lib/ext2fs/swapfs.c	2006-09-18 10:59:16.000000000 -0600
@@ -79,6 +79,7 @@ void ext2fs_swap_group_desc(struct ext2_
 	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);
+	gdp->bg_checksum = ext2fs_swab16(gdp->bg_checksum);
 }
 
 void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
Index: e2fsprogs/lib/ext2fs/tst_csum.c
===================================================================
--- e2fsprogs.orig/lib/ext2fs/tst_csum.c	2006-09-06 05:35:19.060515568 -0600
+++ e2fsprogs/lib/ext2fs/tst_csum.c	2006-09-18 10:59:16.000000000 -0600
@@ -0,0 +1,52 @@
+/*
+ * This testing program verifies checksumming operations
+ *
+ * Copyright (C) 2006 by Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+
+main(int argc, char **argv)
+{
+	struct ext2_group_desc desc = { 0 };
+	struct ext2_super_block sb = { .s_feature_ro_compat =
+					EXT4_FEATURE_RO_COMPAT_GDT_CSUM };
+	__u16 csum1, csum2;
+
+	csum1 = ext2fs_group_desc_csum(&sb, &desc, 0);
+	csum2 = ext2fs_group_desc_csum(&sb, &desc, 1);
+	if (csum1 == csum2) {
+		printf("checksums for different groups shouldn't match\n");
+		exit(1);
+	}
+	csum2 = ext2fs_group_desc_csum(&sb, &desc, 0xffff);
+	if (csum1 == csum2) {
+		printf("checksums for different groups shouldn't match\n");
+		exit(1);
+	}
+	desc.bg_checksum = csum1;
+	csum2 = ext2fs_group_desc_csum(&sb, &desc, 0);
+	if (csum1 != csum2) {
+		printf("checksums should not depend on checksum field\n");
+		exit(1);
+	}
+	if (!ext2fs_group_desc_csum_verify(&sb, &desc, 0)) {
+		printf("checksums should verify against gd_checksum\n");
+		exit(1);
+	}
+	desc.bg_free_blocks_count = 1;
+	csum2 = ext2fs_group_desc_csum(&sb, &desc, 0);
+	if (csum1 == csum2) {
+		printf("checksums for different data shouldn't match\n");
+		exit(1);
+	}
+
+	return 0;
+}
+
Index: e2fsprogs/misc/mke2fs.c
===================================================================
--- e2fsprogs.orig/misc/mke2fs.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/misc/mke2fs.c	2006-09-18 10:59:16.000000000 -0600
@@ -262,6 +262,10 @@ _("Warning: the backup superblock/group 
 				group_bad++;
 				group = ext2fs_group_of_blk(fs, group_block+j);
 				fs->group_desc[group].bg_free_blocks_count++;
+				fs->group_desc[group].bg_checksum =
+					ext2fs_group_desc_csum(fs->super,
+							&fs->group_desc[group],
+							group);
 				fs->super->s_free_blocks_count++;
 			}
 		}
@@ -450,8 +454,7 @@ static void setup_lazy_bg(ext2_filsys fs
 	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)) {
+	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))
@@ -469,6 +472,8 @@ static void setup_lazy_bg(ext2_filsys fs
 				bg->bg_flags |= EXT2_BG_BLOCK_UNINIT;
 				sb->s_free_blocks_count -= blks;
 			}
+			bg->bg_checksum =
+				ext2fs_group_desc_csum(fs->super, bg, i);
 		}
 	}
 }
@@ -544,6 +549,8 @@ static void create_bad_block_inode(ext2_
 	
 	ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO);
 	fs->group_desc[0].bg_free_inodes_count--;
+	fs->group_desc[0].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[0], 0);
 	fs->super->s_free_inodes_count--;
 	retval = ext2fs_update_bb_inode(fs, bb_list);
 	if (retval) {
@@ -563,6 +570,9 @@ static void reserve_inodes(ext2_filsys f
 		ext2fs_mark_inode_bitmap(fs->inode_map, i);
 		group = ext2fs_group_of_ino(fs, i);
 		fs->group_desc[group].bg_free_inodes_count--;
+		fs->group_desc[group].bg_checksum =
+			ext2fs_group_desc_csum(fs->super,
+					       &fs->group_desc[group], group);
 		fs->super->s_free_inodes_count--;
 	}
 	ext2fs_mark_ib_dirty(fs);
@@ -859,7 +869,8 @@ static __u32 ok_features[3] = {
 	EXT2_FEATURE_INCOMPAT_FILETYPE|		/* Incompat */
 		EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
 		EXT2_FEATURE_INCOMPAT_META_BG,
-	EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	/* R/O compat */
+	EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|	/* R/O compat */
+		EXT4_FEATURE_RO_COMPAT_GDT_CSUM
 };
 
 
Index: e2fsprogs/misc/tune2fs.c
===================================================================
--- e2fsprogs.orig/misc/tune2fs.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/misc/tune2fs.c	2006-09-18 10:59:16.000000000 -0600
@@ -213,6 +213,8 @@ static int release_blocks_proc(ext2_fils
 	ext2fs_unmark_block_bitmap(fs->block_map,block);
 	group = ext2fs_group_of_blk(fs, block);
 	fs->group_desc[group].bg_free_blocks_count++;
+	fs->group_desc[group].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[group],group);
 	fs->super->s_free_blocks_count++;
 	return 0;
 }
Index: e2fsprogs/resize/resize2fs.c
===================================================================
--- e2fsprogs.orig/resize/resize2fs.c	2006-09-13 12:59:34.000000000 -0600
+++ e2fsprogs/resize/resize2fs.c	2006-09-18 10:59:16.000000000 -0600
@@ -338,7 +338,9 @@ retry:
 		numblocks = fs->super->s_blocks_per_group;
 	i = old_fs->group_desc_count - 1;
 	fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
-		
+	fs->group_desc[i].bg_checksum =
+		ext2fs_group_desc_csum(fs->super, &fs->group_desc[i], i);
+
 	/*
 	 * If the number of block groups is staying the same, we're
 	 * done and can exit now.  (If the number block groups is
@@ -414,7 +416,8 @@ retry:
 		fs->group_desc[i].bg_free_inodes_count =
 			fs->super->s_inodes_per_group;
 		fs->group_desc[i].bg_used_dirs_count = 0;
-
+		fs->group_desc[i].bg_checksum =
+			ext2fs_group_desc_csum(fs->super, &fs->group_desc[i],i);
 		retval = ext2fs_allocate_group_table(fs, i, 0);
 		if (retval) goto errout;
 
@@ -1222,9 +1225,14 @@ static errcode_t inode_scan_and_fix(ext2
 		if (retval) goto errout;
 
 		group = (new_inode-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
-		if (LINUX_S_ISDIR(inode.i_mode))
+		if (LINUX_S_ISDIR(inode.i_mode)) {
 			rfs->new_fs->group_desc[group].bg_used_dirs_count++;
-		
+			rfs->new_fs->group_desc[group].bg_checksum =
+				ext2fs_group_desc_csum(rfs->new_fs->super,
+						&rfs->new_fs->group_desc[group],
+						group);
+		}
+
 #ifdef RESIZE2FS_DEBUG
 		if (rfs->flags & RESIZE_DEBUG_INODEMAP)
 			printf("Inode moved %u->%u\n", ino, new_inode);
@@ -1475,6 +1483,9 @@ static errcode_t move_itables(ext2_resiz
 			ext2fs_unmark_block_bitmap(fs->block_map, blk);
 
 		rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
+		rfs->old_fs->group_desc[i].bg_checksum =
+			ext2fs_group_desc_csum(rfs->old_fs->super,
+					       &rfs->old_fs->group_desc[i], i);
 		ext2fs_mark_super_dirty(rfs->old_fs);
 		ext2fs_flush(rfs->old_fs);
 
@@ -1572,8 +1583,13 @@ static errcode_t ext2fs_calculate_summar
 		count++;
 		if ((count == fs->super->s_blocks_per_group) ||
 		    (blk == fs->super->s_blocks_count-1)) {
-			fs->group_desc[group++].bg_free_blocks_count =
+			fs->group_desc[group].bg_free_blocks_count =
 				group_free;
+			fs->group_desc[group].bg_checksum =
+				ext2fs_group_desc_csum(fs->super,
+						       &fs->group_desc[group],
+						       group);
+			group++;
 			count = 0;
 			group_free = 0;
 		}
@@ -1597,8 +1613,13 @@ static errcode_t ext2fs_calculate_summar
 		count++;
 		if ((count == fs->super->s_inodes_per_group) ||
 		    (ino == fs->super->s_inodes_count)) {
-			fs->group_desc[group++].bg_free_inodes_count =
+			fs->group_desc[group].bg_free_inodes_count =
 				group_free;
+			fs->group_desc[group].bg_checksum =
+				ext2fs_group_desc_csum(fs->super,
+						       &fs->group_desc[group],
+						       group);
+			group++;
 			count = 0;
 			group_free = 0;
 		}

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2006-09-18 19:51 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-12 11:07 ext2/3 create large filesystem takes too much time; solutions Pavel Mironchik
2006-09-15 21:20 ` Theodore Tso
2006-09-16 14:56   ` Pavel Mironchik
2006-09-16 20:06     ` Theodore Tso
2006-09-17  7:57       ` Andreas Dilger
2006-09-18 19:51         ` Andreas Dilger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox