Whamcloud - gitweb
libext2fs: change ext4 on-disk layout to support metadata checksumming
authorDarrick J. Wong <djwong@us.ibm.com>
Mon, 30 Jul 2012 21:44:15 +0000 (17:44 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 30 Jul 2012 21:44:15 +0000 (17:44 -0400)
Define flags and extend ext4 structure definitions to support metadata
checksumming.  Ted Ts'o covered many of these fields in an earlier
patch, but there are more required changes to the disk layout.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
lib/blkid/probe.h
lib/ext2fs/ext2_ext_attr.h
lib/ext2fs/ext2_fs.h
lib/ext2fs/ext2fs.h
lib/ext2fs/ext3_extents.h
lib/ext2fs/tst_super_size.c

index 37e80ef..d6809e1 100644 (file)
@@ -110,6 +110,7 @@ struct ext2_super_block {
 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK       0x0020
 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE     0x0040
 #define EXT4_FEATURE_RO_COMPAT_QUOTA           0x0100
+#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM   0x0400
 
 /* for s_feature_incompat */
 #define EXT2_FEATURE_INCOMPAT_FILETYPE         0x0002
index ed548d1..bbb0aaa 100644 (file)
@@ -20,7 +20,9 @@ struct ext2_ext_attr_header {
        __u32   h_refcount;     /* reference count */
        __u32   h_blocks;       /* number of disk blocks used */
        __u32   h_hash;         /* hash value of all attributes */
-       __u32   h_reserved[4];  /* zero right now */
+       __u32   h_checksum;     /* crc32c(uuid+id+xattrs) */
+                               /* id = inum if refcount = 1, else blknum */
+       __u32   h_reserved[3];  /* zero right now */
 };
 
 struct ext2_ext_attr_entry {
index fb3f7cc..39cc534 100644 (file)
@@ -235,6 +235,13 @@ struct ext2_dx_countlimit {
        __u16 count;
 };
 
+/*
+ * This goes at the end of each htree block.
+ */
+struct ext2_dx_tail {
+       __u32 dt_reserved;
+       __u32 dt_checksum;      /* crc32c(uuid+inum+dxblock) */
+};
 
 /*
  * Macro-instructions used to manage group descriptors
@@ -464,6 +471,7 @@ struct ext2_inode_large {
 #define i_gid_low      i_gid
 #define i_uid_high     osd2.linux2.l_i_uid_high
 #define i_gid_high     osd2.linux2.l_i_gid_high
+#define i_checksum_lo  osd2.linux2.l_i_checksum_lo
 #else
 #if defined(__GNU__)
 
@@ -535,6 +543,9 @@ struct ext2_inode_large {
 #define ext4_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 #endif
 
+/* Metadata checksum algorithms */
+#define EXT2_CRC32C_CHKSUM             1
+
 /*
  * Structure of the super block
  */
@@ -620,7 +631,7 @@ struct ext2_super_block {
        __u64   s_mmp_block;            /* Block for multi-mount protection */
        __u32   s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
        __u8    s_log_groups_per_flex;  /* FLEX_BG group size */
-       __u8    s_reserved_char_pad;
+       __u8    s_checksum_type;        /* metadata checksum algorithm */
        __u16   s_reserved_pad;         /* Padding to next 32bits */
        __u64   s_kbytes_written;       /* nr of lifetime kilobytes written */
        __u32   s_snapshot_inum;        /* Inode number of active snapshot */
@@ -708,6 +719,11 @@ struct ext2_super_block {
 #define EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT    0x0080
 #define EXT4_FEATURE_RO_COMPAT_QUOTA           0x0100
 #define EXT4_FEATURE_RO_COMPAT_BIGALLOC                0x0200
+/*
+ * METADATA_CSUM implies GDT_CSUM.  When METADATA_CSUM is set, group
+ * descriptor checksums use the same algorithm as all other data
+ * structures' checksums.
+ */
 #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM   0x0400
 #define EXT4_FEATURE_RO_COMPAT_REPLICA         0x0800
 
@@ -784,6 +800,17 @@ struct ext2_dir_entry_2 {
 };
 
 /*
+ * This is a bogus directory entry at the end of each leaf block that
+ * records checksums.
+ */
+struct ext2_dir_entry_tail {
+       __u32   det_reserved_zero1;     /* Pretend to be unused */
+       __u16   det_rec_len;            /* 12 */
+       __u16   det_reserved_name_len;  /* 0xDE00, fake namelen/filetype */
+       __u32   det_checksum;           /* crc32c(uuid+inode+dirent) */
+};
+
+/*
  * Ext2 directory file types.  Only the low 3 bits are used.  The
  * other bits are reserved for now.
  */
@@ -799,6 +826,14 @@ struct ext2_dir_entry_2 {
 #define EXT2_FT_MAX            8
 
 /*
+ * Annoyingly, e2fsprogs always swab16s ext2_dir_entry.name_len, so we
+ * have to build ext2_dir_entry_tail with that assumption too.  This
+ * constant helps to build the dir_entry_tail to look like it has an
+ * "invalid" file type.
+ */
+#define EXT2_DIR_NAME_LEN_CSUM 0xDE00
+
+/*
  * EXT2_DIR_PAD defines the directory entries boundaries
  *
  * NOTE: It must be a multiple of 4
@@ -839,7 +874,8 @@ struct mmp_struct {
        char    mmp_bdevname[32];       /* Bdev which last updated MMP block */
        __u16   mmp_check_interval;     /* Changed mmp_check_interval */
        __u16   mmp_pad1;
-       __u32   mmp_pad2[227];
+       __u32   mmp_pad2[226];
+       __u32   mmp_checksum;           /* crc32c(uuid+mmp_block) */
 };
 
 /*
index 5746b4f..0728999 100644 (file)
@@ -185,6 +185,7 @@ typedef struct ext2_file *ext2_file_t;
 #define EXT2_FLAG_PRINT_PROGRESS       0x40000
 #define EXT2_FLAG_DIRECT_IO            0x80000
 #define EXT2_FLAG_SKIP_MMP             0x100000
+#define EXT2_FLAG_IGNORE_CSUM_ERRORS   0x200000
 
 /*
  * Special flag in the ext2 inode i_flag field that means that this is
index 88fabc9..4163436 100644 (file)
  */
 
 /*
+ * This is extent tail on-disk structure.
+ * All other extent structures are 12 bytes long.  It turns out that
+ * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which
+ * covers all valid ext4 block sizes.  Therefore, this tail structure can be
+ * crammed into the end of the block without having to rebalance the tree.
+ */
+struct ext3_extent_tail {
+       __u32   et_checksum;    /* crc32c(uuid+inum+extent_block) */
+};
+
+/*
  * this is extent on-disk structure
  * it's used at the bottom of the tree
  */
index 76e6e6f..d5d594b 100644 (file)
@@ -110,7 +110,7 @@ int main(int argc, char **argv)
        check_field(s_mmp_block, 8);
        check_field(s_raid_stripe_width, 4);
        check_field(s_log_groups_per_flex, 1);
-       check_field(s_reserved_char_pad, 1);
+       check_field(s_checksum_type, 1);
        check_field(s_reserved_pad, 2);
        check_field(s_kbytes_written, 8);
        check_field(s_snapshot_inum, 4);