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
<[EMAIL PROTECTED]>, 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.

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 {                                                           \
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 <[EMAIL PROTECTED]>
+ *
+ * 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;
                }

Reply via email to