All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 00/37] e2fsprogs: Add metadata checksumming
@ 2011-09-01  0:35 Darrick J. Wong
  2011-09-01  0:35 ` [PATCH 01/37] e2fsprogs: Read and write full-sized inodes Darrick J. Wong
                   ` (35 more replies)
  0 siblings, 36 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:35 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Hi all,

This patchset adds support in e2fsprogs for attaching crc32c checksums to most
of the ext4 metadata objects.  A full design document is on the ext4 wiki[1].
Please see the cover letter for the kernel patches for a more thorough summary
of this work.

Please have a look at the design document and patches, and please feel free to
suggest any changes.  I will be at LPC next week if anyone wishes to discuss,
debate, or protest.

--D

[1] https://ext4.wiki.kernel.org/index.php/Ext4_Metadata_Checksums

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

* [PATCH 01/37] e2fsprogs: Read and write full-sized inodes
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
@ 2011-09-01  0:35 ` Darrick J. Wong
  2011-09-03 18:05   ` Andreas Dilger
  2011-09-14 16:39   ` Ted Ts'o
  2011-09-01  0:35 ` [PATCH 02/37] libext2fs: Add metadata checksum flag Darrick J. Wong
                   ` (34 subsequent siblings)
  35 siblings, 2 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:35 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

As part of adding inode checksums, it is necessary for all e2fsprogs to read
and write full inodes so that checksums may be calculated correctly.  Since
struct ext2_inode_large is a superset of struct ext2_inode, replace the smaller
one with the larger one.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 debugfs/debugfs.c               |   28 ++++++++--------
 debugfs/debugfs.h               |   12 ++++---
 debugfs/dump.c                  |   12 +++----
 debugfs/htree.c                 |   10 +++---
 debugfs/icheck.c                |    2 +
 debugfs/logdump.c               |   13 ++++---
 debugfs/ls.c                    |    4 +-
 debugfs/lsdel.c                 |    2 +
 debugfs/ncheck.c                |    2 +
 debugfs/set_fields.c            |    2 +
 debugfs/util.c                  |    8 ++---
 doc/libext2fs.texinfo           |   12 +++----
 e2fsck/e2fsck.h                 |   23 +++++++------
 e2fsck/emptydir.c               |    2 +
 e2fsck/iscan.c                  |    2 +
 e2fsck/jfs_user.h               |    2 +
 e2fsck/journal.c                |    5 ++-
 e2fsck/message.c                |    2 +
 e2fsck/pass1.c                  |   35 ++++++++++----------
 e2fsck/pass1b.c                 |   10 +++---
 e2fsck/pass2.c                  |   10 +++---
 e2fsck/pass3.c                  |   10 +++---
 e2fsck/pass4.c                  |   11 ++++--
 e2fsck/problem.h                |    2 +
 e2fsck/rehash.c                 |    6 ++-
 e2fsck/scantest.c               |    2 +
 e2fsck/super.c                  |    6 ++-
 e2fsck/util.c                   |    8 ++---
 ext2ed/dir_com.c                |    2 +
 ext2ed/doc/ext2ed-design.sgml   |    6 ++-
 ext2ed/doc/ext2fs-overview.sgml |    2 +
 ext2ed/ext2.descriptors         |    2 +
 ext2ed/ext2ed.h                 |    4 +-
 ext2ed/file_com.c               |    2 +
 ext2ed/init.c                   |    2 +
 ext2ed/inode_com.c              |   18 +++++-----
 lib/e2p/ls.c                    |    2 +
 lib/ext2fs/bb_inode.c           |    2 +
 lib/ext2fs/blknum.c             |    8 ++---
 lib/ext2fs/block.c              |    2 +
 lib/ext2fs/bmap.c               |   16 +++++----
 lib/ext2fs/bmove.c              |    4 +-
 lib/ext2fs/expanddir.c          |    2 +
 lib/ext2fs/ext2_fs.h            |   47 ---------------------------
 lib/ext2fs/ext2fs.h             |   61 ++++++++++++++++++-----------------
 lib/ext2fs/ext2fsP.h            |    2 +
 lib/ext2fs/extent.c             |    6 ++-
 lib/ext2fs/fileio.c             |    8 ++---
 lib/ext2fs/i_block.c            |    7 ++--
 lib/ext2fs/initialize.c         |    2 +
 lib/ext2fs/inode.c              |   68 ++++++++++++++++++---------------------
 lib/ext2fs/inode_io.c           |    6 ++-
 lib/ext2fs/link.c               |    2 +
 lib/ext2fs/mkdir.c              |    4 +-
 lib/ext2fs/mkjournal.c          |    2 +
 lib/ext2fs/namei.c              |    2 +
 lib/ext2fs/punch.c              |   11 +++---
 lib/ext2fs/read_bb.c            |    2 +
 lib/ext2fs/res_gdt.c            |    2 +
 lib/ext2fs/swapfs.c             |   22 ++++++-------
 lib/ext2fs/tst_iscan.c          |    2 +
 lib/ext2fs/valid_blk.c          |    2 +
 misc/dumpe2fs.c                 |    2 +
 misc/e2image.c                  |    6 ++-
 misc/e2initrd_helper.c          |    2 +
 misc/mke2fs.c                   |    2 +
 misc/tune2fs.c                  |    4 +-
 resize/resize2fs.c              |   10 +++---
 68 files changed, 283 insertions(+), 318 deletions(-)


diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index e7d7436..94732b9 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -688,7 +688,7 @@ static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino,
 }
 
 void internal_dump_inode(FILE *out, const char *prefix,
-			 ext2_ino_t inode_num, struct ext2_inode *inode,
+			 ext2_ino_t inode_num, struct ext2_inode_large *inode,
 			 int do_dump_blocks)
 {
 	const char *i_type;
@@ -812,7 +812,7 @@ void internal_dump_inode(FILE *out, const char *prefix,
 	}
 }
 
-static void dump_inode(ext2_ino_t inode_num, struct ext2_inode *inode)
+static void dump_inode(ext2_ino_t inode_num, struct ext2_inode_large *inode)
 {
 	FILE	*out;
 
@@ -824,12 +824,12 @@ static void dump_inode(ext2_ino_t inode_num, struct ext2_inode *inode)
 void do_stat(int argc, char *argv[])
 {
 	ext2_ino_t	inode;
-	struct ext2_inode * inode_buf;
+	struct ext2_inode_large *inode_buf;
 
 	if (check_fs_open(argv[0]))
 		return;
 
-	inode_buf = (struct ext2_inode *)
+	inode_buf = (struct ext2_inode_large *)
 			malloc(EXT2_INODE_SIZE(current_fs->super));
 	if (!inode_buf) {
 		fprintf(stderr, "do_stat: can't allocate buffer\n");
@@ -854,7 +854,7 @@ void do_stat(int argc, char *argv[])
 
 void do_dump_extents(int argc, char **argv)
 {
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	ext2_ino_t	ino;
 	FILE		*out;
 	int		c, flags = 0;
@@ -959,7 +959,7 @@ void do_chroot(int argc, char *argv[])
 void do_clri(int argc, char *argv[])
 {
 	ext2_ino_t inode;
-	struct ext2_inode inode_buf;
+	struct ext2_inode_large inode_buf;
 
 	if (common_inode_args_process(argc, argv, &inode, CHECK_FS_RW))
 		return;
@@ -1135,7 +1135,7 @@ static void modify_u32(char *com, const char *prompt,
 
 void do_modify_inode(int argc, char *argv[])
 {
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	ext2_ino_t	inode_num;
 	int 		i;
 	unsigned char	*frag, *fsize;
@@ -1293,7 +1293,7 @@ static int ext2_file_type(unsigned int mode)
 static void make_link(char *sourcename, char *destname)
 {
 	ext2_ino_t	ino;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	int		retval;
 	ext2_ino_t	dir;
 	char		*dest, *cp, *base_name;
@@ -1369,7 +1369,7 @@ static int mark_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
 void do_undel(int argc, char *argv[])
 {
 	ext2_ino_t	ino;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 
 	if (common_args_process(argc, argv, 2, 3, "undelete",
 				"<inode_num> [dest_name]",
@@ -1577,7 +1577,7 @@ void do_write(int argc, char *argv[])
 	struct stat	statbuf;
 	ext2_ino_t	newfile;
 	errcode_t	retval;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 
 	if (common_args_process(argc, argv, 3, 3, "write",
 				"<native file> <new file>", CHECK_FS_RW))
@@ -1654,7 +1654,7 @@ void do_mknod(int argc, char *argv[])
 	unsigned long	mode, major, minor;
 	ext2_ino_t	newfile;
 	errcode_t 	retval;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	int		filetype, nr;
 
 	if (check_fs_open(argv[0]))
@@ -1792,7 +1792,7 @@ static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
 
 static void kill_file_by_inode(ext2_ino_t inode)
 {
-	struct ext2_inode inode_buf;
+	struct ext2_inode_large inode_buf;
 
 	if (debugfs_read_inode(inode, &inode_buf, 0))
 		return;
@@ -1824,7 +1824,7 @@ void do_rm(int argc, char *argv[])
 {
 	int retval;
 	ext2_ino_t inode_num;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 
 	if (common_args_process(argc, argv, 2, 2, "rm",
 				"<filename>", CHECK_FS_RW))
@@ -1885,7 +1885,7 @@ void do_rmdir(int argc, char *argv[])
 {
 	int retval;
 	ext2_ino_t inode_num;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	struct rd_struct rds;
 
 	if (common_args_process(argc, argv, 2, 2, "rmdir",
diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
index 0ea2474..d65a371 100644
--- a/debugfs/debugfs.h
+++ b/debugfs/debugfs.h
@@ -44,13 +44,15 @@ extern int common_inode_args_process(int argc, char *argv[],
 				     ext2_ino_t *inode, int flags);
 extern int common_block_args_process(int argc, char *argv[],
 				     blk64_t *block, blk64_t *count);
-extern int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode,
+extern int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
 			      const char *cmd);
-extern int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode,
+extern int debugfs_read_inode_full(ext2_ino_t ino,
+				   struct ext2_inode_large *inode,
 				   const char *cmd, int bufsize);
-extern int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode * inode,
+extern int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
 			       const char *cmd);
-extern int debugfs_write_new_inode(ext2_ino_t ino, struct ext2_inode * inode,
+extern int debugfs_write_new_inode(ext2_ino_t ino,
+				   struct ext2_inode_large *inode,
 				   const char *cmd);
 
 /* ss command functions */
@@ -87,7 +89,7 @@ extern void do_dump_unused(int argc, char **argv);
 
 /* debugfs.c */
 extern void internal_dump_inode(FILE *, const char *, ext2_ino_t,
-				struct ext2_inode *, int);
+				struct ext2_inode_large *, int);
 
 extern void do_dirty_filesys(int argc, char **argv);
 extern void do_open_filesys(int argc, char **argv);
diff --git a/debugfs/dump.c b/debugfs/dump.c
index 4cf0752..fe7e7f4 100644
--- a/debugfs/dump.c
+++ b/debugfs/dump.c
@@ -66,7 +66,7 @@ static mode_t mode_xlate(__u16 lmode)
 	return mode;
 }
 
-static void fix_perms(const char *cmd, const struct ext2_inode *inode,
+static void fix_perms(const char *cmd, const struct ext2_inode_large *inode,
 		      int fd, const char *name)
 {
 	struct utimbuf ut;
@@ -103,7 +103,7 @@ static void dump_file(const char *cmdname, ext2_ino_t ino, int fd,
 		      int preserve, char *outname)
 {
 	errcode_t retval;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	char 		buf[8192];
 	ext2_file_t	e2_file;
 	int		nbytes;
@@ -187,7 +187,7 @@ void do_dump(int argc, char **argv)
 	return;
 }
 
-static void rdump_symlink(ext2_ino_t ino, struct ext2_inode *inode,
+static void rdump_symlink(ext2_ino_t ino, struct ext2_inode_large *inode,
 			  const char *fullname)
 {
 	ext2_file_t e2_file;
@@ -241,7 +241,7 @@ errout:
 
 static int rdump_dirent(struct ext2_dir_entry *, int, int, char *, void *);
 
-static void rdump_inode(ext2_ino_t ino, struct ext2_inode *inode,
+static void rdump_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
 			const char *name, const char *dumproot)
 {
 	char *fullname;
@@ -298,7 +298,7 @@ static int rdump_dirent(struct ext2_dir_entry *dirent,
 	char name[EXT2_NAME_LEN + 1];
 	int thislen;
 	const char *dumproot = private;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 
 	thislen = ((dirent->name_len & 0xFF) < EXT2_NAME_LEN
 		   ? (dirent->name_len & 0xFF) : EXT2_NAME_LEN);
@@ -316,7 +316,7 @@ static int rdump_dirent(struct ext2_dir_entry *dirent,
 void do_rdump(int argc, char **argv)
 {
 	ext2_ino_t ino;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	struct stat st;
 	int i;
 	char *p;
diff --git a/debugfs/htree.c b/debugfs/htree.c
index b829e25..d72b996 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -29,7 +29,7 @@ extern char *optarg;
 static FILE *pager;
 
 static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
-				 struct ext2_inode *inode,
+				 struct ext2_inode_large *inode,
 				 struct ext2_dx_root_info * rootnode,
 				 blk64_t blk, char *buf)
 {
@@ -107,13 +107,13 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
 
 
 static void htree_dump_int_block(ext2_filsys fs, ext2_ino_t ino,
-				 struct ext2_inode *inode,
+				 struct ext2_inode_large *inode,
 				 struct ext2_dx_root_info * rootnode,
 				 blk64_t blk, char *buf, int level);
 
 
 static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
-				struct ext2_inode *inode,
+				struct ext2_inode_large *inode,
 				struct ext2_dx_root_info * rootnode,
 				struct ext2_dx_entry *ent,
 				char *buf, int level)
@@ -156,7 +156,7 @@ static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
 }
 
 static void htree_dump_int_block(ext2_filsys fs, ext2_ino_t ino,
-				 struct ext2_inode *inode,
+				 struct ext2_inode_large *inode,
 				 struct ext2_dx_root_info * rootnode,
 				 blk64_t blk, char *buf, int level)
 {
@@ -196,7 +196,7 @@ errout:
 void do_htree_dump(int argc, char *argv[])
 {
 	ext2_ino_t	ino;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	blk64_t		blk;
 	char		*buf = NULL;
 	struct 		ext2_dx_root_info  *rootnode;
diff --git a/debugfs/icheck.c b/debugfs/icheck.c
index 729ac93..d1aaefe 100644
--- a/debugfs/icheck.c
+++ b/debugfs/icheck.c
@@ -59,7 +59,7 @@ void do_icheck(int argc, char **argv)
 	int			i;
 	ext2_inode_scan		scan = 0;
 	ext2_ino_t		ino;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	errcode_t		retval;
 	char			*block_buf;
 
diff --git a/debugfs/logdump.c b/debugfs/logdump.c
index d1e64fd..dfb243e 100644
--- a/debugfs/logdump.c
+++ b/debugfs/logdump.c
@@ -83,7 +83,7 @@ void do_logdump(int argc, char **argv)
 	int		journal_fd = 0;
 	int		use_sb = 0;
 	ext2_ino_t	journal_inum;
-	struct ext2_inode journal_inode;
+	struct ext2_inode_large journal_inode;
 	ext2_file_t 	journal_file;
 	char		*tmp;
 	struct journal_source journal_source;
@@ -154,13 +154,13 @@ void do_logdump(int argc, char **argv)
 		group_offset = ((inode_to_dump - 1)
 				% es->s_inodes_per_group);
 		inodes_per_block = (current_fs->blocksize
-				    / sizeof(struct ext2_inode));
+				    / EXT2_GOOD_OLD_INODE_SIZE);
 
 		inode_block_to_dump =
 			ext2fs_inode_table_loc(current_fs, inode_group) +
 			(group_offset / inodes_per_block);
 		inode_offset_to_dump = ((group_offset % inodes_per_block)
-					* sizeof(struct ext2_inode));
+					* EXT2_GOOD_OLD_INODE_SIZE);
 		printf("Inode %u is at group %u, block %u, offset %u\n",
 		       inode_to_dump, inode_group,
 		       inode_block_to_dump, inode_offset_to_dump);
@@ -206,7 +206,8 @@ void do_logdump(int argc, char **argv)
 					"no journal backup in super block\n");
 				goto errout;
 			}
-			memset(&journal_inode, 0, sizeof(struct ext2_inode));
+			memset(&journal_inode, 0,
+			       sizeof(struct ext2_inode_large));
 			memcpy(&journal_inode.i_block[0], es->s_jnl_blocks,
 			       EXT2_N_BLOCKS*4);
 			journal_inode.i_size_high = es->s_jnl_blocks[15];
@@ -630,13 +631,13 @@ static void dump_metadata_block(FILE *out_file, struct journal_source *source,
 	}
 
 	if (fs_blocknr == inode_block_to_dump) {
-		struct ext2_inode *inode;
+		struct ext2_inode_large *inode;
 		int first, prev, this, start_extent, i;
 
 		fprintf(out_file, "    (inode block for inode %u):\n",
 			inode_to_dump);
 
-		inode = (struct ext2_inode *) (buf + inode_offset_to_dump);
+		inode = (struct ext2_inode_large *)(buf + inode_offset_to_dump);
 		internal_dump_inode(out_file, "    ", inode_to_dump, inode, 0);
 
 		/* Dump out the direct/indirect blocks here:
diff --git a/debugfs/ls.c b/debugfs/ls.c
index 8e019d2..9977a79 100644
--- a/debugfs/ls.c
+++ b/debugfs/ls.c
@@ -49,7 +49,7 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
 			 char	*buf EXT2FS_ATTR((unused)),
 			 void	*private)
 {
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	ext2_ino_t		ino;
 	struct tm		*tm_p;
 	time_t			modtime;
@@ -94,7 +94,7 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
 				tm_p->tm_min);
 		} else {
 			strcpy(datestr, "                 ");
-			memset(&inode, 0, sizeof(struct ext2_inode));
+			memset(&inode, 0, sizeof(struct ext2_inode_large));
 		}
 		fprintf(ls->f, "%c%6u%c %6o (%d)  %5d  %5d   ", lbr, ino, rbr,
 			inode.i_mode, dirent->name_len >> 8,
diff --git a/debugfs/lsdel.c b/debugfs/lsdel.c
index ba7a90f..4126dac 100644
--- a/debugfs/lsdel.c
+++ b/debugfs/lsdel.c
@@ -77,7 +77,7 @@ void do_lsdel(int argc, char **argv)
 	int			num_delarray, max_delarray;
 	ext2_inode_scan		scan = 0;
 	ext2_ino_t		ino;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	errcode_t		retval;
 	char			*block_buf;
 	int			i;
diff --git a/debugfs/ncheck.c b/debugfs/ncheck.c
index a366281..2de66ae 100644
--- a/debugfs/ncheck.c
+++ b/debugfs/ncheck.c
@@ -56,7 +56,7 @@ void do_ncheck(int argc, char **argv)
 	int			i;
 	ext2_inode_scan		scan = 0;
 	ext2_ino_t		ino;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	errcode_t		retval;
 	char			*tmp;
 
diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
index ac6bc25..1bc6410 100644
--- a/debugfs/set_fields.c
+++ b/debugfs/set_fields.c
@@ -40,7 +40,7 @@
 #include "e2p/e2p.h"
 
 static struct ext2_super_block set_sb;
-static struct ext2_inode set_inode;
+static struct ext2_inode_large set_inode;
 static struct ext2_group_desc set_gd;
 static dgrp_t set_bg;
 static ext2_ino_t set_ino;
diff --git a/debugfs/util.c b/debugfs/util.c
index c3ac6f8..ff1f878 100644
--- a/debugfs/util.c
+++ b/debugfs/util.c
@@ -375,7 +375,7 @@ int common_block_args_process(int argc, char *argv[],
 	return 0;
 }
 
-int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode,
+int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode_large *inode,
 			const char *cmd, int bufsize)
 {
 	int retval;
@@ -388,7 +388,7 @@ int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode,
 	return 0;
 }
 
-int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode,
+int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
 			const char *cmd)
 {
 	int retval;
@@ -401,7 +401,7 @@ int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode,
 	return 0;
 }
 
-int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode * inode,
+int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
 			const char *cmd)
 {
 	int retval;
@@ -414,7 +414,7 @@ int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode * inode,
 	return 0;
 }
 
-int debugfs_write_new_inode(ext2_ino_t ino, struct ext2_inode * inode,
+int debugfs_write_new_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
 			    const char *cmd)
 {
 	int retval;
diff --git a/doc/libext2fs.texinfo b/doc/libext2fs.texinfo
index d607396..5785f50 100644
--- a/doc/libext2fs.texinfo
+++ b/doc/libext2fs.texinfo
@@ -426,7 +426,7 @@ opened via inode numbers instead of via pathnames.  To resolve a
 pathname to an inode number, use the function @code{ext2fs_namei} or to
 create a new file, use @code{ext2fs_new_inode} and @code{ext2fs_link}.
 
-@deftypefun errcode_t ext2fs_file_open2 (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode *@var{inode}, int @var{flags}, ext2_file_t *@var{ret})
+@deftypefun errcode_t ext2fs_file_open2 (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode_large *@var{inode}, int @var{flags}, ext2_file_t *@var{ret})
 @deftypefunx errcode_t ext2fs_file_open (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, int @var{flags}, ext2_file_t *@var{ret})
 
 Opens a file identified by inode number @var{ino} in filesystem @var{fs}
@@ -538,11 +538,11 @@ Return the size of the file @var{file}.
 @comment  node-name,  next,  previous,  up
 @subsection Reading and writing inodes
 
-@deftypefun errcode_t ext2fs_read_inode (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode *@var{inode})
+@deftypefun errcode_t ext2fs_read_inode (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode_large *@var{inode})
 Read the inode number @var{ino} into @var{inode}.
 @end deftypefun
 
-@deftypefun errcode_t ext2fs_write_inode (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode *@var{inode})
+@deftypefun errcode_t ext2fs_write_inode (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode_large *@var{inode})
 Write @var{inode} to inode @var{ino}.
 @end deftypefun
 
@@ -569,7 +569,7 @@ suitable default value will be used.
 Release the memory associated with @var{scan} and invalidate it.
 @end deftypefun
 
-@deftypefun errcode_t ext2fs_get_next_inode (ext2_inode_scan @var{scan}, ext2_ino_t *@var{ino}, struct ext2_inode *@var{inode})
+@deftypefun errcode_t ext2fs_get_next_inode (ext2_inode_scan @var{scan}, ext2_ino_t *@var{ino}, struct ext2_inode_large *@var{inode})
 
 This function returns the next inode from the filesystem; the inode
 number of the inode is stored in @var{ino}, and the inode is stored in
@@ -712,7 +712,7 @@ inode structure.
 Returns 0 if @var{ino} is a directory, and @code{ENOTDIR} if it is not.
 @end deftypefun
 
-@deftypefun int ext2fs_inode_has_valid_blocks (struct ext2_inode *@var{inode})
+@deftypefun int ext2fs_inode_has_valid_blocks (struct ext2_inode_large *@var{inode})
 
 Returns 1 if the inode's block entries actually valid block entries, and
 0 if not.  Inodes which represent devices and fast symbolic links do not
@@ -1281,7 +1281,7 @@ intended for debugging and testing use only.
 @deftypefun void ext2fs_swap_group_desc (struct ext2_group_desc *@var{gdp})
 @end deftypefun
 
-@deftypefun void ext2fs_swap_inode (ext2_filsys @var{fs}, struct ext2_inode *@var{to}, struct ext2_inode *@var{from}, int @var{hostorder})
+@deftypefun void ext2fs_swap_inode (ext2_filsys @var{fs}, struct ext2_inode_large *@var{to}, struct ext2_inode_large *@var{from}, int @var{hostorder})
 @end deftypefun
 
 @deftypefun int ext2fs_native_flag (void)
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index b4a1a88..d515a9d 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -267,7 +267,7 @@ struct e2fsck_struct {
 	 * For pass1_check_directory and pass1_get_blocks
 	 */
 	ext2_ino_t stashed_ino;
-	struct ext2_inode *stashed_inode;
+	struct ext2_inode_large *stashed_inode;
 
 	/*
 	 * Location of the lost and found directory
@@ -446,11 +446,12 @@ extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags,
 				    ext2_icount_t *ret);
 extern void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
 extern int e2fsck_pass1_check_device_inode(ext2_filsys fs,
-					   struct ext2_inode *inode);
+					   struct ext2_inode_large *inode);
 extern int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
-				      struct ext2_inode *inode, char *buf);
+				      struct ext2_inode_large *inode,
+				      char *buf);
 extern void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
-			       struct ext2_inode *inode, int restart_flag,
+			       struct ext2_inode_large *inode, int restart_flag,
 			       const char *source);
 
 /* pass2.c */
@@ -505,17 +506,19 @@ extern void init_resource_track(struct resource_track *track,
 #define print_resource_track(ctx, desc, track, channel) do { } while (0)
 #define init_resource_track(track, channel) do { } while (0)
 #endif
-extern int inode_has_valid_blocks(struct ext2_inode *inode);
+extern int inode_has_valid_blocks(struct ext2_inode_large *inode);
 extern void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
-			      struct ext2_inode * inode, const char * proc);
+			      struct ext2_inode_large *inode,
+			      const char *proc);
 extern void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
-				   struct ext2_inode *inode,
+				   struct ext2_inode_large *inode,
 				   const int bufsize, const char *proc);
 extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
-			       struct ext2_inode * inode, const char * proc);
+			       struct ext2_inode_large *inode,
+			       const char *proc);
 extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
-                               struct ext2_inode * inode, int bufsize,
-                               const char *proc);
+				    struct ext2_inode_large *inode, int bufsize,
+				    const char *proc);
 #ifdef MTRACE
 extern void mtrace_print(char *mesg);
 #endif
diff --git a/e2fsck/emptydir.c b/e2fsck/emptydir.c
index cf9b521..2ae5dcc 100644
--- a/e2fsck/emptydir.c
+++ b/e2fsck/emptydir.c
@@ -24,7 +24,7 @@ struct empty_dir_info_struct {
 	ext2fs_inode_bitmap dir_map;
 	char *block_buf;
 	ext2_ino_t ino;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	blk64_t	logblk;
 	blk64_t	freed_blocks;
 };
diff --git a/e2fsck/iscan.c b/e2fsck/iscan.c
index 84e2cc1..8cae736 100644
--- a/e2fsck/iscan.c
+++ b/e2fsck/iscan.c
@@ -99,7 +99,7 @@ int main (int argc, char *argv[])
 	ext2_filsys	fs;
 	ext2_ino_t	ino;
 	__u32	num_inodes = 0;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	ext2_inode_scan	scan;
 
 	init_resource_track(&global_rtrack);
diff --git a/e2fsck/jfs_user.h b/e2fsck/jfs_user.h
index 2bb71c3..2fada54 100644
--- a/e2fsck/jfs_user.h
+++ b/e2fsck/jfs_user.h
@@ -28,7 +28,7 @@ struct buffer_head {
 struct inode {
 	e2fsck_t	i_ctx;
 	ext2_ino_t	i_ino;
-	struct ext2_inode i_ext2;
+	struct ext2_inode_large i_ext2;
 };
 
 struct kdev_s {
diff --git a/e2fsck/journal.c b/e2fsck/journal.c
index 6d350ee..0e2816f 100644
--- a/e2fsck/journal.c
+++ b/e2fsck/journal.c
@@ -285,7 +285,8 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
 			if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
 			    tried_backup_jnl)
 				goto errout;
-			memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
+			memset(&j_inode->i_ext2, 0,
+			       sizeof(struct ext2_inode_large));
 			memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
 			       EXT2_N_BLOCKS*4);
 			j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15];
@@ -912,7 +913,7 @@ void e2fsck_move_ext3_journal(e2fsck_t ctx)
 {
 	struct ext2_super_block *sb = ctx->fs->super;
 	struct problem_context	pctx;
-	struct ext2_inode 	inode;
+	struct ext2_inode_large	inode;
 	ext2_filsys		fs = ctx->fs;
 	ext2_ino_t		ino;
 	errcode_t		retval;
diff --git a/e2fsck/message.c b/e2fsck/message.c
index c456752..753dd26 100644
--- a/e2fsck/message.c
+++ b/e2fsck/message.c
@@ -261,7 +261,7 @@ static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
 static _INLINE_ void expand_inode_expression(ext2_filsys fs, char ch,
 					     struct problem_context *ctx)
 {
-	struct ext2_inode	*inode;
+	struct ext2_inode_large	*inode;
 	struct ext2_inode_large	*large_inode;
 
 	if (!ctx || !ctx->inode)
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index fe5dd9b..ba17b30 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -86,7 +86,7 @@ struct process_block_struct {
 	e2_blkcnt_t	last_db_block;
 	int		num_illegal_blocks;
 	blk64_t		previous_block;
-	struct ext2_inode *inode;
+	struct ext2_inode_large *inode;
 	struct problem_context *pctx;
 	ext2fs_block_bitmap fs_meta_blocks;
 	e2fsck_t	ctx;
@@ -94,7 +94,7 @@ struct process_block_struct {
 
 struct process_inode_block {
 	ext2_ino_t ino;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 };
 
 struct scan_callback_struct {
@@ -130,7 +130,7 @@ static void unwind_pass1(ext2_filsys fs EXT2FS_ATTR((unused)))
  * zero.
  */
 int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
-				    struct ext2_inode *inode)
+				    struct ext2_inode_large *inode)
 {
 	int	i;
 
@@ -165,7 +165,7 @@ int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
  * checks out, 0 if not.
  */
 int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
-			       struct ext2_inode *inode, char *buf)
+			       struct ext2_inode_large *inode, char *buf)
 {
 	unsigned int len;
 	int i;
@@ -254,7 +254,7 @@ static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
  */
 static void check_size(e2fsck_t ctx, struct problem_context *pctx)
 {
-	struct ext2_inode *inode = pctx->inode;
+	struct ext2_inode_large *inode = pctx->inode;
 
 	if (EXT2_I_SIZE(inode) == 0)
 		return;
@@ -400,7 +400,7 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
 static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
 				char *buf)
 {
-	struct ext2_inode *inode = pctx->inode;
+	struct ext2_inode_large *inode = pctx->inode;
 	struct ext2_dir_entry 	*dirent;
 	const char		*old_op;
 	errcode_t		retval;
@@ -546,7 +546,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 	__u64	max_sizes;
 	ext2_filsys fs = ctx->fs;
 	ext2_ino_t	ino;
-	struct ext2_inode *inode;
+	struct ext2_inode_large *inode;
 	ext2_inode_scan	scan;
 	char		*block_buf;
 #ifdef RESOURCE_TRACK
@@ -637,8 +637,9 @@ void e2fsck_pass1(e2fsck_t ctx)
 		return;
 	}
 	inode_size = EXT2_INODE_SIZE(fs->super);
-	inode = (struct ext2_inode *)
-		e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
+	if (sizeof(struct ext2_inode_large) > inode_size)
+		inode_size = sizeof(struct ext2_inode_large);
+	inode = e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
 
 	inodes_to_process = (struct process_inode_block *)
 		e2fsck_allocate_memory(ctx,
@@ -1212,7 +1213,7 @@ static errcode_t scan_callback(ext2_filsys fs,
 static void process_inodes(e2fsck_t ctx, char *block_buf)
 {
 	int			i;
-	struct ext2_inode	*old_stashed_inode;
+	struct ext2_inode_large	*old_stashed_inode;
 	ext2_ino_t		old_stashed_ino;
 	const char		*old_operation;
 	char			buf[80];
@@ -1421,7 +1422,7 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
 {
 	ext2_filsys fs = ctx->fs;
 	ext2_ino_t	ino = pctx->ino;
-	struct ext2_inode *inode = pctx->inode;
+	struct ext2_inode_large *inode = pctx->inode;
 	blk64_t		blk;
 	char *		end;
 	struct ext2_ext_attr_header *header;
@@ -1599,7 +1600,7 @@ clear_extattr:
 
 /* Returns 1 if bad htree, 0 if OK */
 static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
-			ext2_ino_t ino, struct ext2_inode *inode,
+			ext2_ino_t ino, struct ext2_inode_large *inode,
 			char *block_buf)
 {
 	struct ext2_dx_root_info	*root;
@@ -1656,7 +1657,7 @@ static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
 }
 
 void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
-			struct ext2_inode *inode, int restart_flag,
+			struct ext2_inode_large *inode, int restart_flag,
 			const char *source)
 {
 	inode->i_flags = 0;
@@ -1841,7 +1842,7 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
 				 struct process_block_struct *pb)
 {
 	struct ext2_extent_info info;
-	struct ext2_inode	*inode = pctx->inode;
+	struct ext2_inode_large	*inode = pctx->inode;
 	ext2_extent_handle_t	ehandle;
 	ext2_filsys		fs = ctx->fs;
 	ext2_ino_t		ino = pctx->ino;
@@ -1885,7 +1886,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 	ext2_filsys fs = ctx->fs;
 	struct process_block_struct pb;
 	ext2_ino_t	ino = pctx->ino;
-	struct ext2_inode *inode = pctx->inode;
+	struct ext2_inode_large *inode = pctx->inode;
 	int		bad_size = 0;
 	int		dirty_inode = 0;
 	int		extent_fs;
@@ -2671,7 +2672,7 @@ static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
 }
 
 static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
-				  struct ext2_inode *inode)
+				  struct ext2_inode_large *inode)
 {
 	e2fsck_t ctx = (e2fsck_t) fs->priv_data;
 
@@ -2682,7 +2683,7 @@ static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
 }
 
 static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
-			    struct ext2_inode *inode)
+			    struct ext2_inode_large *inode)
 {
 	e2fsck_t ctx = (e2fsck_t) fs->priv_data;
 
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
index 12a03b0..efa68c7 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -78,7 +78,7 @@ struct dup_cluster {
 struct dup_inode {
 	ext2_ino_t		dir;
 	int			num_dupblocks;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	struct cluster_el	*cluster_list;
 };
 
@@ -117,7 +117,7 @@ static int dict_int_cmp(const void *a, const void *b)
  * Add a duplicate block record
  */
 static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk64_t cluster,
-		     struct ext2_inode *inode)
+		     struct ext2_inode_large *inode)
 {
 	dnode_t	*n;
 	struct dup_cluster	*db;
@@ -258,7 +258,7 @@ struct process_block_struct {
 	e2fsck_t	ctx;
 	ext2_ino_t	ino;
 	int		dup_blocks;
-	struct ext2_inode *inode;
+	struct ext2_inode_large *inode;
 	struct problem_context *pctx;
 };
 
@@ -266,7 +266,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
 {
 	ext2_filsys fs = ctx->fs;
 	ext2_ino_t ino;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	ext2_inode_scan	scan;
 	struct process_block_struct pb;
 	struct problem_context pctx;
@@ -606,7 +606,7 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
 {
 	ext2_filsys fs = ctx->fs;
 	struct process_block_struct pb;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	struct problem_context	pctx;
 	unsigned int		count;
 
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 2863699..9241a07 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -479,7 +479,7 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
 {
 	int	filetype = dirent->name_len >> 8;
 	int	should_be = EXT2_FT_UNKNOWN;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 
 	if (!(ctx->fs->super->s_feature_incompat &
 	      EXT2_FEATURE_INCOMPAT_FILETYPE)) {
@@ -1178,7 +1178,7 @@ static int deallocate_inode_block(ext2_filsys fs,
 static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
 {
 	ext2_filsys fs = ctx->fs;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	struct problem_context	pctx;
 	__u32			count;
 
@@ -1237,7 +1237,7 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
  */
 static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
 {
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 
 	e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
 	inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
@@ -1251,7 +1251,7 @@ extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
 				    ext2_ino_t ino, char *buf)
 {
 	ext2_filsys fs = ctx->fs;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	int			inode_modified = 0;
 	int			not_fixed = 0;
 	unsigned char		*frag, *fsize;
@@ -1404,7 +1404,7 @@ static int allocate_dir_block(e2fsck_t ctx,
 	ext2_filsys fs = ctx->fs;
 	blk64_t			blk;
 	char			*block;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 
 	if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
 		return 1;
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index c067164..2330aab 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -142,7 +142,7 @@ static void check_root(e2fsck_t ctx)
 {
 	ext2_filsys fs = ctx->fs;
 	blk64_t			blk;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	char *			block;
 	struct problem_context	pctx;
 
@@ -357,7 +357,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
 	ext2_ino_t			ino;
 	blk64_t			blk;
 	errcode_t		retval;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	char *			block;
 	static const char	name[] = "lost+found";
 	struct 	problem_context	pctx;
@@ -503,7 +503,7 @@ int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
 	errcode_t	retval;
 	char		name[80];
 	struct problem_context	pctx;
-	struct ext2_inode 	inode;
+	struct ext2_inode_large	inode;
 	int		file_type = 0;
 
 	clear_problem_context(&pctx);
@@ -552,7 +552,7 @@ errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
 {
 	ext2_filsys fs = ctx->fs;
 	errcode_t		retval;
-	struct ext2_inode 	inode;
+	struct ext2_inode_large	inode;
 
 	if (!ino)
 		return 0;
@@ -753,7 +753,7 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
 	ext2_filsys fs = ctx->fs;
 	errcode_t	retval;
 	struct expand_dir_struct es;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 
 	if (!(fs->flags & EXT2_FLAG_RW))
 		return EXT2_ET_RO_FILSYS;
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index 695612b..566854f 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -25,7 +25,7 @@
  * rest of the pass 4 tests.
  */
 static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
-			    struct ext2_inode *inode)
+			    struct ext2_inode_large *inode)
 {
 	ext2_filsys fs = ctx->fs;
 	struct problem_context	pctx;
@@ -90,7 +90,7 @@ void e2fsck_pass4(e2fsck_t ctx)
 {
 	ext2_filsys fs = ctx->fs;
 	ext2_ino_t	i;
-	struct ext2_inode	*inode;
+	struct ext2_inode_large	*inode;
 #ifdef RESOURCE_TRACK
 	struct resource_track	rtrack;
 #endif
@@ -98,6 +98,7 @@ void e2fsck_pass4(e2fsck_t ctx)
 	__u16	link_count, link_counted;
 	char	*buf = 0;
 	int	group, maxgroup;
+	int	inode_size;
 
 	init_resource_track(&rtrack, ctx->fs->io);
 
@@ -116,8 +117,10 @@ void e2fsck_pass4(e2fsck_t ctx)
 		if ((ctx->progress)(ctx, 4, 0, maxgroup))
 			return;
 
-	inode = e2fsck_allocate_memory(ctx, EXT2_INODE_SIZE(fs->super),
-				       "scratch inode");
+	inode_size = EXT2_INODE_SIZE(fs->super);
+	if (sizeof(struct ext2_inode_large) > inode_size)
+		inode_size = sizeof(struct ext2_inode_large);
+	inode = e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
 
 	/* Protect loop from wrap-around if s_inodes_count maxed */
 	for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) {
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 8379e0c..a4d96ae 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -14,7 +14,7 @@ typedef __u32 problem_t;
 struct problem_context {
 	errcode_t	errcode;
 	ext2_ino_t ino, ino2, dir;
-	struct ext2_inode *inode;
+	struct ext2_inode_large *inode;
 	struct ext2_dir_entry *dirent;
 	blk64_t	blk, blk2;
 	e2_blkcnt_t	blkcount;
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index e8af323..1263f56 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -53,7 +53,7 @@
 
 struct fill_dir_struct {
 	char *buf;
-	struct ext2_inode *inode;
+	struct ext2_inode_large *inode;
 	int err;
 	e2fsck_t ctx;
 	struct hash_entry *harray;
@@ -670,7 +670,7 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
 {
 	struct write_dir_struct wd;
 	errcode_t	retval;
-	struct ext2_inode 	inode;
+	struct ext2_inode_large	inode;
 
 	retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
 	if (retval)
@@ -704,7 +704,7 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
 {
 	ext2_filsys 		fs = ctx->fs;
 	errcode_t		retval;
-	struct ext2_inode 	inode;
+	struct ext2_inode_large	inode;
 	char			*dir_buf = 0;
 	struct fill_dir_struct	fd;
 	struct out_dir		outdir;
diff --git a/e2fsck/scantest.c b/e2fsck/scantest.c
index ed586b1..01b243d 100644
--- a/e2fsck/scantest.c
+++ b/e2fsck/scantest.c
@@ -95,7 +95,7 @@ int main (int argc, char *argv[])
 	ext2_filsys	fs;
 	ext2_inode_scan	scan;
 	ext2_ino_t	ino;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 
 	printf(_("size of inode=%d\n"), sizeof(inode));
 
diff --git a/e2fsck/super.c b/e2fsck/super.c
index a61eb33..28f041d 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -151,7 +151,7 @@ static int release_inode_block(ext2_filsys fs,
  * not deleted.
  */
 static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
-				struct ext2_inode *inode, char *block_buf,
+				struct ext2_inode_large *inode, char *block_buf,
 				struct problem_context *pctx)
 {
 	struct process_block_struct 	pb;
@@ -226,7 +226,7 @@ static int release_orphan_inodes(e2fsck_t ctx)
 {
 	ext2_filsys fs = ctx->fs;
 	ext2_ino_t	ino, next_ino;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	struct problem_context pctx;
 	char *block_buf;
 
@@ -308,7 +308,7 @@ return_abort:
 void check_resize_inode(e2fsck_t ctx)
 {
 	ext2_filsys fs = ctx->fs;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	struct problem_context	pctx;
 	int		i, gdt_off, ind_off;
 	dgrp_t		j;
diff --git a/e2fsck/util.c b/e2fsck/util.c
index fb9a87a..22e06c2 100644
--- a/e2fsck/util.c
+++ b/e2fsck/util.c
@@ -381,7 +381,7 @@ void print_resource_track(e2fsck_t ctx, const char *desc,
 #endif /* RESOURCE_TRACK */
 
 void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
-			      struct ext2_inode * inode, const char *proc)
+			      struct ext2_inode_large *inode, const char *proc)
 {
 	int retval;
 
@@ -394,7 +394,7 @@ void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
 }
 
 void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
-			    struct ext2_inode *inode, int bufsize,
+			    struct ext2_inode_large *inode, int bufsize,
 			    const char *proc)
 {
 	int retval;
@@ -408,7 +408,7 @@ void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
 }
 
 extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
-			       struct ext2_inode * inode, int bufsize,
+			       struct ext2_inode_large *inode, int bufsize,
 			       const char *proc)
 {
 	int retval;
@@ -422,7 +422,7 @@ extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
 }
 
 extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
-			       struct ext2_inode * inode, const char *proc)
+			       struct ext2_inode_large *inode, const char *proc)
 {
 	int retval;
 
diff --git a/ext2ed/dir_com.c b/ext2ed/dir_com.c
index b023e7a..8c49af3 100644
--- a/ext2ed/dir_com.c
+++ b/ext2ed/dir_com.c
@@ -48,7 +48,7 @@ directories.
 */
 
 {
-	struct ext2_inode *ptr;
+	struct ext2_inode_large *ptr;
 
 	ptr=&type_data.u.t_ext2_inode;					/* type_data contains the inode */
 
diff --git a/ext2ed/doc/ext2ed-design.sgml b/ext2ed/doc/ext2ed-design.sgml
index ad2df96..7f42a1a 100644
--- a/ext2ed/doc/ext2ed-design.sgml
+++ b/ext2ed/doc/ext2ed-design.sgml
@@ -1955,7 +1955,7 @@ struct struct_type_data {
 		struct ext2_acl_entry t_ext2_acl_entry;
 		struct ext2_old_group_desc t_ext2_old_group_desc;
 		struct ext2_group_desc t_ext2_group_desc;
-		struct ext2_inode t_ext2_inode;
+		struct ext2_inode_large t_ext2_inode;
 		struct ext2_super_block t_ext2_super_block;
 		struct ext2_dir_entry t_ext2_dir_entry;
 	} u;
@@ -2703,7 +2703,7 @@ directory.
 <Para>
 
 <ProgramListing>
-struct ext2_inode {
+struct ext2_inode_large {
 	__u16	i_mode;		/* File mode */
 	__u16	i_uid;		/* Owner Uid */
 	__u32	i_size;		/* Size in bytes */
@@ -2873,7 +2873,7 @@ initialized:
 <ProgramListing>
 struct struct_file_info {
 
-	struct ext2_inodes *inode_ptr;
+	struct ext2_inode_larges *inode_ptr;
 	
 	long inode_offset;
 	long global_block_num,global_block_offset;
diff --git a/ext2ed/doc/ext2fs-overview.sgml b/ext2ed/doc/ext2fs-overview.sgml
index a6ebf5a..119cc26 100644
--- a/ext2ed/doc/ext2fs-overview.sgml
+++ b/ext2ed/doc/ext2fs-overview.sgml
@@ -461,7 +461,7 @@ Follows the structure of an inode in Ext2fs:
 <Para>
 
 <ProgramListing>
-struct ext2_inode {
+struct ext2_inode_large {
 	__u16	i_mode;		/* File mode */
 	__u16	i_uid;		/* Owner Uid */
 	__u32	i_size;		/* Size in bytes */
diff --git a/ext2ed/ext2.descriptors b/ext2ed/ext2.descriptors
index bf927b0..abd81f6 100644
--- a/ext2ed/ext2.descriptors
+++ b/ext2ed/ext2.descriptors
@@ -72,7 +72,7 @@ struct ext2_group_desc
 /*
  * Structure of an inode on the disk
  */
-struct ext2_inode {
+struct ext2_inode_large {
 	__u16 i_mode;		/* File mode */
 	__u16 i_uid;		/* Owner Uid */
 	__u32  i_size;		/* Size in bytes */
diff --git a/ext2ed/ext2ed.h b/ext2ed/ext2ed.h
index 2ee483e..32161f5 100644
--- a/ext2ed/ext2ed.h
+++ b/ext2ed/ext2ed.h
@@ -112,7 +112,7 @@ struct struct_type_data {				/* The object's data is usually here */
 		struct ext2_acl_header t_ext2_acl_header;
 		struct ext2_acl_entry t_ext2_acl_entry;
 		struct ext2_group_desc t_ext2_group_desc;
-		struct ext2_inode t_ext2_inode;
+		struct ext2_inode_large t_ext2_inode;
 		struct ext2_super_block t_ext2_super_block;
 		struct ext2_dir_entry t_ext2_dir_entry;
 	} u;
@@ -132,7 +132,7 @@ struct struct_file_system_info {			/* Important information about the filesystem
 
 struct struct_file_info {				/* Used to handle files and directories */
 
-	struct ext2_inode *inode_ptr;
+	struct ext2_inode_large *inode_ptr;
 
 	long inode_offset;
 	long global_block_num,global_block_offset;
diff --git a/ext2ed/file_com.c b/ext2ed/file_com.c
index 9772f66..0fdedaf 100644
--- a/ext2ed/file_com.c
+++ b/ext2ed/file_com.c
@@ -23,7 +23,7 @@ Copyright (C) 1995 Gadi Oxman
 int init_file_info (void)
 
 {
-	struct ext2_inode *ptr;
+	struct ext2_inode_large *ptr;
 
 	ptr=&type_data.u.t_ext2_inode;
 
diff --git a/ext2ed/init.c b/ext2ed/init.c
index 3815ab5..af47cd2 100644
--- a/ext2ed/init.c
+++ b/ext2ed/init.c
@@ -418,7 +418,7 @@ int set_file_system_info (void)
 		file_system_info.groups_count = ext2fs_div64_ceil(ext2fs_blocks_count(sb),
 						 sb->s_blocks_per_group);
 
-		file_system_info.inodes_per_block=file_system_info.block_size/sizeof (struct ext2_inode);
+		file_system_info.inodes_per_block=file_system_info.block_size/EXT2_GOOD_OLD_INODE_SIZE;
 		file_system_info.blocks_per_group=sb->s_inodes_per_group/file_system_info.inodes_per_block;
 		file_system_info.no_blocks_in_group=sb->s_blocks_per_group;
 		file_system_info.file_system_size=(ext2fs_blocks_count(sb)-1)*file_system_info.block_size;
diff --git a/ext2ed/inode_com.c b/ext2ed/inode_com.c
index 8d4b9f3..b2fa692 100644
--- a/ext2ed/inode_com.c
+++ b/ext2ed/inode_com.c
@@ -43,13 +43,13 @@ void type_ext2_inode___prev (char *command_line)
 
 	low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
 
-	entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
+	entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/EXT2_GOOD_OLD_INODE_SIZE;
 
 	first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
 	inode_num=0;
 
 	if (entry_num-mult+1>0) {
-		device_offset-=sizeof (struct ext2_inode)*mult;
+		device_offset-=sizeof (struct ext2_inode_large)*mult;
 		entry_num-=mult;
 
 		sprintf (buffer,"setoffset %ld",device_offset);dispatch (buffer);
@@ -91,13 +91,13 @@ void type_ext2_inode___next (char *command_line)
 
 	low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
 
-	entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
+	entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/EXT2_GOOD_OLD_INODE_SIZE;
 
 	first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
 	inode_num=0;
 
 	if (entry_num+mult-1<last_entry) {
-		device_offset+=sizeof (struct ext2_inode)*mult;
+		device_offset+=sizeof (struct ext2_inode_large)*mult;
 		entry_num+=mult;
 
 		sprintf (buffer,"setoffset %ld",device_offset);dispatch (buffer);
@@ -118,7 +118,7 @@ void type_ext2_inode___next (char *command_line)
 void type_ext2_inode___show (char *command_line)
 
 {
-	struct ext2_inode *inode_ptr;
+	struct ext2_inode_large *inode_ptr;
 
 	unsigned short temp;
 	int i;
@@ -133,7 +133,7 @@ void type_ext2_inode___show (char *command_line)
 
 	low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
 
-	entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
+	entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/EXT2_GOOD_OLD_INODE_SIZE;
 	first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
 	inode_num=group_num*file_system_info.super_block.s_inodes_per_group+1;
 	inode_num+=entry_num;
@@ -299,7 +299,7 @@ void type_ext2_inode___entry (char *command_line)
 
 	low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
 
-	entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
+	entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/EXT2_GOOD_OLD_INODE_SIZE;
 
 	if (wanted_entry > entry_num) {
 		sprintf (buffer,"next %ld",wanted_entry-entry_num);
@@ -409,7 +409,7 @@ long int inode_offset_to_inode_num (long inode_offset)
 
 	low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
 
-	entry_num=(inode_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
+	entry_num=(inode_offset-desc.bg_inode_table*file_system_info.block_size)/EXT2_GOOD_OLD_INODE_SIZE;
 	first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
 	inode_num=group_num*file_system_info.super_block.s_inodes_per_group+1;
 	inode_num+=entry_num;
@@ -430,7 +430,7 @@ long int inode_num_to_inode_offset (long inode_num)
 	group_offset=file_system_info.first_group_desc_offset+group_num*sizeof (struct ext2_group_desc);
 	low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
 
-	inode_offset=desc.bg_inode_table*file_system_info.block_size+inode_entry*sizeof (struct ext2_inode);
+	inode_offset=desc.bg_inode_table*file_system_info.block_size+inode_entry*EXT2_GOOD_OLD_INODE_SIZE;
 
 	return (inode_offset);
 }
diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c
index 0f36f40..aa4a389 100644
--- a/lib/e2p/ls.c
+++ b/lib/e2p/ls.c
@@ -188,7 +188,7 @@ static __u64 e2p_free_blocks_count(struct ext2_super_block *super)
 }
 
 #ifndef EXT2_INODE_SIZE
-#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode)
+#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode_large)
 #endif
 
 #ifndef EXT2_GOOD_OLD_REV
diff --git a/lib/ext2fs/bb_inode.c b/lib/ext2fs/bb_inode.c
index 0b6c3dd..dbc29d6 100644
--- a/lib/ext2fs/bb_inode.c
+++ b/lib/ext2fs/bb_inode.c
@@ -58,7 +58,7 @@ errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
 {
 	errcode_t			retval;
 	struct set_badblock_record 	rec;
-	struct ext2_inode		inode;
+	struct ext2_inode_large		inode;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
diff --git a/lib/ext2fs/blknum.c b/lib/ext2fs/blknum.c
index b3e6dca..7e7fcd8 100644
--- a/lib/ext2fs/blknum.c
+++ b/lib/ext2fs/blknum.c
@@ -46,7 +46,7 @@ blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group)
  * Return the inode data block count
  */
 blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
-					struct ext2_inode *inode)
+					struct ext2_inode_large *inode)
 {
 	return (inode->i_blocks |
 		((fs->super->s_feature_ro_compat &
@@ -59,7 +59,7 @@ blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
  * Return the inode i_blocks count
  */
 blk64_t ext2fs_inode_i_blocks(ext2_filsys fs,
-					struct ext2_inode *inode)
+					struct ext2_inode_large *inode)
 {
 	return (inode->i_blocks |
 		((fs->super->s_feature_ro_compat &
@@ -460,7 +460,7 @@ void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum)
  * called don't have access to the fs struct, and the high bits should
  * be 0 in the non-64-bit case anyway.
  */
-blk64_t ext2fs_file_acl_block(const struct ext2_inode *inode)
+blk64_t ext2fs_file_acl_block(const struct ext2_inode_large *inode)
 {
 	return (inode->i_file_acl |
 		(__u64) inode->osd2.linux2.l_i_file_acl_high << 32);
@@ -469,7 +469,7 @@ blk64_t ext2fs_file_acl_block(const struct ext2_inode *inode)
 /*
  * Set the acl block of a file
  */
-void ext2fs_file_acl_block_set(struct ext2_inode *inode, blk64_t blk)
+void ext2fs_file_acl_block_set(struct ext2_inode_large *inode, blk64_t blk)
 {
 	inode->i_file_acl = blk;
 	inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32;
diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index 95ad31e..f193dc2 100644
--- a/lib/ext2fs/block.c
+++ b/lib/ext2fs/block.c
@@ -331,7 +331,7 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
 {
 	int	i;
 	int	r, ret = 0;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	errcode_t	retval;
 	struct block_context ctx;
 	int	limit;
diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index 7a515be..26f2074 100644
--- a/lib/ext2fs/bmap.c
+++ b/lib/ext2fs/bmap.c
@@ -26,7 +26,7 @@
 #endif
 
 extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
-			     struct ext2_inode *inode,
+			     struct ext2_inode_large *inode,
 			     char *block_buf, int bmap_flags,
 			     blk_t block, blk_t *phys_blk);
 
@@ -130,14 +130,14 @@ static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
 }
 
 static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
-			     struct ext2_inode *inode,
+			     struct ext2_inode_large *inode,
 			     ext2_extent_handle_t handle,
 			     char *block_buf, int bmap_flags, blk64_t block,
 			     int *ret_flags, int *blocks_alloc,
 			     blk64_t *phys_blk);
 
 static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
-				       struct ext2_inode *inode,
+				       struct ext2_inode_large *inode,
 				       ext2_extent_handle_t handle,
 				       blk64_t block, blk64_t *phys_blk)
 {
@@ -164,7 +164,7 @@ static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
 }
 
 static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
-			     struct ext2_inode *inode,
+			     struct ext2_inode_large *inode,
 			     ext2_extent_handle_t handle,
 			     char *block_buf, int bmap_flags, blk64_t block,
 			     int *ret_flags, int *blocks_alloc,
@@ -229,11 +229,12 @@ got_block:
 }
 
 
-errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
+errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino,
+		       struct ext2_inode_large *inode,
 		       char *block_buf, int bmap_flags, blk64_t block,
 		       int *ret_flags, blk64_t *phys_blk)
 {
-	struct ext2_inode inode_buf;
+	struct ext2_inode_large inode_buf;
 	ext2_extent_handle_t handle = 0;
 	blk_t addr_per_block;
 	blk_t	b, blk32;
@@ -379,7 +380,8 @@ done:
 	return retval;
 }
 
-errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
+errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
+		      struct ext2_inode_large *inode,
 		      char *block_buf, int bmap_flags, blk_t block,
 		      blk_t *phys_blk)
 {
diff --git a/lib/ext2fs/bmove.c b/lib/ext2fs/bmove.c
index deabf38..1443f57 100644
--- a/lib/ext2fs/bmove.c
+++ b/lib/ext2fs/bmove.c
@@ -27,7 +27,7 @@
 
 struct process_block_struct {
 	ext2_ino_t		ino;
-	struct ext2_inode *	inode;
+	struct ext2_inode_large	*inode;
 	ext2fs_block_bitmap	reserve;
 	ext2fs_block_bitmap	alloc_map;
 	errcode_t		error;
@@ -99,7 +99,7 @@ errcode_t ext2fs_move_blocks(ext2_filsys fs,
 			     int flags)
 {
 	ext2_ino_t	ino;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	errcode_t	retval;
 	struct process_block_struct pb;
 	ext2_inode_scan	scan;
diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
index 8f738c8..ee90970 100644
--- a/lib/ext2fs/expanddir.c
+++ b/lib/ext2fs/expanddir.c
@@ -91,7 +91,7 @@ errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
 {
 	errcode_t	retval;
 	struct expand_dir_struct es;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 54cb3d4..e342bf0 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -329,53 +329,6 @@ struct ext4_new_group_input {
 #define EXT4_IOC_GROUP_ADD		_IOW('f', 8,struct ext4_new_group_input)
 
 /*
- * Structure of an inode on the disk
- */
-struct ext2_inode {
-	__u16	i_mode;		/* File mode */
-	__u16	i_uid;		/* Low 16 bits of Owner Uid */
-	__u32	i_size;		/* Size in bytes */
-	__u32	i_atime;	/* Access time */
-	__u32	i_ctime;	/* Inode change time */
-	__u32	i_mtime;	/* Modification time */
-	__u32	i_dtime;	/* Deletion Time */
-	__u16	i_gid;		/* Low 16 bits of Group Id */
-	__u16	i_links_count;	/* Links count */
-	__u32	i_blocks;	/* Blocks count */
-	__u32	i_flags;	/* File flags */
-	union {
-		struct {
-			__u32	l_i_version; /* was l_i_reserved1 */
-		} linux1;
-		struct {
-			__u32  h_i_translator;
-		} hurd1;
-	} osd1;				/* OS dependent 1 */
-	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
-	__u32	i_generation;	/* File version (for NFS) */
-	__u32	i_file_acl;	/* File ACL */
-	__u32	i_size_high;	/* Formerly i_dir_acl, directory ACL */
-	__u32	i_faddr;	/* Fragment address */
-	union {
-		struct {
-			__u16	l_i_blocks_hi;
-			__u16	l_i_file_acl_high;
-			__u16	l_i_uid_high;	/* these 2 fields    */
-			__u16	l_i_gid_high;	/* were reserved2[0] */
-			__u32	l_i_reserved2;
-		} linux2;
-		struct {
-			__u8	h_i_frag;	/* Fragment number */
-			__u8	h_i_fsize;	/* Fragment size */
-			__u16	h_i_mode_high;
-			__u16	h_i_uid_high;
-			__u16	h_i_gid_high;
-			__u32	h_i_author;
-		} hurd2;
-	} osd2;				/* OS dependent 2 */
-};
-
-/*
  * Permanent part of an large inode on the disk
  */
 struct ext2_inode_large {
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index dc83fb0..b290a1f 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -229,9 +229,9 @@ struct struct_ext2_filsys {
 	errcode_t (*check_directory)(ext2_filsys fs, ext2_ino_t ino);
 	errcode_t (*write_bitmaps)(ext2_filsys fs);
 	errcode_t (*read_inode)(ext2_filsys fs, ext2_ino_t ino,
-				struct ext2_inode *inode);
+				struct ext2_inode_large *inode);
 	errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino,
-				struct ext2_inode *inode);
+				struct ext2_inode_large *inode);
 	ext2_badblocks_list		badblocks;
 	ext2_dblist			dblist;
 	__u32				stride;	/* for mke2fs */
@@ -758,9 +758,9 @@ extern dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t);
 extern blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group);
 extern blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group);
 extern blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
-					 struct ext2_inode *inode);
+					 struct ext2_inode_large *inode);
 extern blk64_t ext2fs_inode_i_blocks(ext2_filsys fs,
-					 struct ext2_inode *inode);
+					 struct ext2_inode_large *inode);
 extern blk64_t ext2fs_blocks_count(struct ext2_super_block *super);
 extern void ext2fs_blocks_count_set(struct ext2_super_block *super,
 				    blk64_t blk);
@@ -807,9 +807,11 @@ extern int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag);
 extern void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags);
 extern void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags);
 extern __u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group);
-extern void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum);
-extern blk64_t ext2fs_file_acl_block(const struct ext2_inode *inode);
-extern void ext2fs_file_acl_block_set(struct ext2_inode *inode, blk64_t blk);
+extern void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group,
+				   __u16 checksum);
+extern blk64_t ext2fs_file_acl_block(const struct ext2_inode_large *inode);
+extern void ext2fs_file_acl_block_set(struct ext2_inode_large *inode,
+				      blk64_t blk);
 
 /* block.c */
 extern errcode_t ext2fs_block_iterate(ext2_filsys fs,
@@ -846,11 +848,11 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
 
 /* bmap.c */
 extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
-			     struct ext2_inode *inode,
+			     struct ext2_inode_large *inode,
 			     char *block_buf, int bmap_flags,
 			     blk_t block, blk_t *phys_blk);
 extern errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino,
-			      struct ext2_inode *inode,
+			      struct ext2_inode_large *inode,
 			      char *block_buf, int bmap_flags, blk64_t block,
 			      int *ret_flags, blk64_t *phys_blk);
 
@@ -1017,7 +1019,7 @@ extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);
 extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino,
 				    ext2_extent_handle_t *handle);
 extern errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
-					struct ext2_inode *inode,
+					struct ext2_inode_large *inode,
 					ext2_extent_handle_t *ret_handle);
 extern void ext2fs_extent_free(ext2_extent_handle_t handle);
 extern errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
@@ -1037,12 +1039,12 @@ extern errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
 
 /* fileio.c */
 extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
-				   struct ext2_inode *inode,
+				   struct ext2_inode_large *inode,
 				   int flags, ext2_file_t *ret);
 extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
 				  int flags, ext2_file_t *ret);
 extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file);
-struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file);
+struct ext2_inode_large *ext2fs_file_get_inode(ext2_file_t file);
 extern errcode_t ext2fs_file_close(ext2_file_t file);
 extern errcode_t ext2fs_file_flush(ext2_file_t file);
 extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
@@ -1147,11 +1149,12 @@ errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize);
 errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize);
 
 /* i_block.c */
-errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
+errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode_large *inode,
 				 blk64_t num_blocks);
-errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
+errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode_large *inode,
 				 blk64_t num_blocks);
-errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b);
+errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode_large *inode,
+			  blk64_t b);
 
 /* imager.c */
 extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags);
@@ -1195,13 +1198,13 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
 extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
 extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
 					    ext2_ino_t *ino,
-					    struct ext2_inode *inode,
+					    struct ext2_inode_large *inode,
 					    int bufsize);
 extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
 				  ext2_inode_scan *ret_scan);
 extern void ext2fs_close_inode_scan(ext2_inode_scan scan);
 extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
-			       struct ext2_inode *inode);
+			       struct ext2_inode_large *inode);
 extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
 						   int	group);
 extern void ext2fs_set_inode_callback
@@ -1214,17 +1217,17 @@ extern void ext2fs_set_inode_callback
 extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
 				   int clear_flags);
 extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
-					struct ext2_inode * inode,
+					struct ext2_inode_large *inode,
 					int bufsize);
 extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
-			    struct ext2_inode * inode);
+			    struct ext2_inode_large *inode);
 extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
-					 struct ext2_inode * inode,
+					 struct ext2_inode_large *inode,
 					 int bufsize);
 extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
-			    struct ext2_inode * inode);
+			    struct ext2_inode_large *inode);
 extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
-			    struct ext2_inode * inode);
+			    struct ext2_inode_large *inode);
 extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
 extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino);
 
@@ -1233,7 +1236,7 @@ extern io_manager inode_io_manager;
 extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
 					char **name);
 extern errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
-					 struct ext2_inode *inode,
+					 struct ext2_inode_large *inode,
 					 char **name);
 
 /* ismounted.c */
@@ -1243,7 +1246,7 @@ extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
 
 /* punch.c */
 extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
-			      struct ext2_inode *inode,
+			      struct ext2_inode_large *inode,
 			      char *block_buf, blk64_t start,
 			      blk64_t end);
 
@@ -1341,11 +1344,11 @@ extern void ext2fs_swap_group_desc2(ext2_filsys, struct ext2_group_desc *gdp);
 extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
 				   struct ext2_inode_large *f, int hostorder,
 				   int bufsize);
-extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
-			      struct ext2_inode *f, int hostorder);
+extern void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode_large *t,
+			      struct ext2_inode_large *f, int hostorder);
 
 /* valid_blk.c */
-extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
+extern int ext2fs_inode_has_valid_blocks(struct ext2_inode_large *inode);
 
 /* version.c */
 extern int ext2fs_parse_version_string(const char *ver_string);
@@ -1385,7 +1388,7 @@ extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
 extern blk_t ext2fs_group_first_block(ext2_filsys fs, dgrp_t group);
 extern blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group);
 extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
-				      struct ext2_inode *inode);
+				      struct ext2_inode_large *inode);
 extern unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b);
 extern __u64 ext2fs_div64_ceil(__u64 a, __u64 b);
 
@@ -1616,7 +1619,7 @@ _INLINE_ blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group)
 }
 
 _INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
-					struct ext2_inode *inode)
+					struct ext2_inode_large *inode)
 {
 	return ext2fs_inode_data_blocks2(fs, inode);
 }
diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
index b182d7f..27c4332 100644
--- a/lib/ext2fs/ext2fsP.h
+++ b/lib/ext2fs/ext2fsP.h
@@ -73,7 +73,7 @@ struct ext2_inode_cache {
 
 struct ext2_inode_cache_ent {
 	ext2_ino_t		ino;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 };
 
 /* Function prototypes */
diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
index abb60dd..33f1a88 100644
--- a/lib/ext2fs/extent.c
+++ b/lib/ext2fs/extent.c
@@ -52,8 +52,8 @@ struct ext2_extent_handle {
 	errcode_t		magic;
 	ext2_filsys		fs;
 	ext2_ino_t 		ino;
-	struct ext2_inode	*inode;
-	struct ext2_inode	inodebuf;
+	struct ext2_inode_large	*inode;
+	struct ext2_inode_large	inodebuf;
 	int			type;
 	int			level;
 	int			max_depth;
@@ -183,7 +183,7 @@ extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino,
 }
 
 extern errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
-				    struct ext2_inode *inode,
+				    struct ext2_inode_large *inode,
 				    ext2_extent_handle_t *ret_handle)
 {
 	struct ext2_extent_handle	*handle;
diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
index 324f046..6d139e5 100644
--- a/lib/ext2fs/fileio.c
+++ b/lib/ext2fs/fileio.c
@@ -22,7 +22,7 @@ struct ext2_file {
 	errcode_t		magic;
 	ext2_filsys 		fs;
 	ext2_ino_t		ino;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	int 			flags;
 	__u64			pos;
 	blk64_t			blockno;
@@ -33,7 +33,7 @@ struct ext2_file {
 #define BMAP_BUFFER (file->buf + fs->blocksize)
 
 errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
-			    struct ext2_inode *inode,
+			    struct ext2_inode_large *inode,
 			    int flags, ext2_file_t *ret)
 {
 	ext2_file_t 	file;
@@ -58,7 +58,7 @@ errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
 	file->flags = flags & EXT2_FILE_MASK;
 
 	if (inode) {
-		memcpy(&file->inode, inode, sizeof(struct ext2_inode));
+		memcpy(&file->inode, inode, sizeof(struct ext2_inode_large));
 	} else {
 		retval = ext2fs_read_inode(fs, ino, &file->inode);
 		if (retval)
@@ -98,7 +98,7 @@ ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
 /*
  * This function returns the pointer to the inode of a file from the structure
  */
-struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file)
+struct ext2_inode_large *ext2fs_file_get_inode(ext2_file_t file)
 {
 	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
 		return NULL;
diff --git a/lib/ext2fs/i_block.c b/lib/ext2fs/i_block.c
index f36c3c4..1801570 100644
--- a/lib/ext2fs/i_block.c
+++ b/lib/ext2fs/i_block.c
@@ -26,7 +26,7 @@
 #include "ext2_fs.h"
 #include "ext2fs.h"
 
-errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
+errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode_large *inode,
 				 blk64_t num_blocks)
 {
 	unsigned long long b = inode->i_blocks;
@@ -50,7 +50,7 @@ errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
 	return 0;
 }
 
-errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
+errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode_large *inode,
 				 blk64_t num_blocks)
 {
 	unsigned long long b = inode->i_blocks;
@@ -75,7 +75,8 @@ errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
 	return 0;
 }
 
-errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b)
+errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode_large *inode,
+			  blk64_t b)
 {
 	if (!(fs->super->s_feature_ro_compat &
 	      EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
index ccc2dee..96a93b9 100644
--- a/lib/ext2fs/initialize.c
+++ b/lib/ext2fs/initialize.c
@@ -180,7 +180,7 @@ errcode_t ext2fs_initialize(const char *name, int flags,
 	if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
 		set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
 		set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
-		if (super->s_inode_size >= sizeof(struct ext2_inode_large)) {
+		if (super->s_inode_size >= EXT2_GOOD_OLD_INODE_SIZE) {
 			int extra_isize = sizeof(struct ext2_inode_large) -
 				EXT2_GOOD_OLD_INODE_SIZE;
 			set_field(s_min_extra_isize, extra_isize);
diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
index 829e032..76893fd 100644
--- a/lib/ext2fs/inode.c
+++ b/lib/ext2fs/inode.c
@@ -402,13 +402,17 @@ static inline int is_empty_scan(ext2_inode_scan scan)
 #endif
 
 errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
-				     struct ext2_inode *inode, int bufsize)
+				     struct ext2_inode_large *inode,
+				     int bufsize)
 {
 	errcode_t	retval;
 	int		extra_bytes = 0;
 
 	EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
 
+	if (bufsize > scan->inode_size)
+		bufsize = scan->inode_size;
+
 	/*
 	 * Do we need to start reading a new block group?
 	 */
@@ -482,7 +486,7 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
 			       (struct ext2_inode_large *) scan->temp_buffer,
 			       0, bufsize);
 #else
-		*inode = *((struct ext2_inode *) scan->temp_buffer);
+		*inode = *((struct ext2_inode_large *) scan->temp_buffer);
 #endif
 		if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
 			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
@@ -502,6 +506,8 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
 		if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
 			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
 	}
+	if (EXT2_INODE_SIZE(scan->fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
+		inode->i_extra_isize = 0;
 
 	scan->inodes_left--;
 	scan->current_inode++;
@@ -510,17 +516,17 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
 }
 
 errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
-				struct ext2_inode *inode)
+				struct ext2_inode_large *inode)
 {
 	return ext2fs_get_next_inode_full(scan, ino, inode,
-						sizeof(struct ext2_inode));
+					  sizeof(struct ext2_inode_large));
 }
 
 /*
  * Functions to read and write a single inode.
  */
 errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
-				 struct ext2_inode * inode, int bufsize)
+				 struct ext2_inode_large *inode, int bufsize)
 {
 	blk64_t		block_nr;
 	unsigned long 	group, block, offset;
@@ -546,7 +552,7 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
 			return retval;
 	}
 	/* Check to see if it's in the inode cache */
-	if (bufsize == sizeof(struct ext2_inode)) {
+	if (bufsize == sizeof(struct ext2_inode_large)) {
 		/* only old good inode can be retrieved from the cache */
 		for (i=0; i < fs->icache->cache_size; i++) {
 			if (fs->icache->cache[i].ino == ino) {
@@ -581,6 +587,8 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
 	if (bufsize < length)
 		length = bufsize;
 
+	if (length == EXT2_GOOD_OLD_INODE_SIZE)
+		inode->i_extra_isize = 0;
 	ptr = (char *) inode;
 	while (length) {
 		clen = length;
@@ -620,14 +628,14 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
 }
 
 errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
-			    struct ext2_inode * inode)
+			    struct ext2_inode_large *inode)
 {
 	return ext2fs_read_inode_full(fs, ino, inode,
-					sizeof(struct ext2_inode));
+					sizeof(struct ext2_inode_large));
 }
 
 errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
-				  struct ext2_inode * inode, int bufsize)
+				  struct ext2_inode_large *inode, int bufsize)
 {
 	blk64_t block_nr;
 	unsigned long group, block, offset;
@@ -678,9 +686,7 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
 	memset(w_inode, 0, length);
 
 #ifdef WORDS_BIGENDIAN
-	ext2fs_swap_inode_full(fs, w_inode,
-			       (struct ext2_inode_large *) inode,
-			       1, bufsize);
+	ext2fs_swap_inode_full(fs, w_inode, inode, 1, bufsize);
 #else
 	memcpy(w_inode, inode, bufsize);
 #endif
@@ -739,10 +745,10 @@ errout:
 }
 
 errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
-			     struct ext2_inode *inode)
+			     struct ext2_inode_large *inode)
 {
 	return ext2fs_write_inode_full(fs, ino, inode,
-				       sizeof(struct ext2_inode));
+				       sizeof(struct ext2_inode_large));
 }
 
 /*
@@ -750,9 +756,9 @@ errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
  * sure that extra part of large inodes is initialized properly.
  */
 errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
-				 struct ext2_inode *inode)
+				 struct ext2_inode_large *inode)
 {
-	struct ext2_inode	*buf;
+	struct ext2_inode_large	*buf;
 	int 			size = EXT2_INODE_SIZE(fs->super);
 	struct ext2_inode_large	*large_inode;
 	errcode_t		retval;
@@ -765,32 +771,20 @@ errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
 	if (!inode->i_atime)
 		inode->i_atime = t;
 
-	if (size == sizeof(struct ext2_inode))
-		return ext2fs_write_inode_full(fs, ino, inode,
-					       sizeof(struct ext2_inode));
-
-	buf = malloc(size);
-	if (!buf)
-		return ENOMEM;
-
-	memset(buf, 0, size);
-	*buf = *inode;
-
-	large_inode = (struct ext2_inode_large *) buf;
-	large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
-		EXT2_GOOD_OLD_INODE_SIZE;
-	if (!large_inode->i_crtime)
-		large_inode->i_crtime = t;
+	if (size > EXT2_GOOD_OLD_INODE_SIZE) {
+		inode->i_extra_isize = sizeof(struct ext2_inode_large) -
+				       EXT2_GOOD_OLD_INODE_SIZE;
+		if (!inode->i_crtime)
+			inode->i_crtime = t;
+	}
 
-	retval = ext2fs_write_inode_full(fs, ino, buf, size);
-	free(buf);
-	return retval;
+	return ext2fs_write_inode_full(fs, ino, inode, size);
 }
 
 
 errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
 {
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	int			i;
 	errcode_t		retval;
 
@@ -813,7 +807,7 @@ errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
 
 errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
 {
-	struct	ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	errcode_t		retval;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
diff --git a/lib/ext2fs/inode_io.c b/lib/ext2fs/inode_io.c
index b3e7ce5..bfd6028 100644
--- a/lib/ext2fs/inode_io.c
+++ b/lib/ext2fs/inode_io.c
@@ -36,7 +36,7 @@ struct inode_private_data {
 	ext2_file_t			file;
 	ext2_filsys			fs;
 	ext2_ino_t 			ino;
-	struct ext2_inode		inode;
+	struct ext2_inode_large		inode;
 	int				flags;
 	struct inode_private_data	*next;
 };
@@ -80,7 +80,7 @@ static struct struct_io_manager struct_inode_manager = {
 io_manager inode_io_manager = &struct_inode_manager;
 
 errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
-				  struct ext2_inode *inode,
+				  struct ext2_inode_large *inode,
 				  char **name)
 {
 	struct inode_private_data 	*data;
@@ -96,7 +96,7 @@ errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
 	data->ino = ino;
 	data->flags = 0;
 	if (inode) {
-		memcpy(&data->inode, inode, sizeof(struct ext2_inode));
+		memcpy(&data->inode, inode, sizeof(struct ext2_inode_large));
 		data->flags |= CHANNEL_HAS_INODE;
 	}
 	data->next = top_intern;
diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
index 0fd3ea8..a32ec03 100644
--- a/lib/ext2fs/link.c
+++ b/lib/ext2fs/link.c
@@ -113,7 +113,7 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
 {
 	errcode_t		retval;
 	struct link_struct	ls;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
index 9b6b799..08a0bd6 100644
--- a/lib/ext2fs/mkdir.c
+++ b/lib/ext2fs/mkdir.c
@@ -35,7 +35,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 {
 	ext2_extent_handle_t	handle;
 	errcode_t		retval;
-	struct ext2_inode	parent_inode, inode;
+	struct ext2_inode_large	parent_inode, inode;
 	ext2_ino_t		ino = inum;
 	ext2_ino_t		scratch_ino;
 	blk64_t			blk;
@@ -80,7 +80,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 	/*
 	 * Create the inode structure....
 	 */
-	memset(&inode, 0, sizeof(struct ext2_inode));
+	memset(&inode, 0, sizeof(struct ext2_inode_large));
 	inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
 	inode.i_uid = inode.i_gid = 0;
 	ext2fs_iblk_set(fs, &inode, 1);
diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c
index aaad2f6..33e58f7 100644
--- a/lib/ext2fs/mkjournal.c
+++ b/lib/ext2fs/mkjournal.c
@@ -302,7 +302,7 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
 	char			*buf;
 	dgrp_t			group, start, end, i, log_flex;
 	errcode_t		retval;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	unsigned long long	inode_size;
 	struct mkjournal_struct	es;
 
diff --git a/lib/ext2fs/namei.c b/lib/ext2fs/namei.c
index bc0ae61..b1911e3 100644
--- a/lib/ext2fs/namei.c
+++ b/lib/ext2fs/namei.c
@@ -31,7 +31,7 @@ static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
 	char *pathname;
 	char *buffer = 0;
 	errcode_t retval;
-	struct ext2_inode ei;
+	struct ext2_inode_large ei;
 
 #ifdef NAMEI_DEBUG
 	printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c
index 2f24b5e..b8bd816 100644
--- a/lib/ext2fs/punch.c
+++ b/lib/ext2fs/punch.c
@@ -44,7 +44,7 @@ static int check_zero_block(char *buf, int blocksize)
  * each one, will recursively handle any indirect blocks and then
  * frees and deallocates the blocks.
  */
-static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode,
+static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode_large *inode,
 			   char *block_buf, blk_t *p, int level,
 			   blk_t start, blk_t count, int max)
 {
@@ -98,7 +98,8 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode,
 	return ext2fs_iblk_sub_blocks(fs, inode, freed);
 }
 
-static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode,
+static errcode_t ext2fs_punch_ind(ext2_filsys fs,
+				  struct ext2_inode_large *inode,
 				  char *block_buf, blk_t start, blk_t count)
 {
 	errcode_t		retval;
@@ -176,7 +177,7 @@ static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
 #endif
 
 static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
-				     struct ext2_inode *inode,
+				     struct ext2_inode_large *inode,
 				     blk64_t start, blk64_t end)
 {
 	ext2_extent_handle_t	handle = 0;
@@ -286,12 +287,12 @@ errout:
  * If end is ~0, then this is effectively truncate.
  */
 extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
-			      struct ext2_inode *inode,
+			      struct ext2_inode_large *inode,
 			      char *block_buf, blk64_t start,
 			      blk64_t end)
 {
 	errcode_t		retval;
-	struct ext2_inode	inode_buf;
+	struct ext2_inode_large	inode_buf;
 
 	if (start > end)
 		return EINVAL;
diff --git a/lib/ext2fs/read_bb.c b/lib/ext2fs/read_bb.c
index e5d6322..40d0247 100644
--- a/lib/ext2fs/read_bb.c
+++ b/lib/ext2fs/read_bb.c
@@ -65,7 +65,7 @@ errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list)
 {
 	errcode_t	retval;
 	struct read_bb_record rb;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	blk_t	numblocks;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
diff --git a/lib/ext2fs/res_gdt.c b/lib/ext2fs/res_gdt.c
index acce650..7a80512 100644
--- a/lib/ext2fs/res_gdt.c
+++ b/lib/ext2fs/res_gdt.c
@@ -62,7 +62,7 @@ errcode_t ext2fs_create_resize_inode(ext2_filsys fs)
 {
 	errcode_t		retval, retval2;
 	struct ext2_super_block	*sb;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	__u32			*dindir_buf, *gdt_buf;
 	unsigned long long	apb, inode_size;
 	/* FIXME-64 - can't deal with extents */
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index 87b1a2e..517f1d7 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -210,11 +210,11 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
 	t->i_file_acl = ext2fs_swab32(f->i_file_acl);
 	if (hostorder)
 		has_data_blocks = ext2fs_inode_data_blocks(fs,
-					   (struct ext2_inode *) f);
+					   (struct ext2_inode_large *) f);
 	t->i_blocks = ext2fs_swab32(f->i_blocks);
 	if (!hostorder)
 		has_data_blocks = ext2fs_inode_data_blocks(fs,
-					   (struct ext2_inode *) t);
+					   (struct ext2_inode_large *) t);
 	if (hostorder && (f->i_flags & EXT4_EXTENTS_FL))
 		has_extents = 1;
 	t->i_flags = ext2fs_swab32(f->i_flags);
@@ -265,7 +265,7 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
 		break;
 	}
 
-	if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
+	if (bufsize < (int) (sizeof(struct ext2_inode_large) + sizeof(__u16)))
 		return; /* no i_extra_isize field */
 
 	if (hostorder)
@@ -274,16 +274,16 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
 	if (!hostorder)
 		extra_isize = t->i_extra_isize;
 	if (extra_isize > EXT2_INODE_SIZE(fs->super) -
-				sizeof(struct ext2_inode)) {
+				EXT2_GOOD_OLD_INODE_SIZE) {
 		/* this is error case: i_extra_size is too large */
 		return;
 	}
 
-	i = sizeof(struct ext2_inode) + extra_isize + sizeof(__u32);
+	i = EXT2_GOOD_OLD_INODE_SIZE + extra_isize + sizeof(__u32);
 	if (bufsize < (int) i)
 		return; /* no space for EA magic */
 
-	eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) +
+	eaf = (__u32 *) (((char *) f) + EXT2_GOOD_OLD_INODE_SIZE +
 					extra_isize);
 
 	attr_magic = *eaf;
@@ -293,23 +293,23 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
 	if (attr_magic != EXT2_EXT_ATTR_MAGIC)
 		return; /* it seems no magic here */
 
-	eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) +
+	eat = (__u32 *) (((char *) t) + EXT2_GOOD_OLD_INODE_SIZE +
 					extra_isize);
 	*eat = ext2fs_swab32(*eaf);
 
 	/* convert EA(s) */
 	ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1),
-			     bufsize - sizeof(struct ext2_inode) -
+			     bufsize - EXT2_GOOD_OLD_INODE_SIZE -
 			     extra_isize - sizeof(__u32), 0);
 
 }
 
-void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
-		       struct ext2_inode *f, int hostorder)
+void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode_large *t,
+		       struct ext2_inode_large *f, int hostorder)
 {
 	ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t,
 				(struct ext2_inode_large *) f, hostorder,
-				sizeof(struct ext2_inode));
+				sizeof(struct ext2_inode_large));
 }
 
 #endif
diff --git a/lib/ext2fs/tst_iscan.c b/lib/ext2fs/tst_iscan.c
index 64246d3..dcf81d1 100644
--- a/lib/ext2fs/tst_iscan.c
+++ b/lib/ext2fs/tst_iscan.c
@@ -139,7 +139,7 @@ static void setup(void)
  */
 static void iterate(void)
 {
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	ext2_inode_scan	scan;
 	errcode_t	retval;
 	ext2_ino_t	ino;
diff --git a/lib/ext2fs/valid_blk.c b/lib/ext2fs/valid_blk.c
index ec3edd8..9419166 100644
--- a/lib/ext2fs/valid_blk.c
+++ b/lib/ext2fs/valid_blk.c
@@ -23,7 +23,7 @@
  * This function returns 1 if the inode's block entries actually
  * contain block entries.
  */
-int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode)
+int ext2fs_inode_has_valid_blocks(struct ext2_inode_large *inode)
 {
 	/*
 	 * Only directories, regular files, and some symbolic links
diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
index 9a0dd46..7d74e84 100644
--- a/misc/dumpe2fs.c
+++ b/misc/dumpe2fs.c
@@ -300,7 +300,7 @@ static void list_bad_blocks(ext2_filsys fs, int dump)
 static void print_inline_journal_information(ext2_filsys fs)
 {
 	journal_superblock_t	*jsb;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	ext2_file_t		journal_file;
 	errcode_t		retval;
 	ino_t			ino = fs->super->s_journal_inum;
diff --git a/misc/e2image.c b/misc/e2image.c
index 83a9d02..56a5321 100644
--- a/misc/e2image.c
+++ b/misc/e2image.c
@@ -232,7 +232,7 @@ struct process_block_struct {
  * the inode again.
  */
 static ino_t stashed_ino = 0;
-static struct ext2_inode *stashed_inode;
+static struct ext2_inode_large *stashed_inode;
 
 static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)),
 				 ext2_ino_t ino,
@@ -261,7 +261,7 @@ static errcode_t meta_check_directory(ext2_filsys fs EXT2FS_ATTR((unused)),
 
 static errcode_t meta_read_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
 				 ext2_ino_t ino,
-				 struct ext2_inode *inode)
+				 struct ext2_inode_large *inode)
 {
 	if ((ino != stashed_ino) || !stashed_inode)
 		return EXT2_ET_CALLBACK_NOTHANDLED;
@@ -1032,7 +1032,7 @@ static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
 static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
 {
 	struct process_block_struct	pb;
-	struct ext2_inode		inode;
+	struct ext2_inode_large		inode;
 	ext2_inode_scan			scan;
 	ext2_ino_t			ino;
 	errcode_t			retval;
diff --git a/misc/e2initrd_helper.c b/misc/e2initrd_helper.c
index eaf9ce6..3d1535b 100644
--- a/misc/e2initrd_helper.c
+++ b/misc/e2initrd_helper.c
@@ -75,7 +75,7 @@ static errcode_t get_file(ext2_filsys fs, const char * filename,
 	char 		*buf;
 	ext2_file_t	e2_file;
 	unsigned int	got;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	ext2_ino_t	ino;
 
 	ret_file->buf = 0;
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index e062bda..2d57d09 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -352,7 +352,7 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
 static void create_root_dir(ext2_filsys fs)
 {
 	errcode_t		retval;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	__u32			uid, gid;
 
 	retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 5bf5187..82833ad 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -275,7 +275,7 @@ static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
  */
 static void remove_journal_inode(ext2_filsys fs)
 {
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	errcode_t		retval;
 	ino_t			ino = fs->super->s_journal_inum;
 
@@ -1209,7 +1209,7 @@ static int inode_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
 	ext2_ino_t ino;
 	blk64_t blk;
 	char *block_buf = 0;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	ext2_inode_scan	scan = NULL;
 
 	retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
diff --git a/resize/resize2fs.c b/resize/resize2fs.c
index 45ea5f4..d35be59 100644
--- a/resize/resize2fs.c
+++ b/resize/resize2fs.c
@@ -1234,7 +1234,7 @@ errout:
 struct process_block_struct {
 	ext2_resize_t 		rfs;
 	ext2_ino_t		ino;
-	struct ext2_inode *	inode;
+	struct ext2_inode_large	*inode;
 	errcode_t		error;
 	int			is_dir;
 	int			changed;
@@ -1309,7 +1309,7 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
 {
 	struct process_block_struct	pb;
 	ext2_ino_t		ino, new_inode;
-	struct ext2_inode 	*inode = NULL;
+	struct ext2_inode_large	*inode = NULL;
 	ext2_inode_scan 	scan = NULL;
 	errcode_t		retval;
 	char			*block_buf = 0;
@@ -1475,7 +1475,7 @@ static int check_and_change_inodes(ext2_ino_t dir,
 				   void *priv_data)
 {
 	struct istruct *is = (struct istruct *) priv_data;
-	struct ext2_inode 	inode;
+	struct ext2_inode_large	inode;
 	ext2_ino_t		new_inode;
 	errcode_t		retval;
 
@@ -1712,7 +1712,7 @@ errout:
  */
 static errcode_t fix_resize_inode(ext2_filsys fs)
 {
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	errcode_t		retval;
 	char *			block_buf;
 
@@ -1866,7 +1866,7 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
 static errcode_t fix_sb_journal_backup(ext2_filsys fs)
 {
 	errcode_t	  retval;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 
 	if (!(fs->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
 		return 0;


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

* [PATCH 02/37] libext2fs: Add metadata checksum flag
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
  2011-09-01  0:35 ` [PATCH 01/37] e2fsprogs: Read and write full-sized inodes Darrick J. Wong
@ 2011-09-01  0:35 ` Darrick J. Wong
  2011-09-04  1:47   ` Andreas Dilger
  2011-09-01  0:35 ` [PATCH 03/37] debugfs: Optionally ignore bad checksums Darrick J. Wong
                   ` (33 subsequent siblings)
  35 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:35 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Add a feature flag to enable metadata checksumming in e2fsprogs.  Also add a
runtime flag to disable checksum verification; this flag will be used by
debugfs to salvage filesystems and tune2fs when resetting checksums.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/blkid/probe.h    |    1 +
 lib/e2p/feature.c    |    2 ++
 lib/ext2fs/ext2_fs.h |    1 +
 lib/ext2fs/ext2fs.h  |    4 +++-
 4 files changed, 7 insertions(+), 1 deletions(-)


diff --git a/lib/blkid/probe.h b/lib/blkid/probe.h
index 37e80ef..d6809e1 100644
--- a/lib/blkid/probe.h
+++ b/lib/blkid/probe.h
@@ -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
diff --git a/lib/e2p/feature.c b/lib/e2p/feature.c
index 16fba53..07b700d 100644
--- a/lib/e2p/feature.c
+++ b/lib/e2p/feature.c
@@ -59,6 +59,8 @@ static struct feature feature_list[] = {
 			"quota" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_BIGALLOC,
 			"bigalloc"},
+	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM,
+			"metadata_csum"},
 
 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
 			"compression" },
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index e342bf0..ae7662e 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -635,6 +635,7 @@ 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
+#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM	0x0400
 
 #define EXT2_FEATURE_INCOMPAT_COMPRESSION	0x0001
 #define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index b290a1f..e638169 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -195,6 +195,7 @@ typedef struct ext2_file *ext2_file_t;
 #define EXT2_FLAG_64BITS		0x20000
 #define EXT2_FLAG_PRINT_PROGRESS	0x40000
 #define EXT2_FLAG_DIRECT_IO		0x80000
+#define EXT2_FLAG_IGNORE_CSUM_ERRORS	0x100000
 
 /*
  * Special flag in the ext2 inode i_flag field that means that this is
@@ -564,7 +565,8 @@ typedef struct ext2_icount *ext2_icount_t;
 					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\
 					 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\
 					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\
-					 EXT4_FEATURE_RO_COMPAT_BIGALLOC)
+					 EXT4_FEATURE_RO_COMPAT_BIGALLOC|\
+					 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
 
 /*
  * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed


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

* [PATCH 03/37] debugfs: Optionally ignore bad checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
  2011-09-01  0:35 ` [PATCH 01/37] e2fsprogs: Read and write full-sized inodes Darrick J. Wong
  2011-09-01  0:35 ` [PATCH 02/37] libext2fs: Add metadata checksum flag Darrick J. Wong
@ 2011-09-01  0:35 ` Darrick J. Wong
  2011-09-01  0:35 ` [PATCH 04/37] libext2fs: Add crc32c implementation for metadata checksumming Darrick J. Wong
                   ` (32 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:35 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

If someone is debugging a badly damaged filesystem, it might be useful to
disable the checksum verifications that will otherwise prevent the filesystem
from loading.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 debugfs/debugfs.8.in |    7 ++++++-
 debugfs/debugfs.c    |    5 ++++-
 2 files changed, 10 insertions(+), 2 deletions(-)


diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in
index fe07f34..b5d208f 100644
--- a/debugfs/debugfs.8.in
+++ b/debugfs/debugfs.8.in
@@ -8,7 +8,7 @@ debugfs \- ext2/ext3/ext4 file system debugger
 .SH SYNOPSIS
 .B debugfs
 [
-.B \-DVwci
+.B \-DVwcin
 ]
 [
 .B \-b
@@ -48,6 +48,11 @@ file system (e.g /dev/hdXX).
 Specifies that the file system should be opened in read-write mode.
 Without this option, the file system is opened in read-only mode.
 .TP
+.I \-n
+Disables metadata checksum verification.  This should only be used if
+you believe the metadata to be correct despite the complaints of
+e2fsprogs.
+.TP
 .I \-c
 Specifies that the file system should be opened in catastrophic mode, in
 which the inode and group bitmaps are not read initially.  This can be
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 94732b9..ad0789f 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -2219,7 +2219,7 @@ int main(int argc, char **argv)
 	fprintf (stderr, "%s %s (%s)\n", debug_prog_name,
 		 E2FSPROGS_VERSION, E2FSPROGS_DATE);
 
-	while ((c = getopt (argc, argv, "iwcR:f:b:s:Vd:D")) != EOF) {
+	while ((c = getopt(argc, argv, "niwcR:f:b:s:Vd:D")) != EOF) {
 		switch (c) {
 		case 'R':
 			request = optarg;
@@ -2233,6 +2233,9 @@ int main(int argc, char **argv)
 		case 'i':
 			open_flags |= EXT2_FLAG_IMAGE_FILE;
 			break;
+		case 'n':
+			open_flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+			break;
 		case 'w':
 			open_flags |= EXT2_FLAG_RW;
 			break;


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

* [PATCH 04/37] libext2fs: Add crc32c implementation for metadata checksumming
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (2 preceding siblings ...)
  2011-09-01  0:35 ` [PATCH 03/37] debugfs: Optionally ignore bad checksums Darrick J. Wong
@ 2011-09-01  0:35 ` Darrick J. Wong
  2011-09-16  3:32   ` Ted Ts'o
  2011-09-01  0:35 ` [PATCH 05/37] libext2fs: Implement a crc32c self-test Darrick J. Wong
                   ` (31 subsequent siblings)
  35 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:35 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Add a slicing-by-8 CRC32c implementation for metadata checksumming.
Adapted from Bob Pearson's kernel patch.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/Makefile.in       |   15 +
 lib/ext2fs/crc32c.c          |  435 ++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/crc32c_defs.h     |   67 ++++++
 lib/ext2fs/ext2fs.h          |    4 
 lib/ext2fs/gen_crc32ctable.c |  123 ++++++++++++
 5 files changed, 644 insertions(+), 0 deletions(-)
 create mode 100644 lib/ext2fs/crc32c.c
 create mode 100644 lib/ext2fs/crc32c_defs.h
 create mode 100644 lib/ext2fs/gen_crc32ctable.c


diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index f6338f0..f05cba8 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -33,6 +33,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
 	check_desc.o \
 	closefs.o \
 	crc16.o \
+	crc32c.o \
 	csum.o \
 	dblist.o \
 	dblist_dir.o \
@@ -99,6 +100,8 @@ SRCS= ext2_err.c \
 	$(srcdir)/check_desc.c \
 	$(srcdir)/closefs.c \
 	$(srcdir)/crc16.c \
+	$(srcdir)/crc32c.c \
+	$(srcdir)/gen_crc32ctable.c \
 	$(srcdir)/csum.c \
 	$(srcdir)/dblist.c \
 	$(srcdir)/dblist_dir.c \
@@ -393,6 +396,15 @@ $(top_builddir)/lib/ext2fs/ext2_err.h: ext2_err.h
 
 $(OBJS): subdirs
 
+gen_crc32ctable: $(srcdir)/gen_crc32ctable.c
+	$(E) "	CC $@"
+	$(Q) $(BUILD_CC) $(BUILD_CFLAGS) -o gen_crc32ctable \
+		$(srcdir)/gen_crc32ctable.c
+
+crc32c_table.h: gen_crc32ctable
+	$(E) "	GEN32CTABLE $@"
+	$(Q) ./gen_crc32ctable > crc32c_table.h
+
 # +++ Dependency line eater +++
 # 
 # Makefile dependencies follow.  This must be the last section in
@@ -476,6 +488,9 @@ closefs.o: $(srcdir)/closefs.c $(srcdir)/ext2_fs.h \
  $(srcdir)/bitops.h
 crc16.o: $(srcdir)/crc16.c $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(srcdir)/crc16.h
+crc32c.o: $(srcdir)/crc32c.c $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(srcdir)/crc32c_table.h $(srcdir)/crc32c_defs.h
+gen_crc32ctable.o: $(srcdir)/gen_crc32ctable.c $(srcdir)/crc32c_defs.h
 csum.o: $(srcdir)/csum.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
diff --git a/lib/ext2fs/crc32c.c b/lib/ext2fs/crc32c.c
new file mode 100644
index 0000000..229bd37
--- /dev/null
+++ b/lib/ext2fs/crc32c.c
@@ -0,0 +1,435 @@
+/*
+ * crc32c.c
+ *
+ * August 26, 2011 Darrick J. Wong <djwong at us.ibm.com>
+ * Reuse Bob Pearson's slice-by-8 implementation for e2fsprogs.
+ *
+ * July 20, 2011 Bob Pearson <rpearson at systemfabricworks.com>
+ * added slice by 8 algorithm to the existing conventional and
+ * slice by 4 algorithms.
+ *
+ * Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Nicer crc32 functions/docs submitted by linux@horizon.com.  Thanks!
+ * Code was from the public domain, copyright abandoned.  Code was
+ * subsequently included in the kernel, thus was re-licensed under the
+ * GNU GPL v2.
+ *
+ * Oct 12, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Same crc32 function was used in 5 other places in the kernel.
+ * I made one version, and deleted the others.
+ * There are various incantations of crc32().  Some use a seed of 0 or ~0.
+ * Some xor at the end with ~0.  The generic crc32() function takes
+ * seed as an argument, and doesn't xor at the end.  Then individual
+ * users can do whatever they need.
+ *   drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
+ *   fs/jffs2 uses seed 0, doesn't xor with ~0.
+ *   fs/partitions/efi.c uses seed ~0, xor's with ~0.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+#include <stdint.h>
+#include <endian.h>
+#include <stdlib.h>
+#define __force
+#define min(x, y)		((x) > (y) ? (y) : (x))
+#define __ALIGN_KERNEL_MASK(x, mask)	(((x) + (mask)) & ~(mask))
+#define __ALIGN_KERNEL(x, a)	__ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
+#define ALIGN(x, a)		__ALIGN_KERNEL((x), (a))
+#define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), (a)))
+#include "crc32c_defs.h"
+
+#if CRC_LE_BITS > 8
+# define tole(x) (__force uint32_t) __constant_cpu_to_le32(x)
+#else
+# define tole(x) (x)
+#endif
+
+#if CRC_BE_BITS > 8
+# define tobe(x) (__force uint32_t) __constant_cpu_to_be32(x)
+#else
+# define tobe(x) (x)
+#endif
+
+#include "crc32c_table.h"
+
+#if CRC_LE_BITS == 32
+/* slice by 4 algorithm */
+static uint32_t crc32c_le_body(uint32_t crc, uint8_t const *buf, size_t len)
+{
+	const uint8_t *p8;
+	const uint32_t *p32;
+	size_t init_bytes;
+	size_t words;
+	size_t end_bytes;
+	size_t i;
+	uint32_t q;
+	uint8_t i0, i1, i2, i3;
+
+	crc = (__force uint32_t) __cpu_to_le32(crc);
+
+	/* unroll loop into 'init_bytes' odd bytes followed by
+	 * 'words' aligned 4 byte words followed by
+	 * 'end_bytes' odd bytes at the end */
+	p8 = buf;
+	p32 = (uint32_t *)PTR_ALIGN(p8, 4);
+	init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
+	words = (len - init_bytes) >> 2;
+	end_bytes = (len - init_bytes) & 3;
+
+	for (i = 0; i < init_bytes; i++) {
+#ifndef WORDS_BIGENDIAN
+		i0 = *p8++ ^ crc;
+		crc = t0_le[i0] ^ (crc >> 8);
+#else
+		i0 = *p8++ ^ (crc >> 24);
+		crc = t0_le[i0] ^ (crc << 8);
+#endif
+	}
+
+	/* using pre-increment below slightly faster */
+	p32--;
+
+	for (i = 0; i < words; i++) {
+#ifndef WORDS_BIGENDIAN
+		q = *++p32 ^ crc;
+		i3 = q;
+		i2 = q >> 8;
+		i1 = q >> 16;
+		i0 = q >> 24;
+		crc = t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
+#else
+		q = *++p32 ^ crc;
+		i3 = q >> 24;
+		i2 = q >> 16;
+		i1 = q >> 8;
+		i0 = q;
+		crc = t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
+#endif
+	}
+
+	p8 = (uint8_t *)(++p32);
+
+	for (i = 0; i < end_bytes; i++) {
+#ifndef WORDS_BIGENDIAN
+		i0 = *p8++ ^ crc;
+		crc = t0_le[i0] ^ (crc >> 8);
+#else
+		i0 = *p8++ ^ (crc >> 24);
+		crc = t0_le[i0] ^ (crc << 8);
+#endif
+	}
+
+	return __le32_to_cpu((__force __le32)crc);
+}
+#endif
+
+#if CRC_BE_BITS == 32
+static uint32_t crc32c_be_body(uint32_t crc, uint8_t const *buf, size_t len)
+{
+	const uint8_t *p8;
+	const uint32_t *p32;
+	size_t init_bytes;
+	size_t words;
+	size_t end_bytes;
+	size_t i;
+	uint32_t q;
+	uint8_t i0, i1, i2, i3;
+
+	crc = (__force uint32_t) __cpu_to_be32(crc);
+
+	p8 = buf;
+	p32 = (uint32_t *)PTR_ALIGN(p8, 4);
+	init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
+	words = (len - init_bytes) >> 2;
+	end_bytes = (len - init_bytes) & 3;
+
+	for (i = 0; i < init_bytes; i++) {
+#ifndef WORDS_BIGENDIAN
+		i0 = *p8++ ^ crc;
+		crc = t0_be[i0] ^ (crc >> 8);
+#else
+		i0 = *p8++ ^ (crc >> 24);
+		crc = t0_be[i0] ^ (crc << 8);
+#endif
+	}
+
+	p32--;
+
+	for (i = 0; i < words; i++) {
+#ifndef WORDS_BIGENDIAN
+		q = *++p32 ^ crc;
+		i3 = q;
+		i2 = q >> 8;
+		i1 = q >> 16;
+		i0 = q >> 24;
+		crc = t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
+#else
+		q = *++p32 ^ crc;
+		i3 = q >> 24;
+		i2 = q >> 16;
+		i1 = q >> 8;
+		i0 = q;
+		crc = t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
+#endif
+	}
+
+	p8 = (uint8_t *)(++p32);
+
+	for (i = 0; i < end_bytes; i++) {
+#ifndef WORDS_BIGENDIAN
+		i0 = *p8++ ^ crc;
+		crc = t0_be[i0] ^ (crc >> 8);
+#else
+		i0 = *p8++ ^ (crc >> 24);
+		crc = t0_be[i0] ^ (crc << 8);
+#endif
+	}
+
+	return __be32_to_cpu((__force __be32)crc);
+}
+#endif
+
+#if CRC_LE_BITS == 64
+/* slice by 8 algorithm */
+static uint32_t crc32c_le_body(uint32_t crc, uint8_t const *buf, size_t len)
+{
+	const uint8_t *p8;
+	const uint32_t *p32;
+	size_t init_bytes;
+	size_t words;
+	size_t end_bytes;
+	size_t i;
+	uint32_t q;
+	uint8_t i0, i1, i2, i3;
+
+	crc = (__force uint32_t) __cpu_to_le32(crc);
+
+	p8 = buf;
+	p32 = (uint32_t *)PTR_ALIGN(p8, 8);
+	init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
+	words = (len - init_bytes) >> 3;
+	end_bytes = (len - init_bytes) & 7;
+
+	for (i = 0; i < init_bytes; i++) {
+#ifndef WORDS_BIGENDIAN
+		i0 = *p8++ ^ crc;
+		crc = t0_le[i0] ^ (crc >> 8);
+#else
+		i0 = *p8++ ^ (crc >> 24);
+		crc = t0_le[i0] ^ (crc << 8);
+#endif
+	}
+
+	p32--;
+
+	for (i = 0; i < words; i++) {
+#ifndef WORDS_BIGENDIAN
+		q = *++p32 ^ crc;
+		i3 = q;
+		i2 = q >> 8;
+		i1 = q >> 16;
+		i0 = q >> 24;
+		crc = t7_le[i3] ^ t6_le[i2] ^ t5_le[i1] ^ t4_le[i0];
+
+		q = *++p32;
+		i3 = q;
+		i2 = q >> 8;
+		i1 = q >> 16;
+		i0 = q >> 24;
+		crc ^= t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
+#else
+		q = *++p32 ^ crc;
+		i3 = q >> 24;
+		i2 = q >> 16;
+		i1 = q >> 8;
+		i0 = q;
+		crc = t7_le[i3] ^ t6_le[i2] ^ t5_le[i1] ^ t4_le[i0];
+
+		q = *++p32;
+		i3 = q >> 24;
+		i2 = q >> 16;
+		i1 = q >> 8;
+		i0 = q;
+		crc ^= t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
+#endif
+	}
+
+	p8 = (uint8_t *)(++p32);
+
+	for (i = 0; i < end_bytes; i++) {
+#ifndef WORDS_BIGENDIAN
+		i0 = *p8++ ^ crc;
+		crc = t0_le[i0] ^ (crc >> 8);
+#else
+		i0 = *p8++ ^ (crc >> 24);
+		crc = t0_le[i0] ^ (crc << 8);
+#endif
+	}
+
+	return __le32_to_cpu(crc);
+}
+#endif
+
+#if CRC_BE_BITS == 64
+static uint32_t crc32c_be_body(uint32_t crc, uint8_t const *buf, size_t len)
+{
+	const uint8_t *p8;
+	const uint32_t *p32;
+	size_t init_bytes;
+	size_t words;
+	size_t end_bytes;
+	size_t i;
+	uint32_t q;
+	uint8_t i0, i1, i2, i3;
+
+	crc = (__force uint32_t) __cpu_to_be32(crc);
+
+	p8 = buf;
+	p32 = (uint32_t *)PTR_ALIGN(p8, 8);
+	init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
+	words = (len - init_bytes) >> 3;
+	end_bytes = (len - init_bytes) & 7;
+
+	for (i = 0; i < init_bytes; i++) {
+#ifndef WORDS_BIGENDIAN
+		i0 = *p8++ ^ crc;
+		crc = t0_be[i0] ^ (crc >> 8);
+#else
+		i0 = *p8++ ^ (crc >> 24);
+		crc = t0_be[i0] ^ (crc << 8);
+#endif
+	}
+
+	p32--;
+
+	for (i = 0; i < words; i++) {
+#ifndef WORDS_BIGENDIAN
+		q = *++p32 ^ crc;
+		i3 = q;
+		i2 = q >> 8;
+		i1 = q >> 16;
+		i0 = q >> 24;
+		crc = t7_be[i3] ^ t6_be[i2] ^ t5_be[i1] ^ t4_be[i0];
+
+		q = *++p32;
+		i3 = q;
+		i2 = q >> 8;
+		i1 = q >> 16;
+		i0 = q >> 24;
+		crc ^= t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
+#else
+		q = *++p32 ^ crc;
+		i3 = q >> 24;
+		i2 = q >> 16;
+		i1 = q >> 8;
+		i0 = q;
+		crc = t7_be[i3] ^ t6_be[i2] ^ t5_be[i1] ^ t4_be[i0];
+
+		q = *++p32;
+		i3 = q >> 24;
+		i2 = q >> 16;
+		i1 = q >> 8;
+		i0 = q;
+		crc ^= t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
+#endif
+	}
+
+	p8 = (uint8_t *)(++p32);
+
+	for (i = 0; i < end_bytes; i++) {
+#ifndef WORDS_BIGENDIAN
+		i0 = *p8++ ^ crc;
+		crc = t0_be[i0] ^ (crc >> 8);
+#else
+		i0 = *p8++ ^ (crc >> 24);
+		crc = t0_be[i0] ^ (crc << 8);
+#endif
+	}
+
+	return __be32_to_cpu(crc);
+}
+#endif
+
+/**
+ * crc32c_le() - Calculate bitwise little-endian CRC32c.
+ * @crc: seed value for computation.  ~0 for ext4, sometimes 0 for
+ *	other uses, or the previous crc32c value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+uint32_t crc32c_le(uint32_t crc, unsigned char const *p, size_t len)
+{
+#if CRC_LE_BITS == 1
+	int i;
+	while (len--) {
+		crc ^= *p++;
+		for (i = 0; i < 8; i++)
+			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+	}
+# elif CRC_LE_BITS == 2
+	while (len--) {
+		crc ^= *p++;
+		crc = (crc >> 2) ^ t0_le[crc & 0x03];
+		crc = (crc >> 2) ^ t0_le[crc & 0x03];
+		crc = (crc >> 2) ^ t0_le[crc & 0x03];
+		crc = (crc >> 2) ^ t0_le[crc & 0x03];
+	}
+# elif CRC_LE_BITS == 4
+	while (len--) {
+		crc ^= *p++;
+		crc = (crc >> 4) ^ t0_le[crc & 0x0f];
+		crc = (crc >> 4) ^ t0_le[crc & 0x0f];
+	}
+# elif CRC_LE_BITS == 8
+	while (len--) {
+		crc ^= *p++;
+		crc = (crc >> 8) ^ t0_le[crc & 0xff];
+	}
+# else
+	crc = crc32c_le_body(crc, p, len);
+# endif
+	return crc;
+}
+
+/**
+ * crc32c_be() - Calculate bitwise big-endian CRC32c.
+ * @crc: seed value for computation.  ~0 for ext4, sometimes 0 for
+ *	other uses, or the previous crc32c value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+uint32_t crc32c_be(uint32_t crc, unsigned char const *p, size_t len)
+{
+#if CRC_BE_BITS == 1
+	int i;
+	while (len--) {
+		crc ^= *p++ << 24;
+		for (i = 0; i < 8; i++)
+			crc = (crc << 1) ^
+			      ((crc & 0x80000000) ? CRCPOLY_BE : 0);
+	}
+# elif CRC_BE_BITS == 2
+	while (len--) {
+		crc ^= *p++ << 24;
+		crc = (crc << 2) ^ t0_be[crc >> 30];
+		crc = (crc << 2) ^ t0_be[crc >> 30];
+		crc = (crc << 2) ^ t0_be[crc >> 30];
+		crc = (crc << 2) ^ t0_be[crc >> 30];
+	}
+# elif CRC_BE_BITS == 4
+	while (len--) {
+		crc ^= *p++ << 24;
+		crc = (crc << 4) ^ t0_be[crc >> 28];
+		crc = (crc << 4) ^ t0_be[crc >> 28];
+	}
+# elif CRC_BE_BITS == 8
+	while (len--) {
+		crc ^= *p++ << 24;
+		crc = (crc << 8) ^ t0_be[crc >> 24];
+	}
+# else
+	crc = crc32c_be_body(crc, p, len);
+# endif
+	return crc;
+}
diff --git a/lib/ext2fs/crc32c_defs.h b/lib/ext2fs/crc32c_defs.h
new file mode 100644
index 0000000..1752970
--- /dev/null
+++ b/lib/ext2fs/crc32c_defs.h
@@ -0,0 +1,67 @@
+/*
+ * This is the CRC32c polynomial, as outlined by Castagnoli.
+ * x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+
+ * x^8+x^6+x^0
+ */
+#define CRCPOLY_LE 0x82F63B78
+#define CRCPOLY_BE 0x1EDC6F41
+
+/* How many bits at a time to use.  Valid values are 1, 2, 4, 8, 32 and 64. */
+/* For less performance-sensitive, use 4 */
+#ifndef CRC_LE_BITS
+# define CRC_LE_BITS 64
+#endif
+#ifndef CRC_BE_BITS
+# define CRC_BE_BITS 64
+#endif
+
+/*
+ * Little-endian CRC computation.  Used with serial bit streams sent
+ * lsbit-first.  Be sure to use cpu_to_le32() to append the computed CRC.
+ */
+#if CRC_LE_BITS > 64 || CRC_LE_BITS < 1 || CRC_LE_BITS == 16 || \
+	CRC_LE_BITS & CRC_LE_BITS-1
+# error "CRC_LE_BITS must be one of {1, 2, 4, 8, 32, 64}"
+#endif
+
+/*
+ * Big-endian CRC computation.  Used with serial bit streams sent
+ * msbit-first.  Be sure to use cpu_to_be32() to append the computed CRC.
+ */
+#if CRC_BE_BITS > 64 || CRC_BE_BITS < 1 || CRC_BE_BITS == 16 || \
+	CRC_BE_BITS & CRC_BE_BITS-1
+# error "CRC_BE_BITS must be one of {1, 2, 4, 8, 32, 64}"
+#endif
+
+
+#define ___constant_swab32(x) \
+	((uint32_t)( \
+		(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
+		(((uint32_t)(x) & (uint32_t)0x0000ff00UL) <<  8) | \
+		(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >>  8) | \
+		(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)))
+
+
+#ifdef WORDS_BIGENDIAN
+#define __constant_cpu_to_le32(x) ___constant_swab32((x))
+#define __constant_cpu_to_be32(x) (x)
+#define __be32_to_cpu(x) (x)
+#define __cpu_to_be32(x) (x)
+#define __cpu_to_le32(x) (htole32((x)))
+#define __le32_to_cpu(x) (le32toh((x)))
+#else
+#define __constant_cpu_to_le32(x) (x)
+#define __constant_cpu_to_be32(x) ___constant_swab32((x))
+#define __be32_to_cpu(x) (be32toh((x)))
+#define __cpu_to_be32(x) (htobe32((x)))
+#define __cpu_to_le32(x) (x)
+#define __le32_to_cpu(x) (x)
+#endif
+
+#if (__GNUC__ >= 3)
+#define likely(x)	__builtin_expect(!!(x), 1)
+#define unlikely(x)	__builtin_expect(!!(x), 0)
+#else
+#define likely(x)	(x)
+#define unlikely(x)	(x)
+#endif
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index e638169..e571508 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -887,6 +887,10 @@ extern int ext2fs_super_and_bgd_loc(ext2_filsys fs,
 				    int *ret_meta_bg);
 extern void ext2fs_update_dynamic_rev(ext2_filsys fs);
 
+/* crc32c.c */
+extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len);
+extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
+
 /* csum.c */
 extern void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group);
 extern int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group);
diff --git a/lib/ext2fs/gen_crc32ctable.c b/lib/ext2fs/gen_crc32ctable.c
new file mode 100644
index 0000000..9996e9d
--- /dev/null
+++ b/lib/ext2fs/gen_crc32ctable.c
@@ -0,0 +1,123 @@
+#include <stdio.h>
+#include "crc32c_defs.h"
+#include <inttypes.h>
+
+#define ENTRIES_PER_LINE 4
+
+#if CRC_LE_BITS <= 8
+#define LE_TABLE_SIZE (1 << CRC_LE_BITS)
+#else
+#define LE_TABLE_SIZE 256
+#endif
+
+#if CRC_BE_BITS <= 8
+#define BE_TABLE_SIZE (1 << CRC_BE_BITS)
+#else
+#define BE_TABLE_SIZE 256
+#endif
+
+static uint32_t crc32ctable_le[8][256];
+static uint32_t crc32ctable_be[8][256];
+
+/**
+ * crc32cinit_le() - allocate and initialize LE table data
+ *
+ * crc is the crc of the byte i; other entries are filled in based on the
+ * fact that crctable[i^j] = crctable[i] ^ crctable[j].
+ *
+ */
+static void crc32cinit_le(void)
+{
+	unsigned i, j;
+	uint32_t crc = 1;
+
+	crc32ctable_le[0][0] = 0;
+
+	for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) {
+		crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+		for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
+			crc32ctable_le[0][i + j] = crc ^ crc32ctable_le[0][j];
+	}
+	for (i = 0; i < LE_TABLE_SIZE; i++) {
+		crc = crc32ctable_le[0][i];
+		for (j = 1; j < 8; j++) {
+			crc = crc32ctable_le[0][crc & 0xff] ^ (crc >> 8);
+			crc32ctable_le[j][i] = crc;
+		}
+	}
+}
+
+/**
+ * crc32cinit_be() - allocate and initialize BE table data
+ */
+static void crc32cinit_be(void)
+{
+	unsigned i, j;
+	uint32_t crc = 0x80000000;
+
+	crc32ctable_be[0][0] = 0;
+
+	for (i = 1; i < BE_TABLE_SIZE; i <<= 1) {
+		crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
+		for (j = 0; j < i; j++)
+			crc32ctable_be[0][i + j] = crc ^ crc32ctable_be[0][j];
+	}
+	for (i = 0; i < BE_TABLE_SIZE; i++) {
+		crc = crc32ctable_be[0][i];
+		for (j = 1; j < 8; j++) {
+			crc = crc32ctable_be[0][(crc >> 24) & 0xff] ^
+			      (crc << 8);
+			crc32ctable_be[j][i] = crc;
+		}
+	}
+}
+
+static void output_table(uint32_t table[8][256], int len, char trans)
+{
+	int i, j;
+
+	for (j = 0 ; j < 8; j++) {
+		printf("static const uint32_t t%d_%ce[] = {", j, trans);
+		for (i = 0; i < len - 1; i++) {
+			if ((i % ENTRIES_PER_LINE) == 0)
+				printf("\n");
+			printf("to%ce(0x%8.8xL),", trans, table[j][i]);
+			if ((i % ENTRIES_PER_LINE) != (ENTRIES_PER_LINE - 1))
+				printf(" ");
+		}
+		printf("to%ce(0x%8.8xL)};\n\n", trans, table[j][len - 1]);
+
+		if (trans == 'l') {
+			if ((j+1)*8 >= CRC_LE_BITS)
+				break;
+		} else {
+			if ((j+1)*8 >= CRC_BE_BITS)
+				break;
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	printf("/*\n");
+	printf(" * crc32ctable.h - CRC32c tables\n");
+	printf(" *    this file is generated - do not edit\n");
+	printf(" *	# gen_crc32ctable > crc32c_table.h\n");
+	printf(" *    with\n");
+	printf(" *	CRC_LE_BITS = %d\n", CRC_LE_BITS);
+	printf(" *	CRC_BE_BITS = %d\n", CRC_BE_BITS);
+	printf(" */\n");
+	printf("#include <stdint.h>\n");
+
+	if (CRC_LE_BITS > 1) {
+		crc32cinit_le();
+		output_table(crc32ctable_le, LE_TABLE_SIZE, 'l');
+	}
+
+	if (CRC_BE_BITS > 1) {
+		crc32cinit_be();
+		output_table(crc32ctable_be, BE_TABLE_SIZE, 'b');
+	}
+
+	return 0;
+}


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

* [PATCH 05/37] libext2fs: Implement a crc32c self-test
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (3 preceding siblings ...)
  2011-09-01  0:35 ` [PATCH 04/37] libext2fs: Add crc32c implementation for metadata checksumming Darrick J. Wong
@ 2011-09-01  0:35 ` Darrick J. Wong
  2011-09-01  0:35 ` [PATCH 06/37] libext2fs: Add inode checksum support Darrick J. Wong
                   ` (30 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:35 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Provide a self-test mechanism so that we can verify the correct operation of
the crc32c code.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/Makefile.in |    5 
 lib/ext2fs/crc32c.c    |  692 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 697 insertions(+), 0 deletions(-)


diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index f05cba8..5ab789e 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -338,11 +338,16 @@ tst_csum: csum.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR) \
 	$(Q) $(CC) -o tst_csum $(srcdir)/csum.c -DDEBUG \
 		$(ALL_CFLAGS) $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(LIBE2P)
 
+tst_crc32c: $(srcdir)/crc32c.c
+	$(Q) $(CC) $(BUILD_LDFLAGS) $(ALL_CFLAGS) -o tst_crc32c $(srcdir)/crc32c.c \
+		-DUNITTEST
+
 mkjournal: mkjournal.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
 	$(E) "	LD $@"
 	$(Q) $(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS)
 
 check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount tst_super_size tst_types tst_csum
+	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_crc32c
 	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
diff --git a/lib/ext2fs/crc32c.c b/lib/ext2fs/crc32c.c
index 229bd37..ba3a366 100644
--- a/lib/ext2fs/crc32c.c
+++ b/lib/ext2fs/crc32c.c
@@ -31,6 +31,7 @@
 #include <stdint.h>
 #include <endian.h>
 #include <stdlib.h>
+#include <stdio.h>
 #define __force
 #define min(x, y)		((x) > (y) ? (y) : (x))
 #define __ALIGN_KERNEL_MASK(x, mask)	(((x) + (mask)) & ~(mask))
@@ -433,3 +434,694 @@ uint32_t crc32c_be(uint32_t crc, unsigned char const *p, size_t len)
 # endif
 	return crc;
 }
+
+#ifdef UNITTEST
+static uint8_t test_buf[] = {
+	0xd9, 0xd7, 0x6a, 0x13, 0x3a, 0xb1, 0x05, 0x48,
+	0xda, 0xad, 0x14, 0xbd, 0x03, 0x3a, 0x58, 0x5e,
+	0x6e, 0xd1, 0x56, 0xc9, 0x2e, 0xc4, 0xcb, 0x6b,
+	0xe8, 0x77, 0x52, 0x37, 0x4e, 0x0f, 0x55, 0xd2,
+	0x12, 0x65, 0x90, 0xc2, 0x41, 0x49, 0x81, 0x01,
+	0xf5, 0x01, 0xeb, 0x2d, 0x78, 0x74, 0x23, 0x5d,
+	0x84, 0x5c, 0x81, 0x92, 0x21, 0xe9, 0x8d, 0x1d,
+	0x89, 0xf2, 0x4a, 0xac, 0xdd, 0xf9, 0xaf, 0xee,
+	0x44, 0xe7, 0x6e, 0xed, 0xfb, 0xd8, 0x89, 0x0e,
+	0x96, 0x62, 0xcd, 0xa4, 0x4b, 0xa9, 0xe5, 0x45,
+	0xb1, 0x29, 0x9b, 0x0f, 0xfc, 0xbd, 0x83, 0xab,
+	0xa8, 0x54, 0x96, 0x44, 0x2c, 0x7f, 0xbb, 0xe7,
+	0x52, 0x29, 0x08, 0xee, 0x14, 0xc5, 0xc2, 0xec,
+	0x5a, 0xeb, 0x40, 0x40, 0xea, 0xd1, 0x3d, 0x15,
+	0x73, 0xaa, 0x8c, 0x73, 0xfc, 0xf2, 0x2b, 0x49,
+	0x0b, 0x13, 0x96, 0xd9, 0x8e, 0x4b, 0xbc, 0xe0,
+	0xf4, 0xd2, 0xe0, 0x2e, 0x7a, 0xf0, 0x5d, 0x1f,
+	0xd2, 0x92, 0x97, 0xe0, 0xaa, 0x59, 0xab, 0xc9,
+	0x5c, 0xa6, 0x51, 0x1a, 0xe3, 0xd6, 0x06, 0xb9,
+	0xae, 0xb8, 0x76, 0x36, 0x79, 0x37, 0x52, 0xf6,
+	0x34, 0xaf, 0x27, 0x19, 0xe1, 0xc0, 0x2b, 0xdd,
+	0x01, 0x15, 0xcd, 0xce, 0x44, 0xf6, 0x4c, 0x18,
+	0x92, 0x69, 0xbe, 0x8a, 0x76, 0x23, 0x52, 0x13,
+	0x3f, 0xf9, 0xe0, 0xf5, 0x06, 0x28, 0x7c, 0xc7,
+	0xf3, 0x42, 0x0f, 0xdd, 0x40, 0x33, 0xf7, 0x99,
+	0xe2, 0xad, 0x26, 0xd9, 0x53, 0x10, 0x72, 0x0c,
+	0x4e, 0x43, 0x4c, 0x61, 0xfe, 0xd9, 0xc1, 0x16,
+	0xa1, 0x93, 0xca, 0x3c, 0x75, 0x7f, 0x07, 0x7a,
+	0x65, 0xb3, 0x53, 0x2a, 0x52, 0x00, 0xa0, 0x62,
+	0xe0, 0xa3, 0x1f, 0xad, 0xd7, 0xbb, 0xc0, 0x83,
+	0x5d, 0x54, 0x87, 0x5f, 0xc8, 0x2f, 0xc8, 0xbf,
+	0x69, 0x04, 0x91, 0xc8, 0xa6, 0x1d, 0x4d, 0x46,
+	0x91, 0xfc, 0x26, 0xf4, 0x16, 0xd1, 0xa4, 0xbf,
+	0x5c, 0xa2, 0x6c, 0xdd, 0xb4, 0x40, 0xf2, 0x2e,
+	0xa2, 0xad, 0xf7, 0xf4, 0xa5, 0x8a, 0x3e, 0x23,
+	0x64, 0x08, 0xc8, 0xa1, 0xa0, 0xf0, 0x5d, 0x70,
+	0xd2, 0x77, 0xfd, 0xc8, 0x50, 0x83, 0x0f, 0xd6,
+	0x2b, 0xe4, 0x1f, 0x52, 0x34, 0x33, 0x68, 0xfd,
+	0x92, 0xbe, 0x9f, 0x97, 0x6b, 0x8d, 0x81, 0x91,
+	0x0f, 0xef, 0x65, 0xc8, 0x0d, 0x15, 0x01, 0x77,
+	0x58, 0xb2, 0xf4, 0x1b, 0x06, 0x7e, 0xf5, 0xca,
+	0x15, 0x2e, 0x38, 0xd8, 0x81, 0x1c, 0x1c, 0xa0,
+	0xb6, 0x13, 0x6a, 0x2b, 0x71, 0x34, 0x52, 0xd7,
+	0x1d, 0xbd, 0x37, 0x59, 0xbc, 0x86, 0x25, 0x2b,
+	0xa8, 0x93, 0xce, 0x1a, 0x03, 0x16, 0xfe, 0x01,
+	0x57, 0x99, 0x24, 0x25, 0x2c, 0xb3, 0xab, 0x1e,
+	0x2d, 0x65, 0x20, 0x89, 0x17, 0x02, 0x0e, 0x0a,
+	0xf5, 0x1e, 0xc7, 0xff, 0x1f, 0x61, 0xa9, 0x54,
+	0x18, 0xd4, 0xba, 0x50, 0x57, 0x02, 0xa1, 0xab,
+	0x22, 0x2e, 0x07, 0xea, 0xa9, 0xa3, 0x83, 0x4f,
+	0x27, 0xf5, 0xc5, 0xee, 0x3c, 0x3b, 0x10, 0xad,
+	0x32, 0x2b, 0x1c, 0x03, 0xcb, 0xaf, 0x98, 0x83,
+	0x54, 0xc3, 0x68, 0x63, 0xd4, 0xe0, 0x0e, 0x3c,
+	0x1a, 0x4e, 0xc0, 0x81, 0xd0, 0xe8, 0x6a, 0x62,
+	0x6b, 0x3e, 0x6f, 0xc4, 0xc6, 0x33, 0x4e, 0x26,
+	0x21, 0xf5, 0x04, 0xdf, 0xfa, 0xce, 0x45, 0xaf,
+	0xdc, 0x5e, 0x1b, 0xad, 0x93, 0xca, 0xf5, 0xcf,
+	0xd7, 0xee, 0x0c, 0x5c, 0x5e, 0xb4, 0xf0, 0x92,
+	0xd2, 0xf2, 0xf0, 0xa9, 0x1e, 0xab, 0x80, 0x68,
+	0x46, 0xef, 0xcc, 0x26, 0x0c, 0x5c, 0xdd, 0x4e,
+	0x83, 0xb8, 0xb9, 0x53, 0x6e, 0xf8, 0x93, 0x38,
+	0x67, 0xa4, 0x41, 0x87, 0x72, 0xe7, 0x7e, 0x86,
+	0xc9, 0x49, 0x00, 0x33, 0xb1, 0x38, 0x6c, 0x71,
+	0xd7, 0x1d, 0x8e, 0x61, 0x01, 0xb6, 0x57, 0xa9,
+	0xf1, 0xac, 0x15, 0xc2, 0x83, 0x77, 0xca, 0x64,
+	0xca, 0x7b, 0x6c, 0xa1, 0x10, 0x1b, 0x13, 0xd0,
+	0xd3, 0x9e, 0x9e, 0x10, 0x70, 0xc8, 0x1a, 0xbb,
+	0x3f, 0x19, 0x86, 0xab, 0x01, 0x0e, 0xea, 0x34,
+	0x22, 0xea, 0xe2, 0x15, 0xb7, 0xed, 0x21, 0x21,
+	0x75, 0xa5, 0xe7, 0x08, 0xa1, 0x38, 0xe0, 0x91,
+	0x05, 0x60, 0xea, 0xa7, 0x50, 0x27, 0x18, 0x07,
+	0x9d, 0xe0, 0x18, 0x2b, 0xd4, 0x07, 0x59, 0x00,
+	0xe6, 0x45, 0x18, 0x2a, 0x30, 0x6e, 0xf3, 0xb4,
+	0xd0, 0xef, 0xa6, 0x5b, 0x71, 0xa2, 0x5a, 0x3b,
+	0x89, 0x4c, 0xaf, 0x3f, 0xcb, 0x9f, 0x03, 0xfb,
+	0x43, 0x7c, 0x6b, 0xd3, 0x6a, 0xea, 0xce, 0x4a,
+	0x5f, 0x64, 0xb5, 0x62, 0xda, 0x5d, 0x27, 0xb7,
+	0xb8, 0x11, 0xca, 0x33, 0x30, 0xec, 0x70, 0xf0,
+	0x1b, 0x03, 0x50, 0xff, 0x5e, 0xa6, 0x08, 0xde,
+	0x37, 0x70, 0xc0, 0x81, 0x55, 0x60, 0x17, 0xa1,
+	0x85, 0xae, 0x26, 0x44, 0xe4, 0x67, 0x3c, 0x91,
+	0xfd, 0xc4, 0x3d, 0x97, 0x72, 0x23, 0xf3, 0x3c,
+	0x8f, 0xe0, 0xe2, 0xf2, 0x09, 0x96, 0x10, 0x67,
+	0xb5, 0xfe, 0xff, 0x3d, 0x4a, 0xc8, 0x62, 0x11,
+	0xa5, 0x98, 0xc1, 0x2d, 0x40, 0x82, 0x88, 0x8b,
+	0xe5, 0xb0, 0x75, 0xbf, 0x2f, 0xa8, 0x6a, 0x55,
+	0x49, 0x2e, 0x9c, 0x29, 0xd2, 0x7c, 0xbf, 0xf3,
+	0xaa, 0x3a, 0x16, 0x4a, 0xa4, 0x15, 0xf3, 0x48,
+	0xde, 0x38, 0x13, 0x44, 0x26, 0x02, 0xe6, 0xe9,
+	0xa8, 0x24, 0x89, 0xb5, 0x43, 0x95, 0xe4, 0x4c,
+	0xc3, 0xa0, 0xdf, 0xcc, 0x42, 0xf8, 0x8d, 0xb0,
+	0x3b, 0xea, 0x10, 0xb7, 0xe1, 0x40, 0x54, 0xb9,
+	0xa3, 0x2d, 0xfb, 0xb4, 0x91, 0xc0, 0x3e, 0x94,
+	0xf1, 0xa1, 0x3c, 0xbe, 0xef, 0xb8, 0x70, 0x55,
+	0x0a, 0x26, 0x93, 0xbf, 0xe6, 0x21, 0x92, 0x32,
+	0x3c, 0x39, 0x27, 0x6a, 0x23, 0x48, 0x02, 0x35,
+	0x3c, 0xd4, 0xcc, 0x04, 0xc0, 0x4e, 0xa7, 0x02,
+	0x63, 0x37, 0xc2, 0xb8, 0x56, 0x1d, 0x57, 0x57,
+	0x42, 0x04, 0x8d, 0xee, 0xcf, 0x8b, 0xc9, 0xc3,
+	0xba, 0x3b, 0x15, 0xd7, 0xaf, 0xbf, 0x9e, 0xcd,
+	0x44, 0xcf, 0xf0, 0x00, 0xb7, 0x3a, 0xfc, 0xa8,
+	0x12, 0xab, 0x3a, 0x62, 0x01, 0x21, 0x46, 0xe9,
+	0x1e, 0x48, 0x37, 0xfc, 0x13, 0x4d, 0xf6, 0x2a,
+	0x72, 0x40, 0x75, 0x38, 0x71, 0xf2, 0x17, 0x20,
+	0x2c, 0xdd, 0xc0, 0x49, 0xbc, 0x63, 0x33, 0xea,
+	0x06, 0x75, 0x41, 0xe7, 0x5c, 0x1f, 0xfb, 0xf9,
+	0x68, 0x83, 0xc2, 0x5a, 0x4a, 0x1e, 0x61, 0x08,
+	0x57, 0xf3, 0x00, 0xba, 0x77, 0x92, 0x63, 0xa5,
+	0xb7, 0xfe, 0x97, 0x22, 0xda, 0x5e, 0xd3, 0xaf,
+	0xbc, 0x89, 0x0d, 0x4c, 0x37, 0xa9, 0x27, 0x4a,
+	0x7f, 0xdb, 0x81, 0x39, 0x11, 0x86, 0x12, 0xf9,
+	0x10, 0x50, 0xe4, 0xdb, 0x72, 0xf9, 0xae, 0x10,
+	0x7c, 0xed, 0x50, 0x5c, 0x61, 0xeb, 0x42, 0x1e,
+	0xa4, 0xf4, 0xf0, 0xfa, 0x45, 0x4d, 0x95, 0x2b,
+	0xd4, 0x67, 0x4a, 0xe3, 0x8a, 0x15, 0x55, 0x92,
+	0x77, 0x64, 0x8c, 0x51, 0x38, 0xf9, 0x26, 0x3e,
+	0x68, 0xe2, 0xac, 0xbb, 0x64, 0x77, 0xe2, 0x82,
+	0xa4, 0x42, 0x41, 0x38, 0xa0, 0xf0, 0xc9, 0xd8,
+	0x6c, 0xe0, 0xef, 0x4c, 0xda, 0xb4, 0x92, 0xef,
+	0x1b, 0xe3, 0x9b, 0xc1, 0x44, 0x3c, 0xb9, 0xb7,
+	0x39, 0xac, 0x5c, 0x32, 0x39, 0xb4, 0x21, 0x85,
+	0x93, 0xbc, 0xf2, 0x51, 0x43, 0xb7, 0xae, 0x1e,
+	0x61, 0x9c, 0x38, 0x9c, 0xaa, 0xff, 0xde, 0xfc,
+	0xbf, 0x85, 0xef, 0x17, 0x34, 0x36, 0x71, 0x5f,
+	0x04, 0x16, 0xa6, 0x9e, 0xfd, 0x3a, 0x03, 0xd8,
+	0xbf, 0x71, 0x70, 0x20, 0x8f, 0x7c, 0xfb, 0xff,
+	0x61, 0xe0, 0xe2, 0x60, 0xa7, 0xb1, 0xc0, 0xe0,
+	0xd9, 0x3f, 0xdc, 0x8d, 0x4a, 0xa4, 0x52, 0x61,
+	0xaf, 0x9d, 0xdf, 0x8a, 0x0d, 0x41, 0xc0, 0x25,
+	0x68, 0x12, 0x7b, 0xd5, 0xc7, 0xdb, 0x68, 0x70,
+	0x2d, 0x7d, 0x95, 0x12, 0x03, 0x23, 0x0c, 0xe8,
+	0x14, 0x41, 0x11, 0x28, 0xec, 0x9d, 0xd3, 0x28,
+	0x77, 0x7a, 0x3c, 0x93, 0x8e, 0x5c, 0x7e, 0xb3,
+	0x42, 0x9a, 0x18, 0x25, 0x93, 0xc8, 0xea, 0x43,
+	0x1b, 0xbe, 0xd5, 0x27, 0xf1, 0xd4, 0xe0, 0x1e,
+	0xce, 0xc7, 0xc7, 0x2c, 0x25, 0x35, 0x58, 0xb8,
+	0x6c, 0xf3, 0xa2, 0xad, 0xe7, 0x58, 0x49, 0x47,
+	0xf7, 0xca, 0xde, 0x8b, 0x81, 0xb7, 0x75, 0xf4,
+	0x95, 0xa7, 0x5c, 0xc3, 0x2c, 0x0e, 0x1c, 0x52,
+	0x9a, 0xc3, 0x2a, 0x00, 0x21, 0xa7, 0x51, 0x6b,
+	0xf0, 0x05, 0x87, 0x8c, 0x42, 0x1b, 0xc3, 0x2e,
+	0xa3, 0x76, 0x22, 0xd5, 0x7f, 0x56, 0x10, 0xef,
+	0x98, 0x85, 0x65, 0x86, 0x71, 0x87, 0xd2, 0x8c,
+	0xc0, 0x47, 0x20, 0xe8, 0xb5, 0x1c, 0xe3, 0xdd,
+	0x3c, 0x5c, 0x03, 0xbb, 0x0e, 0x97, 0x3b, 0xe1,
+	0x56, 0x9a, 0xd5, 0x0a, 0x63, 0xd5, 0x33, 0xaf,
+	0x36, 0xca, 0xcf, 0x8f, 0x00, 0x28, 0xa3, 0x45,
+	0xb8, 0xcd, 0xde, 0x73, 0xd4, 0xfa, 0x2d, 0x6f,
+	0xdb, 0x93, 0xaa, 0xdd, 0x7f, 0xd2, 0x22, 0x9c,
+	0x96, 0x48, 0x1e, 0xa8, 0x63, 0xbe, 0xbc, 0x0d,
+	0x14, 0x3c, 0x2e, 0x11, 0x1f, 0xd2, 0xf4, 0x57,
+	0xb3, 0x47, 0xf8, 0xa6, 0x1b, 0xc3, 0xa7, 0x95,
+	0x2d, 0xd4, 0xca, 0xb8, 0x0d, 0xfb, 0x06, 0x85,
+	0xda, 0x63, 0xf0, 0x3e, 0x9d, 0x5e, 0xee, 0xce,
+	0xed, 0x74, 0x1d, 0x2c, 0x97, 0x3f, 0x71, 0x95,
+	0x12, 0x03, 0xc5, 0x92, 0x46, 0x84, 0x1b, 0x07,
+	0xe6, 0xb4, 0x1d, 0x3a, 0xf1, 0x89, 0x90, 0x50,
+	0x10, 0x29, 0x34, 0xc0, 0x90, 0xbe, 0x4a, 0xa9,
+	0x0d, 0xb0, 0x7b, 0xfb, 0x35, 0xee, 0x4e, 0x34,
+	0xec, 0x5a, 0x58, 0xbc, 0xb8, 0xda, 0x38, 0x88,
+	0x8c, 0x74, 0x1e, 0xc9, 0xab, 0x78, 0x2e, 0x2a,
+	0x17, 0x8a, 0x43, 0x3d, 0xa1, 0x2a, 0x41, 0xb5,
+	0xd6, 0xe8, 0x5b, 0xc5, 0x4a, 0x1c, 0x3c, 0x9f,
+	0x8d, 0x3a, 0x69, 0x88, 0xf8, 0x80, 0xd2, 0x11,
+	0xfc, 0x7e, 0x80, 0x8e, 0x7f, 0x85, 0x64, 0x9c,
+	0x46, 0x58, 0xc8, 0x48, 0x98, 0x4b, 0xf5, 0x73,
+	0x3f, 0x49, 0xce, 0x53, 0x2c, 0xd5, 0xfc, 0x33,
+	0xf1, 0x6f, 0xd8, 0xe9, 0x2e, 0x70, 0x2e, 0xdc,
+	0xe5, 0x43, 0x80, 0x38, 0xf2, 0x87, 0xed, 0x85,
+	0xe4, 0x3e, 0x45, 0x14, 0x20, 0xcf, 0xa0, 0x61,
+	0x4f, 0xe8, 0xd7, 0x5b, 0xb3, 0x0d, 0x0e, 0x4e,
+	0x4d, 0xce, 0xbe, 0xba, 0xaa, 0x90, 0x09, 0xcb,
+	0x4b, 0x5d, 0x08, 0xff, 0x52, 0xd5, 0x23, 0xbc,
+	0xad, 0x8d, 0xd3, 0x06, 0x4a, 0xa0, 0x51, 0x56,
+	0xa7, 0xd8, 0x33, 0xab, 0xbc, 0xd0, 0xdf, 0x92,
+	0x87, 0x20, 0x2d, 0x7b, 0x5e, 0xfa, 0x30, 0xa7,
+	0x06, 0x06, 0xe5, 0x4f, 0x2c, 0xb5, 0x61, 0xd7,
+	0x54, 0xd3, 0xdf, 0xd0, 0x0a, 0xb0, 0x06, 0xce,
+	0xf6, 0x86, 0xb7, 0x8e, 0xaa, 0x7b, 0x78, 0xd5,
+	0xb9, 0xeb, 0x07, 0xac, 0x5f, 0xc5, 0xd2, 0x8c,
+	0x40, 0xe0, 0x7f, 0x98, 0xd4, 0xe5, 0x4b, 0xca,
+	0xfb, 0x47, 0xef, 0xef, 0xb9, 0x4d, 0x6d, 0x8f,
+	0x82, 0x68, 0x74, 0x84, 0xe0, 0x0a, 0x93, 0x0f,
+	0xb2, 0x01, 0xa9, 0x9f, 0x68, 0x6a, 0xe8, 0xf7,
+	0xfb, 0x0b, 0xde, 0x17, 0xe0, 0x30, 0x38, 0x51,
+	0xbc, 0x07, 0xb8, 0x2c, 0x91, 0x0f, 0xc1, 0x0e,
+	0xa6, 0xf9, 0xf0, 0xd5, 0x48, 0x76, 0x8a, 0xde,
+	0x74, 0xe3, 0x30, 0x65, 0x56, 0xb3, 0x5c, 0xe2,
+	0x89, 0x8d, 0xda, 0x80, 0xad, 0x0f, 0x22, 0xfb,
+	0x24, 0x1d, 0x16, 0xdd, 0x34, 0x4b, 0x90, 0x58,
+	0x4e, 0x0c, 0x13, 0x28, 0xcf, 0x1d, 0xa4, 0xaa,
+	0xb7, 0xf3, 0xb1, 0x66, 0xad, 0x3b, 0xcf, 0x79,
+	0x12, 0x04, 0xd7, 0x79, 0xd9, 0x5f, 0xdf, 0x89,
+	0xb2, 0x5b, 0xa7, 0x9a, 0x26, 0x1e, 0x67, 0x46,
+	0x7c, 0x66, 0x95, 0x67, 0xe6, 0x45, 0x8b, 0x1f,
+	0x65, 0x79, 0x9f, 0x6d, 0x11, 0x81, 0x17, 0x0d,
+	0x11, 0xb0, 0x5c, 0xb4, 0xc7, 0x27, 0x87, 0xab,
+	0x5d, 0x0a, 0x18, 0xae, 0x4e, 0x06, 0xa3, 0x3d,
+	0xc7, 0xb0, 0x22, 0xba, 0x03, 0xa4, 0x0f, 0xe5,
+	0x1c, 0x72, 0x2a, 0x04, 0xce, 0x83, 0xe9, 0xf3,
+	0xd7, 0xc9, 0x67, 0x6c, 0x1e, 0x6b, 0x3c, 0x9b,
+	0x0b, 0x5e, 0x6a, 0xa6, 0x79, 0x0a, 0xf1, 0xbe,
+	0xd7, 0xb4, 0x6f, 0x45, 0x1e, 0xfb, 0x78, 0x97,
+	0xaf, 0x34, 0x76, 0x95, 0x52, 0xf7, 0x3d, 0x5d,
+	0x07, 0x28, 0x57, 0x9c, 0x4a, 0x0f, 0xcf, 0x0b,
+	0x1b, 0xc4, 0xc2, 0x72, 0xd7, 0x72, 0x38, 0x9b,
+	0xea, 0xeb, 0xee, 0xae, 0x34, 0xc8, 0x01, 0xd7,
+	0xa5, 0xe3, 0xce, 0x41, 0xad, 0x02, 0x60, 0x23,
+	0x18, 0x36, 0xba, 0x17, 0xfa, 0xcf, 0xe4, 0xda,
+	0xdc, 0xfc, 0x82, 0xdc, 0x7c, 0x11, 0xf4, 0xb8,
+	0x52, 0x5d, 0xf7, 0x2f, 0xc8, 0xfe, 0x4a, 0xe6,
+	0xb9, 0xaf, 0x4b, 0x17, 0x18, 0x91, 0xc2, 0xfe,
+	0xd7, 0x3a, 0x77, 0x0c, 0xa0, 0x43, 0x9c, 0x6f,
+	0x13, 0x06, 0xbe, 0x6e, 0xe0, 0x1a, 0x3c, 0xf3,
+	0xf5, 0xcc, 0x78, 0xfb, 0x5d, 0xd5, 0xda, 0xb7,
+	0x58, 0xea, 0x86, 0x42, 0x6b, 0x32, 0xff, 0xb2,
+	0xe2, 0xee, 0x03, 0x1f, 0xf4, 0xef, 0xdb, 0x53,
+	0x79, 0xd5, 0x4e, 0xaf, 0x60, 0x8e, 0x02, 0xc2,
+	0xcc, 0x39, 0x97, 0x7b, 0xfd, 0xa1, 0xf8, 0x7a,
+	0x26, 0xe8, 0x55, 0xd6, 0xa4, 0x8b, 0xa0, 0x1b,
+	0x2d, 0x63, 0xaa, 0x73, 0x71, 0x6e, 0xbf, 0x8b,
+	0x3b, 0xe3, 0x1b, 0x0d, 0xbb, 0x2e, 0x44, 0x09,
+	0x64, 0xac, 0xc7, 0x9e, 0xb5, 0xc6, 0x77, 0xb0,
+	0x79, 0xb3, 0xaa, 0xfc, 0x67, 0x57, 0x9a, 0x50,
+	0x81, 0x37, 0x14, 0x7c, 0xd7, 0xa0, 0xd4, 0x6a,
+	0x79, 0x84, 0x51, 0x0e, 0x95, 0x0a, 0x30, 0xa3,
+	0x60, 0x55, 0x48, 0x05, 0x16, 0xae, 0x43, 0x90,
+	0xdc, 0x8e, 0x09, 0xbe, 0x79, 0xf6, 0x90, 0x74,
+	0xf8, 0x20, 0x96, 0x4d, 0xa7, 0xf5, 0x1a, 0x2b,
+	0xc7, 0x15, 0x9d, 0x18, 0xf7, 0x94, 0x87, 0xf7,
+	0xf4, 0xfb, 0x0d, 0x61, 0xb6, 0xd7, 0xbe, 0x10,
+	0x8e, 0x47, 0x3c, 0x10, 0x44, 0x90, 0x52, 0x21,
+	0x83, 0xc0, 0xf5, 0x99, 0xaa, 0xbc, 0xf6, 0x55,
+	0xae, 0xf5, 0xb2, 0xa4, 0xcd, 0x4d, 0xb9, 0x38,
+	0x6c, 0xbc, 0x80, 0xc3, 0xad, 0xf4, 0x46, 0x31,
+	0x01, 0x58, 0x2d, 0x88, 0x57, 0xc3, 0x23, 0xd1,
+	0x64, 0xc9, 0xa3, 0x21, 0x6b, 0x8b, 0x8a, 0x23,
+	0x2c, 0x4f, 0xa9, 0xcd, 0x67, 0xfa, 0x77, 0xad,
+	0xa3, 0x16, 0xa2, 0xe5, 0x19, 0x14, 0x70, 0x41,
+	0x5b, 0xda, 0x14, 0xde, 0xe3, 0xe5, 0xc1, 0x15,
+	0xb4, 0x77, 0xa4, 0x9b, 0xb8, 0xb1, 0x28, 0x51,
+	0x30, 0xb4, 0xf1, 0xf3, 0xf8, 0x6d, 0xd0, 0xc3,
+	0x8c, 0x4c, 0x76, 0xb0, 0x9a, 0xdf, 0xc8, 0xbe,
+	0xf8, 0x4a, 0x61, 0x6e, 0x3e, 0xd6, 0x3c, 0xe8,
+	0xde, 0x56, 0xa0, 0x9c, 0x25, 0xbe, 0xce, 0x93,
+	0x1f, 0x88, 0xfb, 0x9a, 0x1a, 0xe2, 0xff, 0x88,
+	0xad, 0x10, 0xcb, 0x6c, 0xd6, 0xe7, 0x39, 0x0b,
+	0xe5, 0x1a, 0x06, 0x05, 0x64, 0x5b, 0x0a, 0xdf,
+	0x22, 0x58, 0xd7, 0xfb, 0x88, 0x12, 0xdd, 0xb7,
+	0x52, 0x3a, 0xc9, 0xbf, 0x49, 0xdf, 0x8c, 0x87,
+	0x9f, 0x84, 0xb5, 0x0a, 0xf6, 0x00, 0x52, 0xae,
+	0x67, 0x12, 0x1a, 0x8c, 0x71, 0x15, 0xf5, 0xa1,
+	0x13, 0x39, 0xf0, 0x91, 0x7e, 0x88, 0x7c, 0xb3,
+	0x95, 0x50, 0x02, 0xa6, 0x63, 0xb5, 0x64, 0xfb,
+	0x90, 0x87, 0x61, 0xe2, 0x27, 0xaf, 0x11, 0x0c,
+	0x73, 0x83, 0xef, 0xa9, 0x28, 0xfe, 0xc8, 0x85,
+	0x1a, 0x3a, 0xde, 0xf2, 0xe5, 0x25, 0x64, 0x6d,
+	0xaa, 0x41, 0x4c, 0x80, 0x2e, 0x84, 0xff, 0xc1,
+	0xc0, 0x54, 0x0c, 0x29, 0x1b, 0xa3, 0x07, 0x7c,
+	0x33, 0x4c, 0x10, 0xf6, 0x6f, 0x79, 0xdf, 0xd3,
+	0xf0, 0x24, 0x57, 0xf1, 0x60, 0xe1, 0xf0, 0xbd,
+	0xc4, 0x1f, 0xf4, 0x67, 0xd2, 0xd3, 0xcc, 0x6a,
+	0x07, 0x72, 0x44, 0x16, 0x85, 0x46, 0xd0, 0x73,
+	0x87, 0xa9, 0xc7, 0x2f, 0xd1, 0xf5, 0xec, 0xe3,
+	0x28, 0xa3, 0x93, 0x4f, 0xd7, 0x76, 0xc1, 0x3c,
+	0x0d, 0x13, 0x33, 0xcf, 0x5b, 0xbd, 0x6a, 0x52,
+	0x4e, 0xee, 0xc8, 0x5e, 0xa1, 0x58, 0x4a, 0x08,
+	0x81, 0xd9, 0x23, 0xcc, 0xfb, 0x1c, 0xb2, 0xd8,
+	0xa3, 0xe4, 0x53, 0xfe, 0xf4, 0x4b, 0x48, 0xc1,
+	0x20, 0xa4, 0x97, 0xf8, 0x38, 0xa3, 0x69, 0xc1,
+	0x11, 0xf0, 0xa1, 0x3b, 0xa9, 0x9a, 0x12, 0x61,
+	0xe8, 0x8d, 0x99, 0x44, 0x3f, 0x94, 0x72, 0x82,
+	0x19, 0x96, 0x62, 0xb0, 0xa6, 0x64, 0x05, 0x19,
+	0x8f, 0xd6, 0x5d, 0x05, 0xbf, 0x79, 0x9e, 0x9d,
+	0xe4, 0x93, 0x4c, 0xad, 0x61, 0x8c, 0x18, 0xda,
+	0xb6, 0x2e, 0xb3, 0xca, 0x14, 0x4d, 0x53, 0xa4,
+	0x97, 0x27, 0x10, 0x56, 0xa2, 0x67, 0x5a, 0x5a,
+	0x5e, 0x13, 0xc0, 0xdb, 0xa7, 0x9f, 0x45, 0x5b,
+	0xeb, 0x1a, 0x14, 0x0c, 0x8c, 0x38, 0x5e, 0x77,
+	0x9a, 0xec, 0x75, 0x68, 0x93, 0x65, 0x02, 0x9c,
+	0xfb, 0x62, 0x60, 0x49, 0xdd, 0xb2, 0x2a, 0x67,
+	0x86, 0xe3, 0x8a, 0x7d, 0x8c, 0x46, 0x78, 0x81,
+	0x60, 0x69, 0xf2, 0x3f, 0x74, 0x11, 0x35, 0xff,
+	0x77, 0xa3, 0x66, 0x20, 0xfc, 0x98, 0x4a, 0x35,
+	0x7a, 0x52, 0xe4, 0x90, 0x13, 0x80, 0xb9, 0xa6,
+	0x73, 0x7a, 0x7d, 0x66, 0x6e, 0x6b, 0xb6, 0x43,
+	0x10, 0xd5, 0x91, 0x2b, 0x66, 0xdd, 0x89, 0x87,
+	0xe3, 0x8c, 0x58, 0x53, 0x2f, 0x40, 0x74, 0x45,
+	0x1b, 0x77, 0x7a, 0xa4, 0x44, 0x19, 0x78, 0xba,
+	0x87, 0x10, 0x41, 0x31, 0x32, 0x5f, 0x87, 0x68,
+	0xde, 0x43, 0x4a, 0xef, 0x33, 0xb3, 0x11, 0x83,
+	0xa9, 0xc2, 0x6f, 0x8d, 0x34, 0xe2, 0x95, 0x84,
+	0x3a, 0x4f, 0x6f, 0x8c, 0x31, 0x1d, 0xb6, 0xf5,
+	0x95, 0x0d, 0x01, 0x11, 0x20, 0xdf, 0x72, 0xf3,
+	0x3f, 0x9a, 0x33, 0xaa, 0xb1, 0x06, 0x6a, 0x63,
+	0x47, 0x91, 0x01, 0xdf, 0xb3, 0x54, 0x36, 0xfd,
+	0x06, 0x2d, 0xb8, 0x08, 0xe3, 0xd3, 0x65, 0xac,
+	0x66, 0x03, 0xee, 0xa4, 0x63, 0xbd, 0xd4, 0xce,
+	0xbd, 0x79, 0xa7, 0x48, 0x38, 0xc5, 0x7d, 0xb5,
+	0x71, 0x9a, 0x3c, 0x11, 0x7c, 0x6c, 0xe2, 0x54,
+	0x02, 0x5d, 0x42, 0xab, 0x25, 0x93, 0x66, 0x01,
+	0x37, 0x78, 0x35, 0x4a, 0x8c, 0x19, 0x4d, 0x00,
+	0x75, 0x4f, 0xcc, 0xc0, 0x26, 0x82, 0xc1, 0x35,
+	0x8c, 0xc7, 0xc2, 0x59, 0x01, 0x3e, 0x98, 0x22,
+	0x88, 0x9c, 0x90, 0x75, 0x05, 0x33, 0x07, 0xb9,
+	0x39, 0x81, 0x38, 0x58, 0x10, 0x29, 0xcf, 0xc8,
+	0x98, 0xb2, 0x03, 0xd7, 0x5b, 0xb3, 0x18, 0xba,
+	0x34, 0x0c, 0x9f, 0xab, 0xd7, 0xed, 0x29, 0x82,
+	0x41, 0xe0, 0x20, 0x97, 0x57, 0x92, 0xb2, 0xb8,
+	0x10, 0x2d, 0x0b, 0xa2, 0xc5, 0x8f, 0x90, 0x6f,
+	0xed, 0x12, 0x56, 0x25, 0xbe, 0xfd, 0x75, 0xf7,
+	0xb6, 0xf8, 0x40, 0x67, 0x39, 0x11, 0xfa, 0x15,
+	0xae, 0x6a, 0x54, 0x5f, 0x32, 0x2b, 0xf8, 0x48,
+	0x55, 0xbe, 0x86, 0x2f, 0x69, 0x48, 0x5b, 0x5d,
+	0x4d, 0xb7, 0x35, 0xaa, 0xb6, 0x91, 0x88, 0x19,
+	0x96, 0x1c, 0x68, 0xf6, 0x85, 0x9e, 0xb3, 0xb2,
+	0xa3, 0x32, 0xd4, 0x52, 0x70, 0xb7, 0x62, 0xe3,
+	0x14, 0xb6, 0x78, 0x5f, 0x1b, 0x1d, 0x04, 0x9c,
+	0x26, 0x0c, 0x33, 0x94, 0xb1, 0x97, 0x08, 0xdb,
+	0x0b, 0x39, 0x29, 0xd4, 0xbc, 0x6d, 0xdf, 0x02,
+	0xc6, 0x99, 0xab, 0x99, 0x32, 0xe5, 0xce, 0x51,
+	0x4f, 0xae, 0xb8, 0x8b, 0xe0, 0xaf, 0x07, 0xc4,
+	0xf9, 0x41, 0x7c, 0x59, 0xa0, 0xac, 0x74, 0x4d,
+	0x7e, 0x43, 0x77, 0x9c, 0x06, 0x49, 0x79, 0x8a,
+	0x14, 0x73, 0x93, 0xa8, 0x5b, 0x1b, 0x34, 0x29,
+	0x78, 0x04, 0x2f, 0xd7, 0x1f, 0x13, 0x90, 0xe0,
+	0xdd, 0x3b, 0x42, 0x6b, 0x79, 0x6e, 0x52, 0xc7,
+	0x0f, 0x38, 0xda, 0x01, 0x2c, 0x8d, 0xe6, 0x94,
+	0x5d, 0x59, 0x27, 0x1d, 0x10, 0x4e, 0x11, 0x36,
+	0xfb, 0x53, 0x16, 0x05, 0x25, 0xf2, 0x64, 0xd8,
+	0xf9, 0xcd, 0x5c, 0xfe, 0xb4, 0x18, 0x44, 0x80,
+	0x10, 0xbc, 0x3d, 0xf3, 0x1d, 0x5a, 0xf0, 0xc1,
+	0xc3, 0x55, 0xff, 0x41, 0x3e, 0xe3, 0xef, 0x44,
+	0xb2, 0xc0, 0x01, 0x18, 0xa2, 0x49, 0x88, 0x78,
+	0x0d, 0x4c, 0xc8, 0x73, 0xcf, 0x30, 0x85, 0x3a,
+	0x88, 0x90, 0x01, 0xcf, 0x69, 0x53, 0xa3, 0x18,
+	0x3f, 0xd6, 0xe7, 0x94, 0x14, 0xa7, 0xae, 0xcd,
+	0x6f, 0x11, 0x72, 0xfe, 0x2b, 0xb0, 0x81, 0x53,
+	0xea, 0x67, 0xd6, 0xe4, 0xca, 0x42, 0xa0, 0xf9,
+	0xb1, 0xd4, 0xb5, 0x3b, 0xc9, 0xf0, 0x36, 0xc1,
+	0x1c, 0xf4, 0xb1, 0xf6, 0x84, 0xd0, 0x86, 0x6c,
+	0x76, 0x9a, 0x03, 0xc2, 0xb6, 0x2e, 0x9a, 0x46,
+	0xf5, 0x5f, 0x2c, 0x38, 0xac, 0xad, 0x6f, 0x2e,
+	0x7a, 0x18, 0x2d, 0x22, 0x95, 0x5e, 0x5e, 0xc9,
+	0x7a, 0x0a, 0x56, 0xe1, 0xc7, 0x15, 0xfd, 0xbf,
+	0xff, 0xf7, 0x7e, 0x85, 0x20, 0xa9, 0x8a, 0x9c,
+	0xa9, 0x7d, 0xe8, 0xed, 0xfc, 0x7f, 0xbb, 0xf0,
+	0x05, 0x3f, 0xce, 0x4f, 0x4c, 0xee, 0xa4, 0xa0,
+	0xcc, 0x9c, 0x62, 0x1e, 0xd6, 0xd0, 0x30, 0x37,
+	0xb8, 0x98, 0x56, 0x1d, 0xaa, 0xd6, 0x5e, 0x73,
+	0x12, 0xe4, 0x88, 0x82, 0x48, 0x64, 0x06, 0xd7,
+	0x2a, 0x31, 0x50, 0x7b, 0x10, 0x17, 0xb8, 0x4c,
+	0x5a, 0x8d, 0xf1, 0xfc, 0xf1, 0x33, 0x3b, 0x98,
+	0x42, 0x18, 0x5b, 0x35, 0x78, 0xca, 0x8e, 0x41,
+	0x52, 0xae, 0x6d, 0xe1, 0xa2, 0x9d, 0x5b, 0xbd,
+	0xf3, 0x5f, 0x49, 0xc1, 0x27, 0x06, 0xc1, 0xaf,
+	0xc0, 0xa3, 0x9d, 0xf3, 0x1c, 0x8e, 0x90, 0x8a,
+	0xb0, 0x69, 0xb0, 0xc5, 0x11, 0x0c, 0x91, 0x14,
+	0x1f, 0x5e, 0x10, 0xe1, 0x1d, 0x14, 0x30, 0x54,
+	0x1e, 0x17, 0x3d, 0x31, 0x7b, 0xbf, 0x2f, 0x9d,
+	0x6d, 0x63, 0x32, 0xf0, 0x9d, 0x9f, 0x95, 0x3d,
+	0x0b, 0xd2, 0x4d, 0x10, 0xe2, 0x3f, 0x67, 0x69,
+	0x43, 0x9a, 0x4a, 0x2c, 0x54, 0x71, 0xa8, 0xa0,
+	0x9e, 0x9f, 0x10, 0xaf, 0x1b, 0xce, 0x99, 0xe3,
+	0x25, 0x32, 0x10, 0x54, 0x80, 0xfe, 0xda, 0x57,
+	0xd0, 0xb2, 0x92, 0x7f, 0xbb, 0x5f, 0xe7, 0x4d,
+	0x1b, 0x3d, 0x46, 0x4d, 0xe4, 0x4c, 0xd6, 0xaf,
+	0x1a, 0x32, 0x12, 0x40, 0xb8, 0x84, 0x8e, 0xe4,
+	0x80, 0xce, 0x7e, 0xc1, 0x13, 0x8b, 0xb0, 0xb7,
+	0x6f, 0x24, 0xba, 0x85, 0x50, 0x83, 0xc3, 0xcf,
+	0x19, 0xb3, 0xf0, 0xc7, 0xee, 0x68, 0xbe, 0x9e,
+	0x6d, 0xb9, 0xfb, 0xd5, 0x29, 0xce, 0x82, 0xcd,
+	0x69, 0x16, 0x68, 0x6b, 0x6a, 0xf4, 0x02, 0x32,
+	0xce, 0x60, 0x37, 0x0c, 0xb9, 0x38, 0x92, 0x9c,
+	0x42, 0xa9, 0x0b, 0x53, 0x96, 0xfe, 0x39, 0xc1,
+	0x24, 0x65, 0x9b, 0xcd, 0xe7, 0x8d, 0x36, 0x07,
+	0x9f, 0x1d, 0x35, 0x8e, 0xdc, 0x4c, 0xb5, 0x68,
+	0xc5, 0xfd, 0x44, 0x19, 0xf2, 0x6c, 0x59, 0x1c,
+	0xb1, 0x0b, 0x35, 0x48, 0x86, 0x1a, 0x05, 0x22,
+	0x03, 0x0c, 0x0c, 0xa2, 0x92, 0x90, 0x35, 0xfb,
+	0x37, 0x94, 0xc7, 0x15, 0x84, 0xae, 0xe8, 0x05,
+	0xa0, 0xf7, 0x30, 0x11, 0x5c, 0xe4, 0x5d, 0x3e,
+	0x12, 0x54, 0x80, 0x54, 0x6b, 0x09, 0x8c, 0xce,
+	0x80, 0x5e, 0xa7, 0xc8, 0x6a, 0x0c, 0x56, 0xe1,
+	0x18, 0x7d, 0xc9, 0x39, 0xc1, 0xef, 0xe3, 0x25,
+	0xa0, 0x8b, 0x2f, 0x60, 0x3a, 0x43, 0x39, 0xa6,
+	0x28, 0x28, 0x7b, 0x4c, 0x77, 0xd4, 0x49, 0x61,
+	0x46, 0xe9, 0x1b, 0x45, 0xd6, 0xb1, 0x56, 0xe1,
+	0x7d, 0x34, 0xcd, 0x06, 0xb6, 0x67, 0x8d, 0x7d,
+	0x7a, 0xe2, 0xbe, 0x68, 0x35, 0xa6, 0x78, 0xe5,
+	0x47, 0x48, 0xb7, 0xc7, 0xde, 0xcd, 0xc9, 0x05,
+	0xb4, 0xe7, 0x50, 0x48, 0xe1, 0x4b, 0xfe, 0x76,
+	0x77, 0xc6, 0xf7, 0x5f, 0xcb, 0xc2, 0xa8, 0xd7,
+	0xd6, 0x8a, 0xe5, 0x49, 0xd9, 0xca, 0x45, 0xf4,
+	0xda, 0xcd, 0x33, 0xd1, 0x59, 0x2d, 0x9e, 0xc1,
+	0x5c, 0xe6, 0x01, 0x18, 0xb8, 0xf0, 0x5e, 0xb1,
+	0x69, 0x95, 0x2f, 0x02, 0x2a, 0xe7, 0x4a, 0xd7,
+	0xd1, 0xc3, 0xd5, 0x6f, 0x15, 0xc8, 0xdc, 0x29,
+	0xde, 0xb9, 0x3f, 0x8b, 0xa6, 0xbc, 0xdd, 0x25,
+	0x84, 0x35, 0x3c, 0x90, 0x2d, 0xc2, 0x1e, 0x98,
+	0x8a, 0x50, 0x09, 0x77, 0x42, 0xe9, 0x35, 0x8a,
+	0x7c, 0x97, 0xbf, 0xe8, 0xbf, 0x56, 0xd0, 0x8b,
+	0x65, 0xd3, 0xaf, 0x1e, 0x05, 0x94, 0xfa, 0xac,
+	0xa8, 0x2b, 0x28, 0xcb, 0x37, 0x3e, 0xe8, 0xbb,
+	0x66, 0x3a, 0xed, 0xb2, 0x48, 0x10, 0x0f, 0x3a,
+	0x5a, 0xc5, 0xdb, 0x26, 0x0e, 0xaa, 0x5e, 0x69,
+	0x15, 0xd6, 0x81, 0xae, 0xbd, 0xe6, 0x03, 0xf1,
+	0xf6, 0x37, 0xc8, 0xde, 0x70, 0x1f, 0x64, 0xb9,
+	0x5e, 0xbf, 0x2e, 0x4f, 0xb1, 0xea, 0xa0, 0x17,
+	0xe6, 0x7c, 0xf9, 0x2f, 0x1e, 0xd8, 0x58, 0xde,
+	0xa7, 0xf0, 0x46, 0x52, 0x95, 0xdf, 0xa4, 0x96,
+	0xd0, 0xc4, 0x97, 0x2b, 0x95, 0xcd, 0x5e, 0x40,
+	0x23, 0x5c, 0x10, 0xee, 0xba, 0x72, 0x9b, 0xcf,
+	0x0b, 0xe8, 0x18, 0x3a, 0x70, 0xd2, 0x5e, 0x07,
+	0x68, 0x93, 0xef, 0x4a, 0x5b, 0x8d, 0x72, 0x41,
+	0x4e, 0xea, 0x33, 0x6a, 0x0a, 0x5e, 0xfb, 0x02,
+	0x3f, 0xd4, 0xed, 0x5b, 0xe0, 0x42, 0x84, 0xd4,
+	0xaa, 0x85, 0xdc, 0x5b, 0x67, 0xee, 0x71, 0x67,
+	0xba, 0x8e, 0xd2, 0xbe, 0x61, 0xdf, 0x5a, 0x26,
+	0xb9, 0xf0, 0x77, 0x81, 0x53, 0x24, 0x16, 0xcb,
+	0x8c, 0xb8, 0x06, 0x6e, 0x68, 0xda, 0xc8, 0x2d,
+	0x17, 0x54, 0xdb, 0x46, 0xcb, 0xfd, 0x1f, 0x3d,
+	0x94, 0x81, 0x09, 0x4b, 0xfa, 0xb1, 0x46, 0xd9,
+	0x11, 0xa3, 0xb7, 0x31, 0x9c, 0xd2, 0x38, 0xd6,
+	0xba, 0x3d, 0xa3, 0x74, 0xd8, 0xf1, 0x24, 0xe8,
+	0x9c, 0xcb, 0x1d, 0xf9, 0x4a, 0xf7, 0xc8, 0x4b,
+	0xfe, 0x97, 0x7c, 0xa1, 0x02, 0xeb, 0x40, 0xc3,
+	0x89, 0x71, 0x01, 0xcd, 0x33, 0x2a, 0xc2, 0x82,
+	0xce, 0x62, 0x8d, 0x53, 0x7c, 0xdf, 0xce, 0xd7,
+	0xf5, 0xa8, 0x4f, 0xf2, 0xf2, 0x2e, 0xc1, 0xeb,
+	0x97, 0x99, 0x37, 0x3c, 0x53, 0xa6, 0xb4, 0x46,
+	0x05, 0x64, 0x92, 0x87, 0x08, 0x3c, 0x23, 0x4b,
+	0x9d, 0x67, 0x18, 0xf9, 0xe2, 0x0b, 0x1c, 0x39,
+	0xd3, 0x87, 0x70, 0xc0, 0xb9, 0x1e, 0x52, 0x0a,
+	0x0f, 0x48, 0xe2, 0xe7, 0x51, 0x72, 0x94, 0xf7,
+	0xa3, 0xdc, 0xe5, 0x66, 0x33, 0x39, 0x54, 0x06,
+	0x55, 0x93, 0x30, 0xf9, 0x5e, 0x76, 0x8f, 0xe0,
+	0x59, 0x4d, 0x0d, 0xa7, 0xf5, 0xbe, 0xdb, 0x20,
+	0xad, 0x0d, 0x76, 0x88, 0x5f, 0x9c, 0x7c, 0x75,
+	0x2f, 0x2a, 0x0b, 0x79, 0x6e, 0xd3, 0xe2, 0x66,
+	0xf5, 0x4a, 0x2d, 0x87, 0x87, 0x49, 0x84, 0x17,
+	0xa2, 0x62, 0x4c, 0xbb, 0xe4, 0x6e, 0x98, 0x10,
+	0xc9, 0xfb, 0x8a, 0x04, 0x68, 0x8d, 0x22, 0x66,
+	0xad, 0xea, 0x2a, 0xc9, 0x97, 0x2d, 0x3c, 0xbc,
+	0xd0, 0x77, 0x5f, 0xe6, 0xb8, 0x7f, 0xe6, 0xf6,
+	0x39, 0xbf, 0x56, 0x0e, 0x26, 0x6d, 0xc5, 0x3e,
+	0x53, 0x19, 0xd6, 0xb4, 0x57, 0x36, 0xa3, 0xc6,
+	0xd3, 0x3d, 0x66, 0x79, 0x30, 0x5c, 0x14, 0x0c,
+	0x0f, 0x3e, 0x96, 0xae, 0x90, 0x97, 0xab, 0x0d,
+	0x9f, 0xc3, 0xe7, 0x66, 0x3e, 0xe0, 0x31, 0x43,
+	0x4b, 0x01, 0xb3, 0x0e, 0x9e, 0x8c, 0x82, 0x4a,
+	0x8c, 0xc7, 0x79, 0x85, 0xdf, 0x75, 0x0d, 0xb4,
+	0x2b, 0x03, 0x14, 0xef, 0x72, 0x58, 0xfd, 0x64,
+	0xc8, 0xe3, 0x0d, 0x9a, 0x14, 0x6f, 0x76, 0xf9,
+	0x46, 0xd1, 0xd2, 0x81, 0xb3, 0x16, 0x6e, 0xc7,
+	0x76, 0x82, 0xce, 0xf4, 0xee, 0x33, 0x00, 0xe6,
+	0x77, 0xc4, 0xad, 0x4f, 0x06, 0xa7, 0x48, 0x80,
+	0x9e, 0x21, 0x66, 0xca, 0x75, 0x69, 0x57, 0xcb,
+	0xf0, 0x67, 0x6a, 0xaa, 0x8f, 0x88, 0x14, 0xbd,
+	0x65, 0x62, 0xe2, 0xad, 0xcc, 0x22, 0x88, 0x7b,
+	0x94, 0xbd, 0x0e, 0xcd, 0xb6, 0x69, 0xa2, 0xcb,
+	0x7d, 0x57, 0x5c, 0xb4, 0x92, 0x80, 0x13, 0x99,
+	0x84, 0xf3, 0x79, 0x0a, 0x2d, 0x70, 0xa4, 0xe0,
+	0xde, 0xc6, 0x32, 0xb0, 0x8a, 0x62, 0xb5, 0xcf,
+	0xfa, 0x5e, 0x5a, 0x92, 0x32, 0x7d, 0x34, 0x07,
+	0xb5, 0x52, 0x3a, 0xb5, 0x7d, 0x0f, 0xa1, 0xba,
+	0x56, 0xd0, 0x07, 0x76, 0x11, 0xf2, 0xc3, 0x33,
+	0x9d, 0xbd, 0x12, 0x35, 0x5e, 0xf7, 0x05, 0x88,
+	0x76, 0x94, 0xa6, 0xbf, 0xed, 0xb8, 0xa4, 0xa2,
+	0x0c, 0xbe, 0x0f, 0x6a, 0xaf, 0xf3, 0x1b, 0x33,
+	0x4a, 0xb7, 0x68, 0x3f, 0xbe, 0x95, 0x13, 0x97,
+	0x0f, 0x15, 0x17, 0x1b, 0x23, 0xaa, 0x08, 0x78,
+	0xa6, 0x5b, 0x08, 0xa2, 0x9d, 0x03, 0xa8, 0xa7,
+	0x39, 0xdc, 0xbc, 0x9a, 0x85, 0xf5, 0xe5, 0x55,
+	0x59, 0x3c, 0xef, 0xf9, 0x3f, 0x22, 0x8e, 0xf8,
+	0xd8, 0x3e, 0x02, 0x0b, 0xd8, 0x78, 0x4b, 0x15,
+	0x7f, 0xaa, 0x2c, 0xff, 0xbe, 0x77, 0x33, 0xc7,
+	0x6a, 0x12, 0xaa, 0xa4, 0xbe, 0xc0, 0x3b, 0xcb,
+	0x13, 0x9d, 0x9c, 0x5a, 0x9f, 0x8a, 0x57, 0x36,
+	0x4f, 0x02, 0x5a, 0xf8, 0x1d, 0x97, 0x77, 0x43,
+	0xc8, 0xa5, 0xb7, 0x9b, 0x10, 0x98, 0xfd, 0x58,
+	0xbf, 0x42, 0xf6, 0xbf, 0xff, 0x6c, 0x40, 0x18,
+	0x18, 0xdf, 0xac, 0x57, 0x71, 0xea, 0xcc, 0x8e,
+	0xfd, 0xfe, 0x10, 0xfb, 0xb9, 0xfe, 0xbc, 0x9a,
+	0x9c, 0x27, 0xe4, 0x10, 0x15, 0x94, 0x41, 0xa1,
+	0xcc, 0xf6, 0x25, 0x49, 0x4f, 0x96, 0xc1, 0x8c,
+	0x9e, 0x3e, 0x18, 0x29, 0x49, 0x92, 0xe7, 0xfe,
+	0x22, 0xff, 0xed, 0x02, 0x16, 0x90, 0xef, 0xac,
+	0xec, 0x95, 0x1d, 0x5b, 0x94, 0x9c, 0xf6, 0x7c,
+	0x1b, 0x5a, 0x9d, 0xb0, 0x9b, 0x05, 0x36, 0xbf,
+	0xef, 0xec, 0x63, 0x35, 0x40, 0x24, 0x45, 0x40,
+	0x30, 0x1a, 0x9b, 0x90, 0xc3, 0xc2, 0xf7, 0x37,
+	0xfb, 0x08, 0x8e, 0x48, 0x19, 0x48, 0xed, 0xa8,
+	0xa8, 0x04, 0x6f, 0xd0, 0x33, 0xe9, 0xb8, 0x8d,
+	0xe7, 0x1e, 0x5c, 0x47, 0x74, 0xc0, 0x66, 0x30,
+	0x4e, 0xa7, 0x86, 0x73, 0xf1, 0xe5, 0x78, 0xa6,
+	0xe0, 0xc1, 0xda, 0x13, 0x72, 0x07, 0x85, 0x34,
+	0x63, 0x95, 0x49, 0x30, 0x4b, 0x9d, 0x03, 0xf1,
+	0x7a, 0x6b, 0x91, 0xa2, 0x85, 0x41, 0xf9, 0x4a,
+	0xd6, 0xff, 0xff, 0x86, 0xf7, 0xf0, 0xce, 0xb9,
+	0x07, 0xf1, 0x88, 0x04, 0x33, 0xaa, 0xeb, 0x54,
+	0xb2, 0x1c, 0x8e, 0x2e, 0x7b, 0x04, 0xa8, 0xcc,
+	0x2c, 0x7a, 0xb3, 0xad, 0x1a, 0x89, 0x38, 0x89,
+	0xd7, 0x11, 0x3a, 0x8c, 0xcf, 0xe3, 0xc5, 0xba,
+	0xb0, 0xcc, 0xc4, 0xe3, 0x33, 0xf3, 0x18, 0xba,
+	0xec, 0x56, 0xd9, 0x1c, 0x40, 0x70, 0x0d, 0x4e,
+	0x97, 0x01, 0x23, 0xf3, 0x5a, 0xdc, 0xbf, 0x68,
+	0x93, 0xc2, 0x1d, 0x8a, 0x96, 0xb7, 0xac, 0x18,
+	0x6f, 0xf7, 0x84, 0x71, 0x0d, 0x3d, 0xf8, 0xba,
+	0xdf, 0xb6, 0x89, 0x1d, 0x78, 0x19, 0xf2, 0x59,
+	0xe9, 0x15, 0x55, 0x29, 0x73, 0x50, 0x59, 0x14,
+	0x02, 0x21, 0x16, 0x8f, 0x0f, 0xdf, 0xa5, 0xf0,
+};
+
+static struct crc_test {
+	uint32_t crc;		/* random starting crc */
+	uint32_t start;		/* random offset in buf */
+	uint32_t length;	/* random length of test */
+	uint32_t crc_le;	/* expected crc32_le result */
+	uint32_t crc_be;	/* expected crc32_be result */
+} test[] = {
+	{0xffffffff, 0x00000000, 0x00001000, 0x13934bef, 0x14f3b75f},
+	{0xfe7328ea, 0x00000763, 0x00000717, 0xed2c0d70, 0x57531214},
+	{0x4c40684e, 0x00000721, 0x0000011e, 0xd7f46ccc, 0xedf12ec3},
+	{0x6b487f90, 0x00000264, 0x000007bc, 0x759e9939, 0x9af8e387},
+	{0x9f5810db, 0x00000afa, 0x00000255, 0x2685197f, 0x716de6ed},
+	{0xb15c4755, 0x00000d5b, 0x000002a4, 0xd8fadcb5, 0xfc34ae3f},
+	{0x06518253, 0x00000ffb, 0x00000004, 0xabee2433, 0xfa30ac9e},
+	{0xd9e71c55, 0x00000a2a, 0x00000259, 0x96682af2, 0xe5907ea3},
+	{0x0c1ae843, 0x00000ce4, 0x0000031b, 0x7b637c43, 0xe7f71b04},
+	{0xec3cd517, 0x000002ff, 0x00000566, 0x5d719a77, 0xed16e045},
+	{0x77828e95, 0x0000067f, 0x0000038f, 0x43ee5b6c, 0x35999927},
+	{0xec87b4e3, 0x00000d1c, 0x000002e3, 0x2ddd2eee, 0x9452d3f8},
+	{0x412158bb, 0x00000eee, 0x00000111, 0x67b38ba2, 0x177976d0},
+	{0x2e52de3e, 0x00000c4a, 0x000003b5, 0xbcc5d61d, 0xf60fee71},
+	{0x6ddaae8b, 0x00000d99, 0x00000266, 0x8b535544, 0x1dab8596},
+	{0x049b6cb1, 0x000009c5, 0x000000b0, 0xfc22cabc, 0x47ebc954},
+	{0x77d4b954, 0x0000028a, 0x000007fa, 0x71d00923, 0x905585ef},
+	{0x5e192355, 0x00000ac1, 0x000001fa, 0xb966b81a, 0x33c12903},
+	{0x7d80b71d, 0x00000213, 0x000001e0, 0x2bba371a, 0x5f4bd8d9},
+	{0x01f6f1e4, 0x000001d6, 0x00000395, 0xb7e8a647, 0x2a7943a1},
+	{0x1dfabb13, 0x00000e14, 0x000001eb, 0x53917fba, 0x8dee1e5d},
+	{0xb00a4449, 0x00000bf6, 0x00000409, 0xedecb577, 0x628e087d},
+	{0x7ecd3981, 0x0000083f, 0x0000016b, 0xefef62b9, 0xda4f94e6},
+	{0xf8f330d2, 0x000004be, 0x00000757, 0x9357c9f3, 0x8e2d5c2f},
+	{0x03c38af2, 0x00000d23, 0x000002dc, 0x360fa8c0, 0x6294c0d6},
+	{0x687bb79b, 0x00000f3d, 0x000000c2, 0x448d3be2, 0x08f48f3a},
+	{0x6710f550, 0x000009e9, 0x00000603, 0xdbfd1998, 0xc950ac29},
+	{0x873171d1, 0x00000787, 0x000004d5, 0xab7f1b62, 0xe66896ab},
+	{0x373b1314, 0x00000f0f, 0x000000f0, 0x184098ab, 0x4038e674},
+	{0x90fad9cd, 0x00000ead, 0x00000152, 0x23ce52ff, 0x9eff3974},
+	{0x19676fe7, 0x0000007d, 0x0000070d, 0xf8a76f1e, 0xfbc5c8a9},
+	{0x89facd45, 0x000005f3, 0x00000473, 0x4331a006, 0xb8f0f0cc},
+	{0x6f173747, 0x00000fc3, 0x0000003c, 0xb012f08e, 0x5126e378},
+	{0x4b44a106, 0x0000075a, 0x0000008b, 0xf6f7ac38, 0xf9b1781b},
+	{0xb620ad06, 0x00000774, 0x0000017e, 0xd34558e6, 0xb175edd3},
+	{0x976f21e9, 0x000008d7, 0x0000034a, 0xe533aa3a, 0x1e4367b9},
+	{0x687628c0, 0x000006c5, 0x0000061b, 0x3a840b15, 0xfb5989a0},
+	{0xe24ac108, 0x00000cd0, 0x0000032f, 0x51010ae8, 0xcdd8f182},
+	{0x361c44a3, 0x00000304, 0x00000719, 0xfd7bd481, 0x12de540f},
+	{0xd93ff95e, 0x00000db7, 0x0000008e, 0xcfbbc304, 0x42eecd5a},
+	{0xed752d12, 0x00000883, 0x00000091, 0x65a6c868, 0x9ebfa578},
+	{0xb4ff4b54, 0x000003d3, 0x000001c1, 0xf82597e7, 0xa8ad2b19},
+	{0x111b520f, 0x00000708, 0x000000eb, 0xc3e109f3, 0x323ace17},
+	{0x62c806f2, 0x00000ba3, 0x0000045c, 0x874d3a72, 0xaf1a1360},
+	{0x40d97470, 0x000005e1, 0x0000058d, 0x87a9684f, 0x524244a8},
+	{0x4312179c, 0x00000056, 0x0000070e, 0x809a00f5, 0xf9e940b0},
+	{0x13d5f84c, 0x00000a2d, 0x00000104, 0xf3d27578, 0x5d33341c},
+	{0x1f302cb2, 0x00000151, 0x00000014, 0x1e162693, 0x53c3cfc3},
+	{0xe491db24, 0x00000600, 0x000006f6, 0x7ff09615, 0xa300ecf7},
+	{0xf9a98069, 0x000002ba, 0x000002ad, 0x01af7387, 0x31c0911e},
+	{0xe9c477ad, 0x0000015f, 0x00000778, 0x6facf9a0, 0x1993b688},
+	{0x353f32b2, 0x0000087c, 0x00000783, 0x6cc964ea, 0x418db561},
+	{0x78e1b24f, 0x00000650, 0x000006a8, 0xb3bb7c27, 0xf2aad006},
+	{0x61aa400e, 0x00000049, 0x00000254, 0xb8cd1681, 0x79150b15},
+	{0xb84b10b0, 0x00000f73, 0x0000008c, 0x406a6450, 0x0c705222},
+	{0x9fa99c9c, 0x00000a7c, 0x000004d7, 0xfb3d21b4, 0xe4e789df},
+	{0x3fc9ebe3, 0x00000cd9, 0x000000d6, 0x43803f9c, 0x5a152be5},
+	{0x529879cd, 0x000002f2, 0x00000595, 0x78b4c6a6, 0xf7236ec4},
+	{0x3a933019, 0x00000516, 0x00000266, 0xdcb45436, 0x2c7935f5},
+	{0x887b4977, 0x00000227, 0x0000038d, 0xc5f7c3d9, 0x0d6d7df6},
+	{0x770745de, 0x000008c6, 0x00000739, 0xf69145e8, 0x47d5efc9},
+	{0x28be3b47, 0x00000c46, 0x0000032b, 0x764c028f, 0x1eb70d64},
+	{0x5013a050, 0x00000cf6, 0x00000309, 0xea8fe164, 0x186affa4},
+	{0x2ec4c9ba, 0x000006e8, 0x0000078d, 0xa35557a9, 0xb41f49ec},
+	{0xa9f950c9, 0x00000d33, 0x000002cc, 0x41ea8618, 0xab8dfae3},
+	{0x5b520229, 0x000007b2, 0x00000484, 0x44569f1f, 0x607a8052},
+	{0xd8dcbbfc, 0x0000002f, 0x0000048c, 0xdb88ab8b, 0xf1c411f1},
+	{0x25529792, 0x00000d1d, 0x000002e2, 0x20cda404, 0x32683a2d},
+	{0x9f3f6d71, 0x00000238, 0x0000079a, 0x0720443e, 0x4b8ba2ff},
+	{0x64121215, 0x000007ff, 0x0000038f, 0x6aacff2c, 0x3b84233b},
+	{0xfb6cdde0, 0x00000ef8, 0x00000107, 0xbd43a0f1, 0x926624d0},
+	{0x221c9d6f, 0x000007b6, 0x0000014f, 0xb67f834b, 0x2bdedda4},
+	{0x030e1de4, 0x00000836, 0x000004b4, 0x0d67d26a, 0x75a73b73},
+	{0xb56fa6cf, 0x00000c07, 0x000003f8, 0x60601ac1, 0x10a43f35},
+	{0xb55c89f5, 0x0000098e, 0x000001d4, 0x2400efbe, 0x006e28eb},
+	{0x5e90b6d5, 0x0000070b, 0x000003ea, 0x3bb5d6ea, 0xb175fa6b},
+	{0x2a7045ae, 0x00000961, 0x00000633, 0xfca89e4b, 0x962cd6d2},
+	{0x8b374ea9, 0x000006ba, 0x00000780, 0xbce036ed, 0x4dc8279b},
+	{0x8bd90bc9, 0x00000562, 0x00000369, 0xcb26a24b, 0x50dee743},
+	{0x5b1b1762, 0x000000fd, 0x0000051a, 0x33cdda07, 0xee75ff7b},
+	{0xa4153555, 0x0000058f, 0x000005c7, 0xbe50eeca, 0xe73fffcc},
+	{0x0be1f931, 0x00000651, 0x00000672, 0x95a25753, 0x4ad6270f},
+	{0xb7e78618, 0x00000a7f, 0x000002bb, 0xe06bcc1c, 0x1a35ee59},
+	{0x4a9bc41b, 0x00000e51, 0x000001ae, 0x709e8d2c, 0x75080ca8},
+	{0xfc359d13, 0x00000440, 0x000002f8, 0x0a58451f, 0x6fa3cfbf},
+	{0x5aa48619, 0x000006d1, 0x00000284, 0x928ead83, 0xbd600efc},
+	{0xa609afa8, 0x0000053e, 0x00000272, 0xb048c141, 0x184f80bb},
+	{0x3f108afb, 0x00000949, 0x00000150, 0x9a6bb5bc, 0x0ea02be1},
+	{0x79bec2d3, 0x000008ed, 0x00000712, 0x32692d57, 0x2eb13289},
+	{0x9429e067, 0x00000bc3, 0x0000043c, 0x5295ceff, 0x8a9014a7},
+	{0xae58b96a, 0x0000082d, 0x000007d2, 0xc2a681ba, 0x6af94089},
+	{0x95df24be, 0x00000985, 0x000004c1, 0x3a287765, 0x379fcb42},
+	{0x5e94976f, 0x00000596, 0x000004ed, 0xff00c489, 0x991fc1f5},
+	{0xf5e5f1de, 0x00000d31, 0x000002ce, 0x35f28e91, 0x543def1a},
+	{0xa2c219cf, 0x00000a3c, 0x00000374, 0x707d21eb, 0xa6d28bc1},
+	{0xf21b6ceb, 0x00000919, 0x00000135, 0x0847fb8b, 0x224468c2},
+	{0xaa988728, 0x00000787, 0x00000771, 0x885aeaa4, 0x814db00b},
+	{0xaa5dfaac, 0x000003e5, 0x0000051b, 0x52c48ab7, 0x725bef8a},
+	{0x0a053968, 0x00000d2a, 0x000002d5, 0x7a90256d, 0xc53b9402},
+	{0x1421dc20, 0x00000eef, 0x00000110, 0x97d6da24, 0x10846935},
+	{0xb47c2166, 0x00000a6a, 0x00000209, 0xcfd6cc52, 0x46e2797e},
+	{0x77dd1955, 0x000000de, 0x00000266, 0xba74bcaa, 0x4fa3fe9c},
+	{0x68a03cc2, 0x0000082f, 0x000007b0, 0x752bd5d8, 0x4f760c63},
+	{0x0226b0a3, 0x00000a5f, 0x000005a0, 0x82de4970, 0x8ee1310e},
+	{0x637bf3b1, 0x00000d93, 0x0000026c, 0x5c7115cb, 0x9f6a0ced},
+	{0x3b120edf, 0x00000c13, 0x000003ec, 0x80d7d20f, 0x241657d5},
+	{0xe2456780, 0x000002eb, 0x00000641, 0xc0a5d289, 0x74df96b4},
+	{0x9b2e7125, 0x00000c0c, 0x000003f3, 0xcc15f57e, 0x03e290bf},
+	{0x153033ef, 0x00000787, 0x000006b6, 0x3cde443b, 0x7bf1d121},
+	{0x18458b3f, 0x0000066c, 0x00000561, 0x9a2bd8c6, 0x9d564bef},
+	{0x4ff9d4b9, 0x00000c8f, 0x0000033a, 0xd0ee6d6d, 0xee00aa0b},
+	{0xdf84b5d9, 0x00000802, 0x0000029a, 0xdab0d74a, 0xd0cb63dc},
+	{0x81ee15df, 0x000003ce, 0x00000725, 0x9942e2de, 0xe48fb26b},
+	{0x5c768e04, 0x00000afd, 0x00000160, 0x36110831, 0x8dc74483},
+	{0xe5e18094, 0x00000b4b, 0x000000a0, 0xffa3e4a7, 0xc0145e1b},
+	{0xed7263b6, 0x00000d0d, 0x000002f2, 0xb0006a35, 0x5468ae3a},
+	{0x5bfde7d7, 0x000006fb, 0x00000554, 0xa4193b76, 0xb73d34b2},
+	{0x67f4a743, 0x00000b85, 0x0000047a, 0xf05c8d8f, 0x4f843e49},
+	{0xf13bdf22, 0x00000ff7, 0x00000008, 0x816351eb, 0x41f537f6},
+	{0x08ecc608, 0x00000d5d, 0x00000098, 0x90492772, 0xf5172204},
+	{0x296f52ba, 0x000004f9, 0x00000788, 0x5e5a4896, 0xe01d5b46},
+	{0xbe4624c2, 0x00000427, 0x000004ef, 0xcd267b94, 0x7b9069f4},
+	{0x906f7c7c, 0x00000a05, 0x0000003f, 0x03fcfc33, 0x7b6ff563},
+	{0x8f7b323e, 0x00000458, 0x000004c7, 0xcd4969c8, 0xd4c22ada},
+	{0x88d6593d, 0x00000597, 0x000005b5, 0xf199cd3b, 0x5c3e8ca2},
+	{0x978a7768, 0x00000268, 0x000001d3, 0xb28c95bd, 0x49a2cc67},
+	{0x857a621e, 0x000007a7, 0x000003a8, 0xf4bf84ab, 0xde26f369},
+	{0xb0e121ef, 0x000005be, 0x00000644, 0x28747c14, 0x61d4dc6b},
+	{0, 0, 0, 0, 0},
+};
+
+static int test_crc32c(void)
+{
+	struct crc_test *t = test;
+	int failures = 0;
+
+	while (t->length) {
+		uint32_t be, le;
+		le = crc32c_le(t->crc, test_buf + t->start, t->length);
+		be = crc32c_be(t->crc, test_buf + t->start, t->length);
+		if (le != t->crc_le) {
+			printf("Test %d LE fails, %x != %x\n",
+			       (t - test), le, t->crc_le);
+			failures++;
+		}
+		if (be != t->crc_be) {
+			printf("Test %d BE fails, %x != %x\n",
+			       (t - test), be, t->crc_be);
+			failures++;
+		}
+		t++;
+	}
+
+	return failures;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret;
+
+	ret = test_crc32c();
+	if (!ret)
+		printf("No failures.\n");
+
+	return ret;
+}
+#endif /* UNITTEST */


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

* [PATCH 06/37] libext2fs: Add inode checksum support
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (4 preceding siblings ...)
  2011-09-01  0:35 ` [PATCH 05/37] libext2fs: Implement a crc32c self-test Darrick J. Wong
@ 2011-09-01  0:35 ` Darrick J. Wong
  2011-09-04 17:59   ` Andreas Dilger
  2011-09-01  0:35 ` [PATCH 07/37] debugfs: Dump inode checksum when appropriate Darrick J. Wong
                   ` (29 subsequent siblings)
  35 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:35 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

This patch adds the ability for the libext2fs functions to read and write the
inode checksum.  It also fixes a few fields that were omitted from the byte
swapping routines.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/csum.c         |   59 +++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/ext2_err.et.in |    9 +++++++
 lib/ext2fs/ext2_fs.h      |    4 ++-
 lib/ext2fs/ext2fs.h       |    6 +++++
 lib/ext2fs/inode.c        |   20 +++++++++++++++
 lib/ext2fs/swapfs.c       |   10 ++++++--
 6 files changed, 104 insertions(+), 4 deletions(-)


diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index 2fece68..57adc4c 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -29,6 +29,65 @@
 #define STATIC static
 #endif
 
+__u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
+			struct ext2_inode_large *inode)
+{
+	struct ext2_inode_large *desc = inode;
+	int offset = offsetof(struct ext2_inode_large, i_checksum);
+	int extra_size = inode->i_extra_isize;
+	size_t size = fs->super->s_inode_size;
+	__u32 crc = 0;
+
+	if (size < EXT2_GOOD_OLD_INODE_SIZE + extra_size)
+		printf("ERROR: inode %d size %d != extra_size %d!\n", inum,
+		       size, extra_size + EXT2_GOOD_OLD_INODE_SIZE);
+
+	if (fs->super->s_creator_os != EXT2_OS_LINUX)
+		return 0;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+
+		return 0;
+
+#ifdef WORDS_BIGENDIAN
+	char buf[EXT2_INODE_CORE_SIZE(fs->super)];
+	struct ext2_inode_large *swabinode = (struct ext2_inode_large *)buf;
+
+	/* Have to swab back to little-endian to do the checksum */
+	memcpy(swabinode, inode, size);
+	ext2fs_swap_inode_full(fs, swabinode, swabinode, 1, size);
+	desc = swabinode;
+#endif
+	inum = ext2fs_cpu_to_le32(inum);
+	crc = crc32c_le(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid));
+	crc = crc32c_le(crc, (char *)&inum, sizeof(inum));
+	crc = crc32c_le(crc, (char *)desc, offset);
+	offset += sizeof(inode->i_checksum); /* skip checksum */
+	crc = crc32c_le(crc, (char *)desc + offset,
+			   EXT2_GOOD_OLD_INODE_SIZE + extra_size - offset);
+	return crc;
+}
+
+int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+			     struct ext2_inode_large *inode)
+{
+	if (fs->super->s_creator_os == EXT2_OS_LINUX &&
+	    EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+	    (inode->i_checksum != ext2fs_inode_csum(fs, inum, inode)))
+		return 0;
+	return 1;
+}
+
+void ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
+			   struct ext2_inode_large *inode)
+{
+	if (fs->super->s_creator_os != EXT2_OS_LINUX)
+		return;
+	inode->i_checksum = ext2fs_inode_csum(fs, inum, inode);
+}
+
 STATIC __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
 {
 	__u16 crc = 0;
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 995ddc3..31c8fe1 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -422,4 +422,13 @@ ec	EXT2_NO_MTAB_FILE,
 ec	EXT2_ET_CANT_USE_LEGACY_BITMAPS,
 	"Filesystem too large to use legacy bitmaps"
 
+ec	EXT2_ET_INODE_CSUM_INVALID,
+	"Inode checksum is incorrect"
+
+ec	EXT2_ET_INODE_CORRUPT,
+	"Inode checksum indicates corruption"
+
+ec	EXT2_ET_INODE_CSUM_NONZERO,
+	"Inode checksum should not be set"
+
 	end
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index ae7662e..1f08673 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -362,7 +362,7 @@ struct ext2_inode_large {
 			__u16	l_i_file_acl_high;
 			__u16	l_i_uid_high;	/* these 2 fields    */
 			__u16	l_i_gid_high;	/* were reserved2[0] */
-			__u32	l_i_reserved2;
+			__u32	l_i_checksum;	/* crc32c(uuid+inum+inode) */
 		} linux2;
 		struct {
 			__u8	h_i_frag;	/* Fragment number */
@@ -393,7 +393,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_reserved2	osd2.linux2.l_i_reserved2
+#define i_checksum	osd2.linux2.l_i_checksum
 #else
 #if defined(__GNU__)
 
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index e571508..db8b28b 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -892,6 +892,12 @@ extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len);
 extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
 
 /* csum.c */
+extern __u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
+			      struct ext2_inode_large *inode);
+extern void ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
+				  struct ext2_inode_large *inode);
+extern int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+				    struct ext2_inode_large *inode);
 extern void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group);
 extern int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group);
 extern errcode_t ext2fs_set_gdt_csum(ext2_filsys fs);
diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
index 76893fd..0789505 100644
--- a/lib/ext2fs/inode.c
+++ b/lib/ext2fs/inode.c
@@ -509,6 +509,12 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
 	if (EXT2_INODE_SIZE(scan->fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
 		inode->i_extra_isize = 0;
 
+	/* Verify the inode checksum. */
+	if (!(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+	    !ext2fs_inode_csum_verify(scan->fs, scan->current_inode, inode))
+		return EXT2_ET_INODE_CSUM_INVALID;
+
+
 	scan->inodes_left--;
 	scan->current_inode++;
 	*ino = scan->current_inode;
@@ -617,6 +623,10 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
 			       (struct ext2_inode_large *) inode,
 			       0, bufsize);
 #endif
+	/* Verify the inode checksum. */
+	if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+	    !ext2fs_inode_csum_verify(fs, ino, inode))
+		return EXT2_ET_INODE_CSUM_INVALID;
 
 	/* Update the inode cache */
 	fs->icache->cache_last = (fs->icache->cache_last + 1) %
@@ -685,6 +695,16 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
 		w_inode = &temp_inode;
 	memset(w_inode, 0, length);
 
+	/*
+	 * If inode checksum enabled, ensure that we actually have the whole
+	 * inode in memory.
+	 */
+	if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
+	    bufsize <= EXT2_GOOD_OLD_INODE_SIZE) {
+		fprintf(stderr, "inode %d has a too-short buffer!\n", ino);
+		abort();
+	}
+	ext2fs_inode_csum_set(fs, ino, inode);
 #ifdef WORDS_BIGENDIAN
 	ext2fs_swap_inode_full(fs, w_inode, inode, 1, bufsize);
 #else
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index 517f1d7..df604ba 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -244,8 +244,7 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
 		  ext2fs_swab16 (f->osd2.linux2.l_i_uid_high);
 		t->osd2.linux2.l_i_gid_high =
 		  ext2fs_swab16 (f->osd2.linux2.l_i_gid_high);
-		t->osd2.linux2.l_i_reserved2 =
-			ext2fs_swab32(f->osd2.linux2.l_i_reserved2);
+		t->i_checksum = ext2fs_swab32(f->i_checksum);
 		break;
 	case EXT2_OS_HURD:
 		t->osd1.hurd1.h_i_translator =
@@ -279,6 +278,13 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
 		return;
 	}
 
+	t->i_ctime_extra = ext2fs_swab32(f->i_ctime_extra);
+	t->i_mtime_extra = ext2fs_swab32(f->i_mtime_extra);
+	t->i_atime_extra = ext2fs_swab32(f->i_atime_extra);
+	t->i_crtime = ext2fs_swab32(f->i_crtime);
+	t->i_crtime_extra = ext2fs_swab32(f->i_crtime_extra);
+	t->i_version_hi = ext2fs_swab32(f->i_version_hi);
+
 	i = EXT2_GOOD_OLD_INODE_SIZE + extra_isize + sizeof(__u32);
 	if (bufsize < (int) i)
 		return; /* no space for EA magic */


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

* [PATCH 07/37] debugfs: Dump inode checksum when appropriate
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (5 preceding siblings ...)
  2011-09-01  0:35 ` [PATCH 06/37] libext2fs: Add inode checksum support Darrick J. Wong
@ 2011-09-01  0:35 ` Darrick J. Wong
  2011-09-01  0:36 ` [PATCH 08/37] tune2fs: Add inode checksum support Darrick J. Wong
                   ` (28 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:35 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Dump inode checksum when displaying inode info

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 debugfs/debugfs.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)


diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index ad0789f..e1bbc6c 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -784,6 +784,11 @@ void internal_dump_inode(FILE *out, const char *prefix,
 	if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
 		internal_dump_inode_extra(out, prefix, inode_num,
 					  (struct ext2_inode_large *) inode);
+	if (current_fs->super->s_creator_os == EXT2_OS_LINUX &&
+	    current_fs->super->s_feature_ro_compat &
+		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+		fprintf(out, "Inode checksum: 0x%08x\n", inode->i_checksum);
+
 	if (LINUX_S_ISLNK(inode->i_mode) && ext2fs_inode_data_blocks(current_fs,inode) == 0)
 		fprintf(out, "%sFast_link_dest: %.*s\n", prefix,
 			(int) inode->i_size, (char *)inode->i_block);


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

* [PATCH 08/37] tune2fs: Add inode checksum support
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (6 preceding siblings ...)
  2011-09-01  0:35 ` [PATCH 07/37] debugfs: Dump inode checksum when appropriate Darrick J. Wong
@ 2011-09-01  0:36 ` Darrick J. Wong
  2011-09-01  0:36 ` [PATCH 09/37] e2fsck: Verify and correct inode checksums Darrick J. Wong
                   ` (27 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:36 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

This patch adds to tune2fs the ability to toggle the metadata checksum rocompat
feature flag, which will rewrite the inode table with checksums.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 misc/tune2fs.c |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 75 insertions(+), 2 deletions(-)


diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 82833ad..283ad1d 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -82,6 +82,7 @@ static int stride_set, stripe_width_set;
 static char *extended_cmd;
 static unsigned long new_inode_size;
 static char *ext_mount_opts;
+static int rewrite_checksums;
 
 int journal_size, journal_flags;
 char *journal_device;
@@ -131,7 +132,8 @@ static __u32 ok_features[3] = {
 		EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
 		EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
 		EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
-		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER |
+		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
 };
 
 static __u32 clear_ok_features[3] = {
@@ -147,7 +149,8 @@ static __u32 clear_ok_features[3] = {
 		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
 		EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
 		EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
-		EXT4_FEATURE_RO_COMPAT_GDT_CSUM
+		EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
+		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
 };
 
 /*
@@ -330,6 +333,16 @@ static void update_mntopts(ext2_filsys fs, char *mntopts)
 	ext2fs_mark_super_dirty(fs);
 }
 
+static int check_fsck_needed(ext2_filsys fs)
+{
+	if (fs->super->s_state & EXT2_VALID_FS)
+		return 0;
+	printf("\n%s\n", _(please_fsck));
+	if (mount_flags & EXT2_MF_READONLY)
+		printf(_("(and reboot afterwards!)\n"));
+	return 1;
+}
+
 static void request_fsck_afterwards(ext2_filsys fs)
 {
 	static int requested = 0;
@@ -343,6 +356,49 @@ static void request_fsck_afterwards(ext2_filsys fs)
 }
 
 /*
+ * Forcibly set checksums in all inodes.
+ */
+static void rewrite_inodes(ext2_filsys fs)
+{
+	struct ext2_inode_large inode;
+	ext2_inode_scan	scan;
+	errcode_t	retval;
+	ext2_ino_t	ino;
+
+	if (fs->super->s_creator_os != EXT2_OS_LINUX)
+		return;
+
+	retval = ext2fs_open_inode_scan(fs, 0, &scan);
+	if (retval) {
+		com_err("set_csum", retval, "While opening inode scan");
+		exit(1);
+	}
+
+	do {
+		retval = ext2fs_get_next_inode(scan, &ino, &inode);
+		if (retval) {
+			com_err("set_csum", retval, "while getting next inode");
+			exit(1);
+		}
+		if (!ino)
+			break;
+		retval = ext2fs_write_inode(fs, ino, &inode);
+		if (retval) {
+			com_err("set_csum", retval, "while writing inode");
+			exit(1);
+		}
+	} while (ino);
+	ext2fs_close_inode_scan(scan);
+}
+
+static void rewrite_metadata_checksums(ext2_filsys fs)
+{
+	fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+	rewrite_inodes(fs);
+	fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
+}
+
+/*
  * Update the feature set as provided by the user.
  */
 static void update_feature_set(ext2_filsys fs, char *features)
@@ -448,6 +504,20 @@ static void update_feature_set(ext2_filsys fs, char *features)
 	}
 
 	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
+		       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+		if (check_fsck_needed(fs))
+			exit(1);
+		rewrite_checksums = 1;
+	}
+
+	if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+			EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+		if (check_fsck_needed(fs))
+			exit(1);
+		rewrite_checksums = 1;
+	}
+
+	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
 		       EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
 		for (i = 0; i < fs->group_desc_count; i++) {
 			gd = ext2fs_group_desc(fs, fs->group_desc, i);
@@ -1824,7 +1894,10 @@ retry_open:
 			fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
 		}
 		ext2fs_mark_super_dirty(fs);
+		rewrite_checksums = 1;
 	}
+	if (rewrite_checksums)
+		rewrite_metadata_checksums(fs);
 	if (I_flag) {
 		if (mount_flags & EXT2_MF_MOUNTED) {
 			fputs(_("The inode size may only be "


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

* [PATCH 09/37] e2fsck: Verify and correct inode checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (7 preceding siblings ...)
  2011-09-01  0:36 ` [PATCH 08/37] tune2fs: Add inode checksum support Darrick J. Wong
@ 2011-09-01  0:36 ` Darrick J. Wong
  2011-09-04 18:17   ` Andreas Dilger
  2011-09-01  0:36 ` [PATCH 10/37] mke2fs: Allow metadata checksums to be turned on at mkfs time Darrick J. Wong
                   ` (26 subsequent siblings)
  35 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:36 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Detect mismatches of the inode and checksum, and prompt the user to fix the
situation.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 e2fsck/pass1.c   |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 e2fsck/problem.c |   15 +++++++++++++++
 e2fsck/problem.h |    9 +++++++++
 3 files changed, 76 insertions(+), 0 deletions(-)


diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index ba17b30..e9b0876 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -540,6 +540,50 @@ extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags,
 		*ret = 0;
 }
 
+static int validate_inode_checksum(ext2_filsys fs,
+				   e2fsck_t ctx,
+				   struct problem_context *pctx,
+				   ext2_ino_t ino,
+				   struct ext2_inode_large *inode)
+{
+	struct ext2_inode_large *linode = (struct ext2_inode_large *)inode;
+
+	/* Ignore non-Linux filesystems */
+	if (fs->super->s_creator_os != EXT2_OS_LINUX)
+		return 0;
+
+	/* Check for checksums present even w/o feature flag */
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+	    linode->i_checksum &&
+	    fix_problem(ctx, PR_1_INODE_CSUM_NONZERO, pctx)) {
+		e2fsck_write_inode(ctx, ino, inode, "pass1");
+		return PR_1_INODE_CSUM_NONZERO;
+	}
+
+	/* Check for invalid inode checksum */
+	if (ext2fs_inode_csum_verify(fs, ino, linode))
+		return 0;
+
+	/*
+	 * TODO: Change the following check to use the inode badness patch.
+	 * For the moment we'll just assume that the user wants to clear the
+	 * bad inode.
+	 */
+	if (fix_problem(ctx, PR_1_INODE_CORRUPT, pctx)) {
+		e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
+		if (ino == EXT2_BAD_INO)
+			ext2fs_mark_inode_bitmap2(ctx->inode_used_map,
+						  ino);
+		return PR_1_INODE_CORRUPT;
+	} else if (fix_problem(ctx, PR_1_INODE_CSUM_INVALID, pctx)) {
+		e2fsck_write_inode(ctx, ino, inode, "pass1");
+		return PR_1_INODE_CSUM_INVALID;
+	}
+
+	return 0;
+}
+
 void e2fsck_pass1(e2fsck_t ctx)
 {
 	int	i;
@@ -707,8 +751,10 @@ void e2fsck_pass1(e2fsck_t ctx)
 
 	while (1) {
 		old_op = ehandler_operation(_("getting next inode from scan"));
+		ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
 		pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
 							  inode, inode_size);
+		ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 		ehandler_operation(old_op);
 		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
 			return;
@@ -740,6 +786,12 @@ void e2fsck_pass1(e2fsck_t ctx)
 			}
 		}
 
+		check_inode_extra_space(ctx, &pctx);
+		/* Validate inode checksum.  i_extra_isize must be sane. */
+		if (validate_inode_checksum(fs, ctx, &pctx, ino, inode) ==
+		    PR_1_INODE_CORRUPT)
+			continue;
+
 		/*
 		 * Test for incorrect extent flag settings.
 		 *
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index c5bebf8..b5176d4 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -905,6 +905,21 @@ static struct e2fsck_problem problem_table[] = {
 	  N_("Error converting subcluster @b @B: %m\n"),
 	  PROMPT_NONE, PR_FATAL },
 
+	/* inode checksum probably not set */
+	{ PR_1_INODE_CSUM_INVALID,
+	  N_("@i %i checksum incorrect.  "),
+	  PROMPT_FIX, PR_PREEN_OK },
+
+	/* inode checksum probably set, but does not match */
+	{ PR_1_INODE_CORRUPT,
+	  N_("@i %i checksum shows corruption.  "),
+	  PROMPT_CLEAR, PR_PREEN_OK },
+
+	/* inode checksumming disabled, yet checksum is probably set? */
+	{ PR_1_INODE_CSUM_NONZERO,
+	  N_("@i %i checksum should not be set.  "),
+	  PROMPT_CLEAR, PR_PREEN_OK },
+
 	/* Pass 1b errors */
 
 	/* Pass 1B: Rescan for duplicate/bad blocks */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index a4d96ae..4e353b7 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -529,6 +529,15 @@ struct problem_context {
 /* Failed to convert subcluster bitmap */
 #define PR_1_CONVERT_SUBCLUSTER		0x010061
 
+/* inode checksum probably not set */
+#define PR_1_INODE_CSUM_INVALID		0x010062
+
+/* inode checksum probably set, but does not match */
+#define PR_1_INODE_CORRUPT		0x010063
+
+/* inode checksum should not be set */
+#define PR_1_INODE_CSUM_NONZERO		0x010064
+
 /*
  * Pass 1b errors
  */


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

* [PATCH 10/37] mke2fs: Allow metadata checksums to be turned on at mkfs time
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (8 preceding siblings ...)
  2011-09-01  0:36 ` [PATCH 09/37] e2fsck: Verify and correct inode checksums Darrick J. Wong
@ 2011-09-01  0:36 ` Darrick J. Wong
  2011-09-04 18:28   ` Andreas Dilger
  2011-09-01  0:36 ` [PATCH 11/37] libext2fs: Create the inode bitmap checksum Darrick J. Wong
                   ` (25 subsequent siblings)
  35 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:36 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Write out checksummed inodes even when writing out a zeroed table.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 misc/mke2fs.c |   37 ++++++++++++++++++++++++++++++-------
 1 files changed, 30 insertions(+), 7 deletions(-)


diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 2d57d09..bbc0533 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -309,6 +309,8 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
 	dgrp_t		i;
 	int		num;
 	struct ext2fs_numeric_progress_struct progress;
+	ext2_ino_t	ino;
+	struct ext2_inode_large inode;
 
 	ext2fs_numeric_progress_init(fs, &progress,
 				     _("Writing inode tables: "),
@@ -330,12 +332,32 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
 			ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_ZEROED);
 			ext2fs_group_desc_csum_set(fs, i);
 		}
-		retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num);
-		if (retval) {
-			fprintf(stderr, _("\nCould not write %d "
-				  "blocks in inode table starting at %llu: %s\n"),
-				num, blk, error_message(retval));
-			exit(1);
+		if (fs->super->s_creator_os == EXT2_OS_LINUX &&
+		    fs->super->s_feature_ro_compat &
+		    EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
+			bzero(&inode, sizeof(inode));
+			for (ino = fs->super->s_inodes_per_group * i;
+			     ino < fs->super->s_inodes_per_group * (i + 1);
+			     ino++) {
+				if (!ino)
+					continue;
+				retval = ext2fs_write_inode(fs, ino, &inode);
+				if (retval) {
+					com_err("inode_init", retval,
+						"while writing inode %d\n",
+						ino);
+					exit(1);
+				}
+			}
+		} else {
+			retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num);
+			if (retval) {
+				fprintf(stderr, _("\nCould not write %d "
+					"blocks in inode table starting "
+					"at %llu: %s\n"),
+					num, blk, error_message(retval));
+				exit(1);
+			}
 		}
 		if (sync_kludge) {
 			if (sync_kludge == 1)
@@ -829,7 +851,8 @@ static __u32 ok_features[3] = {
 		EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
 		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|
 		EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
-		EXT4_FEATURE_RO_COMPAT_BIGALLOC
+		EXT4_FEATURE_RO_COMPAT_BIGALLOC|
+		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
 };
 
 


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

* [PATCH 11/37] libext2fs: Create the inode bitmap checksum
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (9 preceding siblings ...)
  2011-09-01  0:36 ` [PATCH 10/37] mke2fs: Allow metadata checksums to be turned on at mkfs time Darrick J. Wong
@ 2011-09-01  0:36 ` Darrick J. Wong
  2011-09-14 17:02   ` Ted Ts'o
  2011-09-01  0:36 ` [PATCH 12/37] tune2fs: Rewrite inode bitmap checksums Darrick J. Wong
                   ` (24 subsequent siblings)
  35 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:36 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Provide a field in the block group descriptor to store inode bitmap checksum,
and some helper functions to calculate and verify it.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/blknum.c     |   11 +++++++++++
 lib/ext2fs/closefs.c    |   29 +++++++++++++++++------------
 lib/ext2fs/csum.c       |   45 +++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/ext2_fs.h    |    3 ++-
 lib/ext2fs/ext2fs.h     |    7 +++++++
 lib/ext2fs/rw_bitmaps.c |   15 +++++++++++++++
 lib/ext2fs/swapfs.c     |    1 +
 7 files changed, 98 insertions(+), 13 deletions(-)


diff --git a/lib/ext2fs/blknum.c b/lib/ext2fs/blknum.c
index 7e7fcd8..47d3fda 100644
--- a/lib/ext2fs/blknum.c
+++ b/lib/ext2fs/blknum.c
@@ -210,6 +210,17 @@ void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
 }
 
 /*
+ * Return the inode bitmap checksum of a group
+ */
+blk64_t ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group)
+{
+	struct ext4_group_desc *gdp;
+
+	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
+	return gdp->bg_inode_bitmap_csum;
+}
+
+/*
  * Return the inode bitmap block of a group
  */
 blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group)
diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c
index 952f496..73dc136 100644
--- a/lib/ext2fs/closefs.c
+++ b/lib/ext2fs/closefs.c
@@ -289,6 +289,23 @@ errcode_t ext2fs_flush(ext2_filsys fs)
 
 	fs->super->s_wtime = fs->now ? fs->now : time(NULL);
 	fs->super->s_block_group_nr = 0;
+
+	/*
+	 * If the write_bitmaps() function is present, call it to
+	 * flush the bitmaps.  This is done this way so that a simple
+	 * program that doesn't mess with the bitmaps doesn't need to
+	 * drag in the bitmaps.c code.
+	 *
+	 * Bitmap checksums live in the group descriptor, so the
+	 * bitmaps need to be written before the descriptors.
+	 */
+	if (fs->write_bitmaps) {
+		retval = fs->write_bitmaps(fs);
+		if (retval)
+			goto errout;
+	}
+
+	/* Prepare the group descriptors for writing */
 #ifdef WORDS_BIGENDIAN
 	retval = EXT2_ET_NO_MEMORY;
 	retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
@@ -379,18 +396,6 @@ errcode_t ext2fs_flush(ext2_filsys fs)
 
 	ext2fs_numeric_progress_close(fs, &progress, NULL);
 
-	/*
-	 * If the write_bitmaps() function is present, call it to
-	 * flush the bitmaps.  This is done this way so that a simple
-	 * program that doesn't mess with the bitmaps doesn't need to
-	 * drag in the bitmaps.c code.
-	 */
-	if (fs->write_bitmaps) {
-		retval = fs->write_bitmaps(fs);
-		if (retval)
-			goto errout;
-	}
-
 write_primary_superblock_only:
 	/*
 	 * Write out master superblock.  This has to be done
diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index 57adc4c..56b75da 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -29,6 +29,51 @@
 #define STATIC static
 #endif
 
+__u32 ext2fs_bitmap_csum(ext2_filsys fs, dgrp_t group, char *bitmap, int size)
+{
+	__u32 crc = 0;
+
+	if (fs->super->s_desc_size < EXT2_MIN_DESC_SIZE_64BIT)
+		return 0;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return 0;
+
+	group = ext2fs_cpu_to_le32(group);
+	crc = crc32c_le(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid));
+	crc = crc32c_le(crc, (char *)&group, sizeof(group));
+	crc = crc32c_le(crc, (char *)bitmap, size);
+
+	return crc;
+}
+
+int ext2fs_bitmap_csum_verify(ext2_filsys fs, dgrp_t group, __u32 provided,
+			      char *bitmap, int size)
+{
+	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT &&
+	    EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+	    (provided != ext2fs_bitmap_csum(fs, group, bitmap, size)))
+		return 0;
+	return 1;
+}
+
+void ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group, char *bitmap,
+				  int size)
+{
+	struct ext4_group_desc *gdp = (struct ext4_group_desc *)
+			ext2fs_group_desc(fs, fs->group_desc, group);
+
+	if (fs->super->s_desc_size < EXT2_MIN_DESC_SIZE_64BIT)
+		return;
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return;
+
+	gdp->bg_inode_bitmap_csum = ext2fs_bitmap_csum(fs, group, bitmap, size);
+}
+
 __u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
 			struct ext2_inode_large *inode)
 {
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 1f08673..367bfdf 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -169,7 +169,8 @@ struct ext4_group_desc
 	__u16	bg_free_inodes_count_hi;/* Free inodes count MSB */
 	__u16	bg_used_dirs_count_hi;	/* Directories count MSB */
 	__u16	bg_itable_unused_hi;	/* Unused inodes count MSB */
-	__u32	bg_reserved2[3];
+	__u32	bg_inode_bitmap_csum;	/* crc32c(uuid+group+ibitmap) */
+	__u32	bg_reserved2[2];
 };
 
 #define EXT2_BG_INODE_UNINIT	0x0001 /* Inode table/bitmap not initialized */
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index db8b28b..0899e34 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -785,6 +785,7 @@ extern struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
 extern blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group);
 extern void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group,
 					blk64_t blk);
+extern blk64_t ext2fs_inode_bitmap_csum(ext2_filsys fs, dgrp_t group);
 extern blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group);
 extern void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group,
 					blk64_t blk);
@@ -892,6 +893,12 @@ extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len);
 extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
 
 /* csum.c */
+extern __u32 ext2fs_bitmap_csum(ext2_filsys fs, dgrp_t group, char *bitmap,
+				int size);
+extern int ext2fs_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
+				     __u32 provided, char *bitmap, int size);
+extern void ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
+					 char *bitmap, int size);
 extern __u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
 			      struct ext2_inode_large *inode);
 extern void ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c
index f8c8a9f..57aba59 100644
--- a/lib/ext2fs/rw_bitmaps.c
+++ b/lib/ext2fs/rw_bitmaps.c
@@ -114,6 +114,9 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
 		if (retval)
 			return retval;
 
+		ext2fs_inode_bitmap_csum_set(fs, i, inode_buf, inode_nbytes);
+		ext2fs_group_desc_csum_set(fs, i);
+
 		blk = ext2fs_inode_bitmap_loc(fs, i);
 		if (blk) {
 			retval = io_channel_write_blk64(fs->io, blk, 1,
@@ -152,6 +155,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
 	blk64_t   blk_cnt;
 	ext2_ino_t ino_itr = 1;
 	ext2_ino_t ino_cnt;
+	struct ext4_group_desc *gdp;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -277,6 +281,17 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
 					retval = EXT2_ET_INODE_BITMAP_READ;
 					goto cleanup;
 				}
+
+				/* verify inode bitmap checksum */
+				gdp = (struct ext4_group_desc *)
+					ext2fs_group_desc(fs, fs->group_desc,
+							  i);
+				if (!(fs->flags &
+				      EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+				    !ext2fs_bitmap_csum_verify(fs, i,
+					gdp->bg_inode_bitmap_csum,
+					inode_bitmap, inode_nbytes))
+					return EXT2_ET_INODE_BITMAP_READ;
 			} else
 				memset(inode_bitmap, 0, inode_nbytes);
 			cnt = inode_nbytes << 3;
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index df604ba..747e130 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -125,6 +125,7 @@ void ext2fs_swap_group_desc2(ext2_filsys fs, struct ext2_group_desc *gdp)
 	gdp4->bg_used_dirs_count_hi =
 		ext2fs_swab16(gdp4->bg_used_dirs_count_hi);
 	gdp4->bg_itable_unused_hi = ext2fs_swab16(gdp4->bg_itable_unused_hi);
+	gdp4->bg_inode_bitmap_csum = ext2fs_swab32(gdp4->bg_inode_bitmap_csum);
 }
 
 void ext2fs_swap_group_desc(struct ext2_group_desc *gdp)


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

* [PATCH 12/37] tune2fs: Rewrite inode bitmap checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (10 preceding siblings ...)
  2011-09-01  0:36 ` [PATCH 11/37] libext2fs: Create the inode bitmap checksum Darrick J. Wong
@ 2011-09-01  0:36 ` Darrick J. Wong
  2011-09-01  0:36 ` [PATCH 13/37] dumpe2fs: Display inode bitmap checksum Darrick J. Wong
                   ` (23 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:36 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

When toggling metadata_csum, mark the inode bitmap dirty so that they are
written out with new checksums.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 misc/tune2fs.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)


diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 283ad1d..36a5cb8 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -395,6 +395,9 @@ static void rewrite_metadata_checksums(ext2_filsys fs)
 {
 	fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
 	rewrite_inodes(fs);
+	ext2fs_read_bitmaps(fs);
+	ext2fs_mark_ib_dirty(fs);
+	fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
 	fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 }
 


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

* [PATCH 13/37] dumpe2fs: Display inode bitmap checksum
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (11 preceding siblings ...)
  2011-09-01  0:36 ` [PATCH 12/37] tune2fs: Rewrite inode bitmap checksums Darrick J. Wong
@ 2011-09-01  0:36 ` Darrick J. Wong
  2011-09-04 18:30   ` Andreas Dilger
  2011-09-01  0:36 ` [PATCH 14/37] e2fsck: Verify " Darrick J. Wong
                   ` (22 subsequent siblings)
  35 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:36 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Display the inode bitmap checksum for each block group.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 misc/dumpe2fs.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)


diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
index 7d74e84..ed207cb 100644
--- a/misc/dumpe2fs.c
+++ b/misc/dumpe2fs.c
@@ -220,6 +220,11 @@ static void list_desc (ext2_filsys fs)
 		print_number(ext2fs_inode_bitmap_loc(fs, i));
 		print_bg_rel_offset(fs, ext2fs_inode_bitmap_loc(fs, i), 0,
 				    first_block, last_block);
+		if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT &&
+		    fs->super->s_feature_ro_compat &
+		    EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+			printf(_(", checksum 0x%08x"),
+			       ext2fs_inode_bitmap_checksum(fs, i));
 		fputs(_("\n  Inode table at "), stdout);
 		print_range(ext2fs_inode_table_loc(fs, i),
 			    ext2fs_inode_table_loc(fs, i) +


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

* [PATCH 14/37] e2fsck: Verify inode bitmap checksum
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (12 preceding siblings ...)
  2011-09-01  0:36 ` [PATCH 13/37] dumpe2fs: Display inode bitmap checksum Darrick J. Wong
@ 2011-09-01  0:36 ` Darrick J. Wong
  2011-09-01  0:36 ` [PATCH 15/37] libext2fs: Create the block " Darrick J. Wong
                   ` (21 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:36 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Rewrite the block bitmap when the checksum doesn't match.  This is ok since
e2fsck will have already computed the correct inode bitmap.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 e2fsck/pass5.c   |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 e2fsck/problem.c |    5 ++++
 e2fsck/problem.h |    3 +++
 3 files changed, 69 insertions(+), 0 deletions(-)


diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c
index f9d746c..a0cc564 100644
--- a/e2fsck/pass5.c
+++ b/e2fsck/pass5.c
@@ -26,6 +26,7 @@ static void check_block_bitmaps(e2fsck_t ctx);
 static void check_inode_bitmaps(e2fsck_t ctx);
 static void check_inode_end(e2fsck_t ctx);
 static void check_block_end(e2fsck_t ctx);
+static void check_inode_bitmap_checksum(e2fsck_t ctx);
 
 void e2fsck_pass5(e2fsck_t ctx)
 {
@@ -48,7 +49,9 @@ void e2fsck_pass5(e2fsck_t ctx)
 		if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
 			return;
 
+	ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
 	e2fsck_read_bitmaps(ctx);
+	ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 
 	check_block_bitmaps(ctx);
 	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
@@ -63,6 +66,8 @@ void e2fsck_pass5(e2fsck_t ctx)
 	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
 		return;
 
+	check_inode_bitmap_checksum(ctx);
+
 	ext2fs_free_inode_bitmap(ctx->inode_used_map);
 	ctx->inode_used_map = 0;
 	ext2fs_free_inode_bitmap(ctx->inode_dir_map);
@@ -73,6 +78,62 @@ void e2fsck_pass5(e2fsck_t ctx)
 	print_resource_track(ctx, _("Pass 5"), &rtrack, ctx->fs->io);
 }
 
+static void check_inode_bitmap_checksum(e2fsck_t ctx)
+{
+	struct problem_context	pctx;
+	struct ext4_group_desc	*gdp;
+	char		*buf;
+	dgrp_t		i;
+	int		nbytes;
+	ext2_ino_t	ino_itr;
+	errcode_t	retval;
+	int		csum_flag = 0;
+
+	/* If bitmap is dirty from being fixed, checksum will be corrected */
+	if (ext2fs_test_ib_dirty(ctx->fs))
+		return;
+
+	nbytes = (size_t)((EXT2_INODES_PER_GROUP(ctx->fs->super) + 7) / 8);
+	retval = ext2fs_get_memalign(ctx->fs->blocksize, ctx->fs->blocksize,
+				     &buf);
+	if (retval)
+		return;
+
+	if (EXT2_HAS_RO_COMPAT_FEATURE(ctx->fs->super,
+				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+		csum_flag = 1;
+
+	clear_problem_context(&pctx);
+	for (i = 0; i < ctx->fs->group_desc_count; i++) {
+		if (csum_flag && ext2fs_bg_flags_test(ctx->fs, i,
+						      EXT2_BG_INODE_UNINIT))
+			continue;
+
+		ino_itr = 1 + (i * (nbytes << 3));
+		gdp = (struct ext4_group_desc *)ext2fs_group_desc(ctx->fs,
+				ctx->fs->group_desc, i);
+		retval = ext2fs_get_inode_bitmap_range2(ctx->fs->inode_map,
+							ino_itr, nbytes << 3,
+							buf);
+		if (retval)
+			break;
+
+		if (ext2fs_bitmap_csum_verify(ctx->fs, i,
+					      gdp->bg_inode_bitmap_csum,
+					      buf, nbytes))
+			continue;
+		pctx.group = i;
+		if (!fix_problem(ctx, PR_5_INODE_BITMAP_CSUM_INVALID, &pctx))
+			continue;
+
+		/* Fixing one checksum will rewrite all of them */
+		ext2fs_mark_ib_dirty(ctx->fs);
+		break;
+	}
+
+	ext2fs_free_mem(&buf);
+}
+
 static void e2fsck_discard_blocks(e2fsck_t ctx, io_manager manager,
 				  blk64_t start, blk64_t count)
 {
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index b5176d4..35a8055 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1659,6 +1659,11 @@ static struct e2fsck_problem problem_table[] = {
 	  N_("@g %g @i(s) in use but @g is marked INODE_UNINIT\n"),
 	  PROMPT_FIX, PR_PREEN_OK },
 
+	/* Group N inode bitmap does not match checksum */
+	{ PR_5_INODE_BITMAP_CSUM_INVALID,
+	  N_("@g %g @i bitmap does not match checksum\n"),
+	  PROMPT_FIX, PR_LATCH_IBITMAP | PR_PREEN_OK },
+
 	/* Post-Pass 5 errors */
 
 	/* Recreate journal if E2F_FLAG_JOURNAL_INODE flag is set */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 4e353b7..9766113 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -1001,6 +1001,9 @@ struct problem_context {
 /* Inode in use but group is marked INODE_UNINIT */
 #define PR_5_INODE_UNINIT		0x050019
 
+/* Inode bitmap checksum does not match */
+#define PR_5_INODE_BITMAP_CSUM_INVALID	0x05001A
+
 /*
  * Post-Pass 5 errors
  */


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

* [PATCH 15/37] libext2fs: Create the block bitmap checksum
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (13 preceding siblings ...)
  2011-09-01  0:36 ` [PATCH 14/37] e2fsck: Verify " Darrick J. Wong
@ 2011-09-01  0:36 ` Darrick J. Wong
  2011-09-01  0:36 ` [PATCH 16/37] dumpe2fs: Display " Darrick J. Wong
                   ` (20 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:36 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Provide a field in the block group descriptor to store block bitmap checksum,
and some helper functions to calculate and verify it.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/blknum.c     |   11 +++++++++++
 lib/ext2fs/csum.c       |   15 +++++++++++++++
 lib/ext2fs/ext2_fs.h    |    3 ++-
 lib/ext2fs/ext2fs.h     |    1 +
 lib/ext2fs/rw_bitmaps.c |   14 ++++++++++++++
 lib/ext2fs/swapfs.c     |    1 +
 6 files changed, 44 insertions(+), 1 deletions(-)


diff --git a/lib/ext2fs/blknum.c b/lib/ext2fs/blknum.c
index 47d3fda..07b2cb3 100644
--- a/lib/ext2fs/blknum.c
+++ b/lib/ext2fs/blknum.c
@@ -183,6 +183,17 @@ static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs,
 }
 
 /*
+ * Return the block bitmap checksum of a group
+ */
+blk64_t ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group)
+{
+	struct ext4_group_desc *gdp;
+
+	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
+	return gdp->bg_block_bitmap_csum;
+}
+
+/*
  * Return the block bitmap block of a group
  */
 blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group)
diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index 56b75da..f594c90 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -74,6 +74,21 @@ void ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group, char *bitmap,
 	gdp->bg_inode_bitmap_csum = ext2fs_bitmap_csum(fs, group, bitmap, size);
 }
 
+void ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group, char *bitmap,
+				  int size)
+{
+	struct ext4_group_desc *gdp = (struct ext4_group_desc *)
+			ext2fs_group_desc(fs, fs->group_desc, group);
+
+	if (fs->super->s_desc_size < EXT2_MIN_DESC_SIZE_64BIT)
+		return;
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return;
+
+	gdp->bg_block_bitmap_csum = ext2fs_bitmap_csum(fs, group, bitmap, size);
+}
+
 __u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
 			struct ext2_inode_large *inode)
 {
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 367bfdf..ec28fac 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -159,7 +159,8 @@ struct ext4_group_desc
 	__u16	bg_free_inodes_count;	/* Free inodes count */
 	__u16	bg_used_dirs_count;	/* Directories count */
 	__u16	bg_flags;		/* EXT4_BG_flags (INODE_UNINIT, etc) */
-	__u32	bg_reserved[2];		/* Likely block/inode bitmap checksum */
+	__u32	bg_reserved[1];		/* unclaimed */
+	__u32	bg_block_bitmap_csum;	/* crc32c(uuid+group+bbitmap) */
 	__u16	bg_itable_unused;	/* Unused inodes count */
 	__u16	bg_checksum;		/* crc16(sb_uuid+group+desc) */
 	__u32	bg_block_bitmap_hi;	/* Blocks bitmap block MSB */
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 0899e34..0cc3012 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -782,6 +782,7 @@ extern void ext2fs_free_blocks_count_add(struct ext2_super_block *super,
 extern struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
 					  struct opaque_ext2_group_desc *gdp,
 					  dgrp_t group);
+extern blk64_t ext2fs_block_bitmap_csum(ext2_filsys fs, dgrp_t group);
 extern blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group);
 extern void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group,
 					blk64_t blk);
diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c
index 57aba59..802ce9f 100644
--- a/lib/ext2fs/rw_bitmaps.c
+++ b/lib/ext2fs/rw_bitmaps.c
@@ -91,6 +91,10 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
 				for (j = nbits; j < fs->blocksize * 8; j++)
 					ext2fs_set_bit(j, block_buf);
 		}
+
+		ext2fs_block_bitmap_csum_set(fs, i, block_buf, block_nbytes);
+		ext2fs_group_desc_csum_set(fs, i);
+
 		blk = ext2fs_block_bitmap_loc(fs, i);
 		if (blk) {
 			retval = io_channel_write_blk64(fs->io, blk, 1,
@@ -259,6 +263,16 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
 					retval = EXT2_ET_BLOCK_BITMAP_READ;
 					goto cleanup;
 				}
+				/* verify block bitmap checksum */
+				gdp = (struct ext4_group_desc *)
+					ext2fs_group_desc(fs, fs->group_desc,
+							  i);
+				if (!(fs->flags &
+				      EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+				    !ext2fs_bitmap_csum_verify(fs, i,
+					gdp->bg_block_bitmap_csum,
+					block_bitmap, block_nbytes))
+					return EXT2_ET_BLOCK_BITMAP_READ;
 			} else
 				memset(block_bitmap, 0, block_nbytes);
 			cnt = block_nbytes << 3;
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index 747e130..f657c47 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -126,6 +126,7 @@ void ext2fs_swap_group_desc2(ext2_filsys fs, struct ext2_group_desc *gdp)
 		ext2fs_swab16(gdp4->bg_used_dirs_count_hi);
 	gdp4->bg_itable_unused_hi = ext2fs_swab16(gdp4->bg_itable_unused_hi);
 	gdp4->bg_inode_bitmap_csum = ext2fs_swab32(gdp4->bg_inode_bitmap_csum);
+	gdp4->bg_block_bitmap_csum = ext2fs_swab32(gdp4->bg_block_bitmap_csum);
 }
 
 void ext2fs_swap_group_desc(struct ext2_group_desc *gdp)


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

* [PATCH 16/37] dumpe2fs: Display block bitmap checksum
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (14 preceding siblings ...)
  2011-09-01  0:36 ` [PATCH 15/37] libext2fs: Create the block " Darrick J. Wong
@ 2011-09-01  0:36 ` Darrick J. Wong
  2011-09-01  0:37 ` [PATCH 17/37] e2fsck: Verify " Darrick J. Wong
                   ` (19 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:36 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Display the block bitmap checksum when displaying block groups.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 misc/dumpe2fs.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)


diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
index ed207cb..94162d2 100644
--- a/misc/dumpe2fs.c
+++ b/misc/dumpe2fs.c
@@ -216,6 +216,11 @@ static void list_desc (ext2_filsys fs)
 		print_number(ext2fs_block_bitmap_loc(fs, i));
 		print_bg_rel_offset(fs, ext2fs_block_bitmap_loc(fs, i), 0,
 				    first_block, last_block);
+		if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT &&
+		    fs->super->s_feature_ro_compat &
+		    EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+			printf(_(", checksum 0x%08x"),
+			       ext2fs_block_bitmap_checksum(fs, i));
 		fputs(_(", Inode bitmap at "), stdout);
 		print_number(ext2fs_inode_bitmap_loc(fs, i));
 		print_bg_rel_offset(fs, ext2fs_inode_bitmap_loc(fs, i), 0,


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

* [PATCH 17/37] e2fsck: Verify block bitmap checksum
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (15 preceding siblings ...)
  2011-09-01  0:36 ` [PATCH 16/37] dumpe2fs: Display " Darrick J. Wong
@ 2011-09-01  0:37 ` Darrick J. Wong
  2011-09-01  0:37 ` [PATCH 18/37] e2fsck: Don't verify bitmap checksums Darrick J. Wong
                   ` (18 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:37 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Check block bitmap checksum and write a new checksum if the verification fails.
This is ok because e2fsck has already computed the correct block bitmap.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 e2fsck/pass5.c   |   60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 e2fsck/problem.c |    5 +++++
 e2fsck/problem.h |    3 +++
 3 files changed, 68 insertions(+), 0 deletions(-)


diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c
index a0cc564..63b7e99 100644
--- a/e2fsck/pass5.c
+++ b/e2fsck/pass5.c
@@ -27,6 +27,7 @@ static void check_inode_bitmaps(e2fsck_t ctx);
 static void check_inode_end(e2fsck_t ctx);
 static void check_block_end(e2fsck_t ctx);
 static void check_inode_bitmap_checksum(e2fsck_t ctx);
+static void check_block_bitmap_checksum(e2fsck_t ctx);
 
 void e2fsck_pass5(e2fsck_t ctx)
 {
@@ -67,6 +68,7 @@ void e2fsck_pass5(e2fsck_t ctx)
 		return;
 
 	check_inode_bitmap_checksum(ctx);
+	check_block_bitmap_checksum(ctx);
 
 	ext2fs_free_inode_bitmap(ctx->inode_used_map);
 	ctx->inode_used_map = 0;
@@ -134,6 +136,64 @@ static void check_inode_bitmap_checksum(e2fsck_t ctx)
 	ext2fs_free_mem(&buf);
 }
 
+static void check_block_bitmap_checksum(e2fsck_t ctx)
+{
+	struct problem_context	pctx;
+	struct ext4_group_desc	*gdp;
+	char		*buf;
+	dgrp_t		i;
+	int		nbytes;
+	blk64_t		blk_itr;
+	errcode_t	retval;
+	int		csum_flag = 0;
+
+	/* If bitmap is dirty from being fixed, checksum will be corrected */
+	if (ext2fs_test_bb_dirty(ctx->fs))
+		return;
+
+	nbytes = (size_t)((EXT2_BLOCKS_PER_GROUP(ctx->fs->super) + 7) / 8);
+	retval = ext2fs_get_memalign(ctx->fs->blocksize, ctx->fs->blocksize,
+				     &buf);
+	if (retval)
+		return;
+
+	if (EXT2_HAS_RO_COMPAT_FEATURE(ctx->fs->super,
+				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+		csum_flag = 1;
+
+	clear_problem_context(&pctx);
+	for (i = 0; i < ctx->fs->group_desc_count; i++) {
+		if (csum_flag && ext2fs_bg_flags_test(ctx->fs, i,
+						      EXT2_BG_BLOCK_UNINIT))
+			continue;
+
+		blk_itr = EXT2FS_B2C(ctx->fs,
+				     ctx->fs->super->s_first_data_block) +
+			  (i * (nbytes << 3));
+		gdp = (struct ext4_group_desc *)ext2fs_group_desc(ctx->fs,
+				ctx->fs->group_desc, i);
+		retval = ext2fs_get_block_bitmap_range2(ctx->fs->block_map,
+							blk_itr, nbytes << 3,
+							buf);
+		if (retval)
+			break;
+
+		if (ext2fs_bitmap_csum_verify(ctx->fs, i,
+					      gdp->bg_block_bitmap_csum, buf,
+					      nbytes))
+			continue;
+		pctx.group = i;
+		if (!fix_problem(ctx, PR_5_BLOCK_BITMAP_CSUM_INVALID, &pctx))
+			continue;
+
+		/* Fixing one checksum will rewrite all of them */
+		ext2fs_mark_bb_dirty(ctx->fs);
+		break;
+	}
+
+	ext2fs_free_mem(&buf);
+}
+
 static void e2fsck_discard_blocks(e2fsck_t ctx, io_manager manager,
 				  blk64_t start, blk64_t count)
 {
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 35a8055..9629b9e 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1664,6 +1664,11 @@ static struct e2fsck_problem problem_table[] = {
 	  N_("@g %g @i bitmap does not match checksum\n"),
 	  PROMPT_FIX, PR_LATCH_IBITMAP | PR_PREEN_OK },
 
+	/* Group N block bitmap does not match checksum */
+	{ PR_5_BLOCK_BITMAP_CSUM_INVALID,
+	  N_("@g %g @b bitmap does not match checksum\n"),
+	  PROMPT_FIX, PR_LATCH_BBITMAP | PR_PREEN_OK },
+
 	/* Post-Pass 5 errors */
 
 	/* Recreate journal if E2F_FLAG_JOURNAL_INODE flag is set */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 9766113..8cc461b 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -1004,6 +1004,9 @@ struct problem_context {
 /* Inode bitmap checksum does not match */
 #define PR_5_INODE_BITMAP_CSUM_INVALID	0x05001A
 
+/* Block bitmap checksum does not match */
+#define PR_5_BLOCK_BITMAP_CSUM_INVALID	0x05001B
+
 /*
  * Post-Pass 5 errors
  */


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

* [PATCH 18/37] e2fsck: Don't verify bitmap checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (16 preceding siblings ...)
  2011-09-01  0:37 ` [PATCH 17/37] e2fsck: Verify " Darrick J. Wong
@ 2011-09-01  0:37 ` Darrick J. Wong
  2011-09-01  0:37 ` [PATCH 19/37] tune2fs: Rewrite block " Darrick J. Wong
                   ` (17 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:37 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Since the correct inode and block bitmaps are calculated in pass 5, don't fail
the bitmap read operation in prior passes since (a) incorrect results won't
kill us and (b) if we fail early, we'll never _get_ to pass 5.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 e2fsck/util.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)


diff --git a/e2fsck/util.c b/e2fsck/util.c
index 22e06c2..61fa3db 100644
--- a/e2fsck/util.c
+++ b/e2fsck/util.c
@@ -224,7 +224,9 @@ void e2fsck_read_bitmaps(e2fsck_t ctx)
 	}
 
 	old_op = ehandler_operation(_("reading inode and block bitmaps"));
+	ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
 	retval = ext2fs_read_bitmaps(fs);
+	ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 	ehandler_operation(old_op);
 	if (retval) {
 		com_err(ctx->program_name, retval,


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

* [PATCH 19/37] tune2fs: Rewrite block bitmap checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (17 preceding siblings ...)
  2011-09-01  0:37 ` [PATCH 18/37] e2fsck: Don't verify bitmap checksums Darrick J. Wong
@ 2011-09-01  0:37 ` Darrick J. Wong
  2011-09-01  0:37 ` [PATCH 20/37] libext2fs: Verify and calculate extent tree block checksums Darrick J. Wong
                   ` (16 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:37 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

When toggling metadata_csum, mark the block bitmap dirty so that it gets
written with new checksums.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 misc/tune2fs.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)


diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 36a5cb8..dd4011e 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -397,6 +397,7 @@ static void rewrite_metadata_checksums(ext2_filsys fs)
 	rewrite_inodes(fs);
 	ext2fs_read_bitmaps(fs);
 	ext2fs_mark_ib_dirty(fs);
+	ext2fs_mark_bb_dirty(fs);
 	fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
 	fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 }


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

* [PATCH 20/37] libext2fs: Verify and calculate extent tree block checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (18 preceding siblings ...)
  2011-09-01  0:37 ` [PATCH 19/37] tune2fs: Rewrite block " Darrick J. Wong
@ 2011-09-01  0:37 ` Darrick J. Wong
  2011-09-01  0:37 ` [PATCH 21/37] tune2fs: Enable extent tree checksums Darrick J. Wong
                   ` (15 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:37 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Verify and calculate extent tree block checksums when processing filesystems.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/csum.c         |   64 +++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/ext2fs.h       |    8 ++++++
 lib/ext2fs/ext3_extents.h |   11 ++++++++
 lib/ext2fs/extent.c       |   16 +++++++++++
 4 files changed, 99 insertions(+), 0 deletions(-)


diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index f594c90..fdca971 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -29,6 +29,70 @@
 #define STATIC static
 #endif
 
+#define EXT3_EXTENT_TAIL_OFFSET(hdr)	(sizeof(struct ext3_extent_header) + \
+	(sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max)))
+
+static struct ext3_extent_tail *get_extent_tail(struct ext3_extent_header *h)
+{
+	return (struct ext3_extent_tail *)(((void *)h) +
+					   EXT3_EXTENT_TAIL_OFFSET(h));
+}
+
+__u32 ext2fs_extent_block_csum(ext2_filsys fs, ext2_ino_t inum,
+			       struct ext3_extent_header *eh)
+{
+	int size;
+	__u32 crc = 0;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return 0;
+
+	size = EXT3_EXTENT_TAIL_OFFSET(eh) + offsetof(struct ext3_extent_tail,
+						      et_checksum);
+
+	inum = ext2fs_cpu_to_le32(inum);
+	crc = crc32c_le(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid));
+	crc = crc32c_le(crc, (char *)&inum, sizeof(inum));
+	crc = crc32c_le(crc, (char *)eh, size);
+
+	return crc;
+}
+
+int ext2fs_extent_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+				    struct ext3_extent_header *eh)
+{
+	struct ext3_extent_tail *t = get_extent_tail(eh);
+
+	/*
+	 * The extent tree structures are accessed in LE order, so we must
+	 * swap the checksum bytes here.
+	 */
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+	    ext2fs_le32_to_cpu(t->et_checksum) !=
+	    ext2fs_extent_block_csum(fs, inum, eh))
+		return 0;
+	return 1;
+}
+
+void ext2fs_extent_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
+				  struct ext3_extent_header *eh)
+{
+	struct ext3_extent_tail *t = get_extent_tail(eh);
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return;
+
+	/*
+	 * The extent tree structures are accessed in LE order, so we must
+	 * swap the checksum bytes here.
+	 */
+	t->et_checksum = ext2fs_cpu_to_le32(ext2fs_extent_block_csum(fs, inum,
+								     eh));
+}
+
 __u32 ext2fs_bitmap_csum(ext2_filsys fs, dgrp_t group, char *bitmap, int size)
 {
 	__u32 crc = 0;
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 0cc3012..1e3e9f1 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -894,6 +894,14 @@ extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len);
 extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
 
 /* csum.c */
+extern __u32 ext2fs_extent_block_csum(ext2_filsys fs, ext2_ino_t inum,
+				      struct ext3_extent_header *eh);
+extern int ext2fs_extent_block_csum_verify(ext2_filsys fs,
+					   ext2_ino_t inum,
+					   struct ext3_extent_header *eh);
+extern void ext2fs_extent_block_csum_set(ext2_filsys fs,
+					 ext2_ino_t inum,
+					 struct ext3_extent_header *eh);
 extern __u32 ext2fs_bitmap_csum(ext2_filsys fs, dgrp_t group, char *bitmap,
 				int size);
 extern int ext2fs_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
diff --git a/lib/ext2fs/ext3_extents.h b/lib/ext2fs/ext3_extents.h
index 88fabc9..99a4f47 100644
--- a/lib/ext2fs/ext3_extents.h
+++ b/lib/ext2fs/ext3_extents.h
@@ -19,6 +19,17 @@
  */
 
 /*
+ * This is extent tail on-disk structure.
+ * All other extent structures are 12 bytes long.  It turns out that
+ * block_size % 12 >= 4 for all valid block sizes (1k, 2k, 4k).
+ * 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
  */
diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
index 33f1a88..d19af48 100644
--- a/lib/ext2fs/extent.c
+++ b/lib/ext2fs/extent.c
@@ -452,6 +452,13 @@ retry:
 			return retval;
 		}
 
+		if (!(handle->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+		    !ext2fs_extent_block_csum_verify(handle->fs, handle->ino,
+						     eh)) {
+			handle->level--;
+			return EXT2_ET_EXTENT_HEADER_BAD;
+		}
+
 		newpath->left = newpath->entries =
 			ext2fs_le16_to_cpu(eh->eh_entries);
 		newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
@@ -538,6 +545,7 @@ static errcode_t update_path(ext2_extent_handle_t handle)
 	blk64_t				blk;
 	errcode_t			retval;
 	struct ext3_extent_idx		*ix;
+	struct ext3_extent_header	*eh;
 
 	if (handle->level == 0) {
 		retval = ext2fs_write_inode(handle->fs, handle->ino,
@@ -547,6 +555,11 @@ static errcode_t update_path(ext2_extent_handle_t handle)
 		blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
 			((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
 
+		/* then update the checksum */
+		eh = (struct ext3_extent_header *)
+				handle->path[handle->level].buf;
+		ext2fs_extent_block_csum_set(handle->fs, handle->ino, eh);
+
 		retval = io_channel_write_blk64(handle->fs->io,
 				      blk, 1, handle->path[handle->level].buf);
 	}
@@ -955,6 +968,9 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle)
 
 	new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block);
 
+	/* then update the checksum */
+	ext2fs_extent_block_csum_set(handle->fs, handle->ino, neweh);
+
 	/* ...and write the new node block out to disk. */
 	retval = io_channel_write_blk64(handle->fs->io, new_node_pblk, 1,
 					block_buf);


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

* [PATCH 21/37] tune2fs: Enable extent tree checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (19 preceding siblings ...)
  2011-09-01  0:37 ` [PATCH 20/37] libext2fs: Verify and calculate extent tree block checksums Darrick J. Wong
@ 2011-09-01  0:37 ` Darrick J. Wong
  2011-09-01  0:37 ` [PATCH 22/37] libext2fs: Introduce dx_tail and dir_entry_tail Darrick J. Wong
                   ` (14 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:37 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Add to tune2fs the ability to recalculate extent tree checksums when altering
the metadata checksum feature flag.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 misc/tune2fs.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 50 insertions(+), 0 deletions(-)


diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index dd4011e..0c0a911 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -355,6 +355,49 @@ static void request_fsck_afterwards(ext2_filsys fs)
 		printf(_("(and reboot afterwards!)\n"));
 }
 
+/* Rewrite extents */
+static errcode_t rewrite_extents(ext2_filsys fs, ext2_ino_t ino,
+				 struct ext2_inode_large *inode)
+{
+	ext2_extent_handle_t	handle;
+	struct ext2fs_extent	extent;
+	int			op = EXT2_EXTENT_ROOT;
+	unsigned int		printed = 0;
+	errcode_t		errcode;
+
+	if (!(inode->i_flags & EXT4_EXTENTS_FL))
+		return 0;
+
+	errcode = ext2fs_extent_open(fs, ino, &handle);
+	if (errcode)
+		return errcode;
+
+	while (1) {
+		errcode = ext2fs_extent_get(handle, op, &extent);
+		if (errcode)
+			break;
+
+		/* Root node is in the separately checksummed inode */
+		if (op == EXT2_EXTENT_ROOT) {
+			op = EXT2_EXTENT_NEXT;
+			continue;
+		}
+		op = EXT2_EXTENT_NEXT;
+
+		/* Only visit the first extent in each extent block */
+		if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
+			continue;
+		errcode = ext2fs_extent_replace(handle, 0, &extent);
+		if (errcode)
+			break;
+	}
+
+	/* Ok if we run off the end */
+	if (errcode == EXT2_ET_EXTENT_NO_NEXT)
+		errcode = 0;
+	return errcode;
+}
+
 /*
  * Forcibly set checksums in all inodes.
  */
@@ -387,6 +430,13 @@ static void rewrite_inodes(ext2_filsys fs)
 			com_err("set_csum", retval, "while writing inode");
 			exit(1);
 		}
+
+		retval = rewrite_extents(fs, ino, &inode);
+		if (retval) {
+			com_err("rewrite_extents", retval,
+				"while rewriting extents");
+			exit(1);
+		}
 	} while (ino);
 	ext2fs_close_inode_scan(scan);
 }


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

* [PATCH 22/37] libext2fs: Introduce dx_tail and dir_entry_tail
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (20 preceding siblings ...)
  2011-09-01  0:37 ` [PATCH 21/37] tune2fs: Enable extent tree checksums Darrick J. Wong
@ 2011-09-01  0:37 ` Darrick J. Wong
  2011-09-01  0:37 ` [PATCH 23/37] debugfs: Print htree internal node checksums Darrick J. Wong
                   ` (13 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:37 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Introduce small structures for recording directory tree checksums

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/ext2_fs.h |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)


diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index ec28fac..64adff9 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -217,6 +217,14 @@ struct ext2_dx_countlimit {
 	__u16 count;
 };
 
+/*
+ * This goes at the end of each htree block.  If you want to use the
+ * reserved field, you'll have to update the checksum code to include it.
+ */
+struct ext2_dx_tail {
+	__u32 reserved;
+	__u32 checksum;	/* crc32c(uuid+inum+dxblock) */
+};
 
 /*
  * Macro-instructions used to manage group descriptors


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

* [PATCH 23/37] debugfs: Print htree internal node checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (21 preceding siblings ...)
  2011-09-01  0:37 ` [PATCH 22/37] libext2fs: Introduce dx_tail and dir_entry_tail Darrick J. Wong
@ 2011-09-01  0:37 ` Darrick J. Wong
  2011-09-01  0:37 ` [PATCH 24/37] libext2fs: Add dx_root/dx_node checksum calculation and verification helpers Darrick J. Wong
                   ` (12 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:37 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Print htree node checksums when dumping a directory index.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 debugfs/htree.c |   17 ++++++++++++++++-
 1 files changed, 16 insertions(+), 1 deletions(-)


diff --git a/debugfs/htree.c b/debugfs/htree.c
index d72b996..9b4758a 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -120,8 +120,9 @@ static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
 {
 	struct ext2_dx_countlimit	limit;
 	struct ext2_dx_entry		e;
+	struct ext2_dx_tail		*tail;
 	int				hash, i;
-
+	int				remainder;
 
 	limit = *((struct ext2_dx_countlimit *) ent);
 	limit.count = ext2fs_le16_to_cpu(limit.count);
@@ -130,6 +131,20 @@ static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
 	fprintf(pager, "Number of entries (count): %d\n", limit.count);
 	fprintf(pager, "Number of entries (limit): %d\n", limit.limit);
 
+	remainder = fs->blocksize - (limit.limit *
+				     sizeof(struct ext2_dx_entry));
+	if (ent == (struct ext2_dx_entry *)(rootnode + 1))
+		remainder -= sizeof(struct ext2_dx_root_info) + 24;
+	else
+		remainder -= 8;
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+	    remainder == sizeof(struct ext2_dx_tail)) {
+		tail = (struct ext2_dx_tail *)(ent + limit.limit);
+		fprintf(pager, "Checksum: 0x%08x\n",
+			ext2fs_le32_to_cpu(tail->checksum));
+	}
+
 	for (i=0; i < limit.count; i++) {
 		hash = i ? ext2fs_le32_to_cpu(ent[i].hash) : 0;
 		fprintf(pager, "Entry #%d: Hash 0x%08x%s, block %u\n", i,


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

* [PATCH 24/37] libext2fs: Add dx_root/dx_node checksum calculation and verification helpers
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (22 preceding siblings ...)
  2011-09-01  0:37 ` [PATCH 23/37] debugfs: Print htree internal node checksums Darrick J. Wong
@ 2011-09-01  0:37 ` Darrick J. Wong
  2011-09-01  0:37 ` [PATCH 25/37] e2fsck: Verify htree root/node checksums Darrick J. Wong
                   ` (11 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:37 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Verify and calculate checksums of htree internal node blocks.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/csum.c    |  107 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/dirhash.c |   41 +++++++++++++++++++
 lib/ext2fs/ext2fs.h  |    8 ++++
 3 files changed, 156 insertions(+), 0 deletions(-)


diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index fdca971..4963524 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -29,6 +29,113 @@
 #define STATIC static
 #endif
 
+__u32 ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
+		     struct ext2_dir_entry *dirent)
+{
+	char *buf = (char *)dirent;
+	struct ext2_dx_countlimit *c;
+	int size, count_offset, limit, count;
+	__u32 crc = 0;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return 0;
+
+	c = ext2fs_get_dx_countlimit(fs, dirent, &count_offset);
+	if (!c)
+		return 0;
+	limit = ext2fs_le16_to_cpu(c->limit);
+	count = ext2fs_le16_to_cpu(c->count);
+	if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
+	    fs->blocksize - sizeof(struct ext2_dx_tail))
+		return 0;
+
+	size = count_offset + (count * sizeof(struct ext2_dx_entry));
+
+	/*
+	 * The dx_root/dx_entry structures are always accessed via
+	 * le*_to_cpu helpers and don't need swapping here.  However, the
+	 * dirent container fields need to be swapped.
+	 */
+#ifdef WORDS_BIGENDIAN
+	errcode_t retval;
+
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return 0;
+	memcpy(buf, dirent, fs->blocksize);
+	retval = ext2fs_dirent_swab_out(fs, buf, 0);
+	if (retval) {
+		crc = 0;
+		goto out;
+	}
+#endif
+
+	inum = ext2fs_cpu_to_le32(inum);
+	crc = crc32c_le(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid));
+	crc = crc32c_le(crc, (char *)&inum, sizeof(inum));
+	crc = crc32c_le(crc, buf, size);
+
+#ifdef WORDS_BIGENDIAN
+out:
+	ext2fs_free_mem(&buf);
+#endif
+
+	return crc;
+}
+
+int ext2fs_dx_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+			  struct ext2_dir_entry *dirent)
+{
+	struct ext2_dx_countlimit *c;
+	struct ext2_dx_tail *t;
+	int count_offset, limit, count;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return 1;
+
+	c = ext2fs_get_dx_countlimit(fs, dirent, &count_offset);
+	if (!c)
+		return 1;
+	limit = ext2fs_le16_to_cpu(c->limit);
+	count = ext2fs_le16_to_cpu(c->count);
+	if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
+	    fs->blocksize - sizeof(struct ext2_dx_tail))
+		return 0;
+	/* htree structs are accessed in LE order */
+	t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
+	if (ext2fs_le32_to_cpu(t->checksum) != ext2fs_dx_csum(fs, inum, dirent))
+		return 0;
+
+	return 1;
+}
+
+void ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum,
+			struct ext2_dir_entry *dirent)
+{
+	struct ext2_dx_countlimit *c;
+	struct ext2_dx_tail *t;
+	int count_offset, limit, count;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return;
+
+	c = ext2fs_get_dx_countlimit(fs, dirent, &count_offset);
+	if (!c)
+		return;
+	limit = ext2fs_le16_to_cpu(c->limit);
+	count = ext2fs_le16_to_cpu(c->count);
+	if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
+	    fs->blocksize - sizeof(struct ext2_dx_tail))
+		return;
+	t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
+
+	/* htree structs are accessed in LE order */
+	t->checksum = ext2fs_cpu_to_le32(ext2fs_dx_csum(fs, inum, dirent));
+}
+
 #define EXT3_EXTENT_TAIL_OFFSET(hdr)	(sizeof(struct ext3_extent_header) + \
 	(sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max)))
 
diff --git a/lib/ext2fs/dirhash.c b/lib/ext2fs/dirhash.c
index a069706..76ac274 100644
--- a/lib/ext2fs/dirhash.c
+++ b/lib/ext2fs/dirhash.c
@@ -255,3 +255,44 @@ errcode_t ext2fs_dirhash(int version, const char *name, int len,
 		*ret_minor_hash = minor_hash;
 	return 0;
 }
+
+struct ext2_dx_countlimit *ext2fs_get_dx_countlimit(ext2_filsys fs,
+		struct ext2_dir_entry *dirent, int *offset)
+{
+	struct ext2_dir_entry *dp;
+	struct ext2_dx_root_info *root;
+	struct ext2_dx_countlimit *c;
+	int count_offset, max_sane_entries;
+	unsigned int rec_len;
+	errcode_t retval;
+
+	retval = ext2fs_get_rec_len(fs, dirent, &rec_len);
+	if (retval)
+		return NULL;
+
+	if (rec_len == fs->blocksize && dirent->name_len == 0)
+		count_offset = 8;
+	else if (rec_len == 12) {
+		dp = (struct ext2_dir_entry *)(((void *)dirent) + rec_len);
+		retval = ext2fs_get_rec_len(fs, dp, &rec_len);
+		if (retval || rec_len != fs->blocksize - 12)
+			return NULL;
+		root = (struct ext2_dx_root_info *)(((void *)dp + 12));
+		if (root->reserved_zero ||
+		    root->info_length != sizeof(struct ext2_dx_root_info))
+			return NULL;
+		count_offset = 32;
+	} else
+		return NULL;
+
+	c = (struct ext2_dx_countlimit *)(((void *)dirent) + count_offset);
+	max_sane_entries = (fs->blocksize - count_offset) /
+			   sizeof(struct ext2_dx_entry);
+	if (ext2fs_le16_to_cpu(c->limit) > max_sane_entries ||
+	    ext2fs_le16_to_cpu(c->count) > max_sane_entries)
+		return NULL;
+
+	if (offset)
+		*offset = count_offset;
+	return c;
+}
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 1e3e9f1..7110f72 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -894,6 +894,12 @@ extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len);
 extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
 
 /* csum.c */
+extern __u32 ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
+			    struct ext2_dir_entry *dirent);
+extern int ext2fs_dx_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+				 struct ext2_dir_entry *dirent);
+extern void ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum,
+			       struct ext2_dir_entry *dirent);
 extern __u32 ext2fs_extent_block_csum(ext2_filsys fs, ext2_ino_t inum,
 				      struct ext3_extent_header *eh);
 extern int ext2fs_extent_block_csum_verify(ext2_filsys fs,
@@ -983,6 +989,8 @@ extern errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
 					 void *buf, int flags);
 
 /* dirhash.c */
+extern struct ext2_dx_countlimit *ext2fs_get_dx_countlimit(ext2_filsys fs,
+				struct ext2_dir_entry *dirent, int *offset);
 extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
 				const __u32 *seed,
 				ext2_dirhash_t *ret_hash,


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

* [PATCH 25/37] e2fsck: Verify htree root/node checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (23 preceding siblings ...)
  2011-09-01  0:37 ` [PATCH 24/37] libext2fs: Add dx_root/dx_node checksum calculation and verification helpers Darrick J. Wong
@ 2011-09-01  0:37 ` Darrick J. Wong
  2011-09-01  0:37 ` [PATCH 26/37] libext2fs: Introduce dir_entry_tail to provide checksums for directory leaf nodes Darrick J. Wong
                   ` (10 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:37 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Check htree internal node checksums.  If broken, ask user to clear the htree
index and recreate it later.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 e2fsck/pass2.c   |   32 ++++++++++++++++++++++++++++----
 e2fsck/problem.c |   10 ++++++++++
 e2fsck/problem.h |    6 ++++++
 e2fsck/rehash.c  |   25 ++++++++++++++++++++++---
 4 files changed, 66 insertions(+), 7 deletions(-)


diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 9241a07..586bcec 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -532,6 +532,7 @@ static void parse_int_node(ext2_filsys fs,
 	ext2_dirhash_t	min_hash = 0xffffffff;
 	ext2_dirhash_t	max_hash = 0;
 	ext2_dirhash_t	hash = 0, prev_hash;
+	int		csum_size = 0;
 
 	if (db->blockcnt == 0) {
 		root = (struct ext2_dx_root_info *) (block_buf + 24);
@@ -545,10 +546,24 @@ static void parse_int_node(ext2_filsys fs,
 		printf("\t Flags: %d\n", root->unused_flags);
 #endif
 
-		ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
+		ent = (struct ext2_dx_entry *)
+				(block_buf + 24 + root->info_length);
+
+		if (!ext2fs_dx_csum_verify(fs, cd->pctx.ino,
+				(struct ext2_dir_entry *)block_buf) &&
+		    fix_problem(cd->ctx, PR_2_HTREE_ROOT_CSUM_INVALID,
+				&cd->pctx))
+			goto clear_and_exit;
 	} else {
 		ent = (struct ext2_dx_entry *) (block_buf+8);
+
+		if (!ext2fs_dx_csum_verify(fs, cd->pctx.ino,
+				(struct ext2_dir_entry *)block_buf) &&
+		    fix_problem(cd->ctx, PR_2_HTREE_NODE_CSUM_INVALID,
+				&cd->pctx))
+			goto clear_and_exit;
 	}
+
 	limit = (struct ext2_dx_countlimit *) ent;
 
 #ifdef DX_DEBUG
@@ -559,8 +574,12 @@ static void parse_int_node(ext2_filsys fs,
 #endif
 
 	count = ext2fs_le16_to_cpu(limit->count);
-	expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
-		sizeof(struct ext2_dx_entry);
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		csum_size = sizeof(struct ext2_dx_tail);
+	expect_limit = (fs->blocksize -
+			(csum_size + ((char *) ent - block_buf))) /
+		       sizeof(struct ext2_dx_entry);
 	if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
 		cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
 		if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
@@ -729,6 +748,7 @@ static int check_dir_block(ext2_filsys fs,
 	struct problem_context	pctx;
 	int	dups_found = 0;
 	int	ret;
+	int	csum_size = 0;
 
 	cd = (struct check_dir_struct *) priv_data;
 	buf = cd->buf;
@@ -740,6 +760,10 @@ static int check_dir_block(ext2_filsys fs,
 	if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
 		return DIRENT_ABORT;
 
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		csum_size = sizeof(struct ext2_dx_tail);
+
 	/*
 	 * Make sure the inode is still in use (could have been
 	 * deleted in the duplicate/bad blocks pass.
@@ -829,7 +853,7 @@ static int check_dir_block(ext2_filsys fs,
 			   (rec_len == fs->blocksize) &&
 			   (dirent->name_len == 0) &&
 			   (ext2fs_le16_to_cpu(limit->limit) ==
-			    ((fs->blocksize-8) /
+			    ((fs->blocksize - (8 + csum_size)) /
 			     sizeof(struct ext2_dx_entry))))
 			dx_db->type = DX_DIRBLOCK_NODE;
 	}
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 9629b9e..637b254 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1343,6 +1343,16 @@ static struct e2fsck_problem problem_table[] = {
 	  N_("i_file_acl_hi @F %N, @s zero.\n"),
 	  PROMPT_CLEAR, PR_PREEN_OK },
 
+	/* htree root node fails checksum */
+	{ PR_2_HTREE_ROOT_CSUM_INVALID,
+	  N_("@p @h %d: root node fails checksum\n"),
+	  PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+	/* htree internal node fails checksum */
+	{ PR_2_HTREE_NODE_CSUM_INVALID,
+	  N_("@p @h %d: node fails checksum\n"),
+	  PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
 	/* Pass 3 errors */
 
 	/* Pass 3: Checking directory connectivity */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 8cc461b..d4e596f 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -803,6 +803,12 @@ struct problem_context {
 /* i_file_acl_hi should be zero */
 #define PR_2_I_FILE_ACL_HI_ZERO		0x020048
 
+/* htree root node fails checksum */
+#define PR_2_HTREE_ROOT_CSUM_INVALID	0x020049
+
+/* htree node fails checksum */
+#define PR_2_HTREE_NODE_CSUM_INVALID	0x02004A
+
 /*
  * Pass 3 errors
  */
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 1263f56..97d2b83 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -494,6 +494,7 @@ static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
 	struct ext2_dx_root_info  	*root;
 	struct ext2_dx_countlimit	*limits;
 	int				filetype = 0;
+	int				csum_size = 0;
 
 	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
 		filetype = EXT2_FT_DIR << 8;
@@ -518,8 +519,13 @@ static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
 	root->indirect_levels = 0;
 	root->unused_flags = 0;
 
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		csum_size = sizeof(struct ext2_dx_tail);
+
 	limits = (struct ext2_dx_countlimit *) (buf+32);
-	limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
+	limits->limit = (fs->blocksize - (32 + csum_size)) /
+			sizeof(struct ext2_dx_entry);
 	limits->count = 0;
 
 	return root;
@@ -530,14 +536,20 @@ static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
 {
 	struct ext2_dir_entry 		*dir;
 	struct ext2_dx_countlimit	*limits;
+	int				csum_size = 0;
 
 	memset(buf, 0, fs->blocksize);
 	dir = (struct ext2_dir_entry *) buf;
 	dir->inode = 0;
 	(void) ext2fs_set_rec_len(fs, fs->blocksize, dir);
 
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		csum_size = sizeof(struct ext2_dx_tail);
+
 	limits = (struct ext2_dx_countlimit *) (buf+8);
-	limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
+	limits->limit = (fs->blocksize - (8 + csum_size)) /
+			sizeof(struct ext2_dx_entry);
 	limits->count = 0;
 
 	return (struct ext2_dx_entry *) limits;
@@ -587,9 +599,12 @@ static errcode_t calculate_tree(ext2_filsys fs,
 			if (c1 == 0)
 				return ENOSPC;
 			if (c2 == 0) {
-				if (limit)
+				if (limit) {
 					limit->limit = limit->count =
 		ext2fs_cpu_to_le16(limit->limit);
+					ext2fs_dx_csum_set(fs, ino,
+		(struct ext2_dir_entry *)(((void *)limit) - 8));
+				}
 				root = (struct ext2_dx_entry *)
 					(outdir->buf + root_offset);
 				root->block = ext2fs_cpu_to_le32(outdir->num);
@@ -614,10 +629,14 @@ static errcode_t calculate_tree(ext2_filsys fs,
 		}
 		limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
 		limit->limit = ext2fs_cpu_to_le16(limit->limit);
+		ext2fs_dx_csum_set(fs, ino,
+				   (struct ext2_dir_entry *)(((void *)limit) -
+							     8));
 	}
 	root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
 	root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
 	root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
+	ext2fs_dx_csum_set(fs, ino, (struct ext2_dir_entry *)outdir->buf);
 
 	return 0;
 }


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

* [PATCH 26/37] libext2fs: Introduce dir_entry_tail to provide checksums for directory leaf nodes
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (24 preceding siblings ...)
  2011-09-01  0:37 ` [PATCH 25/37] e2fsck: Verify htree root/node checksums Darrick J. Wong
@ 2011-09-01  0:37 ` Darrick J. Wong
  2011-09-01  0:38 ` [PATCH 27/37] e2fsck: Check directory leaf block checksums Darrick J. Wong
                   ` (9 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:37 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Introduce small structures for recording directory tree checksums, and some API
changes to support writing out directory blocks with checksums.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 debugfs/htree.c          |    9 ++-
 e2fsck/pass1.c           |    4 +
 e2fsck/pass2.c           |    9 ++-
 e2fsck/pass3.c           |    8 +-
 e2fsck/rehash.c          |   48 ++++++++++----
 lib/ext2fs/csum.c        |  159 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/dir_iterate.c |   12 +++
 lib/ext2fs/dirblock.c    |   94 +++++++++------------------
 lib/ext2fs/expanddir.c   |    4 +
 lib/ext2fs/ext2_fs.h     |   11 +++
 lib/ext2fs/ext2fs.h      |   26 ++++++--
 lib/ext2fs/link.c        |    6 +-
 lib/ext2fs/mkdir.c       |    2 -
 lib/ext2fs/newdir.c      |   17 ++++-
 lib/ext2fs/swapfs.c      |   62 ++++++++++++++++++
 15 files changed, 372 insertions(+), 99 deletions(-)


diff --git a/debugfs/htree.c b/debugfs/htree.c
index 9b4758a..1850978 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -43,6 +43,11 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
 	ext2_dirhash_t 	hash, minor_hash;
 	unsigned int	rec_len;
 	int		hash_alg;
+	int		csum_size = 0;
+
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		csum_size = sizeof(struct ext2_dir_entry_tail);
 
 	errcode = ext2fs_bmap2(fs, ino, inode, buf, 0, blk, 0, &pblk);
 	if (errcode) {
@@ -52,7 +57,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
 	}
 
 	printf("Reading directory block %llu, phys %llu\n", blk, pblk);
-	errcode = ext2fs_read_dir_block2(current_fs, pblk, buf, 0);
+	errcode = ext2fs_read_dir_block2(current_fs, pblk, buf, 0, ino);
 	if (errcode) {
 		com_err("htree_dump_leaf_node", errcode,
 			"while reading block %llu (%llu)\n",
@@ -64,7 +69,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
 	    (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
 		hash_alg += 3;
 
-	while (offset < fs->blocksize) {
+	while (offset < (fs->blocksize - csum_size)) {
 		dirent = (struct ext2_dir_entry *) (buf + offset);
 		errcode = ext2fs_get_rec_len(fs, dirent, &rec_len);
 		if (errcode) {
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index e9b0876..71cbddb 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -473,7 +473,9 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
 
 	/* read the first block */
 	old_op = ehandler_operation(_("reading directory block"));
-	retval = ext2fs_read_dir_block3(ctx->fs, blk, buf, 0);
+	ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+	retval = ext2fs_read_dir_block3(ctx->fs, blk, buf, 0, pctx->ino);
+	ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 	ehandler_operation(0);
 	if (retval)
 		return;
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 586bcec..93a09d1 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -799,7 +799,9 @@ static int check_dir_block(ext2_filsys fs,
 #endif
 
 	old_op = ehandler_operation(_("reading directory block"));
-	cd->pctx.errcode = ext2fs_read_dir_block3(fs, block_nr, buf, 0);
+	ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+	cd->pctx.errcode = ext2fs_read_dir_block3(fs, block_nr, buf, 0, ino);
+	ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 	ehandler_operation(0);
 	if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
 		cd->pctx.errcode = 0; /* We'll handle this ourselves */
@@ -1157,7 +1159,8 @@ out_htree:
 		}
 	}
 	if (dir_modified) {
-		cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
+		cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf,
+							  ino);
 		if (cd->pctx.errcode) {
 			if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
 					 &cd->pctx))
@@ -1467,7 +1470,7 @@ static int allocate_dir_block(e2fsck_t ctx,
 		return 1;
 	}
 
-	pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
+	pctx->errcode = ext2fs_write_dir_block(fs, blk, block, db->ino);
 	ext2fs_free_mem(&block);
 	if (pctx->errcode) {
 		pctx->str = "ext2fs_write_dir_block";
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index 2330aab..2360aff 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -196,7 +196,7 @@ static void check_root(e2fsck_t ctx)
 		return;
 	}
 
-	pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
+	pctx.errcode = ext2fs_write_dir_block(fs, blk, block, EXT2_ROOT_INO);
 	if (pctx.errcode) {
 		pctx.str = "ext2fs_write_dir_block";
 		fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
@@ -442,7 +442,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
 		return 0;
 	}
 
-	retval = ext2fs_write_dir_block(fs, blk, block);
+	retval = ext2fs_write_dir_block(fs, blk, block, ino);
 	ext2fs_free_mem(&block);
 	if (retval) {
 		pctx.errcode = retval;
@@ -681,6 +681,7 @@ struct expand_dir_struct {
 	blk64_t			last_block;
 	errcode_t		err;
 	e2fsck_t		ctx;
+	ext2_ino_t		dir;
 };
 
 static int expand_dir_proc(ext2_filsys fs,
@@ -721,7 +722,7 @@ static int expand_dir_proc(ext2_filsys fs,
 			return BLOCK_ABORT;
 		}
 		es->num--;
-		retval = ext2fs_write_dir_block(fs, new_blk, block);
+		retval = ext2fs_write_dir_block(fs, new_blk, block, es->dir);
 	} else {
 		retval = ext2fs_get_mem(fs->blocksize, &block);
 		if (retval) {
@@ -774,6 +775,7 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
 	es.err = 0;
 	es.newblocks = 0;
 	es.ctx = ctx;
+	es.dir = dir;
 
 	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
 				       0, expand_dir_proc, &es);
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 97d2b83..25cc8b8 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -61,6 +61,7 @@ struct fill_dir_struct {
 	int dir_size;
 	int compress;
 	ino_t parent;
+	ext2_ino_t dir;
 };
 
 struct hash_entry {
@@ -105,7 +106,10 @@ static int fill_dir_block(ext2_filsys fs,
 		dirent = (struct ext2_dir_entry *) dir;
 		(void) ext2fs_set_rec_len(fs, fs->blocksize, dirent);
 	} else {
-		fd->err = ext2fs_read_dir_block3(fs, *block_nr, dir, 0);
+		fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+		fd->err = ext2fs_read_dir_block3(fs, *block_nr, dir, 0,
+						 fd->dir);
+		fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 		if (fd->err)
 			return BLOCK_ABORT;
 	}
@@ -396,7 +400,8 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
 
 static errcode_t copy_dir_entries(e2fsck_t ctx,
 				  struct fill_dir_struct *fd,
-				  struct out_dir *outdir)
+				  struct out_dir *outdir,
+				  ext2_ino_t ino)
 {
 	ext2_filsys 		fs = ctx->fs;
 	errcode_t		retval;
@@ -407,6 +412,8 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
 	int			i, left;
 	ext2_dirhash_t		prev_hash;
 	int			offset, slack;
+	int			csum_size = 0;
+	struct			ext2_dir_entry_tail *t;
 
 	if (ctx->htree_slack_percentage == 255) {
 		profile_get_uint(ctx->profile, "options",
@@ -417,6 +424,10 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
 			ctx->htree_slack_percentage = 20;
 	}
 
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		csum_size = sizeof(struct ext2_dir_entry_tail);
+
 	outdir->max = 0;
 	retval = alloc_size_dir(fs, outdir,
 				(fd->dir_size / fs->blocksize) + 2);
@@ -431,9 +442,9 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
 	dirent = (struct ext2_dir_entry *) block_start;
 	prev_rec_len = 0;
 	rec_len = 0;
-	left = fs->blocksize;
+	left = fs->blocksize - csum_size;
 	slack = fd->compress ? 12 :
-		(fs->blocksize * ctx->htree_slack_percentage)/100;
+		((fs->blocksize - csum_size) * ctx->htree_slack_percentage)/100;
 	if (slack < 12)
 		slack = 12;
 	for (i = 0; i < fd->num_array; i++) {
@@ -448,12 +459,20 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
 				if (retval)
 					return retval;
 			}
+			if (csum_size) {
+				t = (struct ext2_dir_entry_tail *)
+						(block_start + fs->blocksize -
+						 csum_size);
+				memset(t, 0, csum_size);
+				ext2fs_set_rec_len(fs, csum_size,
+						   (struct ext2_dir_entry *)t);
+			}
 			if ((retval = get_next_block(fs, outdir,
 						      &block_start)))
 				return retval;
 			offset = 0;
 		}
-		left = fs->blocksize - offset;
+		left = (fs->blocksize - csum_size) - offset;
 		dirent = (struct ext2_dir_entry *) (block_start + offset);
 		if (offset == 0) {
 			if (ent->hash == prev_hash)
@@ -482,6 +501,12 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
 	}
 	if (left)
 		retval = ext2fs_set_rec_len(fs, rec_len + left, dirent);
+	if (csum_size) {
+		t = (struct ext2_dir_entry_tail *)
+				(block_start + fs->blocksize - csum_size);
+		memset(t, 0, csum_size);
+		ext2fs_set_rec_len(fs, csum_size, (struct ext2_dir_entry *)t);
+	}
 
 	return retval;
 }
@@ -602,8 +627,6 @@ static errcode_t calculate_tree(ext2_filsys fs,
 				if (limit) {
 					limit->limit = limit->count =
 		ext2fs_cpu_to_le16(limit->limit);
-					ext2fs_dx_csum_set(fs, ino,
-		(struct ext2_dir_entry *)(((void *)limit) - 8));
 				}
 				root = (struct ext2_dx_entry *)
 					(outdir->buf + root_offset);
@@ -629,14 +652,10 @@ static errcode_t calculate_tree(ext2_filsys fs,
 		}
 		limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
 		limit->limit = ext2fs_cpu_to_le16(limit->limit);
-		ext2fs_dx_csum_set(fs, ino,
-				   (struct ext2_dir_entry *)(((void *)limit) -
-							     8));
 	}
 	root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
 	root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
 	root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
-	ext2fs_dx_csum_set(fs, ino, (struct ext2_dir_entry *)outdir->buf);
 
 	return 0;
 }
@@ -646,6 +665,7 @@ struct write_dir_struct {
 	errcode_t	err;
 	e2fsck_t	ctx;
 	int		cleared;
+	ext2_ino_t	dir;
 };
 
 /*
@@ -677,7 +697,7 @@ static int write_dir_block(ext2_filsys fs,
 		return 0;
 
 	dir = wd->outdir->buf + (blockcnt * fs->blocksize);
-	wd->err = ext2fs_write_dir_block3(fs, *block_nr, dir, 0);
+	wd->err = ext2fs_write_dir_block3(fs, *block_nr, dir, 0, wd->dir);
 	if (wd->err)
 		return BLOCK_ABORT;
 	return 0;
@@ -699,6 +719,7 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
 	wd.err = 0;
 	wd.ctx = ctx;
 	wd.cleared = 0;
+	wd.dir = ino;
 
 	retval = ext2fs_block_iterate3(fs, ino, 0, 0,
 				       write_dir_block, &wd);
@@ -751,6 +772,7 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
 	fd.err = 0;
 	fd.dir_size = 0;
 	fd.compress = 0;
+	fd.dir = ino;
 	if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
 	    (inode.i_size / fs->blocksize) < 2)
 		fd.compress = 1;
@@ -810,7 +832,7 @@ resort:
 	 * Copy the directory entries.  In a htree directory these
 	 * will become the leaf nodes.
 	 */
-	retval = copy_dir_entries(ctx, &fd, &outdir);
+	retval = copy_dir_entries(ctx, &fd, &outdir, ino);
 	if (retval)
 		goto errout;
 
diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index 4963524..a606b7c 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -29,6 +29,126 @@
 #define STATIC static
 #endif
 
+static struct ext2_dir_entry_tail *get_dirent_tail(ext2_filsys fs,
+						struct ext2_dir_entry *dirent)
+{
+	struct ext2_dir_entry *d, *top;
+	struct ext2_dir_entry_tail *t;
+	unsigned int rec_len;
+	errcode_t retval;
+
+	d = dirent;
+	top = (struct ext2_dir_entry *)
+			(((void *)dirent) +
+			 (fs->blocksize - sizeof(struct ext2_dir_entry_tail)));
+
+	retval = ext2fs_get_rec_len(fs, d, &rec_len);
+	while (d < top && !retval && rec_len) {
+		d = (struct ext2_dir_entry *)(((void *)d) + rec_len);
+		retval = ext2fs_get_rec_len(fs, d, &rec_len);
+	}
+
+	if (d != top)
+		return NULL;
+
+	t = (struct ext2_dir_entry_tail *)d;
+	if (t->reserved_zero1 ||
+	    t->rec_len != sizeof(struct ext2_dir_entry_tail) ||
+	    t->reserved_zero2)
+		return NULL;
+
+	return t;
+}
+
+int ext2fs_dirent_has_tail(ext2_filsys fs, struct ext2_dir_entry *dirent)
+{
+	return get_dirent_tail(fs, dirent) != NULL;
+}
+
+__u32 ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum,
+			 struct ext2_dir_entry *dirent)
+{
+	errcode_t retval;
+	char *buf = (char *)dirent;
+	struct ext2_dir_entry_tail *t;
+	int size;
+	__u32 crc = 0;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return 0;
+
+	t = get_dirent_tail(fs, dirent);
+	if (!t)
+		return 0;
+
+#ifdef WORDS_BIGENDIAN
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return 0;
+	memcpy(buf, dirent, fs->blocksize);
+	retval = ext2fs_dirent_swab_out(fs, buf, 0);
+	if (retval) {
+		crc = 0;
+		goto out;
+	}
+#endif
+
+	size = (void *)t - (void *)dirent;
+	inum = ext2fs_cpu_to_le32(inum);
+	crc = crc32c_le(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid));
+	crc = crc32c_le(crc, (char *)&inum, sizeof(inum));
+	crc = crc32c_le(crc, buf, size);
+
+#ifdef WORDS_BIGENDIAN
+out:
+	ext2fs_free_mem(&buf);
+#endif
+
+	return crc;
+}
+
+int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+			      struct ext2_dir_entry *dirent)
+{
+	struct ext2_dir_entry_tail *t;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return 1;
+
+	t = get_dirent_tail(fs, dirent);
+	if (!t)
+		return 1;
+
+	/*
+	 * The checksum field is overlaid with the dirent->name field
+	 * so the swapfs.c functions won't change the endianness.
+	 */
+	if (ext2fs_le32_to_cpu(t->checksum) !=
+	    ext2fs_dirent_csum(fs, inum, dirent))
+		return 0;
+
+	return 1;
+}
+
+void ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum,
+			    struct ext2_dir_entry *dirent)
+{
+	struct ext2_dir_entry_tail *t;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return;
+
+	t = get_dirent_tail(fs, dirent);
+	if (!t)
+		return;
+
+	/* swapfs.c functions don't change the checksum endianness */
+	t->checksum = ext2fs_cpu_to_le32(ext2fs_dirent_csum(fs, inum, dirent));
+}
+
 __u32 ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
 		     struct ext2_dir_entry *dirent)
 {
@@ -136,6 +256,45 @@ void ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum,
 	t->checksum = ext2fs_cpu_to_le32(ext2fs_dx_csum(fs, inum, dirent));
 }
 
+int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+				 struct ext2_dir_entry *dirent)
+{
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return 1;
+
+	if (get_dirent_tail(fs, dirent))
+		return ext2fs_dirent_csum_verify(fs, inum, dirent);
+	if (ext2fs_get_dx_countlimit(fs, dirent, NULL))
+		return ext2fs_dx_csum_verify(fs, inum, dirent);
+
+	printf("%s: Not htree or leaf dir block?\n", __func__);
+	abort();
+}
+
+void ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
+			       struct ext2_dir_entry *dirent)
+{
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return;
+
+	if (get_dirent_tail(fs, dirent)) {
+		ext2fs_dirent_csum_set(fs, inum, dirent);
+		return;
+	}
+
+	if (ext2fs_get_dx_countlimit(fs, dirent, NULL)) {
+		ext2fs_dx_csum_set(fs, inum, dirent);
+		return;
+	}
+
+	if (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)
+		return;
+	printf("%s: Not htree or leaf dir block?\n", __func__);
+	abort();
+}
+
 #define EXT3_EXTENT_TAIL_OFFSET(hdr)	(sizeof(struct ext3_extent_header) + \
 	(sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max)))
 
diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c
index 88f6b47..b5a27e2 100644
--- a/lib/ext2fs/dir_iterate.c
+++ b/lib/ext2fs/dir_iterate.c
@@ -191,17 +191,23 @@ int ext2fs_process_dir_block(ext2_filsys fs,
 	unsigned int	rec_len, size;
 	int		entry;
 	struct ext2_dir_entry *dirent;
+	int		csum_size = 0;
 
 	if (blockcnt < 0)
 		return 0;
 
 	entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
 
-	ctx->errcode = ext2fs_read_dir_block3(fs, *blocknr, ctx->buf, 0);
+	ctx->errcode = ext2fs_read_dir_block3(fs, *blocknr, ctx->buf, 0,
+					      ctx->dir);
 	if (ctx->errcode)
 		return BLOCK_ABORT;
 
-	while (offset < fs->blocksize) {
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		csum_size = sizeof(struct ext2_dir_entry_tail);
+
+	while (offset < (fs->blocksize - csum_size)) {
 		dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
 		if (ext2fs_get_rec_len(fs, dirent, &rec_len))
 			return BLOCK_ABORT;
@@ -259,7 +265,7 @@ next:
 
 	if (changed) {
 		ctx->errcode = ext2fs_write_dir_block3(fs, *blocknr, ctx->buf,
-						       0);
+						       0, ctx->dir);
 		if (ctx->errcode)
 			return BLOCK_ABORT;
 	}
diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c
index 73e1f0a..bc7959f 100644
--- a/lib/ext2fs/dirblock.c
+++ b/lib/ext2fs/dirblock.c
@@ -20,107 +20,75 @@
 #include "ext2fs.h"
 
 errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
-				 void *buf, int flags EXT2FS_ATTR((unused)))
+				 void *buf, int flags EXT2FS_ATTR((unused)),
+				 ext2_ino_t ino)
 {
 	errcode_t	retval;
-	char		*p, *end;
-	struct ext2_dir_entry *dirent;
-	unsigned int	name_len, rec_len;
-
 
 	retval = io_channel_read_blk64(fs->io, block, 1, buf);
 	if (retval)
 		return retval;
-
-	p = (char *) buf;
-	end = (char *) buf + fs->blocksize;
-	while (p < end-8) {
-		dirent = (struct ext2_dir_entry *) p;
-#ifdef WORDS_BIGENDIAN
-		dirent->inode = ext2fs_swab32(dirent->inode);
-		dirent->rec_len = ext2fs_swab16(dirent->rec_len);
-		dirent->name_len = ext2fs_swab16(dirent->name_len);
-#endif
-		name_len = dirent->name_len;
 #ifdef WORDS_BIGENDIAN
-		if (flags & EXT2_DIRBLOCK_V2_STRUCT)
-			dirent->name_len = ext2fs_swab16(dirent->name_len);
+	retval = ext2fs_dirent_swab_in(fs, buf, flags);
+	if (retval)
+		return retval;
 #endif
-		if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
-			return retval;
-		if ((rec_len < 8) || (rec_len % 4)) {
-			rec_len = 8;
-			retval = EXT2_ET_DIR_CORRUPTED;
-		} else if (((name_len & 0xFF) + 8) > rec_len)
-			retval = EXT2_ET_DIR_CORRUPTED;
-		p += rec_len;
-	}
+
+	if (!fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS &&
+	    !ext2fs_dir_block_csum_verify(fs, ino,
+					  (struct ext2_dir_entry *)buf))
+		return EXT2_ET_DIR_CORRUPTED;
 	return retval;
 }
 
 errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
-				 void *buf, int flags EXT2FS_ATTR((unused)))
+				 void *buf, int flags EXT2FS_ATTR((unused)),
+				 ext2_ino_t ino)
 {
-	return ext2fs_read_dir_block3(fs, block, buf, flags);
+	return ext2fs_read_dir_block3(fs, block, buf, flags, ino);
 }
 
 errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
-				 void *buf)
+				 void *buf, ext2_ino_t ino)
 {
-	return ext2fs_read_dir_block3(fs, block, buf, 0);
+	return ext2fs_read_dir_block3(fs, block, buf, 0, ino);
 }
 
 
 errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
-				  void *inbuf, int flags EXT2FS_ATTR((unused)))
+				  void *inbuf, int flags EXT2FS_ATTR((unused)),
+				  ext2_ino_t ino)
 {
-#ifdef WORDS_BIGENDIAN
 	errcode_t	retval;
-	char		*p, *end;
-	char		*buf = 0;
-	unsigned int	rec_len;
-	struct ext2_dir_entry *dirent;
+	char		*buf = inbuf;
 
+	ext2fs_dir_block_csum_set(fs, ino, (struct ext2_dir_entry *)inbuf);
+#ifdef WORDS_BIGENDIAN
 	retval = ext2fs_get_mem(fs->blocksize, &buf);
 	if (retval)
 		return retval;
 	memcpy(buf, inbuf, fs->blocksize);
-	p = buf;
-	end = buf + fs->blocksize;
-	while (p < end) {
-		dirent = (struct ext2_dir_entry *) p;
-		if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
-			return retval;
-		if ((rec_len < 8) ||
-		    (rec_len % 4)) {
-			ext2fs_free_mem(&buf);
-			return (EXT2_ET_DIR_CORRUPTED);
-		}
-		p += rec_len;
-		dirent->inode = ext2fs_swab32(dirent->inode);
-		dirent->rec_len = ext2fs_swab16(dirent->rec_len);
-		dirent->name_len = ext2fs_swab16(dirent->name_len);
-
-		if (flags & EXT2_DIRBLOCK_V2_STRUCT)
-			dirent->name_len = ext2fs_swab16(dirent->name_len);
-	}
+	retval = ext2fs_dirent_swab_out(fs, buf, flags);
+	if (retval)
+		return retval;
+#endif
 	retval = io_channel_write_blk64(fs->io, block, 1, buf);
+#ifdef WORDS_BIGENDIAN
 	ext2fs_free_mem(&buf);
-	return retval;
-#else
-	return io_channel_write_blk64(fs->io, block, 1, (char *) inbuf);
 #endif
+	return retval;
 }
 
 errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
-				 void *inbuf, int flags EXT2FS_ATTR((unused)))
+				 void *inbuf, int flags EXT2FS_ATTR((unused)),
+				 ext2_ino_t ino)
 {
-	return ext2fs_write_dir_block3(fs, block, inbuf, flags);
+	return ext2fs_write_dir_block3(fs, block, inbuf, flags, ino);
 }
 
 errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
-				 void *inbuf)
+				 void *inbuf, ext2_ino_t ino)
 {
-	return ext2fs_write_dir_block3(fs, block, inbuf, 0);
+	return ext2fs_write_dir_block3(fs, block, inbuf, 0, ino);
 }
 
diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
index ee90970..e7e6e05 100644
--- a/lib/ext2fs/expanddir.c
+++ b/lib/ext2fs/expanddir.c
@@ -23,6 +23,7 @@ struct expand_dir_struct {
 	int		newblocks;
 	blk64_t		goal;
 	errcode_t	err;
+	ext2_ino_t	dir;
 };
 
 static int expand_dir_proc(ext2_filsys	fs,
@@ -61,7 +62,7 @@ static int expand_dir_proc(ext2_filsys	fs,
 			return BLOCK_ABORT;
 		}
 		es->done = 1;
-		retval = ext2fs_write_dir_block(fs, new_blk, block);
+		retval = ext2fs_write_dir_block(fs, new_blk, block, es->dir);
 	} else {
 		retval = ext2fs_get_mem(fs->blocksize, &block);
 		if (retval) {
@@ -109,6 +110,7 @@ errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
 	es.err = 0;
 	es.goal = 0;
 	es.newblocks = 0;
+	es.dir = dir;
 
 	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
 				       0, expand_dir_proc, &es);
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 64adff9..1c27249 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -716,6 +716,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	reserved_zero1;		/* Pretend to be unused */
+	__u16	rec_len;
+	__u16	reserved_zero2;		/* Zero name length */
+	__u32	checksum;		/* crc32c(uuid+inode+dirent) */
+};
+
+/*
  * Ext2 directory file types.  Only the low 3 bits are used.  The
  * other bits are reserved for now.
  */
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 7110f72..706357a 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -894,6 +894,18 @@ extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len);
 extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
 
 /* csum.c */
+extern int ext2fs_dirent_has_tail(ext2_filsys fs,
+				  struct ext2_dir_entry *dirent);
+extern int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+				     struct ext2_dir_entry *dirent);
+extern void ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
+				   struct ext2_dir_entry *dirent);
+extern __u32 ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum,
+				struct ext2_dir_entry *dirent);
+extern int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+				     struct ext2_dir_entry *dirent);
+extern void ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum,
+				   struct ext2_dir_entry *dirent);
 extern __u32 ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
 			    struct ext2_dir_entry *dirent);
 extern int ext2fs_dx_csum_verify(ext2_filsys fs, ext2_ino_t inum,
@@ -976,17 +988,17 @@ extern errcode_t
 
 /* dirblock.c */
 extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
-				       void *buf);
+				       void *buf, ext2_ino_t ino);
 extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
-					void *buf, int flags);
+					void *buf, int flags, ext2_ino_t ino);
 extern errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
-					void *buf, int flags);
+					void *buf, int flags, ext2_ino_t ino);
 extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
-					void *buf);
+					void *buf, ext2_ino_t ino);
 extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
-					 void *buf, int flags);
+					 void *buf, int flags, ext2_ino_t ino);
 extern errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
-					 void *buf, int flags);
+					 void *buf, int flags, ext2_ino_t ino);
 
 /* dirhash.c */
 extern struct ext2_dx_countlimit *ext2fs_get_dx_countlimit(ext2_filsys fs,
@@ -1368,6 +1380,8 @@ extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f,
 extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
 
 /* swapfs.c */
+extern errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags);
+extern errcode_t ext2fs_dirent_swab_out(ext2_filsys fs, char *buf, int flags);
 extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize,
 				 int has_header);
 extern void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header,
diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
index a32ec03..c4d66b0 100644
--- a/lib/ext2fs/link.c
+++ b/lib/ext2fs/link.c
@@ -40,6 +40,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
 	struct ext2_dir_entry *next;
 	unsigned int rec_len, min_rec_len, curr_rec_len;
 	int ret = 0;
+	int csum_size = 0;
 
 	rec_len = EXT2_DIR_REC_LEN(ls->namelen);
 
@@ -47,12 +48,15 @@ static int link_proc(struct ext2_dir_entry *dirent,
 	if (ls->err)
 		return DIRENT_ABORT;
 
+	if (EXT2_HAS_RO_COMPAT_FEATURE(ls->fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		csum_size = sizeof(struct ext2_dir_entry_tail);
 	/*
 	 * See if the following directory entry (if any) is unused;
 	 * if so, absorb it into this one.
 	 */
 	next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len);
-	if ((offset + (int) curr_rec_len < blocksize - 8) &&
+	if ((offset + (int) curr_rec_len < blocksize - (8 + csum_size)) &&
 	    (next->inode == 0) &&
 	    (offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) {
 		curr_rec_len += next->rec_len;
diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
index 08a0bd6..5fa6274 100644
--- a/lib/ext2fs/mkdir.c
+++ b/lib/ext2fs/mkdir.c
@@ -94,7 +94,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 	/*
 	 * Write out the inode and inode data block
 	 */
-	retval = ext2fs_write_dir_block(fs, blk, block);
+	retval = ext2fs_write_dir_block(fs, blk, block, ino);
 	if (retval)
 		goto cleanup;
 	retval = ext2fs_write_new_inode(fs, ino, &inode);
diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c
index 6bc5719..d1ccf9a 100644
--- a/lib/ext2fs/newdir.c
+++ b/lib/ext2fs/newdir.c
@@ -33,6 +33,8 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
 	char			*buf;
 	int			rec_len;
 	int			filetype = 0;
+	struct ext2_dir_entry_tail	*t;
+	int			csum_size = 0;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -42,7 +44,11 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
 	memset(buf, 0, fs->blocksize);
 	dir = (struct ext2_dir_entry *) buf;
 
-	retval = ext2fs_set_rec_len(fs, fs->blocksize, dir);
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		csum_size = sizeof(struct ext2_dir_entry_tail);
+
+	retval = ext2fs_set_rec_len(fs, fs->blocksize - csum_size, dir);
 	if (retval)
 		return retval;
 
@@ -56,7 +62,7 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
 		dir->inode = dir_ino;
 		dir->name_len = 1 | filetype;
 		dir->name[0] = '.';
-		rec_len = fs->blocksize - EXT2_DIR_REC_LEN(1);
+		rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
 		dir->rec_len = EXT2_DIR_REC_LEN(1);
 
 		/*
@@ -72,6 +78,13 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
 		dir->name[1] = '.';
 
 	}
+
+	if (csum_size) {
+		t = (struct ext2_dir_entry_tail *)
+				(buf + fs->blocksize - csum_size);
+		memset(t, 0, csum_size);
+		ext2fs_set_rec_len(fs, csum_size, (struct ext2_dir_entry *)t);
+	}
 	*block = buf;
 	return 0;
 }
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index f657c47..570ab7d 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -320,4 +320,66 @@ void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode_large *t,
 				sizeof(struct ext2_inode_large));
 }
 
+errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags)
+{
+	errcode_t	retval;
+	char		*p, *end;
+	struct ext2_dir_entry *dirent;
+	unsigned int	name_len, rec_len;
+
+	p = (char *) buf;
+	end = (char *) buf + fs->blocksize;
+	while (p < end-8) {
+		dirent = (struct ext2_dir_entry *) p;
+		dirent->inode = ext2fs_swab32(dirent->inode);
+		dirent->rec_len = ext2fs_swab16(dirent->rec_len);
+		dirent->name_len = ext2fs_swab16(dirent->name_len);
+		name_len = dirent->name_len;
+		if (flags & EXT2_DIRBLOCK_V2_STRUCT)
+			dirent->name_len = ext2fs_swab16(dirent->name_len);
+		retval = ext2fs_get_rec_len(fs, dirent, &rec_len);
+		if (retval)
+			return retval;
+		if ((rec_len < 8) || (rec_len % 4)) {
+			rec_len = 8;
+			retval = EXT2_ET_DIR_CORRUPTED;
+		} else if (((name_len & 0xFF) + 8) > rec_len)
+			retval = EXT2_ET_DIR_CORRUPTED;
+		p += rec_len;
+	}
+
+	return 0;
+}
+
+errcode_t ext2fs_dirent_swab_out(ext2_filsys fs, char *buf, int flags)
+{
+	errcode_t	retval;
+	char		*p, *end;
+	unsigned int	rec_len;
+	struct ext2_dir_entry *dirent;
+
+	p = buf;
+	end = buf + fs->blocksize;
+	while (p < end) {
+		dirent = (struct ext2_dir_entry *) p;
+		retval = ext2fs_get_rec_len(fs, dirent, &rec_len);
+		if (retval)
+			return retval;
+		if ((rec_len < 8) ||
+		    (rec_len % 4)) {
+			ext2fs_free_mem(&buf);
+			return EXT2_ET_DIR_CORRUPTED;
+		}
+		p += rec_len;
+		dirent->inode = ext2fs_swab32(dirent->inode);
+		dirent->rec_len = ext2fs_swab16(dirent->rec_len);
+		dirent->name_len = ext2fs_swab16(dirent->name_len);
+
+		if (flags & EXT2_DIRBLOCK_V2_STRUCT)
+			dirent->name_len = ext2fs_swab16(dirent->name_len);
+	}
+
+	return 0;
+}
+
 #endif


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

* [PATCH 27/37] e2fsck: Check directory leaf block checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (25 preceding siblings ...)
  2011-09-01  0:37 ` [PATCH 26/37] libext2fs: Introduce dir_entry_tail to provide checksums for directory leaf nodes Darrick J. Wong
@ 2011-09-01  0:38 ` Darrick J. Wong
  2011-09-01  0:38 ` [PATCH 28/37] tune2fs: Rebuild and checksum directories when toggling metadata_csum or changing UUID Darrick J. Wong
                   ` (8 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:38 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Checks that directory leaf blocks have the necessary fake dir_entry at the end
of the block to hold a checksum and that the checksum is valid.  It will resize
the block and/or rebuild the directory if necessary.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 e2fsck/e2fsck.h  |    1 +
 e2fsck/pass2.c   |   76 ++++++++++++++++++++++++++++++++++++++++++++++++------
 e2fsck/pass3.c   |    4 +++
 e2fsck/problem.c |   10 +++++++
 e2fsck/problem.h |    6 ++++
 e2fsck/rehash.c  |   12 +++++++++
 6 files changed, 101 insertions(+), 8 deletions(-)


diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index d515a9d..2a7a80e 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -473,6 +473,7 @@ extern void region_free(region_t region);
 extern int region_allocate(region_t region, region_addr_t start, int n);
 
 /* rehash.c */
+int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino);
 errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino);
 void e2fsck_rehash_directories(e2fsck_t ctx);
 
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 93a09d1..4563c9c 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -748,7 +748,8 @@ static int check_dir_block(ext2_filsys fs,
 	struct problem_context	pctx;
 	int	dups_found = 0;
 	int	ret;
-	int	csum_size = 0;
+	int	dx_csum_size = 0, de_csum_size = 0;
+	int	is_leaf = 1;
 
 	cd = (struct check_dir_struct *) priv_data;
 	buf = cd->buf;
@@ -761,8 +762,10 @@ static int check_dir_block(ext2_filsys fs,
 		return DIRENT_ABORT;
 
 	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
-		csum_size = sizeof(struct ext2_dx_tail);
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+		dx_csum_size = sizeof(struct ext2_dx_tail);
+		de_csum_size = sizeof(struct ext2_dir_entry_tail);
+	}
 
 	/*
 	 * Make sure the inode is still in use (could have been
@@ -806,11 +809,15 @@ static int check_dir_block(ext2_filsys fs,
 	if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
 		cd->pctx.errcode = 0; /* We'll handle this ourselves */
 	if (cd->pctx.errcode) {
+		char *buf2;
 		if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
 			ctx->flags |= E2F_FLAG_ABORT;
 			return DIRENT_ABORT;
 		}
-		memset(buf, 0, fs->blocksize);
+		ext2fs_new_dir_block(fs, db->blockcnt == 0 ? ino : 0,
+				     EXT2_ROOT_INO, &buf2);
+		memcpy(buf, buf2, fs->blocksize);
+		ext2fs_free_mem(&buf2);
 	}
 #ifdef ENABLE_HTREE
 	dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
@@ -855,13 +862,49 @@ static int check_dir_block(ext2_filsys fs,
 			   (rec_len == fs->blocksize) &&
 			   (dirent->name_len == 0) &&
 			   (ext2fs_le16_to_cpu(limit->limit) ==
-			    ((fs->blocksize - (8 + csum_size)) /
+			    ((fs->blocksize - (8 + dx_csum_size)) /
 			     sizeof(struct ext2_dx_entry))))
 			dx_db->type = DX_DIRBLOCK_NODE;
+		is_leaf = 0;
 	}
 out_htree:
 #endif /* ENABLE_HTREE */
 
+	/* Verify checksum. */
+	if (is_leaf && de_csum_size) {
+		/* No space for csum?  Rebuild dirs in pass 3A. */
+		if (!ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
+			de_csum_size = 0;
+			if (e2fsck_dir_will_be_rehashed(ctx, ino))
+				goto skip_checksum;
+			if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_MISSING_CSUM,
+					 &cd->pctx))
+				goto skip_checksum;
+			if (!ctx->dirs_to_hash)
+				ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
+			if (ctx->dirs_to_hash)
+				ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+			goto skip_checksum;
+		}
+		if (!ext2fs_dirent_csum_verify(fs, ino,
+					       (struct ext2_dir_entry *)buf)) {
+			char *buf2;
+			if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_CSUM_INVALID,
+					 &cd->pctx))
+				goto skip_checksum;
+			ext2fs_new_dir_block(fs,
+					     db->blockcnt == 0 ? ino : 0,
+					     EXT2_ROOT_INO, &buf2);
+			memcpy(buf, buf2, fs->blocksize);
+			ext2fs_free_mem(&buf2);
+			dir_modified++;
+		}
+	}
+	/* htree nodes don't use fake dirents to store checksums */
+	if (!is_leaf)
+		de_csum_size = 0;
+
+skip_checksum:
 	dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
 	prev = 0;
 	do {
@@ -1134,7 +1177,7 @@ out_htree:
 			(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
 		offset += rec_len;
 		dot_state++;
-	} while (offset < fs->blocksize);
+	} while (offset < fs->blocksize - de_csum_size);
 #if 0
 	printf("\n");
 #endif
@@ -1151,16 +1194,33 @@ out_htree:
 			parse_int_node(fs, db, cd, dx_dir, buf);
 	}
 #endif /* ENABLE_HTREE */
-	if (offset != fs->blocksize) {
-		cd->pctx.num = rec_len - fs->blocksize + offset;
+
+	if (offset != fs->blocksize - de_csum_size) {
+		cd->pctx.num = rec_len - (fs->blocksize - de_csum_size) +
+			       offset;
 		if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
 			dirent->rec_len = cd->pctx.num;
 			dir_modified++;
 		}
 	}
 	if (dir_modified) {
+		/* leaf block with no tail?  Rehash dirs later. */
+		if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+		    is_leaf &&
+		    !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
+			if (!ctx->dirs_to_hash)
+				ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
+			if (ctx->dirs_to_hash)
+				ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+		}
+
+		if (e2fsck_dir_will_be_rehashed(ctx, ino))
+			ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
 		cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf,
 							  ino);
+		if (e2fsck_dir_will_be_rehashed(ctx, ino))
+			ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 		if (cd->pctx.errcode) {
 			if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
 					 &cd->pctx))
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index 2360aff..ada6646 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -654,8 +654,12 @@ static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
 
 	clear_problem_context(&pctx);
 	pctx.ino = ino;
+	if (e2fsck_dir_will_be_rehashed(ctx, ino))
+		ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
 	retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY,
 				    0, fix_dotdot_proc, &fp);
+	if (e2fsck_dir_will_be_rehashed(ctx, ino))
+		ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 	if (retval || !fp.done) {
 		pctx.errcode = retval;
 		fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 637b254..835f0ff 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1353,6 +1353,16 @@ static struct e2fsck_problem problem_table[] = {
 	  N_("@p @h %d: node fails checksum\n"),
 	  PROMPT_CLEAR_HTREE, PR_PREEN_OK },
 
+	/* leaf node fails checksum */
+	{ PR_2_LEAF_NODE_CSUM_INVALID,
+	  N_("@d @i %i, %B, offset %N: @d fails checksum\n"),
+	  PROMPT_SALVAGE, 0 },
+
+	/* leaf node fails checksum */
+	{ PR_2_LEAF_NODE_MISSING_CSUM,
+	  N_("@d @i %i, %B, offset %N: @d has no checksum\n"),
+	  PROMPT_FIX, PR_PREEN_OK },
+
 	/* Pass 3 errors */
 
 	/* Pass 3: Checking directory connectivity */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index d4e596f..df29057 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -809,6 +809,12 @@ struct problem_context {
 /* htree node fails checksum */
 #define PR_2_HTREE_NODE_CSUM_INVALID	0x02004A
 
+/* dir leaf node fails checksum */
+#define PR_2_LEAF_NODE_CSUM_INVALID	0x02004B
+
+/* no space in leaf for checksum */
+#define PR_2_LEAF_NODE_MISSING_CSUM	0x02004C
+
 /*
  * Pass 3 errors
  */
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 25cc8b8..ae6d406 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -51,6 +51,15 @@
 #include "e2fsck.h"
 #include "problem.h"
 
+int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino)
+{
+	if (ctx->options & E2F_OPT_COMPRESS_DIRS)
+		return 1;
+	if (!ctx->dirs_to_hash)
+		return 0;
+	return ext2fs_u32_list_test(ctx->dirs_to_hash, ino);
+}
+
 struct fill_dir_struct {
 	char *buf;
 	struct ext2_inode_large *inode;
@@ -905,8 +914,11 @@ void e2fsck_rehash_directories(e2fsck_t ctx)
 			if (!ext2fs_u32_list_iterate(iter, &ino))
 				break;
 		}
+#if 0
+		/* Why is lost_and_found never cleaned up or hashed? */
 		if (ino == ctx->lost_and_found)
 			continue;
+#endif
 		pctx.dir = ino;
 		if (first) {
 			fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);


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

* [PATCH 28/37] tune2fs: Rebuild and checksum directories when toggling metadata_csum or changing UUID
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (26 preceding siblings ...)
  2011-09-01  0:38 ` [PATCH 27/37] e2fsck: Check directory leaf block checksums Darrick J. Wong
@ 2011-09-01  0:38 ` Darrick J. Wong
  2011-09-01  0:38 ` [PATCH 29/37] libext2fs: Verify and calculate extended attribute block checksums Darrick J. Wong
                   ` (7 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:38 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Since all the metadata checksums depend on the fs UUID, tune2fs must be able to
rewrite the checksums of _all_ metadata.  It's not that hard to add in the bits
to resize the directory block structures at the same time.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 misc/tune2fs.c |  198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 197 insertions(+), 1 deletions(-)


diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 0c0a911..ba5b9d2 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -97,6 +97,8 @@ struct blk_move {
 
 
 static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
+static const char *please_dir_fsck =
+		N_("Please run e2fsck -D on the filesystem.\n");
 
 #ifdef CONFIG_BUILD_FINDFS
 void do_findfs(int argc, char **argv);
@@ -343,6 +345,18 @@ static int check_fsck_needed(ext2_filsys fs)
 	return 1;
 }
 
+static void request_dir_fsck_afterwards(ext2_filsys fs)
+{
+	static int requested;
+
+	if (requested++)
+		return;
+	fs->super->s_state &= ~EXT2_VALID_FS;
+	printf("\n%s\n", _(please_dir_fsck));
+	if (mount_flags & EXT2_MF_READONLY)
+		printf(_("(and reboot afterwards!)\n"));
+}
+
 static void request_fsck_afterwards(ext2_filsys fs)
 {
 	static int requested = 0;
@@ -399,6 +413,177 @@ static errcode_t rewrite_extents(ext2_filsys fs, ext2_ino_t ino,
 }
 
 /*
+ * Rewrite directory blocks with checksums
+ */
+struct rewrite_dir_context {
+	char *buf;
+	errcode_t errcode;
+	ext2_ino_t dir;
+	int is_htree;
+};
+
+static int rewrite_dir_block(ext2_filsys fs,
+			     blk64_t	*blocknr,
+			     e2_blkcnt_t blockcnt,
+			     blk64_t	ref_block EXT2FS_ATTR((unused)),
+			     int	ref_offset EXT2FS_ATTR((unused)),
+			     void	*priv_data)
+{
+	struct ext2_dx_countlimit *dcl = NULL;
+	struct rewrite_dir_context *ctx = priv_data;
+	int dcl_offset, changed = 0;
+
+	ctx->errcode = ext2fs_read_dir_block3(fs, *blocknr, ctx->buf, 0,
+					      ctx->dir);
+	if (ctx->errcode)
+		return BLOCK_ABORT;
+
+	/* if htree node... */
+	if (ctx->is_htree)
+		dcl = ext2fs_get_dx_countlimit(fs,
+				(struct ext2_dir_entry *)ctx->buf, &dcl_offset);
+	if (dcl) {
+		if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+			/* Ensure limit is the max size */
+			int max_entries = (fs->blocksize - dcl_offset) /
+					  sizeof(struct ext2_dx_entry);
+			if (ext2fs_le16_to_cpu(dcl->limit) != max_entries) {
+				changed = 1;
+				dcl->limit = ext2fs_cpu_to_le16(max_entries);
+			}
+		} else {
+			/* If htree block is full then rebuild the dir */
+			if (ext2fs_le16_to_cpu(dcl->count) ==
+			    ext2fs_le16_to_cpu(dcl->limit)) {
+				request_dir_fsck_afterwards(fs);
+				return 0;
+			}
+			/*
+			 * Ensure dcl->limit is small enough to leave room for
+			 * the checksum tail.
+			 */
+			int max_entries = (fs->blocksize - (dcl_offset +
+						sizeof(struct ext2_dx_tail))) /
+					  sizeof(struct ext2_dx_entry);
+			if (ext2fs_le16_to_cpu(dcl->limit) != max_entries)
+				dcl->limit = ext2fs_cpu_to_le16(max_entries);
+			/* Always rewrite checksum */
+			changed = 1;
+		}
+	} else {
+		int rec_len, name_size;
+		char *top = ctx->buf + fs->blocksize;
+		struct ext2_dir_entry *de = (struct ext2_dir_entry *)ctx->buf;
+		struct ext2_dir_entry *last_de = NULL, *penultimate_de = NULL;
+
+		/* Find last and penultimate dirent */
+		while ((char *)de < top) {
+			penultimate_de = last_de;
+			last_de = de;
+			ctx->errcode = ext2fs_get_rec_len(fs, de, &rec_len);
+			if (!ctx->errcode && !rec_len)
+				ctx->errcode = EXT2_ET_DIR_CORRUPTED;
+			if (ctx->errcode)
+				return BLOCK_ABORT;
+			de = (struct ext2_dir_entry *)(((void *)de) + rec_len);
+		}
+		ctx->errcode = ext2fs_get_rec_len(fs, last_de, &rec_len);
+		if (ctx->errcode)
+			return BLOCK_ABORT;
+		name_size = last_de->name_len & 0xFF;
+
+		if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+			if (!penultimate_de)
+				return 0;
+			if (last_de->inode ||
+			    name_size ||
+			    rec_len != sizeof(struct ext2_dir_entry_tail))
+				return 0;
+			/*
+			 * The last dirent is unused and the right length to
+			 * have stored a checksum.  Erase it.
+			 */
+			ctx->errcode = ext2fs_get_rec_len(fs, penultimate_de,
+							  &rec_len);
+			if (!rec_len)
+				ctx->errcode = EXT2_ET_DIR_CORRUPTED;
+			if (ctx->errcode)
+				return BLOCK_ABORT;
+			ext2fs_set_rec_len(fs, rec_len +
+					sizeof(struct ext2_dir_entry_tail),
+					penultimate_de);
+			changed = 1;
+		} else {
+			int csum_size = sizeof(struct ext2_dir_entry_tail);
+			struct ext2_dir_entry_tail *t;
+
+			/*
+			 * If the last dirent looks like the tail, just update
+			 * the checksum.
+			 */
+			if (!last_de->inode && !name_size &&
+			    rec_len == csum_size) {
+				changed = 1;
+				goto out;
+			}
+			if (name_size & 3)
+				name_size = (name_size & ~3) + 4;
+			/* If there's not enough space for the tail, e2fsck */
+			if (rec_len <= (8 + name_size + csum_size)) {
+				request_dir_fsck_afterwards(fs);
+				return 0;
+			}
+			/* Shorten that last de and insert the tail */
+			ext2fs_set_rec_len(fs, rec_len - csum_size, last_de);
+			t = (struct ext2_dir_entry_tail *)
+					(ctx->buf + fs->blocksize - csum_size);
+			bzero(t, csum_size);
+			ext2fs_set_rec_len(fs, csum_size,
+					   (struct ext2_dir_entry *)t);
+
+			/* Always update checksum */
+			changed = 1;
+		}
+	}
+
+out:
+	if (!changed)
+		return 0;
+
+	ctx->errcode = ext2fs_write_dir_block3(fs, *blocknr, ctx->buf,
+					       0, ctx->dir);
+	if (ctx->errcode)
+		return BLOCK_ABORT;
+
+	return 0;
+}
+
+errcode_t rewrite_directory(ext2_filsys fs, ext2_ino_t dir,
+			    struct ext2_inode_large *inode)
+{
+	errcode_t	retval;
+	struct rewrite_dir_context ctx;
+
+	retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
+	if (retval)
+		return retval;
+
+	ctx.is_htree = (inode->i_flags & EXT2_INDEX_FL);
+	ctx.dir = dir;
+	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY |
+						BLOCK_FLAG_DATA_ONLY,
+				       0, rewrite_dir_block, &ctx);
+
+	ext2fs_free_mem(&ctx.buf);
+	if (retval)
+		return retval;
+
+	return ctx.errcode;
+}
+
+/*
  * Forcibly set checksums in all inodes.
  */
 static void rewrite_inodes(ext2_filsys fs)
@@ -437,6 +622,15 @@ static void rewrite_inodes(ext2_filsys fs)
 				"while rewriting extents");
 			exit(1);
 		}
+
+		if (LINUX_S_ISDIR(inode->i_mode)) {
+			retval = rewrite_directory(fs, ino, inode);
+			if (retval) {
+				com_err("rewrite_directory", retval,
+					"while rewriting directories");
+				exit(1);
+			}
+		}
 	} while (ino);
 	ext2fs_close_inode_scan(scan);
 }
@@ -1948,7 +2142,9 @@ retry_open:
 			fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
 		}
 		ext2fs_mark_super_dirty(fs);
-		rewrite_checksums = 1;
+		if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+			rewrite_checksums = 1;
 	}
 	if (rewrite_checksums)
 		rewrite_metadata_checksums(fs);


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

* [PATCH 29/37] libext2fs: Verify and calculate extended attribute block checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (27 preceding siblings ...)
  2011-09-01  0:38 ` [PATCH 28/37] tune2fs: Rebuild and checksum directories when toggling metadata_csum or changing UUID Darrick J. Wong
@ 2011-09-01  0:38 ` Darrick J. Wong
  2011-09-01  0:38 ` [PATCH 30/37] e2fsck: Check " Darrick J. Wong
                   ` (6 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:38 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Calculate and verify the checksum for separate (i.e. not in the inode) extended
attribute blocks; the checksum lives in the header.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/csum.c          |   54 ++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/ext2_err.et.in  |    3 ++
 lib/ext2fs/ext2_ext_attr.h |    3 ++
 lib/ext2fs/ext2fs.h        |    6 +++++
 lib/ext2fs/ext_attr.c      |   11 ++++++++-
 lib/ext2fs/swapfs.c        |    3 ++
 6 files changed, 77 insertions(+), 3 deletions(-)


diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index a606b7c..4fe4b3d 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -29,6 +29,60 @@
 #define STATIC static
 #endif
 
+__u32 ext2fs_ext_attr_block_csum(ext2_filsys fs, blk64_t block,
+				 struct ext2_ext_attr_header *hdr)
+{
+	char *buf = (char *)hdr;
+	int offset = offsetof(struct ext2_ext_attr_header, h_checksum);
+	__u32 crc = 0;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return 0;
+
+#ifdef WORDS_BIGENDIAN
+	errcode_t retval;
+
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return retval;
+	ext2fs_swap_ext_attr(buf, (char *)hdr, fs->blocksize, 1);
+#endif
+
+	block = ext2fs_cpu_to_le64(block);
+	crc = crc32c_le(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid));
+	crc = crc32c_le(crc, (char *)&block, sizeof(block));
+	crc = crc32c_le(crc, buf, offset);
+	offset += sizeof(hdr->h_checksum); /* skip checksum */
+	crc = crc32c_le(crc, buf + offset, fs->blocksize - offset);
+
+#ifdef WORDS_BIGENDIAN
+	ext2fs_free_mem(&buf);
+#endif
+
+	return crc;
+}
+
+int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, blk64_t block,
+				      struct ext2_ext_attr_header *hdr)
+{
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+	    (hdr->h_checksum != ext2fs_ext_attr_block_csum(fs, block, hdr)))
+		return 0;
+	return 1;
+}
+
+void ext2fs_ext_attr_block_csum_set(ext2_filsys fs, blk64_t block,
+				    struct ext2_ext_attr_header *hdr)
+{
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return;
+
+	hdr->h_checksum = ext2fs_ext_attr_block_csum(fs, block, hdr);
+}
+
 static struct ext2_dir_entry_tail *get_dirent_tail(ext2_filsys fs,
 						struct ext2_dir_entry *dirent)
 {
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 31c8fe1..6e2c22c 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -431,4 +431,7 @@ ec	EXT2_ET_INODE_CORRUPT,
 ec	EXT2_ET_INODE_CSUM_NONZERO,
 	"Inode checksum should not be set"
 
+ec	EXT2_ET_EXT_ATTR_BLOCK_CORRUPT,
+	"Extended attribute block fails checksum"
+
 	end
diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
index ed548d1..ee45175 100644
--- a/lib/ext2fs/ext2_ext_attr.h
+++ b/lib/ext2fs/ext2_ext_attr.h
@@ -20,7 +20,8 @@ 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+inode+xattrs) */
+	__u32	h_reserved[3];	/* zero right now */
 };
 
 struct ext2_ext_attr_entry {
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 706357a..0820e43 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -894,6 +894,12 @@ extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len);
 extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
 
 /* csum.c */
+extern __u32 ext2fs_ext_attr_block_csum(ext2_filsys fs, blk64_t block,
+					struct ext2_ext_attr_header *hdr);
+extern int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, blk64_t block,
+					     struct ext2_ext_attr_header *hdr);
+extern void ext2fs_ext_attr_block_csum_set(ext2_filsys fs, blk64_t block,
+					   struct ext2_ext_attr_header *hdr);
 extern int ext2fs_dirent_has_tail(ext2_filsys fs,
 				  struct ext2_dir_entry *dirent);
 extern int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c
index 52664eb..2240e3e 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -70,6 +70,11 @@ errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf)
 #ifdef WORDS_BIGENDIAN
 	ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
 #endif
+
+	if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+	    !ext2fs_ext_attr_block_csum_verify(fs, block, buf))
+		return EXT2_ET_EXT_ATTR_BLOCK_CORRUPT;
+
 	return 0;
 }
 
@@ -84,6 +89,9 @@ errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf)
 	char		*write_buf;
 	char		*buf = NULL;
 
+	ext2fs_ext_attr_block_csum_set(fs, block,
+			(struct ext2_ext_attr_header *)inbuf);
+
 #ifdef WORDS_BIGENDIAN
 	retval = ext2fs_get_mem(fs->blocksize, &buf);
 	if (retval)
@@ -151,5 +159,6 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
 					char *block_buf, int adjust,
 					__u32 *newcount)
 {
-	return ext2fs_adjust_ea_refcount(fs, blk, block_buf, adjust, newcount);
+	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
+					  newcount);
 }
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index 570ab7d..a13f46a 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -144,7 +144,8 @@ void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header,
 	to_header->h_blocks   = ext2fs_swab32(from_header->h_blocks);
 	to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
 	to_header->h_hash     = ext2fs_swab32(from_header->h_hash);
-	for (n = 0; n < 4; n++)
+	to_header->h_checksum = ext2fs_swab32(from_header->h_checksum);
+	for (n = 0; n < 3; n++)
 		to_header->h_reserved[n] =
 			ext2fs_swab32(from_header->h_reserved[n]);
 }


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

* [PATCH 30/37] e2fsck: Check extended attribute block checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (28 preceding siblings ...)
  2011-09-01  0:38 ` [PATCH 29/37] libext2fs: Verify and calculate extended attribute block checksums Darrick J. Wong
@ 2011-09-01  0:38 ` Darrick J. Wong
  2011-09-01  0:38 ` [PATCH 32/37] libext2fs: Extend inode checksum to cover the EA block Darrick J. Wong
                   ` (5 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:38 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Verify the checksums of separate extended attribute blocks and offer to clear
it if there is a mismatch.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 e2fsck/pass1.c   |    7 +++++++
 e2fsck/problem.c |    5 +++++
 e2fsck/problem.h |    3 +++
 3 files changed, 15 insertions(+), 0 deletions(-)


diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 71cbddb..e4d4c78 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -1555,7 +1555,9 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
 	 * validate it
 	 */
 	pctx->blk = blk;
+	fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
 	pctx->errcode = ext2fs_read_ext_attr2(fs, blk, block_buf);
+	fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 	if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
 		goto clear_extattr;
 	header = (struct ext2_ext_attr_header *) block_buf;
@@ -1568,6 +1570,11 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
 			goto clear_extattr;
 	}
 
+	if (!ext2fs_ext_attr_block_csum_verify(fs, pctx->blk,
+			(struct ext2_ext_attr_header *)block_buf) &&
+	    fix_problem(ctx, PR_1_EA_BLOCK_CSUM_INVALID, pctx))
+		goto clear_extattr;
+
 	if (header->h_blocks != 1) {
 		if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
 			goto clear_extattr;
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 835f0ff..1259568 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -920,6 +920,11 @@ static struct e2fsck_problem problem_table[] = {
 	  N_("@i %i checksum should not be set.  "),
 	  PROMPT_CLEAR, PR_PREEN_OK },
 
+	/* Checksum failure reading extended attribute block */
+	{ PR_1_EA_BLOCK_CSUM_INVALID,
+	  N_("Checksum failure @a @b %b for @i %i.  "),
+	  PROMPT_CLEAR, 0 },
+
 	/* Pass 1b errors */
 
 	/* Pass 1B: Rescan for duplicate/bad blocks */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index df29057..47e6904 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -538,6 +538,9 @@ struct problem_context {
 /* inode checksum should not be set */
 #define PR_1_INODE_CSUM_NONZERO		0x010064
 
+/* ea block checksum invalid */
+#define PR_1_EA_BLOCK_CSUM_INVALID	0x010065
+
 /*
  * Pass 1b errors
  */


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

* [PATCH 32/37] libext2fs: Extend inode checksum to cover the EA block
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (29 preceding siblings ...)
  2011-09-01  0:38 ` [PATCH 30/37] e2fsck: Check " Darrick J. Wong
@ 2011-09-01  0:38 ` Darrick J. Wong
  2011-09-14 16:48   ` Ted Ts'o
  2011-09-01  0:38 ` [PATCH 33/37] tune2fs: Rewrite extended attribute block checksums Darrick J. Wong
                   ` (4 subsequent siblings)
  35 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:38 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Now that e2fsprogs knows to read the entire s_inode_size, change the inode
checksum code to checksum the entire block.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/csum.c |    8 +-------
 1 files changed, 1 insertions(+), 7 deletions(-)


diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index 4fe4b3d..dc87de3 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -478,14 +478,9 @@ __u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
 {
 	struct ext2_inode_large *desc = inode;
 	int offset = offsetof(struct ext2_inode_large, i_checksum);
-	int extra_size = inode->i_extra_isize;
 	size_t size = fs->super->s_inode_size;
 	__u32 crc = 0;
 
-	if (size < EXT2_GOOD_OLD_INODE_SIZE + extra_size)
-		printf("ERROR: inode %d size %d != extra_size %d!\n", inum,
-		       size, extra_size + EXT2_GOOD_OLD_INODE_SIZE);

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

* [PATCH 33/37] tune2fs: Rewrite extended attribute block checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (30 preceding siblings ...)
  2011-09-01  0:38 ` [PATCH 32/37] libext2fs: Extend inode checksum to cover the EA block Darrick J. Wong
@ 2011-09-01  0:38 ` Darrick J. Wong
  2011-09-01  0:38 ` [PATCH 34/37] libext2fs: Calculate and verify superblock checksums Darrick J. Wong
                   ` (3 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:38 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

When enabling metadata checksums, rewrite separate extended attribute blocks.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 misc/tune2fs.c |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)


diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 5663e49..60c1a6a 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -589,11 +589,13 @@ errcode_t rewrite_directory(ext2_filsys fs, ext2_ino_t dir,
  */
 static void rewrite_inodes(ext2_filsys fs)
 {
+	char		*ea_buf;
 	char		buf[EXT2_INODE_CORE_SIZE(fs->super)];
 	struct ext2_inode_large *inode = (struct ext2_inode_large *)buf;
 	ext2_inode_scan	scan;
 	errcode_t	retval;
 	ext2_ino_t	ino;
+	blk64_t		file_acl_block;
 
 	if (fs->super->s_creator_os != EXT2_OS_LINUX)
 		return;
@@ -604,6 +606,12 @@ static void rewrite_inodes(ext2_filsys fs)
 		exit(1);
 	}
 
+	retval = ext2fs_get_mem(fs->blocksize, &ea_buf);
+	if (retval) {
+		com_err("set_csum", retval, "while allocating memory");
+		exit(1);
+	}
+
 	do {
 		retval = ext2fs_get_next_inode(scan, &ino, inode);
 		if (retval) {
@@ -633,7 +641,25 @@ static void rewrite_inodes(ext2_filsys fs)
 				exit(1);
 			}
 		}
+
+		file_acl_block = ext2fs_file_acl_block(inode);
+		if (!file_acl_block)
+			continue;
+		retval = ext2fs_read_ext_attr2(fs, file_acl_block, ea_buf);
+		if (retval) {
+			com_err("rewrite_eablock", retval,
+				"while rewriting extended attribute");
+			exit(1);
+		}
+		retval = ext2fs_write_ext_attr2(fs, file_acl_block, ea_buf);
+		if (retval) {
+			com_err("rewrite_eablock", retval,
+				"while rewriting extended attribute");
+			exit(1);
+		}
 	} while (ino);
+
+	ext2fs_free_mem(&ea_buf);
 	ext2fs_close_inode_scan(scan);
 }
 


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

* [PATCH 34/37] libext2fs: Calculate and verify superblock checksums
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (31 preceding siblings ...)
  2011-09-01  0:38 ` [PATCH 33/37] tune2fs: Rewrite extended attribute block checksums Darrick J. Wong
@ 2011-09-01  0:38 ` Darrick J. Wong
  2011-09-01  0:38 ` [PATCH 35/37] e2fsck: Handle superblock checksum errors gracefully Darrick J. Wong
                   ` (2 subsequent siblings)
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:38 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Calculate and verify the superblock checksums.  Each copy of the superblock
records the number of the group it's in and the FS UUID, so we can simply
checksum the whole block.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/ext2fs/closefs.c      |   13 ++++++-------
 lib/ext2fs/csum.c         |   39 +++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/ext2_err.et.in |    3 +++
 lib/ext2fs/ext2_fs.h      |    3 ++-
 lib/ext2fs/ext2fs.h       |    6 ++++++
 lib/ext2fs/openfs.c       |    6 ++++++
 lib/ext2fs/swapfs.c       |    2 ++
 7 files changed, 64 insertions(+), 8 deletions(-)


diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c
index 73dc136..017e9ba 100644
--- a/lib/ext2fs/closefs.c
+++ b/lib/ext2fs/closefs.c
@@ -256,10 +256,11 @@ static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
 
 	if (sgrp > ((1 << 16) - 1))
 		sgrp = (1 << 16) - 1;
+
+	super_shadow->s_block_group_nr = sgrp;
+	ext2fs_superblock_csum_set(fs, super_shadow);
 #ifdef WORDS_BIGENDIAN
-	super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
-#else
-	fs->super->s_block_group_nr = sgrp;
+	ext2fs_swap_super(super_shadow);
 #endif
 
 	return io_channel_write_blk64(fs->io, group_block, -SUPERBLOCK_SIZE,
@@ -315,6 +316,7 @@ errcode_t ext2fs_flush(ext2_filsys fs)
 				  &group_shadow);
 	if (retval)
 		goto errout;
+	memcpy(super_shadow, fs->super, sizeof(struct ext2_super_block));
 	memcpy(group_shadow, fs->group_desc, (size_t) fs->blocksize *
 	       fs->desc_blocks);
 
@@ -335,10 +337,6 @@ errcode_t ext2fs_flush(ext2_filsys fs)
 	 */
 	fs->super->s_state &= ~EXT2_VALID_FS;
 	fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
-#ifdef WORDS_BIGENDIAN
-	*super_shadow = *fs->super;
-	ext2fs_swap_super(super_shadow);
-#endif
 
 	/*
 	 * If this is an external journal device, don't write out the
@@ -408,6 +406,7 @@ write_primary_superblock_only:
 	fs->super->s_block_group_nr = 0;
 	fs->super->s_state = fs_state;
 	fs->super->s_feature_incompat = feature_incompat;
+	ext2fs_superblock_csum_set(fs, fs->super);
 #ifdef WORDS_BIGENDIAN
 	*super_shadow = *fs->super;
 	ext2fs_swap_super(super_shadow);
diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index dc87de3..1da5bfc 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -29,6 +29,45 @@
 #define STATIC static
 #endif
 
+__u32 ext2fs_superblock_csum(ext2_filsys fs, struct ext2_super_block *sb)
+{
+	int offset = offsetof(struct ext2_super_block, s_checksum);
+	__u32 crc = 0;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return 0;
+
+#ifdef WORDS_BIGENDIAN
+	struct ext2_super_block swabsb;
+	memcpy(&swabsb, sb, sizeof(struct ext2_super_block));
+	ext2fs_swap_super(&swabsb);
+	sb = &swabsb;
+#endif
+
+	crc = crc32c_le(~0, (char *)sb, offset);
+
+	return crc;
+}
+
+int ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *sb)
+{
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+	    (sb->s_checksum != ext2fs_superblock_csum(fs, sb)))
+		return 0;
+	return 1;
+}
+
+void ext2fs_superblock_csum_set(ext2_filsys fs, struct ext2_super_block *sb)
+{
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return;
+
+	sb->s_checksum = ext2fs_superblock_csum(fs, sb);
+}
+
 __u32 ext2fs_ext_attr_block_csum(ext2_filsys fs, blk64_t block,
 				 struct ext2_ext_attr_header *hdr)
 {
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 6e2c22c..956427d 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -434,4 +434,7 @@ ec	EXT2_ET_INODE_CSUM_NONZERO,
 ec	EXT2_ET_EXT_ATTR_BLOCK_CORRUPT,
 	"Extended attribute block fails checksum"
 
+ec	EXT2_ET_SB_CSUM_INVALID,
+	"Superblock fails checksum"
+
 	end
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 40b5900..7d43e15 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -589,7 +589,8 @@ struct ext2_super_block {
 	__u32	s_usr_quota_inum;	/* inode number of user quota file */
 	__u32	s_grp_quota_inum;	/* inode number of group quota file */
 	__u32	s_overhead_blocks;	/* overhead blocks/clusters in fs */
-	__u32   s_reserved[109];        /* Padding to the end of the block */
+	__u32	s_checksum;		/* crc32c(superblock) */
+	__u32   s_reserved[108];        /* Padding to the end of the block */
 };
 
 #define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 0820e43..282806b 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -894,6 +894,12 @@ extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len);
 extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
 
 /* csum.c */
+extern __u32 ext2fs_superblock_csum(ext2_filsys fs,
+				    struct ext2_super_block *sb);
+extern int ext2fs_superblock_csum_verify(ext2_filsys fs,
+					 struct ext2_super_block *sb);
+extern void ext2fs_superblock_csum_set(ext2_filsys fs,
+				       struct ext2_super_block *sb);
 extern __u32 ext2fs_ext_attr_block_csum(ext2_filsys fs, blk64_t block,
 					struct ext2_ext_attr_header *hdr);
 extern int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, blk64_t block,
diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c
index 0edeb2f..5472d9a 100644
--- a/lib/ext2fs/openfs.c
+++ b/lib/ext2fs/openfs.c
@@ -198,6 +198,12 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
 	}
 #endif
 
+	if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+	    !ext2fs_superblock_csum_verify(fs, fs->super)) {
+		retval = EXT2_ET_SB_CSUM_INVALID;
+		goto cleanup;
+	}
+
 	if (fs->super->s_magic != EXT2_SUPER_MAGIC) {
 		retval = EXT2_ET_BAD_MAGIC;
 		goto cleanup;
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index 5cbb4b9..5234451 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -94,6 +94,8 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
 	}
 	for (; i < 17; i++)
 		sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]);
+
+	sb->s_checksum = ext2fs_swab32(sb->s_checksum);
 }
 
 void ext2fs_swap_group_desc2(ext2_filsys fs, struct ext2_group_desc *gdp)


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

* [PATCH 35/37] e2fsck: Handle superblock checksum errors gracefully
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (32 preceding siblings ...)
  2011-09-01  0:38 ` [PATCH 34/37] libext2fs: Calculate and verify superblock checksums Darrick J. Wong
@ 2011-09-01  0:38 ` Darrick J. Wong
  2011-09-01  0:39 ` [PATCH 36/37] e2p: Print superblock checksum in list_super Darrick J. Wong
  2011-09-01  0:39 ` [PATCH 37/37] e2fsck: Support CRC32c checksum in journal commit blocks Darrick J. Wong
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:38 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

If e2fsck finds a superblock with an invalid checksum, try the backups.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 e2fsck/unix.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)


diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index 7e95ca8..c32b8d7 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -1096,6 +1096,7 @@ restart:
 	if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
 	    !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
 	    ((retval == EXT2_ET_BAD_MAGIC) ||
+	     (retval == EXT2_ET_SB_CSUM_INVALID) ||
 	     (retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
 	     ((retval == 0) && (retval2 = ext2fs_check_desc(fs))))) {
 		if (retval2 == ENOMEM) {


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

* [PATCH 36/37] e2p: Print superblock checksum in list_super
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (33 preceding siblings ...)
  2011-09-01  0:38 ` [PATCH 35/37] e2fsck: Handle superblock checksum errors gracefully Darrick J. Wong
@ 2011-09-01  0:39 ` Darrick J. Wong
  2011-09-01  0:39 ` [PATCH 37/37] e2fsck: Support CRC32c checksum in journal commit blocks Darrick J. Wong
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:39 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

Displays superblock checksum when dumping superblock contents.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 lib/e2p/ls.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)


diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c
index aa4a389..1c3ab1c 100644
--- a/lib/e2p/ls.c
+++ b/lib/e2p/ls.c
@@ -413,6 +413,10 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
 	if (sb->s_grp_quota_inum)
 		fprintf(f, "Group quota inode:        %u\n",
 			sb->s_grp_quota_inum);
+
+	if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+		fprintf(f, "Checksum:                 0x%08x\n",
+			sb->s_checksum);
 }
 
 void list_super (struct ext2_super_block * s)


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

* [PATCH 37/37] e2fsck: Support CRC32c checksum in journal commit blocks
  2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
                   ` (34 preceding siblings ...)
  2011-09-01  0:39 ` [PATCH 36/37] e2p: Print superblock checksum in list_super Darrick J. Wong
@ 2011-09-01  0:39 ` Darrick J. Wong
  35 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-01  0:39 UTC (permalink / raw)
  To: Andreas Dilger, Theodore Tso, Darrick J. Wong
  Cc: Sunil Mushran, Amir Goldstein, Andi Kleen, Mingming Cao,
	Joel Becker, linux-ext4, Coly Li

The CRC32c polynomial provides better error detection and can be hardware
accelerated on newer machines.  To that end, support replaying transactions
with this checksum type.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---
 e2fsck/jfs_user.h       |    1 +
 e2fsck/recovery.c       |   19 ++++++++++++++++---
 lib/ext2fs/kernel-jbd.h |    1 +
 3 files changed, 18 insertions(+), 3 deletions(-)


diff --git a/e2fsck/jfs_user.h b/e2fsck/jfs_user.h
index 802f6e8..2f15c19 100644
--- a/e2fsck/jfs_user.h
+++ b/e2fsck/jfs_user.h
@@ -13,6 +13,7 @@
  * Pull in the definition of the e2fsck context structure
  */
 #include "e2fsck.h"
+#include "ext2fs/ext2fs.h"
 
 struct buffer_head {
 	e2fsck_t	b_ctx;
diff --git a/e2fsck/recovery.c b/e2fsck/recovery.c
index cac9294..2d4dd06 100644
--- a/e2fsck/recovery.c
+++ b/e2fsck/recovery.c
@@ -323,7 +323,8 @@ static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag
  * descriptor block.
  */
 static int calc_chksums(journal_t *journal, struct buffer_head *bh,
-			unsigned long *next_log_block, __u32 *crc32_sum)
+			unsigned long *next_log_block, __u32 *crc32_sum,
+			__u32 *crc32c_sum)
 {
 	int i, num_blks, err;
 	unsigned long io_block;
@@ -332,6 +333,7 @@ static int calc_chksums(journal_t *journal, struct buffer_head *bh,
 	num_blks = count_tags(journal, bh);
 	/* Calculate checksum of the descriptor block. */
 	*crc32_sum = crc32_be(*crc32_sum, (void *)bh->b_data, bh->b_size);
+	*crc32c_sum = crc32c_le(*crc32c_sum, (void *)bh->b_data, bh->b_size);
 
 	for (i = 0; i < num_blks; i++) {
 		io_block = (*next_log_block)++;
@@ -344,6 +346,9 @@ static int calc_chksums(journal_t *journal, struct buffer_head *bh,
 		} else {
 			*crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data,
 				     obh->b_size);
+			*crc32c_sum = crc32c_le(*crc32c_sum,
+				     (void *)obh->b_data,
+				     obh->b_size);
 		}
 		brelse(obh);
 	}
@@ -363,6 +368,7 @@ static int do_one_pass(journal_t *journal,
 	int			blocktype;
 	int			tag_bytes = journal_tag_bytes(journal);
 	__u32			crc32_sum = ~0; /* Transactional Checksums */
+	__u32			crc32c_sum = ~0; /* Transactional Checksums */
 
 	/* Precompute the maximum metadata descriptors in a descriptor block */
 	int			MAX_BLOCKS_PER_DESC;
@@ -464,7 +470,8 @@ static int do_one_pass(journal_t *journal,
 				    !info->end_transaction) {
 					if (calc_chksums(journal, bh,
 							&next_log_block,
-							&crc32_sum)) {
+							&crc32_sum,
+							&crc32c_sum)) {
 						brelse(bh);
 						break;
 					}
@@ -627,7 +634,12 @@ static int do_one_pass(journal_t *journal,
 				    cbh->h_chksum_type == JBD2_CRC32_CHKSUM &&
 				    cbh->h_chksum_size ==
 						JBD2_CRC32_CHKSUM_SIZE)
-				       chksum_seen = 1;
+					chksum_seen = 1;
+				else if (crc32c_sum == found_chksum &&
+				    cbh->h_chksum_type == JBD2_CRC32C_CHKSUM &&
+				    cbh->h_chksum_size ==
+						JBD2_CRC32_CHKSUM_SIZE)
+					chksum_seen = 1;
 				else if (!(cbh->h_chksum_type == 0 &&
 					     cbh->h_chksum_size == 0 &&
 					     found_chksum == 0 &&
@@ -657,6 +669,7 @@ static int do_one_pass(journal_t *journal,
 					}
 				}
 				crc32_sum = ~0;
+				crc32c_sum = ~0;
 			}
 			brelse(bh);
 			next_commit_ID++;
diff --git a/lib/ext2fs/kernel-jbd.h b/lib/ext2fs/kernel-jbd.h
index 066c031..7d92b56 100644
--- a/lib/ext2fs/kernel-jbd.h
+++ b/lib/ext2fs/kernel-jbd.h
@@ -114,6 +114,7 @@ typedef struct journal_header_s
 #define JBD2_CRC32_CHKSUM   1
 #define JBD2_MD5_CHKSUM     2
 #define JBD2_SHA1_CHKSUM    3
+#define JBD2_CRC32C_CHKSUM  4
 
 #define JBD2_CRC32_CHKSUM_SIZE 4
 


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

* Re: [PATCH 01/37] e2fsprogs: Read and write full-sized inodes
  2011-09-01  0:35 ` [PATCH 01/37] e2fsprogs: Read and write full-sized inodes Darrick J. Wong
@ 2011-09-03 18:05   ` Andreas Dilger
  2011-09-04 14:04     ` Ted Ts'o
  2011-09-14 16:39   ` Ted Ts'o
  1 sibling, 1 reply; 63+ messages in thread
From: Andreas Dilger @ 2011-09-03 18:05 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Theodore Tso, Darrick J. Wong, Sunil Mushran,
	Amir Goldstein, Andi Kleen, Mingming Cao, Joel Becker,
	linux-ext4, Coly Li

Why not just get rid of ext2_inode and replace it with ext2_inode_large?  Less change to the code, and less confusion for developers. 

Cheers, Andreas

On 2011-08-31, at 6:35 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:

> As part of adding inode checksums, it is necessary for all e2fsprogs to read
> and write full inodes so that checksums may be calculated correctly.  Since
> struct ext2_inode_large is a superset of struct ext2_inode, replace the smaller
> one with the larger one.
> 
> Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
> ---
> debugfs/debugfs.c               |   28 ++++++++--------
> debugfs/debugfs.h               |   12 ++++---
> debugfs/dump.c                  |   12 +++----
> debugfs/htree.c                 |   10 +++---
> debugfs/icheck.c                |    2 +
> debugfs/logdump.c               |   13 ++++---
> debugfs/ls.c                    |    4 +-
> debugfs/lsdel.c                 |    2 +
> debugfs/ncheck.c                |    2 +
> debugfs/set_fields.c            |    2 +
> debugfs/util.c                  |    8 ++---
> doc/libext2fs.texinfo           |   12 +++----
> e2fsck/e2fsck.h                 |   23 +++++++------
> e2fsck/emptydir.c               |    2 +
> e2fsck/iscan.c                  |    2 +
> e2fsck/jfs_user.h               |    2 +
> e2fsck/journal.c                |    5 ++-
> e2fsck/message.c                |    2 +
> e2fsck/pass1.c                  |   35 ++++++++++----------
> e2fsck/pass1b.c                 |   10 +++---
> e2fsck/pass2.c                  |   10 +++---
> e2fsck/pass3.c                  |   10 +++---
> e2fsck/pass4.c                  |   11 ++++--
> e2fsck/problem.h                |    2 +
> e2fsck/rehash.c                 |    6 ++-
> e2fsck/scantest.c               |    2 +
> e2fsck/super.c                  |    6 ++-
> e2fsck/util.c                   |    8 ++---
> ext2ed/dir_com.c                |    2 +
> ext2ed/doc/ext2ed-design.sgml   |    6 ++-
> ext2ed/doc/ext2fs-overview.sgml |    2 +
> ext2ed/ext2.descriptors         |    2 +
> ext2ed/ext2ed.h                 |    4 +-
> ext2ed/file_com.c               |    2 +
> ext2ed/init.c                   |    2 +
> ext2ed/inode_com.c              |   18 +++++-----
> lib/e2p/ls.c                    |    2 +
> lib/ext2fs/bb_inode.c           |    2 +
> lib/ext2fs/blknum.c             |    8 ++---
> lib/ext2fs/block.c              |    2 +
> lib/ext2fs/bmap.c               |   16 +++++----
> lib/ext2fs/bmove.c              |    4 +-
> lib/ext2fs/expanddir.c          |    2 +
> lib/ext2fs/ext2_fs.h            |   47 ---------------------------
> lib/ext2fs/ext2fs.h             |   61 ++++++++++++++++++-----------------
> lib/ext2fs/ext2fsP.h            |    2 +
> lib/ext2fs/extent.c             |    6 ++-
> lib/ext2fs/fileio.c             |    8 ++---
> lib/ext2fs/i_block.c            |    7 ++--
> lib/ext2fs/initialize.c         |    2 +
> lib/ext2fs/inode.c              |   68 ++++++++++++++++++---------------------
> lib/ext2fs/inode_io.c           |    6 ++-
> lib/ext2fs/link.c               |    2 +
> lib/ext2fs/mkdir.c              |    4 +-
> lib/ext2fs/mkjournal.c          |    2 +
> lib/ext2fs/namei.c              |    2 +
> lib/ext2fs/punch.c              |   11 +++---
> lib/ext2fs/read_bb.c            |    2 +
> lib/ext2fs/res_gdt.c            |    2 +
> lib/ext2fs/swapfs.c             |   22 ++++++-------
> lib/ext2fs/tst_iscan.c          |    2 +
> lib/ext2fs/valid_blk.c          |    2 +
> misc/dumpe2fs.c                 |    2 +
> misc/e2image.c                  |    6 ++-
> misc/e2initrd_helper.c          |    2 +
> misc/mke2fs.c                   |    2 +
> misc/tune2fs.c                  |    4 +-
> resize/resize2fs.c              |   10 +++---
> 68 files changed, 283 insertions(+), 318 deletions(-)
> 
> 
> diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
> index e7d7436..94732b9 100644
> --- a/debugfs/debugfs.c
> +++ b/debugfs/debugfs.c
> @@ -688,7 +688,7 @@ static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino,
> }
> 
> void internal_dump_inode(FILE *out, const char *prefix,
> -             ext2_ino_t inode_num, struct ext2_inode *inode,
> +             ext2_ino_t inode_num, struct ext2_inode_large *inode,
>             int do_dump_blocks)
> {
>    const char *i_type;
> @@ -812,7 +812,7 @@ void internal_dump_inode(FILE *out, const char *prefix,
>    }
> }
> 
> -static void dump_inode(ext2_ino_t inode_num, struct ext2_inode *inode)
> +static void dump_inode(ext2_ino_t inode_num, struct ext2_inode_large *inode)
> {
>    FILE    *out;
> 
> @@ -824,12 +824,12 @@ static void dump_inode(ext2_ino_t inode_num, struct ext2_inode *inode)
> void do_stat(int argc, char *argv[])
> {
>    ext2_ino_t    inode;
> -    struct ext2_inode * inode_buf;
> +    struct ext2_inode_large *inode_buf;
> 
>    if (check_fs_open(argv[0]))
>        return;
> 
> -    inode_buf = (struct ext2_inode *)
> +    inode_buf = (struct ext2_inode_large *)
>            malloc(EXT2_INODE_SIZE(current_fs->super));
>    if (!inode_buf) {
>        fprintf(stderr, "do_stat: can't allocate buffer\n");
> @@ -854,7 +854,7 @@ void do_stat(int argc, char *argv[])
> 
> void do_dump_extents(int argc, char **argv)
> {
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    ext2_ino_t    ino;
>    FILE        *out;
>    int        c, flags = 0;
> @@ -959,7 +959,7 @@ void do_chroot(int argc, char *argv[])
> void do_clri(int argc, char *argv[])
> {
>    ext2_ino_t inode;
> -    struct ext2_inode inode_buf;
> +    struct ext2_inode_large inode_buf;
> 
>    if (common_inode_args_process(argc, argv, &inode, CHECK_FS_RW))
>        return;
> @@ -1135,7 +1135,7 @@ static void modify_u32(char *com, const char *prompt,
> 
> void do_modify_inode(int argc, char *argv[])
> {
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    ext2_ino_t    inode_num;
>    int        i;
>    unsigned char    *frag, *fsize;
> @@ -1293,7 +1293,7 @@ static int ext2_file_type(unsigned int mode)
> static void make_link(char *sourcename, char *destname)
> {
>    ext2_ino_t    ino;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    int        retval;
>    ext2_ino_t    dir;
>    char        *dest, *cp, *base_name;
> @@ -1369,7 +1369,7 @@ static int mark_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
> void do_undel(int argc, char *argv[])
> {
>    ext2_ino_t    ino;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
> 
>    if (common_args_process(argc, argv, 2, 3, "undelete",
>                "<inode_num> [dest_name]",
> @@ -1577,7 +1577,7 @@ void do_write(int argc, char *argv[])
>    struct stat    statbuf;
>    ext2_ino_t    newfile;
>    errcode_t    retval;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
> 
>    if (common_args_process(argc, argv, 3, 3, "write",
>                "<native file> <new file>", CHECK_FS_RW))
> @@ -1654,7 +1654,7 @@ void do_mknod(int argc, char *argv[])
>    unsigned long    mode, major, minor;
>    ext2_ino_t    newfile;
>    errcode_t    retval;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    int        filetype, nr;
> 
>    if (check_fs_open(argv[0]))
> @@ -1792,7 +1792,7 @@ static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
> 
> static void kill_file_by_inode(ext2_ino_t inode)
> {
> -    struct ext2_inode inode_buf;
> +    struct ext2_inode_large inode_buf;
> 
>    if (debugfs_read_inode(inode, &inode_buf, 0))
>        return;
> @@ -1824,7 +1824,7 @@ void do_rm(int argc, char *argv[])
> {
>    int retval;
>    ext2_ino_t inode_num;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
> 
>    if (common_args_process(argc, argv, 2, 2, "rm",
>                "<filename>", CHECK_FS_RW))
> @@ -1885,7 +1885,7 @@ void do_rmdir(int argc, char *argv[])
> {
>    int retval;
>    ext2_ino_t inode_num;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    struct rd_struct rds;
> 
>    if (common_args_process(argc, argv, 2, 2, "rmdir",
> diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
> index 0ea2474..d65a371 100644
> --- a/debugfs/debugfs.h
> +++ b/debugfs/debugfs.h
> @@ -44,13 +44,15 @@ extern int common_inode_args_process(int argc, char *argv[],
>                     ext2_ino_t *inode, int flags);
> extern int common_block_args_process(int argc, char *argv[],
>                     blk64_t *block, blk64_t *count);
> -extern int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode,
> +extern int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
>                  const char *cmd);
> -extern int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode,
> +extern int debugfs_read_inode_full(ext2_ino_t ino,
> +                   struct ext2_inode_large *inode,
>                   const char *cmd, int bufsize);
> -extern int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode * inode,
> +extern int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
>                   const char *cmd);
> -extern int debugfs_write_new_inode(ext2_ino_t ino, struct ext2_inode * inode,
> +extern int debugfs_write_new_inode(ext2_ino_t ino,
> +                   struct ext2_inode_large *inode,
>                   const char *cmd);
> 
> /* ss command functions */
> @@ -87,7 +89,7 @@ extern void do_dump_unused(int argc, char **argv);
> 
> /* debugfs.c */
> extern void internal_dump_inode(FILE *, const char *, ext2_ino_t,
> -                struct ext2_inode *, int);
> +                struct ext2_inode_large *, int);
> 
> extern void do_dirty_filesys(int argc, char **argv);
> extern void do_open_filesys(int argc, char **argv);
> diff --git a/debugfs/dump.c b/debugfs/dump.c
> index 4cf0752..fe7e7f4 100644
> --- a/debugfs/dump.c
> +++ b/debugfs/dump.c
> @@ -66,7 +66,7 @@ static mode_t mode_xlate(__u16 lmode)
>    return mode;
> }
> 
> -static void fix_perms(const char *cmd, const struct ext2_inode *inode,
> +static void fix_perms(const char *cmd, const struct ext2_inode_large *inode,
>              int fd, const char *name)
> {
>    struct utimbuf ut;
> @@ -103,7 +103,7 @@ static void dump_file(const char *cmdname, ext2_ino_t ino, int fd,
>              int preserve, char *outname)
> {
>    errcode_t retval;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    char        buf[8192];
>    ext2_file_t    e2_file;
>    int        nbytes;
> @@ -187,7 +187,7 @@ void do_dump(int argc, char **argv)
>    return;
> }
> 
> -static void rdump_symlink(ext2_ino_t ino, struct ext2_inode *inode,
> +static void rdump_symlink(ext2_ino_t ino, struct ext2_inode_large *inode,
>              const char *fullname)
> {
>    ext2_file_t e2_file;
> @@ -241,7 +241,7 @@ errout:
> 
> static int rdump_dirent(struct ext2_dir_entry *, int, int, char *, void *);
> 
> -static void rdump_inode(ext2_ino_t ino, struct ext2_inode *inode,
> +static void rdump_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
>            const char *name, const char *dumproot)
> {
>    char *fullname;
> @@ -298,7 +298,7 @@ static int rdump_dirent(struct ext2_dir_entry *dirent,
>    char name[EXT2_NAME_LEN + 1];
>    int thislen;
>    const char *dumproot = private;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
> 
>    thislen = ((dirent->name_len & 0xFF) < EXT2_NAME_LEN
>           ? (dirent->name_len & 0xFF) : EXT2_NAME_LEN);
> @@ -316,7 +316,7 @@ static int rdump_dirent(struct ext2_dir_entry *dirent,
> void do_rdump(int argc, char **argv)
> {
>    ext2_ino_t ino;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    struct stat st;
>    int i;
>    char *p;
> diff --git a/debugfs/htree.c b/debugfs/htree.c
> index b829e25..d72b996 100644
> --- a/debugfs/htree.c
> +++ b/debugfs/htree.c
> @@ -29,7 +29,7 @@ extern char *optarg;
> static FILE *pager;
> 
> static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
> -                 struct ext2_inode *inode,
> +                 struct ext2_inode_large *inode,
>                 struct ext2_dx_root_info * rootnode,
>                 blk64_t blk, char *buf)
> {
> @@ -107,13 +107,13 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
> 
> 
> static void htree_dump_int_block(ext2_filsys fs, ext2_ino_t ino,
> -                 struct ext2_inode *inode,
> +                 struct ext2_inode_large *inode,
>                 struct ext2_dx_root_info * rootnode,
>                 blk64_t blk, char *buf, int level);
> 
> 
> static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
> -                struct ext2_inode *inode,
> +                struct ext2_inode_large *inode,
>                struct ext2_dx_root_info * rootnode,
>                struct ext2_dx_entry *ent,
>                char *buf, int level)
> @@ -156,7 +156,7 @@ static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
> }
> 
> static void htree_dump_int_block(ext2_filsys fs, ext2_ino_t ino,
> -                 struct ext2_inode *inode,
> +                 struct ext2_inode_large *inode,
>                 struct ext2_dx_root_info * rootnode,
>                 blk64_t blk, char *buf, int level)
> {
> @@ -196,7 +196,7 @@ errout:
> void do_htree_dump(int argc, char *argv[])
> {
>    ext2_ino_t    ino;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    blk64_t        blk;
>    char        *buf = NULL;
>    struct        ext2_dx_root_info  *rootnode;
> diff --git a/debugfs/icheck.c b/debugfs/icheck.c
> index 729ac93..d1aaefe 100644
> --- a/debugfs/icheck.c
> +++ b/debugfs/icheck.c
> @@ -59,7 +59,7 @@ void do_icheck(int argc, char **argv)
>    int            i;
>    ext2_inode_scan        scan = 0;
>    ext2_ino_t        ino;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    errcode_t        retval;
>    char            *block_buf;
> 
> diff --git a/debugfs/logdump.c b/debugfs/logdump.c
> index d1e64fd..dfb243e 100644
> --- a/debugfs/logdump.c
> +++ b/debugfs/logdump.c
> @@ -83,7 +83,7 @@ void do_logdump(int argc, char **argv)
>    int        journal_fd = 0;
>    int        use_sb = 0;
>    ext2_ino_t    journal_inum;
> -    struct ext2_inode journal_inode;
> +    struct ext2_inode_large journal_inode;
>    ext2_file_t    journal_file;
>    char        *tmp;
>    struct journal_source journal_source;
> @@ -154,13 +154,13 @@ void do_logdump(int argc, char **argv)
>        group_offset = ((inode_to_dump - 1)
>                % es->s_inodes_per_group);
>        inodes_per_block = (current_fs->blocksize
> -                    / sizeof(struct ext2_inode));
> +                    / EXT2_GOOD_OLD_INODE_SIZE);
> 
>        inode_block_to_dump =
>            ext2fs_inode_table_loc(current_fs, inode_group) +
>            (group_offset / inodes_per_block);
>        inode_offset_to_dump = ((group_offset % inodes_per_block)
> -                    * sizeof(struct ext2_inode));
> +                    * EXT2_GOOD_OLD_INODE_SIZE);
>        printf("Inode %u is at group %u, block %u, offset %u\n",
>               inode_to_dump, inode_group,
>               inode_block_to_dump, inode_offset_to_dump);
> @@ -206,7 +206,8 @@ void do_logdump(int argc, char **argv)
>                    "no journal backup in super block\n");
>                goto errout;
>            }
> -            memset(&journal_inode, 0, sizeof(struct ext2_inode));
> +            memset(&journal_inode, 0,
> +                   sizeof(struct ext2_inode_large));
>            memcpy(&journal_inode.i_block[0], es->s_jnl_blocks,
>                   EXT2_N_BLOCKS*4);
>            journal_inode.i_size_high = es->s_jnl_blocks[15];
> @@ -630,13 +631,13 @@ static void dump_metadata_block(FILE *out_file, struct journal_source *source,
>    }
> 
>    if (fs_blocknr == inode_block_to_dump) {
> -        struct ext2_inode *inode;
> +        struct ext2_inode_large *inode;
>        int first, prev, this, start_extent, i;
> 
>        fprintf(out_file, "    (inode block for inode %u):\n",
>            inode_to_dump);
> 
> -        inode = (struct ext2_inode *) (buf + inode_offset_to_dump);
> +        inode = (struct ext2_inode_large *)(buf + inode_offset_to_dump);
>        internal_dump_inode(out_file, "    ", inode_to_dump, inode, 0);
> 
>        /* Dump out the direct/indirect blocks here:
> diff --git a/debugfs/ls.c b/debugfs/ls.c
> index 8e019d2..9977a79 100644
> --- a/debugfs/ls.c
> +++ b/debugfs/ls.c
> @@ -49,7 +49,7 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
>             char    *buf EXT2FS_ATTR((unused)),
>             void    *private)
> {
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    ext2_ino_t        ino;
>    struct tm        *tm_p;
>    time_t            modtime;
> @@ -94,7 +94,7 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
>                tm_p->tm_min);
>        } else {
>            strcpy(datestr, "                 ");
> -            memset(&inode, 0, sizeof(struct ext2_inode));
> +            memset(&inode, 0, sizeof(struct ext2_inode_large));
>        }
>        fprintf(ls->f, "%c%6u%c %6o (%d)  %5d  %5d   ", lbr, ino, rbr,
>            inode.i_mode, dirent->name_len >> 8,
> diff --git a/debugfs/lsdel.c b/debugfs/lsdel.c
> index ba7a90f..4126dac 100644
> --- a/debugfs/lsdel.c
> +++ b/debugfs/lsdel.c
> @@ -77,7 +77,7 @@ void do_lsdel(int argc, char **argv)
>    int            num_delarray, max_delarray;
>    ext2_inode_scan        scan = 0;
>    ext2_ino_t        ino;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    errcode_t        retval;
>    char            *block_buf;
>    int            i;
> diff --git a/debugfs/ncheck.c b/debugfs/ncheck.c
> index a366281..2de66ae 100644
> --- a/debugfs/ncheck.c
> +++ b/debugfs/ncheck.c
> @@ -56,7 +56,7 @@ void do_ncheck(int argc, char **argv)
>    int            i;
>    ext2_inode_scan        scan = 0;
>    ext2_ino_t        ino;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    errcode_t        retval;
>    char            *tmp;
> 
> diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
> index ac6bc25..1bc6410 100644
> --- a/debugfs/set_fields.c
> +++ b/debugfs/set_fields.c
> @@ -40,7 +40,7 @@
> #include "e2p/e2p.h"
> 
> static struct ext2_super_block set_sb;
> -static struct ext2_inode set_inode;
> +static struct ext2_inode_large set_inode;
> static struct ext2_group_desc set_gd;
> static dgrp_t set_bg;
> static ext2_ino_t set_ino;
> diff --git a/debugfs/util.c b/debugfs/util.c
> index c3ac6f8..ff1f878 100644
> --- a/debugfs/util.c
> +++ b/debugfs/util.c
> @@ -375,7 +375,7 @@ int common_block_args_process(int argc, char *argv[],
>    return 0;
> }
> 
> -int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode,
> +int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode_large *inode,
>            const char *cmd, int bufsize)
> {
>    int retval;
> @@ -388,7 +388,7 @@ int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode,
>    return 0;
> }
> 
> -int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode,
> +int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
>            const char *cmd)
> {
>    int retval;
> @@ -401,7 +401,7 @@ int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode,
>    return 0;
> }
> 
> -int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode * inode,
> +int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
>            const char *cmd)
> {
>    int retval;
> @@ -414,7 +414,7 @@ int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode * inode,
>    return 0;
> }
> 
> -int debugfs_write_new_inode(ext2_ino_t ino, struct ext2_inode * inode,
> +int debugfs_write_new_inode(ext2_ino_t ino, struct ext2_inode_large *inode,
>                const char *cmd)
> {
>    int retval;
> diff --git a/doc/libext2fs.texinfo b/doc/libext2fs.texinfo
> index d607396..5785f50 100644
> --- a/doc/libext2fs.texinfo
> +++ b/doc/libext2fs.texinfo
> @@ -426,7 +426,7 @@ opened via inode numbers instead of via pathnames.  To resolve a
> pathname to an inode number, use the function @code{ext2fs_namei} or to
> create a new file, use @code{ext2fs_new_inode} and @code{ext2fs_link}.
> 
> -@deftypefun errcode_t ext2fs_file_open2 (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode *@var{inode}, int @var{flags}, ext2_file_t *@var{ret})
> +@deftypefun errcode_t ext2fs_file_open2 (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode_large *@var{inode}, int @var{flags}, ext2_file_t *@var{ret})
> @deftypefunx errcode_t ext2fs_file_open (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, int @var{flags}, ext2_file_t *@var{ret})
> 
> Opens a file identified by inode number @var{ino} in filesystem @var{fs}
> @@ -538,11 +538,11 @@ Return the size of the file @var{file}.
> @comment  node-name,  next,  previous,  up
> @subsection Reading and writing inodes
> 
> -@deftypefun errcode_t ext2fs_read_inode (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode *@var{inode})
> +@deftypefun errcode_t ext2fs_read_inode (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode_large *@var{inode})
> Read the inode number @var{ino} into @var{inode}.
> @end deftypefun
> 
> -@deftypefun errcode_t ext2fs_write_inode (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode *@var{inode})
> +@deftypefun errcode_t ext2fs_write_inode (ext2_filsys @var{fs}, ext2_ino_t @var{ino}, struct ext2_inode_large *@var{inode})
> Write @var{inode} to inode @var{ino}.
> @end deftypefun
> 
> @@ -569,7 +569,7 @@ suitable default value will be used.
> Release the memory associated with @var{scan} and invalidate it.
> @end deftypefun
> 
> -@deftypefun errcode_t ext2fs_get_next_inode (ext2_inode_scan @var{scan}, ext2_ino_t *@var{ino}, struct ext2_inode *@var{inode})
> +@deftypefun errcode_t ext2fs_get_next_inode (ext2_inode_scan @var{scan}, ext2_ino_t *@var{ino}, struct ext2_inode_large *@var{inode})
> 
> This function returns the next inode from the filesystem; the inode
> number of the inode is stored in @var{ino}, and the inode is stored in
> @@ -712,7 +712,7 @@ inode structure.
> Returns 0 if @var{ino} is a directory, and @code{ENOTDIR} if it is not.
> @end deftypefun
> 
> -@deftypefun int ext2fs_inode_has_valid_blocks (struct ext2_inode *@var{inode})
> +@deftypefun int ext2fs_inode_has_valid_blocks (struct ext2_inode_large *@var{inode})
> 
> Returns 1 if the inode's block entries actually valid block entries, and
> 0 if not.  Inodes which represent devices and fast symbolic links do not
> @@ -1281,7 +1281,7 @@ intended for debugging and testing use only.
> @deftypefun void ext2fs_swap_group_desc (struct ext2_group_desc *@var{gdp})
> @end deftypefun
> 
> -@deftypefun void ext2fs_swap_inode (ext2_filsys @var{fs}, struct ext2_inode *@var{to}, struct ext2_inode *@var{from}, int @var{hostorder})
> +@deftypefun void ext2fs_swap_inode (ext2_filsys @var{fs}, struct ext2_inode_large *@var{to}, struct ext2_inode_large *@var{from}, int @var{hostorder})
> @end deftypefun
> 
> @deftypefun int ext2fs_native_flag (void)
> diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
> index b4a1a88..d515a9d 100644
> --- a/e2fsck/e2fsck.h
> +++ b/e2fsck/e2fsck.h
> @@ -267,7 +267,7 @@ struct e2fsck_struct {
>     * For pass1_check_directory and pass1_get_blocks
>     */
>    ext2_ino_t stashed_ino;
> -    struct ext2_inode *stashed_inode;
> +    struct ext2_inode_large *stashed_inode;
> 
>    /*
>     * Location of the lost and found directory
> @@ -446,11 +446,12 @@ extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags,
>                    ext2_icount_t *ret);
> extern void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
> extern int e2fsck_pass1_check_device_inode(ext2_filsys fs,
> -                       struct ext2_inode *inode);
> +                       struct ext2_inode_large *inode);
> extern int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
> -                      struct ext2_inode *inode, char *buf);
> +                      struct ext2_inode_large *inode,
> +                      char *buf);
> extern void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
> -                   struct ext2_inode *inode, int restart_flag,
> +                   struct ext2_inode_large *inode, int restart_flag,
>                   const char *source);
> 
> /* pass2.c */
> @@ -505,17 +506,19 @@ extern void init_resource_track(struct resource_track *track,
> #define print_resource_track(ctx, desc, track, channel) do { } while (0)
> #define init_resource_track(track, channel) do { } while (0)
> #endif
> -extern int inode_has_valid_blocks(struct ext2_inode *inode);
> +extern int inode_has_valid_blocks(struct ext2_inode_large *inode);
> extern void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
> -                  struct ext2_inode * inode, const char * proc);
> +                  struct ext2_inode_large *inode,
> +                  const char *proc);
> extern void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
> -                   struct ext2_inode *inode,
> +                   struct ext2_inode_large *inode,
>                   const int bufsize, const char *proc);
> extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
> -                   struct ext2_inode * inode, const char * proc);
> +                   struct ext2_inode_large *inode,
> +                   const char *proc);
> extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
> -                               struct ext2_inode * inode, int bufsize,
> -                               const char *proc);
> +                    struct ext2_inode_large *inode, int bufsize,
> +                    const char *proc);
> #ifdef MTRACE
> extern void mtrace_print(char *mesg);
> #endif
> diff --git a/e2fsck/emptydir.c b/e2fsck/emptydir.c
> index cf9b521..2ae5dcc 100644
> --- a/e2fsck/emptydir.c
> +++ b/e2fsck/emptydir.c
> @@ -24,7 +24,7 @@ struct empty_dir_info_struct {
>    ext2fs_inode_bitmap dir_map;
>    char *block_buf;
>    ext2_ino_t ino;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    blk64_t    logblk;
>    blk64_t    freed_blocks;
> };
> diff --git a/e2fsck/iscan.c b/e2fsck/iscan.c
> index 84e2cc1..8cae736 100644
> --- a/e2fsck/iscan.c
> +++ b/e2fsck/iscan.c
> @@ -99,7 +99,7 @@ int main (int argc, char *argv[])
>    ext2_filsys    fs;
>    ext2_ino_t    ino;
>    __u32    num_inodes = 0;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    ext2_inode_scan    scan;
> 
>    init_resource_track(&global_rtrack);
> diff --git a/e2fsck/jfs_user.h b/e2fsck/jfs_user.h
> index 2bb71c3..2fada54 100644
> --- a/e2fsck/jfs_user.h
> +++ b/e2fsck/jfs_user.h
> @@ -28,7 +28,7 @@ struct buffer_head {
> struct inode {
>    e2fsck_t    i_ctx;
>    ext2_ino_t    i_ino;
> -    struct ext2_inode i_ext2;
> +    struct ext2_inode_large i_ext2;
> };
> 
> struct kdev_s {
> diff --git a/e2fsck/journal.c b/e2fsck/journal.c
> index 6d350ee..0e2816f 100644
> --- a/e2fsck/journal.c
> +++ b/e2fsck/journal.c
> @@ -285,7 +285,8 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
>            if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
>                tried_backup_jnl)
>                goto errout;
> -            memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
> +            memset(&j_inode->i_ext2, 0,
> +                   sizeof(struct ext2_inode_large));
>            memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
>                   EXT2_N_BLOCKS*4);
>            j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15];
> @@ -912,7 +913,7 @@ void e2fsck_move_ext3_journal(e2fsck_t ctx)
> {
>    struct ext2_super_block *sb = ctx->fs->super;
>    struct problem_context    pctx;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    ext2_filsys        fs = ctx->fs;
>    ext2_ino_t        ino;
>    errcode_t        retval;
> diff --git a/e2fsck/message.c b/e2fsck/message.c
> index c456752..753dd26 100644
> --- a/e2fsck/message.c
> +++ b/e2fsck/message.c
> @@ -261,7 +261,7 @@ static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
> static _INLINE_ void expand_inode_expression(ext2_filsys fs, char ch,
>                         struct problem_context *ctx)
> {
> -    struct ext2_inode    *inode;
> +    struct ext2_inode_large    *inode;
>    struct ext2_inode_large    *large_inode;
> 
>    if (!ctx || !ctx->inode)
> diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> index fe5dd9b..ba17b30 100644
> --- a/e2fsck/pass1.c
> +++ b/e2fsck/pass1.c
> @@ -86,7 +86,7 @@ struct process_block_struct {
>    e2_blkcnt_t    last_db_block;
>    int        num_illegal_blocks;
>    blk64_t        previous_block;
> -    struct ext2_inode *inode;
> +    struct ext2_inode_large *inode;
>    struct problem_context *pctx;
>    ext2fs_block_bitmap fs_meta_blocks;
>    e2fsck_t    ctx;
> @@ -94,7 +94,7 @@ struct process_block_struct {
> 
> struct process_inode_block {
>    ext2_ino_t ino;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
> };
> 
> struct scan_callback_struct {
> @@ -130,7 +130,7 @@ static void unwind_pass1(ext2_filsys fs EXT2FS_ATTR((unused)))
>  * zero.
>  */
> int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
> -                    struct ext2_inode *inode)
> +                    struct ext2_inode_large *inode)
> {
>    int    i;
> 
> @@ -165,7 +165,7 @@ int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
>  * checks out, 0 if not.
>  */
> int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
> -                   struct ext2_inode *inode, char *buf)
> +                   struct ext2_inode_large *inode, char *buf)
> {
>    unsigned int len;
>    int i;
> @@ -254,7 +254,7 @@ static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
>  */
> static void check_size(e2fsck_t ctx, struct problem_context *pctx)
> {
> -    struct ext2_inode *inode = pctx->inode;
> +    struct ext2_inode_large *inode = pctx->inode;
> 
>    if (EXT2_I_SIZE(inode) == 0)
>        return;
> @@ -400,7 +400,7 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
> static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
>                char *buf)
> {
> -    struct ext2_inode *inode = pctx->inode;
> +    struct ext2_inode_large *inode = pctx->inode;
>    struct ext2_dir_entry    *dirent;
>    const char        *old_op;
>    errcode_t        retval;
> @@ -546,7 +546,7 @@ void e2fsck_pass1(e2fsck_t ctx)
>    __u64    max_sizes;
>    ext2_filsys fs = ctx->fs;
>    ext2_ino_t    ino;
> -    struct ext2_inode *inode;
> +    struct ext2_inode_large *inode;
>    ext2_inode_scan    scan;
>    char        *block_buf;
> #ifdef RESOURCE_TRACK
> @@ -637,8 +637,9 @@ void e2fsck_pass1(e2fsck_t ctx)
>        return;
>    }
>    inode_size = EXT2_INODE_SIZE(fs->super);
> -    inode = (struct ext2_inode *)
> -        e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
> +    if (sizeof(struct ext2_inode_large) > inode_size)
> +        inode_size = sizeof(struct ext2_inode_large);
> +    inode = e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
> 
>    inodes_to_process = (struct process_inode_block *)
>        e2fsck_allocate_memory(ctx,
> @@ -1212,7 +1213,7 @@ static errcode_t scan_callback(ext2_filsys fs,
> static void process_inodes(e2fsck_t ctx, char *block_buf)
> {
>    int            i;
> -    struct ext2_inode    *old_stashed_inode;
> +    struct ext2_inode_large    *old_stashed_inode;
>    ext2_ino_t        old_stashed_ino;
>    const char        *old_operation;
>    char            buf[80];
> @@ -1421,7 +1422,7 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
> {
>    ext2_filsys fs = ctx->fs;
>    ext2_ino_t    ino = pctx->ino;
> -    struct ext2_inode *inode = pctx->inode;
> +    struct ext2_inode_large *inode = pctx->inode;
>    blk64_t        blk;
>    char *        end;
>    struct ext2_ext_attr_header *header;
> @@ -1599,7 +1600,7 @@ clear_extattr:
> 
> /* Returns 1 if bad htree, 0 if OK */
> static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
> -            ext2_ino_t ino, struct ext2_inode *inode,
> +            ext2_ino_t ino, struct ext2_inode_large *inode,
>            char *block_buf)
> {
>    struct ext2_dx_root_info    *root;
> @@ -1656,7 +1657,7 @@ static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
> }
> 
> void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
> -            struct ext2_inode *inode, int restart_flag,
> +            struct ext2_inode_large *inode, int restart_flag,
>            const char *source)
> {
>    inode->i_flags = 0;
> @@ -1841,7 +1842,7 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
>                 struct process_block_struct *pb)
> {
>    struct ext2_extent_info info;
> -    struct ext2_inode    *inode = pctx->inode;
> +    struct ext2_inode_large    *inode = pctx->inode;
>    ext2_extent_handle_t    ehandle;
>    ext2_filsys        fs = ctx->fs;
>    ext2_ino_t        ino = pctx->ino;
> @@ -1885,7 +1886,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
>    ext2_filsys fs = ctx->fs;
>    struct process_block_struct pb;
>    ext2_ino_t    ino = pctx->ino;
> -    struct ext2_inode *inode = pctx->inode;
> +    struct ext2_inode_large *inode = pctx->inode;
>    int        bad_size = 0;
>    int        dirty_inode = 0;
>    int        extent_fs;
> @@ -2671,7 +2672,7 @@ static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
> }
> 
> static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
> -                  struct ext2_inode *inode)
> +                  struct ext2_inode_large *inode)
> {
>    e2fsck_t ctx = (e2fsck_t) fs->priv_data;
> 
> @@ -2682,7 +2683,7 @@ static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
> }
> 
> static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
> -                struct ext2_inode *inode)
> +                struct ext2_inode_large *inode)
> {
>    e2fsck_t ctx = (e2fsck_t) fs->priv_data;
> 
> diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
> index 12a03b0..efa68c7 100644
> --- a/e2fsck/pass1b.c
> +++ b/e2fsck/pass1b.c
> @@ -78,7 +78,7 @@ struct dup_cluster {
> struct dup_inode {
>    ext2_ino_t        dir;
>    int            num_dupblocks;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    struct cluster_el    *cluster_list;
> };
> 
> @@ -117,7 +117,7 @@ static int dict_int_cmp(const void *a, const void *b)
>  * Add a duplicate block record
>  */
> static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk64_t cluster,
> -             struct ext2_inode *inode)
> +             struct ext2_inode_large *inode)
> {
>    dnode_t    *n;
>    struct dup_cluster    *db;
> @@ -258,7 +258,7 @@ struct process_block_struct {
>    e2fsck_t    ctx;
>    ext2_ino_t    ino;
>    int        dup_blocks;
> -    struct ext2_inode *inode;
> +    struct ext2_inode_large *inode;
>    struct problem_context *pctx;
> };
> 
> @@ -266,7 +266,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
> {
>    ext2_filsys fs = ctx->fs;
>    ext2_ino_t ino;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    ext2_inode_scan    scan;
>    struct process_block_struct pb;
>    struct problem_context pctx;
> @@ -606,7 +606,7 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
> {
>    ext2_filsys fs = ctx->fs;
>    struct process_block_struct pb;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    struct problem_context    pctx;
>    unsigned int        count;
> 
> diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
> index 2863699..9241a07 100644
> --- a/e2fsck/pass2.c
> +++ b/e2fsck/pass2.c
> @@ -479,7 +479,7 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
> {
>    int    filetype = dirent->name_len >> 8;
>    int    should_be = EXT2_FT_UNKNOWN;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
> 
>    if (!(ctx->fs->super->s_feature_incompat &
>          EXT2_FEATURE_INCOMPAT_FILETYPE)) {
> @@ -1178,7 +1178,7 @@ static int deallocate_inode_block(ext2_filsys fs,
> static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
> {
>    ext2_filsys fs = ctx->fs;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    struct problem_context    pctx;
>    __u32            count;
> 
> @@ -1237,7 +1237,7 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
>  */
> static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
> {
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
> 
>    e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
>    inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
> @@ -1251,7 +1251,7 @@ extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
>                    ext2_ino_t ino, char *buf)
> {
>    ext2_filsys fs = ctx->fs;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    int            inode_modified = 0;
>    int            not_fixed = 0;
>    unsigned char        *frag, *fsize;
> @@ -1404,7 +1404,7 @@ static int allocate_dir_block(e2fsck_t ctx,
>    ext2_filsys fs = ctx->fs;
>    blk64_t            blk;
>    char            *block;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
> 
>    if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
>        return 1;
> diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> index c067164..2330aab 100644
> --- a/e2fsck/pass3.c
> +++ b/e2fsck/pass3.c
> @@ -142,7 +142,7 @@ static void check_root(e2fsck_t ctx)
> {
>    ext2_filsys fs = ctx->fs;
>    blk64_t            blk;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    char *            block;
>    struct problem_context    pctx;
> 
> @@ -357,7 +357,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
>    ext2_ino_t            ino;
>    blk64_t            blk;
>    errcode_t        retval;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    char *            block;
>    static const char    name[] = "lost+found";
>    struct    problem_context    pctx;
> @@ -503,7 +503,7 @@ int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
>    errcode_t    retval;
>    char        name[80];
>    struct problem_context    pctx;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    int        file_type = 0;
> 
>    clear_problem_context(&pctx);
> @@ -552,7 +552,7 @@ errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
> {
>    ext2_filsys fs = ctx->fs;
>    errcode_t        retval;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
> 
>    if (!ino)
>        return 0;
> @@ -753,7 +753,7 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
>    ext2_filsys fs = ctx->fs;
>    errcode_t    retval;
>    struct expand_dir_struct es;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
> 
>    if (!(fs->flags & EXT2_FLAG_RW))
>        return EXT2_ET_RO_FILSYS;
> diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
> index 695612b..566854f 100644
> --- a/e2fsck/pass4.c
> +++ b/e2fsck/pass4.c
> @@ -25,7 +25,7 @@
>  * rest of the pass 4 tests.
>  */
> static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
> -                struct ext2_inode *inode)
> +                struct ext2_inode_large *inode)
> {
>    ext2_filsys fs = ctx->fs;
>    struct problem_context    pctx;
> @@ -90,7 +90,7 @@ void e2fsck_pass4(e2fsck_t ctx)
> {
>    ext2_filsys fs = ctx->fs;
>    ext2_ino_t    i;
> -    struct ext2_inode    *inode;
> +    struct ext2_inode_large    *inode;
> #ifdef RESOURCE_TRACK
>    struct resource_track    rtrack;
> #endif
> @@ -98,6 +98,7 @@ void e2fsck_pass4(e2fsck_t ctx)
>    __u16    link_count, link_counted;
>    char    *buf = 0;
>    int    group, maxgroup;
> +    int    inode_size;
> 
>    init_resource_track(&rtrack, ctx->fs->io);
> 
> @@ -116,8 +117,10 @@ void e2fsck_pass4(e2fsck_t ctx)
>        if ((ctx->progress)(ctx, 4, 0, maxgroup))
>            return;
> 
> -    inode = e2fsck_allocate_memory(ctx, EXT2_INODE_SIZE(fs->super),
> -                       "scratch inode");
> +    inode_size = EXT2_INODE_SIZE(fs->super);
> +    if (sizeof(struct ext2_inode_large) > inode_size)
> +        inode_size = sizeof(struct ext2_inode_large);
> +    inode = e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
> 
>    /* Protect loop from wrap-around if s_inodes_count maxed */
>    for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) {
> diff --git a/e2fsck/problem.h b/e2fsck/problem.h
> index 8379e0c..a4d96ae 100644
> --- a/e2fsck/problem.h
> +++ b/e2fsck/problem.h
> @@ -14,7 +14,7 @@ typedef __u32 problem_t;
> struct problem_context {
>    errcode_t    errcode;
>    ext2_ino_t ino, ino2, dir;
> -    struct ext2_inode *inode;
> +    struct ext2_inode_large *inode;
>    struct ext2_dir_entry *dirent;
>    blk64_t    blk, blk2;
>    e2_blkcnt_t    blkcount;
> diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
> index e8af323..1263f56 100644
> --- a/e2fsck/rehash.c
> +++ b/e2fsck/rehash.c
> @@ -53,7 +53,7 @@
> 
> struct fill_dir_struct {
>    char *buf;
> -    struct ext2_inode *inode;
> +    struct ext2_inode_large *inode;
>    int err;
>    e2fsck_t ctx;
>    struct hash_entry *harray;
> @@ -670,7 +670,7 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
> {
>    struct write_dir_struct wd;
>    errcode_t    retval;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
> 
>    retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
>    if (retval)
> @@ -704,7 +704,7 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
> {
>    ext2_filsys        fs = ctx->fs;
>    errcode_t        retval;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    char            *dir_buf = 0;
>    struct fill_dir_struct    fd;
>    struct out_dir        outdir;
> diff --git a/e2fsck/scantest.c b/e2fsck/scantest.c
> index ed586b1..01b243d 100644
> --- a/e2fsck/scantest.c
> +++ b/e2fsck/scantest.c
> @@ -95,7 +95,7 @@ int main (int argc, char *argv[])
>    ext2_filsys    fs;
>    ext2_inode_scan    scan;
>    ext2_ino_t    ino;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
> 
>    printf(_("size of inode=%d\n"), sizeof(inode));
> 
> diff --git a/e2fsck/super.c b/e2fsck/super.c
> index a61eb33..28f041d 100644
> --- a/e2fsck/super.c
> +++ b/e2fsck/super.c
> @@ -151,7 +151,7 @@ static int release_inode_block(ext2_filsys fs,
>  * not deleted.
>  */
> static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
> -                struct ext2_inode *inode, char *block_buf,
> +                struct ext2_inode_large *inode, char *block_buf,
>                struct problem_context *pctx)
> {
>    struct process_block_struct    pb;
> @@ -226,7 +226,7 @@ static int release_orphan_inodes(e2fsck_t ctx)
> {
>    ext2_filsys fs = ctx->fs;
>    ext2_ino_t    ino, next_ino;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    struct problem_context pctx;
>    char *block_buf;
> 
> @@ -308,7 +308,7 @@ return_abort:
> void check_resize_inode(e2fsck_t ctx)
> {
>    ext2_filsys fs = ctx->fs;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    struct problem_context    pctx;
>    int        i, gdt_off, ind_off;
>    dgrp_t        j;
> diff --git a/e2fsck/util.c b/e2fsck/util.c
> index fb9a87a..22e06c2 100644
> --- a/e2fsck/util.c
> +++ b/e2fsck/util.c
> @@ -381,7 +381,7 @@ void print_resource_track(e2fsck_t ctx, const char *desc,
> #endif /* RESOURCE_TRACK */
> 
> void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
> -                  struct ext2_inode * inode, const char *proc)
> +                  struct ext2_inode_large *inode, const char *proc)
> {
>    int retval;
> 
> @@ -394,7 +394,7 @@ void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
> }
> 
> void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
> -                struct ext2_inode *inode, int bufsize,
> +                struct ext2_inode_large *inode, int bufsize,
>                const char *proc)
> {
>    int retval;
> @@ -408,7 +408,7 @@ void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
> }
> 
> extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
> -                   struct ext2_inode * inode, int bufsize,
> +                   struct ext2_inode_large *inode, int bufsize,
>                   const char *proc)
> {
>    int retval;
> @@ -422,7 +422,7 @@ extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
> }
> 
> extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
> -                   struct ext2_inode * inode, const char *proc)
> +                   struct ext2_inode_large *inode, const char *proc)
> {
>    int retval;
> 
> diff --git a/ext2ed/dir_com.c b/ext2ed/dir_com.c
> index b023e7a..8c49af3 100644
> --- a/ext2ed/dir_com.c
> +++ b/ext2ed/dir_com.c
> @@ -48,7 +48,7 @@ directories.
> */
> 
> {
> -    struct ext2_inode *ptr;
> +    struct ext2_inode_large *ptr;
> 
>    ptr=&type_data.u.t_ext2_inode;                    /* type_data contains the inode */
> 
> diff --git a/ext2ed/doc/ext2ed-design.sgml b/ext2ed/doc/ext2ed-design.sgml
> index ad2df96..7f42a1a 100644
> --- a/ext2ed/doc/ext2ed-design.sgml
> +++ b/ext2ed/doc/ext2ed-design.sgml
> @@ -1955,7 +1955,7 @@ struct struct_type_data {
>        struct ext2_acl_entry t_ext2_acl_entry;
>        struct ext2_old_group_desc t_ext2_old_group_desc;
>        struct ext2_group_desc t_ext2_group_desc;
> -        struct ext2_inode t_ext2_inode;
> +        struct ext2_inode_large t_ext2_inode;
>        struct ext2_super_block t_ext2_super_block;
>        struct ext2_dir_entry t_ext2_dir_entry;
>    } u;
> @@ -2703,7 +2703,7 @@ directory.
> <Para>
> 
> <ProgramListing>
> -struct ext2_inode {
> +struct ext2_inode_large {
>    __u16    i_mode;        /* File mode */
>    __u16    i_uid;        /* Owner Uid */
>    __u32    i_size;        /* Size in bytes */
> @@ -2873,7 +2873,7 @@ initialized:
> <ProgramListing>
> struct struct_file_info {
> 
> -    struct ext2_inodes *inode_ptr;
> +    struct ext2_inode_larges *inode_ptr;
>    
>    long inode_offset;
>    long global_block_num,global_block_offset;
> diff --git a/ext2ed/doc/ext2fs-overview.sgml b/ext2ed/doc/ext2fs-overview.sgml
> index a6ebf5a..119cc26 100644
> --- a/ext2ed/doc/ext2fs-overview.sgml
> +++ b/ext2ed/doc/ext2fs-overview.sgml
> @@ -461,7 +461,7 @@ Follows the structure of an inode in Ext2fs:
> <Para>
> 
> <ProgramListing>
> -struct ext2_inode {
> +struct ext2_inode_large {
>    __u16    i_mode;        /* File mode */
>    __u16    i_uid;        /* Owner Uid */
>    __u32    i_size;        /* Size in bytes */
> diff --git a/ext2ed/ext2.descriptors b/ext2ed/ext2.descriptors
> index bf927b0..abd81f6 100644
> --- a/ext2ed/ext2.descriptors
> +++ b/ext2ed/ext2.descriptors
> @@ -72,7 +72,7 @@ struct ext2_group_desc
> /*
>  * Structure of an inode on the disk
>  */
> -struct ext2_inode {
> +struct ext2_inode_large {
>    __u16 i_mode;        /* File mode */
>    __u16 i_uid;        /* Owner Uid */
>    __u32  i_size;        /* Size in bytes */
> diff --git a/ext2ed/ext2ed.h b/ext2ed/ext2ed.h
> index 2ee483e..32161f5 100644
> --- a/ext2ed/ext2ed.h
> +++ b/ext2ed/ext2ed.h
> @@ -112,7 +112,7 @@ struct struct_type_data {                /* The object's data is usually here */
>        struct ext2_acl_header t_ext2_acl_header;
>        struct ext2_acl_entry t_ext2_acl_entry;
>        struct ext2_group_desc t_ext2_group_desc;
> -        struct ext2_inode t_ext2_inode;
> +        struct ext2_inode_large t_ext2_inode;
>        struct ext2_super_block t_ext2_super_block;
>        struct ext2_dir_entry t_ext2_dir_entry;
>    } u;
> @@ -132,7 +132,7 @@ struct struct_file_system_info {            /* Important information about the filesystem
> 
> struct struct_file_info {                /* Used to handle files and directories */
> 
> -    struct ext2_inode *inode_ptr;
> +    struct ext2_inode_large *inode_ptr;
> 
>    long inode_offset;
>    long global_block_num,global_block_offset;
> diff --git a/ext2ed/file_com.c b/ext2ed/file_com.c
> index 9772f66..0fdedaf 100644
> --- a/ext2ed/file_com.c
> +++ b/ext2ed/file_com.c
> @@ -23,7 +23,7 @@ Copyright (C) 1995 Gadi Oxman
> int init_file_info (void)
> 
> {
> -    struct ext2_inode *ptr;
> +    struct ext2_inode_large *ptr;
> 
>    ptr=&type_data.u.t_ext2_inode;
> 
> diff --git a/ext2ed/init.c b/ext2ed/init.c
> index 3815ab5..af47cd2 100644
> --- a/ext2ed/init.c
> +++ b/ext2ed/init.c
> @@ -418,7 +418,7 @@ int set_file_system_info (void)
>        file_system_info.groups_count = ext2fs_div64_ceil(ext2fs_blocks_count(sb),
>                         sb->s_blocks_per_group);
> 
> -        file_system_info.inodes_per_block=file_system_info.block_size/sizeof (struct ext2_inode);
> +        file_system_info.inodes_per_block=file_system_info.block_size/EXT2_GOOD_OLD_INODE_SIZE;
>        file_system_info.blocks_per_group=sb->s_inodes_per_group/file_system_info.inodes_per_block;
>        file_system_info.no_blocks_in_group=sb->s_blocks_per_group;
>        file_system_info.file_system_size=(ext2fs_blocks_count(sb)-1)*file_system_info.block_size;
> diff --git a/ext2ed/inode_com.c b/ext2ed/inode_com.c
> index 8d4b9f3..b2fa692 100644
> --- a/ext2ed/inode_com.c
> +++ b/ext2ed/inode_com.c
> @@ -43,13 +43,13 @@ void type_ext2_inode___prev (char *command_line)
> 
>    low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
> 
> -    entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
> +    entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/EXT2_GOOD_OLD_INODE_SIZE;
> 
>    first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
>    inode_num=0;
> 
>    if (entry_num-mult+1>0) {
> -        device_offset-=sizeof (struct ext2_inode)*mult;
> +        device_offset-=sizeof (struct ext2_inode_large)*mult;
>        entry_num-=mult;
> 
>        sprintf (buffer,"setoffset %ld",device_offset);dispatch (buffer);
> @@ -91,13 +91,13 @@ void type_ext2_inode___next (char *command_line)
> 
>    low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
> 
> -    entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
> +    entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/EXT2_GOOD_OLD_INODE_SIZE;
> 
>    first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
>    inode_num=0;
> 
>    if (entry_num+mult-1<last_entry) {
> -        device_offset+=sizeof (struct ext2_inode)*mult;
> +        device_offset+=sizeof (struct ext2_inode_large)*mult;
>        entry_num+=mult;
> 
>        sprintf (buffer,"setoffset %ld",device_offset);dispatch (buffer);
> @@ -118,7 +118,7 @@ void type_ext2_inode___next (char *command_line)
> void type_ext2_inode___show (char *command_line)
> 
> {
> -    struct ext2_inode *inode_ptr;
> +    struct ext2_inode_large *inode_ptr;
> 
>    unsigned short temp;
>    int i;
> @@ -133,7 +133,7 @@ void type_ext2_inode___show (char *command_line)
> 
>    low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
> 
> -    entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
> +    entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/EXT2_GOOD_OLD_INODE_SIZE;
>    first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
>    inode_num=group_num*file_system_info.super_block.s_inodes_per_group+1;
>    inode_num+=entry_num;
> @@ -299,7 +299,7 @@ void type_ext2_inode___entry (char *command_line)
> 
>    low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
> 
> -    entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
> +    entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/EXT2_GOOD_OLD_INODE_SIZE;
> 
>    if (wanted_entry > entry_num) {
>        sprintf (buffer,"next %ld",wanted_entry-entry_num);
> @@ -409,7 +409,7 @@ long int inode_offset_to_inode_num (long inode_offset)
> 
>    low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
> 
> -    entry_num=(inode_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
> +    entry_num=(inode_offset-desc.bg_inode_table*file_system_info.block_size)/EXT2_GOOD_OLD_INODE_SIZE;
>    first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
>    inode_num=group_num*file_system_info.super_block.s_inodes_per_group+1;
>    inode_num+=entry_num;
> @@ -430,7 +430,7 @@ long int inode_num_to_inode_offset (long inode_num)
>    group_offset=file_system_info.first_group_desc_offset+group_num*sizeof (struct ext2_group_desc);
>    low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
> 
> -    inode_offset=desc.bg_inode_table*file_system_info.block_size+inode_entry*sizeof (struct ext2_inode);
> +    inode_offset=desc.bg_inode_table*file_system_info.block_size+inode_entry*EXT2_GOOD_OLD_INODE_SIZE;
> 
>    return (inode_offset);
> }
> diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c
> index 0f36f40..aa4a389 100644
> --- a/lib/e2p/ls.c
> +++ b/lib/e2p/ls.c
> @@ -188,7 +188,7 @@ static __u64 e2p_free_blocks_count(struct ext2_super_block *super)
> }
> 
> #ifndef EXT2_INODE_SIZE
> -#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode)
> +#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode_large)
> #endif
> 
> #ifndef EXT2_GOOD_OLD_REV
> diff --git a/lib/ext2fs/bb_inode.c b/lib/ext2fs/bb_inode.c
> index 0b6c3dd..dbc29d6 100644
> --- a/lib/ext2fs/bb_inode.c
> +++ b/lib/ext2fs/bb_inode.c
> @@ -58,7 +58,7 @@ errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
> {
>    errcode_t            retval;
>    struct set_badblock_record    rec;
> -    struct ext2_inode        inode;
> +    struct ext2_inode_large        inode;
> 
>    EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
> 
> diff --git a/lib/ext2fs/blknum.c b/lib/ext2fs/blknum.c
> index b3e6dca..7e7fcd8 100644
> --- a/lib/ext2fs/blknum.c
> +++ b/lib/ext2fs/blknum.c
> @@ -46,7 +46,7 @@ blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group)
>  * Return the inode data block count
>  */
> blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
> -                    struct ext2_inode *inode)
> +                    struct ext2_inode_large *inode)
> {
>    return (inode->i_blocks |
>        ((fs->super->s_feature_ro_compat &
> @@ -59,7 +59,7 @@ blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
>  * Return the inode i_blocks count
>  */
> blk64_t ext2fs_inode_i_blocks(ext2_filsys fs,
> -                    struct ext2_inode *inode)
> +                    struct ext2_inode_large *inode)
> {
>    return (inode->i_blocks |
>        ((fs->super->s_feature_ro_compat &
> @@ -460,7 +460,7 @@ void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum)
>  * called don't have access to the fs struct, and the high bits should
>  * be 0 in the non-64-bit case anyway.
>  */
> -blk64_t ext2fs_file_acl_block(const struct ext2_inode *inode)
> +blk64_t ext2fs_file_acl_block(const struct ext2_inode_large *inode)
> {
>    return (inode->i_file_acl |
>        (__u64) inode->osd2.linux2.l_i_file_acl_high << 32);
> @@ -469,7 +469,7 @@ blk64_t ext2fs_file_acl_block(const struct ext2_inode *inode)
> /*
>  * Set the acl block of a file
>  */
> -void ext2fs_file_acl_block_set(struct ext2_inode *inode, blk64_t blk)
> +void ext2fs_file_acl_block_set(struct ext2_inode_large *inode, blk64_t blk)
> {
>    inode->i_file_acl = blk;
>    inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32;
> diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
> index 95ad31e..f193dc2 100644
> --- a/lib/ext2fs/block.c
> +++ b/lib/ext2fs/block.c
> @@ -331,7 +331,7 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
> {
>    int    i;
>    int    r, ret = 0;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    errcode_t    retval;
>    struct block_context ctx;
>    int    limit;
> diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
> index 7a515be..26f2074 100644
> --- a/lib/ext2fs/bmap.c
> +++ b/lib/ext2fs/bmap.c
> @@ -26,7 +26,7 @@
> #endif
> 
> extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
> -                 struct ext2_inode *inode,
> +                 struct ext2_inode_large *inode,
>                 char *block_buf, int bmap_flags,
>                 blk_t block, blk_t *phys_blk);
> 
> @@ -130,14 +130,14 @@ static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
> }
> 
> static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
> -                 struct ext2_inode *inode,
> +                 struct ext2_inode_large *inode,
>                 ext2_extent_handle_t handle,
>                 char *block_buf, int bmap_flags, blk64_t block,
>                 int *ret_flags, int *blocks_alloc,
>                 blk64_t *phys_blk);
> 
> static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
> -                       struct ext2_inode *inode,
> +                       struct ext2_inode_large *inode,
>                       ext2_extent_handle_t handle,
>                       blk64_t block, blk64_t *phys_blk)
> {
> @@ -164,7 +164,7 @@ static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
> }
> 
> static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
> -                 struct ext2_inode *inode,
> +                 struct ext2_inode_large *inode,
>                 ext2_extent_handle_t handle,
>                 char *block_buf, int bmap_flags, blk64_t block,
>                 int *ret_flags, int *blocks_alloc,
> @@ -229,11 +229,12 @@ got_block:
> }
> 
> 
> -errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
> +errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino,
> +               struct ext2_inode_large *inode,
>               char *block_buf, int bmap_flags, blk64_t block,
>               int *ret_flags, blk64_t *phys_blk)
> {
> -    struct ext2_inode inode_buf;
> +    struct ext2_inode_large inode_buf;
>    ext2_extent_handle_t handle = 0;
>    blk_t addr_per_block;
>    blk_t    b, blk32;
> @@ -379,7 +380,8 @@ done:
>    return retval;
> }
> 
> -errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
> +errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
> +              struct ext2_inode_large *inode,
>              char *block_buf, int bmap_flags, blk_t block,
>              blk_t *phys_blk)
> {
> diff --git a/lib/ext2fs/bmove.c b/lib/ext2fs/bmove.c
> index deabf38..1443f57 100644
> --- a/lib/ext2fs/bmove.c
> +++ b/lib/ext2fs/bmove.c
> @@ -27,7 +27,7 @@
> 
> struct process_block_struct {
>    ext2_ino_t        ino;
> -    struct ext2_inode *    inode;
> +    struct ext2_inode_large    *inode;
>    ext2fs_block_bitmap    reserve;
>    ext2fs_block_bitmap    alloc_map;
>    errcode_t        error;
> @@ -99,7 +99,7 @@ errcode_t ext2fs_move_blocks(ext2_filsys fs,
>                 int flags)
> {
>    ext2_ino_t    ino;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    errcode_t    retval;
>    struct process_block_struct pb;
>    ext2_inode_scan    scan;
> diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
> index 8f738c8..ee90970 100644
> --- a/lib/ext2fs/expanddir.c
> +++ b/lib/ext2fs/expanddir.c
> @@ -91,7 +91,7 @@ errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
> {
>    errcode_t    retval;
>    struct expand_dir_struct es;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
> 
>    EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
> 
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index 54cb3d4..e342bf0 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -329,53 +329,6 @@ struct ext4_new_group_input {
> #define EXT4_IOC_GROUP_ADD        _IOW('f', 8,struct ext4_new_group_input)
> 
> /*
> - * Structure of an inode on the disk
> - */
> -struct ext2_inode {
> -    __u16    i_mode;        /* File mode */
> -    __u16    i_uid;        /* Low 16 bits of Owner Uid */
> -    __u32    i_size;        /* Size in bytes */
> -    __u32    i_atime;    /* Access time */
> -    __u32    i_ctime;    /* Inode change time */
> -    __u32    i_mtime;    /* Modification time */
> -    __u32    i_dtime;    /* Deletion Time */
> -    __u16    i_gid;        /* Low 16 bits of Group Id */
> -    __u16    i_links_count;    /* Links count */
> -    __u32    i_blocks;    /* Blocks count */
> -    __u32    i_flags;    /* File flags */
> -    union {
> -        struct {
> -            __u32    l_i_version; /* was l_i_reserved1 */
> -        } linux1;
> -        struct {
> -            __u32  h_i_translator;
> -        } hurd1;
> -    } osd1;                /* OS dependent 1 */
> -    __u32    i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
> -    __u32    i_generation;    /* File version (for NFS) */
> -    __u32    i_file_acl;    /* File ACL */
> -    __u32    i_size_high;    /* Formerly i_dir_acl, directory ACL */
> -    __u32    i_faddr;    /* Fragment address */
> -    union {
> -        struct {
> -            __u16    l_i_blocks_hi;
> -            __u16    l_i_file_acl_high;
> -            __u16    l_i_uid_high;    /* these 2 fields    */
> -            __u16    l_i_gid_high;    /* were reserved2[0] */
> -            __u32    l_i_reserved2;
> -        } linux2;
> -        struct {
> -            __u8    h_i_frag;    /* Fragment number */
> -            __u8    h_i_fsize;    /* Fragment size */
> -            __u16    h_i_mode_high;
> -            __u16    h_i_uid_high;
> -            __u16    h_i_gid_high;
> -            __u32    h_i_author;
> -        } hurd2;
> -    } osd2;                /* OS dependent 2 */
> -};
> -
> -/*
>  * Permanent part of an large inode on the disk
>  */
> struct ext2_inode_large {
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index dc83fb0..b290a1f 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -229,9 +229,9 @@ struct struct_ext2_filsys {
>    errcode_t (*check_directory)(ext2_filsys fs, ext2_ino_t ino);
>    errcode_t (*write_bitmaps)(ext2_filsys fs);
>    errcode_t (*read_inode)(ext2_filsys fs, ext2_ino_t ino,
> -                struct ext2_inode *inode);
> +                struct ext2_inode_large *inode);
>    errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino,
> -                struct ext2_inode *inode);
> +                struct ext2_inode_large *inode);
>    ext2_badblocks_list        badblocks;
>    ext2_dblist            dblist;
>    __u32                stride;    /* for mke2fs */
> @@ -758,9 +758,9 @@ extern dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t);
> extern blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group);
> extern blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group);
> extern blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
> -                     struct ext2_inode *inode);
> +                     struct ext2_inode_large *inode);
> extern blk64_t ext2fs_inode_i_blocks(ext2_filsys fs,
> -                     struct ext2_inode *inode);
> +                     struct ext2_inode_large *inode);
> extern blk64_t ext2fs_blocks_count(struct ext2_super_block *super);
> extern void ext2fs_blocks_count_set(struct ext2_super_block *super,
>                    blk64_t blk);
> @@ -807,9 +807,11 @@ extern int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag);
> extern void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags);
> extern void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags);
> extern __u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group);
> -extern void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum);
> -extern blk64_t ext2fs_file_acl_block(const struct ext2_inode *inode);
> -extern void ext2fs_file_acl_block_set(struct ext2_inode *inode, blk64_t blk);
> +extern void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group,
> +                   __u16 checksum);
> +extern blk64_t ext2fs_file_acl_block(const struct ext2_inode_large *inode);
> +extern void ext2fs_file_acl_block_set(struct ext2_inode_large *inode,
> +                      blk64_t blk);
> 
> /* block.c */
> extern errcode_t ext2fs_block_iterate(ext2_filsys fs,
> @@ -846,11 +848,11 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
> 
> /* bmap.c */
> extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
> -                 struct ext2_inode *inode,
> +                 struct ext2_inode_large *inode,
>                 char *block_buf, int bmap_flags,
>                 blk_t block, blk_t *phys_blk);
> extern errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino,
> -                  struct ext2_inode *inode,
> +                  struct ext2_inode_large *inode,
>                  char *block_buf, int bmap_flags, blk64_t block,
>                  int *ret_flags, blk64_t *phys_blk);
> 
> @@ -1017,7 +1019,7 @@ extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);
> extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino,
>                    ext2_extent_handle_t *handle);
> extern errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
> -                    struct ext2_inode *inode,
> +                    struct ext2_inode_large *inode,
>                    ext2_extent_handle_t *ret_handle);
> extern void ext2fs_extent_free(ext2_extent_handle_t handle);
> extern errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
> @@ -1037,12 +1039,12 @@ extern errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
> 
> /* fileio.c */
> extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
> -                   struct ext2_inode *inode,
> +                   struct ext2_inode_large *inode,
>                   int flags, ext2_file_t *ret);
> extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
>                  int flags, ext2_file_t *ret);
> extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file);
> -struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file);
> +struct ext2_inode_large *ext2fs_file_get_inode(ext2_file_t file);
> extern errcode_t ext2fs_file_close(ext2_file_t file);
> extern errcode_t ext2fs_file_flush(ext2_file_t file);
> extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
> @@ -1147,11 +1149,12 @@ errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize);
> errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize);
> 
> /* i_block.c */
> -errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
> +errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode_large *inode,
>                 blk64_t num_blocks);
> -errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
> +errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode_large *inode,
>                 blk64_t num_blocks);
> -errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b);
> +errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode_large *inode,
> +              blk64_t b);
> 
> /* imager.c */
> extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags);
> @@ -1195,13 +1198,13 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
> extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
> extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
>                        ext2_ino_t *ino,
> -                        struct ext2_inode *inode,
> +                        struct ext2_inode_large *inode,
>                        int bufsize);
> extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
>                  ext2_inode_scan *ret_scan);
> extern void ext2fs_close_inode_scan(ext2_inode_scan scan);
> extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
> -                   struct ext2_inode *inode);
> +                   struct ext2_inode_large *inode);
> extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
>                           int    group);
> extern void ext2fs_set_inode_callback
> @@ -1214,17 +1217,17 @@ extern void ext2fs_set_inode_callback
> extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
>                   int clear_flags);
> extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
> -                    struct ext2_inode * inode,
> +                    struct ext2_inode_large *inode,
>                    int bufsize);
> extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
> -                struct ext2_inode * inode);
> +                struct ext2_inode_large *inode);
> extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
> -                     struct ext2_inode * inode,
> +                     struct ext2_inode_large *inode,
>                     int bufsize);
> extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
> -                struct ext2_inode * inode);
> +                struct ext2_inode_large *inode);
> extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
> -                struct ext2_inode * inode);
> +                struct ext2_inode_large *inode);
> extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
> extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino);
> 
> @@ -1233,7 +1236,7 @@ extern io_manager inode_io_manager;
> extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
>                    char **name);
> extern errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
> -                     struct ext2_inode *inode,
> +                     struct ext2_inode_large *inode,
>                     char **name);
> 
> /* ismounted.c */
> @@ -1243,7 +1246,7 @@ extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
> 
> /* punch.c */
> extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
> -                  struct ext2_inode *inode,
> +                  struct ext2_inode_large *inode,
>                  char *block_buf, blk64_t start,
>                  blk64_t end);
> 
> @@ -1341,11 +1344,11 @@ extern void ext2fs_swap_group_desc2(ext2_filsys, struct ext2_group_desc *gdp);
> extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
>                   struct ext2_inode_large *f, int hostorder,
>                   int bufsize);
> -extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
> -                  struct ext2_inode *f, int hostorder);
> +extern void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode_large *t,
> +                  struct ext2_inode_large *f, int hostorder);
> 
> /* valid_blk.c */
> -extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
> +extern int ext2fs_inode_has_valid_blocks(struct ext2_inode_large *inode);
> 
> /* version.c */
> extern int ext2fs_parse_version_string(const char *ver_string);
> @@ -1385,7 +1388,7 @@ extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
> extern blk_t ext2fs_group_first_block(ext2_filsys fs, dgrp_t group);
> extern blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group);
> extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
> -                      struct ext2_inode *inode);
> +                      struct ext2_inode_large *inode);
> extern unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b);
> extern __u64 ext2fs_div64_ceil(__u64 a, __u64 b);
> 
> @@ -1616,7 +1619,7 @@ _INLINE_ blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group)
> }
> 
> _INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
> -                    struct ext2_inode *inode)
> +                    struct ext2_inode_large *inode)
> {
>    return ext2fs_inode_data_blocks2(fs, inode);
> }
> diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
> index b182d7f..27c4332 100644
> --- a/lib/ext2fs/ext2fsP.h
> +++ b/lib/ext2fs/ext2fsP.h
> @@ -73,7 +73,7 @@ struct ext2_inode_cache {
> 
> struct ext2_inode_cache_ent {
>    ext2_ino_t        ino;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
> };
> 
> /* Function prototypes */
> diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
> index abb60dd..33f1a88 100644
> --- a/lib/ext2fs/extent.c
> +++ b/lib/ext2fs/extent.c
> @@ -52,8 +52,8 @@ struct ext2_extent_handle {
>    errcode_t        magic;
>    ext2_filsys        fs;
>    ext2_ino_t        ino;
> -    struct ext2_inode    *inode;
> -    struct ext2_inode    inodebuf;
> +    struct ext2_inode_large    *inode;
> +    struct ext2_inode_large    inodebuf;
>    int            type;
>    int            level;
>    int            max_depth;
> @@ -183,7 +183,7 @@ extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino,
> }
> 
> extern errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
> -                    struct ext2_inode *inode,
> +                    struct ext2_inode_large *inode,
>                    ext2_extent_handle_t *ret_handle)
> {
>    struct ext2_extent_handle    *handle;
> diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
> index 324f046..6d139e5 100644
> --- a/lib/ext2fs/fileio.c
> +++ b/lib/ext2fs/fileio.c
> @@ -22,7 +22,7 @@ struct ext2_file {
>    errcode_t        magic;
>    ext2_filsys        fs;
>    ext2_ino_t        ino;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    int            flags;
>    __u64            pos;
>    blk64_t            blockno;
> @@ -33,7 +33,7 @@ struct ext2_file {
> #define BMAP_BUFFER (file->buf + fs->blocksize)
> 
> errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
> -                struct ext2_inode *inode,
> +                struct ext2_inode_large *inode,
>                int flags, ext2_file_t *ret)
> {
>    ext2_file_t    file;
> @@ -58,7 +58,7 @@ errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
>    file->flags = flags & EXT2_FILE_MASK;
> 
>    if (inode) {
> -        memcpy(&file->inode, inode, sizeof(struct ext2_inode));
> +        memcpy(&file->inode, inode, sizeof(struct ext2_inode_large));
>    } else {
>        retval = ext2fs_read_inode(fs, ino, &file->inode);
>        if (retval)
> @@ -98,7 +98,7 @@ ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
> /*
>  * This function returns the pointer to the inode of a file from the structure
>  */
> -struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file)
> +struct ext2_inode_large *ext2fs_file_get_inode(ext2_file_t file)
> {
>    if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
>        return NULL;
> diff --git a/lib/ext2fs/i_block.c b/lib/ext2fs/i_block.c
> index f36c3c4..1801570 100644
> --- a/lib/ext2fs/i_block.c
> +++ b/lib/ext2fs/i_block.c
> @@ -26,7 +26,7 @@
> #include "ext2_fs.h"
> #include "ext2fs.h"
> 
> -errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
> +errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode_large *inode,
>                 blk64_t num_blocks)
> {
>    unsigned long long b = inode->i_blocks;
> @@ -50,7 +50,7 @@ errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
>    return 0;
> }
> 
> -errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
> +errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode_large *inode,
>                 blk64_t num_blocks)
> {
>    unsigned long long b = inode->i_blocks;
> @@ -75,7 +75,8 @@ errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
>    return 0;
> }
> 
> -errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b)
> +errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode_large *inode,
> +              blk64_t b)
> {
>    if (!(fs->super->s_feature_ro_compat &
>          EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
> diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
> index ccc2dee..96a93b9 100644
> --- a/lib/ext2fs/initialize.c
> +++ b/lib/ext2fs/initialize.c
> @@ -180,7 +180,7 @@ errcode_t ext2fs_initialize(const char *name, int flags,
>    if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
>        set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
>        set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
> -        if (super->s_inode_size >= sizeof(struct ext2_inode_large)) {
> +        if (super->s_inode_size >= EXT2_GOOD_OLD_INODE_SIZE) {
>            int extra_isize = sizeof(struct ext2_inode_large) -
>                EXT2_GOOD_OLD_INODE_SIZE;
>            set_field(s_min_extra_isize, extra_isize);
> diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
> index 829e032..76893fd 100644
> --- a/lib/ext2fs/inode.c
> +++ b/lib/ext2fs/inode.c
> @@ -402,13 +402,17 @@ static inline int is_empty_scan(ext2_inode_scan scan)
> #endif
> 
> errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
> -                     struct ext2_inode *inode, int bufsize)
> +                     struct ext2_inode_large *inode,
> +                     int bufsize)
> {
>    errcode_t    retval;
>    int        extra_bytes = 0;
> 
>    EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
> 
> +    if (bufsize > scan->inode_size)
> +        bufsize = scan->inode_size;
> +
>    /*
>     * Do we need to start reading a new block group?
>     */
> @@ -482,7 +486,7 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
>                   (struct ext2_inode_large *) scan->temp_buffer,
>                   0, bufsize);
> #else
> -        *inode = *((struct ext2_inode *) scan->temp_buffer);
> +        *inode = *((struct ext2_inode_large *) scan->temp_buffer);
> #endif
>        if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
>            retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
> @@ -502,6 +506,8 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
>        if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
>            retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
>    }
> +    if (EXT2_INODE_SIZE(scan->fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
> +        inode->i_extra_isize = 0;
> 
>    scan->inodes_left--;
>    scan->current_inode++;
> @@ -510,17 +516,17 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
> }
> 
> errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
> -                struct ext2_inode *inode)
> +                struct ext2_inode_large *inode)
> {
>    return ext2fs_get_next_inode_full(scan, ino, inode,
> -                        sizeof(struct ext2_inode));
> +                      sizeof(struct ext2_inode_large));
> }
> 
> /*
>  * Functions to read and write a single inode.
>  */
> errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
> -                 struct ext2_inode * inode, int bufsize)
> +                 struct ext2_inode_large *inode, int bufsize)
> {
>    blk64_t        block_nr;
>    unsigned long    group, block, offset;
> @@ -546,7 +552,7 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
>            return retval;
>    }
>    /* Check to see if it's in the inode cache */
> -    if (bufsize == sizeof(struct ext2_inode)) {
> +    if (bufsize == sizeof(struct ext2_inode_large)) {
>        /* only old good inode can be retrieved from the cache */
>        for (i=0; i < fs->icache->cache_size; i++) {
>            if (fs->icache->cache[i].ino == ino) {
> @@ -581,6 +587,8 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
>    if (bufsize < length)
>        length = bufsize;
> 
> +    if (length == EXT2_GOOD_OLD_INODE_SIZE)
> +        inode->i_extra_isize = 0;
>    ptr = (char *) inode;
>    while (length) {
>        clen = length;
> @@ -620,14 +628,14 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
> }
> 
> errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
> -                struct ext2_inode * inode)
> +                struct ext2_inode_large *inode)
> {
>    return ext2fs_read_inode_full(fs, ino, inode,
> -                    sizeof(struct ext2_inode));
> +                    sizeof(struct ext2_inode_large));
> }
> 
> errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
> -                  struct ext2_inode * inode, int bufsize)
> +                  struct ext2_inode_large *inode, int bufsize)
> {
>    blk64_t block_nr;
>    unsigned long group, block, offset;
> @@ -678,9 +686,7 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
>    memset(w_inode, 0, length);
> 
> #ifdef WORDS_BIGENDIAN
> -    ext2fs_swap_inode_full(fs, w_inode,
> -                   (struct ext2_inode_large *) inode,
> -                   1, bufsize);
> +    ext2fs_swap_inode_full(fs, w_inode, inode, 1, bufsize);
> #else
>    memcpy(w_inode, inode, bufsize);
> #endif
> @@ -739,10 +745,10 @@ errout:
> }
> 
> errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
> -                 struct ext2_inode *inode)
> +                 struct ext2_inode_large *inode)
> {
>    return ext2fs_write_inode_full(fs, ino, inode,
> -                       sizeof(struct ext2_inode));
> +                       sizeof(struct ext2_inode_large));
> }
> 
> /*
> @@ -750,9 +756,9 @@ errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
>  * sure that extra part of large inodes is initialized properly.
>  */
> errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
> -                 struct ext2_inode *inode)
> +                 struct ext2_inode_large *inode)
> {
> -    struct ext2_inode    *buf;
> +    struct ext2_inode_large    *buf;
>    int            size = EXT2_INODE_SIZE(fs->super);
>    struct ext2_inode_large    *large_inode;
>    errcode_t        retval;
> @@ -765,32 +771,20 @@ errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
>    if (!inode->i_atime)
>        inode->i_atime = t;
> 
> -    if (size == sizeof(struct ext2_inode))
> -        return ext2fs_write_inode_full(fs, ino, inode,
> -                           sizeof(struct ext2_inode));
> -
> -    buf = malloc(size);
> -    if (!buf)
> -        return ENOMEM;
> -
> -    memset(buf, 0, size);
> -    *buf = *inode;
> -
> -    large_inode = (struct ext2_inode_large *) buf;
> -    large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
> -        EXT2_GOOD_OLD_INODE_SIZE;
> -    if (!large_inode->i_crtime)
> -        large_inode->i_crtime = t;
> +    if (size > EXT2_GOOD_OLD_INODE_SIZE) {
> +        inode->i_extra_isize = sizeof(struct ext2_inode_large) -
> +                       EXT2_GOOD_OLD_INODE_SIZE;
> +        if (!inode->i_crtime)
> +            inode->i_crtime = t;
> +    }
> 
> -    retval = ext2fs_write_inode_full(fs, ino, buf, size);
> -    free(buf);
> -    return retval;
> +    return ext2fs_write_inode_full(fs, ino, inode, size);
> }
> 
> 
> errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
> {
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    int            i;
>    errcode_t        retval;
> 
> @@ -813,7 +807,7 @@ errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
> 
> errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
> {
> -    struct    ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    errcode_t        retval;
> 
>    EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
> diff --git a/lib/ext2fs/inode_io.c b/lib/ext2fs/inode_io.c
> index b3e7ce5..bfd6028 100644
> --- a/lib/ext2fs/inode_io.c
> +++ b/lib/ext2fs/inode_io.c
> @@ -36,7 +36,7 @@ struct inode_private_data {
>    ext2_file_t            file;
>    ext2_filsys            fs;
>    ext2_ino_t            ino;
> -    struct ext2_inode        inode;
> +    struct ext2_inode_large        inode;
>    int                flags;
>    struct inode_private_data    *next;
> };
> @@ -80,7 +80,7 @@ static struct struct_io_manager struct_inode_manager = {
> io_manager inode_io_manager = &struct_inode_manager;
> 
> errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
> -                  struct ext2_inode *inode,
> +                  struct ext2_inode_large *inode,
>                  char **name)
> {
>    struct inode_private_data    *data;
> @@ -96,7 +96,7 @@ errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
>    data->ino = ino;
>    data->flags = 0;
>    if (inode) {
> -        memcpy(&data->inode, inode, sizeof(struct ext2_inode));
> +        memcpy(&data->inode, inode, sizeof(struct ext2_inode_large));
>        data->flags |= CHANNEL_HAS_INODE;
>    }
>    data->next = top_intern;
> diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
> index 0fd3ea8..a32ec03 100644
> --- a/lib/ext2fs/link.c
> +++ b/lib/ext2fs/link.c
> @@ -113,7 +113,7 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
> {
>    errcode_t        retval;
>    struct link_struct    ls;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
> 
>    EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
> 
> diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
> index 9b6b799..08a0bd6 100644
> --- a/lib/ext2fs/mkdir.c
> +++ b/lib/ext2fs/mkdir.c
> @@ -35,7 +35,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
> {
>    ext2_extent_handle_t    handle;
>    errcode_t        retval;
> -    struct ext2_inode    parent_inode, inode;
> +    struct ext2_inode_large    parent_inode, inode;
>    ext2_ino_t        ino = inum;
>    ext2_ino_t        scratch_ino;
>    blk64_t            blk;
> @@ -80,7 +80,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
>    /*
>     * Create the inode structure....
>     */
> -    memset(&inode, 0, sizeof(struct ext2_inode));
> +    memset(&inode, 0, sizeof(struct ext2_inode_large));
>    inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
>    inode.i_uid = inode.i_gid = 0;
>    ext2fs_iblk_set(fs, &inode, 1);
> diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c
> index aaad2f6..33e58f7 100644
> --- a/lib/ext2fs/mkjournal.c
> +++ b/lib/ext2fs/mkjournal.c
> @@ -302,7 +302,7 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
>    char            *buf;
>    dgrp_t            group, start, end, i, log_flex;
>    errcode_t        retval;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    unsigned long long    inode_size;
>    struct mkjournal_struct    es;
> 
> diff --git a/lib/ext2fs/namei.c b/lib/ext2fs/namei.c
> index bc0ae61..b1911e3 100644
> --- a/lib/ext2fs/namei.c
> +++ b/lib/ext2fs/namei.c
> @@ -31,7 +31,7 @@ static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
>    char *pathname;
>    char *buffer = 0;
>    errcode_t retval;
> -    struct ext2_inode ei;
> +    struct ext2_inode_large ei;
> 
> #ifdef NAMEI_DEBUG
>    printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
> diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c
> index 2f24b5e..b8bd816 100644
> --- a/lib/ext2fs/punch.c
> +++ b/lib/ext2fs/punch.c
> @@ -44,7 +44,7 @@ static int check_zero_block(char *buf, int blocksize)
>  * each one, will recursively handle any indirect blocks and then
>  * frees and deallocates the blocks.
>  */
> -static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode,
> +static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode_large *inode,
>               char *block_buf, blk_t *p, int level,
>               blk_t start, blk_t count, int max)
> {
> @@ -98,7 +98,8 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode,
>    return ext2fs_iblk_sub_blocks(fs, inode, freed);
> }
> 
> -static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode,
> +static errcode_t ext2fs_punch_ind(ext2_filsys fs,
> +                  struct ext2_inode_large *inode,
>                  char *block_buf, blk_t start, blk_t count)
> {
>    errcode_t        retval;
> @@ -176,7 +177,7 @@ static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
> #endif
> 
> static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
> -                     struct ext2_inode *inode,
> +                     struct ext2_inode_large *inode,
>                     blk64_t start, blk64_t end)
> {
>    ext2_extent_handle_t    handle = 0;
> @@ -286,12 +287,12 @@ errout:
>  * If end is ~0, then this is effectively truncate.
>  */
> extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
> -                  struct ext2_inode *inode,
> +                  struct ext2_inode_large *inode,
>                  char *block_buf, blk64_t start,
>                  blk64_t end)
> {
>    errcode_t        retval;
> -    struct ext2_inode    inode_buf;
> +    struct ext2_inode_large    inode_buf;
> 
>    if (start > end)
>        return EINVAL;
> diff --git a/lib/ext2fs/read_bb.c b/lib/ext2fs/read_bb.c
> index e5d6322..40d0247 100644
> --- a/lib/ext2fs/read_bb.c
> +++ b/lib/ext2fs/read_bb.c
> @@ -65,7 +65,7 @@ errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list)
> {
>    errcode_t    retval;
>    struct read_bb_record rb;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    blk_t    numblocks;
> 
>    EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
> diff --git a/lib/ext2fs/res_gdt.c b/lib/ext2fs/res_gdt.c
> index acce650..7a80512 100644
> --- a/lib/ext2fs/res_gdt.c
> +++ b/lib/ext2fs/res_gdt.c
> @@ -62,7 +62,7 @@ errcode_t ext2fs_create_resize_inode(ext2_filsys fs)
> {
>    errcode_t        retval, retval2;
>    struct ext2_super_block    *sb;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    __u32            *dindir_buf, *gdt_buf;
>    unsigned long long    apb, inode_size;
>    /* FIXME-64 - can't deal with extents */
> diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
> index 87b1a2e..517f1d7 100644
> --- a/lib/ext2fs/swapfs.c
> +++ b/lib/ext2fs/swapfs.c
> @@ -210,11 +210,11 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
>    t->i_file_acl = ext2fs_swab32(f->i_file_acl);
>    if (hostorder)
>        has_data_blocks = ext2fs_inode_data_blocks(fs,
> -                       (struct ext2_inode *) f);
> +                       (struct ext2_inode_large *) f);
>    t->i_blocks = ext2fs_swab32(f->i_blocks);
>    if (!hostorder)
>        has_data_blocks = ext2fs_inode_data_blocks(fs,
> -                       (struct ext2_inode *) t);
> +                       (struct ext2_inode_large *) t);
>    if (hostorder && (f->i_flags & EXT4_EXTENTS_FL))
>        has_extents = 1;
>    t->i_flags = ext2fs_swab32(f->i_flags);
> @@ -265,7 +265,7 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
>        break;
>    }
> 
> -    if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
> +    if (bufsize < (int) (sizeof(struct ext2_inode_large) + sizeof(__u16)))
>        return; /* no i_extra_isize field */
> 
>    if (hostorder)
> @@ -274,16 +274,16 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
>    if (!hostorder)
>        extra_isize = t->i_extra_isize;
>    if (extra_isize > EXT2_INODE_SIZE(fs->super) -
> -                sizeof(struct ext2_inode)) {
> +                EXT2_GOOD_OLD_INODE_SIZE) {
>        /* this is error case: i_extra_size is too large */
>        return;
>    }
> 
> -    i = sizeof(struct ext2_inode) + extra_isize + sizeof(__u32);
> +    i = EXT2_GOOD_OLD_INODE_SIZE + extra_isize + sizeof(__u32);
>    if (bufsize < (int) i)
>        return; /* no space for EA magic */
> 
> -    eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) +
> +    eaf = (__u32 *) (((char *) f) + EXT2_GOOD_OLD_INODE_SIZE +
>                    extra_isize);
> 
>    attr_magic = *eaf;
> @@ -293,23 +293,23 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
>    if (attr_magic != EXT2_EXT_ATTR_MAGIC)
>        return; /* it seems no magic here */
> 
> -    eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) +
> +    eat = (__u32 *) (((char *) t) + EXT2_GOOD_OLD_INODE_SIZE +
>                    extra_isize);
>    *eat = ext2fs_swab32(*eaf);
> 
>    /* convert EA(s) */
>    ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1),
> -                 bufsize - sizeof(struct ext2_inode) -
> +                 bufsize - EXT2_GOOD_OLD_INODE_SIZE -
>                 extra_isize - sizeof(__u32), 0);
> 
> }
> 
> -void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
> -               struct ext2_inode *f, int hostorder)
> +void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode_large *t,
> +               struct ext2_inode_large *f, int hostorder)
> {
>    ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t,
>                (struct ext2_inode_large *) f, hostorder,
> -                sizeof(struct ext2_inode));
> +                sizeof(struct ext2_inode_large));
> }
> 
> #endif
> diff --git a/lib/ext2fs/tst_iscan.c b/lib/ext2fs/tst_iscan.c
> index 64246d3..dcf81d1 100644
> --- a/lib/ext2fs/tst_iscan.c
> +++ b/lib/ext2fs/tst_iscan.c
> @@ -139,7 +139,7 @@ static void setup(void)
>  */
> static void iterate(void)
> {
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    ext2_inode_scan    scan;
>    errcode_t    retval;
>    ext2_ino_t    ino;
> diff --git a/lib/ext2fs/valid_blk.c b/lib/ext2fs/valid_blk.c
> index ec3edd8..9419166 100644
> --- a/lib/ext2fs/valid_blk.c
> +++ b/lib/ext2fs/valid_blk.c
> @@ -23,7 +23,7 @@
>  * This function returns 1 if the inode's block entries actually
>  * contain block entries.
>  */
> -int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode)
> +int ext2fs_inode_has_valid_blocks(struct ext2_inode_large *inode)
> {
>    /*
>     * Only directories, regular files, and some symbolic links
> diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
> index 9a0dd46..7d74e84 100644
> --- a/misc/dumpe2fs.c
> +++ b/misc/dumpe2fs.c
> @@ -300,7 +300,7 @@ static void list_bad_blocks(ext2_filsys fs, int dump)
> static void print_inline_journal_information(ext2_filsys fs)
> {
>    journal_superblock_t    *jsb;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    ext2_file_t        journal_file;
>    errcode_t        retval;
>    ino_t            ino = fs->super->s_journal_inum;
> diff --git a/misc/e2image.c b/misc/e2image.c
> index 83a9d02..56a5321 100644
> --- a/misc/e2image.c
> +++ b/misc/e2image.c
> @@ -232,7 +232,7 @@ struct process_block_struct {
>  * the inode again.
>  */
> static ino_t stashed_ino = 0;
> -static struct ext2_inode *stashed_inode;
> +static struct ext2_inode_large *stashed_inode;
> 
> static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)),
>                 ext2_ino_t ino,
> @@ -261,7 +261,7 @@ static errcode_t meta_check_directory(ext2_filsys fs EXT2FS_ATTR((unused)),
> 
> static errcode_t meta_read_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
>                 ext2_ino_t ino,
> -                 struct ext2_inode *inode)
> +                 struct ext2_inode_large *inode)
> {
>    if ((ino != stashed_ino) || !stashed_inode)
>        return EXT2_ET_CALLBACK_NOTHANDLED;
> @@ -1032,7 +1032,7 @@ static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
> static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
> {
>    struct process_block_struct    pb;
> -    struct ext2_inode        inode;
> +    struct ext2_inode_large        inode;
>    ext2_inode_scan            scan;
>    ext2_ino_t            ino;
>    errcode_t            retval;
> diff --git a/misc/e2initrd_helper.c b/misc/e2initrd_helper.c
> index eaf9ce6..3d1535b 100644
> --- a/misc/e2initrd_helper.c
> +++ b/misc/e2initrd_helper.c
> @@ -75,7 +75,7 @@ static errcode_t get_file(ext2_filsys fs, const char * filename,
>    char        *buf;
>    ext2_file_t    e2_file;
>    unsigned int    got;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    ext2_ino_t    ino;
> 
>    ret_file->buf = 0;
> diff --git a/misc/mke2fs.c b/misc/mke2fs.c
> index e062bda..2d57d09 100644
> --- a/misc/mke2fs.c
> +++ b/misc/mke2fs.c
> @@ -352,7 +352,7 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
> static void create_root_dir(ext2_filsys fs)
> {
>    errcode_t        retval;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    __u32            uid, gid;
> 
>    retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
> diff --git a/misc/tune2fs.c b/misc/tune2fs.c
> index 5bf5187..82833ad 100644
> --- a/misc/tune2fs.c
> +++ b/misc/tune2fs.c
> @@ -275,7 +275,7 @@ static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
>  */
> static void remove_journal_inode(ext2_filsys fs)
> {
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    errcode_t        retval;
>    ino_t            ino = fs->super->s_journal_inum;
> 
> @@ -1209,7 +1209,7 @@ static int inode_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
>    ext2_ino_t ino;
>    blk64_t blk;
>    char *block_buf = 0;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
>    ext2_inode_scan    scan = NULL;
> 
>    retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
> diff --git a/resize/resize2fs.c b/resize/resize2fs.c
> index 45ea5f4..d35be59 100644
> --- a/resize/resize2fs.c
> +++ b/resize/resize2fs.c
> @@ -1234,7 +1234,7 @@ errout:
> struct process_block_struct {
>    ext2_resize_t        rfs;
>    ext2_ino_t        ino;
> -    struct ext2_inode *    inode;
> +    struct ext2_inode_large    *inode;
>    errcode_t        error;
>    int            is_dir;
>    int            changed;
> @@ -1309,7 +1309,7 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
> {
>    struct process_block_struct    pb;
>    ext2_ino_t        ino, new_inode;
> -    struct ext2_inode    *inode = NULL;
> +    struct ext2_inode_large    *inode = NULL;
>    ext2_inode_scan    scan = NULL;
>    errcode_t        retval;
>    char            *block_buf = 0;
> @@ -1475,7 +1475,7 @@ static int check_and_change_inodes(ext2_ino_t dir,
>                   void *priv_data)
> {
>    struct istruct *is = (struct istruct *) priv_data;
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    ext2_ino_t        new_inode;
>    errcode_t        retval;
> 
> @@ -1712,7 +1712,7 @@ errout:
>  */
> static errcode_t fix_resize_inode(ext2_filsys fs)
> {
> -    struct ext2_inode    inode;
> +    struct ext2_inode_large    inode;
>    errcode_t        retval;
>    char *            block_buf;
> 
> @@ -1866,7 +1866,7 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
> static errcode_t fix_sb_journal_backup(ext2_filsys fs)
> {
>    errcode_t      retval;
> -    struct ext2_inode inode;
> +    struct ext2_inode_large inode;
> 
>    if (!(fs->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
>        return 0;
> 

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

* Re: [PATCH 02/37] libext2fs: Add metadata checksum flag
  2011-09-01  0:35 ` [PATCH 02/37] libext2fs: Add metadata checksum flag Darrick J. Wong
@ 2011-09-04  1:47   ` Andreas Dilger
  0 siblings, 0 replies; 63+ messages in thread
From: Andreas Dilger @ 2011-09-04  1:47 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Theodore Tso, Darrick J. Wong, Sunil Mushran,
	Amir Goldstein, Andi Kleen, Mingming Cao, Joel Becker,
	linux-ext4, Coly Li

On 2011-08-31, at 6:35 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> Add a feature flag to enable metadata checksumming in e2fsprogs.  Also add a
> runtime flag to disable checksum verification; this flag will be used by
> debugfs to salvage filesystems and tune2fs when resetting checksums.
> 
> Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
> ---
> lib/blkid/probe.h    |    1 +
> lib/e2p/feature.c    |    2 ++
> lib/ext2fs/ext2_fs.h |    1 +
> lib/ext2fs/ext2fs.h  |    4 +++-
> 4 files changed, 7 insertions(+), 1 deletions(-)
> 
> 
> diff --git a/lib/blkid/probe.h b/lib/blkid/probe.h
> index 37e80ef..d6809e1 100644
> --- a/lib/blkid/probe.h
> +++ b/lib/blkid/probe.h
> @@ -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

There is really no reason to add every feature flag to probe.h. This was only used for distinguishing ext2/3/4. The blkid code officially lives in util-linux anyway.  Probably better to remove the ones that are not actually used. 

> /* for s_feature_incompat */
> #define EXT2_FEATURE_INCOMPAT_FILETYPE        0x0002
> diff --git a/lib/e2p/feature.c b/lib/e2p/feature.c
> index 16fba53..07b700d 100644
> --- a/lib/e2p/feature.c
> +++ b/lib/e2p/feature.c
> @@ -59,6 +59,8 @@ static struct feature feature_list[] = {
>            "quota" },
>    {    E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_BIGALLOC,
>            "bigalloc"},
> +    {    E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM,
> +            "metadata_csum"},
> 
>    {    E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
>            "compression" },
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index e342bf0..ae7662e 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -635,6 +635,7 @@ 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
> +#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM    0x0400
> 
> #define EXT2_FEATURE_INCOMPAT_COMPRESSION    0x0001
> #define EXT2_FEATURE_INCOMPAT_FILETYPE        0x0002
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index b290a1f..e638169 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -195,6 +195,7 @@ typedef struct ext2_file *ext2_file_t;
> #define EXT2_FLAG_64BITS        0x20000
> #define EXT2_FLAG_PRINT_PROGRESS    0x40000
> #define EXT2_FLAG_DIRECT_IO        0x80000
> +#define EXT2_FLAG_IGNORE_CSUM_ERRORS    0x100000
> 
> /*
>  * Special flag in the ext2 inode i_flag field that means that this is
> @@ -564,7 +565,8 @@ typedef struct ext2_icount *ext2_icount_t;
>                     EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\
>                     EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\
>                     EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\
> -                     EXT4_FEATURE_RO_COMPAT_BIGALLOC)
> +                     EXT4_FEATURE_RO_COMPAT_BIGALLOC|\
> +                     EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
> 
> /*
>  * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 01/37] e2fsprogs: Read and write full-sized inodes
  2011-09-03 18:05   ` Andreas Dilger
@ 2011-09-04 14:04     ` Ted Ts'o
  2011-09-04 17:40       ` Andreas Dilger
  0 siblings, 1 reply; 63+ messages in thread
From: Ted Ts'o @ 2011-09-04 14:04 UTC (permalink / raw)
  To: Andreas Dilger
  Cc: Darrick J. Wong, Andreas Dilger, Sunil Mushran, Amir Goldstein,
	Andi Kleen, Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Sat, Sep 03, 2011 at 12:05:39PM -0600, Andreas Dilger wrote:
> Why not just get rid of ext2_inode and replace it with
> ext2_inode_large?  Less change to the code, and less confusion for
> developers.

struct ext2_inode_large is there to make sure we don't break ABI
compatibility for shared libraries.

						- Ted

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

* Re: [PATCH 01/37] e2fsprogs: Read and write full-sized inodes
  2011-09-04 14:04     ` Ted Ts'o
@ 2011-09-04 17:40       ` Andreas Dilger
  0 siblings, 0 replies; 63+ messages in thread
From: Andreas Dilger @ 2011-09-04 17:40 UTC (permalink / raw)
  To: Ted Ts'o
  Cc: Andreas Dilger, Darrick J. Wong, Andreas Dilger, Sunil Mushran,
	AmirGoldstein, Andi Kleen, MingmingCao, Joel Becker, linux-ext4,
	Coly Li

On 2011-09-04, at 8:04 AM, Ted Ts'o <tytso@mit.edu> wrote:

> On Sat, Sep 03, 2011 at 12:05:39PM -0600, Andreas Dilger wrote:
>> Why not just get rid of ext2_inode and replace it with
>> ext2_inode_large?  Less change to the code, and less confusion for
>> developers.
> 
> struct ext2_inode_large is there to make sure we don't break ABI
> compatibility for shared libraries.

What about renaming ext2_inode to ext2_inode_{small,orig} and then (optionally) rename ext2_inode_large to ext2_inode?  That still avoids the code churn and continual risk of errors by developers using the small inode instead of the large inode, but keeps ABI compatibility. 

Cheers, Andreas

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

* Re: [PATCH 06/37] libext2fs: Add inode checksum support
  2011-09-01  0:35 ` [PATCH 06/37] libext2fs: Add inode checksum support Darrick J. Wong
@ 2011-09-04 17:59   ` Andreas Dilger
  2011-09-05 18:59     ` Darrick J. Wong
  0 siblings, 1 reply; 63+ messages in thread
From: Andreas Dilger @ 2011-09-04 17:59 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Theodore Tso, Darrick J. Wong, Sunil Mushran,
	Amir Goldstein, Andi Kleen, Mingming Cao, Joel Becker,
	linux-ext4, Coly Li

On 2011-08-31, at 6:35 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:

> This patch adds the ability for the libext2fs functions to read and write the
> inode checksum.  It also fixes a few fields that were omitted from the byte
> swapping routines.
> 
> Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
> ---
> lib/ext2fs/csum.c         |   59 +++++++++++++++++++++++++++++++++++++++++++++
> lib/ext2fs/ext2_err.et.in |    9 +++++++
> lib/ext2fs/ext2_fs.h      |    4 ++-
> lib/ext2fs/ext2fs.h       |    6 +++++
> lib/ext2fs/inode.c        |   20 +++++++++++++++
> lib/ext2fs/swapfs.c       |   10 ++++++--
> 6 files changed, 104 insertions(+), 4 deletions(-)
> 
> 
> diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
> index 2fece68..57adc4c 100644
> --- a/lib/ext2fs/csum.c
> +++ b/lib/ext2fs/csum.c
> @@ -29,6 +29,65 @@
> #define STATIC static
> #endif
> 
> +__u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
> +            struct ext2_inode_large *inode)
> +{
> +    struct ext2_inode_large *desc = inode;
> +    int offset = offsetof(struct ext2_inode_large, i_checksum);
> +    int extra_size = inode->i_extra_isize;
> +    size_t size = fs->super->s_inode_size;
> +    __u32 crc = 0;
> +
> +    if (size < EXT2_GOOD_OLD_INODE_SIZE + extra_size)
> +        printf("ERROR: inode %d size %d != extra_size %d!\n", inum,
> +               size, extra_size + EXT2_GOOD_OLD_INODE_SIZE);

This shouldn't have to be checked for every inode checksum. If the checksum is covering the whole inode size then this is a constant size, and e2fsck is already checking the value of i_extra_isize. 

> +    if (fs->super->s_creator_os != EXT2_OS_LINUX)
> +        return 0;
> +
> +    if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
> +                    EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
> +
> +        return 0;
> +
> +#ifdef WORDS_BIGENDIAN
> +    char buf[EXT2_INODE_CORE_SIZE(fs->super)];
> +    struct ext2_inode_large *swabinode = (struct ext2_inode_large *)buf;
> +
> +    /* Have to swab back to little-endian to do the checksum */
> +    memcpy(swabinode, inode, size);
> +    ext2fs_swap_inode_full(fs, swabinode, swabinode, 1, size);
> +    desc = swabinode;
> +#endif
> +    inum = ext2fs_cpu_to_le32(inum);
> +    crc = crc32c_le(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid));
> +    crc = crc32c_le(crc, (char *)&inum, sizeof(inum));
> +    crc = crc32c_le(crc, (char *)desc, offset);
> +    offset += sizeof(inode->i_checksum); /* skip checksum */
> +    crc = crc32c_le(crc, (char *)desc + offset,
> +               EXT2_GOOD_OLD_INODE_SIZE + extra_size - offset);
> +    return crc;
> +}
> +
> +int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
> +                 struct ext2_inode_large *inode)
> +{
> +    if (fs->super->s_creator_os == EXT2_OS_LINUX &&
> +        EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
> +                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
> +        (inode->i_checksum != ext2fs_inode_csum(fs, inum, inode)))
> +        return 0;
> +    return 1;
> +}
> +
> +void ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
> +               struct ext2_inode_large *inode)
> +{
> +    if (fs->super->s_creator_os != EXT2_OS_LINUX)
> +        return;
> +    inode->i_checksum = ext2fs_inode_csum(fs, inum, inode);
> +}
> +
> STATIC __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
> {
>    __u16 crc = 0;
> diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> index 995ddc3..31c8fe1 100644
> --- a/lib/ext2fs/ext2_err.et.in
> +++ b/lib/ext2fs/ext2_err.et.in
> @@ -422,4 +422,13 @@ ec    EXT2_NO_MTAB_FILE,
> ec    EXT2_ET_CANT_USE_LEGACY_BITMAPS,
>    "Filesystem too large to use legacy bitmaps"
> 
> +ec    EXT2_ET_INODE_CSUM_INVALID,
> +    "Inode checksum is incorrect"
> +
> +ec    EXT2_ET_INODE_CORRUPT,
> +    "Inode checksum indicates corruption"
> +
> +ec    EXT2_ET_INODE_CSUM_NONZERO,
> +    "Inode checksum should not be set"
> +
>    end
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index ae7662e..1f08673 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -362,7 +362,7 @@ struct ext2_inode_large {
>            __u16    l_i_file_acl_high;
>            __u16    l_i_uid_high;    /* these 2 fields    */
>            __u16    l_i_gid_high;    /* were reserved2[0] */
> -            __u32    l_i_reserved2;
> +            __u32    l_i_checksum;    /* crc32c(uuid+inum+inode) */
>        } linux2;
>        struct {
>            __u8    h_i_frag;    /* Fragment number */
> @@ -393,7 +393,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_reserved2    osd2.linux2.l_i_reserved2
> +#define i_checksum    osd2.linux2.l_i_checksum
> #else
> #if defined(__GNU__)
> 
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index e571508..db8b28b 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -892,6 +892,12 @@ extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len);
> extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
> 
> /* csum.c */
> +extern __u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
> +                  struct ext2_inode_large *inode);
> +extern void ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
> +                  struct ext2_inode_large *inode);
> +extern int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
> +                    struct ext2_inode_large *inode);
> extern void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group);
> extern int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group);
> extern errcode_t ext2fs_set_gdt_csum(ext2_filsys fs);
> diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
> index 76893fd..0789505 100644
> --- a/lib/ext2fs/inode.c
> +++ b/lib/ext2fs/inode.c
> @@ -509,6 +509,12 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
>    if (EXT2_INODE_SIZE(scan->fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
>        inode->i_extra_isize = 0;
> 
> +    /* Verify the inode checksum. */
> +    if (!(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
> +        !ext2fs_inode_csum_verify(scan->fs, scan->current_inode, inode))
> +        return EXT2_ET_INODE_CSUM_INVALID;
> +
> +
>    scan->inodes_left--;
>    scan->current_inode++;
>    *ino = scan->current_inode;
> @@ -617,6 +623,10 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
>                   (struct ext2_inode_large *) inode,
>                   0, bufsize);
> #endif
> +    /* Verify the inode checksum. */
> +    if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
> +        !ext2fs_inode_csum_verify(fs, ino, inode))
> +        return EXT2_ET_INODE_CSUM_INVALID;
> 
>    /* Update the inode cache */
>    fs->icache->cache_last = (fs->icache->cache_last + 1) %
> @@ -685,6 +695,16 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
>        w_inode = &temp_inode;
>    memset(w_inode, 0, length);
> 
> +    /*
> +     * If inode checksum enabled, ensure that we actually have the whole
> +     * inode in memory.
> +     */
> +    if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
> +        bufsize <= EXT2_GOOD_OLD_INODE_SIZE) {
> +        fprintf(stderr, "inode %d has a too-short buffer!\n", ino);
> +        abort();
> +    }
> +    ext2fs_inode_csum_set(fs, ino, inode);
> #ifdef WORDS_BIGENDIAN
>    ext2fs_swap_inode_full(fs, w_inode, inode, 1, bufsize);
> #else
> diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
> index 517f1d7..df604ba 100644
> --- a/lib/ext2fs/swapfs.c
> +++ b/lib/ext2fs/swapfs.c
> @@ -244,8 +244,7 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
>          ext2fs_swab16 (f->osd2.linux2.l_i_uid_high);
>        t->osd2.linux2.l_i_gid_high =
>          ext2fs_swab16 (f->osd2.linux2.l_i_gid_high);
> -        t->osd2.linux2.l_i_reserved2 =
> -            ext2fs_swab32(f->osd2.linux2.l_i_reserved2);
> +        t->i_checksum = ext2fs_swab32(f->i_checksum);
>        break;
>    case EXT2_OS_HURD:
>        t->osd1.hurd1.h_i_translator =
> @@ -279,6 +278,13 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
>        return;
>    }
> 
> +    t->i_ctime_extra = ext2fs_swab32(f->i_ctime_extra);
> +    t->i_mtime_extra = ext2fs_swab32(f->i_mtime_extra);
> +    t->i_atime_extra = ext2fs_swab32(f->i_atime_extra);
> +    t->i_crtime = ext2fs_swab32(f->i_crtime);
> +    t->i_crtime_extra = ext2fs_swab32(f->i_crtime_extra);
> +    t->i_version_hi = ext2fs_swab32(f->i_version_hi);
> +
>    i = EXT2_GOOD_OLD_INODE_SIZE + extra_isize + sizeof(__u32);
>    if (bufsize < (int) i)
>        return; /* no space for EA magic */
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 09/37] e2fsck: Verify and correct inode checksums
  2011-09-01  0:36 ` [PATCH 09/37] e2fsck: Verify and correct inode checksums Darrick J. Wong
@ 2011-09-04 18:17   ` Andreas Dilger
  2011-09-05 19:05     ` Darrick J. Wong
  0 siblings, 1 reply; 63+ messages in thread
From: Andreas Dilger @ 2011-09-04 18:17 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Theodore Tso, Darrick J. Wong, Sunil Mushran,
	Amir Goldstein, Andi Kleen, Mingming Cao, Joel Becker,
	linux-ext4, Coly Li

On 2011-08-31, at 6:36 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> Detect mismatches of the inode and checksum, and prompt the user to fix the
> situation.
> 
> Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
> ---
> e2fsck/pass1.c   |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> e2fsck/problem.c |   15 +++++++++++++++
> e2fsck/problem.h |    9 +++++++++
> 3 files changed, 76 insertions(+), 0 deletions(-)
> 
> 
> diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> index ba17b30..e9b0876 100644
> --- a/e2fsck/pass1.c
> +++ b/e2fsck/pass1.c
> @@ -540,6 +540,50 @@ extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags,
>        *ret = 0;
> }
> 
> +static int validate_inode_checksum(ext2_filsys fs,
> +                   e2fsck_t ctx,
> +                   struct problem_context *pctx,
> +                   ext2_ino_t ino,
> +                   struct ext2_inode_large *inode)
> +{
> +    struct ext2_inode_large *linode = (struct ext2_inode_large *)inode;
> +
> +    /* Ignore non-Linux filesystems */
> +    if (fs->super->s_creator_os != EXT2_OS_LINUX)
> +        return 0;
> +
> +    /* Check for checksums present even w/o feature flag */
> +    if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
> +                    EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
> +        linode->i_checksum &&
> +        fix_problem(ctx, PR_1_INODE_CSUM_NONZERO, pctx)) {
> +        e2fsck_write_inode(ctx, ino, inode, "pass1");
> +        return PR_1_INODE_CSUM_NONZERO;
> +    }
> +
> +    /* Check for invalid inode checksum */
> +    if (ext2fs_inode_csum_verify(fs, ino, linode))
> +        return 0;
> +
> +    /*
> +     * TODO: Change the following check to use the inode badness patch.
> +     * For the moment we'll just assume that the user wants to clear the
> +     * bad inode.
> +     */
> +    if (fix_problem(ctx, PR_1_INODE_CORRUPT, pctx)) {
> +        e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");

IMHO this would make the checksums _less_ robust than the current code. 

Currently it is possible to handle minor corruptions without erasing the whole inode.  If there was a problem that affected the whole filesystem (e.g. if the METADATA_CSUM flag is set with debugfs, change the filesystem UUID, etc) this would irrevocably erase the entire filesystem when "e2fsck -p/-y" was run. 

I think making it contribute to the inode badness in e2fsck is the only way to go. For the kernel it is OK to treat a bad checksum as -EIO, since that doesn't actually cause the inode to be erased, unlike this check. 

> +        if (ino == EXT2_BAD_INO)
> +            ext2fs_mark_inode_bitmap2(ctx->inode_used_map,
> +                          ino);
> +        return PR_1_INODE_CORRUPT;
> +    } else if (fix_problem(ctx, PR_1_INODE_CSUM_INVALID, pctx)) {
> +        e2fsck_write_inode(ctx, ino, inode, "pass1");
> +        return PR_1_INODE_CSUM_INVALID;
> +    }
> +
> +    return 0;
> +}
> +
> void e2fsck_pass1(e2fsck_t ctx)
> {
>    int    i;
> @@ -707,8 +751,10 @@ void e2fsck_pass1(e2fsck_t ctx)
> 
>    while (1) {
>        old_op = ehandler_operation(_("getting next inode from scan"));
> +        ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
>        pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
>                              inode, inode_size);
> +        ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
>        ehandler_operation(old_op);
>        if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
>            return;
> @@ -740,6 +786,12 @@ void e2fsck_pass1(e2fsck_t ctx)
>            }
>        }
> 
> +        check_inode_extra_space(ctx, &pctx);

This is already being called once per inode (later on) so there is no reason to call it twice for every inode. 

> +        /* Validate inode checksum.  i_extra_isize must be sane. */
> +        if (validate_inode_checksum(fs, ctx, &pctx, ino, inode) ==
> +            PR_1_INODE_CORRUPT)
> +            continue;
> +
>        /*
>         * Test for incorrect extent flag settings.
>         *
> diff --git a/e2fsck/problem.c b/e2fsck/problem.c
> index c5bebf8..b5176d4 100644
> --- a/e2fsck/problem.c
> +++ b/e2fsck/problem.c
> @@ -905,6 +905,21 @@ static struct e2fsck_problem problem_table[] = {
>      N_("Error converting subcluster @b @B: %m\n"),
>      PROMPT_NONE, PR_FATAL },
> 
> +    /* inode checksum probably not set */
> +    { PR_1_INODE_CSUM_INVALID,
> +      N_("@i %i checksum incorrect.  "),
> +      PROMPT_FIX, PR_PREEN_OK },
> +
> +    /* inode checksum probably set, but does not match */
> +    { PR_1_INODE_CORRUPT,
> +      N_("@i %i checksum shows corruption.  "),
> +      PROMPT_CLEAR, PR_PREEN_OK },
> +
> +    /* inode checksumming disabled, yet checksum is probably set? */
> +    { PR_1_INODE_CSUM_NONZERO,
> +      N_("@i %i checksum should not be set.  "),
> +      PROMPT_CLEAR, PR_PREEN_OK },
> +
>    /* Pass 1b errors */
> 
>    /* Pass 1B: Rescan for duplicate/bad blocks */
> diff --git a/e2fsck/problem.h b/e2fsck/problem.h
> index a4d96ae..4e353b7 100644
> --- a/e2fsck/problem.h
> +++ b/e2fsck/problem.h
> @@ -529,6 +529,15 @@ struct problem_context {
> /* Failed to convert subcluster bitmap */
> #define PR_1_CONVERT_SUBCLUSTER        0x010061
> 
> +/* inode checksum probably not set */
> +#define PR_1_INODE_CSUM_INVALID        0x010062
> +
> +/* inode checksum probably set, but does not match */
> +#define PR_1_INODE_CORRUPT        0x010063
> +
> +/* inode checksum should not be set */
> +#define PR_1_INODE_CSUM_NONZERO        0x010064
> +
> /*
>  * Pass 1b errors
>  */
> 

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

* Re: [PATCH 10/37] mke2fs: Allow metadata checksums to be turned on at mkfs time
  2011-09-01  0:36 ` [PATCH 10/37] mke2fs: Allow metadata checksums to be turned on at mkfs time Darrick J. Wong
@ 2011-09-04 18:28   ` Andreas Dilger
  2011-09-05 19:20     ` Darrick J. Wong
  0 siblings, 1 reply; 63+ messages in thread
From: Andreas Dilger @ 2011-09-04 18:28 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Theodore Tso, Darrick J. Wong, Sunil Mushran,
	Amir Goldstein, Andi Kleen, Mingming Cao, Joel Becker,
	linux-ext4, Coly Li

On 2011-08-31, at 6:36 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> Write out checksummed inodes even when writing out a zeroed table.
> 
> Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
> ---
> misc/mke2fs.c |   37 ++++++++++++++++++++++++++++++-------
> 1 files changed, 30 insertions(+), 7 deletions(-)
> 
> 
> diff --git a/misc/mke2fs.c b/misc/mke2fs.c
> index 2d57d09..bbc0533 100644
> --- a/misc/mke2fs.c
> +++ b/misc/mke2fs.c
> @@ -309,6 +309,8 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
>    dgrp_t        i;
>    int        num;
>    struct ext2fs_numeric_progress_struct progress;
> +    ext2_ino_t    ino;
> +    struct ext2_inode_large inode;
> 
>    ext2fs_numeric_progress_init(fs, &progress,
>                     _("Writing inode tables: "),
> @@ -330,12 +332,32 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
>            ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_ZEROED);
>            ext2fs_group_desc_csum_set(fs, i);
>        }
> -        retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num);
> -        if (retval) {
> -            fprintf(stderr, _("\nCould not write %d "
> -                  "blocks in inode table starting at %llu: %s\n"),
> -                num, blk, error_message(retval));
> -            exit(1);
> +        if (fs->super->s_creator_os == EXT2_OS_LINUX &&
> +            fs->super->s_feature_ro_compat &
> +            EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {

Somehow it doesn't look like this is skipping the zeroing of the inode table blocks if lazy itable zeroing is set. 

Any measurements on how much this slows down inode table writing (which is already the slowest part of mke2fs)?

> +            bzero(&inode, sizeof(inode));
> +            for (ino = fs->super->s_inodes_per_group * i;
> +                 ino < fs->super->s_inodes_per_group * (i + 1);
> +                 ino++) {

Why recompute "ino" each time through this loop?  It should be enough to simply initialize it at 1 and then increment it for each inode written. 

> +                if (!ino)
> +                    continue;
> +                retval = ext2fs_write_inode(fs, ino, &inode);
> +                if (retval) {
> +                    com_err("inode_init", retval,
> +                        "while writing inode %d\n",
> +                        ino);
> +                    exit(1);
> +                }
> +            }
> +        } else {
> +            retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num);
> +            if (retval) {
> +                fprintf(stderr, _("\nCould not write %d "
> +                    "blocks in inode table starting "
> +                    "at %llu: %s\n"),
> +                    num, blk, error_message(retval));
> +                exit(1);
> +            }
>        }
>        if (sync_kludge) {
>            if (sync_kludge == 1)
> @@ -829,7 +851,8 @@ static __u32 ok_features[3] = {
>        EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
>        EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|
>        EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
> -        EXT4_FEATURE_RO_COMPAT_BIGALLOC
> +        EXT4_FEATURE_RO_COMPAT_BIGALLOC|
> +        EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
> };
> 
> 
> 

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

* Re: [PATCH 13/37] dumpe2fs: Display inode bitmap checksum
  2011-09-01  0:36 ` [PATCH 13/37] dumpe2fs: Display inode bitmap checksum Darrick J. Wong
@ 2011-09-04 18:30   ` Andreas Dilger
  2011-09-05 19:20     ` Darrick J. Wong
  0 siblings, 1 reply; 63+ messages in thread
From: Andreas Dilger @ 2011-09-04 18:30 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Theodore Tso, Darrick J. Wong, Sunil Mushran,
	Amir Goldstein, Andi Kleen, Mingming Cao, Joel Becker,
	linux-ext4, Coly Li

On 2011-08-31, at 6:36 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> Display the inode bitmap checksum for each block group.
> 
> Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
> ---
> misc/dumpe2fs.c |    5 +++++
> 1 files changed, 5 insertions(+), 0 deletions(-)
> 
> 
> diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
> index 7d74e84..ed207cb 100644
> --- a/misc/dumpe2fs.c
> +++ b/misc/dumpe2fs.c
> @@ -220,6 +220,11 @@ static void list_desc (ext2_filsys fs)
>        print_number(ext2fs_inode_bitmap_loc(fs, i));
>        print_bg_rel_offset(fs, ext2fs_inode_bitmap_loc(fs, i), 0,
>                    first_block, last_block);
> +        if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT &&
> +            fs->super->s_feature_ro_compat &
> +            EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
> +            printf(_(", checksum 0x%08x"),

Since this line is already very long, printing "csum" should be enough. 

> +                  ext2fs_inode_bitmap_checksum(fs, i));
>        fputs(_("\n  Inode table at "), stdout);
>        print_range(ext2fs_inode_table_loc(fs, i),
>                ext2fs_inode_table_loc(fs, i) +
> 

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

* Re: [PATCH 06/37] libext2fs: Add inode checksum support
  2011-09-04 17:59   ` Andreas Dilger
@ 2011-09-05 18:59     ` Darrick J. Wong
  0 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-05 18:59 UTC (permalink / raw)
  To: Andreas Dilger
  Cc: Andreas Dilger, Theodore Tso, Sunil Mushran, Amir Goldstein,
	Andi Kleen, Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Sun, Sep 04, 2011 at 11:59:44AM -0600, Andreas Dilger wrote:
> On 2011-08-31, at 6:35 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> 
> > This patch adds the ability for the libext2fs functions to read and write the
> > inode checksum.  It also fixes a few fields that were omitted from the byte
> > swapping routines.
> > 
> > Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
> > ---
> > lib/ext2fs/csum.c         |   59 +++++++++++++++++++++++++++++++++++++++++++++
> > lib/ext2fs/ext2_err.et.in |    9 +++++++
> > lib/ext2fs/ext2_fs.h      |    4 ++-
> > lib/ext2fs/ext2fs.h       |    6 +++++
> > lib/ext2fs/inode.c        |   20 +++++++++++++++
> > lib/ext2fs/swapfs.c       |   10 ++++++--
> > 6 files changed, 104 insertions(+), 4 deletions(-)
> > 
> > 
> > diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
> > index 2fece68..57adc4c 100644
> > --- a/lib/ext2fs/csum.c
> > +++ b/lib/ext2fs/csum.c
> > @@ -29,6 +29,65 @@
> > #define STATIC static
> > #endif
> > 
> > +__u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
> > +            struct ext2_inode_large *inode)
> > +{
> > +    struct ext2_inode_large *desc = inode;
> > +    int offset = offsetof(struct ext2_inode_large, i_checksum);
> > +    int extra_size = inode->i_extra_isize;
> > +    size_t size = fs->super->s_inode_size;
> > +    __u32 crc = 0;
> > +
> > +    if (size < EXT2_GOOD_OLD_INODE_SIZE + extra_size)
> > +        printf("ERROR: inode %d size %d != extra_size %d!\n", inum,
> > +               size, extra_size + EXT2_GOOD_OLD_INODE_SIZE);
> 
> This shouldn't have to be checked for every inode checksum. If the checksum
> is covering the whole inode size then this is a constant size, and e2fsck is
> already checking the value of i_extra_isize. 

This actually comes out later in the patchset when I change the checksum to
cover the entire inode size.  I'll remove this hunk since it goes away.

--D
> 
> > +    if (fs->super->s_creator_os != EXT2_OS_LINUX)
> > +        return 0;
> > +
> > +    if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
> > +                    EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
> > +
> > +        return 0;
> > +
> > +#ifdef WORDS_BIGENDIAN
> > +    char buf[EXT2_INODE_CORE_SIZE(fs->super)];
> > +    struct ext2_inode_large *swabinode = (struct ext2_inode_large *)buf;
> > +
> > +    /* Have to swab back to little-endian to do the checksum */
> > +    memcpy(swabinode, inode, size);
> > +    ext2fs_swap_inode_full(fs, swabinode, swabinode, 1, size);
> > +    desc = swabinode;
> > +#endif
> > +    inum = ext2fs_cpu_to_le32(inum);
> > +    crc = crc32c_le(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid));
> > +    crc = crc32c_le(crc, (char *)&inum, sizeof(inum));
> > +    crc = crc32c_le(crc, (char *)desc, offset);
> > +    offset += sizeof(inode->i_checksum); /* skip checksum */
> > +    crc = crc32c_le(crc, (char *)desc + offset,
> > +               EXT2_GOOD_OLD_INODE_SIZE + extra_size - offset);
> > +    return crc;
> > +}
> > +
> > +int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
> > +                 struct ext2_inode_large *inode)
> > +{
> > +    if (fs->super->s_creator_os == EXT2_OS_LINUX &&
> > +        EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
> > +                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
> > +        (inode->i_checksum != ext2fs_inode_csum(fs, inum, inode)))
> > +        return 0;
> > +    return 1;
> > +}
> > +
> > +void ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
> > +               struct ext2_inode_large *inode)
> > +{
> > +    if (fs->super->s_creator_os != EXT2_OS_LINUX)
> > +        return;
> > +    inode->i_checksum = ext2fs_inode_csum(fs, inum, inode);
> > +}
> > +
> > STATIC __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
> > {
> >    __u16 crc = 0;
> > diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> > index 995ddc3..31c8fe1 100644
> > --- a/lib/ext2fs/ext2_err.et.in
> > +++ b/lib/ext2fs/ext2_err.et.in
> > @@ -422,4 +422,13 @@ ec    EXT2_NO_MTAB_FILE,
> > ec    EXT2_ET_CANT_USE_LEGACY_BITMAPS,
> >    "Filesystem too large to use legacy bitmaps"
> > 
> > +ec    EXT2_ET_INODE_CSUM_INVALID,
> > +    "Inode checksum is incorrect"
> > +
> > +ec    EXT2_ET_INODE_CORRUPT,
> > +    "Inode checksum indicates corruption"
> > +
> > +ec    EXT2_ET_INODE_CSUM_NONZERO,
> > +    "Inode checksum should not be set"
> > +
> >    end
> > diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> > index ae7662e..1f08673 100644
> > --- a/lib/ext2fs/ext2_fs.h
> > +++ b/lib/ext2fs/ext2_fs.h
> > @@ -362,7 +362,7 @@ struct ext2_inode_large {
> >            __u16    l_i_file_acl_high;
> >            __u16    l_i_uid_high;    /* these 2 fields    */
> >            __u16    l_i_gid_high;    /* were reserved2[0] */
> > -            __u32    l_i_reserved2;
> > +            __u32    l_i_checksum;    /* crc32c(uuid+inum+inode) */
> >        } linux2;
> >        struct {
> >            __u8    h_i_frag;    /* Fragment number */
> > @@ -393,7 +393,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_reserved2    osd2.linux2.l_i_reserved2
> > +#define i_checksum    osd2.linux2.l_i_checksum
> > #else
> > #if defined(__GNU__)
> > 
> > diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> > index e571508..db8b28b 100644
> > --- a/lib/ext2fs/ext2fs.h
> > +++ b/lib/ext2fs/ext2fs.h
> > @@ -892,6 +892,12 @@ extern __u32 crc32c_be(__u32 crc, unsigned char const *p, size_t len);
> > extern __u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
> > 
> > /* csum.c */
> > +extern __u32 ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
> > +                  struct ext2_inode_large *inode);
> > +extern void ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
> > +                  struct ext2_inode_large *inode);
> > +extern int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
> > +                    struct ext2_inode_large *inode);
> > extern void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group);
> > extern int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group);
> > extern errcode_t ext2fs_set_gdt_csum(ext2_filsys fs);
> > diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
> > index 76893fd..0789505 100644
> > --- a/lib/ext2fs/inode.c
> > +++ b/lib/ext2fs/inode.c
> > @@ -509,6 +509,12 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
> >    if (EXT2_INODE_SIZE(scan->fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
> >        inode->i_extra_isize = 0;
> > 
> > +    /* Verify the inode checksum. */
> > +    if (!(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
> > +        !ext2fs_inode_csum_verify(scan->fs, scan->current_inode, inode))
> > +        return EXT2_ET_INODE_CSUM_INVALID;
> > +
> > +
> >    scan->inodes_left--;
> >    scan->current_inode++;
> >    *ino = scan->current_inode;
> > @@ -617,6 +623,10 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
> >                   (struct ext2_inode_large *) inode,
> >                   0, bufsize);
> > #endif
> > +    /* Verify the inode checksum. */
> > +    if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
> > +        !ext2fs_inode_csum_verify(fs, ino, inode))
> > +        return EXT2_ET_INODE_CSUM_INVALID;
> > 
> >    /* Update the inode cache */
> >    fs->icache->cache_last = (fs->icache->cache_last + 1) %
> > @@ -685,6 +695,16 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
> >        w_inode = &temp_inode;
> >    memset(w_inode, 0, length);
> > 
> > +    /*
> > +     * If inode checksum enabled, ensure that we actually have the whole
> > +     * inode in memory.
> > +     */
> > +    if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
> > +        bufsize <= EXT2_GOOD_OLD_INODE_SIZE) {
> > +        fprintf(stderr, "inode %d has a too-short buffer!\n", ino);
> > +        abort();
> > +    }
> > +    ext2fs_inode_csum_set(fs, ino, inode);
> > #ifdef WORDS_BIGENDIAN
> >    ext2fs_swap_inode_full(fs, w_inode, inode, 1, bufsize);
> > #else
> > diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
> > index 517f1d7..df604ba 100644
> > --- a/lib/ext2fs/swapfs.c
> > +++ b/lib/ext2fs/swapfs.c
> > @@ -244,8 +244,7 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
> >          ext2fs_swab16 (f->osd2.linux2.l_i_uid_high);
> >        t->osd2.linux2.l_i_gid_high =
> >          ext2fs_swab16 (f->osd2.linux2.l_i_gid_high);
> > -        t->osd2.linux2.l_i_reserved2 =
> > -            ext2fs_swab32(f->osd2.linux2.l_i_reserved2);
> > +        t->i_checksum = ext2fs_swab32(f->i_checksum);
> >        break;
> >    case EXT2_OS_HURD:
> >        t->osd1.hurd1.h_i_translator =
> > @@ -279,6 +278,13 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
> >        return;
> >    }
> > 
> > +    t->i_ctime_extra = ext2fs_swab32(f->i_ctime_extra);
> > +    t->i_mtime_extra = ext2fs_swab32(f->i_mtime_extra);
> > +    t->i_atime_extra = ext2fs_swab32(f->i_atime_extra);
> > +    t->i_crtime = ext2fs_swab32(f->i_crtime);
> > +    t->i_crtime_extra = ext2fs_swab32(f->i_crtime_extra);
> > +    t->i_version_hi = ext2fs_swab32(f->i_version_hi);
> > +
> >    i = EXT2_GOOD_OLD_INODE_SIZE + extra_isize + sizeof(__u32);
> >    if (bufsize < (int) i)
> >        return; /* no space for EA magic */
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 09/37] e2fsck: Verify and correct inode checksums
  2011-09-04 18:17   ` Andreas Dilger
@ 2011-09-05 19:05     ` Darrick J. Wong
  0 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-05 19:05 UTC (permalink / raw)
  To: Andreas Dilger
  Cc: Andreas Dilger, Theodore Tso, Sunil Mushran, Amir Goldstein,
	Andi Kleen, Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Sun, Sep 04, 2011 at 12:17:49PM -0600, Andreas Dilger wrote:
> On 2011-08-31, at 6:36 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> > Detect mismatches of the inode and checksum, and prompt the user to fix the
> > situation.
> > 
> > Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
> > ---
> > e2fsck/pass1.c   |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> > e2fsck/problem.c |   15 +++++++++++++++
> > e2fsck/problem.h |    9 +++++++++
> > 3 files changed, 76 insertions(+), 0 deletions(-)
> > 
> > 
> > diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> > index ba17b30..e9b0876 100644
> > --- a/e2fsck/pass1.c
> > +++ b/e2fsck/pass1.c
> > @@ -540,6 +540,50 @@ extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags,
> >        *ret = 0;
> > }
> > 
> > +static int validate_inode_checksum(ext2_filsys fs,
> > +                   e2fsck_t ctx,
> > +                   struct problem_context *pctx,
> > +                   ext2_ino_t ino,
> > +                   struct ext2_inode_large *inode)
> > +{
> > +    struct ext2_inode_large *linode = (struct ext2_inode_large *)inode;
> > +
> > +    /* Ignore non-Linux filesystems */
> > +    if (fs->super->s_creator_os != EXT2_OS_LINUX)
> > +        return 0;
> > +
> > +    /* Check for checksums present even w/o feature flag */
> > +    if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
> > +                    EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
> > +        linode->i_checksum &&
> > +        fix_problem(ctx, PR_1_INODE_CSUM_NONZERO, pctx)) {
> > +        e2fsck_write_inode(ctx, ino, inode, "pass1");
> > +        return PR_1_INODE_CSUM_NONZERO;
> > +    }
> > +
> > +    /* Check for invalid inode checksum */
> > +    if (ext2fs_inode_csum_verify(fs, ino, linode))
> > +        return 0;
> > +
> > +    /*
> > +     * TODO: Change the following check to use the inode badness patch.
> > +     * For the moment we'll just assume that the user wants to clear the
> > +     * bad inode.
> > +     */
> > +    if (fix_problem(ctx, PR_1_INODE_CORRUPT, pctx)) {
> > +        e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
> 
> IMHO this would make the checksums _less_ robust than the current code. 
> 
> Currently it is possible to handle minor corruptions without erasing the
> whole inode.  If there was a problem that affected the whole filesystem (e.g.
> if the METADATA_CSUM flag is set with debugfs, change the filesystem UUID,
> etc) this would irrevocably erase the entire filesystem when "e2fsck -p/-y"
> was run. 
> 
> I think making it contribute to the inode badness in e2fsck is the only way
> to go. For the kernel it is OK to treat a bad checksum as -EIO, since that
> doesn't actually cause the inode to be erased, unlike this check. 

I wonder, what is the status of that badness patch?  I don't see it in upstream
e2fsprogs.

As I was writing all this e2fsck code the thought occurred to me that perhaps
the checksum should be verified last, and if it's found bad, then we simply
offer to reset the checksum.  That way, if the metadata is really defective,
the earlier structural checks will catch it, and if the metadata simply has an
incorrect checksum (and everything else is ok) then we let it live.

> > +        if (ino == EXT2_BAD_INO)
> > +            ext2fs_mark_inode_bitmap2(ctx->inode_used_map,
> > +                          ino);
> > +        return PR_1_INODE_CORRUPT;
> > +    } else if (fix_problem(ctx, PR_1_INODE_CSUM_INVALID, pctx)) {
> > +        e2fsck_write_inode(ctx, ino, inode, "pass1");
> > +        return PR_1_INODE_CSUM_INVALID;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > void e2fsck_pass1(e2fsck_t ctx)
> > {
> >    int    i;
> > @@ -707,8 +751,10 @@ void e2fsck_pass1(e2fsck_t ctx)
> > 
> >    while (1) {
> >        old_op = ehandler_operation(_("getting next inode from scan"));
> > +        ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
> >        pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
> >                              inode, inode_size);
> > +        ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
> >        ehandler_operation(old_op);
> >        if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
> >            return;
> > @@ -740,6 +786,12 @@ void e2fsck_pass1(e2fsck_t ctx)
> >            }
> >        }
> > 
> > +        check_inode_extra_space(ctx, &pctx);
> 
> This is already being called once per inode (later on) so there is no reason to call it twice for every inode. 

Ok.

--D

> > +        /* Validate inode checksum.  i_extra_isize must be sane. */
> > +        if (validate_inode_checksum(fs, ctx, &pctx, ino, inode) ==
> > +            PR_1_INODE_CORRUPT)
> > +            continue;
> > +
> >        /*
> >         * Test for incorrect extent flag settings.
> >         *
> > diff --git a/e2fsck/problem.c b/e2fsck/problem.c
> > index c5bebf8..b5176d4 100644
> > --- a/e2fsck/problem.c
> > +++ b/e2fsck/problem.c
> > @@ -905,6 +905,21 @@ static struct e2fsck_problem problem_table[] = {
> >      N_("Error converting subcluster @b @B: %m\n"),
> >      PROMPT_NONE, PR_FATAL },
> > 
> > +    /* inode checksum probably not set */
> > +    { PR_1_INODE_CSUM_INVALID,
> > +      N_("@i %i checksum incorrect.  "),
> > +      PROMPT_FIX, PR_PREEN_OK },
> > +
> > +    /* inode checksum probably set, but does not match */
> > +    { PR_1_INODE_CORRUPT,
> > +      N_("@i %i checksum shows corruption.  "),
> > +      PROMPT_CLEAR, PR_PREEN_OK },
> > +
> > +    /* inode checksumming disabled, yet checksum is probably set? */
> > +    { PR_1_INODE_CSUM_NONZERO,
> > +      N_("@i %i checksum should not be set.  "),
> > +      PROMPT_CLEAR, PR_PREEN_OK },
> > +
> >    /* Pass 1b errors */
> > 
> >    /* Pass 1B: Rescan for duplicate/bad blocks */
> > diff --git a/e2fsck/problem.h b/e2fsck/problem.h
> > index a4d96ae..4e353b7 100644
> > --- a/e2fsck/problem.h
> > +++ b/e2fsck/problem.h
> > @@ -529,6 +529,15 @@ struct problem_context {
> > /* Failed to convert subcluster bitmap */
> > #define PR_1_CONVERT_SUBCLUSTER        0x010061
> > 
> > +/* inode checksum probably not set */
> > +#define PR_1_INODE_CSUM_INVALID        0x010062
> > +
> > +/* inode checksum probably set, but does not match */
> > +#define PR_1_INODE_CORRUPT        0x010063
> > +
> > +/* inode checksum should not be set */
> > +#define PR_1_INODE_CSUM_NONZERO        0x010064
> > +
> > /*
> >  * Pass 1b errors
> >  */
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 10/37] mke2fs: Allow metadata checksums to be turned on at mkfs time
  2011-09-04 18:28   ` Andreas Dilger
@ 2011-09-05 19:20     ` Darrick J. Wong
  2011-09-06  1:54       ` Andreas Dilger
  0 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-05 19:20 UTC (permalink / raw)
  To: Andreas Dilger
  Cc: Andreas Dilger, Theodore Tso, Sunil Mushran, Amir Goldstein,
	Andi Kleen, Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Sun, Sep 04, 2011 at 12:28:24PM -0600, Andreas Dilger wrote:
> On 2011-08-31, at 6:36 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> > Write out checksummed inodes even when writing out a zeroed table.
> > 
> > Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
> > ---
> > misc/mke2fs.c |   37 ++++++++++++++++++++++++++++++-------
> > 1 files changed, 30 insertions(+), 7 deletions(-)
> > 
> > 
> > diff --git a/misc/mke2fs.c b/misc/mke2fs.c
> > index 2d57d09..bbc0533 100644
> > --- a/misc/mke2fs.c
> > +++ b/misc/mke2fs.c
> > @@ -309,6 +309,8 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
> >    dgrp_t        i;
> >    int        num;
> >    struct ext2fs_numeric_progress_struct progress;
> > +    ext2_ino_t    ino;
> > +    struct ext2_inode_large inode;
> > 
> >    ext2fs_numeric_progress_init(fs, &progress,
> >                     _("Writing inode tables: "),
> > @@ -330,12 +332,32 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
> >            ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_ZEROED);
> >            ext2fs_group_desc_csum_set(fs, i);
> >        }
> > -        retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num);
> > -        if (retval) {
> > -            fprintf(stderr, _("\nCould not write %d "
> > -                  "blocks in inode table starting at %llu: %s\n"),
> > -                num, blk, error_message(retval));
> > -            exit(1);
> > +        if (fs->super->s_creator_os == EXT2_OS_LINUX &&
> > +            fs->super->s_feature_ro_compat &
> > +            EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
> 
> Somehow it doesn't look like this is skipping the zeroing of the inode table
> blocks if lazy itable zeroing is set. 
> 
> Any measurements on how much this slows down inode table writing (which is
> already the slowest part of mke2fs)?

Quite a lot, actually.  Trouble is, if you're going to write zeroes to the
inode table (without using uninit) then I think you need the checksums to
match.  Maybe the solution is to modify the kernel/e2fsck to ignore the
checksum if the inode bitmap says the inode isn't in use?

A better solution is to zero the buffer, stuff in all the checksums in the
correct places, and then write the block out.

> > +            bzero(&inode, sizeof(inode));
> > +            for (ino = fs->super->s_inodes_per_group * i;
> > +                 ino < fs->super->s_inodes_per_group * (i + 1);
> > +                 ino++) {
> 
> Why recompute "ino" each time through this loop?  It should be enough to
> simply initialize it at 1 and then increment it for each inode written. 

Agreed.

--D
> > +                if (!ino)
> > +                    continue;
> > +                retval = ext2fs_write_inode(fs, ino, &inode);
> > +                if (retval) {
> > +                    com_err("inode_init", retval,
> > +                        "while writing inode %d\n",
> > +                        ino);
> > +                    exit(1);
> > +                }
> > +            }
> > +        } else {
> > +            retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num);
> > +            if (retval) {
> > +                fprintf(stderr, _("\nCould not write %d "
> > +                    "blocks in inode table starting "
> > +                    "at %llu: %s\n"),
> > +                    num, blk, error_message(retval));
> > +                exit(1);
> > +            }
> >        }
> >        if (sync_kludge) {
> >            if (sync_kludge == 1)
> > @@ -829,7 +851,8 @@ static __u32 ok_features[3] = {
> >        EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
> >        EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|
> >        EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
> > -        EXT4_FEATURE_RO_COMPAT_BIGALLOC
> > +        EXT4_FEATURE_RO_COMPAT_BIGALLOC|
> > +        EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
> > };
> > 
> > 
> > 

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

* Re: [PATCH 13/37] dumpe2fs: Display inode bitmap checksum
  2011-09-04 18:30   ` Andreas Dilger
@ 2011-09-05 19:20     ` Darrick J. Wong
  0 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-05 19:20 UTC (permalink / raw)
  To: Andreas Dilger
  Cc: Andreas Dilger, Theodore Tso, Sunil Mushran, Amir Goldstein,
	Andi Kleen, Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Sun, Sep 04, 2011 at 12:30:32PM -0600, Andreas Dilger wrote:
> On 2011-08-31, at 6:36 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> > Display the inode bitmap checksum for each block group.
> > 
> > Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
> > ---
> > misc/dumpe2fs.c |    5 +++++
> > 1 files changed, 5 insertions(+), 0 deletions(-)
> > 
> > 
> > diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
> > index 7d74e84..ed207cb 100644
> > --- a/misc/dumpe2fs.c
> > +++ b/misc/dumpe2fs.c
> > @@ -220,6 +220,11 @@ static void list_desc (ext2_filsys fs)
> >        print_number(ext2fs_inode_bitmap_loc(fs, i));
> >        print_bg_rel_offset(fs, ext2fs_inode_bitmap_loc(fs, i), 0,
> >                    first_block, last_block);
> > +        if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT &&
> > +            fs->super->s_feature_ro_compat &
> > +            EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
> > +            printf(_(", checksum 0x%08x"),
> 
> Since this line is already very long, printing "csum" should be enough. 

Ok.

--D
> 
> > +                  ext2fs_inode_bitmap_checksum(fs, i));
> >        fputs(_("\n  Inode table at "), stdout);
> >        print_range(ext2fs_inode_table_loc(fs, i),
> >                ext2fs_inode_table_loc(fs, i) +
> > 

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

* Re: [PATCH 10/37] mke2fs: Allow metadata checksums to be turned on at mkfs time
  2011-09-05 19:20     ` Darrick J. Wong
@ 2011-09-06  1:54       ` Andreas Dilger
  2011-09-06 17:13         ` Darrick J. Wong
  0 siblings, 1 reply; 63+ messages in thread
From: Andreas Dilger @ 2011-09-06  1:54 UTC (permalink / raw)
  To: djwong
  Cc: Andreas Dilger, Andreas Dilger, Theodore Tso, Sunil Mushran,
	Amir Goldstein, Andi Kleen, Mingming Cao, Joel Becker,
	linux-ext4, Coly Li

On 2011-09-05, at 1:20 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> On Sun, Sep 04, 2011 at 12:28:24PM -0600, Andreas Dilger wrote:
>> On 2011-08-31, at 6:36 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
>>> Write out checksummed inodes even when writing out a zeroed table.
>>> 
>>> +        if (fs->super->s_creator_os == EXT2_OS_LINUX &&
>>> +            fs->super->s_feature_ro_compat &
>>> +            EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
>> 
>> Somehow it doesn't look like this is skipping the zeroing of the inode table
>> blocks if lazy itable zeroing is set. 
>> 
>> Any measurements on how much this slows down inode table writing (which is
>> already the slowest part of mke2fs)?
> 
> Quite a lot, actually.  Trouble is, if you're going to write zeroes to the
> inode table (without using uninit) then I think you need the checksums to
> match.  Maybe the solution is to modify the kernel/e2fsck to ignore the
> checksum if the inode bitmap says the inode isn't in use?

The kernel is already aware of which inodes are not in use if the uninit_bg feature is enabled. Even without uninit_bg, the kernel will not read itable blocks from disk if none of the inodes in that block are used. 

Also, if the lazy_itable_init is passed to mke2fs it isn't supposed to initialize the inode table at all, and the kernel should do it instead. 

> A better solution is to zero the buffer, stuff in all the checksums in the
> correct places, and then write the block out.

Rather, the kernel should do it in the background. 

>>> +            bzero(&inode, sizeof(inode));
>>> +            for (ino = fs->super->s_inodes_per_group * i;
>>> +                 ino < fs->super->s_inodes_per_group * (i + 1);
>>> +                 ino++) {
>> 
>> Why recompute "ino" each time through this loop?  It should be enough to
>> simply initialize it at 1 and then increment it for each inode written. 
> 
> Agreed.
> 
> --D
>>> +                if (!ino)
>>> +                    continue;
>>> +                retval = ext2fs_write_inode(fs, ino, &inode);
>>> +                if (retval) {
>>> +                    com_err("inode_init", retval,
>>> +                        "while writing inode %d\n",
>>> +                        ino);
>>> +                    exit(1);
>>> +                }
>>> +            }
>>> +        } else {
>>> +            retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num);
>>> +            if (retval) {
>>> +                fprintf(stderr, _("\nCould not write %d "
>>> +                    "blocks in inode table starting "
>>> +                    "at %llu: %s\n"),
>>> +                    num, blk, error_message(retval));
>>> +                exit(1);
>>> +            }
>>>       }
>>>       if (sync_kludge) {
>>>           if (sync_kludge == 1)
>>> @@ -829,7 +851,8 @@ static __u32 ok_features[3] = {
>>>       EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
>>>       EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|
>>>       EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
>>> -        EXT4_FEATURE_RO_COMPAT_BIGALLOC
>>> +        EXT4_FEATURE_RO_COMPAT_BIGALLOC|
>>> +        EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
>>> };
>>> 
>>> 
>>> 

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

* Re: [PATCH 10/37] mke2fs: Allow metadata checksums to be turned on at mkfs time
  2011-09-06  1:54       ` Andreas Dilger
@ 2011-09-06 17:13         ` Darrick J. Wong
  0 siblings, 0 replies; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-06 17:13 UTC (permalink / raw)
  To: Andreas Dilger
  Cc: Andreas Dilger, Theodore Tso, Sunil Mushran, Amir Goldstein,
	Andi Kleen, Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Mon, Sep 05, 2011 at 07:54:32PM -0600, Andreas Dilger wrote:
> On 2011-09-05, at 1:20 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> > On Sun, Sep 04, 2011 at 12:28:24PM -0600, Andreas Dilger wrote:
> >> On 2011-08-31, at 6:36 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> >>> Write out checksummed inodes even when writing out a zeroed table.
> >>> 
> >>> +        if (fs->super->s_creator_os == EXT2_OS_LINUX &&
> >>> +            fs->super->s_feature_ro_compat &
> >>> +            EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
> >> 
> >> Somehow it doesn't look like this is skipping the zeroing of the inode table
> >> blocks if lazy itable zeroing is set. 
> >> 
> >> Any measurements on how much this slows down inode table writing (which is
> >> already the slowest part of mke2fs)?
> > 
> > Quite a lot, actually.  Trouble is, if you're going to write zeroes to the
> > inode table (without using uninit) then I think you need the checksums to
> > match.  Maybe the solution is to modify the kernel/e2fsck to ignore the
> > checksum if the inode bitmap says the inode isn't in use?
> 
> The kernel is already aware of which inodes are not in use if the uninit_bg
> feature is enabled. Even without uninit_bg, the kernel will not read itable
> blocks from disk if none of the inodes in that block are used. 
> 
> Also, if the lazy_itable_init is passed to mke2fs it isn't supposed to
> initialize the inode table at all, and the kernel should do it instead. 

Ok.

> > A better solution is to zero the buffer, stuff in all the checksums in the
> > correct places, and then write the block out.
> 
> Rather, the kernel should do it in the background. 

Append "...If the kernel won't do it in the background." to my earlier
statement. :) There seems to be some code that probes around in sysfs to make
sure that the kernel can handle uninit_bg ...
/sys/fs/ext4/features/lazy_itable_init I think?

--D

> >>> +            bzero(&inode, sizeof(inode));
> >>> +            for (ino = fs->super->s_inodes_per_group * i;
> >>> +                 ino < fs->super->s_inodes_per_group * (i + 1);
> >>> +                 ino++) {
> >> 
> >> Why recompute "ino" each time through this loop?  It should be enough to
> >> simply initialize it at 1 and then increment it for each inode written. 
> > 
> > Agreed.
> > 
> > --D
> >>> +                if (!ino)
> >>> +                    continue;
> >>> +                retval = ext2fs_write_inode(fs, ino, &inode);
> >>> +                if (retval) {
> >>> +                    com_err("inode_init", retval,
> >>> +                        "while writing inode %d\n",
> >>> +                        ino);
> >>> +                    exit(1);
> >>> +                }
> >>> +            }
> >>> +        } else {
> >>> +            retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num);
> >>> +            if (retval) {
> >>> +                fprintf(stderr, _("\nCould not write %d "
> >>> +                    "blocks in inode table starting "
> >>> +                    "at %llu: %s\n"),
> >>> +                    num, blk, error_message(retval));
> >>> +                exit(1);
> >>> +            }
> >>>       }
> >>>       if (sync_kludge) {
> >>>           if (sync_kludge == 1)
> >>> @@ -829,7 +851,8 @@ static __u32 ok_features[3] = {
> >>>       EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
> >>>       EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|
> >>>       EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
> >>> -        EXT4_FEATURE_RO_COMPAT_BIGALLOC
> >>> +        EXT4_FEATURE_RO_COMPAT_BIGALLOC|
> >>> +        EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
> >>> };
> >>> 
> >>> 
> >>> 

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

* Re: [PATCH 01/37] e2fsprogs: Read and write full-sized inodes
  2011-09-01  0:35 ` [PATCH 01/37] e2fsprogs: Read and write full-sized inodes Darrick J. Wong
  2011-09-03 18:05   ` Andreas Dilger
@ 2011-09-14 16:39   ` Ted Ts'o
  2011-09-15 20:25     ` Darrick J. Wong
  1 sibling, 1 reply; 63+ messages in thread
From: Ted Ts'o @ 2011-09-14 16:39 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Sunil Mushran, Amir Goldstein, Andi Kleen,
	Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Wed, Aug 31, 2011 at 05:35:17PM -0700, Darrick J. Wong wrote:
> As part of adding inode checksums, it is necessary for all e2fsprogs to read
> and write full inodes so that checksums may be calculated correctly.  Since
> struct ext2_inode_large is a superset of struct ext2_inode, replace the smaller
> one with the larger one.

OK, so I need to explain how the large inode support was designed.

The original assumption behind it was that most of the time, most user
progams outside of programs shipped natively with e2fsprogs (which are
special) don't actually need to access large inodes directly.  They
are much more likely to use ext2fs_file_{open,read}().  To the extent
that they need to access inodes at all, they will tend to do so
read-only to fetch the size or modtime or user/group ownership fields.

And when we write an inode, we need to do a read/modify/write cycle
with the inode table block anyway.  So the idea was to provide full
ABI compatibility with the struct ext4_inode structure, and the
functions that read and write them.  So ext4_inode is a fixed size,
128 byte structure, and functions that currently take ext4_inode must
only read or write the first 128 bytes.

This also implies that probably the better place to put the checksum
calculation code is in ext4_write_inode()/ext4_write_inode_large()
functions.  If we need a new function ext4_write_inode_raw() which has
the same function signature as ext4_write_inode_large(), but which
skips the checksum calculation, so be it.

Similarly, if we put the checksum verfication in
ext4_read_inode{_large}(), with a new error code if the checksum is
incorrect, all existing callers will get checksum verification for
free.

Now, about how ext4_{read,write}_inode_full().  This function is designed so
that struct ext4_inode_large can grow in newer versions of the
library.  To that end, the callers must call it as follows:

	  struct ext2_inode_large inode;

	  retval = ext2fs_read_inode_full(fs, ino, &inode, sizeof(inode));

If they happen to compile on a system where struct ext2_inode_large is
140 bytes, then they will pass in a bufsize of 140 bytes --- and it is
up to struct ext2fs_read_inode_full() to only pass back 140 bytes, and
for struct ext2fs_write_inode_full() to only read 140 bytes from the
passed-in pointer.  You can think of the bufsize parameter as being a
built-in versioning mechanism.

It is for a similar reason that gethostbyname() takes a socklen_t
parameter.  That way it doesn't have to worry about stack smashing an
legacy ipv4-only program.

So you can't just blanket replace struct ext2_inode with struct
ext2_inode_large, and have ext2fs_read_inode() blindly copy out
however many bytes happen to be in sizeof(struct ext2_inode_large)
today.  That way lies all sorts of wierd and hard-to-debug versioning
skew problems....

Does this make sense?

					- Ted

P.S.  The ext4 wiki is down right now, due to the kernel.org security
recovery efforts, but when it's back up, someone please remind me to
get this text up on the wiki.  :-)

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

* Re: [PATCH 32/37] libext2fs: Extend inode checksum to cover the EA block
  2011-09-01  0:38 ` [PATCH 32/37] libext2fs: Extend inode checksum to cover the EA block Darrick J. Wong
@ 2011-09-14 16:48   ` Ted Ts'o
  0 siblings, 0 replies; 63+ messages in thread
From: Ted Ts'o @ 2011-09-14 16:48 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Sunil Mushran, Amir Goldstein, Andi Kleen,
	Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Wed, Aug 31, 2011 at 05:38:36PM -0700, Darrick J. Wong wrote:
> Now that e2fsprogs knows to read the entire s_inode_size, change the inode
> checksum code to checksum the entire block.
> 
> Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>

This should get folded into whatever patch actually starts
checksumming the inode.  There's no point keeping it separate.  Also
note that changes like this are problematic as we bisect the tree,
since the meaning of the fields change as we progess through time.
Although from a development perspective this may be the order in which
you did things, from a patch review perspective it's better if you
collapse functional changes together, especially when it relates to
"this is how we calculate this field in the
inode/superblock/whatever".

					- Ted

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

* Re: [PATCH 11/37] libext2fs: Create the inode bitmap checksum
  2011-09-01  0:36 ` [PATCH 11/37] libext2fs: Create the inode bitmap checksum Darrick J. Wong
@ 2011-09-14 17:02   ` Ted Ts'o
  2011-09-14 19:31     ` Darrick J. Wong
  2011-09-14 19:59     ` Andreas Dilger
  0 siblings, 2 replies; 63+ messages in thread
From: Ted Ts'o @ 2011-09-14 17:02 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Sunil Mushran, Amir Goldstein, Andi Kleen,
	Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Wed, Aug 31, 2011 at 05:36:22PM -0700, Darrick J. Wong wrote:
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index 1f08673..367bfdf 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -169,7 +169,8 @@ struct ext4_group_desc
>  	__u16	bg_free_inodes_count_hi;/* Free inodes count MSB */
>  	__u16	bg_used_dirs_count_hi;	/* Directories count MSB */
>  	__u16	bg_itable_unused_hi;	/* Unused inodes count MSB */
> -	__u32	bg_reserved2[3];
> +	__u32	bg_inode_bitmap_csum;	/* crc32c(uuid+group+ibitmap) */
> +	__u32	bg_reserved2[2];
>  };


One of the reasons why I like to coalesce the patches to the data
structures into their own separate commit, is it's hard when I'm
reviewing individual patches in a mail reader what's going on from a
big picture spective.  (Heck, even just *finding* the patches that
modify the on-disk format is hard....)

But as near as I can tell, your patch series only uses one of the
32-bit fields in bg_reserved.  Is there a good reason why
bg_inode_bitmap_csum can't also used one of the two fields in
bg_reserved?  That way we get two 32-bit checksums for both struct
ext2_group_desc and struct ext4_group_desc.  Is there a third 32-bit
per-block group checksum I'm forgetting about? 

	  		     		       - Ted

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

* Re: [PATCH 11/37] libext2fs: Create the inode bitmap checksum
  2011-09-14 17:02   ` Ted Ts'o
@ 2011-09-14 19:31     ` Darrick J. Wong
  2011-09-14 20:00       ` Andreas Dilger
  2011-09-14 19:59     ` Andreas Dilger
  1 sibling, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-14 19:31 UTC (permalink / raw)
  To: Ted Ts'o
  Cc: Andreas Dilger, Sunil Mushran, Amir Goldstein, Andi Kleen,
	Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Wed, Sep 14, 2011 at 01:02:59PM -0400, Ted Ts'o wrote:
> On Wed, Aug 31, 2011 at 05:36:22PM -0700, Darrick J. Wong wrote:
> > diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> > index 1f08673..367bfdf 100644
> > --- a/lib/ext2fs/ext2_fs.h
> > +++ b/lib/ext2fs/ext2_fs.h
> > @@ -169,7 +169,8 @@ struct ext4_group_desc
> >  	__u16	bg_free_inodes_count_hi;/* Free inodes count MSB */
> >  	__u16	bg_used_dirs_count_hi;	/* Directories count MSB */
> >  	__u16	bg_itable_unused_hi;	/* Unused inodes count MSB */
> > -	__u32	bg_reserved2[3];
> > +	__u32	bg_inode_bitmap_csum;	/* crc32c(uuid+group+ibitmap) */
> > +	__u32	bg_reserved2[2];
> >  };
> 
> 
> One of the reasons why I like to coalesce the patches to the data
> structures into their own separate commit, is it's hard when I'm
> reviewing individual patches in a mail reader what's going on from a
> big picture spective.  (Heck, even just *finding* the patches that
> modify the on-disk format is hard....)
> 
> But as near as I can tell, your patch series only uses one of the
> 32-bit fields in bg_reserved.  Is there a good reason why
> bg_inode_bitmap_csum can't also used one of the two fields in
> bg_reserved?  That way we get two 32-bit checksums for both struct
> ext2_group_desc and struct ext4_group_desc.  Is there a third 32-bit
> per-block group checksum I'm forgetting about? 

No, but I was under the impression that Amir was using one of bg_reserved for
snapshots.  If that's not true, I'll move both bitmap checksums to bg_reserved.

--D
> 
> 	  		     		       - Ted

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

* Re: [PATCH 11/37] libext2fs: Create the inode bitmap checksum
  2011-09-14 17:02   ` Ted Ts'o
  2011-09-14 19:31     ` Darrick J. Wong
@ 2011-09-14 19:59     ` Andreas Dilger
  2011-09-14 22:14       ` Ted Ts'o
  1 sibling, 1 reply; 63+ messages in thread
From: Andreas Dilger @ 2011-09-14 19:59 UTC (permalink / raw)
  To: Ted Ts'o
  Cc: Darrick J. Wong, Sunil Mushran, Amir Goldstein, Andi Kleen,
	Mingming Cao, Joel Becker, linux-ext4, Coly Li

On 2011-09-14, at 11:02 AM, Ted Ts'o wrote:
> On Wed, Aug 31, 2011 at 05:36:22PM -0700, Darrick J. Wong wrote:
>> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
>> index 1f08673..367bfdf 100644
>> --- a/lib/ext2fs/ext2_fs.h
>> +++ b/lib/ext2fs/ext2_fs.h
>> @@ -169,7 +169,8 @@ struct ext4_group_desc
>> 	__u16	bg_free_inodes_count_hi;/* Free inodes count MSB */
>> 	__u16	bg_used_dirs_count_hi;	/* Directories count MSB */
>> 	__u16	bg_itable_unused_hi;	/* Unused inodes count MSB */
>> -	__u32	bg_reserved2[3];
>> +	__u32	bg_inode_bitmap_csum;	/* crc32c(uuid+group+ibitmap) */
>> +	__u32	bg_reserved2[2];
>> };
> 
> One of the reasons why I like to coalesce the patches to the data
> structures into their own separate commit, is it's hard when I'm
> reviewing individual patches in a mail reader what's going on from a
> big picture spective.  (Heck, even just *finding* the patches that
> modify the on-disk format is hard....)
> 
> But as near as I can tell, your patch series only uses one of the
> 32-bit fields in bg_reserved.  Is there a good reason why
> bg_inode_bitmap_csum can't also used one of the two fields in
> bg_reserved?  That way we get two 32-bit checksums for both struct
> ext2_group_desc and struct ext4_group_desc.  Is there a third 32-bit
> per-block group checksum I'm forgetting about?

There is the field that you told Amir he could use for the exception
bitmap for snapshots, which is using one of the two reserved fields in
ext2_group_desc, and also one of the 3 reserved fields in ext4_group_desc
for 64-bit block numbers.  That leaves one __u32 in ext2_group_desc, and
two __u32 in ext4_group_desc for checksums.

My proposal was as follows.  It adds the split checksums for block and
inode bitmaps, and renames bg_checksum to bg_group_desc_csum to avoid
confusion with these new checksums.  Truncate after bg_group_desc_csum
for smaller ext2_group_desc version.

struct ext4_group_desc
{
        __le32  bg_block_bitmap_lo;     /* Blocks bitmap block */
        __le32  bg_inode_bitmap_lo;     /* Inodes bitmap block */
        __le32  bg_inode_table_lo;      /* Inodes table block */
        __le16  bg_free_blocks_count_lo;/* Free blocks count */
        __le16  bg_free_inodes_count_lo;/* Free inodes count */
        __le16  bg_used_dirs_count_lo;  /* Directories count */
        __le16  bg_flags;               /* EXT4_BG_flags (INODE_UNINIT, etc) */
        __le32  bg_exclude_bitmap_lo;   /* Snapshot exclude bitmap block LSB */
        __le16  bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
        __le16  bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
        __le16  bg_itable_unused_lo;    /* Unused inodes count */
        __le16  bg_group_desc_csum;     /* crc16(sb_uuid+group+desc) */
        __le32  bg_block_bitmap_hi;     /* Blocks bitmap block MSB */
        __le32  bg_inode_bitmap_hi;     /* Inodes bitmap block MSB */
        __le32  bg_inode_table_hi;      /* Inodes table block MSB */
        __le16  bg_free_blocks_count_hi;/* Free blocks count MSB */
        __le16  bg_free_inodes_count_hi;/* Free inodes count MSB */
        __le16  bg_used_dirs_count_hi;  /* Directories count MSB */
        __le16  bg_itable_unused_hi;    /* Unused inodes count MSB */
	__le32	bg_exclude_bitmap_hi;	/* Exclude bitmap block MSB */
        __le16  bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bitmap) MSB */
        __le16  bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bitmap) MSB */
        __le32  bg_reserved2;
};

Whether crc32c & 0xffff is as strong as crc16 is open for debate, but it
isn't completely worthless (it provides some protection, and crc32c is
much faster at least for larger block sizes), and is only for filesystems
upgraded in-place from ext3 so it isn't critical in the long run.  I'd
rather have less complex and faster code than having to conditionally
compute crc16 vs crc32c depending on the ext4_group_desc size.

There is also the question if we want to extend bg_group_desc_csum and/or
the bg_flags values to be 32-bit fields?  If we do, then that uses up all
of the space in the 64-byte group descriptor and we would need to bump it
to 128 bytes to add any new fields.  We can deal with that when we run
out of flags.  I don't think there is a need to have a 32-bit checksum
for such a small structure, and potentially it makes sense to use the low
bits of crc32c instead of crc16 just to stick with a single algorithm for
the filesystem.

Cheers, Andreas

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

* Re: [PATCH 11/37] libext2fs: Create the inode bitmap checksum
  2011-09-14 19:31     ` Darrick J. Wong
@ 2011-09-14 20:00       ` Andreas Dilger
  0 siblings, 0 replies; 63+ messages in thread
From: Andreas Dilger @ 2011-09-14 20:00 UTC (permalink / raw)
  To: djwong
  Cc: Ted Ts'o, Sunil Mushran, Amir Goldstein, Andi Kleen,
	Mingming Cao, Joel Becker, linux-ext4, Coly Li

On 2011-09-14, at 1:31 PM, Darrick J. Wong wrote:
> On Wed, Sep 14, 2011 at 01:02:59PM -0400, Ted Ts'o wrote:
>> On Wed, Aug 31, 2011 at 05:36:22PM -0700, Darrick J. Wong wrote:
>>> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
>>> index 1f08673..367bfdf 100644
>>> --- a/lib/ext2fs/ext2_fs.h
>>> +++ b/lib/ext2fs/ext2_fs.h
>>> @@ -169,7 +169,8 @@ struct ext4_group_desc
>>> 	__u16	bg_free_inodes_count_hi;/* Free inodes count MSB */
>>> 	__u16	bg_used_dirs_count_hi;	/* Directories count MSB */
>>> 	__u16	bg_itable_unused_hi;	/* Unused inodes count MSB */
>>> -	__u32	bg_reserved2[3];
>>> +	__u32	bg_inode_bitmap_csum;	/* crc32c(uuid+group+ibitmap) */
>>> +	__u32	bg_reserved2[2];
>>> };
>> 
>> 
>> One of the reasons why I like to coalesce the patches to the data
>> structures into their own separate commit, is it's hard when I'm
>> reviewing individual patches in a mail reader what's going on from a
>> big picture spective.  (Heck, even just *finding* the patches that
>> modify the on-disk format is hard....)
>> 
>> But as near as I can tell, your patch series only uses one of the
>> 32-bit fields in bg_reserved.  Is there a good reason why
>> bg_inode_bitmap_csum can't also used one of the two fields in
>> bg_reserved?  That way we get two 32-bit checksums for both struct
>> ext2_group_desc and struct ext4_group_desc.  Is there a third 32-bit
>> per-block group checksum I'm forgetting about? 
> 
> No, but I was under the impression that Amir was using one of bg_reserved for
> snapshots.  If that's not true, I'll move both bitmap checksums to bg_reserved.

He was, AND the first bg_reserved2 field as well, which the above use
would conflict with.  See my other patch.

Cheers, Andreas






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

* Re: [PATCH 11/37] libext2fs: Create the inode bitmap checksum
  2011-09-14 19:59     ` Andreas Dilger
@ 2011-09-14 22:14       ` Ted Ts'o
  0 siblings, 0 replies; 63+ messages in thread
From: Ted Ts'o @ 2011-09-14 22:14 UTC (permalink / raw)
  To: Andreas Dilger
  Cc: Darrick J. Wong, Sunil Mushran, Amir Goldstein, Andi Kleen,
	Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Wed, Sep 14, 2011 at 01:59:06PM -0600, Andreas Dilger wrote:
> 
> There is the field that you told Amir he could use for the exception
> bitmap for snapshots, which is using one of the two reserved fields in
> ext2_group_desc, and also one of the 3 reserved fields in ext4_group_desc
> for 64-bit block numbers.  That leaves one __u32 in ext2_group_desc, and
> two __u32 in ext4_group_desc for checksums.

Right, that's what I was forgetting.  Thanks for reminding me!

> My proposal was as follows.  It adds the split checksums for block and
> inode bitmaps, and renames bg_checksum to bg_group_desc_csum to avoid
> confusion with these new checksums.  Truncate after bg_group_desc_csum
> for smaller ext2_group_desc version.
> 
> struct ext4_group_desc
> {
>         __le32  bg_block_bitmap_lo;     /* Blocks bitmap block */
>         __le32  bg_inode_bitmap_lo;     /* Inodes bitmap block */
>         __le32  bg_inode_table_lo;      /* Inodes table block */
>         __le16  bg_free_blocks_count_lo;/* Free blocks count */
>         __le16  bg_free_inodes_count_lo;/* Free inodes count */
>         __le16  bg_used_dirs_count_lo;  /* Directories count */
>         __le16  bg_flags;               /* EXT4_BG_flags (INODE_UNINIT, etc) */
>         __le32  bg_exclude_bitmap_lo;   /* Snapshot exclude bitmap block LSB */
>         __le16  bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
>         __le16  bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
>         __le16  bg_itable_unused_lo;    /* Unused inodes count */
>         __le16  bg_group_desc_csum;     /* crc16(sb_uuid+group+desc) */
>         __le32  bg_block_bitmap_hi;     /* Blocks bitmap block MSB */
>         __le32  bg_inode_bitmap_hi;     /* Inodes bitmap block MSB */
>         __le32  bg_inode_table_hi;      /* Inodes table block MSB */
>         __le16  bg_free_blocks_count_hi;/* Free blocks count MSB */
>         __le16  bg_free_inodes_count_hi;/* Free inodes count MSB */
>         __le16  bg_used_dirs_count_hi;  /* Directories count MSB */
>         __le16  bg_itable_unused_hi;    /* Unused inodes count MSB */
> 	__le32	bg_exclude_bitmap_hi;	/* Exclude bitmap block MSB */
>         __le16  bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bitmap) MSB */
>         __le16  bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bitmap) MSB */
>         __le32  bg_reserved2;
> };

That looks reasonable to me.

> Whether crc32c & 0xffff is as strong as crc16 is open for debate, but it
> isn't completely worthless (it provides some protection, and crc32c is
> much faster at least for larger block sizes), and is only for filesystems
> upgraded in-place from ext3 so it isn't critical in the long run.  I'd
> rather have less complex and faster code than having to conditionally
> compute crc16 vs crc32c depending on the ext4_group_desc size.

That seems reasonable for me.  Note that most ext4 file systems are
still being created using the 32 byte bg descriptor, mainly for
compatibility for older 1.41.x e2fsprogs.  But yes, long term that's
fair.

> There is also the question if we want to extend bg_group_desc_csum and/or
> the bg_flags values to be 32-bit fields?  If we do, then that uses up all
> of the space in the 64-byte group descriptor and we would need to bump it
> to 128 bytes to add any new fields.  We can deal with that when we run
> out of flags.

I don't think either is likely; we've used very few flags in bg_flags
so far, and the bg_group_desc_csum is only covering 64 bytes.  A
16-bit checksum should be more than good enough for that.

The thing which did occur to me was whether it would make sence to
change the use of crc16(x) to crc32(x) & 0xffff if the METADATA_CSUM
feature is enabled for the existing bg_checksum field.  But the speed
benefits for checksuming such a small number of bytes is minimal, and
probably not worth the extra code complexity.

Regards,

						- Ted

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

* Re: [PATCH 01/37] e2fsprogs: Read and write full-sized inodes
  2011-09-14 16:39   ` Ted Ts'o
@ 2011-09-15 20:25     ` Darrick J. Wong
  2011-09-15 21:35       ` Andreas Dilger
  0 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-15 20:25 UTC (permalink / raw)
  To: Ted Ts'o
  Cc: Andreas Dilger, Sunil Mushran, Amir Goldstein, Andi Kleen,
	Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Wed, Sep 14, 2011 at 12:39:01PM -0400, Ted Ts'o wrote:
> On Wed, Aug 31, 2011 at 05:35:17PM -0700, Darrick J. Wong wrote:
> > As part of adding inode checksums, it is necessary for all e2fsprogs to read
> > and write full inodes so that checksums may be calculated correctly.  Since
> > struct ext2_inode_large is a superset of struct ext2_inode, replace the smaller
> > one with the larger one.
> 
> OK, so I need to explain how the large inode support was designed.
> 
> The original assumption behind it was that most of the time, most user
> progams outside of programs shipped natively with e2fsprogs (which are
> special) don't actually need to access large inodes directly.  They
> are much more likely to use ext2fs_file_{open,read}().  To the extent
> that they need to access inodes at all, they will tend to do so
> read-only to fetch the size or modtime or user/group ownership fields.
> 
> And when we write an inode, we need to do a read/modify/write cycle
> with the inode table block anyway.  So the idea was to provide full
> ABI compatibility with the struct ext4_inode structure, and the
> functions that read and write them.  So ext4_inode is a fixed size,
> 128 byte structure, and functions that currently take ext4_inode must
> only read or write the first 128 bytes.
> 
> This also implies that probably the better place to put the checksum
> calculation code is in ext4_write_inode()/ext4_write_inode_large()
> functions.  If we need a new function ext4_write_inode_raw() which has
> the same function signature as ext4_write_inode_large(), but which
> skips the checksum calculation, so be it.

Okay, so here's my new game plan ... internally, libext2fs needs to read/write
whatever sb->inode_size is.  However, to avoid ABI breakage, it will use an
internal buffer (stack variable, memory block, whatever) for the IO operation
and the checksum operations.  As for whatever buffer+size the caller passes in,
it will memcpy this (potentially smaller) amount so that external programs that
still use the 128-byte structure won't get corrupted.  The other tools within
e2fsprogs can of course allocate the largest inode size they care about
(ext2_inode_large) if they so choose.

So I think this means that I can rip out both superpatches.  The inode read and
scan functions will need to allocate a buffer that is whatever size the
superblock says inodes are so that it can read, and checksum the inode.  After
that, the functions will copy however many bytes the caller tells us to copy
into the caller's buffer.  The write function will allocate a buffer that is
whatever size the superblock says inodes are, read that size off the disk, copy
however many bytes the caller gave us into this temporary buffer, then
calculate the checksum and write the buffer out to disk.  e2fsprogs that care
about extended inode fields can be modified to use ext2_inode_large, and
everything else can keep using ext2_inode.  This also keeps it so that client
programs don't have to know or care how big inodes really are.

Sorry I wasn't aware that there are non-e2fsprogs users of libext2fs.

--D

> Similarly, if we put the checksum verfication in
> ext4_read_inode{_large}(), with a new error code if the checksum is
> incorrect, all existing callers will get checksum verification for
> free.
> 
> Now, about how ext4_{read,write}_inode_full().  This function is designed so
> that struct ext4_inode_large can grow in newer versions of the
> library.  To that end, the callers must call it as follows:
> 
> 	  struct ext2_inode_large inode;
> 
> 	  retval = ext2fs_read_inode_full(fs, ino, &inode, sizeof(inode));
> 
> If they happen to compile on a system where struct ext2_inode_large is
> 140 bytes, then they will pass in a bufsize of 140 bytes --- and it is
> up to struct ext2fs_read_inode_full() to only pass back 140 bytes, and
> for struct ext2fs_write_inode_full() to only read 140 bytes from the
> passed-in pointer.  You can think of the bufsize parameter as being a
> built-in versioning mechanism.
> 
> It is for a similar reason that gethostbyname() takes a socklen_t
> parameter.  That way it doesn't have to worry about stack smashing an
> legacy ipv4-only program.
> 
> So you can't just blanket replace struct ext2_inode with struct
> ext2_inode_large, and have ext2fs_read_inode() blindly copy out
> however many bytes happen to be in sizeof(struct ext2_inode_large)
> today.  That way lies all sorts of wierd and hard-to-debug versioning
> skew problems....
> 
> Does this make sense?
> 
> 					- Ted
> 
> P.S.  The ext4 wiki is down right now, due to the kernel.org security
> recovery efforts, but when it's back up, someone please remind me to
> get this text up on the wiki.  :-)
> 

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

* Re: [PATCH 01/37] e2fsprogs: Read and write full-sized inodes
  2011-09-15 20:25     ` Darrick J. Wong
@ 2011-09-15 21:35       ` Andreas Dilger
  2011-09-16  1:04         ` Darrick J. Wong
  0 siblings, 1 reply; 63+ messages in thread
From: Andreas Dilger @ 2011-09-15 21:35 UTC (permalink / raw)
  To: djwong
  Cc: Ted Ts'o, Andreas Dilger, Sunil Mushran, Amir Goldstein,
	Andi Kleen, Mingming Cao, Joel Becker, linux-ext4, Coly Li

On 2011-09-15, at 2:25 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> On Wed, Sep 14, 2011 at 12:39:01PM -0400, Ted Ts'o wrote:
>> On Wed, Aug 31, 2011 at 05:35:17PM -0700, Darrick J. Wong wrote:
>>> As part of adding inode checksums, it is necessary for all e2fsprogs to read
>>> and write full inodes so that checksums may be calculated correctly.  Since
>>> struct ext2_inode_large is a superset of struct ext2_inode, replace the smaller
>>> one with the larger one.
>> 
>> OK, so I need to explain how the large inode support was designed.
>> 
>> The original assumption behind it was that most of the time, most user
>> progams outside of programs shipped natively with e2fsprogs (which are
>> special) don't actually need to access large inodes directly.  They
>> are much more likely to use ext2fs_file_{open,read}().  To the extent
>> that they need to access inodes at all, they will tend to do so
>> read-only to fetch the size or modtime or user/group ownership fields.
>> 
>> And when we write an inode, we need to do a read/modify/write cycle
>> with the inode table block anyway.  So the idea was to provide full
>> ABI compatibility with the struct ext4_inode structure, and the
>> functions that read and write them.  So ext4_inode is a fixed size,
>> 128 byte structure, and functions that currently take ext4_inode must
>> only read or write the first 128 bytes.
>> 
>> This also implies that probably the better place to put the checksum
>> calculation code is in ext4_write_inode()/ext4_write_inode_large()
>> functions.  If we need a new function ext4_write_inode_raw() which has
>> the same function signature as ext4_write_inode_large(), but which
>> skips the checksum calculation, so be it.
> 
> Okay, so here's my new game plan ... internally, libext2fs needs to read/write
> whatever sb->inode_size is.  However, to avoid ABI breakage, it will use an
> internal buffer (stack variable, memory block, whatever) for the IO operation
> and the checksum operations.  As for whatever buffer+size the caller passes in,
> it will memcpy this (potentially smaller) amount so that external programs that
> still use the 128-byte structure won't get corrupted.  The other tools within
> e2fsprogs can of course allocate the largest inode size they care about
> (ext2_inode_large) if they so choose.
> 
> So I think this means that I can rip out both superpatches.  The inode read and
> scan functions will need to allocate a buffer that is whatever size the
> superblock says inodes are so that it can read, and checksum the inode.  After
> that, the functions will copy however many bytes the caller tells us to copy
> into the caller's buffer.  The write function will allocate a buffer that is
> whatever size the superblock says inodes are, read that size off the disk, copy
> however many bytes the caller gave us into this temporary buffer, then
> calculate the checksum and write the buffer out to disk.  e2fsprogs that care
> about extended inode fields can be modified to use ext2_inode_large, and
> everything else can keep using ext2_inode.  This also keeps it so that client
> programs don't have to know or care how big inodes really are.

It would be a very straight forward and useful optimization to avoid the extra malloc() and copy if the buffer sizes are the same. 

> Sorry I wasn't aware that there are non-e2fsprogs users of libext2fs.
> 
> --D
> 
>> Similarly, if we put the checksum verfication in
>> ext4_read_inode{_large}(), with a new error code if the checksum is
>> incorrect, all existing callers will get checksum verification for
>> free.
>> 
>> Now, about how ext4_{read,write}_inode_full().  This function is designed so
>> that struct ext4_inode_large can grow in newer versions of the
>> library.  To that end, the callers must call it as follows:
>> 
>>      struct ext2_inode_large inode;
>> 
>>      retval = ext2fs_read_inode_full(fs, ino, &inode, sizeof(inode));
>> 
>> If they happen to compile on a system where struct ext2_inode_large is
>> 140 bytes, then they will pass in a bufsize of 140 bytes --- and it is
>> up to struct ext2fs_read_inode_full() to only pass back 140 bytes, and
>> for struct ext2fs_write_inode_full() to only read 140 bytes from the
>> passed-in pointer.  You can think of the bufsize parameter as being a
>> built-in versioning mechanism.
>> 
>> It is for a similar reason that gethostbyname() takes a socklen_t
>> parameter.  That way it doesn't have to worry about stack smashing an
>> legacy ipv4-only program.
>> 
>> So you can't just blanket replace struct ext2_inode with struct
>> ext2_inode_large, and have ext2fs_read_inode() blindly copy out
>> however many bytes happen to be in sizeof(struct ext2_inode_large)
>> today.  That way lies all sorts of wierd and hard-to-debug versioning
>> skew problems....
>> 
>> Does this make sense?
>> 
>>                    - Ted
>> 
>> P.S.  The ext4 wiki is down right now, due to the kernel.org security
>> recovery efforts, but when it's back up, someone please remind me to
>> get this text up on the wiki.  :-)
>> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 01/37] e2fsprogs: Read and write full-sized inodes
  2011-09-15 21:35       ` Andreas Dilger
@ 2011-09-16  1:04         ` Darrick J. Wong
  2011-09-18  1:52           ` Ted Ts'o
  0 siblings, 1 reply; 63+ messages in thread
From: Darrick J. Wong @ 2011-09-16  1:04 UTC (permalink / raw)
  To: Andreas Dilger
  Cc: Ted Ts'o, Andreas Dilger, Sunil Mushran, Amir Goldstein,
	Andi Kleen, Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Thu, Sep 15, 2011 at 03:35:45PM -0600, Andreas Dilger wrote:
> On 2011-09-15, at 2:25 PM, "Darrick J. Wong" <djwong@us.ibm.com> wrote:
> > On Wed, Sep 14, 2011 at 12:39:01PM -0400, Ted Ts'o wrote:
> >> On Wed, Aug 31, 2011 at 05:35:17PM -0700, Darrick J. Wong wrote:
> >>> As part of adding inode checksums, it is necessary for all e2fsprogs to read
> >>> and write full inodes so that checksums may be calculated correctly.  Since
> >>> struct ext2_inode_large is a superset of struct ext2_inode, replace the smaller
> >>> one with the larger one.
> >> 
> >> OK, so I need to explain how the large inode support was designed.
> >> 
> >> The original assumption behind it was that most of the time, most user
> >> progams outside of programs shipped natively with e2fsprogs (which are
> >> special) don't actually need to access large inodes directly.  They
> >> are much more likely to use ext2fs_file_{open,read}().  To the extent
> >> that they need to access inodes at all, they will tend to do so
> >> read-only to fetch the size or modtime or user/group ownership fields.
> >> 
> >> And when we write an inode, we need to do a read/modify/write cycle
> >> with the inode table block anyway.  So the idea was to provide full
> >> ABI compatibility with the struct ext4_inode structure, and the
> >> functions that read and write them.  So ext4_inode is a fixed size,
> >> 128 byte structure, and functions that currently take ext4_inode must
> >> only read or write the first 128 bytes.
> >> 
> >> This also implies that probably the better place to put the checksum
> >> calculation code is in ext4_write_inode()/ext4_write_inode_large()
> >> functions.  If we need a new function ext4_write_inode_raw() which has
> >> the same function signature as ext4_write_inode_large(), but which
> >> skips the checksum calculation, so be it.
> > 
> > Okay, so here's my new game plan ... internally, libext2fs needs to read/write
> > whatever sb->inode_size is.  However, to avoid ABI breakage, it will use an
> > internal buffer (stack variable, memory block, whatever) for the IO operation
> > and the checksum operations.  As for whatever buffer+size the caller passes in,
> > it will memcpy this (potentially smaller) amount so that external programs that
> > still use the 128-byte structure won't get corrupted.  The other tools within
> > e2fsprogs can of course allocate the largest inode size they care about
> > (ext2_inode_large) if they so choose.
> > 
> > So I think this means that I can rip out both superpatches.  The inode read and
> > scan functions will need to allocate a buffer that is whatever size the
> > superblock says inodes are so that it can read, and checksum the inode.  After
> > that, the functions will copy however many bytes the caller tells us to copy
> > into the caller's buffer.  The write function will allocate a buffer that is
> > whatever size the superblock says inodes are, read that size off the disk, copy
> > however many bytes the caller gave us into this temporary buffer, then
> > calculate the checksum and write the buffer out to disk.  e2fsprogs that care
> > about extended inode fields can be modified to use ext2_inode_large, and
> > everything else can keep using ext2_inode.  This also keeps it so that client
> > programs don't have to know or care how big inodes really are.
> 
> It would be a very straight forward and useful optimization to avoid the
> extra malloc() and copy if the buffer sizes are the same. 

<shrug> I was just going to abuse the stack for that purpose... but I guess
we'd save a memcpy.

Though I guess I should ask: Is it required that e2fsprogs build on compilers
that won't do variable-sized stack arrays?  I think that limits us to C99
compilers that support the feature, but I'm not 100% sure when gcc added that.
Or if we care about other things like ... Visual Studio? ;)

(I think I asked that same question a few weeks ago, but nobody said much
either way.)

--D
> 
> > Sorry I wasn't aware that there are non-e2fsprogs users of libext2fs.
> > 
> > --D
> > 
> >> Similarly, if we put the checksum verfication in
> >> ext4_read_inode{_large}(), with a new error code if the checksum is
> >> incorrect, all existing callers will get checksum verification for
> >> free.
> >> 
> >> Now, about how ext4_{read,write}_inode_full().  This function is designed so
> >> that struct ext4_inode_large can grow in newer versions of the
> >> library.  To that end, the callers must call it as follows:
> >> 
> >>      struct ext2_inode_large inode;
> >> 
> >>      retval = ext2fs_read_inode_full(fs, ino, &inode, sizeof(inode));
> >> 
> >> If they happen to compile on a system where struct ext2_inode_large is
> >> 140 bytes, then they will pass in a bufsize of 140 bytes --- and it is
> >> up to struct ext2fs_read_inode_full() to only pass back 140 bytes, and
> >> for struct ext2fs_write_inode_full() to only read 140 bytes from the
> >> passed-in pointer.  You can think of the bufsize parameter as being a
> >> built-in versioning mechanism.
> >> 
> >> It is for a similar reason that gethostbyname() takes a socklen_t
> >> parameter.  That way it doesn't have to worry about stack smashing an
> >> legacy ipv4-only program.
> >> 
> >> So you can't just blanket replace struct ext2_inode with struct
> >> ext2_inode_large, and have ext2fs_read_inode() blindly copy out
> >> however many bytes happen to be in sizeof(struct ext2_inode_large)
> >> today.  That way lies all sorts of wierd and hard-to-debug versioning
> >> skew problems....
> >> 
> >> Does this make sense?
> >> 
> >>                    - Ted
> >> 
> >> P.S.  The ext4 wiki is down right now, due to the kernel.org security
> >> recovery efforts, but when it's back up, someone please remind me to
> >> get this text up on the wiki.  :-)
> >> 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

* Re: [PATCH 04/37] libext2fs: Add crc32c implementation for metadata checksumming
  2011-09-01  0:35 ` [PATCH 04/37] libext2fs: Add crc32c implementation for metadata checksumming Darrick J. Wong
@ 2011-09-16  3:32   ` Ted Ts'o
  0 siblings, 0 replies; 63+ messages in thread
From: Ted Ts'o @ 2011-09-16  3:32 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Sunil Mushran, Amir Goldstein, Andi Kleen,
	Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Wed, Aug 31, 2011 at 05:35:36PM -0700, Darrick J. Wong wrote:
> Add a slicing-by-8 CRC32c implementation for metadata checksumming.
> Adapted from Bob Pearson's kernel patch.
> 
> Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>

I've added this patch to e2fsprogs' next branch, with the following
changes:
   1) I also folded in the self-test patch 5/37
   2) I added "ext2fs_" to the crc32_be and crc32_le functions, to avoid
	namespace contamination -- I did the same thing with the crc16.c
	function, BTW.

					- Ted

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

* Re: [PATCH 01/37] e2fsprogs: Read and write full-sized inodes
  2011-09-16  1:04         ` Darrick J. Wong
@ 2011-09-18  1:52           ` Ted Ts'o
  0 siblings, 0 replies; 63+ messages in thread
From: Ted Ts'o @ 2011-09-18  1:52 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Andreas Dilger, Andreas Dilger, Sunil Mushran, Amir Goldstein,
	Andi Kleen, Mingming Cao, Joel Becker, linux-ext4, Coly Li

On Thu, Sep 15, 2011 at 06:04:30PM -0700, Darrick J. Wong wrote:
> Though I guess I should ask: Is it required that e2fsprogs build on compilers
> that won't do variable-sized stack arrays?  I think that limits us to C99
> compilers that support the feature, but I'm not 100% sure when gcc added that.
> Or if we care about other things like ... Visual Studio? ;)

There are people who have ported libext2fs to Windows, so MSVC
compatibility is something I'd rather not give up.  The other issue
with VLA's is you have to be very careful about buffer overruns, for
the obvious reasons.

At least for e2fsprogs, we don't have to worried about locking, so at
least for read verification, in the case of reading the base 128 byte
inode it would be possible to just verify the whole inode while it is
in the disk buffer.  And on the write side, since we need to do the
read/modify/write cycle, at least in the normal case it's not clear to
me that we need to use dynamic allocation in as many places as we
might think, if we're a bit clever about things.

Even if we need to save and restore the checksum fields in the disk
buffer, and zero them out while we do the checksum, it's still faster
than needing to copy the whole inode, even if we avoid doing the
malloc by using VLA....

There will be a few cases where we need to malloc and grab the whole
inode (debugfs has one case already), but in most cases I suspect it
can be avoided.

Regards,

						- Ted

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

end of thread, other threads:[~2011-09-18  1:52 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-01  0:35 [PATCH v1 00/37] e2fsprogs: Add metadata checksumming Darrick J. Wong
2011-09-01  0:35 ` [PATCH 01/37] e2fsprogs: Read and write full-sized inodes Darrick J. Wong
2011-09-03 18:05   ` Andreas Dilger
2011-09-04 14:04     ` Ted Ts'o
2011-09-04 17:40       ` Andreas Dilger
2011-09-14 16:39   ` Ted Ts'o
2011-09-15 20:25     ` Darrick J. Wong
2011-09-15 21:35       ` Andreas Dilger
2011-09-16  1:04         ` Darrick J. Wong
2011-09-18  1:52           ` Ted Ts'o
2011-09-01  0:35 ` [PATCH 02/37] libext2fs: Add metadata checksum flag Darrick J. Wong
2011-09-04  1:47   ` Andreas Dilger
2011-09-01  0:35 ` [PATCH 03/37] debugfs: Optionally ignore bad checksums Darrick J. Wong
2011-09-01  0:35 ` [PATCH 04/37] libext2fs: Add crc32c implementation for metadata checksumming Darrick J. Wong
2011-09-16  3:32   ` Ted Ts'o
2011-09-01  0:35 ` [PATCH 05/37] libext2fs: Implement a crc32c self-test Darrick J. Wong
2011-09-01  0:35 ` [PATCH 06/37] libext2fs: Add inode checksum support Darrick J. Wong
2011-09-04 17:59   ` Andreas Dilger
2011-09-05 18:59     ` Darrick J. Wong
2011-09-01  0:35 ` [PATCH 07/37] debugfs: Dump inode checksum when appropriate Darrick J. Wong
2011-09-01  0:36 ` [PATCH 08/37] tune2fs: Add inode checksum support Darrick J. Wong
2011-09-01  0:36 ` [PATCH 09/37] e2fsck: Verify and correct inode checksums Darrick J. Wong
2011-09-04 18:17   ` Andreas Dilger
2011-09-05 19:05     ` Darrick J. Wong
2011-09-01  0:36 ` [PATCH 10/37] mke2fs: Allow metadata checksums to be turned on at mkfs time Darrick J. Wong
2011-09-04 18:28   ` Andreas Dilger
2011-09-05 19:20     ` Darrick J. Wong
2011-09-06  1:54       ` Andreas Dilger
2011-09-06 17:13         ` Darrick J. Wong
2011-09-01  0:36 ` [PATCH 11/37] libext2fs: Create the inode bitmap checksum Darrick J. Wong
2011-09-14 17:02   ` Ted Ts'o
2011-09-14 19:31     ` Darrick J. Wong
2011-09-14 20:00       ` Andreas Dilger
2011-09-14 19:59     ` Andreas Dilger
2011-09-14 22:14       ` Ted Ts'o
2011-09-01  0:36 ` [PATCH 12/37] tune2fs: Rewrite inode bitmap checksums Darrick J. Wong
2011-09-01  0:36 ` [PATCH 13/37] dumpe2fs: Display inode bitmap checksum Darrick J. Wong
2011-09-04 18:30   ` Andreas Dilger
2011-09-05 19:20     ` Darrick J. Wong
2011-09-01  0:36 ` [PATCH 14/37] e2fsck: Verify " Darrick J. Wong
2011-09-01  0:36 ` [PATCH 15/37] libext2fs: Create the block " Darrick J. Wong
2011-09-01  0:36 ` [PATCH 16/37] dumpe2fs: Display " Darrick J. Wong
2011-09-01  0:37 ` [PATCH 17/37] e2fsck: Verify " Darrick J. Wong
2011-09-01  0:37 ` [PATCH 18/37] e2fsck: Don't verify bitmap checksums Darrick J. Wong
2011-09-01  0:37 ` [PATCH 19/37] tune2fs: Rewrite block " Darrick J. Wong
2011-09-01  0:37 ` [PATCH 20/37] libext2fs: Verify and calculate extent tree block checksums Darrick J. Wong
2011-09-01  0:37 ` [PATCH 21/37] tune2fs: Enable extent tree checksums Darrick J. Wong
2011-09-01  0:37 ` [PATCH 22/37] libext2fs: Introduce dx_tail and dir_entry_tail Darrick J. Wong
2011-09-01  0:37 ` [PATCH 23/37] debugfs: Print htree internal node checksums Darrick J. Wong
2011-09-01  0:37 ` [PATCH 24/37] libext2fs: Add dx_root/dx_node checksum calculation and verification helpers Darrick J. Wong
2011-09-01  0:37 ` [PATCH 25/37] e2fsck: Verify htree root/node checksums Darrick J. Wong
2011-09-01  0:37 ` [PATCH 26/37] libext2fs: Introduce dir_entry_tail to provide checksums for directory leaf nodes Darrick J. Wong
2011-09-01  0:38 ` [PATCH 27/37] e2fsck: Check directory leaf block checksums Darrick J. Wong
2011-09-01  0:38 ` [PATCH 28/37] tune2fs: Rebuild and checksum directories when toggling metadata_csum or changing UUID Darrick J. Wong
2011-09-01  0:38 ` [PATCH 29/37] libext2fs: Verify and calculate extended attribute block checksums Darrick J. Wong
2011-09-01  0:38 ` [PATCH 30/37] e2fsck: Check " Darrick J. Wong
2011-09-01  0:38 ` [PATCH 32/37] libext2fs: Extend inode checksum to cover the EA block Darrick J. Wong
2011-09-14 16:48   ` Ted Ts'o
2011-09-01  0:38 ` [PATCH 33/37] tune2fs: Rewrite extended attribute block checksums Darrick J. Wong
2011-09-01  0:38 ` [PATCH 34/37] libext2fs: Calculate and verify superblock checksums Darrick J. Wong
2011-09-01  0:38 ` [PATCH 35/37] e2fsck: Handle superblock checksum errors gracefully Darrick J. Wong
2011-09-01  0:39 ` [PATCH 36/37] e2p: Print superblock checksum in list_super Darrick J. Wong
2011-09-01  0:39 ` [PATCH 37/37] e2fsck: Support CRC32c checksum in journal commit blocks Darrick J. Wong

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.