Merge branch 'maint' into next
diff --git a/Makefile.in b/Makefile.in
index 0f7aba3..54a0d14 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -10,7 +10,7 @@
 @RESIZER_CMT@RESIZE_DIR= resize
 @DEBUGFS_CMT@DEBUGFS_DIR= debugfs
 
-LIB_SUBDIRS=lib/et lib/ss lib/e2p lib/ext2fs lib/uuid lib/blkid intl
+LIB_SUBDIRS=lib/et lib/ss lib/e2p lib/uuid lib/ext2fs lib/blkid intl
 PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po
 SUBDIRS=util $(LIB_SUBDIRS) $(PROG_SUBDIRS) tests
 
diff --git a/configure b/configure
index dc4cac7..89e1611 100755
--- a/configure
+++ b/configure
@@ -684,7 +684,6 @@
 LIB_EXT
 STATIC_LIB_EXT
 PROFILED_LIB_EXT
-SWAPFS_CMT
 DEBUGFS_CMT
 IMAGER_CMT
 RESIZER_CMT
@@ -1371,7 +1370,6 @@
   --enable-jbd-debug  	  enable journal debugging
   --enable-blkid-debug    enable blkid debugging
   --enable-testio-debug   enable the use of the test I/O manager for debugging
-  --disable-swapfs    	  disable support of legacy byte-swapped filesystems
   --disable-debugfs   	  disable support of debugfs program
   --disable-imager   	  disable support of e2image program
   --disable-resizer   	  disable support of e2resize program
@@ -4000,32 +3998,6 @@
 
 fi
 
-# Check whether --enable-swapfs was given.
-if test "${enable_swapfs+set}" = set; then
-  enableval=$enable_swapfs; if test "$enableval" = "no"
-then
-	SWAPFS_CMT=#
-	echo "Disabling swapfs support"
-else
-	SWAPFS_CMT=
-	cat >>confdefs.h <<\_ACEOF
-#define ENABLE_SWAPFS 1
-_ACEOF
-
-	echo "Enabling swapfs support"
-fi
-
-else
-  SWAPFS_CMT=
-echo "Enabling swapfs support by default"
-cat >>confdefs.h <<\_ACEOF
-#define ENABLE_SWAPFS 1
-_ACEOF
-
-
-fi
-
-
 # Check whether --enable-debugfs was given.
 if test "${enable_debugfs+set}" = set; then
   enableval=$enable_debugfs; if test "$enableval" = "no"
@@ -16035,11 +16007,11 @@
 LIB_EXT!$LIB_EXT$ac_delim
 STATIC_LIB_EXT!$STATIC_LIB_EXT$ac_delim
 PROFILED_LIB_EXT!$PROFILED_LIB_EXT$ac_delim
-SWAPFS_CMT!$SWAPFS_CMT$ac_delim
 DEBUGFS_CMT!$DEBUGFS_CMT$ac_delim
 IMAGER_CMT!$IMAGER_CMT$ac_delim
 RESIZER_CMT!$RESIZER_CMT$ac_delim
 FSCK_PROG!$FSCK_PROG$ac_delim
+FSCK_MAN!$FSCK_MAN$ac_delim
 _ACEOF
 
   if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 76; then
@@ -16109,7 +16081,6 @@
 ac_delim='%!_!# '
 for ac_last_try in false false false false false :; do
   cat >conf$$subs.sed <<_ACEOF
-FSCK_MAN!$FSCK_MAN$ac_delim
 E2INITRD_PROG!$E2INITRD_PROG$ac_delim
 E2INITRD_MAN!$E2INITRD_MAN$ac_delim
 PKG_CONFIG!$PKG_CONFIG$ac_delim
@@ -16194,7 +16165,7 @@
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 83; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 82; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
diff --git a/configure.in b/configure.in
index 157816e..5243549 100644
--- a/configure.in
+++ b/configure.in
@@ -367,26 +367,6 @@
 echo "Disabling testio debugging by default"
 )
 dnl
-dnl handle --enable-swapfs
-dnl
-AC_ARG_ENABLE([swapfs],
-[  --disable-swapfs    	  disable support of legacy byte-swapped filesystems],
-if test "$enableval" = "no"
-then
-	SWAPFS_CMT=#
-	echo "Disabling swapfs support"
-else
-	SWAPFS_CMT=
-	AC_DEFINE(ENABLE_SWAPFS)
-	echo "Enabling swapfs support"
-fi
-,
-SWAPFS_CMT=
-echo "Enabling swapfs support by default"
-AC_DEFINE(ENABLE_SWAPFS)
-)
-AC_SUBST(SWAPFS_CMT)
-dnl
 dnl handle --enable-debugfs
 dnl
 AC_ARG_ENABLE([debugfs],
diff --git a/debian/rules b/debian/rules
index df04b5e..4ba301c 100755
--- a/debian/rules
+++ b/debian/rules
@@ -103,7 +103,7 @@
 		${DEVMAPPER}
 
 BF_CONF_FLAGS = --with-ccopts="${CCOPTS} ${BF_CCOPTS}" \
-	--disable-nls --disable-swapfs --disable-imager \
+	--disable-nls --disable-imager \
 	--disable-uuidd --disable-tls \
 	--disable-debugfs  --disable-e2initrd-helper
 
@@ -114,8 +114,7 @@
 	--with-ccopts=-fno-stack-protector
 
 MIPS_NOPIC_CONF_FLAGS = --with-ccopts="${CCOPTS}" \
-	--disable-nls \
-	--disable-swapfs --disable-imager \
+	--disable-nls --disable-imager \
 	--disable-uuidd --disable-tls \
         --disable-resizer # --disable-debugfs
 
diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in
index 81b411e..9775438 100644
--- a/debugfs/debugfs.8.in
+++ b/debugfs/debugfs.8.in
@@ -306,7 +306,7 @@
 .I \-b
 options.
 .TP
-.I ls [-l] [-d] filespec
+.I ls [-l] [-d] [-p] filespec
 Print a listing of the files in the directory
 .IR filespec .
 The 
@@ -315,6 +315,11 @@
 The
 .I \-d
 flag will list deleted entries in the directory.
+The 
+.I \-p
+flag will list the files in a format which is more easily parsable by
+scripts, as well as making it more clear when there are spaces or other
+non-prinitng characters at the end of filenames.
 .TP
 .I modify_inode filespec
 Modify the contents of the inode structure in the inode
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index a92933d..95cc89c 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -38,6 +38,8 @@
 #include "../version.h"
 
 extern ss_request_table debug_cmds;
+ss_request_table *extra_cmds;
+const char *debug_prog_name;
 
 ext2_filsys	current_fs = NULL;
 ext2_ino_t	root, cwd;
@@ -286,7 +288,10 @@
 	FILE 	*out;
 	struct ext2_group_desc *gdp;
 	int	c, header_only = 0;
-	int	numdirs = 0, first;
+	int	numdirs = 0, first, gdt_csum;
+
+	gdt_csum = EXT2_HAS_RO_COMPAT_FEATURE(current_fs->super,
+					      EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
 
 	reset_getopt();
 	while ((c = getopt (argc, argv, "h")) != EOF) {
@@ -322,7 +327,7 @@
 		        "inode table at %u\n"
 		        "           %d free %s, "
 		        "%d free %s, "
-		        "%d used %s\n",
+		        "%d used %s%s",
 		        i, gdp->bg_block_bitmap,
 		        gdp->bg_inode_bitmap, gdp->bg_inode_table,
 		        gdp->bg_free_blocks_count,
@@ -331,12 +336,21 @@
 		        gdp->bg_free_inodes_count != 1 ? "inodes" : "inode",
 		        gdp->bg_used_dirs_count,
 		        gdp->bg_used_dirs_count != 1 ? "directories"
-				: "directory");
+				: "directory", gdt_csum ? ", " : "\n");
+		if (gdt_csum)
+			fprintf(out, "%d unused %s\n",
+				gdp->bg_itable_unused,
+				gdp->bg_itable_unused != 1 ? "inodes":"inode");
 		first = 1;
 		print_bg_opts(gdp, EXT2_BG_INODE_UNINIT, "Inode not init",
 			      &first, out);
 		print_bg_opts(gdp, EXT2_BG_BLOCK_UNINIT, "Block not init",
 			      &first, out);
+		if (gdt_csum) {
+			fprintf(out, "%sChecksum 0x%04x",
+				first ? "           [":", ", gdp->bg_checksum);
+			first = 0;
+		}
 		if (!first)
 			fputs("]\n", out);
 	}
@@ -509,7 +523,7 @@
 	lb.first_block = 0;
 	lb.f = f;
 	lb.first = 1;
-	ext2fs_block_iterate2(current_fs, inode, 0, NULL,
+	ext2fs_block_iterate2(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL,
 			     list_blocks_proc, (void *)&lb);
 	finish_range(&lb);
 	if (lb.total)
@@ -571,10 +585,6 @@
 		frag = inode->osd2.hurd2.h_i_frag;
 		fsize = inode->osd2.hurd2.h_i_fsize;
 		break;
-	    case EXT2_OS_MASIX:
-		frag = inode->osd2.masix2.m_i_frag;
-		fsize = inode->osd2.masix2.m_i_fsize;
-		break;
 	    default:
 		frag = fsize = 0;
 	}
@@ -791,7 +801,8 @@
 
 	sprintf(buf, format, *val);
 	printf("%30s    [%s] ", prompt, buf);
-	fgets(buf, sizeof(buf), stdin);
+	if (!fgets(buf, sizeof(buf), stdin))
+		return;
 	if (buf[strlen (buf) - 1] == '\n')
 		buf[strlen (buf) - 1] = '\0';
 	if (!buf[0])
@@ -812,7 +823,8 @@
 
 	sprintf(buf, format, *val);
 	printf("%30s    [%s] ", prompt, buf);
-	fgets(buf, sizeof(buf), stdin);
+	if (!fgets(buf, sizeof(buf), stdin))
+		return;
 	if (buf[strlen (buf) - 1] == '\n')
 		buf[strlen (buf) - 1] = '\0';
 	if (!buf[0])
@@ -833,7 +845,8 @@
 
 	sprintf(buf, format, *val);
 	printf("%30s    [%s] ", prompt, buf);
-	fgets(buf, sizeof(buf), stdin);
+	if (!fgets(buf, sizeof(buf), stdin))
+		return;
 	if (buf[strlen (buf) - 1] == '\n')
 		buf[strlen (buf) - 1] = '\0';
 	if (!buf[0])
@@ -901,10 +914,6 @@
 		frag = &inode.osd2.hurd2.h_i_frag;
 		fsize = &inode.osd2.hurd2.h_i_fsize;
 		break;
-	    case EXT2_OS_MASIX:
-		frag = &inode.osd2.masix2.m_i_frag;
-		fsize = &inode.osd2.masix2.m_i_fsize;
-		break;
 	    default:
 		frag = fsize = 0;
 	}
@@ -1013,7 +1022,7 @@
 	struct ext2_inode inode;
 	int		retval;
 	ext2_ino_t	dir;
-	char		*dest, *cp, *basename;
+	char		*dest, *cp, *base_name;
 
 	/*
 	 * Get the source inode
@@ -1021,17 +1030,17 @@
 	ino = string_to_inode(sourcename);
 	if (!ino)
 		return;
-	basename = strrchr(sourcename, '/');
-	if (basename)
-		basename++;
+	base_name = strrchr(sourcename, '/');
+	if (base_name)
+		base_name++;
 	else
-		basename = sourcename;
+		base_name = sourcename;
 	/*
 	 * Figure out the destination.  First see if it exists and is
 	 * a directory.  
 	 */
 	if (! (retval=ext2fs_namei(current_fs, root, cwd, destname, &dir)))
-		dest = basename;
+		dest = base_name;
 	else {
 		/*
 		 * OK, it doesn't exist.  See if it is
@@ -1113,7 +1122,7 @@
 	if (debugfs_write_inode(ino, &inode, argv[0]))
 		return;
 
-	ext2fs_block_iterate(current_fs, ino, 0, NULL,
+	ext2fs_block_iterate(current_fs, ino, BLOCK_FLAG_READ_ONLY, NULL,
 			     mark_blocks_proc, NULL);
 
 	ext2fs_inode_alloc_stats2(current_fs, ino, +1, 0);
@@ -1126,19 +1135,19 @@
 {
 	int		retval;
 	ext2_ino_t	dir;
-	char		*basename;
+	char		*base_name;
 	
-	basename = strrchr(filename, '/');
-	if (basename) {
-		*basename++ = '\0';
+	base_name = strrchr(filename, '/');
+	if (base_name) {
+		*base_name++ = '\0';
 		dir = string_to_inode(filename);
 		if (!dir)
 			return;
 	} else {
 		dir = cwd;
-		basename = filename;
+		base_name = filename;
 	}
-	retval = ext2fs_unlink(current_fs, dir, basename, 0, 0);
+	retval = ext2fs_unlink(current_fs, dir, base_name, 0, 0);
 	if (retval)
 		com_err("unlink_file_by_name", retval, 0);
 	return;
@@ -1511,7 +1520,7 @@
 	if (!ext2fs_inode_has_valid_blocks(&inode_buf))
 		return;
 
-	ext2fs_block_iterate(current_fs, inode, 0, NULL,
+	ext2fs_block_iterate(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL,
 			     release_blocks_proc, NULL);
 	printf("\n");
 	ext2fs_inode_alloc_stats2(current_fs, inode, -1,
@@ -1810,7 +1819,7 @@
 {
 	int		retval;
 	int		sci_idx;
-	const char	*usage = "Usage: debugfs [-b blocksize] [-s superblock] [-f cmd_file] [-R request] [-V] [[-w] [-c] device]";
+	const char	*usage = "Usage: %s [-b blocksize] [-s superblock] [-f cmd_file] [-R request] [-V] [[-w] [-c] device]";
 	int		c;
 	int		open_flags = EXT2_FLAG_SOFTSUPP_FEATURES;
 	char		*request = 0;
@@ -1821,9 +1830,12 @@
 	int		catastrophic = 0;
 	char		*data_filename = 0;
 	
+	if (debug_prog_name == 0)
+		debug_prog_name = "debugfs";
+
 	add_error_table(&et_ext2_error_table);
-	fprintf (stderr, "debugfs %s (%s)\n", E2FSPROGS_VERSION,
-		 E2FSPROGS_DATE);
+	fprintf (stderr, "%s %s (%s)\n", debug_prog_name,
+		 E2FSPROGS_VERSION, E2FSPROGS_DATE);
 
 	while ((c = getopt (argc, argv, "iwcR:f:b:s:Vd:")) != EOF) {
 		switch (c) {
@@ -1859,7 +1871,7 @@
 				error_message(EXT2_ET_BASE));
 			exit(0);
 		default:
-			com_err(argv[0], 0, usage);
+			com_err(argv[0], 0, usage, debug_prog_name);
 			return 1;
 		}
 	}
@@ -1868,7 +1880,7 @@
 				superblock, blocksize, catastrophic,
 				data_filename);
 	
-	sci_idx = ss_create_invocation("debugfs", "0.0", (char *) NULL,
+	sci_idx = ss_create_invocation(debug_prog_name, "0.0", (char *) NULL,
 				       &debug_cmds, &retval);
 	if (retval) {
 		ss_perror(sci_idx, retval, "creating invocation");
@@ -1881,6 +1893,12 @@
 		ss_perror(sci_idx, retval, "adding standard requests");
 		exit (1);
 	}
+	if (extra_cmds)
+		ss_add_request_table (sci_idx, extra_cmds, 1, &retval);
+	if (retval) {
+		ss_perror(sci_idx, retval, "adding extra requests");
+		exit (1);
+	}
 	if (request) {
 		retval = 0;
 		retval = ss_execute_line(sci_idx, request);
diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
index d72c7ac..003c19a 100644
--- a/debugfs/debugfs.h
+++ b/debugfs/debugfs.h
@@ -78,6 +78,7 @@
 /* set_fields.c */
 extern void do_set_super(int argc, char **);
 extern void do_set_inode(int argc, char **);
+extern void do_set_block_group_descriptor(int argc, char **);
 
 /* unused.c */
 extern void do_dump_unused(int argc, char **argv);
diff --git a/debugfs/htree.c b/debugfs/htree.c
index d0e673e..a46bae7 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -347,7 +347,8 @@
 	pb.search_name = argv[2];
 	pb.len = strlen(pb.search_name);
 	
-	ext2fs_block_iterate2(current_fs, inode, 0, 0, search_dir_block, &pb);
+	ext2fs_block_iterate2(current_fs, inode, BLOCK_FLAG_READ_ONLY, 0,
+			      search_dir_block, &pb);
 
 	free(pb.buf);
 }
diff --git a/debugfs/icheck.c b/debugfs/icheck.c
index a6b182d..01c78bc 100644
--- a/debugfs/icheck.c
+++ b/debugfs/icheck.c
@@ -127,7 +127,8 @@
 		if (inode.i_dtime)
 			goto next;
 
-		retval = ext2fs_block_iterate2(current_fs, ino, 0, block_buf,
+		retval = ext2fs_block_iterate2(current_fs, ino,
+					       BLOCK_FLAG_READ_ONLY, block_buf,
 					       icheck_proc, &bw);
 		if (retval) {
 			com_err("icheck", retval,
diff --git a/debugfs/logdump.c b/debugfs/logdump.c
index 2bf67b5..08e58f7 100644
--- a/debugfs/logdump.c
+++ b/debugfs/logdump.c
@@ -36,11 +36,11 @@
 
 enum journal_location {JOURNAL_IS_INTERNAL, JOURNAL_IS_EXTERNAL};
 
-#define ANY_BLOCK ((unsigned int) -1)
+#define ANY_BLOCK ((blk_t) -1)
 
 int		dump_all, dump_contents, dump_descriptors;
-unsigned int	block_to_dump, group_to_dump, bitmap_to_dump;
-unsigned int	inode_block_to_dump, inode_offset_to_dump, bitmap_to_dump;
+blk_t		block_to_dump, bitmap_to_dump, inode_block_to_dump;
+unsigned int	group_to_dump, inode_offset_to_dump;
 ext2_ino_t	inode_to_dump;
 
 struct journal_source 
@@ -350,7 +350,7 @@
 
 	jsb = (journal_superblock_t *) buf;
 	sb = (struct ext2_super_block *) (buf+1024);
-#ifdef ENABLE_SWAPFS
+#ifdef WORDS_BIGENDIAN
 	if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) 
 		ext2fs_swap_super(sb);
 #endif
@@ -365,8 +365,8 @@
 		if (dump_all) {
 			fprintf(out_file, "\tuuid=%s\n", jsb_buffer);
 			fprintf(out_file, "\tblocksize=%d\n", blocksize);
-			fprintf(out_file, "\tjournal data size %ld\n",
-				(long) sb->s_blocks_count);
+			fprintf(out_file, "\tjournal data size %lu\n",
+				(unsigned long) sb->s_blocks_count);
 		}
 	}
 	
diff --git a/debugfs/ls.c b/debugfs/ls.c
index 52c7e34..1ceeb1b 100644
--- a/debugfs/ls.c
+++ b/debugfs/ls.c
@@ -30,6 +30,7 @@
 
 #define LONG_OPT	0x0001
 #define DELETED_OPT	0x0002
+#define PARSE_OPT	0x0004
 
 struct list_dir_struct {
 	FILE	*f;
@@ -72,7 +73,16 @@
 	} else {
 		lbr = rbr = ' ';
 	}
-	if (ls->options & LONG_OPT) {
+	if (ls->options & PARSE_OPT) {
+		if (ino && debugfs_read_inode(ino, &inode, name)) return 0;
+		fprintf(ls->f,"/%u/%06o/%d/%d/%s/",ino,inode.i_mode,inode.i_uid, inode.i_gid,name);
+		if (LINUX_S_ISDIR(inode.i_mode))
+			fprintf(ls->f, "/");
+		else
+			fprintf(ls->f, "%lld/", inode.i_size | ((__u64)inode.i_size_high << 32));
+		fprintf(ls->f, "\n");
+	}
+	else if (ls->options & LONG_OPT) {
 		if (ino) {
 			if (debugfs_read_inode(ino, &inode, name))
 				return 0;
@@ -123,7 +133,7 @@
 		return;
 
 	reset_getopt();
-	while ((c = getopt (argc, argv, "dl")) != EOF) {
+	while ((c = getopt (argc, argv, "dlp")) != EOF) {
 		switch (c) {
 		case 'l':
 			ls.options |= LONG_OPT;
@@ -131,6 +141,9 @@
 		case 'd':
 			ls.options |= DELETED_OPT;
 			break;
+		case 'p':
+			ls.options |= PARSE_OPT;
+			break;
 		default:
 			goto print_usage;
 		}
@@ -138,7 +151,7 @@
 
 	if (argc > optind+1) {
 	print_usage:
-		com_err(0, 0, "Usage: ls [-l] [-d] file");
+		com_err(0, 0, "Usage: ls [-l] [-d] [-p] file");
 		return;
 	}
 
diff --git a/debugfs/lsdel.c b/debugfs/lsdel.c
index b3293b8..f703c6b 100644
--- a/debugfs/lsdel.c
+++ b/debugfs/lsdel.c
@@ -140,7 +140,8 @@
 		lsd.free_blocks = 0;
 		lsd.bad_blocks = 0;
 		
-		retval = ext2fs_block_iterate2(current_fs, ino, 0, block_buf,
+		retval = ext2fs_block_iterate2(current_fs, ino,
+					       BLOCK_FLAG_READ_ONLY, block_buf,
 					       lsdel_proc, &lsd);
 		if (retval) {
 			com_err("ls_deleted_inodes", retval,
diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
index 454a3db..ee51c45 100644
--- a/debugfs/set_fields.c
+++ b/debugfs/set_fields.c
@@ -29,6 +29,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif
 #include <fcntl.h>
 #include <utime.h>
 
@@ -39,6 +42,7 @@
 static struct ext2_super_block set_sb;
 static struct ext2_inode set_inode;
 static struct ext2_group_desc set_gd;
+static dgrp_t set_bg;
 static ext2_ino_t set_ino;
 static int array_idx;
 
@@ -60,6 +64,7 @@
 static errcode_t parse_hashalg(struct field_set_info *info, char *arg);
 static errcode_t parse_time(struct field_set_info *info, char *arg);
 static errcode_t parse_bmap(struct field_set_info *info, char *arg);
+static errcode_t parse_gd_csum(struct field_set_info *info, char *arg);
 
 static struct field_set_info super_fields[] = {
 	{ "inodes_count", &set_sb.s_inodes_count, 4, parse_uint },
@@ -175,7 +180,7 @@
 	{ "flags", &set_gd.bg_flags, 2, parse_uint },
 	{ "reserved", &set_gd.bg_reserved, 2, parse_uint, FLAG_ARRAY, 2 },
 	{ "itable_unused", &set_gd.bg_itable_unused, 2, parse_uint },
-	{ "checksum", &set_gd.bg_checksum, 2, parse_uint },
+	{ "checksum", &set_gd.bg_checksum, 2, parse_gd_csum },
 	{ 0, 0, 0, 0 }
 };
 
@@ -399,6 +404,19 @@
 	return retval;
 }
 
+static errcode_t parse_gd_csum(struct field_set_info *info, char *arg)
+{
+
+	if (strcmp(arg, "calc") == 0) {
+		ext2fs_group_desc_csum_set(current_fs, set_bg);
+		set_gd = current_fs->group_desc[set_bg];
+		printf("Checksum set to 0x%04x\n", 
+		       current_fs->group_desc[set_bg].bg_checksum);
+		return 0;
+	}
+
+	return parse_uint(info, arg);
+}
 
 static void print_possible_fields(struct field_set_info *fields)
 {
@@ -518,7 +536,6 @@
 		"\t\"set_block_group_descriptor -l\" will list the names of "
 		"the fields in a block group descriptor\n\twhich can be set.";
 	struct field_set_info	*ss;
-	dgrp_t			set_bg;
 	char			*end;
 
 	if ((argc == 2) && !strcmp(argv[1], "-l")) {
diff --git a/debugfs/util.c b/debugfs/util.c
index ebce9d6..28abe52 100644
--- a/debugfs/util.c
+++ b/debugfs/util.c
@@ -123,7 +123,7 @@
 
 	retval = ext2fs_namei(current_fs, root, cwd, str, &ino);
 	if (retval) {
-		com_err(str, retval, "");
+		com_err(str, retval, 0);
 		return 0;
 	}
 	return ino;
@@ -192,7 +192,7 @@
 {
 	static int	do_gmt = -1;
 	time_t		t = (time_t) cl;
-	char *		tz;
+	const char	*tz;
 
 	if (do_gmt == -1) {
 		/* The diet libc doesn't respect the TZ environemnt variable */
@@ -277,10 +277,8 @@
 
 	blk = parse_ulong(str, cmd, "block number", &err);
 	*ret = blk;
-	if (err == 0 && blk == 0) {
-		com_err(cmd, 0, "Invalid block number 0");
-		err = 1;
-	}
+	if (err)
+		com_err(cmd, 0, "Invalid block number: %s", str);
 	return err;
 }
 
@@ -340,6 +338,11 @@
 
 	if (strtoblk(argv[0], argv[1], block))
 		return 1;
+	if (*block == 0) {
+		com_err(argv[0], 0, "Invalid block number 0");
+		err = 1;
+	}
+
 	if (argc > 2) {
 		*count = parse_ulong(argv[2], argv[0], "count", &err);
 		if (err)
diff --git a/doc/libext2fs.texinfo b/doc/libext2fs.texinfo
index f3b0d1e..bfe8971 100644
--- a/doc/libext2fs.texinfo
+++ b/doc/libext2fs.texinfo
@@ -7,11 +7,9 @@
 
 @ifinfo
 @dircategory Development
-@format
-START-INFO-DIR-ENTRY
+@direntry
 * libext2fs: (libext2fs.info).                  The EXT2FS library.
-END-INFO-DIR-ENTRY
-@end format
+@end direntry
 @end ifinfo
 
 @c smallbook
diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in
index d5a8887..be6dfb7 100644
--- a/e2fsck/Makefile.in
+++ b/e2fsck/Makefile.in
@@ -62,7 +62,7 @@
 #MCHECK= -DMCHECK
 
 OBJS= dict.o unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o pass3.o pass4.o \
-	pass5.o journal.o swapfs.o badblocks.o util.o dirinfo.o dx_dirinfo.o \
+	pass5.o journal.o badblocks.o util.o dirinfo.o dx_dirinfo.o \
 	ehandler.o problem.o message.o recovery.o region.o revoke.o \
 	ea_refcount.o rehash.o profile.o prof_err.o $(MTRACE_OBJ)
 
@@ -71,7 +71,7 @@
 	profiled/pass2.o profiled/pass3.o profiled/pass4.o profiled/pass5.o \
 	profiled/journal.o profiled/badblocks.o profiled/util.o \
 	profiled/dirinfo.o profiled/dx_dirinfo.o profiled/ehandler.o \
-	profiled/message.o profiled/problem.o profiled/swapfs.o \
+	profiled/message.o profiled/problem.o \
 	profiled/recovery.o profiled/region.o profiled/revoke.o \
 	profiled/ea_refcount.o profiled/rehash.o profiled/profile.o \
 	profiled/prof_err.o
@@ -96,7 +96,6 @@
 	$(srcdir)/ehandler.c \
 	$(srcdir)/problem.c \
 	$(srcdir)/message.c \
-	$(srcdir)/swapfs.c \
 	$(srcdir)/ea_refcount.c \
 	$(srcdir)/rehash.c \
 	$(srcdir)/region.c \
@@ -378,13 +377,6 @@
  $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(top_srcdir)/lib/blkid/blkid.h $(top_builddir)/lib/blkid/blkid_types.h \
  $(srcdir)/profile.h prof_err.h $(srcdir)/problem.h
-swapfs.o: $(srcdir)/swapfs.c $(top_srcdir)/lib/et/com_err.h \
- $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
- $(top_srcdir)/lib/blkid/blkid.h $(top_builddir)/lib/blkid/blkid_types.h \
- $(srcdir)/profile.h prof_err.h
 ea_refcount.o: $(srcdir)/ea_refcount.c $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
diff --git a/e2fsck/e2fsck.8.in b/e2fsck/e2fsck.8.in
index 3059e60..53c473e 100644
--- a/e2fsck/e2fsck.8.in
+++ b/e2fsck/e2fsck.8.in
@@ -8,7 +8,7 @@
 .SH SYNOPSIS
 .B e2fsck
 [
-.B \-pacnyrdfkvstDFSV
+.B \-pacnyrdfkvtDFV
 ]
 [
 .B \-b
@@ -279,17 +279,6 @@
 .B \-r
 This option does nothing at all; it is provided only for backwards
 compatibility.
-.TP 
-.B \-s
-This option will byte-swap the filesystem so that it is using the normalized, 
-standard byte-order (which is i386 or little endian).  If the filesystem is
-already in the standard byte-order, 
-.B e2fsck 
-will take no action.
-.TP
-.B \-S
-This option will byte-swap the filesystem, regardless of its current 
-byte-order.
 .TP
 .B \-t
 Print timing statistics for
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index 5af82d5..bd173af 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -135,6 +135,8 @@
 	struct timeval user_start;
 	struct timeval system_start;
 	void	*brk_start;
+	unsigned long long bytes_read;
+	unsigned long long bytes_written;
 };
 #endif
 
@@ -427,8 +429,11 @@
 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);
-extern int e2fsck_pass1_check_symlink(ext2_filsys fs,
+extern int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
 				      struct ext2_inode *inode, char *buf);
+extern void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
+			       struct ext2_inode *inode, int restart_flag,
+			       const char *source);
 
 /* pass2.c */
 extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
@@ -456,9 +461,6 @@
 void check_super_block(e2fsck_t ctx);
 int check_backup_super_block(e2fsck_t ctx);
 
-/* swapfs.c */
-void swap_filesys(e2fsck_t ctx);
-
 /* util.c */
 extern void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
 				    const char *description);
@@ -469,14 +471,21 @@
 extern void e2fsck_write_bitmaps(e2fsck_t ctx);
 extern void preenhalt(e2fsck_t ctx);
 extern char *string_copy(e2fsck_t ctx, const char *str, int len);
+extern errcode_t e2fsck_zero_blocks(ext2_filsys fs, blk_t blk, int num,
+				    blk_t *ret_blk, int *ret_count);
 #ifdef RESOURCE_TRACK
 extern void print_resource_track(const char *desc,
-				 struct resource_track *track);
-extern void init_resource_track(struct resource_track *track);
+				 struct resource_track *track,
+				 io_channel channel);
+extern void init_resource_track(struct resource_track *track,
+				io_channel channel);
 #endif
 extern int inode_has_valid_blocks(struct ext2_inode *inode);
 extern void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
 			      struct ext2_inode * inode, const char * proc);
+extern void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
+				   struct ext2_inode *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);
 extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
diff --git a/e2fsck/journal.c b/e2fsck/journal.c
index dbe1bf1..ec0af4b 100644
--- a/e2fsck/journal.c
+++ b/e2fsck/journal.c
@@ -385,7 +385,7 @@
 		memcpy(&jsuper, start ? bh->b_data :  bh->b_data + 1024,
 		       sizeof(jsuper));
 		brelse(bh);
-#ifdef EXT2FS_ENABLE_SWAPFS
+#ifdef WORDS_BIGENDIAN
 		if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) 
 			ext2fs_swap_super(&jsuper);
 #endif
@@ -988,6 +988,7 @@
 	ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
 	ext2fs_mark_ib_dirty(fs);
 	fs->group_desc[group].bg_free_inodes_count++;
+	ext2fs_group_desc_csum_set(fs, group);
 	fs->super->s_free_inodes_count++;
 	return;
 
diff --git a/e2fsck/message.c b/e2fsck/message.c
index b2e3e0f..8a3705e 100644
--- a/e2fsck/message.c
+++ b/e2fsck/message.c
@@ -80,6 +80,7 @@
  * 	@S	superblock
  * 	@u	unattached
  * 	@v	device
+ *	@x	extent
  * 	@z	zero-length
  */
 
@@ -134,6 +135,7 @@
 	N_("Ssuper@b"),
 	N_("uunattached"),
 	N_("vdevice"),
+	N_("xextent"),
 	N_("zzero-length"),
 	"@@",
 	0
@@ -388,7 +390,11 @@
 		fputc('%', stdout);
 		break;
 	case 'b':
-		printf("%u", ctx->blk);
+#ifdef EXT2_NO_64_TYPE
+		printf("%u", (unsigned long) ctx->blk);
+#else
+		printf("%llu", (unsigned long long) ctx->blk);
+#endif
 		break;
 	case 'B':
 #ifdef EXT2_NO_64_TYPE
@@ -398,7 +404,11 @@
 #endif
 		break;
 	case 'c':
-		printf("%u", ctx->blk2);
+#ifdef EXT2_NO_64_TYPE
+		printf("%u", (unsigned long) ctx->blk2);
+#else
+		printf("%llu", (unsigned long long) ctx->blk2);
+#endif
 		break;
 	case 'd':
 		printf("%u", ctx->dir);
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 839f099..b85f04f 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -163,17 +163,42 @@
  * Check to make sure a symlink inode is real.  Returns 1 if the symlink
  * checks out, 0 if not.
  */
-int e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode,
-			       char *buf)
+int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
+			       struct ext2_inode *inode, char *buf)
 {
 	unsigned int len;
 	int i;
 	blk_t	blocks;
+	ext2_extent_handle_t	handle;
+	struct ext2_extent_info	info;
+	struct ext2fs_extent	extent;
 
 	if ((inode->i_size_high || inode->i_size == 0) ||
 	    (inode->i_flags & EXT2_INDEX_FL))
 		return 0;
 
+	if (inode->i_flags & EXT4_EXTENTS_FL) {
+		if (inode->i_size > fs->blocksize)
+			return 0;
+		if (ext2fs_extent_open(fs, ino, &handle))
+			return 0;
+		i = 0;
+		if (ext2fs_extent_get_info(handle, &info) ||
+		    (info.num_entries != 1) ||
+		    (info.max_depth != 0))
+			goto exit_extent;
+		if (ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent) ||
+		    (extent.e_lblk != 0) ||
+		    (extent.e_len != 1) ||
+		    (extent.e_pblk < fs->super->s_first_data_block) ||
+		    (extent.e_pblk >= fs->super->s_blocks_count))
+			goto exit_extent;
+		i = 1;
+	exit_extent:
+		ext2fs_extent_free(handle);
+		return i;
+	}
+
 	blocks = ext2fs_inode_data_blocks(fs, inode);
 	if (blocks) {
 		if ((inode->i_size >= fs->blocksize) ||
@@ -264,6 +289,7 @@
 	remain = storage_size - sizeof(__u32); 
 
 	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
+		__u32 hash;
 
 		/* header eats this space */
 		remain -= sizeof(struct ext2_ext_attr_entry);
@@ -291,9 +317,12 @@
 			problem = PR_1_ATTR_VALUE_BLOCK;
 			goto fix;
 		}
-		
-		/* e_hash must be 0 in inode's ea */
-		if (entry->e_hash != 0) {
+
+		hash = ext2fs_ext_attr_hash_entry(entry,
+						  start + entry->e_value_offs);
+
+		/* e_hash may be 0 in older inode's ea */
+		if (entry->e_hash != 0 && entry->e_hash != hash) {
 			pctx->num = entry->e_hash;
 			problem = PR_1_ATTR_HASH;
 			goto fix;
@@ -308,15 +337,12 @@
 	 * it seems like a corruption. it's very unlikely we could repair
 	 * EA(s) in automatic fashion -bzzz
 	 */
-#if 0
-	problem = PR_1_ATTR_HASH;
-#endif
 	if (problem == 0 || !fix_problem(ctx, problem, pctx))
 		return;
 
-	/* simple remove all possible EA(s) */
+	/* simply remove all possible EA(s) */
 	*((__u32 *)start) = 0UL;
-	e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *) inode,
+	e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
 				EXT2_INODE_SIZE(sb), "pass1");
 }
 
@@ -480,12 +506,12 @@
 	struct		scan_callback_struct scan_struct;
 	struct ext2_super_block *sb = ctx->fs->super;
 	const char	*old_op;
-	int		imagic_fs;
+	int		imagic_fs, extent_fs;
 	int		busted_fs_time = 0;
 	int		inode_size;
 	
 #ifdef RESOURCE_TRACK
-	init_resource_track(&rtrack);
+	init_resource_track(&rtrack, ctx->fs->io);
 #endif
 	clear_problem_context(&pctx);
 
@@ -514,6 +540,7 @@
 #undef EXT2_BPP
 
 	imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
+	extent_fs = (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS);
 
 	/*
 	 * Allocate bitmaps structures
@@ -653,6 +680,76 @@
 				return;
 			}
 		}
+
+		/*
+		 * Test for incorrect extent flag settings.
+		 *
+		 * On big-endian machines we must be careful:
+		 * When the inode is read, the i_block array is not swapped
+		 * if the extent flag is set.  Therefore if we are testing
+		 * for or fixing a wrongly-set flag, we must potentially
+		 * (un)swap before testing, or after fixing.
+		 */
+
+		/*
+		 * In this case the extents flag was set when read, so
+		 * extent_header_verify is ok.  If the inode is cleared,
+		 * no need to swap... so no extra swapping here.
+		 */
+		if ((inode->i_flags & EXT4_EXTENTS_FL) && !extent_fs && 
+		    (inode->i_links_count || (ino == EXT2_BAD_INO) ||
+		     (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO))) {
+			if ((ext2fs_extent_header_verify(inode->i_block, 
+						 sizeof(inode->i_block)) == 0) &&
+			    fix_problem(ctx, PR_1_EXTENT_FEATURE, &pctx)) {
+				sb->s_feature_incompat |= EXT3_FEATURE_INCOMPAT_EXTENTS;
+				ext2fs_mark_super_dirty(fs);
+				extent_fs = 1;
+			} else if (fix_problem(ctx, PR_1_EXTENTS_SET, &pctx)) {
+			clear_inode:
+				e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
+				if (ino == EXT2_BAD_INO)
+					ext2fs_mark_inode_bitmap(ctx->inode_used_map, 
+								 ino);
+				continue;
+			}
+		}
+
+		/*
+		 * For big-endian machines:
+		 * If the inode didn't have the extents flag set when it
+		 * was read, then the i_blocks array was swapped.  To test
+		 * as an extents header, we must swap it back first.
+		 * IF we then set the extents flag, the entire i_block
+		 * array must be un/re-swapped to make it proper extents data.
+		 */
+		if (extent_fs && !(inode->i_flags & EXT4_EXTENTS_FL) &&
+		    (inode->i_links_count || (ino == EXT2_BAD_INO) ||
+		     (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO)) &&
+		    (LINUX_S_ISREG(inode->i_mode) ||
+		     LINUX_S_ISDIR(inode->i_mode))) {
+			void *ehp;
+#ifdef WORDS_BIGENDIAN
+			__u32 tmp_block[EXT2_N_BLOCKS];
+
+			for (i = 0; i < EXT2_N_BLOCKS; i++)
+				tmp_block[i] = ext2fs_swab32(inode->i_block[i]);
+			ehp = tmp_block;
+#else
+			ehp = inode->i_block;
+#endif
+			if ((ext2fs_extent_header_verify(ehp, 
+					 sizeof(inode->i_block)) == 0) &&
+			    (fix_problem(ctx, PR_1_UNSET_EXTENT_FL, &pctx))) {
+				inode->i_flags |= EXT4_EXTENTS_FL;
+#ifdef WORDS_BIGENDIAN
+				memcpy(inode->i_block, tmp_block, 
+				       sizeof(inode->i_block));
+#endif
+				e2fsck_write_inode(ctx, ino, inode, "pass1");
+			}
+		}
+
 		if (ino == EXT2_BAD_INO) {
 			struct process_block_struct pb;
 			
@@ -695,15 +792,8 @@
 			 * regnerated in pass #3.
 			 */
 			if (!LINUX_S_ISDIR(inode->i_mode)) {
-				if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
-					inode->i_dtime = ctx->now;
-					inode->i_links_count = 0;
-					ext2fs_icount_store(ctx->inode_link_info,
-							    ino, 0);
-					e2fsck_write_inode(ctx, ino, inode,
-							   "pass1");
-				}
-
+				if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx))
+					goto clear_inode;
 			}
 			/*
 			 * If dtime is set, offer to clear it.  mke2fs
@@ -834,10 +924,6 @@
 			frag = inode->osd2.hurd2.h_i_frag;
 			fsize = inode->osd2.hurd2.h_i_fsize;
 			break;
-		    case EXT2_OS_MASIX:
-			frag = inode->osd2.masix2.m_i_frag;
-			fsize = inode->osd2.masix2.m_i_fsize;
-			break;
 		    default:
 			frag = fsize = 0;
 		}
@@ -868,6 +954,18 @@
 		check_inode_extra_space(ctx, &pctx);
 		check_is_really_dir(ctx, &pctx, block_buf);
 
+		/*
+		 * ext2fs_inode_has_valid_blocks does not actually look
+		 * at i_block[] values, so not endian-sensitive here.
+		 */
+		if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL) &&
+		    LINUX_S_ISLNK(inode->i_mode) &&
+		    !ext2fs_inode_has_valid_blocks(inode) &&
+		    fix_problem(ctx, PR_1_FAST_SYMLINK_EXTENT_FL, &pctx)) {
+			inode->i_flags &= ~EXT4_EXTENTS_FL;
+			e2fsck_write_inode(ctx, ino, inode, "pass1");
+		}
+
 		if (LINUX_S_ISDIR(inode->i_mode)) {
 			ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
 			e2fsck_add_dir_info(ctx, ino, 0);
@@ -886,7 +984,8 @@
 			check_size(ctx, &pctx);
 			ctx->fs_blockdev_count++;
 		} else if (LINUX_S_ISLNK (inode->i_mode) &&
-			   e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
+			   e2fsck_pass1_check_symlink(fs, ino, inode, 
+						      block_buf)) {
 			check_immutable(ctx, &pctx);
 			ctx->fs_symlinks_count++;
 			if (ext2fs_inode_data_blocks(fs, inode) == 0) {
@@ -913,10 +1012,11 @@
 			ctx->fs_dind_count++;
 		if (inode->i_block[EXT2_TIND_BLOCK])
 			ctx->fs_tind_count++;
-		if (inode->i_block[EXT2_IND_BLOCK] ||
-		    inode->i_block[EXT2_DIND_BLOCK] ||
-		    inode->i_block[EXT2_TIND_BLOCK] ||
-		    inode->i_file_acl) {
+		if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
+		    (inode->i_block[EXT2_IND_BLOCK] ||
+		     inode->i_block[EXT2_DIND_BLOCK] ||
+		     inode->i_block[EXT2_TIND_BLOCK] ||
+		     inode->i_file_acl)) {
 			inodes_to_process[process_inode_count].ino = ino;
 			inodes_to_process[process_inode_count].inode = *inode;
 			process_inode_count++;
@@ -1013,7 +1113,7 @@
 #ifdef RESOURCE_TRACK
 	if (ctx->options & E2F_OPT_TIME2) {
 		e2fsck_clear_progbar(ctx);
-		print_resource_track(_("Pass 1"), &rtrack);
+		print_resource_track(_("Pass 1"), &rtrack, ctx->fs->io);
 	}
 #endif
 }
@@ -1364,10 +1464,13 @@
 	entry = (struct ext2_ext_attr_entry *)(header+1);
 	end = block_buf + fs->blocksize;
 	while ((char *)entry < end && *(__u32 *)entry) {
+		__u32 hash;
+
 		if (region_allocate(region, (char *)entry - (char *)header,
 			           EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
 			if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
 				goto clear_extattr;
+			break;
 		}
 		if ((ctx->ext_attr_ver == 1 &&
 		     (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
@@ -1375,6 +1478,7 @@
 		     entry->e_name_index == 0)) {
 			if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
 				goto clear_extattr;
+			break;
 		}
 		if (entry->e_value_block != 0) {
 			if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
@@ -1391,6 +1495,17 @@
 			if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
 				goto clear_extattr;
 		}
+
+		hash = ext2fs_ext_attr_hash_entry(entry, block_buf +
+							 entry->e_value_offs);
+
+		if (entry->e_hash != hash) {
+			pctx->num = entry->e_hash;
+			if (fix_problem(ctx, PR_1_ATTR_HASH, pctx))
+				goto clear_extattr;
+			entry->e_hash = hash;
+		}
+
 		entry = EXT2_EXT_ATTR_NEXT(entry);
 	}
 	if (region_allocate(region, (char *)entry - (char *)header, 4)) {
@@ -1416,8 +1531,7 @@
 
 /* Returns 1 if bad htree, 0 if OK */
 static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
-			ext2_ino_t ino EXT2FS_ATTR((unused)),
-			struct ext2_inode *inode,
+			ext2_ino_t ino, struct ext2_inode *inode,
 			char *block_buf)
 {
 	struct ext2_dx_root_info	*root;
@@ -1431,12 +1545,17 @@
 	     fix_problem(ctx, PR_1_HTREE_SET, pctx)))
 		return 1;
 
-	blk = inode->i_block[0];
-	if (((blk == 0) ||
-	     (blk < fs->super->s_first_data_block) ||
-	     (blk >= fs->super->s_blocks_count)) &&
-	    fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
-		return 1;
+	pctx->errcode = ext2fs_bmap(fs, ino, inode, 0, 0, 0, &blk);
+
+	if ((pctx->errcode) ||
+	    (blk == 0) ||
+	    (blk < fs->super->s_first_data_block) ||
+	    (blk >= fs->super->s_blocks_count)) {
+		if (fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
+			return 1;
+		else
+			return 0;
+	}
 
 	retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
 	if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
@@ -1468,6 +1587,147 @@
 	return 0;
 }
 
+void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
+			struct ext2_inode *inode, int restart_flag,
+			const char *source)
+{
+	inode->i_flags = 0;
+	inode->i_links_count = 0;
+	ext2fs_icount_store(ctx->inode_link_info, ino, 0);
+	inode->i_dtime = ctx->now;
+
+	ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
+	ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
+	if (ctx->inode_reg_map)
+		ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
+	if (ctx->inode_bad_map)
+		ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
+
+	/*
+	 * If the inode was partially accounted for before processing
+	 * was aborted, we need to restart the pass 1 scan.
+	 */
+	ctx->flags |= restart_flag;
+
+	e2fsck_write_inode(ctx, ino, inode, source);
+}
+
+static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
+			     struct process_block_struct *pb, 
+			     ext2_extent_handle_t ehandle)
+{
+	struct ext2fs_extent	extent;
+	blk_t			blk;
+	e2_blkcnt_t		blockcnt;
+	int			i;
+	int			is_dir, is_leaf;
+	errcode_t		problem;
+
+
+	pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB,
+					  &extent);
+	while (!pctx->errcode) {
+		is_leaf = extent.e_flags & EXT2_EXTENT_FLAGS_LEAF;
+		is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
+
+		problem = 0;
+		if (extent.e_pblk < ctx->fs->super->s_first_data_block ||
+		    extent.e_pblk >= ctx->fs->super->s_blocks_count)
+			problem = PR_1_EXTENT_BAD_START_BLK;
+		else if ((extent.e_pblk + extent.e_len) >
+			 ctx->fs->super->s_blocks_count)
+			problem = PR_1_EXTENT_ENDS_BEYOND;
+
+		if (problem) {
+			pctx->blk = extent.e_pblk;
+			pctx->blk2 = extent.e_lblk;
+			pctx->num = extent.e_len;
+			if (fix_problem(ctx, problem, pctx)) {
+				pctx->errcode =
+					ext2fs_extent_delete(ehandle, 0);
+				if (pctx->errcode) {
+					fix_problem(ctx,
+						    PR_1_EXTENT_DELETE_FAIL,
+						    pctx);
+					/* Should never get here */
+					ctx->flags |= E2F_FLAG_ABORT;
+					return;
+				}
+			}
+			goto next;
+		}
+
+		if (!is_leaf) {
+			mark_block_used(ctx, extent.e_pblk);
+			pb->num_blocks++;
+			pctx->errcode = ext2fs_extent_get(ehandle,
+						  EXT2_EXTENT_DOWN, &extent);
+			if (pctx->errcode) {
+				printf("Error1: %s on inode %lld\n",
+					error_message(pctx->errcode), pctx->ino);
+				abort();
+			}
+			scan_extent_node(ctx, pctx, pb, ehandle);
+			pctx->errcode = ext2fs_extent_get(ehandle,
+						  EXT2_EXTENT_UP, &extent);
+			if (pctx->errcode) {
+				printf("Error1: %s on inode %lld\n",
+					error_message(pctx->errcode), pctx->ino);
+				abort();
+			}
+			goto next;
+		}
+
+		for (blk = extent.e_pblk, blockcnt = extent.e_lblk, i = 0;
+		     i < extent.e_len;
+		     blk++, blockcnt++, i++) {
+			mark_block_used(ctx, blk);
+
+			if (is_dir) {
+				pctx->errcode = ext2fs_add_dir_block(ctx->fs->dblist, pctx->ino, blk, blockcnt);
+				if (pctx->errcode) {
+					pctx->blk = blk;
+					pctx->num = blockcnt;
+					fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
+					/* Should never get here */
+					ctx->flags |= E2F_FLAG_ABORT;
+					return;
+				}
+			}
+		}
+		pb->num_blocks += extent.e_len;
+		pb->last_block = extent.e_lblk + extent.e_len - 1;
+	next:
+		pctx->errcode = ext2fs_extent_get(ehandle,
+						  EXT2_EXTENT_NEXT_SIB,
+						  &extent);
+	}
+	if (pctx->errcode == EXT2_ET_EXTENT_NO_NEXT)
+		pctx->errcode = 0;
+}
+
+static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
+				 struct process_block_struct *pb, 
+				 char *block_buf)
+{
+	struct ext2_inode	*inode = pctx->inode;
+	ext2_extent_handle_t	ehandle;
+	ext2_filsys		fs = ctx->fs;
+	ext2_ino_t		ino = pctx->ino;
+
+	pctx->errcode = ext2fs_extent_open(fs, ino, &ehandle);
+	if (pctx->errcode &&
+	    fix_problem(ctx, PR_1_READ_EXTENT, pctx)) {
+		e2fsck_clear_inode(ctx, ino, inode, 0, "check_blocks_extents");
+		pctx->errcode = 0;
+		return;
+	}
+
+	scan_extent_node(ctx, pctx, pb, ehandle);
+
+	ext2fs_extent_free(ehandle);
+}
+
 /*
  * This subroutine is called on each inode to account for all of the
  * blocks used by that inode.
@@ -1512,13 +1772,22 @@
 		}
 	}
 
-	if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
+	if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf)) {
+		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+			goto out;
 		pb.num_blocks++;
+	}
 
-	if (ext2fs_inode_has_valid_blocks(inode))
-		pctx->errcode = ext2fs_block_iterate2(fs, ino,
-				       pb.is_dir ? BLOCK_FLAG_HOLE : 0,
-				       block_buf, process_block, &pb);
+	if (ext2fs_inode_has_valid_blocks(inode)) {
+		if ((ctx->fs->super->s_feature_incompat &
+		     EXT3_FEATURE_INCOMPAT_EXTENTS) &&
+		    (inode->i_flags & EXT4_EXTENTS_FL))
+			check_blocks_extents(ctx, pctx, &pb, block_buf);
+		else
+			pctx->errcode = ext2fs_block_iterate2(fs, ino,
+						pb.is_dir ? BLOCK_FLAG_HOLE : 0,
+						block_buf, process_block, &pb);
+	}
 	end_problem_latch(ctx, PR_LATCH_BLOCK);
 	end_problem_latch(ctx, PR_LATCH_TOOBIG);
 	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
@@ -1530,20 +1799,9 @@
 		ctx->fs_fragmented++;
 
 	if (pb.clear) {
-		inode->i_links_count = 0;
-		ext2fs_icount_store(ctx->inode_link_info, ino, 0);
-		inode->i_dtime = ctx->now;
-		dirty_inode++;
-		ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
-		ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
-		ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
-		/*
-		 * The inode was probably partially accounted for
-		 * before processing was aborted, so we need to
-		 * restart the pass 1 scan.
-		 */
-		ctx->flags |= E2F_FLAG_RESTART;
-		goto out;
+		e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART,
+				   "check_blocks");
+		return;
 	}
 	
 	if (pb.is_dir) {
@@ -1583,15 +1841,9 @@
 		
 	if (!pb.num_blocks && pb.is_dir) {
 		if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
-			inode->i_links_count = 0;
-			ext2fs_icount_store(ctx->inode_link_info, ino, 0);
-			inode->i_dtime = ctx->now;
-			dirty_inode++;
-			ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
-			ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
-			ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
+			e2fsck_clear_inode(ctx, ino, inode, 0, "check_blocks");
 			ctx->fs_directory_count--;
-			goto out;
+			return;
 		}
 	}
 
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
index dab3134..06cf87b 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -294,7 +294,8 @@
 		if (ext2fs_inode_has_valid_blocks(&inode) ||
 		    (ino == EXT2_BAD_INO))
 			pctx.errcode = ext2fs_block_iterate2(fs, ino,
-				     0, block_buf, process_pass1b_block, &pb);
+					     BLOCK_FLAG_READ_ONLY, block_buf,
+					     process_pass1b_block, &pb);
 		if (inode.i_file_acl)
 			process_pass1b_block(fs, &inode.i_file_acl,
 					     BLOCK_COUNT_EXTATTR, 0, 0, &pb);
@@ -590,20 +591,17 @@
 
 	e2fsck_read_inode(ctx, ino, &inode, "delete_file");
 	if (ext2fs_inode_has_valid_blocks(&inode))
-		pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
-						     delete_file_block, &pb);
+		pctx.errcode = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_READ_ONLY, 
+						     block_buf, delete_file_block, &pb);
 	if (pctx.errcode)
 		fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
-	ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
-	ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
 	if (ctx->inode_bad_map)
 		ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
 	ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
 
 	/* Inode may have changed by block_iterate, so reread it */
 	e2fsck_read_inode(ctx, ino, &inode, "delete_file");
-	inode.i_links_count = 0;
-	inode.i_dtime = ctx->now;
+	e2fsck_clear_inode(ctx, ino, &inode, 0, "delete_file");
 	if (inode.i_file_acl &&
 	    (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
 		count = 1;
@@ -629,7 +627,6 @@
 			delete_file_block(fs, &inode.i_file_acl,
 					  BLOCK_COUNT_EXTATTR, 0, 0, &pb);
 	}
-	e2fsck_write_inode(ctx, ino, &inode, "delete_file");
 }
 
 struct clone_struct {
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index b79461d..906662d 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -102,7 +102,7 @@
 	int			bad_dir;
 
 #ifdef RESOURCE_TRACK
-	init_resource_track(&rtrack);
+	init_resource_track(&rtrack, ctx->fs->io);
 #endif
 
 	clear_problem_context(&cd.pctx);
@@ -151,7 +151,7 @@
 	
 	cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
 						&cd);
-	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+	if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
 		return;
 	if (cd.pctx.errcode) {
 		fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
@@ -280,7 +280,7 @@
 #ifdef RESOURCE_TRACK
 	if (ctx->options & E2F_OPT_TIME2) {
 		e2fsck_clear_progbar(ctx);
-		print_resource_track(_("Pass 2"), &rtrack);
+		print_resource_track(_("Pass 2"), &rtrack, fs->io);
 	}
 #endif
 }
@@ -727,7 +727,7 @@
 	buf = cd->buf;
 	ctx = cd->ctx;
 
-	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+	if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
 		return DIRENT_ABORT;
 	
 	if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
@@ -831,6 +831,9 @@
 	dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
 	prev = 0;
 	do {
+		int group;
+		ext2_ino_t first_unused_inode;
+
 		problem = 0;
 		dirent = (struct ext2_dir_entry *) (buf + offset);
 		cd->pctx.dirent = dirent;
@@ -880,12 +883,6 @@
 		     (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
 		    (dirent->inode > fs->super->s_inodes_count)) {
 			problem = PR_2_BAD_INO;
-		} else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
-					       dirent->inode))) {
-			/*
-			 * If the inode is unused, offer to clear it.
-			 */
-			problem = PR_2_UNUSED_INODE;
 		} else if (ctx->inode_bb_map &&
 			   (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
 						     dirent->inode))) {
@@ -962,6 +959,67 @@
 				return DIRENT_ABORT;
 		}
 
+		group = ext2fs_group_of_ino(fs, dirent->inode);
+		first_unused_inode = group * fs->super->s_inodes_per_group +
+					1 + fs->super->s_inodes_per_group -
+					fs->group_desc[group].bg_itable_unused;
+		cd->pctx.group = group;
+
+		/*
+		 * Check if the inode was missed out because _INODE_UNINIT
+		 * flag was set or bg_itable_unused was incorrect.
+		 * If that is the case restart e2fsck.
+		 * XXX Optimisations TODO:
+		 * 1. only restart e2fsck once
+		 * 2. only exposed inodes are checked again.
+		 */
+		if (fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT) {
+			if (fix_problem(ctx, PR_2_INOREF_BG_INO_UNINIT,
+					&cd->pctx)){
+				fs->group_desc[group].bg_flags &=
+					~EXT2_BG_INODE_UNINIT;
+				ctx->flags |= E2F_FLAG_RESTART |
+					E2F_FLAG_SIGNAL_MASK;
+			} else {
+				ext2fs_unmark_valid(fs);
+				if (problem == PR_2_BAD_INO)
+					goto next;
+			}
+		} else if (dirent->inode >= first_unused_inode) {
+			if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){
+				fs->group_desc[group].bg_itable_unused = 0;
+				fs->group_desc[group].bg_flags &=
+					~EXT2_BG_INODE_UNINIT;
+				ext2fs_mark_super_dirty(fs);
+				ctx->flags |= E2F_FLAG_RESTART;
+				goto restart_fsck;
+			} else {
+				ext2fs_unmark_valid(fs);
+				if (problem == PR_2_BAD_INO)
+					goto next;
+			}
+		}
+
+		if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
+					       dirent->inode))) {
+			/*
+			 * If the inode is unused, offer to clear it.
+			 */
+			problem = PR_2_UNUSED_INODE;
+		}
+
+		if (problem) {
+			if (fix_problem(ctx, problem, &cd->pctx)) {
+				dirent->inode = 0;
+				dir_modified++;
+				goto next;
+			} else {
+				ext2fs_unmark_valid(fs);
+				if (problem == PR_2_BAD_INO)
+					goto next;
+			}
+		}
+
 		if (check_name(ctx, dirent, ino, &cd->pctx))
 			dir_modified++;
 
@@ -1071,8 +1129,9 @@
 	dict_free_nodes(&de_dict);
 	return 0;
 abort_free_dict:
-	dict_free_nodes(&de_dict);
 	ctx->flags |= E2F_FLAG_ABORT;
+restart_fsck:
+	dict_free_nodes(&de_dict);
 	return DIRENT_ABORT;
 }
 
@@ -1109,11 +1168,8 @@
 	struct problem_context	pctx;
 	__u32			count;
 	
-	ext2fs_icount_store(ctx->inode_link_info, ino, 0);
 	e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
-	inode.i_links_count = 0;
-	inode.i_dtime = ctx->now;
-	e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
+	e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode");
 	clear_problem_context(&pctx);
 	pctx.ino = ino;
 
@@ -1121,10 +1177,6 @@
 	 * Fix up the bitmaps...
 	 */
 	e2fsck_read_bitmaps(ctx);
-	ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
-	ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
-	if (ctx->inode_bad_map)
-		ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
 	ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
 
 	if (inode.i_file_acl &&
@@ -1225,7 +1277,7 @@
 		 && !e2fsck_pass1_check_device_inode(fs, &inode))
 		problem = PR_2_BAD_SOCKET;
 	else if (LINUX_S_ISLNK(inode.i_mode)
-		 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
+		 && !e2fsck_pass1_check_symlink(fs, ino, &inode, buf)) {
 		problem = PR_2_INVALID_SYMLINK;
 	}
 
@@ -1253,10 +1305,6 @@
 		frag = &inode.osd2.hurd2.h_i_frag;
 		fsize = &inode.osd2.hurd2.h_i_fsize;
 		break;
-	    case EXT2_OS_MASIX:
-		frag = &inode.osd2.masix2.m_i_frag;
-		fsize = &inode.osd2.masix2.m_i_fsize;
-		break;
 	    default:
 		frag = fsize = 0;
 	}
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index b9c6edd..867cbf8 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -61,7 +61,7 @@
 	unsigned long maxdirs, count;
 
 #ifdef RESOURCE_TRACK
-	init_resource_track(&rtrack);
+	init_resource_track(&rtrack, ctx->fs->io);
 #endif
 
 	clear_problem_context(&pctx);
@@ -87,7 +87,8 @@
 #ifdef RESOURCE_TRACK
 	if (ctx->options & E2F_OPT_TIME) {
 		e2fsck_clear_progbar(ctx);
-		print_resource_track(_("Peak memory"), &ctx->global_rtrack);
+		print_resource_track(_("Peak memory"), &ctx->global_rtrack,
+				     NULL);
 	}
 #endif
 
@@ -142,7 +143,7 @@
 #ifdef RESOURCE_TRACK
 	if (ctx->options & E2F_OPT_TIME2) {
 		e2fsck_clear_progbar(ctx);
-		print_resource_track(_("Pass 3"), &rtrack);
+		print_resource_track(_("Pass 3"), &rtrack, ctx->fs->io);
 	}
 #endif
 }
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index dfb3a37..ebc19a8 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -15,6 +15,7 @@
 
 #include "e2fsck.h"
 #include "problem.h"
+#include <ext2fs/ext2_ext_attr.h>
 
 /*
  * This routine is called when an inode is not connected to the
@@ -23,39 +24,45 @@
  * This subroutine returns 1 then the caller shouldn't bother with the
  * rest of the pass 4 tests.
  */
-static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
+static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
+			    struct ext2_inode *inode)
 {
 	ext2_filsys fs = ctx->fs;
-	struct ext2_inode	inode;
 	struct problem_context	pctx;
+	__u32 eamagic = 0;
+	int extra_size = 0;
 
-	e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
+	if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE) {
+		e2fsck_read_inode_full(ctx, i, inode,EXT2_INODE_SIZE(fs->super),
+				       "pass4: disconnect_inode");
+		extra_size = ((struct ext2_inode_large *)inode)->i_extra_isize;
+	} else {
+		e2fsck_read_inode(ctx, i, inode, "pass4: disconnect_inode");
+	}
 	clear_problem_context(&pctx);
 	pctx.ino = i;
-	pctx.inode = &inode;
+	pctx.inode = inode;
 	
+	if (EXT2_INODE_SIZE(fs->super) -EXT2_GOOD_OLD_INODE_SIZE -extra_size >0)
+		eamagic = *(__u32 *)(((char *)inode) +EXT2_GOOD_OLD_INODE_SIZE +
+				     extra_size);
 	/*
 	 * Offer to delete any zero-length files that does not have
 	 * blocks.  If there is an EA block, it might have useful
 	 * information, so we won't prompt to delete it, but let it be
 	 * reconnected to lost+found.
 	 */
-	if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
-				LINUX_S_ISDIR(inode.i_mode))) {
+	if (!inode->i_blocks && eamagic != EXT2_EXT_ATTR_MAGIC &&
+	    (LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISDIR(inode->i_mode))) {
 		if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
-			ext2fs_icount_store(ctx->inode_link_info, i, 0);
-			inode.i_links_count = 0;
-			inode.i_dtime = ctx->now;
-			e2fsck_write_inode(ctx, i, &inode,
+			e2fsck_clear_inode(ctx, i, inode, 0, 
 					   "disconnect_inode");
 			/*
 			 * Fix up the bitmaps...
 			 */
 			e2fsck_read_bitmaps(ctx);
-			ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
-			ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
 			ext2fs_inode_alloc_stats2(fs, i, -1,
-						  LINUX_S_ISDIR(inode.i_mode));
+						  LINUX_S_ISDIR(inode->i_mode));
 			return 0;
 		}
 	}
@@ -83,7 +90,7 @@
 {
 	ext2_filsys fs = ctx->fs;
 	ext2_ino_t	i;
-	struct ext2_inode	inode;
+	struct ext2_inode	*inode;
 #ifdef RESOURCE_TRACK
 	struct resource_track	rtrack;
 #endif
@@ -93,7 +100,7 @@
 	int	group, maxgroup;
 	
 #ifdef RESOURCE_TRACK
-	init_resource_track(&rtrack);
+	init_resource_track(&rtrack, ctx->fs->io);
 #endif
 
 #ifdef MTRACE
@@ -111,6 +118,9 @@
 		if ((ctx->progress)(ctx, 4, 0, maxgroup))
 			return;
 
+	inode = e2fsck_allocate_memory(ctx, EXT2_INODE_SIZE(fs->super),
+				       "scratch inode");
+
 	/* Protect loop from wrap-around if s_inodes_count maxed */
 	for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) {
 		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
@@ -138,26 +148,34 @@
 				     fs->blocksize, "bad_inode buffer");
 			if (e2fsck_process_bad_inode(ctx, 0, i, buf))
 				continue;
-			if (disconnect_inode(ctx, i))
+			if (disconnect_inode(ctx, i, inode))
 				continue;
 			ext2fs_icount_fetch(ctx->inode_link_info, i,
 					    &link_count);
 			ext2fs_icount_fetch(ctx->inode_count, i,
 					    &link_counted);
 		}
+		if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i) &&
+		    (link_counted > EXT2_LINK_MAX))
+			link_counted = 1;
 		if (link_counted != link_count) {
-			e2fsck_read_inode(ctx, i, &inode, "pass4");
+			e2fsck_read_inode(ctx, i, inode, "pass4");
 			pctx.ino = i;
-			pctx.inode = &inode;
-			if (link_count != inode.i_links_count) {
+			pctx.inode = inode;
+			if (link_count != inode->i_links_count) {
 				pctx.num = link_count;
 				fix_problem(ctx,
 					    PR_4_INCONSISTENT_COUNT, &pctx);
 			}
 			pctx.num = link_counted;
-			if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
-				inode.i_links_count = link_counted;
-				e2fsck_write_inode(ctx, i, &inode, "pass4");
+			/* i_link_count was previously exceeded, but no longer
+			 * is, fix this but don't consider it an error */
+			if ((LINUX_S_ISDIR(inode->i_mode) && link_counted > 1 &&
+			     (inode->i_flags & EXT2_INDEX_FL) &&
+			     link_count == 1 && !(ctx->options & E2F_OPT_NO)) ||
+			     (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx))) {
+				inode->i_links_count = link_counted;
+				e2fsck_write_inode(ctx, i, inode, "pass4");
 			}
 		}
 	}
@@ -170,10 +188,12 @@
 errout:
 	if (buf)
 		ext2fs_free_mem(&buf);
+
+	ext2fs_free_mem(&inode);
 #ifdef RESOURCE_TRACK
 	if (ctx->options & E2F_OPT_TIME2) {
 		e2fsck_clear_progbar(ctx);
-		print_resource_track(_("Pass 4"), &rtrack);
+		print_resource_track(_("Pass 4"), &rtrack, ctx->fs->io);
 	}
 #endif
 }
diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c
index 56619c3..b70e8d1 100644
--- a/e2fsck/pass5.c
+++ b/e2fsck/pass5.c
@@ -30,7 +30,7 @@
 #endif
 
 #ifdef RESOURCE_TRACK
-	init_resource_track(&rtrack);
+	init_resource_track(&rtrack, ctx->fs->io);
 #endif
 	
 	clear_problem_context(&pctx);
@@ -67,7 +67,7 @@
 #ifdef RESOURCE_TRACK
 	if (ctx->options & E2F_OPT_TIME2) {
 		e2fsck_clear_progbar(ctx);
-		print_resource_track(_("Pass 5"), &rtrack);
+		print_resource_track(_("Pass 5"), &rtrack, ctx->fs->io);
 	}
 #endif
 }
@@ -114,14 +114,14 @@
 	blk_t	i, super;
 	int	*free_array;
 	int	group = 0;
-	unsigned int	blocks = 0;
-	unsigned int	free_blocks = 0;
+	blk_t	blocks = 0;
+	blk_t	free_blocks = 0;
 	int	group_free = 0;
 	int	actual, bitmap;
 	struct problem_context	pctx;
 	int	problem, save_problem, fixit, had_problem;
 	errcode_t	retval;
-	int		lazy_bg = 0;
+	int		lazy_flag, csum_flag;
 	int		skip_group = 0;
 
 	clear_problem_context(&pctx);
@@ -158,15 +158,16 @@
 		goto errout;
 	}
 
-	if (EXT2_HAS_COMPAT_FEATURE(fs->super, EXT2_FEATURE_COMPAT_LAZY_BG))
-		lazy_bg++;
-
+	lazy_flag = EXT2_HAS_COMPAT_FEATURE(fs->super,
+					    EXT2_FEATURE_COMPAT_LAZY_BG);
+	csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					       EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
 redo_counts:
 	had_problem = 0;
 	save_problem = 0;
 	pctx.blk = pctx.blk2 = NO_BLK;
-	if (lazy_bg && (fs->group_desc[group].bg_flags &
-			EXT2_BG_BLOCK_UNINIT))
+	if ((lazy_flag || csum_flag) &&
+	    (fs->group_desc[group].bg_flags & EXT2_BG_BLOCK_UNINIT))
 		skip_group++;
 	super = fs->super->s_first_data_block;
 	for (i = fs->super->s_first_data_block;
@@ -206,6 +207,17 @@
 			 * Block used, but not marked in use in the bitmap.
 			 */
 			problem = PR_5_BLOCK_USED;
+
+			if (skip_group) {
+				struct problem_context pctx2;
+				pctx2.blk = i;
+				pctx2.group = group;
+				if (fix_problem(ctx, PR_5_BLOCK_UNINIT,&pctx2)){
+					fs->group_desc[group].bg_flags &=
+						~EXT2_BG_BLOCK_UNINIT;
+					skip_group = 0;
+				}
+			}
 		}
 		if (pctx.blk == NO_BLK) {
 			pctx.blk = pctx.blk2 = i;
@@ -224,7 +236,7 @@
 		had_problem++;
 
 	do_counts:
-		if (!bitmap && !skip_group) {
+		if (!bitmap && (!skip_group || csum_flag)) {
 			group_free++;
 			free_blocks++;
 		}
@@ -241,7 +253,7 @@
 				if ((ctx->progress)(ctx, 5, group,
 						    fs->group_desc_count*2))
 					goto errout;
-			if (lazy_bg &&
+			if ((lazy_flag || csum_flag) &&
 			    (i != fs->super->s_blocks_count-1) &&
 			    (fs->group_desc[group].bg_flags &
 			     EXT2_BG_BLOCK_UNINIT))
@@ -321,7 +333,7 @@
 	errcode_t	retval;
 	struct problem_context	pctx;
 	int		problem, save_problem, fixit, had_problem;
-	int		lazy_bg = 0;
+	int		lazy_flag, csum_flag;
 	int		skip_group = 0;
 
 	clear_problem_context(&pctx);
@@ -358,16 +370,16 @@
 		goto errout;
 	}
 
-	if (EXT2_HAS_COMPAT_FEATURE(fs->super,
-				    EXT2_FEATURE_COMPAT_LAZY_BG))
-		lazy_bg++;
-
+	lazy_flag = EXT2_HAS_COMPAT_FEATURE(fs->super,
+					    EXT2_FEATURE_COMPAT_LAZY_BG);
+	csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					       EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
 redo_counts:
 	had_problem = 0;
 	save_problem = 0;
 	pctx.ino = pctx.ino2 = 0;
-	if (lazy_bg && (fs->group_desc[group].bg_flags &
-			EXT2_BG_INODE_UNINIT))
+	if ((lazy_flag || csum_flag) &&
+	    (fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT))
 		skip_group++;
 
 	/* Protect loop from wrap-around if inodes_count is maxed */
@@ -390,6 +402,21 @@
 			 * Inode used, but not in bitmap
 			 */
 			problem = PR_5_INODE_USED;
+
+			/* We should never hit this, because it means that
+			 * inodes were marked in use that weren't noticed
+			 * in pass1 or pass 2. It is easier to fix the problem
+			 * than to kill e2fsck and leave the user stuck. */
+			if (skip_group) {
+				struct problem_context pctx2;
+				pctx2.blk = i;
+				pctx2.group = group;
+				if (fix_problem(ctx, PR_5_INODE_UNINIT,&pctx2)){
+					fs->group_desc[group].bg_flags &=
+						~EXT2_BG_INODE_UNINIT;
+					skip_group = 0;
+				}
+			}
 		}
 		if (pctx.ino == 0) {
 			pctx.ino = pctx.ino2 = i;
@@ -411,7 +438,7 @@
 		if (bitmap) {
 			if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
 				dirs_count++;
-		} else if (!skip_group) {
+		} else if (!skip_group || csum_flag) {
 			group_free++;
 			free_inodes++;
 		}
@@ -430,7 +457,7 @@
 					    group + fs->group_desc_count,
 					    fs->group_desc_count*2))
 					goto errout;
-			if (lazy_bg &&
+			if ((lazy_flag || csum_flag) &&
 			    (i != fs->super->s_inodes_count) &&
 			    (fs->group_desc[group].bg_flags &
 			     EXT2_BG_INODE_UNINIT))
@@ -563,7 +590,7 @@
 
 	clear_problem_context(&pctx);
 
-	end = fs->block_map->start +
+	end = ext2fs_get_block_bitmap_start(fs->block_map) +
 		(EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
 	pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
 						     &save_blocks_count);
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index e00dbc1..d9ae911 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -54,7 +54,7 @@
 	N_("Allocate"),		/* 4 */
 	N_("Expand"),		/* 5 */
 	N_("Connect to /lost+found"), /* 6 */
-	N_("Create"),		/* 7 */	
+	N_("Create"),		/* 7 */
 	N_("Salvage"),		/* 8 */
 	N_("Truncate"),		/* 9 */
 	N_("Clear inode"),	/* 10 */
@@ -104,11 +104,11 @@
 
 	/* Block bitmap not in group */
 	{ PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g.  (@b %b)\n"),
-	  PROMPT_RELOCATE, PR_LATCH_RELOC }, 
+	  PROMPT_RELOCATE, PR_LATCH_RELOC },
 
 	/* Inode bitmap not in group */
 	{ PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g.  (@b %b)\n"),
-	  PROMPT_RELOCATE, PR_LATCH_RELOC }, 
+	  PROMPT_RELOCATE, PR_LATCH_RELOC },
 
 	/* Inode table not in group */
 	{ PR_0_ITABLE_NOT_GROUP,
@@ -132,7 +132,7 @@
 	  "Either the @S or the partition table is likely to be corrupt!\n"),
 	  PROMPT_ABORT, 0 },
 
-	/* Fragments not supported */		  
+	/* Fragments not supported */
 	{ PR_0_NO_FRAGMENTS,
 	  N_("@S @b_size = %b, fragsize = %c.\n"
 	  "This version of e2fsck does not support fragment sizes different\n"
@@ -148,7 +148,7 @@
 	{ PR_0_FIRST_DATA_BLOCK,
 	  N_("@S first_data_@b = %b, should have been %c\n"),
 	  PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
-	
+
 	/* Adding UUID to filesystem */
 	{ PR_0_ADD_UUID,
 	  N_("@f did not have a UUID; generating one.\n\n"),
@@ -169,7 +169,7 @@
 	  PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
 
 	/* Error determing physical device size of filesystem */
-	{ PR_0_GETSIZE_ERROR,	  
+	{ PR_0_GETSIZE_ERROR,
 	  N_("Error determining size of the physical @v: %m\n"),
 	  PROMPT_NONE, PR_FATAL },
 
@@ -259,12 +259,12 @@
 	{ PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
 	   N_("@I @b #%B (%b) found in @o @i %i.\n"),
 	  PROMPT_NONE, 0 },
-		  
+
 	/* Already cleared block found in orphaned inode */
 	{ PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
 	   N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
 	  PROMPT_NONE, 0 },
-  
+
 	/* Illegal orphan inode in superblock */
 	{ PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
 	  N_("@I @o @i %i in @S.\n"),
@@ -351,16 +351,41 @@
 	  N_("Adding dirhash hint to @f.\n\n"),
 	  PROMPT_NONE, 0 },
 
+	/* group descriptor N checksum is invalid. */
+	{ PR_0_GDT_CSUM,
+	  N_("@g descriptor %g checksum is invalid.  "),
+	     PROMPT_FIX, PR_PREEN_OK },
+
+	/* group descriptor N marked uninitialized without feature set. */
+	{ PR_0_GDT_UNINIT,
+	  N_("@g descriptor %g marked uninitialized without feature set.\n"),
+	     PROMPT_FIX, PR_PREEN_OK },
+
+	/* group N block bitmap uninitialized but inode bitmap in use. */
+	{ PR_0_BB_UNINIT_IB_INIT,
+	  N_("@g %g @b @B uninitialized but @i @B in use.\n"),
+	     PROMPT_FIX, PR_PREEN_OK },
+
+	/* Group descriptor N has invalid unused inodes count. */
+	{ PR_0_GDT_ITABLE_UNUSED,
+	  N_("@g descriptor %g has invalid unused inodes count %b.  "),
+	     PROMPT_FIX, PR_PREEN_OK },
+
+	/* Last group block bitmap uninitialized. */
+	{ PR_0_BB_UNINIT_LAST,
+	  N_("Last @g @b @B uninitialized.  "),
+	     PROMPT_FIX, PR_PREEN_OK },
+
 	/* Pass 1 errors */
-	
+
 	/* Pass 1: Checking inodes, blocks, and sizes */
 	{ PR_1_PASS_HEADER,
 	  N_("Pass 1: Checking @is, @bs, and sizes\n"),
 	  PROMPT_NONE, 0 },
-		  
+
 	/* Root directory is not an inode */
 	{ PR_1_ROOT_NO_DIR, N_("@r is not a @d.  "),
-	  PROMPT_CLEAR, 0 }, 
+	  PROMPT_CLEAR, 0 },
 
 	/* Root directory has dtime set */
 	{ PR_1_ROOT_DTIME,
@@ -416,7 +441,7 @@
 	{ PR_1_BAD_I_SIZE,
 	  N_("@i %i, i_size is %Is, @s %N.  "),
 	  PROMPT_FIX, PR_PREEN_OK },
-		  
+
 	/* Inode has incorrect i_blocks */
 	{ PR_1_BAD_I_BLOCKS,
 	  N_("@i %i, i_@bs is %Ib, @s %N.  "),
@@ -440,7 +465,7 @@
 	/* Too many bad blocks in inode */
 	{ PR_1_TOO_MANY_BAD_BLOCKS,
 	  N_("Too many illegal @bs in @i %i.\n"),
-	  PROMPT_CLEAR_INODE, PR_NO_OK }, 	
+	  PROMPT_CLEAR_INODE, PR_NO_OK },
 
 	/* Illegal block number in bad block inode */
 	{ PR_1_BB_ILLEGAL_BLOCK_NUM,
@@ -457,12 +482,12 @@
 	  N_("Duplicate or bad @b in use!\n"),
 	  PROMPT_NONE, 0 },
 
-	/* Bad block used as bad block indirect block */	  
+	/* Bad block used as bad block indirect block */
 	{ PR_1_BBINODE_BAD_METABLOCK,
 	  N_("Bad @b %b used as bad @b @i indirect @b.  "),
 	  PROMPT_CLEAR, PR_LATCH_BBLOCK },
 
-	/* Inconsistency can't be fixed prompt */	  
+	/* Inconsistency can't be fixed prompt */
 	{ PR_1_BBINODE_BAD_METABLOCK_PROMPT,
 	  N_("\nThe bad @b @i has probably been corrupted.  You probably\n"
 	     "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
@@ -470,12 +495,12 @@
 	  PROMPT_CONTINUE, PR_PREEN_NOMSG },
 
 	/* Bad primary block */
-	{ PR_1_BAD_PRIMARY_BLOCK,  
+	{ PR_1_BAD_PRIMARY_BLOCK,
 	  N_("\nIf the @b is really bad, the @f can not be fixed.\n"),
 	  PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
-		  
+
 	/* Bad primary block prompt */
-	{ PR_1_BAD_PRIMARY_BLOCK_PROMPT,	  
+	{ PR_1_BAD_PRIMARY_BLOCK_PROMPT,
 	  N_("You can remove this @b from the bad @b list and hope\n"
 	     "that the @b is really OK.  But there are no guarantees.\n\n"),
 	  PROMPT_CLEAR, PR_PREEN_NOMSG },
@@ -484,25 +509,25 @@
 	{ PR_1_BAD_PRIMARY_SUPERBLOCK,
 	  N_("The primary @S (%b) is on the bad @b list.\n"),
 	  PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
-		  
+
 	/* Bad primary block group descriptors */
 	{ PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
 	  N_("Block %b in the primary @g descriptors "
 	  "is on the bad @b list\n"),
 	  PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
-		  
+
 	/* Bad superblock in group */
 	{ PR_1_BAD_SUPERBLOCK,
 	  N_("Warning: Group %g's @S (%b) is bad.\n"),
 	  PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
-		  
+
 	/* Bad block group descriptors in group */
 	{ PR_1_BAD_GROUP_DESCRIPTORS,
 	  N_("Warning: Group %g's copy of the @g descriptors has a bad "
 	  "@b (%b).\n"),
 	  PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
 
-	/* Block claimed for no reason */	  
+	/* Block claimed for no reason */
 	{ PR_1_PROGERR_CLAIMED_BLOCK,
 	  N_("Programming error?  @b #%b claimed for no reason in "
 	  "process_bad_@b.\n"),
@@ -512,27 +537,27 @@
 	{ PR_1_RELOC_BLOCK_ALLOCATE,
 	  N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
 	  PROMPT_NONE, PR_PREEN_OK },
-		
+
 	/* Error allocating block buffer during relocation process */
 	{ PR_1_RELOC_MEMORY_ALLOCATE,
 	  N_("@A @b buffer for relocating %s\n"),
 	  PROMPT_NONE, PR_PREEN_OK },
-		
-	/* Relocating metadata group information from X to Y */	
+
+	/* Relocating metadata group information from X to Y */
 	{ PR_1_RELOC_FROM_TO,
 	  N_("Relocating @g %g's %s from %b to %c...\n"),
 	  PROMPT_NONE, PR_PREEN_OK },
-		
+
 	/* Relocating metatdata group information to X */
 	{ PR_1_RELOC_TO,
 	  N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */
 	  PROMPT_NONE, PR_PREEN_OK },
-		
+
 	/* Block read error during relocation process */
 	{ PR_1_RELOC_READ_ERR,
 	  N_("Warning: could not read @b %b of %s: %m\n"),
 	  PROMPT_NONE, PR_PREEN_OK },
-		
+
 	/* Block write error during relocation process */
 	{ PR_1_RELOC_WRITE_ERR,
 	  N_("Warning: could not write @b %b for %s: %m\n"),
@@ -568,25 +593,25 @@
 	  N_("Error while iterating over @bs in @i %i: %m\n"),
 	  PROMPT_NONE, PR_FATAL },
 
-	/* Error while storing inode count information */	  
+	/* Error while storing inode count information */
 	{ PR_1_ICOUNT_STORE,
 	  N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
 	  PROMPT_NONE, PR_FATAL },
 
-	/* Error while storing directory block information */	  
+	/* Error while storing directory block information */
 	{ PR_1_ADD_DBLOCK,
 	  N_("Error storing @d @b information "
 	  "(@i=%i, @b=%b, num=%N): %m\n"),
 	  PROMPT_NONE, PR_FATAL },
 
-	/* Error while reading inode (for clearing) */	  
+	/* Error while reading inode (for clearing) */
 	{ PR_1_READ_INODE,
 	  N_("Error reading @i %i: %m\n"),
 	  PROMPT_NONE, PR_FATAL },
 
 	/* Suppress messages prompt */
 	{ PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
-		  
+
 	/* Imagic flag set on an inode when filesystem doesn't support it */
 	{ PR_1_SET_IMAGIC,
 	  N_("@i %i has imagic flag set.  "),
@@ -613,11 +638,11 @@
 	  N_("@f has feature flag(s) set, but is a revision 0 @f.  "),
 	  PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
 
-	/* Journal inode is not in use, but contains data */	  
+	/* Journal inode is not in use, but contains data */
 	{ PR_1_JOURNAL_INODE_NOT_CLEAR,
 	  N_("@j @i is not in use, but contains data.  "),
-	  PROMPT_CLEAR, PR_PREEN_OK },	  
-	  
+	  PROMPT_CLEAR, PR_PREEN_OK },
+
 	/* Journal has bad mode */
 	{ PR_1_JOURNAL_BAD_MODE,
 	  N_("@j is not regular file.  "),
@@ -626,14 +651,14 @@
 	/* Deal with inodes that were part of orphan linked list */
 	{ PR_1_LOW_DTIME,
 	  N_("@i %i was part of the @o @i list.  "),
-	  PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },    
+	  PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
 
 	/* Deal with inodes that were part of corrupted orphan linked
 	   list (latch question) */
 	{ PR_1_ORPHAN_LIST_REFUGEES,
 	  N_("@is that were part of a corrupted orphan linked list found.  "),
-	  PROMPT_FIX, 0 },		  
-		  
+	  PROMPT_FIX, 0 },
+
 	/* Error allocating refcount structure */
 	{ PR_1_ALLOCATE_REFCOUNT,
 	  N_("@A refcount structure (%N): %m\n"),
@@ -653,13 +678,13 @@
 	{ PR_1_EXTATTR_READ_ABORT,
 	  N_("Error reading @a @b %b (%m).  "),
 	  PROMPT_ABORT, 0 },
-		  
+
 	/* Extended attribute reference count incorrect */
 	{ PR_1_EXTATTR_REFCOUNT,
 	  N_("@a @b %b has reference count %B, @s %N.  "),
 	  PROMPT_FIX, 0 },
-		  
-	/* Error writing Extended Attribute block while fixing refcount */ 
+
+	/* Error writing Extended Attribute block while fixing refcount */
 	{ PR_1_EXTATTR_WRITE,
 	  N_("Error writing @a @b %b (%m).  "),
 	  PROMPT_ABORT, 0 },
@@ -667,22 +692,22 @@
 	/* Multiple EA blocks not supported */
 	{ PR_1_EA_MULTI_BLOCK,
 	  N_("@a @b %b has h_@bs > 1.  "),
-	  PROMPT_CLEAR, 0},	  
+	  PROMPT_CLEAR, 0},
 
 	/* Error allocating EA region allocation structure */
 	{ PR_1_EA_ALLOC_REGION,
 	  N_("@A @a @b %b.  "),
 	  PROMPT_ABORT, 0},
-	
+
 	/* Error EA allocation collision */
 	{ PR_1_EA_ALLOC_COLLISION,
 	  N_("@a @b %b is corrupt (allocation collision).  "),
 	  PROMPT_CLEAR, 0},
-	
+
 	/* Bad extended attribute name */
 	{ PR_1_EA_BAD_NAME,
 	  N_("@a @b %b is corrupt (@n name).  "),
-	  PROMPT_CLEAR, 0},	  
+	  PROMPT_CLEAR, 0},
 
 	/* Bad extended attribute value */
 	{ PR_1_EA_BAD_VALUE,
@@ -694,7 +719,7 @@
 	  N_("@i %i is too big.  "), PROMPT_TRUNCATE, 0 },
 
 	/* Directory too big */
-	{ PR_1_TOOBIG_DIR, 
+	{ PR_1_TOOBIG_DIR,
 	  N_("@b #%B (%b) causes @d to be too big.  "),
 	  PROMPT_CLEAR, PR_LATCH_TOOBIG },
 
@@ -713,31 +738,31 @@
 	  N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
 	  PROMPT_CLEAR_HTREE, PR_PREEN_OK },
 
-	/* INDEX_FL flag set on a non-directory */	
+	/* INDEX_FL flag set on a non-directory */
 	{ PR_1_HTREE_NODIR,
 	  N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
 	  PROMPT_CLEAR_HTREE, PR_PREEN_OK },
 
-	/* Invalid root node in HTREE directory */	
+	/* Invalid root node in HTREE directory */
 	{ PR_1_HTREE_BADROOT,
 	  N_("@h %i has an @n root node.\n"),
 	  PROMPT_CLEAR_HTREE, PR_PREEN_OK },
 
-	/* Unsupported hash version in HTREE directory */	
+	/* Unsupported hash version in HTREE directory */
 	{ PR_1_HTREE_HASHV,
 	  N_("@h %i has an unsupported hash version (%N)\n"),
 	  PROMPT_CLEAR_HTREE, PR_PREEN_OK },
 
-	/* Incompatible flag in HTREE root node */	
+	/* Incompatible flag in HTREE root node */
 	{ PR_1_HTREE_INCOMPAT,
 	  N_("@h %i uses an incompatible htree root node flag.\n"),
 	  PROMPT_CLEAR_HTREE, PR_PREEN_OK },
 
-	/* HTREE too deep */	
+	/* HTREE too deep */
 	{ PR_1_HTREE_DEPTH,
 	  N_("@h %i has a tree depth (%N) which is too big\n"),
 	  PROMPT_CLEAR_HTREE, PR_PREEN_OK },
-		  
+
 	/* Bad block has indirect block that conflicts with filesystem block */
 	{ PR_1_BB_FS_BLOCK,
 	  N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
@@ -749,34 +774,34 @@
 	  N_("Resize @i (re)creation failed: %m."),
 	  PROMPT_ABORT, 0 },
 
-	/* invalid inode->i_extra_isize */	
+	/* invalid inode->i_extra_isize */
 	{ PR_1_EXTRA_ISIZE,
 	  N_("@i %i has a extra size (%IS) which is @n\n"),
 	  PROMPT_FIX, PR_PREEN_OK },
 
-	/* invalid ea entry->e_name_len */	
+	/* invalid ea entry->e_name_len */
 	{ PR_1_ATTR_NAME_LEN,
 	  N_("@a in @i %i has a namelen (%N) which is @n\n"),
 	  PROMPT_CLEAR, PR_PREEN_OK },
 
-	/* invalid ea entry->e_value_size */	
+	/* invalid ea entry->e_value_size */
 	{ PR_1_ATTR_VALUE_SIZE,
 	  N_("@a in @i %i has a value size (%N) which is @n\n"),
 	  PROMPT_CLEAR, PR_PREEN_OK },
 
-	/* invalid ea entry->e_value_offs */	
+	/* invalid ea entry->e_value_offs */
 	{ PR_1_ATTR_VALUE_OFFSET,
 	  N_("@a in @i %i has a value offset (%N) which is @n\n"),
 	  PROMPT_CLEAR, PR_PREEN_OK },
 
-	/* invalid ea entry->e_value_block */	
+	/* invalid ea entry->e_value_block */
 	{ PR_1_ATTR_VALUE_BLOCK,
 	  N_("@a in @i %i has a value @b (%N) which is @n (must be 0)\n"),
 	  PROMPT_CLEAR, PR_PREEN_OK },
 
-	/* invalid ea entry->e_hash */	
+	/* invalid ea entry->e_hash */
 	{ PR_1_ATTR_HASH,
-	  N_("@a in @i %i has a hash (%N) which is @n (must be 0)\n"),
+	  N_("@a in @i %i has a hash (%N) which is @n\n"),
 	  PROMPT_CLEAR, PR_PREEN_OK },
 
 	/* inode appears to be a directory */
@@ -784,6 +809,46 @@
 	  N_("@i %i is a %It but it looks like it is really a directory.\n"),
 	  PROMPT_FIX, 0 },
 
+	/* Error while reading extent tree */
+	{ PR_1_READ_EXTENT,
+	  N_("Error while reading over @x tree in @i %i: %m\n"),
+	  PROMPT_CLEAR_INODE, 0 },
+
+	/* Error deleting a bogus extent */
+	{ PR_1_EXTENT_DELETE_FAIL,
+	  N_("Error while deleting extent: %m\n"),
+	  PROMPT_ABORT, 0 },
+
+	/* Bad starting block in extent */
+	{ PR_1_EXTENT_BAD_START_BLK,
+	  N_("@i %i has an @n extent\n\t(logical @b %c, @n physical @b %b, len %N)\n"),
+	  PROMPT_CLEAR, 0 },
+
+	/* Extent ends beyond filesystem */
+	{ PR_1_EXTENT_ENDS_BEYOND,
+	  N_("@i %i has an @n extent\n\t(logical @b %c, physical @b %b, @n len %N)\n"),
+	  PROMPT_CLEAR, 0 },
+
+	/* EXTENTS_FL flag set on a non-extents filesystem */
+	{ PR_1_EXTENTS_SET,
+	  N_("@i %i has EXTENTS_FL flag set on @f without extents support.\n"),
+	  PROMPT_CLEAR, 0 },
+
+	/* inode has extents, superblock missing INCOMPAT_EXTENTS feature */
+	{ PR_1_EXTENT_FEATURE,
+	  N_("@i %i is in extent format, but @S is missing EXTENTS feature\n"),
+	  PROMPT_FIX, 0 },
+
+	/* inode missing EXTENTS_FL, but is an extent inode */
+	{ PR_1_UNSET_EXTENT_FL,
+	  N_("@i %i missing EXTENT_FL, but is in extents format\n"),
+	  PROMPT_FIX, PR_PREEN_OK },
+
+	/* Fast symlink has EXTENTS_FL set */
+	{ PR_1_FAST_SYMLINK_EXTENT_FL,
+	  N_("Fast symlink %i has EXTENT_FL set.  "),
+	  PROMPT_CLEAR, 0 },
+
 	/* Pass 1b errors */
 
 	/* Pass 1B: Rescan for duplicate/bad blocks */
@@ -793,12 +858,12 @@
 	  PROMPT_NONE, 0 },
 
 	/* Duplicate/bad block(s) header */
-	{ PR_1B_DUP_BLOCK_HEADER,	  
+	{ PR_1B_DUP_BLOCK_HEADER,
 	  N_("@m @b(s) in @i %i:"),
 	  PROMPT_NONE, 0 },
 
 	/* Duplicate/bad block(s) in inode */
-	{ PR_1B_DUP_BLOCK,	  
+	{ PR_1B_DUP_BLOCK,
 	  " %b",
 	  PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
 
@@ -806,7 +871,7 @@
 	{ PR_1B_DUP_BLOCK_END,
 	  "\n",
 	  PROMPT_NONE, PR_PREEN_NOHDR },
-		  
+
 	/* Error while scanning inodes */
 	{ PR_1B_ISCAN_ERROR,
 	  N_("Error while scanning inodes (%i): %m\n"),
@@ -833,29 +898,29 @@
 	  N_("Pass 1C: Scanning directories for @is with @m @bs\n"),
 	  PROMPT_NONE, 0 },
 
-		  
+
 	/* Pass 1D: Reconciling multiply-claimed blocks */
 	{ PR_1D_PASS_HEADER,
 	  N_("Pass 1D: Reconciling @m @bs\n"),
 	  PROMPT_NONE, 0 },
-		  
+
 	/* File has duplicate blocks */
 	{ PR_1D_DUP_FILE,
 	  N_("File %Q (@i #%i, mod time %IM) \n"
 	  "  has %B @m @b(s), shared with %N file(s):\n"),
 	  PROMPT_NONE, 0 },
-		  
-	/* List of files sharing duplicate blocks */	
+
+	/* List of files sharing duplicate blocks */
 	{ PR_1D_DUP_FILE_LIST,
 	  N_("\t%Q (@i #%i, mod time %IM)\n"),
 	  PROMPT_NONE, 0 },
-	  
-	/* File sharing blocks with filesystem metadata  */	
+
+	/* File sharing blocks with filesystem metadata  */
 	{ PR_1D_SHARE_METADATA,
 	  N_("\t<@f metadata>\n"),
 	  PROMPT_NONE, 0 },
 
-	/* Report of how many duplicate/bad inodes */	
+	/* Report of how many duplicate/bad inodes */
 	{ PR_1D_NUM_DUP_INODES,
 	  N_("(There are %N @is containing @m @bs.)\n\n"),
 	  PROMPT_NONE, 0 },
@@ -868,7 +933,7 @@
 	/* Clone duplicate/bad blocks? */
 	{ PR_1D_CLONE_QUESTION,
 	  "", PROMPT_CLONE, PR_NO_OK },
-		  
+
 	/* Delete file? */
 	{ PR_1D_DELETE_QUESTION,
 	  "", PROMPT_DELETE, 0 },
@@ -883,24 +948,24 @@
 	{ PR_2_PASS_HEADER,
 	  N_("Pass 2: Checking @d structure\n"),
 	  PROMPT_NONE, 0 },
-		  
+
 	/* Bad inode number for '.' */
 	{ PR_2_BAD_INODE_DOT,
 	  N_("@n @i number for '.' in @d @i %i.\n"),
 	  PROMPT_FIX, 0 },
 
 	/* Directory entry has bad inode number */
-	{ PR_2_BAD_INO, 
+	{ PR_2_BAD_INO,
 	  N_("@E has @n @i #: %Di.\n"),
 	  PROMPT_CLEAR, 0 },
 
 	/* Directory entry has deleted or unused inode */
-	{ PR_2_UNUSED_INODE, 
+	{ PR_2_UNUSED_INODE,
 	  N_("@E has @D/unused @i %Di.  "),
 	  PROMPT_CLEAR, PR_PREEN_OK },
 
 	/* Directry entry is link to '.' */
-	{ PR_2_LINK_DOT, 
+	{ PR_2_LINK_DOT,
 	  N_("@E @L to '.'  "),
 	  PROMPT_CLEAR, 0 },
 
@@ -910,26 +975,26 @@
 	  PROMPT_CLEAR, 0 },
 
 	/* Directory entry contains a link to a directory */
-	{ PR_2_LINK_DIR, 
+	{ PR_2_LINK_DIR,
 	  N_("@E @L to @d %P (%Di).\n"),
 	  PROMPT_CLEAR, 0 },
 
 	/* Directory entry contains a link to the root directry */
-	{ PR_2_LINK_ROOT, 
+	{ PR_2_LINK_ROOT,
 	  N_("@E @L to the @r.\n"),
 	  PROMPT_CLEAR, 0 },
 
 	/* Directory entry has illegal characters in its name */
-	{ PR_2_BAD_NAME, 
+	{ PR_2_BAD_NAME,
 	  N_("@E has illegal characters in its name.\n"),
 	  PROMPT_FIX, 0 },
 
-	/* Missing '.' in directory inode */	  
+	/* Missing '.' in directory inode */
 	{ PR_2_MISSING_DOT,
 	  N_("Missing '.' in @d @i %i.\n"),
 	  PROMPT_FIX, 0 },
 
-	/* Missing '..' in directory inode */	  
+	/* Missing '..' in directory inode */
 	{ PR_2_MISSING_DOT_DOT,
 	  N_("Missing '..' in @d @i %i.\n"),
 	  PROMPT_FIX, 0 },
@@ -943,7 +1008,7 @@
 	{ PR_2_2ND_NOT_DOT_DOT,
 	  N_("Second @e '%Dn' (@i=%Di) in @d @i %i @s '..'\n"),
 	  PROMPT_FIX, 0 },
-		  
+
 	/* i_faddr should be zero */
 	{ PR_2_FADDR_ZERO,
 	  N_("i_faddr @F %IF, @s zero.\n"),
@@ -975,17 +1040,17 @@
 	  PROMPT_CLEAR, 0 },
 
 	/* directory corrupted */
-	{ PR_2_DIR_CORRUPTED,	  
+	{ PR_2_DIR_CORRUPTED,
 	  N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
 	  PROMPT_SALVAGE, 0 },
-		  
+
 	/* filename too long */
-	{ PR_2_FILENAME_LONG,	  
+	{ PR_2_FILENAME_LONG,
 	  N_("@d @i %i, @b %B, offset %N: filename too long\n"),
 	  PROMPT_TRUNCATE, 0 },
 
 	/* Directory inode has a missing block (hole) */
-	{ PR_2_DIRECTORY_HOLE,	  
+	{ PR_2_DIRECTORY_HOLE,
 	  N_("@d @i %i has an unallocated @b #%B.  "),
 	  PROMPT_ALLOCATE, 0 },
 
@@ -1012,7 +1077,7 @@
 	/* Duplicate '.' entry */
 	{ PR_2_DUP_DOT,
 	  N_("@E is duplicate '.' @e.\n"),
-	  PROMPT_FIX, 0 },	  
+	  PROMPT_FIX, 0 },
 
 	/* Duplicate '..' entry */
 	{ PR_2_DUP_DOT_DOT,
@@ -1028,7 +1093,7 @@
 	{ PR_2_FINAL_RECLEN,
 	  N_("@E has rec_len of %Dr, @s %N.\n"),
 	  PROMPT_FIX, 0 },
-		  
+
 	/* Error allocating icount structure */
 	{ PR_2_ALLOCATE_ICOUNT,
 	  N_("@A icount structure: %m\n"),
@@ -1108,7 +1173,7 @@
 	{ PR_2_FEATURE_LARGE_FILES,
 	  N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
 	  PROMPT_FIX, 0 },
-	  
+
 	/* Node in HTREE directory not referenced */
 	{ PR_2_HTREE_NOTREF,
 	  N_("@p @h %d: node (%B) not referenced\n"),
@@ -1132,7 +1197,7 @@
 	/* Clear invalid HTREE directory */
 	{ PR_2_HTREE_CLEAR,
 	  N_("@n @h %d (%q).  "), PROMPT_CLEAR_HTREE, 0 },
-		  
+
 	/* Bad block in htree interior node */
 	{ PR_2_HTREE_BADBLK,
 	  N_("@p @h %d (%q): bad @b number %b.\n"),
@@ -1167,22 +1232,22 @@
 	{ PR_2_HTREE_BAD_DEPTH,
 	  N_("@p @h %d: node (%B) has @n depth\n"),
 	  PROMPT_NONE, 0 },
-	
+
 	/* Duplicate directory entry found */
 	{ PR_2_DUPLICATE_DIRENT,
 	  N_("Duplicate @E found.  "),
 	  PROMPT_CLEAR, 0 },
-	
+
 	/* Non-unique filename found */
 	{ PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */
 	  N_("@E has a non-unique filename.\nRename to %s"),
 	  PROMPT_NULL, 0 },
-	
+
 	/* Duplicate directory entry found */
 	{ PR_2_REPORT_DUP_DIRENT,
 	  N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
 	  PROMPT_NONE, 0 },
-	
+
   	/* i_blocks_hi should be zero */
 	{ PR_2_BLOCKS_HI_ZERO,
 	  N_("i_blocks_hi @F %N, @s zero.\n"),
@@ -1191,19 +1256,29 @@
 	/* Unexpected HTREE block */
 	{ PR_2_UNEXPECTED_HTREE_BLOCK,
 	  N_("Unexpected @b in @h %d (%q).\n"), PROMPT_CLEAR_HTREE, 0 },
-		  
+
+	/* Inode found in group where _INODE_UNINIT is set */
+	{ PR_2_INOREF_BG_INO_UNINIT,
+	  N_("@i %i found in @g %g where _INODE_UNINIT is set.  "),
+	  PROMPT_FIX, PR_PREEN_OK },
+
+	/* Inode found in group unused inodes area */
+	{ PR_2_INOREF_IN_UNUSED,
+	  N_("@i %i found in @g %g unused inodes area.  "),
+	  PROMPT_FIX, PR_PREEN_OK },
+
 	/* Pass 3 errors */
 
 	/* Pass 3: Checking directory connectivity */
 	{ PR_3_PASS_HEADER,
 	  N_("Pass 3: Checking @d connectivity\n"),
 	  PROMPT_NONE, 0 },
-		  
+
 	/* Root inode not allocated */
 	{ PR_3_NO_ROOT_INODE,
 	  N_("@r not allocated.  "),
-	  PROMPT_ALLOCATE, 0 },	
-		  
+	  PROMPT_ALLOCATE, 0 },
+
 	/* No room in lost+found */
 	{ PR_3_EXPAND_LF_DIR,
 	  N_("No room in @l @d.  "),
@@ -1245,20 +1320,20 @@
 	  PROMPT_NONE, 0 },
 
 	/* Error in ext2fs_new_block while creating /lost+found */
-	{ PR_3_ERR_LPF_NEW_BLOCK, 
+	{ PR_3_ERR_LPF_NEW_BLOCK,
 	  N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
 	  PROMPT_NONE, 0 },
-		  
+
 	/* Error in ext2fs_new_inode while creating /lost+found */
 	{ PR_3_ERR_LPF_NEW_INODE,
 	  N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
 	  PROMPT_NONE, 0 },
 
-	/* Error in ext2fs_new_dir_block while creating /lost+found */	  
+	/* Error in ext2fs_new_dir_block while creating /lost+found */
 	{ PR_3_ERR_LPF_NEW_DIR_BLOCK,
 	  N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
 	  PROMPT_NONE, 0 },
-		  
+
 	/* Error while writing directory block for /lost+found */
 	{ PR_3_ERR_LPF_WRITE_BLOCK,
 	  N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
@@ -1274,7 +1349,7 @@
 	  N_("Couldn't fix parent of @i %i: %m\n\n"),
 	  PROMPT_NONE, 0 },
 
-	/* Couldn't fix parent directory -- couldn't find it */	  
+	/* Couldn't fix parent directory -- couldn't find it */
 	{ PR_3_FIX_PARENT_NOFIND,
 	  N_("Couldn't fix parent of @i %i: Couldn't find parent @d @e\n\n"),
 	  PROMPT_NONE, 0 },
@@ -1287,22 +1362,22 @@
 	/* Error creating root directory */
 	{ PR_3_CREATE_ROOT_ERROR,
 	  N_("Error creating root @d (%s): %m\n"),
-	  PROMPT_NONE, PR_FATAL },	  
+	  PROMPT_NONE, PR_FATAL },
 
 	/* Error creating lost and found directory */
 	{ PR_3_CREATE_LPF_ERROR,
 	  N_("Error creating /@l @d (%s): %m\n"),
-	  PROMPT_NONE, PR_FATAL },  
+	  PROMPT_NONE, PR_FATAL },
 
 	/* Root inode is not directory; aborting */
 	{ PR_3_ROOT_NOT_DIR_ABORT,
 	  N_("@r is not a @d; aborting.\n"),
-	  PROMPT_NONE, PR_FATAL },  
+	  PROMPT_NONE, PR_FATAL },
 
 	/* Cannot proceed without a root inode. */
 	{ PR_3_NO_ROOT_INODE_ABORT,
 	  N_("Cannot proceed without a @r.\n"),
-	  PROMPT_NONE, PR_FATAL },  
+	  PROMPT_NONE, PR_FATAL },
 
 	/* Internal error: couldn't find dir_info */
 	{ PR_3_NO_DIRINFO,
@@ -1340,19 +1415,19 @@
 	{ PR_3A_OPTIMIZE_DIR,
 	  " %d",
 	  PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
-		  
-	/* Rehashing dir end */	  
+
+	/* Rehashing dir end */
 	{ PR_3A_OPTIMIZE_DIR_END,
 	  "\n",
 	  PROMPT_NONE, PR_PREEN_NOHDR },
 
 	/* Pass 4 errors */
-	
+
 	/* Pass 4: Checking reference counts */
 	{ PR_4_PASS_HEADER,
 	  N_("Pass 4: Checking reference counts\n"),
 	  PROMPT_NONE, 0 },
-		  
+
 	/* Unattached zero-length inode */
 	{ PR_4_ZERO_LEN_INODE,
 	  N_("@u @z @i %i.  "),
@@ -1376,22 +1451,22 @@
 	  PROMPT_NONE, 0 },
 
 	/* Pass 5 errors */
-		  
+
 	/* Pass 5: Checking group summary information */
 	{ PR_5_PASS_HEADER,
 	  N_("Pass 5: Checking @g summary information\n"),
 	  PROMPT_NONE, 0 },
-		  
+
 	/* Padding at end of inode bitmap is not set. */
 	{ PR_5_INODE_BMAP_PADDING,
 	  N_("Padding at end of @i @B is not set. "),
 	  PROMPT_FIX, PR_PREEN_OK },
-		  
+
 	/* Padding at end of block bitmap is not set. */
 	{ PR_5_BLOCK_BMAP_PADDING,
 	  N_("Padding at end of @b @B is not set. "),
 	  PROMPT_FIX, PR_PREEN_OK },
-		
+
 	/* Block bitmap differences header */
 	{ PR_5_BLOCK_BITMAP_HEADER,
 	  N_("@b @B differences: "),
@@ -1401,13 +1476,13 @@
 	{ PR_5_BLOCK_UNUSED,
 	  " -%b",
 	  PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
-		  
+
 	/* Block used, but not marked used in bitmap */
 	{ PR_5_BLOCK_USED,
 	  " +%b",
 	  PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
 
-	/* Block bitmap differences end */	  
+	/* Block bitmap differences end */
 	{ PR_5_BLOCK_BITMAP_END,
 	  "\n",
 	  PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
@@ -1421,13 +1496,13 @@
 	{ PR_5_INODE_UNUSED,
 	  " -%i",
 	  PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
-		  
+
 	/* Inode used, but not marked used in bitmap */
 	{ PR_5_INODE_USED,
 	  " +%i",
 	  PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
 
-	/* Inode bitmap differences end */	  
+	/* Inode bitmap differences end */
 	{ PR_5_INODE_BITMAP_END,
 	  "\n",
 	  PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
@@ -1466,7 +1541,7 @@
 	/* Internal error: fudging end of bitmap */
 	{ PR_5_FUDGE_BITMAP_ERROR,
 	  N_("Internal error: fudging end of bitmap (%N)\n"),
-	  PROMPT_NONE, PR_FATAL },	  
+	  PROMPT_NONE, PR_FATAL },
 
 	/* Error copying in replacement inode bitmap */
 	{ PR_5_COPY_IBITMAP_ERROR,
@@ -1477,12 +1552,12 @@
 	{ PR_5_COPY_BBITMAP_ERROR,
 	  N_("Error copying in replacement @b @B: %m\n"),
 	  PROMPT_NONE, PR_FATAL },
-		  
+
 	/* Block range not used, but marked in bitmap */
 	{ PR_5_BLOCK_RANGE_UNUSED,
 	  " -(%b--%c)",
 	  PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
-		  
+
 	/* Block range used, but not marked used in bitmap */
 	{ PR_5_BLOCK_RANGE_USED,
 	  " +(%b--%c)",
@@ -1492,7 +1567,7 @@
 	{ PR_5_INODE_RANGE_UNUSED,
 	  " -(%i--%j)",
 	  PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
-		  
+
 	/* Inode range used, but not marked used in bitmap */
 	{ PR_5_INODE_RANGE_USED,
 	  " +(%i--%j)",
@@ -1503,6 +1578,16 @@
 	  N_("Recreate journal to make the filesystem ext3 again?\n"),
 	  PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
 
+	/* Group N block(s) in use but group is marked BLOCK_UNINIT */
+	{ PR_5_BLOCK_UNINIT,
+	  N_("@g %g @b(s) in use but @g is marked BLOCK_UNINIT\n"),
+	  PROMPT_FIX, PR_PREEN_OK },
+
+	/* Group N inode(s) in use but group is marked INODE_UNINIT */
+	{ PR_5_INODE_UNINIT,
+	  N_("@g %g @i(s) in use but @g is marked INODE_UNINIT\n"),
+	  PROMPT_FIX, PR_PREEN_OK },
+
 	{ 0 }
 };
 
@@ -1552,7 +1637,7 @@
 	struct latch_descr *ldesc;
 	struct problem_context pctx;
 	int answer = -1;
-	
+
 	ldesc = find_latch(mask);
 	if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
 		clear_problem_context(&pctx);
@@ -1592,7 +1677,7 @@
 	ctx->group = -1;
 }
 
-static void reconfigure_bool(e2fsck_t ctx, struct e2fsck_problem *ptr, 
+static void reconfigure_bool(e2fsck_t ctx, struct e2fsck_problem *ptr,
 			     const char *key, int mask, const char *name)
 {
 	int	bool;
@@ -1709,11 +1794,11 @@
 			answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
 		if (!answer && !(ptr->flags & PR_NO_OK))
 			ext2fs_unmark_valid(fs);
-	
+
 		if (print_answer)
 			printf("%s.\n", answer ?
 			       _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
-	
+
 	}
 
 	if ((ptr->prompt == PROMPT_ABORT) && answer)
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 91a6148..ab5c4df 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -16,7 +16,7 @@
 	ext2_ino_t ino, ino2, dir;
 	struct ext2_inode *inode;
 	struct ext2_dir_entry *dirent;
-	blk_t	blk, blk2;
+	blk64_t	blk, blk2;
 	e2_blkcnt_t	blkcount;
 	int		group;
 	__u64	num;
@@ -82,12 +82,12 @@
 /* Adding UUID to filesystem */
 #define PR_0_ADD_UUID		0x000009
 
-/* Relocate hint */	
+/* Relocate hint */
 #define PR_0_RELOCATE_HINT	0x00000A
 
 /* Miscellaneous superblock corruption */
 #define PR_0_MISC_CORRUPT_SUPER	0x00000B
-	
+
 /* Error determing physical device size of filesystem */
 #define PR_0_GETSIZE_ERROR	0x00000C
 
@@ -135,13 +135,13 @@
 
 /* Clearing orphan inode */
 #define PR_0_ORPHAN_CLEAR_INODE			0x000020
-	
+
 /* Illegal block found in orphaned inode */
 #define PR_0_ORPHAN_ILLEGAL_BLOCK_NUM		0x000021
 
 /* Already cleared block found in orphaned inode */
 #define PR_0_ORPHAN_ALREADY_CLEARED_BLOCK	0x000022
-	
+
 /* Illegal orphan inode in superblock */
 #define PR_0_ORPHAN_ILLEGAL_HEAD_INODE		0x000023
 
@@ -196,6 +196,21 @@
 /* Superblock hint for external journal incorrect */
 #define PR_0_DIRHASH_HINT			0x000034
 
+/* Group descriptor N checksum is invalid */
+#define PR_0_GDT_CSUM				0x000035
+
+/* Group descriptor N marked uninitialized without feature set. */
+#define PR_0_GDT_UNINIT				0x000036
+
+/* Block bitmap is not initialised and Inode bitmap is */
+#define PR_0_BB_UNINIT_IB_INIT			0x000037
+
+/* Group descriptor N has invalid unused inodes count. */
+#define PR_0_GDT_ITABLE_UNUSED			0x000038
+
+/* Last group block bitmap is uninitialized. */
+#define PR_0_BB_UNINIT_LAST			0x000039
+
 /*
  * Pass 1 errors
  */
@@ -253,7 +268,7 @@
 
 /* Too many bad blocks in inode */
 #define	PR_1_TOO_MANY_BAD_BLOCKS 	0x010011
-	
+
 /* Illegal block number in bad block inode */
 #define PR_1_BB_ILLEGAL_BLOCK_NUM 	0x010012
 
@@ -262,16 +277,16 @@
 
 /* Duplicate or bad blocks in use! */
 #define PR_1_DUP_BLOCKS_PREENSTOP	0x010014
-	
-/* Bad block used as bad block indirect block */	  
+
+/* Bad block used as bad block indirect block */
 #define PR_1_BBINODE_BAD_METABLOCK	0x010015
 
 /* Inconsistency can't be fixed prompt */
 #define PR_1_BBINODE_BAD_METABLOCK_PROMPT 0x010016
-	
+
 /* Bad primary block */
 #define PR_1_BAD_PRIMARY_BLOCK		0x010017
-		  
+
 /* Bad primary block prompt */
 #define PR_1_BAD_PRIMARY_BLOCK_PROMPT	0x010018
 
@@ -287,24 +302,24 @@
 /* Bad block group descriptors in group */
 #define PR_1_BAD_GROUP_DESCRIPTORS	0x01001C
 
-/* Block claimed for no reason */	  
+/* Block claimed for no reason */
 #define PR_1_PROGERR_CLAIMED_BLOCK	0x01001D
 
 /* Error allocating blocks for relocating metadata */
 #define PR_1_RELOC_BLOCK_ALLOCATE	0x01001E
-		
+
 /* Error allocating block buffer during relocation process */
 #define PR_1_RELOC_MEMORY_ALLOCATE	0x01001F
-		
-/* Relocating metadata group information from X to Y */	
+
+/* Relocating metadata group information from X to Y */
 #define PR_1_RELOC_FROM_TO		0x010020
-		
+
 /* Relocating metatdata group information to X */
 #define PR_1_RELOC_TO			0x010021
-		
+
 /* Block read error during relocation process */
 #define PR_1_RELOC_READ_ERR		0x010022
-		
+
 /* Block write error during relocation process */
 #define PR_1_RELOC_WRITE_ERR		0x010023
 
@@ -316,7 +331,7 @@
 
 /* Error allocating icount structure */
 #define PR_1_ALLOCATE_ICOUNT		0x010026
-	
+
 /* Error allocating dbcount */
 #define PR_1_ALLOCATE_DBCOUNT		0x010027
 
@@ -326,10 +341,10 @@
 /* Error while iterating over blocks */
 #define PR_1_BLOCK_ITERATE		0x010029
 
-/* Error while storing inode count information */	  
+/* Error while storing inode count information */
 #define PR_1_ICOUNT_STORE		0x01002A
 
-/* Error while storing directory block information */	  
+/* Error while storing directory block information */
 #define PR_1_ADD_DBLOCK			0x01002B
 
 /* Error while reading inode (for clearing) */
@@ -367,7 +382,7 @@
 
 /* Error allocating refcount structure */
 #define PR_1_ALLOCATE_REFCOUNT		0x010038
-	
+
 /* Error reading Extended Attribute block */
 #define PR_1_READ_EA_BLOCK		0x010039
 
@@ -380,7 +395,7 @@
 /* Extended attribute reference count incorrect */
 #define PR_1_EXTATTR_REFCOUNT		0x01003C
 
-/* Error writing Extended Attribute block while fixing refcount */ 
+/* Error writing Extended Attribute block while fixing refcount */
 #define PR_1_EXTATTR_WRITE		0x01003D
 
 /* Multiple EA blocks not supported */
@@ -413,19 +428,19 @@
 /* INDEX_FL flag set on a non-HTREE filesystem */
 #define PR_1_HTREE_SET			0x010047
 
-/* INDEX_FL flag set on a non-directory */	
+/* INDEX_FL flag set on a non-directory */
 #define PR_1_HTREE_NODIR		0x010048
 
-/* Invalid root node in HTREE directory */	
+/* Invalid root node in HTREE directory */
 #define PR_1_HTREE_BADROOT		0x010049
 
-/* Unsupported hash version in HTREE directory */	
+/* Unsupported hash version in HTREE directory */
 #define PR_1_HTREE_HASHV		0x01004A
 
-/* Incompatible flag in HTREE root node */	
+/* Incompatible flag in HTREE root node */
 #define PR_1_HTREE_INCOMPAT		0x01004B
 
-/* HTREE too deep */	
+/* HTREE too deep */
 #define PR_1_HTREE_DEPTH		0x01004C
 
 /* Bad block has indirect block that conflicts with filesystem block */
@@ -434,7 +449,7 @@
 /* Resize inode failed */
 #define PR_1_RESIZE_INODE_CREATE	0x01004E
 
-/* inode->i_size is too long */	
+/* inode->i_size is too long */
 #define PR_1_EXTRA_ISIZE		0x01004F
 
 /* attribute name is too long */
@@ -455,6 +470,30 @@
 /* inode appears to be a directory */
 #define PR_1_TREAT_AS_DIRECTORY		0x010055
 
+/* Error while reading extent tree */
+#define PR_1_READ_EXTENT		0x010056
+
+/* Error deleting a bogus extent */
+#define PR_1_EXTENT_DELETE_FAIL		0x010057
+
+/* Bad starting block in extent */
+#define PR_1_EXTENT_BAD_START_BLK	0x010058
+
+/* Extent ends beyond filesystem */
+#define PR_1_EXTENT_ENDS_BEYOND		0x010059
+
+/* EXTENTS_FL flag set on a non-extents capable filesystem */
+#define PR_1_EXTENTS_SET		0x01005A
+
+/* inode has extents, superblock missing INCOMPAT_EXTENTS feature */
+#define PR_1_EXTENT_FEATURE		0x01005B
+
+/* inode missing EXTENTS_FL, but is an extent inode */
+#define PR_1_UNSET_EXTENT_FL		0x01005C
+
+/* Fast symlink has EXTENTS_FL set */
+#define PR_1_FAST_SYMLINK_EXTENT_FL	0x01005D
+
 /*
  * Pass 1b errors
  */
@@ -470,7 +509,7 @@
 
 /* Duplicate/bad block(s) end */
 #define PR_1B_DUP_BLOCK_END	0x011003
-	
+
 /* Error while scanning inodes */
 #define PR_1B_ISCAN_ERROR	0x011004
 
@@ -494,13 +533,13 @@
 /* File has duplicate blocks */
 #define PR_1D_DUP_FILE		0x013001
 
-/* List of files sharing duplicate blocks */	
+/* List of files sharing duplicate blocks */
 #define PR_1D_DUP_FILE_LIST	0x013002
 
-/* File sharing blocks with filesystem metadata  */	
+/* File sharing blocks with filesystem metadata  */
 #define PR_1D_SHARE_METADATA	0x013003
 
-/* Report of how many duplicate/bad inodes */	
+/* Report of how many duplicate/bad inodes */
 #define PR_1D_NUM_DUP_INODES	0x013004
 
 /* Duplicated blocks already reassigned or cloned. */
@@ -514,7 +553,7 @@
 
 /* Couldn't clone file (error) */
 #define PR_1D_CLONE_ERROR	0x013008
-		
+
 /*
  * Pass 2 errors
  */
@@ -546,10 +585,10 @@
 /* Directory entry has illegal characters in its name */
 #define PR_2_BAD_NAME		0x020008
 
-/* Missing '.' in directory inode */	  
+/* Missing '.' in directory inode */
 #define PR_2_MISSING_DOT	0x020009
 
-/* Missing '..' in directory inode */	  
+/* Missing '..' in directory inode */
 #define PR_2_MISSING_DOT_DOT	0x02000A
 
 /* First entry in directory inode doesn't contain '.' */
@@ -572,16 +611,16 @@
 
 /* i_fsize should be zero */
 #define PR_2_FSIZE_ZERO		0x020011
-		  
+
 /* inode has bad mode */
 #define PR_2_BAD_MODE		0x020012
 
 /* directory corrupted */
 #define PR_2_DIR_CORRUPTED	0x020013
-		  
+
 /* filename too long */
 #define PR_2_FILENAME_LONG	0x020014
-		  
+
 /* Directory inode has a missing block (hole) */
 #define PR_2_DIRECTORY_HOLE	0x020015
 
@@ -602,7 +641,7 @@
 
 /* Duplicate '..' entry */
 #define PR_2_DUP_DOT_DOT	0x02001B
-	
+
 /* Internal error: couldn't find dir_info */
 #define PR_2_NO_DIRINFO		0x02001C
 
@@ -711,6 +750,12 @@
 /* Unexpected HTREE block */
 #define PR_2_UNEXPECTED_HTREE_BLOCK	0x020045
 
+/* Inode found in group where _INODE_UNINIT is set */
+#define PR_2_INOREF_BG_INO_UNINIT	0x020046
+
+/* Inode found in group unused inodes area */
+#define PR_2_INOREF_IN_UNUSED		0x020047
+
 /*
  * Pass 3 errors
  */
@@ -751,9 +796,9 @@
 /* Error in ext2fs_new_inode while creating /lost+found */
 #define PR_3_ERR_LPF_NEW_INODE		0x03000B
 
-/* Error in ext2fs_new_dir_block while creating /lost+found */	  
+/* Error in ext2fs_new_dir_block while creating /lost+found */
 #define PR_3_ERR_LPF_NEW_DIR_BLOCK	0x03000C
-		  
+
 /* Error while writing directory block for /lost+found */
 #define PR_3_ERR_LPF_WRITE_BLOCK	0x03000D
 
@@ -763,12 +808,12 @@
 /* Couldn't fix parent directory -- error */
 #define PR_3_FIX_PARENT_ERR		0x03000F
 
-/* Couldn't fix parent directory -- couldn't find it */	  
+/* Couldn't fix parent directory -- couldn't find it */
 #define PR_3_FIX_PARENT_NOFIND		0x030010
-	
+
 /* Error allocating inode bitmap */
 #define PR_3_ALLOCATE_IBITMAP_ERROR	0x030011
-		  
+
 /* Error creating root directory */
 #define PR_3_CREATE_ROOT_ERROR		0x030012
 
@@ -797,15 +842,15 @@
 #define PR_3A_OPTIMIZE_ITER		0x031001
 
 /* Error rehash directory */
-#define PR_3A_OPTIMIZE_DIR_ERR		0x031002		
+#define PR_3A_OPTIMIZE_DIR_ERR		0x031002
 
 /* Rehashing dir header */
 #define PR_3A_OPTIMIZE_DIR_HEADER		0x031003
 
 /* Rehashing directory %d */
 #define PR_3A_OPTIMIZE_DIR		0x031004
-		  
-/* Rehashing dir end */	  
+
+/* Rehashing dir end */
 #define PR_3A_OPTIMIZE_DIR_END		0x031005
 
 /*
@@ -833,7 +878,7 @@
 
 /* Pass 5: Checking group summary information */
 #define PR_5_PASS_HEADER		0x050000
-	
+
 /* Padding at end of inode bitmap is not set. */
 #define PR_5_INODE_BMAP_PADDING		0x050001
 
@@ -845,11 +890,11 @@
 
 /* Block not used, but marked in bitmap */
 #define PR_5_BLOCK_UNUSED		0x050004
-	  
+
 /* Block used, but not marked used in bitmap */
 #define PR_5_BLOCK_USED			0x050005
 
-/* Block bitmap differences end */	  
+/* Block bitmap differences end */
 #define PR_5_BLOCK_BITMAP_END		0x050006
 
 /* Inode bitmap differences header */
@@ -857,11 +902,11 @@
 
 /* Inode not used, but marked in bitmap */
 #define PR_5_INODE_UNUSED		0x050008
-	  
+
 /* Inode used, but not marked used in bitmap */
 #define PR_5_INODE_USED			0x050009
 
-/* Inode bitmap differences end */	  
+/* Inode bitmap differences end */
 #define PR_5_INODE_BITMAP_END		0x05000A
 
 /* Free inodes count for group wrong */
@@ -893,16 +938,22 @@
 
 /* Block range not used, but marked in bitmap */
 #define PR_5_BLOCK_RANGE_UNUSED		0x050014
-	  
+
 /* Block range used, but not marked used in bitmap */
 #define PR_5_BLOCK_RANGE_USED		0x050015
 
 /* Inode range not used, but marked in bitmap */
 #define PR_5_INODE_RANGE_UNUSED		0x050016
-	  
+
 /* Inode rangeused, but not marked used in bitmap */
 #define PR_5_INODE_RANGE_USED		0x050017
 
+/* Block in use but group is marked BLOCK_UNINIT */
+#define PR_5_BLOCK_UNINIT		0x050018
+
+/* Inode in use but group is marked INODE_UNINIT */
+#define PR_5_INODE_UNINIT		0x050019
+
 /*
  * Post-Pass 5 errors
  */
@@ -921,6 +972,6 @@
 
 /* message.c */
 void print_e2fsck_message(e2fsck_t ctx, const char *msg,
-			  struct problem_context *pctx, int first, 
+			  struct problem_context *pctx, int first,
 			  int recurse);
 
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 8e25f52..a1f75ef 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -789,7 +789,7 @@
 	int			cur, max, all_dirs, dir_index, first = 1;
 
 #ifdef RESOURCE_TRACK
-	init_resource_track(&rtrack);
+	init_resource_track(&rtrack, ctx->fs->io);
 #endif
 
 	all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
@@ -858,7 +858,7 @@
 #ifdef RESOURCE_TRACK
 	if (ctx->options & E2F_OPT_TIME2) {
 		e2fsck_clear_progbar(ctx);
-		print_resource_track("Pass 3A", &rtrack);
+		print_resource_track("Pass 3A", &rtrack, ctx->fs->io);
 	}
 #endif
 }
diff --git a/e2fsck/super.c b/e2fsck/super.c
index 954783e..87a0d78 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -467,7 +467,9 @@
 	dgrp_t	i;
 	blk_t	should_be;
 	struct problem_context	pctx;
-	__u32	free_blocks = 0, free_inodes = 0;
+	blk_t	free_blocks = 0;
+	ino_t	free_inodes = 0;
+	int     lazy_flag, csum_flag;
 
 	inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
 	ipg_max = inodes_per_block * (blocks_per_group - 4);
@@ -574,13 +576,21 @@
 	/*
 	 * Verify the group descriptors....
 	 */
-	first_block =  sb->s_first_data_block;
+	first_block = sb->s_first_data_block;
+	last_block = sb->s_blocks_count-1;
 
+	lazy_flag = EXT2_HAS_COMPAT_FEATURE(fs->super,
+					    EXT2_FEATURE_COMPAT_LAZY_BG);
+	csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					       EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
 	for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
 		pctx.group = i;
 
-		first_block = ext2fs_group_first_block(fs, i);
-		last_block = ext2fs_group_last_block(fs, i);
+		if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+					       EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+			first_block = ext2fs_group_first_block(fs, i);
+			last_block = ext2fs_group_last_block(fs, i);
+		}
 
 		if ((gd->bg_block_bitmap < first_block) ||
 		    (gd->bg_block_bitmap > last_block)) {
@@ -621,6 +631,60 @@
 		    (gd->bg_used_dirs_count > sb->s_inodes_per_group))
 			ext2fs_unmark_valid(fs);
 
+		should_be = 0;
+		if (!ext2fs_group_desc_csum_verify(fs, i)) {
+			if (fix_problem(ctx, PR_0_GDT_CSUM, &pctx)) {
+				gd->bg_flags &=	~(EXT2_BG_BLOCK_UNINIT |
+				                  EXT2_BG_INODE_UNINIT);
+				gd->bg_itable_unused = 0;
+				should_be = 1;
+			}
+			ext2fs_unmark_valid(fs);
+		}
+
+		if (!lazy_flag && !csum_flag &&
+		    (gd->bg_flags &(EXT2_BG_BLOCK_UNINIT|EXT2_BG_INODE_UNINIT)||
+		     gd->bg_itable_unused != 0)){
+			if (fix_problem(ctx, PR_0_GDT_UNINIT, &pctx)) {
+				gd->bg_flags &= ~(EXT2_BG_BLOCK_UNINIT |
+						  EXT2_BG_INODE_UNINIT);
+				gd->bg_itable_unused = 0;
+				should_be = 1;
+			}
+			ext2fs_unmark_valid(fs);
+		}
+
+		if (i == fs->group_desc_count - 1 &&
+		    gd->bg_flags & EXT2_BG_BLOCK_UNINIT) {
+			if (fix_problem(ctx, PR_0_BB_UNINIT_LAST, &pctx)) {
+				gd->bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
+				should_be = 1;
+			}
+			ext2fs_unmark_valid(fs);
+		}
+
+		if (gd->bg_flags & EXT2_BG_BLOCK_UNINIT &&
+		    !(gd->bg_flags & EXT2_BG_INODE_UNINIT)) {
+			if (fix_problem(ctx, PR_0_BB_UNINIT_IB_INIT, &pctx)) {
+				gd->bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
+				should_be = 1;
+			}
+			ext2fs_unmark_valid(fs);
+		}
+
+		if (csum_flag &&
+		    (gd->bg_itable_unused > gd->bg_free_inodes_count ||
+		     gd->bg_itable_unused > sb->s_inodes_per_group)) {
+			pctx.blk = gd->bg_itable_unused;
+			if (fix_problem(ctx, PR_0_GDT_ITABLE_UNUSED, &pctx)) {
+				gd->bg_itable_unused = 0;
+				should_be = 1;
+			}
+			ext2fs_unmark_valid(fs);
+		}
+
+		if (should_be)
+			ext2fs_group_desc_csum_set(fs, i);
 	}
 
 	/*
@@ -797,7 +861,6 @@
 {
 	ext2_filsys	fs = ctx->fs;
 	ext2_filsys	tfs = 0;
-	io_manager	io_ptr;
 	errcode_t	retval;
 	dgrp_t		g;
 	blk_t		sb;
diff --git a/e2fsck/swapfs.c b/e2fsck/swapfs.c
deleted file mode 100644
index 9df1d11..0000000
--- a/e2fsck/swapfs.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * swapfs.c --- byte-swap an ext2 filesystem
- *
- * Copyright 1996, 1997 by Theodore Ts'o
- * 
- * %Begin-Header%
- * This file may be redistributed under the terms of the GNU Public
- * License.
- * %End-Header%
- * 
- */
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <et/com_err.h>
-#include "e2fsck.h"
-
-#ifdef ENABLE_SWAPFS
-
-struct swap_block_struct {
-	ext2_ino_t	ino;
-	int		isdir;
-	errcode_t	errcode;
-	char		*dir_buf;
-	struct ext2_inode *inode;
-};
-
-/*
- * This is a helper function for block_iterate.  We mark all of the
- * indirect and direct blocks as changed, so that block_iterate will
- * write them out.
- */
-static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
-		      void *priv_data)
-{
-	errcode_t	retval;
-	
-	struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
-
-	if (sb->isdir && (blockcnt >= 0) && *block_nr) {
-		retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
-		if (retval) {
-			sb->errcode = retval;
-			return BLOCK_ABORT;
-		}
-		retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
-		if (retval) {
-			sb->errcode = retval;
-			return BLOCK_ABORT;
-		}
-	}
-	if (blockcnt >= 0) {
-		if (blockcnt < EXT2_NDIR_BLOCKS)
-			return 0;
-		return BLOCK_CHANGED;
-	}
-	if (blockcnt == BLOCK_COUNT_IND) {
-		if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
-			return 0;
-		return BLOCK_CHANGED;
-	}
-	if (blockcnt == BLOCK_COUNT_DIND) {
-		if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
-			return 0;
-		return BLOCK_CHANGED;
-	}
-	if (blockcnt == BLOCK_COUNT_TIND) {
-		if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
-			return 0;
-		return BLOCK_CHANGED;
-	}
-	return BLOCK_CHANGED;
-}
-
-/*
- * This function is responsible for byte-swapping all of the indirect,
- * block pointers.  It is also responsible for byte-swapping directories.
- */
-static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
-			      struct ext2_inode *inode)
-{
-	errcode_t			retval;
-	struct swap_block_struct	sb;
-
-	sb.ino = ino;
-	sb.inode = inode;
-	sb.dir_buf = block_buf + ctx->fs->blocksize*3;
-	sb.errcode = 0;
-	sb.isdir = 0;
-	if (LINUX_S_ISDIR(inode->i_mode))
-		sb.isdir = 1;
-
-	retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
-				      swap_block, &sb);
-	if (retval) {
-		com_err("swap_inode_blocks", retval,
-			_("while calling ext2fs_block_iterate"));
-		ctx->flags |= E2F_FLAG_ABORT;
-		return;
-	}
-	if (sb.errcode) {
-		com_err("swap_inode_blocks", sb.errcode,
-			_("while calling iterator function"));
-		ctx->flags |= E2F_FLAG_ABORT;
-		return;
-	}
-}
-
-static void swap_inodes(e2fsck_t ctx)
-{
-	ext2_filsys fs = ctx->fs;
-	dgrp_t			group;
-	unsigned int		i;
-	ext2_ino_t		ino = 1;
-	char 			*buf = NULL, *block_buf = NULL;
-	errcode_t		retval;
-	struct ext2_inode *	inode;
-
-	e2fsck_use_inode_shortcuts(ctx, 1);
-	
-	retval = ext2fs_get_array(fs->blocksize, fs->inode_blocks_per_group,
-				&buf);
-	if (retval) {
-		com_err("swap_inodes", retval,
-			_("while allocating inode buffer"));
-		ctx->flags |= E2F_FLAG_ABORT;
-		goto errout;
-	}
-	block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
-						    "block interate buffer");
-	for (group = 0; group < fs->group_desc_count; group++) {
-		retval = io_channel_read_blk(fs->io,
-		      fs->group_desc[group].bg_inode_table,
-		      fs->inode_blocks_per_group, buf);
-		if (retval) {
-			com_err("swap_inodes", retval,
-				_("while reading inode table (group %d)"),
-				group);
-			ctx->flags |= E2F_FLAG_ABORT;
-			goto errout;
-		}
-		inode = (struct ext2_inode *) buf;
-		for (i=0; i < fs->super->s_inodes_per_group;
-		     i++, ino++, inode++) {
-			ctx->stashed_ino = ino;
-			ctx->stashed_inode = inode;
-			
-			if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
-				ext2fs_swap_inode(fs, inode, inode, 0);
-			
-			/*
-			 * Skip deleted files.
-			 */
-			if (inode->i_links_count == 0)
-				continue;
-			
-			if (LINUX_S_ISDIR(inode->i_mode) ||
-			    ((inode->i_block[EXT2_IND_BLOCK] ||
-			      inode->i_block[EXT2_DIND_BLOCK] ||
-			      inode->i_block[EXT2_TIND_BLOCK]) &&
-			     ext2fs_inode_has_valid_blocks(inode)))
-				swap_inode_blocks(ctx, ino, block_buf, inode);
-
-			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
-				goto errout;
-			
-			if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
-				ext2fs_swap_inode(fs, inode, inode, 1);
-		}
-		retval = io_channel_write_blk(fs->io,
-		      fs->group_desc[group].bg_inode_table,
-		      fs->inode_blocks_per_group, buf);
-		if (retval) {
-			com_err("swap_inodes", retval,
-				_("while writing inode table (group %d)"),
-				group);
-			ctx->flags |= E2F_FLAG_ABORT;
-			goto errout;
-		}
-	}
-errout:
-	if (buf)
-		ext2fs_free_mem(&buf);
-	if (block_buf)
-		ext2fs_free_mem(&block_buf);
-	e2fsck_use_inode_shortcuts(ctx, 0);
-	ext2fs_flush_icache(fs);
-}
-
-#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
-/*
- * On the PowerPC, the big-endian variant of the ext2 filesystem
- * has its bitmaps stored as 32-bit words with bit 0 as the LSB
- * of each word.  Thus a bitmap with only bit 0 set would be, as
- * a string of bytes, 00 00 00 01 00 ...
- * To cope with this, we byte-reverse each word of a bitmap if
- * we have a big-endian filesystem, that is, if we are *not*
- * byte-swapping other word-sized numbers.
- */
-#define EXT2_BIG_ENDIAN_BITMAPS
-#endif
-
-#ifdef EXT2_BIG_ENDIAN_BITMAPS
-static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
-{
-	__u32 *p = (__u32 *) bmap->bitmap;
-	int n, nbytes = (bmap->end - bmap->start + 7) / 8;
-		
-	for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
-		*p = ext2fs_swab32(*p);
-}
-#endif
-
-
-void swap_filesys(e2fsck_t ctx)
-{
-	ext2_filsys fs = ctx->fs;
-#ifdef RESOURCE_TRACK
-	struct resource_track	rtrack;
-
-	init_resource_track(&rtrack);
-#endif
-
-	if (!(ctx->options & E2F_OPT_PREEN))
-		printf(_("Pass 0: Doing byte-swap of filesystem\n"));
-	
-#ifdef MTRACE
-	mtrace_print("Byte swap");
-#endif
-
-	if (fs->super->s_mnt_count) {
-		fprintf(stderr, _("%s: the filesystem must be freshly "
-			"checked using fsck\n"
-			"and not mounted before trying to "
-			"byte-swap it.\n"), ctx->device_name);
-		ctx->flags |= E2F_FLAG_ABORT;
-		return;
-	}
-	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
-		fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
-			       EXT2_FLAG_SWAP_BYTES_WRITE);
-		fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
-	} else {
-		fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
-		fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
-	}
-	swap_inodes(ctx);
-	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
-		return;
-	if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
-		fs->flags |= EXT2_FLAG_SWAP_BYTES;
-	fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
-		       EXT2_FLAG_SWAP_BYTES_WRITE);
-
-#ifdef EXT2_BIG_ENDIAN_BITMAPS
-	e2fsck_read_bitmaps(ctx);
-	ext2fs_swap_bitmap(fs->inode_map);
-	ext2fs_swap_bitmap(fs->block_map);
-	fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
-#endif
-	fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
-	ext2fs_flush(fs);
-	fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
-	
-#ifdef RESOURCE_TRACK
-	if (ctx->options & E2F_OPT_TIME2)
-		print_resource_track(_("Byte swap"), &rtrack);
-#endif
-}
-
-#endif
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index d3a8a2b..93af87b 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -52,8 +52,6 @@
 #include "../version.h"
 
 /* Command line options */
-static int swapfs;
-static int normalize_swapfs;
 static int cflag;		/* check disk */
 static int show_version_only;
 static int verbose;
@@ -71,7 +69,7 @@
 static void usage(e2fsck_t ctx)
 {
 	fprintf(stderr,
-		_("Usage: %s [-panyrcdfvstDFSV] [-b superblock] [-B blocksize]\n"
+		_("Usage: %s [-panyrcdfvtDFV] [-b superblock] [-B blocksize]\n"
 		"\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
 		"\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n"
 		"\t\t[-E extended-options] device\n"),
@@ -268,8 +266,7 @@
 	if (!defer_check_on_battery)
 		batt = 0;
 
-	if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file ||
-	    cflag || swapfs)
+	if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file || cflag)
 		return;
 	
 	lastcheck = fs->super->s_lastcheck;
@@ -561,7 +558,9 @@
 		       "and may take an argument which\n"
 		       "is set off by an equals ('=') sign.  "
 			"Valid extended options are:\n"
-		       "\tea_ver=<ea_version (1 or 2)>\n\n"), stderr);
+			"\tea_ver=<ea_version (1 or 2)>\n"
+			"\tuninit_groups\n"
+			"\tinit_groups\n\n"), stderr);
 		exit(1);
 	}
 }
@@ -739,20 +738,6 @@
 		case 'N':
 			ctx->device_name = string_copy(ctx, optarg, 0);
 			break;
-#ifdef ENABLE_SWAPFS
-		case 's':
-			normalize_swapfs = 1;
-		case 'S':
-			swapfs = 1;
-			break;
-#else
-		case 's':
-		case 'S':
-			fprintf(stderr, _("Byte-swapping filesystems "
-					  "not compiled in this version "
-					  "of e2fsck\n"));
-			exit(1);
-#endif
 		case 'k':
 			keep_bad_blocks++;
 			break;
@@ -764,8 +749,9 @@
 	if (optind != argc - 1)
 		usage(ctx);
 	if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
-	    !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
+	    !cflag && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
 		ctx->options |= E2F_OPT_READONLY;
+
 	ctx->io_options = strchr(argv[optind], '?');
 	if (ctx->io_options) 
 		*ctx->io_options++ = 0;
@@ -800,15 +786,6 @@
 		}
 		close(fd);
 	}
-#ifdef ENABLE_SWAPFS
-	if (swapfs) {
-		if (cflag || bad_blocks_file) {
-			fprintf(stderr, _("Incompatible options not "
-					  "allowed when byte-swapping.\n"));
-			exit(FSCK_USAGE);
-		}
-	}
-#endif
 	if (cflag && bad_blocks_file) {
 		fprintf(stderr, _("The -c and the -l/-L options may "
 				  "not be both used at the same time.\n"));
@@ -874,7 +851,7 @@
 
 static const char *my_ver_string = E2FSPROGS_VERSION;
 static const char *my_ver_date = E2FSPROGS_DATE;
-					
+
 int main (int argc, char *argv[])
 {
 	errcode_t	retval = 0, orig_retval = 0;
@@ -922,7 +899,7 @@
 	reserve_stdio_fds();
 	
 #ifdef RESOURCE_TRACK
-	init_resource_track(&ctx->global_rtrack);
+	init_resource_track(&ctx->global_rtrack, NULL);
 #endif
 
 	if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
@@ -1243,21 +1220,6 @@
 		read_bad_blocks_file(ctx, 0, !keep_bad_blocks); /* Test disk */
 	if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
 		fatal_error(ctx, 0);
-#ifdef ENABLE_SWAPFS
-	if (normalize_swapfs) {
-		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ==
-		    ext2fs_native_flag()) {
-			fprintf(stderr, _("%s: Filesystem byte order "
-				"already normalized.\n"), ctx->device_name);
-			fatal_error(ctx, 0);
-		}
-	}
-	if (swapfs) {
-		swap_filesys(ctx);
-		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
-			fatal_error(ctx, 0);
-	}
-#endif
 
 	/*
 	 * Mark the system as valid, 'til proven otherwise
@@ -1386,17 +1348,27 @@
 		}
 	}
 
+	if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM &&
+	    !(ctx->options & E2F_OPT_READONLY)) {
+		retval = ext2fs_set_gdt_csum(ctx->fs);
+		if (retval) {
+			com_err(ctx->program_name, retval,
+				_("while setting block group checksum info"));
+			fatal_error(ctx, 0);
+		}
+	}
+
 	e2fsck_write_bitmaps(ctx);
-	
+#ifdef RESOURCE_TRACK
+	io_channel_flush(ctx->fs->io);
+	if (ctx->options & E2F_OPT_TIME)
+		print_resource_track(NULL, &ctx->global_rtrack, ctx->fs->io);
+#endif
 	ext2fs_close(fs);
 	ctx->fs = NULL;
 	free(ctx->filesystem_name);
 	free(ctx->journal_name);
 
-#ifdef RESOURCE_TRACK
-	if (ctx->options & E2F_OPT_TIME)
-		print_resource_track(NULL, &ctx->global_rtrack);
-#endif
 	e2fsck_free_context(ctx);
 	remove_error_table(&et_ext2_error_table);
 	remove_error_table(&et_prof_error_table);
diff --git a/e2fsck/util.c b/e2fsck/util.c
index f761ebb..315a575 100644
--- a/e2fsck/util.c
+++ b/e2fsck/util.c
@@ -29,6 +29,10 @@
 #include <malloc.h>
 #endif
 
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
 #include "e2fsck.h"
 
 extern e2fsck_t e2fsck_global_ctx;   /* Try your very best not to use this! */
@@ -276,11 +280,12 @@
 }
 
 #ifdef RESOURCE_TRACK
-void init_resource_track(struct resource_track *track)
+void init_resource_track(struct resource_track *track, io_channel channel)
 {
 #ifdef HAVE_GETRUSAGE
 	struct rusage r;
 #endif
+	io_stats io_start = 0;
 	
 	track->brk_start = sbrk(0);
 	gettimeofday(&track->time_start, 0);
@@ -295,6 +300,14 @@
 	track->user_start.tv_sec = track->user_start.tv_usec = 0;
 	track->system_start.tv_sec = track->system_start.tv_usec = 0;
 #endif
+	track->bytes_read = 0;
+	track->bytes_written = 0;
+	if (channel && channel->manager && channel->manager->get_stats)
+		channel->manager->get_stats(channel, &io_start);
+	if (io_start) {
+		track->bytes_read = io_start->bytes_read;
+		track->bytes_written = io_start->bytes_written;
+	}
 }
 
 #ifdef __GNUC__
@@ -310,7 +323,8 @@
 		((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
 }
 
-void print_resource_track(const char *desc, struct resource_track *track)
+void print_resource_track(const char *desc, struct resource_track *track,
+			  io_channel channel)
 {
 #ifdef HAVE_GETRUSAGE
 	struct rusage r;
@@ -347,6 +361,26 @@
 	printf(_("elapsed time: %6.3f\n"),
 	       timeval_subtract(&time_end, &track->time_start));
 #endif
+#define mbytes(x)	(((x) + 1048575) / 1048576)
+	if (channel && channel->manager && channel->manager->get_stats) {
+		io_stats delta = 0;
+		unsigned long long bytes_read = 0;
+		unsigned long long bytes_written = 0;
+
+		if (desc)
+			printf("%s: ", desc);
+
+		channel->manager->get_stats(channel, &delta);
+		if (delta) {
+			bytes_read = delta->bytes_read - track->bytes_read;
+			bytes_written = delta->bytes_written - 
+				track->bytes_written;
+		}
+		printf("I/O read: %lluMB, write: %lluMB, rate: %.2fMB/s\n",
+		       mbytes(bytes_read), mbytes(bytes_written),
+		       (double)mbytes(bytes_read + bytes_written) /
+		       timeval_subtract(&time_end, &track->time_start));
+	}
 }
 #endif /* RESOURCE_TRACK */
 
@@ -363,6 +397,20 @@
 	}
 }
 
+void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
+			    struct ext2_inode *inode, int bufsize,
+			    const char *proc)
+{
+	int retval;
+
+	retval = ext2fs_read_inode_full(ctx->fs, ino, inode, bufsize);
+	if (retval) {
+		com_err("ext2fs_read_inode_full", retval,
+			_("while reading inode %ld in %s"), ino, proc);
+		fatal_error(ctx, 0);
+	}
+}
+
 extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
 			       struct ext2_inode * inode, int bufsize,
 			       const char *proc)
@@ -451,7 +499,7 @@
 		if (io_channel_read_blk(io, superblock,
 					-SUPERBLOCK_SIZE, buf))
 			continue;
-#ifdef EXT2FS_ENABLE_SWAPFS
+#ifdef WORDS_BIGENDIAN
 		if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
 			ext2fs_swap_super(sb);
 #endif
@@ -502,3 +550,60 @@
 	
 	return 0;
 }
+
+#define STRIDE_LENGTH 8
+/*
+ * Helper function which zeros out _num_ blocks starting at _blk_.  In
+ * case of an error, the details of the error is returned via _ret_blk_
+ * and _ret_count_ if they are non-NULL pointers.  Returns 0 on
+ * success, and an error code on an error.
+ *
+ * As a special case, if the first argument is NULL, then it will
+ * attempt to free the static zeroizing buffer.  (This is to keep
+ * programs that check for memory leaks happy.)
+ */
+errcode_t e2fsck_zero_blocks(ext2_filsys fs, blk_t blk, int num,
+			     blk_t *ret_blk, int *ret_count)
+{
+	int		j, count, next_update, next_update_incr;
+	static char	*buf;
+	errcode_t	retval;
+
+	/* If fs is null, clean up the static buffer and return */
+	if (!fs) {
+		if (buf) {
+			free(buf);
+			buf = 0;
+		}
+		return 0;
+	}
+	/* Allocate the zeroizing buffer if necessary */
+	if (!buf) {
+		buf = malloc(fs->blocksize * STRIDE_LENGTH);
+		if (!buf) {
+			com_err("malloc", ENOMEM,
+				_("while allocating zeroizing buffer"));
+			exit(1);
+		}
+		memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
+	}
+	/* OK, do the write loop */
+	next_update = 0;
+	next_update_incr = num / 100;
+	if (next_update_incr < 1)
+		next_update_incr = 1;
+	for (j = 0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
+		count = num - j;
+		if (count > STRIDE_LENGTH)
+			count = STRIDE_LENGTH;
+		retval = io_channel_write_blk(fs->io, blk, count, buf);
+		if (retval) {
+			if (ret_count)
+				*ret_count = count;
+			if (ret_blk)
+				*ret_blk = blk;
+			return retval;
+		}
+	}
+	return 0;
+}
diff --git a/ext2ed/doc/ext2ed-design.sgml b/ext2ed/doc/ext2ed-design.sgml
index 3eaca69..ad2df96 100644
--- a/ext2ed/doc/ext2ed-design.sgml
+++ b/ext2ed/doc/ext2ed-design.sgml
@@ -2722,9 +2722,6 @@
 		struct {
 			__u32  h_i_translator;
 		} hurd1;
-		struct {
-			__u32  m_i_reserved1;
-		} masix1;
 	} osd1;				/* OS dependent 1 */
 	__u32	i_block[EXT2_N_BLOCKS];	/* Pointers to blocks */
 	__u32	i_version;		/* File version (for NFS) */
@@ -2746,12 +2743,6 @@
 			__u16	h_i_gid_high;
 			__u32	h_i_author;
 		} hurd2;
-		struct {
-			__u8	m_i_frag;	/* Fragment number */
-			__u8	m_i_fsize;	/* Fragment size */
-			__u16	m_pad1;
-			__u32	m_i_reserved2[2];
-		} masix2;
 	} osd2;				/* OS dependent 2 */
 };
 </ProgramListing>
diff --git a/lib/Makefile.library b/lib/Makefile.library
index cc2c0ff..52f28bb 100644
--- a/lib/Makefile.library
+++ b/lib/Makefile.library
@@ -13,7 +13,7 @@
 clean::
 	@$(RM) -f subdirs
 
-$(LIBRARY).a: $(OBJS)
+$(LIB)/$(LIBRARY).a $(LIBRARY).a: $(OBJS)
 	@echo "	GEN_LIB $@"
 	@(if test -r $@; then $(RM) -f $@.bak && $(MV) $@ $@.bak; fi)
 	@$(ARGEN) $@ $(OBJS)
diff --git a/lib/blkid/blkid.pc.in b/lib/blkid/blkid.pc.in
index 510aa84..ff51782 100644
--- a/lib/blkid/blkid.pc.in
+++ b/lib/blkid/blkid.pc.in
@@ -8,4 +8,5 @@
 Version: @E2FSPROGS_VERSION@
 Requires: uuid @DEVMAPPER_REQ@
 Cflags: -I${includedir} 
-Libs: -L${libdir} -lblkid @DEVMAPPER_PC_LIBS@
+Libs: -L${libdir} -lblkid
+Libs.private: @DEVMAPPER_PC_LIBS@
diff --git a/lib/blkid/getsize.c b/lib/blkid/getsize.c
index 04a0cd8..876d682 100644
--- a/lib/blkid/getsize.c
+++ b/lib/blkid/getsize.c
@@ -186,7 +186,7 @@
 #ifdef TEST_PROGRAM
 int main(int argc, char **argv)
 {
-	blkid_loff_t bytes;
+	long long bytes;
 	int	fd;
 
 	if (argc < 2) {
diff --git a/lib/blkid/probe.c b/lib/blkid/probe.c
index 4a5c7e7..45885c3 100644
--- a/lib/blkid/probe.c
+++ b/lib/blkid/probe.c
@@ -779,6 +779,7 @@
 		       unsigned char *buf)
 {
 	char uuid[40];
+
 	/* 168 is the offset to the 40 character uuid:
 	 * http://luks.endorphin.org/LUKS-on-disk-format.pdf */
 	strncpy(uuid, (char *) buf+168, 40);
diff --git a/lib/blkid/test_probe.in b/lib/blkid/test_probe.in
index 02d42bb..ce8c42f 100644
--- a/lib/blkid/test_probe.in
+++ b/lib/blkid/test_probe.in
@@ -8,7 +8,7 @@
 	done
 fi
 
-mkdir -p tests
+mkdir -p tests/tmp
 
 for i in $TESTS
 do
@@ -19,9 +19,9 @@
 		echo "non-existent"
 		continue
 	fi
-	bunzip2 < $SRCDIR/tests/$i.img.bz2 > /tmp/test.img.$$
-	./tst_probe /tmp/test.img.$$ > tests/$i.out
-	/bin/rm -f /tmp/test.img.$$ tests/$i.ok tests/$i.failed
+	bunzip2 < $SRCDIR/tests/$i.img.bz2 > tests/tmp/test.img.$$
+	./tst_probe tests/tmp/test.img.$$ > tests/$i.out
+	/bin/rm -f tests/tmp/test.img.$$ tests/$i.ok tests/$i.failed
 	cmp -s tests/$i.out $SRCDIR/tests/$i.results
 	if [ $? = 0 ];  then
 		echo ok
diff --git a/lib/e2p/feature.c b/lib/e2p/feature.c
index e5f3c3d..cf37447 100644
--- a/lib/e2p/feature.c
+++ b/lib/e2p/feature.c
@@ -45,7 +45,7 @@
 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_HUGE_FILE,
 			"huge_file" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
-			"gdt_checksum" },
+			"uninit_groups" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK,
 			"dir_nlink" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE,
@@ -67,6 +67,8 @@
 			"extent" },
 	{	E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT,
 			"64bit" },
+	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG,
+                        "flex_bg"},
 	{	0, 0, 0 },
 };
 
diff --git a/lib/e2p/fgetflags.c b/lib/e2p/fgetflags.c
index 0aed6c8..372304f 100644
--- a/lib/e2p/fgetflags.c
+++ b/lib/e2p/fgetflags.c
@@ -65,7 +65,7 @@
 #if HAVE_EXT2_IOCTLS
 	int fd, r, f, save_errno = 0;
 
-	if (!stat(name, &buf) &&
+	if (!lstat(name, &buf) &&
 	    !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) {
 		goto notsupp;
 	}
diff --git a/lib/e2p/fsetflags.c b/lib/e2p/fsetflags.c
index 2f1277f..3a05324 100644
--- a/lib/e2p/fsetflags.c
+++ b/lib/e2p/fsetflags.c
@@ -71,7 +71,7 @@
 #if HAVE_EXT2_IOCTLS
 	int fd, r, f, save_errno = 0;
 
-	if (!stat(name, &buf) &&
+	if (!lstat(name, &buf) &&
 	    !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) {
 		goto notsupp;
 	}
diff --git a/lib/e2p/iod.c b/lib/e2p/iod.c
index 808d3a3..84c9709 100644
--- a/lib/e2p/iod.c
+++ b/lib/e2p/iod.c
@@ -27,7 +27,7 @@
 {
 	DIR * dir;
 	struct dirent *de, *dep;
-	int	max_len = -1, len;
+	int	max_len = -1, len, ret = 0;
 
 #if HAVE_PATHCONF && defined(_PC_NAME_MAX) 
 	max_len = pathconf(dir_name, _PC_NAME_MAX);
@@ -64,9 +64,10 @@
 			len = max_len;
 #endif
 		memcpy(de, dep, len);
-		(*func) (dir_name, de, private);
+		if ((*func)(dir_name, de, private))
+			ret++;
 	}
 	free(de);
 	closedir(dir);
-	return 0;
+	return ret;
 }
diff --git a/lib/et/com_err.texinfo b/lib/et/com_err.texinfo
index def088c..7a00ffe 100644
--- a/lib/et/com_err.texinfo
+++ b/lib/et/com_err.texinfo
@@ -19,11 +19,9 @@
 
 @ifinfo
 @dircategory Development
-@format
-START-INFO-DIR-ENTRY
+@direntry
 * Com_err: (com_err).   A Common Error Description Library for UNIX.
-END-INFO-DIR-ENTRY
-@end format
+@end direntry
 @end ifinfo
 
 @iftex
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 199164a..2766493 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -7,10 +7,12 @@
 
 @MCONFIG@
 
-@DEBUGFS_CMT@DEBUGFS_LIB_OBJS = bb_compat.o cmp_bitmaps.o fileio.o \
+@DEBUGFS_CMT@DEBUGFS_LIB_OBJS = bb_compat.o fileio.o \
 @DEBUGFS_CMT@	inode_io.o namei.o write_bb_file.o 
 
-@RESIZER_CMT@RESIZE_LIB_OBJS = rs_bitmap.o dupfs.o test_io.o 
+MK_CMDS=	_SS_DIR_OVERRIDE=../ss ../ss/mk_cmds
+
+@RESIZER_CMT@RESIZE_LIB_OBJS = dupfs.o test_io.o 
 
 @IMAGER_CMT@E2IMAGE_LIB_OBJS = imager.o
 
@@ -28,6 +30,8 @@
 	bmap.o \
 	check_desc.o \
 	closefs.o \
+	crc16.o \
+	csum.o \
 	dblist.o \
 	dblist_dir.o \
 	dirblock.o \
@@ -35,6 +39,7 @@
 	dir_iterate.o \
 	expanddir.o \
 	ext_attr.o \
+	extent.o \
 	finddev.o \
 	flushb.o \
 	freefs.o \
@@ -82,7 +87,8 @@
 	$(srcdir)/bmap.c \
 	$(srcdir)/check_desc.c \
 	$(srcdir)/closefs.c \
-	$(srcdir)/cmp_bitmaps.c \
+	$(srcdir)/crc16.c \
+	$(srcdir)/csum.c \
 	$(srcdir)/dblist.c \
 	$(srcdir)/dblist_dir.c \
 	$(srcdir)/dirblock.c \
@@ -91,6 +97,7 @@
 	$(srcdir)/dupfs.c \
 	$(srcdir)/expanddir.c \
 	$(srcdir)/ext_attr.c \
+	$(srcdir)/extent.c \
 	$(srcdir)/fileio.c \
 	$(srcdir)/finddev.c \
 	$(srcdir)/flushb.c \
@@ -120,21 +127,21 @@
 	$(srcdir)/read_bb.c \
 	$(srcdir)/read_bb_file.c \
 	$(srcdir)/res_gdt.c \
-	$(srcdir)/rs_bitmap.c \
 	$(srcdir)/rw_bitmaps.c \
 	$(srcdir)/swapfs.c \
 	$(srcdir)/tdb.c \
 	$(srcdir)/test_io.c \
+	$(srcdir)/tst_badblocks.c \
+	$(srcdir)/tst_bitops.c \
+	$(srcdir)/tst_byteswap.c \
+	$(srcdir)/tst_csum.c \
+	$(srcdir)/tst_getsize.c \
+	$(srcdir)/tst_iscan.c \
 	$(srcdir)/unix_io.c \
 	$(srcdir)/unlink.c \
 	$(srcdir)/valid_blk.c \
 	$(srcdir)/version.c \
-	$(srcdir)/write_bb_file.c \
-	$(srcdir)/tst_badblocks.c \
-	$(srcdir)/tst_bitops.c \
-	$(srcdir)/tst_byteswap.c \
-	$(srcdir)/tst_getsize.c \
-	$(srcdir)/tst_iscan.c
+	$(srcdir)/write_bb_file.c
 
 HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h ext3_extents.h \
 	tdb.h
@@ -187,46 +194,42 @@
 	@echo "	CONFIG.STATUS $@"
 	@cd $(top_builddir); CONFIG_FILES=lib/ext2fs/ext2fs.pc ./config.status
 
-tst_badblocks: tst_badblocks.o freefs.o \
-		read_bb_file.o write_bb_file.o badblocks.o 
+tst_badblocks: tst_badblocks.o $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
-	@$(CC) -o tst_badblocks tst_badblocks.o freefs.o \
-		read_bb_file.o write_bb_file.o badblocks.o \
-		inline.o bitops.o gen_bitmap.o $(LIBCOM_ERR)
+	@$(CC) -o tst_badblocks tst_badblocks.o $(STATIC_LIBEXT2FS) \
+		$(LIBCOM_ERR)
 
-tst_icount: icount.c initialize.o  $(STATIC_LIBEXT2FS)
+tst_icount: $(srcdir)/icount.c $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
-	@$(CC) -o tst_icount $(srcdir)/icount.c initialize.o \
-		-DDEBUG $(ALL_CFLAGS) \
+	@$(CC) -o tst_icount $(srcdir)/icount.c -DDEBUG $(ALL_CFLAGS) \
 		$(STATIC_LIBEXT2FS) $(LIBCOM_ERR)
 
-tst_iscan: tst_iscan.o inode.o badblocks.o test_io.o $(STATIC_LIBEXT2FS)
+tst_iscan: tst_iscan.o $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
-	@$(CC) -o tst_iscan tst_iscan.o inode.o badblocks.o test_io.o \
-		$(STATIC_LIBEXT2FS) $(LIBCOM_ERR)
+	@$(CC) -o tst_iscan tst_iscan.o $(STATIC_LIBEXT2FS) $(LIBCOM_ERR)
 
-tst_getsize: tst_getsize.o getsize.o $(STATIC_LIBEXT2FS)
+tst_getsize: tst_getsize.o $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
-	@$(CC) -o tst_getsize tst_getsize.o getsize.o $(STATIC_LIBEXT2FS) \
+	@$(CC) -o tst_getsize tst_getsize.o $(STATIC_LIBEXT2FS) \
 		$(LIBCOM_ERR)
 
 tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
 	@$(CC) -o tst_ismounted $(srcdir)/ismounted.c -DDEBUG $(ALL_CFLAGS) $(LIBCOM_ERR) 
 
-tst_byteswap: tst_byteswap.o bitops.o $(STATIC_LIBEXT2FS)
+tst_byteswap: tst_byteswap.o $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
-	@$(CC) -o tst_byteswap tst_byteswap.o bitops.o $(STATIC_LIBEXT2FS) \
+	@$(CC) -o tst_byteswap tst_byteswap.o $(STATIC_LIBEXT2FS) \
 		$(LIBCOM_ERR)
 
-tst_bitops: tst_bitops.o inline.o $(STATIC_LIBEXT2FS)
+tst_bitops: tst_bitops.o $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
-	@$(CC) -o tst_bitops tst_bitops.o inline.o $(ALL_CFLAGS) \
+	@$(CC) -o tst_bitops tst_bitops.o $(ALL_CFLAGS) \
 		$(STATIC_LIBEXT2FS) $(LIBCOM_ERR)
 
-tst_getsectsize: tst_getsectsize.o getsectsize.o $(STATIC_LIBEXT2FS)
+tst_getsectsize: tst_getsectsize.o $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
-	@$(CC) -o tst_sectgetsize tst_getsectsize.o getsectsize.o \
+	@$(CC) -o tst_sectgetsize tst_getsectsize.o \
 		$(STATIC_LIBEXT2FS) $(LIBCOM_ERR)
 
 tst_types: tst_types.o ext2_types.h 
@@ -241,19 +244,85 @@
 	@echo "	LD $@"
 	@$(CC) -o ext2_tdbtool tdbtool.o tdb.o
 
+extent_dbg.c: $(srcdir)/extent_dbg.ct
+	@echo "	MK_CMDS $<"
+	@$(MK_CMDS) $(srcdir)/extent_dbg.ct
+
+debug_cmds.c debug_cmds.h: $(top_srcdir)/debugfs/debug_cmds.ct
+	@echo "	MK_CMDS $<@"
+	@$(MK_CMDS) $(top_srcdir)/debugfs/debug_cmds.ct
+
+DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o ls.o \
+	lsdel.o dump.o set_fields.o logdump.o htree.o unused.o
+
+debugfs.o: $(top_srcdir)/debugfs/debugfs.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+util.o: $(top_srcdir)/debugfs/util.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+ncheck.o: $(top_srcdir)/debugfs/ncheck.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+icheck.o: $(top_srcdir)/debugfs/icheck.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+ls.o: $(top_srcdir)/debugfs/ls.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+lsdel.o: $(top_srcdir)/debugfs/lsdel.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+dump.o: $(top_srcdir)/debugfs/dump.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+set_fields.o: $(top_srcdir)/debugfs/set_fields.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+logdump.o: $(top_srcdir)/debugfs/logdump.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+htree.o: $(top_srcdir)/debugfs/htree.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+unused.o: $(top_srcdir)/debugfs/unused.c
+	@echo "	CC $<"
+	@$(CC) $(ALL_CFLAGS) -c $< -o $@
+
+tst_extents: $(srcdir)/extent.c extent_dbg.c $(DEBUG_OBJS) $(LIBSS) $(LIBE2P) $(DEPLIBUUID) $(DEPLIBBLKID)
+	@echo "	LD $@"
+	@$(CC) -o tst_extents $(srcdir)/extent.c extent_dbg.c \
+		$(ALL_CFLAGS) -DDEBUG $(DEBUG_OBJS) $(LIBSS) $(LIBE2P) \
+		$(LIBUUID) $(STATIC_LIBEXT2FS) $(LIBBLKID) $(LIBCOM_ERR) \
+		-I $(top_srcdir)/debugfs
+
+tst_csum: tst_csum.c csum.c $(STATIC_LIBEXT2FS)
+	@echo "	LD $@"
+	@$(CC) -o tst_csum $(srcdir)/csum.c $(srcdir)/tst_csum.c -DDEBUG \
+		$(ALL_CFLAGS) $(STATIC_LIBEXT2FS) $(LIBCOM_ERR)
+
 mkjournal: mkjournal.c $(STATIC_LIBEXT2FS)
 	@echo "	LD $@"
 	@$(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS)
 
-check:: tst_bitops tst_badblocks tst_iscan @SWAPFS_CMT@ tst_byteswap \
-	tst_types tst_icount tst_super_size
+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_bitops
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_badblocks
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_iscan
-@SWAPFS_CMT@	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_byteswap
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_types
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_icount
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_super_size
+	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_csum
 
 installdirs::
 	@echo "	MKINSTALLDIRS $(libdir) $(includedir)/ext2fs"
@@ -285,8 +354,8 @@
 	$(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* checker/* \
 		tst_badblocks tst_iscan ext2_err.et ext2_err.c ext2_err.h \
 		tst_byteswap tst_ismounted tst_getsize tst_sectgetsize \
-		tst_bitops tst_types tst_icount tst_super_size \
-		ext2_tdbtool mkjournal \
+		tst_bitops tst_types tst_icount tst_super_size tst_csum \
+		ext2_tdbtool mkjournal debug_cmds.c \
 		../libext2fs.a ../libext2fs_p.a ../libext2fs_chk.a
 
 mostlyclean:: clean
@@ -309,277 +378,344 @@
 alloc.o: $(srcdir)/alloc.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 alloc_sb.o: $(srcdir)/alloc_sb.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 alloc_stats.o: $(srcdir)/alloc_stats.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 alloc_tables.o: $(srcdir)/alloc_tables.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 badblocks.o: $(srcdir)/badblocks.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
 bb_compat.o: $(srcdir)/bb_compat.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
 bb_inode.o: $(srcdir)/bb_inode.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 bitmaps.o: $(srcdir)/bitmaps.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 bitops.o: $(srcdir)/bitops.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 block.o: $(srcdir)/block.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 bmap.o: $(srcdir)/bmap.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 check_desc.o: $(srcdir)/check_desc.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 closefs.o: $(srcdir)/closefs.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
-cmp_bitmaps.o: $(srcdir)/cmp_bitmaps.c $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
+crc16.o: $(srcdir)/crc16.c $(srcdir)/crc16.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/crc16.h
 dblist.o: $(srcdir)/dblist.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
 dblist_dir.o: $(srcdir)/dblist_dir.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
 dirblock.o: $(srcdir)/dirblock.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 dirhash.o: $(srcdir)/dirhash.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 dir_iterate.o: $(srcdir)/dir_iterate.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
 dupfs.o: $(srcdir)/dupfs.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
 expanddir.o: $(srcdir)/expanddir.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 ext_attr.o: $(srcdir)/ext_attr.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2_ext_attr.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
+extent.o: $(srcdir)/extent.c $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
+ $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h $(srcdir)/e2image.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h
 fileio.o: $(srcdir)/fileio.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 finddev.o: $(srcdir)/finddev.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 flushb.o: $(srcdir)/flushb.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 freefs.o: $(srcdir)/freefs.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
 gen_bitmap.o: $(srcdir)/gen_bitmap.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 get_pathname.o: $(srcdir)/get_pathname.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 getsize.o: $(srcdir)/getsize.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 getsectsize.o: $(srcdir)/getsectsize.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 icount.o: $(srcdir)/icount.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h \
- $(srcdir)/tdb.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/tdb.h
 ind_block.o: $(srcdir)/ind_block.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 initialize.o: $(srcdir)/initialize.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 inline.o: $(srcdir)/inline.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 inode.o: $(srcdir)/inode.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h $(srcdir)/e2image.h
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h $(srcdir)/e2image.h
 inode_io.o: $(srcdir)/inode_io.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 imager.o: $(srcdir)/imager.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 io_manager.o: $(srcdir)/io_manager.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 ismounted.o: $(srcdir)/ismounted.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 link.o: $(srcdir)/link.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 llseek.o: $(srcdir)/llseek.c $(top_srcdir)/lib/et/com_err.h \
  $(srcdir)/ext2_io.h
 lookup.o: $(srcdir)/lookup.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 mkdir.o: $(srcdir)/mkdir.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 mkjournal.o: $(srcdir)/mkjournal.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/e2p/e2p.h \
  $(srcdir)/ext2_fs.h $(srcdir)/ext2fs.h $(srcdir)/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h \
- $(srcdir)/jfs_user.h $(srcdir)/kernel-jbd.h $(srcdir)/jfs_compat.h \
- $(srcdir)/kernel-list.h
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h $(srcdir)/jfs_user.h $(srcdir)/kernel-jbd.h \
+ $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h
 namei.o: $(srcdir)/namei.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 native.o: $(srcdir)/native.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 newdir.o: $(srcdir)/newdir.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 openfs.o: $(srcdir)/openfs.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h \
- $(srcdir)/e2image.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/e2image.h
 read_bb.o: $(srcdir)/read_bb.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 read_bb_file.o: $(srcdir)/read_bb_file.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 res_gdt.o: $(srcdir)/res_gdt.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
-rs_bitmap.o: $(srcdir)/rs_bitmap.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 rw_bitmaps.o: $(srcdir)/rw_bitmaps.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h \
- $(srcdir)/e2image.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/e2image.h
 swapfs.o: $(srcdir)/swapfs.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h \
- $(srcdir)/ext2_ext_attr.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 tdb.o: $(srcdir)/tdb.c $(srcdir)/tdb.h
 test_io.o: $(srcdir)/test_io.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
-unix_io.o: $(srcdir)/unix_io.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
-unlink.o: $(srcdir)/unlink.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
-valid_blk.o: $(srcdir)/valid_blk.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
-version.o: $(srcdir)/version.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h \
- $(top_srcdir)/version.h
-write_bb_file.o: $(srcdir)/write_bb_file.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 tst_badblocks.o: $(srcdir)/tst_badblocks.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 tst_bitops.o: $(srcdir)/tst_bitops.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 tst_byteswap.o: $(srcdir)/tst_byteswap.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+tst_csum.o: $(srcdir)/tst_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 \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 tst_getsize.o: $(srcdir)/tst_getsize.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 tst_iscan.o: $(srcdir)/tst_iscan.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 \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+unix_io.o: $(srcdir)/unix_io.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 \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+unlink.o: $(srcdir)/unlink.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 \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+valid_blk.o: $(srcdir)/valid_blk.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 \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+version.o: $(srcdir)/version.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 \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(top_srcdir)/version.h
+write_bb_file.o: $(srcdir)/write_bb_file.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 \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
diff --git a/lib/ext2fs/alloc_stats.c b/lib/ext2fs/alloc_stats.c
index 4088f7b..725f28d 100644
--- a/lib/ext2fs/alloc_stats.c
+++ b/lib/ext2fs/alloc_stats.c
@@ -27,6 +27,25 @@
 	fs->group_desc[group].bg_free_inodes_count -= inuse;
 	if (isdir)
 		fs->group_desc[group].bg_used_dirs_count += inuse;
+
+	/* We don't strictly need to be clearing these if inuse < 0
+	 * (i.e. freeing inodes) but it also means something is bad. */
+	fs->group_desc[group].bg_flags &= ~(EXT2_BG_INODE_UNINIT |
+					    EXT2_BG_BLOCK_UNINIT);
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+		ext2_ino_t first_unused_inode =	fs->super->s_inodes_per_group -
+			fs->group_desc[group].bg_itable_unused +
+			group * fs->super->s_inodes_per_group + 1;
+
+		if (ino >= first_unused_inode)
+			fs->group_desc[group].bg_itable_unused =
+				group * fs->super->s_inodes_per_group +
+				fs->super->s_inodes_per_group - ino;
+
+		ext2fs_group_desc_csum_set(fs, group);
+	}
+
 	fs->super->s_free_inodes_count -= inuse;
 	ext2fs_mark_super_dirty(fs);
 	ext2fs_mark_ib_dirty(fs);
@@ -46,6 +65,9 @@
 	else
 		ext2fs_unmark_block_bitmap(fs->block_map, blk);
 	fs->group_desc[group].bg_free_blocks_count -= inuse;
+	fs->group_desc[group].bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
+	ext2fs_group_desc_csum_set(fs, group);
+
 	fs->super->s_free_blocks_count -= inuse;
 	ext2fs_mark_super_dirty(fs);
 	ext2fs_mark_bb_dirty(fs);
diff --git a/lib/ext2fs/alloc_tables.c b/lib/ext2fs/alloc_tables.c
index 4ad2ba9..9b4f0e5 100644
--- a/lib/ext2fs/alloc_tables.c
+++ b/lib/ext2fs/alloc_tables.c
@@ -95,13 +95,11 @@
 			ext2fs_mark_block_bitmap(bmap, blk);
 		fs->group_desc[group].bg_inode_table = new_blk;
 	}
+	ext2fs_group_desc_csum_set(fs, group);
 
-	
 	return 0;
 }
 
-	
-
 errcode_t ext2fs_allocate_tables(ext2_filsys fs)
 {
 	errcode_t	retval;
diff --git a/lib/ext2fs/bitmaps.c b/lib/ext2fs/bitmaps.c
index 696baad..b033fa3 100644
--- a/lib/ext2fs/bitmaps.c
+++ b/lib/ext2fs/bitmaps.c
@@ -27,96 +27,31 @@
 #include "ext2_fs.h"
 #include "ext2fs.h"
 
-static errcode_t make_bitmap(__u32 start, __u32 end, __u32 real_end,
-			     const char *descr, char *init_map,
-			     ext2fs_generic_bitmap *ret)
+void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
 {
-	ext2fs_generic_bitmap	bitmap;
-	errcode_t		retval;
-	size_t			size;
-
-	retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), 
-				&bitmap);
-	if (retval)
-		return retval;
-
-	bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
-	bitmap->fs = NULL;
-	bitmap->start = start;
-	bitmap->end = end;
-	bitmap->real_end = real_end;
-	bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
-	if (descr) {
-		retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
-		if (retval) {
-			ext2fs_free_mem(&bitmap);
-			return retval;
-		}
-		strcpy(bitmap->description, descr);
-	} else
-		bitmap->description = 0;
-
-	size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
-	retval = ext2fs_get_mem(size, &bitmap->bitmap);
-	if (retval) {
-		ext2fs_free_mem(&bitmap->description);
-		ext2fs_free_mem(&bitmap);
-		return retval;
-	}
-
-	if (init_map)
-		memcpy(bitmap->bitmap, init_map, size);
-	else
-		memset(bitmap->bitmap, 0, size);
-	*ret = bitmap;
-	return 0;
+	ext2fs_free_generic_bitmap(bitmap);
 }
 
-errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
-					 __u32 end,
-					 __u32 real_end,
-					 const char *descr,
-					 ext2fs_generic_bitmap *ret)
+void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap)
 {
-	return make_bitmap(start, end, real_end, descr, 0, ret);
+	ext2fs_free_generic_bitmap(bitmap);
 }
 
 errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
 			     ext2fs_generic_bitmap *dest)
 {
-	errcode_t		retval;
-	ext2fs_generic_bitmap	new_map;
-
-	retval = make_bitmap(src->start, src->end, src->real_end,
-			     src->description, src->bitmap, &new_map);
-	if (retval)
-		return retval;
-	new_map->magic = src->magic;
-	new_map->fs = src->fs;
-	new_map->base_error_code = src->base_error_code;
-	*dest = new_map;
-	return 0;
+	return (ext2fs_copy_generic_bitmap(src, dest));
 }
 
 void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
 {
-	__u32	i, j;
-
-	/* Protect loop from wrap-around if map->real_end is maxed */
-	for (i=map->end+1, j = i - map->start; 
-	     i <= map->real_end && i > map->end; 
-	     i++, j++)
-		ext2fs_set_bit(j, map->bitmap);
-
-	return;
+	ext2fs_set_generic_bitmap_padding(map);
 }	
 
 errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
 				       const char *descr,
 				       ext2fs_inode_bitmap *ret)
 {
-	ext2fs_inode_bitmap bitmap;
-	errcode_t	retval;
 	__u32		start, end, real_end;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@@ -127,25 +62,15 @@
 	end = fs->super->s_inodes_count;
 	real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count);
 
-	retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
-						descr, &bitmap);
-	if (retval)
-		return retval;
-	
-	bitmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
-	bitmap->fs = fs;
-	bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
-	
-	*ret = bitmap;
-	return 0;
+	return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP, fs,
+					   start, end, real_end,
+					   descr, 0, ret));
 }
 
 errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
 				       const char *descr,
 				       ext2fs_block_bitmap *ret)
 {
-	ext2fs_block_bitmap bitmap;
-	errcode_t	retval;
 	__u32		start, end, real_end;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@@ -157,59 +82,102 @@
 	real_end = (EXT2_BLOCKS_PER_GROUP(fs->super)  
 		    * fs->group_desc_count)-1 + start;
 	
-	retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
-						descr, &bitmap);
-	if (retval)
-		return retval;
-
-	bitmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
-	bitmap->fs = fs;
-	bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
-	
-	*ret = bitmap;
-	return 0;
+	return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, fs,
+					   start, end, real_end,
+					   descr, 0, ret));
 }
 
 errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
 					ext2_ino_t end, ext2_ino_t *oend)
 {
-	EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
-	
-	if (end > bitmap->real_end)
-		return EXT2_ET_FUDGE_INODE_BITMAP_END;
-	if (oend)
-		*oend = bitmap->end;
-	bitmap->end = end;
-	return 0;
+
+	return (ext2fs_fudge_generic_bitmap_end(bitmap,
+						EXT2_ET_MAGIC_INODE_BITMAP,
+						EXT2_ET_FUDGE_INODE_BITMAP_END,
+						end, oend));
 }
 
 errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
 					blk_t end, blk_t *oend)
 {
-	EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
-	
-	if (end > bitmap->real_end)
-		return EXT2_ET_FUDGE_BLOCK_BITMAP_END;
-	if (oend)
-		*oend = bitmap->end;
-	bitmap->end = end;
-	return 0;
+	return (ext2fs_fudge_generic_bitmap_end(bitmap,
+						EXT2_ET_MAGIC_BLOCK_BITMAP,
+						EXT2_ET_FUDGE_BLOCK_BITMAP_END,
+						end, oend));
 }
 
 void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap)
 {
-	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
-		return;
-
-	memset(bitmap->bitmap, 0,
-	       (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
+	ext2fs_clear_generic_bitmap(bitmap);
 }
 
 void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap)
 {
-	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
-		return;
+	ext2fs_clear_generic_bitmap(bitmap);
+}
 
-	memset(bitmap->bitmap, 0,
-	       (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
+errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
+				     ext2fs_inode_bitmap bmap)
+{
+	return (ext2fs_resize_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP,
+					     new_end, new_real_end, bmap));
+}
+
+errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
+				     ext2fs_block_bitmap bmap)
+{
+	return (ext2fs_resize_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP,
+					     new_end, new_real_end, bmap));
+}
+
+errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
+				      ext2fs_block_bitmap bm2)
+{
+	return (ext2fs_compare_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP,
+					      EXT2_ET_NEQ_BLOCK_BITMAP,
+					      bm1, bm2));
+}
+
+errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
+				      ext2fs_inode_bitmap bm2)
+{
+	return (ext2fs_compare_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP,
+					      EXT2_ET_NEQ_INODE_BITMAP,
+					      bm1, bm2));
+}
+
+errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap,
+					ext2_ino_t start, unsigned int num,
+					void *in)
+{
+	return (ext2fs_set_generic_bitmap_range(bmap,
+						EXT2_ET_MAGIC_INODE_BITMAP,
+						start, num, in));
+}
+
+errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap,
+					ext2_ino_t start, unsigned int num,
+					void *out)
+{
+	return (ext2fs_get_generic_bitmap_range(bmap,
+						EXT2_ET_MAGIC_INODE_BITMAP,
+						start, num, out));
+}
+
+errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap,
+					blk_t start, unsigned int num,
+					void *in)
+{
+	return (ext2fs_set_generic_bitmap_range(bmap, 
+						EXT2_ET_MAGIC_BLOCK_BITMAP,
+						start, num, in));
+}
+
+errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap,
+					blk_t start, unsigned int num,
+					void *out)
+{
+	return (ext2fs_get_generic_bitmap_range(bmap,
+						EXT2_ET_MAGIC_BLOCK_BITMAP,
+						start, num, out));
 }
diff --git a/lib/ext2fs/bitops.c b/lib/ext2fs/bitops.c
index 78632c6..9c34847 100644
--- a/lib/ext2fs/bitops.c
+++ b/lib/ext2fs/bitops.c
@@ -76,16 +76,3 @@
 		com_err(0, errcode, "#%lu", arg);
 #endif
 }
-
-void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
-			    int code, unsigned long arg)
-{
-#ifndef OMIT_COM_ERR
-	if (bitmap->description)
-		com_err(0, bitmap->base_error_code+code,
-			"#%lu for %s", arg, bitmap->description);
-	else
-		com_err(0, bitmap->base_error_code + code, "#%lu", arg);
-#endif
-}
-
diff --git a/lib/ext2fs/bitops.h b/lib/ext2fs/bitops.h
index 76f902d..d83ce8e 100644
--- a/lib/ext2fs/bitops.h
+++ b/lib/ext2fs/bitops.h
@@ -104,11 +104,18 @@
 					       blk_t block, int num);
 extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map);
 
-/* These two routines moved to gen_bitmap.c */
+/* These routines moved to gen_bitmap.c */
 extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
 					 __u32 bitno);
 extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
 					   blk_t bitno);
+extern int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
+				      blk_t bitno);
+extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+					  blk_t block, int num);
+extern __u32 ext2fs_get_generic_bitmap_start(ext2fs_generic_bitmap bitmap);
+extern __u32 ext2fs_get_generic_bitmap_end(ext2fs_generic_bitmap bitmap);
+
 /*
  * The inline routines themselves...
  * 
@@ -267,36 +274,6 @@
 }
 #endif
 
-#ifdef EXT2FS_ENABLE_SWAPFS
-_INLINE_ __u32 ext2fs_swab32(__u32 val)
-{
-#ifdef EXT2FS_REQUIRE_486
-	__asm__("bswap %0" : "=r" (val) : "0" (val));
-#else
-	__asm__("xchgb %b0,%h0\n\t"	/* swap lower bytes	*/
-		"rorl $16,%0\n\t"	/* swap words		*/
-		"xchgb %b0,%h0"		/* swap higher bytes	*/
-		:"=q" (val)
-		: "0" (val));
-#endif
-	return val;
-}
-
-_INLINE_ __u16 ext2fs_swab16(__u16 val)
-{
-	__asm__("xchgb %b0,%h0"		/* swap bytes		*/ \
-		: "=q" (val) \
-		:  "0" (val)); \
-		return val;
-}
-
-_INLINE_ __u64 ext2fs_swab64(__u64 val)
-{
-	return (ext2fs_swab32(val >> 32) |
-		(((__u64)ext2fs_swab32(val & 0xFFFFFFFFUL)) << 32));
-}
-#endif
-
 #undef EXT2FS_ADDR
 
 #endif	/* i386 */
@@ -339,7 +316,7 @@
 #endif /* __mc68000__ */
 
 
-#if !defined(_EXT2_HAVE_ASM_SWAB_) && defined(EXT2FS_ENABLE_SWAPFS)
+#if !defined(_EXT2_HAVE_ASM_SWAB_) && defined(WORDS_BIGENDIAN)
 
 _INLINE_ __u16 ext2fs_swab16(__u16 val)
 {
@@ -401,24 +378,10 @@
 }
 #endif	
 
-_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
-					blk_t bitno);
-
-_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
-					blk_t bitno)
-{
-	if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
-		ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
-		return 0;
-	}
-	return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
-}
-
 _INLINE_ int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
 				       blk_t block)
 {
-	return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap)
-				       bitmap,
+	return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
 					  block);
 }
 
@@ -460,197 +423,77 @@
 _INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
 					    blk_t block)
 {
-#ifdef EXT2FS_DEBUG_FAST_OPS
-	if ((block < bitmap->start) || (block > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
-				   bitmap->description);
-		return;
-	}
-#endif	
-	ext2fs_fast_set_bit(block - bitmap->start, bitmap->bitmap);
+	ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, block);
 }
 
 _INLINE_ void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
 					      blk_t block)
 {
-#ifdef EXT2FS_DEBUG_FAST_OPS
-	if ((block < bitmap->start) || (block > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK,
-				   block, bitmap->description);
-		return;
-	}
-#endif
-	ext2fs_fast_clear_bit(block - bitmap->start, bitmap->bitmap);
+	ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, block);
 }
 
 _INLINE_ int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
 					    blk_t block)
 {
-#ifdef EXT2FS_DEBUG_FAST_OPS
-	if ((block < bitmap->start) || (block > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
-				   block, bitmap->description);
-		return 0;
-	}
-#endif
-	return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
+	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
+					  block);
 }
 
 _INLINE_ void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
 					    ext2_ino_t inode)
 {
-#ifdef EXT2FS_DEBUG_FAST_OPS
-	if ((inode < bitmap->start) || (inode > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_MARK,
-				   inode, bitmap->description);
-		return;
-	}
-#endif
-	ext2fs_fast_set_bit(inode - bitmap->start, bitmap->bitmap);
+	ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, inode);
 }
 
 _INLINE_ void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
 					      ext2_ino_t inode)
 {
-#ifdef EXT2FS_DEBUG_FAST_OPS
-	if ((inode < bitmap->start) || (inode > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_UNMARK,
-				   inode, bitmap->description);
-		return;
-	}
-#endif
-	ext2fs_fast_clear_bit(inode - bitmap->start, bitmap->bitmap);
+	ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, inode);
 }
 
 _INLINE_ int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
 					   ext2_ino_t inode)
 {
-#ifdef EXT2FS_DEBUG_FAST_OPS
-	if ((inode < bitmap->start) || (inode > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
-				   inode, bitmap->description);
-		return 0;
-	}
-#endif
-	return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
+	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
+					  inode);
 }
 
 _INLINE_ blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap)
 {
-	return bitmap->start;
+	return ext2fs_get_generic_bitmap_start((ext2fs_generic_bitmap) bitmap);
 }
 
 _INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap)
 {
-	return bitmap->start;
+	return ext2fs_get_generic_bitmap_start((ext2fs_generic_bitmap) bitmap);
 }
 
 _INLINE_ blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap)
 {
-	return bitmap->end;
+	return ext2fs_get_generic_bitmap_end((ext2fs_generic_bitmap) bitmap);
 }
 
 _INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap)
 {
-	return bitmap->end;
-}
-
-_INLINE_ int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
-					    blk_t block, int num)
-{
-	int	i;
-
-	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
-				   block, bitmap->description);
-		return 0;
-	}
-	for (i=0; i < num; i++) {
-		if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
-			return 0;
-	}
-	return 1;
+	return ext2fs_get_generic_bitmap_end((ext2fs_generic_bitmap) bitmap);
 }
 
 _INLINE_ int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
 						 blk_t block, int num)
 {
-	int	i;
-
-#ifdef EXT2FS_DEBUG_FAST_OPS
-	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
-				   block, bitmap->description);
-		return 0;
-	}
-#endif
-	for (i=0; i < num; i++) {
-		if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
-			return 0;
-	}
-	return 1;
-}
-
-_INLINE_ void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
-					     blk_t block, int num)
-{
-	int	i;
-	
-	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
-				   bitmap->description);
-		return;
-	}
-	for (i=0; i < num; i++)
-		ext2fs_fast_set_bit(block + i - bitmap->start, bitmap->bitmap);
+	return ext2fs_test_block_bitmap_range(bitmap, block, num);
 }
 
 _INLINE_ void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
 						  blk_t block, int num)
 {
-	int	i;
-	
-#ifdef EXT2FS_DEBUG_FAST_OPS
-	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
-				   bitmap->description);
-		return;
-	}
-#endif	
-	for (i=0; i < num; i++)
-		ext2fs_fast_set_bit(block + i - bitmap->start, bitmap->bitmap);
-}
-
-_INLINE_ void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
-					       blk_t block, int num)
-{
-	int	i;
-	
-	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
-				   bitmap->description);
-		return;
-	}
-	for (i=0; i < num; i++)
-		ext2fs_fast_clear_bit(block + i - bitmap->start, 
-				      bitmap->bitmap);
+	ext2fs_mark_block_bitmap_range(bitmap, block, num);
 }
 
 _INLINE_ void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
 						    blk_t block, int num)
 {
-	int	i;
-	
-#ifdef EXT2FS_DEBUG_FAST_OPS
-	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
-				   bitmap->description);
-		return;
-	}
-#endif	
-	for (i=0; i < num; i++)
-		ext2fs_fast_clear_bit(block + i - bitmap->start, 
-				      bitmap->bitmap);
+	ext2fs_unmark_block_bitmap_range(bitmap, block, num);
 }
 #undef _INLINE_
 #endif
diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index 07a6415..279a33f 100644
--- a/lib/ext2fs/block.c
+++ b/lib/ext2fs/block.c
@@ -36,6 +36,26 @@
 	void	*priv_data;
 };
 
+#define check_for_ro_violation_return(ctx, ret)				\
+	do {								\
+		if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) &&		\
+		    ((ret) & BLOCK_CHANGED)) {				\
+			(ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE;	\
+			ret |= BLOCK_ABORT | BLOCK_ERROR;		\
+			return ret;					\
+		}							\
+	} while (0)
+
+#define check_for_ro_violation_goto(ctx, ret, label)			\
+	do {								\
+		if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) &&		\
+		    ((ret) & BLOCK_CHANGED)) {				\
+			(ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE;	\
+			ret |= BLOCK_ABORT | BLOCK_ERROR;		\
+			goto label;					\
+		}							\
+	} while (0)
+
 static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
 			     int ref_offset, struct block_context *ctx)
 {
@@ -49,6 +69,7 @@
 		ret = (*ctx->func)(ctx->fs, ind_block,
 				   BLOCK_COUNT_IND, ref_block,
 				   ref_offset, ctx->priv_data);
+	check_for_ro_violation_return(ctx, ret);
 	if (!*ind_block || (ret & BLOCK_ABORT)) {
 		ctx->bcount += limit;
 		return ret;
@@ -95,6 +116,7 @@
 			offset += sizeof(blk_t);
 		}
 	}
+	check_for_ro_violation_return(ctx, changed);
 	if (changed & BLOCK_CHANGED) {
 		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
 						      ctx->ind_buf);
@@ -107,6 +129,7 @@
 		ret |= (*ctx->func)(ctx->fs, ind_block,
 				    BLOCK_COUNT_IND, ref_block,
 				    ref_offset, ctx->priv_data);
+	check_for_ro_violation_return(ctx, ret);
 	return ret;
 }
 	
@@ -123,6 +146,7 @@
 		ret = (*ctx->func)(ctx->fs, dind_block,
 				   BLOCK_COUNT_DIND, ref_block,
 				   ref_offset, ctx->priv_data);
+	check_for_ro_violation_return(ctx, ret);
 	if (!*dind_block || (ret & BLOCK_ABORT)) {
 		ctx->bcount += limit*limit;
 		return ret;
@@ -171,6 +195,7 @@
 			offset += sizeof(blk_t);
 		}
 	}
+	check_for_ro_violation_return(ctx, changed);
 	if (changed & BLOCK_CHANGED) {
 		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
 						      ctx->dind_buf);
@@ -183,6 +208,7 @@
 		ret |= (*ctx->func)(ctx->fs, dind_block,
 				    BLOCK_COUNT_DIND, ref_block,
 				    ref_offset, ctx->priv_data);
+	check_for_ro_violation_return(ctx, ret);
 	return ret;
 }
 	
@@ -199,6 +225,7 @@
 		ret = (*ctx->func)(ctx->fs, tind_block,
 				   BLOCK_COUNT_TIND, ref_block,
 				   ref_offset, ctx->priv_data);
+	check_for_ro_violation_return(ctx, ret);
 	if (!*tind_block || (ret & BLOCK_ABORT)) {
 		ctx->bcount += limit*limit*limit;
 		return ret;
@@ -247,6 +274,7 @@
 			offset += sizeof(blk_t);
 		}
 	}
+	check_for_ro_violation_return(ctx, changed);
 	if (changed & BLOCK_CHANGED) {
 		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
 						      ctx->tind_buf);
@@ -259,7 +287,7 @@
 		ret |= (*ctx->func)(ctx->fs, tind_block,
 				    BLOCK_COUNT_TIND, ref_block,
 				    ref_offset, ctx->priv_data);
-	
+	check_for_ro_violation_return(ctx, ret);
 	return ret;
 }
 	
@@ -276,9 +304,7 @@
 				void *priv_data)
 {
 	int	i;
-	int	got_inode = 0;
 	int	ret = 0;
-	blk_t	blocks[EXT2_N_BLOCKS];	/* directory data blocks */
 	struct ext2_inode inode;
 	errcode_t	retval;
 	struct block_context ctx;
@@ -286,23 +312,19 @@
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
+	ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
+	if (ctx.errcode)
+		return ctx.errcode;
+
 	/*
 	 * Check to see if we need to limit large files
 	 */
 	if (flags & BLOCK_FLAG_NO_LARGE) {
-		ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
-		if (ctx.errcode)
-			return ctx.errcode;
-		got_inode = 1;
 		if (!LINUX_S_ISDIR(inode.i_mode) &&
 		    (inode.i_size_high != 0))
 			return EXT2_ET_FILE_TOO_BIG;
 	}
 
-	retval = ext2fs_get_blocks(fs, ino, blocks);
-	if (retval)
-		return retval;
-
 	limit = fs->blocksize >> 2;
 
 	ctx.fs = fs;
@@ -325,10 +347,6 @@
 	 */
 	if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
 	    !(flags & BLOCK_FLAG_DATA_ONLY)) {
-		ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
-		if (ctx.errcode)
-			goto abort_exit;
-		got_inode = 1;
 		if (inode.osd1.hurd1.h_i_translator) {
 			ret |= (*ctx.func)(fs,
 					   &inode.osd1.hurd1.h_i_translator,
@@ -336,36 +354,98 @@
 					   0, 0, priv_data);
 			if (ret & BLOCK_ABORT)
 				goto abort_exit;
+			check_for_ro_violation_goto(&ctx, ret, abort_exit);
 		}
 	}
 	
+	if (inode.i_flags & EXT4_EXTENTS_FL) {
+		ext2_extent_handle_t	handle;
+		struct ext2fs_extent	extent;
+		e2_blkcnt_t		blockcnt;
+		blk_t			blk;
+		int			op = EXT2_EXTENT_ROOT;
+		unsigned int		j;
+
+		if (!(flags & BLOCK_FLAG_READ_ONLY))
+			return EXT2_ET_EXTENT_NOT_SUPPORTED;
+
+		ctx.errcode = ext2fs_extent_open(fs, ino, &handle);
+		if (ctx.errcode)
+			goto abort_exit;
+
+		while (1) {
+			ctx.errcode = ext2fs_extent_get(handle, op, &extent);
+			if (ctx.errcode) {
+				if (ctx.errcode == EXT2_ET_EXTENT_NO_NEXT)
+					ctx.errcode = 0;
+				break;
+			}
+
+			op = EXT2_EXTENT_NEXT;
+			blk = extent.e_pblk;
+			if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) &&
+			    !(ctx.flags & BLOCK_FLAG_DATA_ONLY) &&
+			    ((!(extent.e_flags &
+				EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
+			      !(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) ||
+			     ((extent.e_flags &
+			       EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
+			      (ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)))) {
+				ret |= (*ctx.func)(fs, &blk,
+						   -1, 0, 0, priv_data);
+				check_for_ro_violation_goto(&ctx, ret,
+							    extent_errout);
+				continue;
+			}
+			for (blockcnt = extent.e_lblk, j = 0;
+			     j < extent.e_len;
+			     blk++, blockcnt++, j++) {
+				ret |= (*ctx.func)(fs, &blk,
+						   blockcnt,
+						   0, 0, priv_data);
+				check_for_ro_violation_goto(&ctx, ret,
+							    extent_errout);
+				if (ret & BLOCK_ABORT) {
+					ext2fs_extent_free(handle);
+					goto abort_exit;
+				}
+			}
+		}
+
+	extent_errout:
+		ext2fs_extent_free(handle);
+		ret |= BLOCK_ERROR | BLOCK_ABORT;
+		goto abort_exit;
+	}
+
 	/*
 	 * Iterate over normal data blocks
 	 */
 	for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
-		if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
-			ret |= (*ctx.func)(fs, &blocks[i],
+		if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) {
+			ret |= (*ctx.func)(fs, &inode.i_block[i],
 					    ctx.bcount, 0, i, priv_data);
 			if (ret & BLOCK_ABORT)
 				goto abort_exit;
 		}
 	}
-	if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
-		ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
+	check_for_ro_violation_goto(&ctx, ret, abort_exit);
+	if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
+		ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK],
 					 0, EXT2_IND_BLOCK, &ctx);
 		if (ret & BLOCK_ABORT)
 			goto abort_exit;
 	} else
 		ctx.bcount += limit;
-	if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
-		ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
+	if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
+		ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK],
 					  0, EXT2_DIND_BLOCK, &ctx);
 		if (ret & BLOCK_ABORT)
 			goto abort_exit;
 	} else
 		ctx.bcount += limit * limit;
-	if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
-		ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
+	if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
+		ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK],
 					  0, EXT2_TIND_BLOCK, &ctx);
 		if (ret & BLOCK_ABORT)
 			goto abort_exit;
@@ -373,13 +453,6 @@
 
 abort_exit:
 	if (ret & BLOCK_CHANGED) {
-		if (!got_inode) {
-			retval = ext2fs_read_inode(fs, ino, &inode);
-			if (retval)
-				return retval;
-		}
-		for (i=0; i < EXT2_N_BLOCKS; i++)
-			inode.i_block[i] = blocks[i];
 		retval = ext2fs_write_inode(fs, ino, &inode);
 		if (retval)
 			return retval;
diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index 754fc49..5fe0986 100644
--- a/lib/ext2fs/bmap.c
+++ b/lib/ext2fs/bmap.c
@@ -14,6 +14,7 @@
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#include <errno.h>
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
@@ -51,10 +52,8 @@
 
 	if (flags & BMAP_SET) {
 		b = *ret_blk;
-#ifdef EXT2FS_ENABLE_SWAPFS
-		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-		    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
-			b = ext2fs_swab32(b);
+#ifdef WORDS_BIGENDIAN
+		b = ext2fs_swab32(b);
 #endif
 		((blk_t *) block_buf)[nr] = b;
 		return io_channel_write_blk(fs->io, ind, 1, block_buf);
@@ -62,10 +61,8 @@
 
 	b = ((blk_t *) block_buf)[nr];
 
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
-		b = ext2fs_swab32(b);
+#ifdef WORDS_BIGENDIAN
+	b = ext2fs_swab32(b);
 #endif
 
 	if (!b && (flags & BMAP_ALLOC)) {
@@ -75,13 +72,11 @@
 		if (retval)
 			return retval;
 
-#ifdef EXT2FS_ENABLE_SWAPFS
-		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-		    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
-			((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
-		else
+#ifdef WORDS_BIGENDIAN
+		((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
+#else
+		((blk_t *) block_buf)[nr] = b;
 #endif
-			((blk_t *) block_buf)[nr] = b;
 
 		retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
 		if (retval)
@@ -134,13 +129,14 @@
 	return retval;
 }
 
-errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
-		      char *block_buf, int bmap_flags, blk_t block,
-		      blk_t *phys_blk)
+errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
+		       char *block_buf, int bmap_flags, blk64_t block,
+		       int *ret_flags, blk64_t *phys_blk)
 {
 	struct ext2_inode inode_buf;
+	ext2_extent_handle_t handle = 0;
 	blk_t addr_per_block;
-	blk_t	b;
+	blk_t	b, blk32;
 	char	*buf = 0;
 	errcode_t	retval = 0;
 	int		blocks_alloc = 0, inode_dirty = 0;
@@ -148,6 +144,9 @@
 	if (!(bmap_flags & BMAP_SET))
 		*phys_blk = 0;
 
+	if (ret_flags)
+		*ret_flags = 0;
+
 	/* Read inode structure if necessary */
 	if (!inode) {
 		retval = ext2fs_read_inode(fs, ino, &inode_buf);
@@ -157,6 +156,37 @@
 	}
 	addr_per_block = (blk_t) fs->blocksize >> 2;
 
+	if (inode->i_flags & EXT4_EXTENTS_FL) {
+		struct ext2fs_extent	extent;
+		unsigned int		offset;
+
+		if (bmap_flags & BMAP_SET) {
+			retval = EXT2_ET_EXTENT_NOT_SUPPORTED;
+			goto done;
+		}
+		retval = ext2fs_extent_open(fs, ino, &handle);
+		if (retval)
+			goto done;
+		retval = ext2fs_extent_goto(handle, block);
+		if (retval) {
+			/* If the extent is not found, return phys_blk = 0 */
+			if (retval == EXT2_ET_EXTENT_NOT_FOUND)
+				retval = 0;
+			goto done;
+		}
+		retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
+		if (retval)
+			goto done;
+		offset = block - extent.e_lblk;
+		if (block >= extent.e_lblk && (offset <= extent.e_len)) {
+			*phys_blk = extent.e_pblk + offset;
+			if (ret_flags && extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
+				*ret_flags |= BMAP_RET_UNINIT;
+		}
+		retval = 0;
+		goto done;
+	}
+
 	if (!block_buf) {
 		retval = ext2fs_get_array(2, fs->blocksize, &buf);
 		if (retval)
@@ -167,10 +197,8 @@
 	if (block < EXT2_NDIR_BLOCKS) {
 		if (bmap_flags & BMAP_SET) {
 			b = *phys_blk;
-#ifdef EXT2FS_ENABLE_SWAPFS
-			if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-			    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
-				b = ext2fs_swab32(b);
+#ifdef WORDS_BIGENDIAN
+			b = ext2fs_swab32(b);
 #endif
 			inode_bmap(inode, block) = b;
 			inode_dirty++;
@@ -193,6 +221,7 @@
 	
 	/* Indirect block */
 	block -= EXT2_NDIR_BLOCKS;
+	blk32 = *phys_blk;
 	if (block < addr_per_block) {
 		b = inode_bmap(inode, EXT2_IND_BLOCK);
 		if (!b) {
@@ -210,7 +239,9 @@
 			blocks_alloc++;
 		}
 		retval = block_ind_bmap(fs, bmap_flags, b, block_buf, 
-					&blocks_alloc, block, phys_blk);
+					&blocks_alloc, block, &blk32);
+		if (retval == 0)
+			*phys_blk = blk32;
 		goto done;
 	}
 	
@@ -233,7 +264,9 @@
 			blocks_alloc++;
 		}
 		retval = block_dind_bmap(fs, bmap_flags, b, block_buf, 
-					 &blocks_alloc, block, phys_blk);
+					 &blocks_alloc, block, &blk32);
+		if (retval == 0)
+			*phys_blk = blk32;
 		goto done;
 	}
 
@@ -255,10 +288,14 @@
 		blocks_alloc++;
 	}
 	retval = block_tind_bmap(fs, bmap_flags, b, block_buf, 
-				 &blocks_alloc, block, phys_blk);
+				 &blocks_alloc, block, &blk32);
+	if (retval == 0)
+		*phys_blk = blk32;
 done:
 	if (buf)
 		ext2fs_free_mem(&buf);
+	if (handle)
+		ext2fs_extent_free(handle);
 	if ((retval == 0) && (blocks_alloc || inode_dirty)) {
 		inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
 		retval = ext2fs_write_inode(fs, ino, inode);
@@ -266,5 +303,19 @@
 	return retval;
 }
 
+errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
+		      char *block_buf, int bmap_flags, blk_t block,
+		      blk_t *phys_blk)
+{
+	errcode_t ret;
+	blk64_t	ret_blk;
 
-
+	ret = ext2fs_bmap2(fs, ino, inode, block_buf, bmap_flags, block,
+			    0, &ret_blk);
+	if (ret)
+		return ret;
+	if (ret_blk >= ((long long) 1 << 32))
+		return EOVERFLOW;
+	*phys_blk = ret_blk;
+	return 0;
+}
diff --git a/lib/ext2fs/check_desc.c b/lib/ext2fs/check_desc.c
index 146f9e5..900b179 100644
--- a/lib/ext2fs/check_desc.c
+++ b/lib/ext2fs/check_desc.c
@@ -33,13 +33,16 @@
 {
 	dgrp_t i;
 	blk_t first_block = fs->super->s_first_data_block;
-	blk_t last_block;
+	blk_t last_block = fs->super->s_blocks_count-1;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
 	for (i = 0; i < fs->group_desc_count; i++) {
-		first_block = ext2fs_group_first_block(fs, i);
-		last_block = ext2fs_group_last_block(fs, i);
+		if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+					       EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+			first_block = ext2fs_group_first_block(fs, i);
+			last_block = ext2fs_group_last_block(fs, i);
+		}
 
 		/*
 		 * Check to make sure block bitmap for group is
diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c
index 88c515a..086c28a 100644
--- a/lib/ext2fs/closefs.c
+++ b/lib/ext2fs/closefs.c
@@ -54,11 +54,10 @@
 {
 	blk_t	group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0;
 	unsigned int meta_bg, meta_bg_size;
-	int	numblocks, has_super;
-	int	old_desc_blocks;
+	blk_t	numblocks, old_desc_blocks;
+	int	has_super;
 
-	group_block = fs->super->s_first_data_block +
-		(group * fs->super->s_blocks_per_group);
+	group_block = ext2fs_group_first_block(fs, group);
 
 	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
 		old_desc_blocks = fs->super->s_first_meta_bg;
@@ -81,7 +80,7 @@
 		super_blk = group_block;
 		numblocks--;
 	}
-	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
+	meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
 	meta_bg = group / meta_bg_size;
 
 	if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
@@ -191,12 +190,11 @@
 	
 	if (sgrp > ((1 << 16) - 1))
 		sgrp = (1 << 16) - 1;
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if (fs->flags & EXT2_FLAG_SWAP_BYTES)
-		super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
-	else
+#ifdef WORDS_BIGENDIAN
+	super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
+#else
+	fs->super->s_block_group_nr = sgrp;
 #endif
-		fs->super->s_block_group_nr = sgrp;
 
 	return io_channel_write_blk(fs->io, group_block, -SUPERBLOCK_SIZE, 
 				    super_shadow);
@@ -205,13 +203,16 @@
 
 errcode_t ext2fs_flush(ext2_filsys fs)
 {
-	dgrp_t		i,j;
+	dgrp_t		i;
 	errcode_t	retval;
 	unsigned long	fs_state;
 	__u32		feature_incompat;
 	struct ext2_super_block *super_shadow = 0;
 	struct ext2_group_desc *group_shadow = 0;
+#ifdef WORDS_BIGENDIAN
 	struct ext2_group_desc *s, *t;
+	dgrp_t		j;
+#endif
 	char	*group_ptr;
 	int	old_desc_blocks;
 	
@@ -222,28 +223,23 @@
 
 	fs->super->s_wtime = fs->now ? fs->now : time(NULL);
 	fs->super->s_block_group_nr = 0;
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
-		retval = EXT2_ET_NO_MEMORY;
-		retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
-		if (retval)
-			goto errout;
-		retval = ext2fs_get_array(fs->blocksize, fs->desc_blocks,
-					&group_shadow);
-		if (retval)
-			goto errout;
-		memset(group_shadow, 0, (size_t) fs->blocksize *
-		       fs->desc_blocks);
-
-		/* swap the group descriptors */
-		for (j=0, s=fs->group_desc, t=group_shadow;
-		     j < fs->group_desc_count; j++, t++, s++) {
-			*t = *s;
-			ext2fs_swap_group_desc(t);
-		}
-	} else {
-		super_shadow = fs->super;
-		group_shadow = fs->group_desc;
+#ifdef WORDS_BIGENDIAN
+	retval = EXT2_ET_NO_MEMORY;
+	retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
+	if (retval)
+		goto errout;
+	retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, 
+				  &group_shadow);
+	if (retval)
+		goto errout;
+	memset(group_shadow, 0, (size_t) fs->blocksize *
+	       fs->desc_blocks);
+	
+	/* swap the group descriptors */
+	for (j=0, s=fs->group_desc, t=group_shadow;
+	     j < fs->group_desc_count; j++, t++, s++) {
+		*t = *s;
+		ext2fs_swap_group_desc(t);
 	}
 #else
 	super_shadow = fs->super;
@@ -257,11 +253,9 @@
 	 */
 	fs->super->s_state &= ~EXT2_VALID_FS;
 	fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
-		*super_shadow = *fs->super;
-		ext2fs_swap_super(super_shadow);
-	}
+#ifdef WORDS_BIGENDIAN
+	*super_shadow = *fs->super;
+	ext2fs_swap_super(super_shadow);
 #endif
 
 	/*
@@ -336,11 +330,9 @@
 	fs->super->s_block_group_nr = 0;
 	fs->super->s_state = fs_state;
 	fs->super->s_feature_incompat = feature_incompat;
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
-		*super_shadow = *fs->super;
-		ext2fs_swap_super(super_shadow);
-	}
+#ifdef WORDS_BIGENDIAN
+	*super_shadow = *fs->super;
+	ext2fs_swap_super(super_shadow);
 #endif
 
 	retval = io_channel_flush(fs->io);
@@ -353,12 +345,12 @@
 	retval = io_channel_flush(fs->io);
 errout:
 	fs->super->s_state = fs_state;
-	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
-		if (super_shadow)
-			ext2fs_free_mem(&super_shadow);
-		if (group_shadow)
-			ext2fs_free_mem(&group_shadow);
-	}
+#ifdef WORDS_BIGENDIAN
+	if (super_shadow)
+		ext2fs_free_mem(&super_shadow);
+	if (group_shadow)
+		ext2fs_free_mem(&group_shadow);
+#endif
 	return retval;
 }
 
diff --git a/lib/ext2fs/cmp_bitmaps.c b/lib/ext2fs/cmp_bitmaps.c
deleted file mode 100644
index 51cc3d0..0000000
--- a/lib/ext2fs/cmp_bitmaps.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * cmp_bitmaps.c --- routines to compare inode and block bitmaps.
- *
- * Copyright (C) 1995 Theodore Ts'o.
- *
- * %Begin-Header%
- * This file may be redistributed under the terms of the GNU Public
- * License.
- * %End-Header%
- */
-
-#include <stdio.h>
-#include <string.h>
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <fcntl.h>
-#include <time.h>
-#if HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#include "ext2_fs.h"
-#include "ext2fs.h"
-
-errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
-				      ext2fs_block_bitmap bm2)
-{
-	blk_t	i;
-	
-	EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_BLOCK_BITMAP);
-	EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_BLOCK_BITMAP);
-
-	if ((bm1->start != bm2->start) ||
-	    (bm1->end != bm2->end) ||
-	    (memcmp(bm1->bitmap, bm2->bitmap,
-		    (size_t) (bm1->end - bm1->start)/8)))
-		return EXT2_ET_NEQ_BLOCK_BITMAP;
-
-	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
-		if (ext2fs_fast_test_block_bitmap(bm1, i) !=
-		    ext2fs_fast_test_block_bitmap(bm2, i))
-			return EXT2_ET_NEQ_BLOCK_BITMAP;
-
-	return 0;
-}
-
-errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
-				      ext2fs_inode_bitmap bm2)
-{
-	ext2_ino_t	i;
-	
-	EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_INODE_BITMAP);
-	EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_INODE_BITMAP);
-
-	if ((bm1->start != bm2->start) ||
-	    (bm1->end != bm2->end) ||
-	    (memcmp(bm1->bitmap, bm2->bitmap,
-		    (size_t) (bm1->end - bm1->start)/8)))
-		return EXT2_ET_NEQ_INODE_BITMAP;
-
-	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
-		if (ext2fs_fast_test_inode_bitmap(bm1, i) !=
-		    ext2fs_fast_test_inode_bitmap(bm2, i))
-			return EXT2_ET_NEQ_INODE_BITMAP;
-
-	return 0;
-}
-
diff --git a/lib/ext2fs/crc16.c b/lib/ext2fs/crc16.c
new file mode 100644
index 0000000..1b2b8a1
--- /dev/null
+++ b/lib/ext2fs/crc16.c
@@ -0,0 +1,61 @@
+/*
+ *      crc16.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include "crc16.h"
+
+/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */
+__u16 const crc16_table[256] = {
+	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+/**
+ * Compute the CRC-16 for the data buffer
+ *
+ * @param crc     previous CRC value
+ * @param buffer  data pointer
+ * @param len     number of bytes in the buffer
+ * @return        the updated CRC value
+ */
+crc16_t crc16(crc16_t crc, const void *buffer, unsigned int len)
+{
+	const unsigned char *cp = buffer;
+
+	while (len--)
+		crc = crc16_byte(crc, *cp++);
+	return crc;
+}
diff --git a/lib/ext2fs/crc16.h b/lib/ext2fs/crc16.h
new file mode 100644
index 0000000..ab3f094
--- /dev/null
+++ b/lib/ext2fs/crc16.h
@@ -0,0 +1,45 @@
+/*
+ *	crc16.h - CRC-16 routine
+ *
+ * Implements the standard CRC-16:
+ *   Width 16
+ *   Poly  0x8005 (x16 + x15 + x2 + 1)
+ *   Init  0
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#ifndef __CRC16_H
+#define __CRC16_H
+
+#include <ext2fs/ext2_types.h>
+
+extern __u16 const crc16_table[256];
+
+#ifdef WORDS_BIGENDIAN
+/* for an unknown reason, PPC treats __u16 as signed and keeps doing sign
+ * extension on the value.  Instead, use only the low 16 bits of an
+ * unsigned int for holding the CRC value to avoid this.
+ */
+typedef unsigned crc16_t;
+
+static inline crc16_t crc16_byte(crc16_t crc, const unsigned char data)
+{
+	return (((crc >> 8) & 0xffU) ^ crc16_table[(crc ^ data) & 0xffU]) &
+		0x0000ffffU;
+}
+#else
+typedef __u16 crc16_t;
+
+static inline crc16_t crc16_byte(crc16_t crc, const unsigned char data)
+{
+	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
+}
+#endif
+
+extern crc16_t crc16(crc16_t crc, const void *buffer, unsigned int len);
+
+#endif /* __CRC16_H */
diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
new file mode 100644
index 0000000..0774e00
--- /dev/null
+++ b/lib/ext2fs/csum.c
@@ -0,0 +1,160 @@
+/*
+ * csum.c --- checksumming of ext3 structures
+ *
+ * Copyright (C) 2006 Cluster File Systems, Inc.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "crc16.h"
+#include <assert.h>
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+STATIC __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
+{
+	__u16 crc = 0;
+	struct ext2_group_desc *desc;
+
+	desc = &fs->group_desc[group];
+
+	if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+		int offset = offsetof(struct ext2_group_desc, bg_checksum);
+
+#ifdef WORDS_BIGENDIAN
+		struct ext2_group_desc swabdesc = *desc;
+
+		/* Have to swab back to little-endian to do the checksum */
+		ext2fs_swap_group_desc(&swabdesc);
+		desc = &swabdesc;
+
+		group = ext2fs_swab32(group);
+#endif
+		crc = crc16(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid));
+		crc = crc16(crc, &group, sizeof(group));
+		crc = crc16(crc, desc, offset);
+		offset += sizeof(desc->bg_checksum); /* skip checksum */
+		assert(offset == sizeof(*desc));
+		/* for checksum of struct ext4_group_desc do the rest...*/
+		if (offset < fs->super->s_desc_size) {
+			crc = crc16(crc, (char *)desc + offset,
+				    fs->super->s_desc_size - offset);
+		}
+	}
+
+	return crc;
+}
+
+int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group)
+{
+	if (fs->group_desc[group].bg_checksum != 
+	    ext2fs_group_desc_csum(fs, group))
+		return 0;
+
+	return 1;
+}
+
+void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group)
+{
+	fs->group_desc[group].bg_checksum = ext2fs_group_desc_csum(fs, group);
+}
+
+static __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap,
+				   __u32 inodes_per_grp, dgrp_t grp_no)
+{
+	ext2_ino_t i, start_ino, end_ino;
+
+	start_ino = grp_no * inodes_per_grp + 1;
+	end_ino = start_ino + inodes_per_grp - 1;
+
+	for (i = end_ino; i >= start_ino; i--) {
+		if (ext2fs_fast_test_inode_bitmap(bitmap, i))
+			return i - start_ino + 1;
+	}
+	return inodes_per_grp;
+}
+
+/* update the bitmap flags, set the itable high watermark, and calculate
+ * checksums for the group descriptors */
+errcode_t ext2fs_set_gdt_csum(ext2_filsys fs)
+{
+	struct ext2_super_block *sb = fs->super;
+	struct ext2_group_desc *bg = fs->group_desc;
+	int blks, csum_flag, dirty = 0;
+	dgrp_t i;
+
+	if (!fs->inode_map)
+		return EXT2_ET_NO_INODE_BITMAP;
+
+	csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					       EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+	if (!EXT2_HAS_COMPAT_FEATURE(fs->super,
+				     EXT2_FEATURE_COMPAT_LAZY_BG) && !csum_flag)
+		return 0;
+
+	for (i = 0; i < fs->group_desc_count; i++, bg++) {
+		int old_csum = bg->bg_checksum;
+		int old_unused = bg->bg_itable_unused;
+		int old_flags = bg->bg_flags;
+
+		/* Even if it wasn't zeroed, by the time this function is
+		 * called by e2fsck we have already scanned and corrected
+		 * the whole inode table so we may as well not overwrite it.
+		 * This is just a hint to the kernel that it could do lazy
+		 * zeroing of the inode table if mke2fs didn't do it, to help
+		 * out if we need to do a full itable scan sometime later. */
+		if (!(bg->bg_flags & (EXT2_BG_INODE_UNINIT |
+				      EXT2_BG_INODE_ZEROED)))
+			fs->group_desc[i].bg_flags |= EXT2_BG_INODE_ZEROED;
+
+		if (bg->bg_free_inodes_count == sb->s_inodes_per_group &&
+		    i > 0 && (i < fs->group_desc_count - 1 || csum_flag)) {
+			if (!(bg->bg_flags & EXT2_BG_INODE_UNINIT))
+				bg->bg_flags |= EXT2_BG_INODE_UNINIT;
+
+			if (csum_flag)
+				bg->bg_itable_unused = sb->s_inodes_per_group;
+		} else if (csum_flag) {
+			bg->bg_flags &= ~EXT2_BG_INODE_UNINIT;
+			bg->bg_itable_unused = sb->s_inodes_per_group -
+				find_last_inode_ingrp(fs->inode_map,
+						      sb->s_inodes_per_group,i);
+		}
+
+		/* skip first and last groups, or groups with GDT backups
+		 * because the resize inode has blocks allocated in them. */
+		if (i == 0 || i == fs->group_desc_count - 1 ||
+		    (ext2fs_bg_has_super(fs, i) && sb->s_reserved_gdt_blocks))
+			goto checksum;
+
+		blks = ext2fs_super_and_bgd_loc(fs, i, 0, 0, 0, 0);
+		if (bg->bg_free_blocks_count == blks &&
+		    bg->bg_flags & EXT2_BG_INODE_UNINIT &&
+		    !(bg->bg_flags & EXT2_BG_BLOCK_UNINIT))
+			bg->bg_flags |= EXT2_BG_BLOCK_UNINIT;
+checksum:
+		ext2fs_group_desc_csum_set(fs, i);
+		if (old_flags != bg->bg_flags)
+			dirty = 1;
+		if (old_unused != bg->bg_itable_unused)
+			dirty = 1;
+		if (old_csum != bg->bg_checksum)
+			dirty = 1;
+	}
+	if (dirty)
+		ext2fs_mark_super_dirty(fs);
+	return 0;
+}
diff --git a/lib/ext2fs/dblist.c b/lib/ext2fs/dblist.c
index 3bf63a0..0067cae 100644
--- a/lib/ext2fs/dblist.c
+++ b/lib/ext2fs/dblist.c
@@ -263,8 +263,6 @@
 errcode_t ext2fs_dblist_get_last(ext2_dblist dblist, 
 				 struct ext2_db_entry **entry)
 {
-	errcode_t		retval;
-
 	EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
 
 	if (dblist->count == 0)
diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c
index 003c0a3..3e7b7b0 100644
--- a/lib/ext2fs/dir_iterate.c
+++ b/lib/ext2fs/dir_iterate.c
@@ -78,7 +78,7 @@
 	ctx.func = func;
 	ctx.priv_data = priv_data;
 	ctx.errcode = 0;
-	retval = ext2fs_block_iterate2(fs, dir, 0, 0,
+	retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_READ_ONLY, 0,
 				       ext2fs_process_dir_block, &ctx);
 	if (!block_buf)
 		ext2fs_free_mem(&ctx.buf);
diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c
index ebfc72c..fb20fa0 100644
--- a/lib/ext2fs/dirblock.c
+++ b/lib/ext2fs/dirblock.c
@@ -25,26 +25,21 @@
 	errcode_t	retval;
 	char		*p, *end;
 	struct ext2_dir_entry *dirent;
-	unsigned int	name_len, rec_len, do_swap;
+	unsigned int	name_len, rec_len;
 	
 
  	retval = io_channel_read_blk(fs->io, block, 1, buf);
 	if (retval)
 		return retval;
-#ifdef EXT2FS_ENABLE_SWAPFS
-	do_swap = (fs->flags & (EXT2_FLAG_SWAP_BYTES|
-				EXT2_FLAG_SWAP_BYTES_READ)) != 0;
-#endif
+
 	p = (char *) buf;
 	end = (char *) buf + fs->blocksize;
 	while (p < end-8) {
 		dirent = (struct ext2_dir_entry *) p;
-#ifdef EXT2FS_ENABLE_SWAPFS
-		if (do_swap) {
-			dirent->inode = ext2fs_swab32(dirent->inode);
-			dirent->rec_len = ext2fs_swab16(dirent->rec_len);
-			dirent->name_len = ext2fs_swab16(dirent->name_len);
-		}
+#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
@@ -73,22 +68,12 @@
 errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
 				  void *inbuf, int flags EXT2FS_ATTR((unused)))
 {
-#ifdef EXT2FS_ENABLE_SWAPFS
-	int		do_swap = 0;
+#ifdef WORDS_BIGENDIAN
 	errcode_t	retval;
 	char		*p, *end;
 	char		*buf = 0;
 	struct ext2_dir_entry *dirent;
 
-	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
-		do_swap = 1;
-
-#ifndef WORDS_BIGENDIAN
-	if (!do_swap)
-		return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
-#endif
-
 	retval = ext2fs_get_mem(fs->blocksize, &buf);
 	if (retval)
 		return retval;
@@ -103,15 +88,12 @@
 			return (EXT2_ET_DIR_CORRUPTED);
 		}
 		p += dirent->rec_len;
-		if (do_swap) {
-			dirent->inode = ext2fs_swab32(dirent->inode);
-			dirent->rec_len = ext2fs_swab16(dirent->rec_len);
-			dirent->name_len = ext2fs_swab16(dirent->name_len);
-		}
-#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);
+
 		if (flags & EXT2_DIRBLOCK_V2_STRUCT)
 			dirent->name_len = ext2fs_swab16(dirent->name_len);
-#endif
 	}
  	retval = io_channel_write_blk(fs->io, block, 1, buf);
 	ext2fs_free_mem(&buf);
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 7451242..9047a8f 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -62,8 +62,8 @@
 ec	EXT2_ET_MAGIC_INODE_IO_CHANNEL,
 	"Wrong magic number for inode io_channel structure"
 
-ec	EXT2_ET_MAGIC_RESERVED_9,
-	"Wrong magic number --- RESERVED_9"
+ec	EXT2_ET_MAGIC_EXTENT_HANDLE,
+	"Wrong magic number for ext4 extent handle"
 
 ec	EXT2_ET_BAD_MAGIC,
 	"Bad magic number in super-block"
@@ -329,5 +329,82 @@
 ec	EXT2_ET_DBLIST_EMPTY,
 	"Ext2fs directory block list is empty"
 
-	end
+ec	EXT2_ET_RO_BLOCK_ITERATE,
+	"Attempt to modify a block mapping via a read-only block iterator"
 
+ec	EXT2_ET_MAGIC_EXTENT_PATH,
+	"Wrong magic number for ext4 extent saved path"
+
+ec	EXT2_ET_MAGIC_RESERVED_10,
+	"Wrong magic number --- RESERVED_10"
+
+ec	EXT2_ET_MAGIC_RESERVED_11,
+	"Wrong magic number --- RESERVED_11"
+
+ec	EXT2_ET_MAGIC_RESERVED_12,
+	"Wrong magic number --- RESERVED_12"
+
+ec	EXT2_ET_MAGIC_RESERVED_13,
+	"Wrong magic number --- RESERVED_13"
+
+ec	EXT2_ET_MAGIC_RESERVED_14,
+	"Wrong magic number --- RESERVED_14"
+
+ec	EXT2_ET_MAGIC_RESERVED_15,
+	"Wrong magic number --- RESERVED_15"
+
+ec	EXT2_ET_MAGIC_RESERVED_16,
+	"Wrong magic number --- RESERVED_16"
+
+ec	EXT2_ET_MAGIC_RESERVED_17,
+	"Wrong magic number --- RESERVED_17"
+
+ec	EXT2_ET_MAGIC_RESERVED_18,
+	"Wrong magic number --- RESERVED_18"
+
+ec	EXT2_ET_MAGIC_RESERVED_19,
+	"Wrong magic number --- RESERVED_19"
+
+ec	EXT2_ET_EXTENT_HEADER_BAD,
+	"Corrupt extent header"
+
+ec	EXT2_ET_EXTENT_INDEX_BAD,
+	"Corrupt extent index"
+
+ec	EXT2_ET_EXTENT_LEAF_BAD,
+	"Corrupt extent"
+
+ec	EXT2_ET_EXTENT_NO_SPACE,
+	"No free space in extent map"
+
+ec	EXT2_ET_INODE_NOT_EXTENT,
+	"Inode does not use extents"
+
+ec	EXT2_ET_EXTENT_NO_NEXT,
+	"No 'next' extent"
+
+ec	EXT2_ET_EXTENT_NO_PREV,
+	"No 'previous' extent"
+
+ec	EXT2_ET_EXTENT_NO_UP,
+	"No 'up' extent"
+
+ec	EXT2_ET_EXTENT_NO_DOWN,
+	"No 'down' extent"
+
+ec	EXT2_ET_NO_CURRENT_NODE,
+	"No current node"
+
+ec	EXT2_ET_OP_NOT_SUPPORTED,
+	"Ext2fs operation not supported"
+
+ec	EXT2_ET_CANT_INSERT_EXTENT,
+	"No room to insert extent in node"
+
+ec	EXT2_ET_EXTENT_NOT_FOUND,
+	"Extent not found"
+
+ec	EXT2_ET_EXTENT_NOT_SUPPORTED,
+	"Operation not supported for inodes containing extents"
+
+	end
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index be8d773..444211d 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -173,6 +173,7 @@
 
 #define EXT2_BG_INODE_UNINIT	0x0001 /* Inode table/bitmap not initialized */
 #define EXT2_BG_BLOCK_UNINIT	0x0002 /* Block bitmap not initialized */
+#define EXT2_BG_INODE_ZEROED	0x0004 /* On-disk itable initialized to zero */
 
 /*
  * Data structures used by the directory indexing feature
@@ -217,6 +218,13 @@
 /*
  * Macro-instructions used to manage group descriptors
  */
+#define EXT2_MIN_DESC_SIZE             32
+#define EXT2_MIN_DESC_SIZE_64BIT       64
+#define EXT2_MAX_DESC_SIZE             EXT2_MIN_BLOCK_SIZE
+#define EXT2_DESC_SIZE(s)                                                \
+       ((EXT2_SB(s)->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) ? \
+	(s)->s_desc_size : EXT2_MIN_DESC_SIZE)
+
 #define EXT2_BLOCKS_PER_GROUP(s)	(EXT2_SB(s)->s_blocks_per_group)
 #define EXT2_INODES_PER_GROUP(s)	(EXT2_SB(s)->s_inodes_per_group)
 #define EXT2_INODES_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
@@ -227,7 +235,7 @@
 #define EXT2_DESC_PER_BLOCK(s)		(EXT2_SB(s)->s_desc_per_block)
 #define EXT2_DESC_PER_BLOCK_BITS(s)	(EXT2_SB(s)->s_desc_per_block_bits)
 #else
-#define EXT2_DESC_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+#define EXT2_DESC_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s))
 #endif
 
 /*
@@ -319,9 +327,6 @@
 		struct {
 			__u32  h_i_translator;
 		} hurd1;
-		struct {
-			__u32  m_i_reserved1;
-		} masix1;
 	} osd1;				/* OS dependent 1 */
 	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
 	__u32	i_generation;	/* File version (for NFS) */
@@ -344,12 +349,6 @@
 			__u16	h_i_gid_high;
 			__u32	h_i_author;
 		} hurd2;
-		struct {
-			__u8	m_i_frag;	/* Fragment number */
-			__u8	m_i_fsize;	/* Fragment size */
-			__u16	m_pad1;
-			__u32	m_i_reserved2[2];
-		} masix2;
 	} osd2;				/* OS dependent 2 */
 };
 
@@ -375,9 +374,6 @@
 		struct {
 			__u32  h_i_translator;
 		} hurd1;
-		struct {
-			__u32  m_i_reserved1;
-		} masix1;
 	} osd1;				/* OS dependent 1 */
 	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
 	__u32	i_generation;	/* File version (for NFS) */
@@ -400,12 +396,6 @@
 			__u16	h_i_gid_high;
 			__u32	h_i_author;
 		} hurd2;
-		struct {
-			__u8	m_i_frag;	/* Fragment number */
-			__u8	m_i_fsize;	/* Fragment size */
-			__u16	m_pad1;
-			__u32	m_i_reserved2[2];
-		} masix2;
 	} osd2;				/* OS dependent 2 */
 	__u16	i_extra_isize;
 	__u16	i_pad1;
@@ -437,30 +427,13 @@
 #define i_gid_high	osd2.hurd2.h_i_gid_high
 #define i_author	osd2.hurd2.h_i_author
 
-#else
-#if defined(__masix__)
-
-#define i_reserved1	osd1.masix1.m_i_reserved1
-#define i_frag		osd2.masix2.m_i_frag
-#define i_fsize		osd2.masix2.m_i_fsize
-#define i_reserved2	osd2.masix2.m_i_reserved2
-
-#endif  /* __masix__ */
 #endif  /* __GNU__ */
 #endif	/* defined(__KERNEL__) || defined(__linux__) */
 
-#if defined(__masix__)
-#define inode_uid(inode)	((inode).i_uid)
-#define inode_gid(inode)	((inode).i_gid)
-#define ext2fs_set_i_uid_high(inode,x) (x)
-#define ext2fs_set_i_gid_high(inode,x) (x)
-
-#else
 #define inode_uid(inode)	((inode).i_uid | (inode).osd2.linux2.l_i_uid_high << 16)
 #define inode_gid(inode)	((inode).i_gid | (inode).osd2.linux2.l_i_gid_high << 16)
 #define ext2fs_set_i_uid_high(inode,x) ((inode).osd2.linux2.l_i_uid_high = (x))
 #define ext2fs_set_i_gid_high(inode,x) ((inode).osd2.linux2.l_i_gid_high = (x))
-#endif
 
 /*
  * File system states
@@ -598,7 +571,7 @@
  */
 #define EXT2_OS_LINUX		0
 #define EXT2_OS_HURD		1
-#define EXT2_OS_MASIX		2
+#define EXT2_OBSO_OS_MASIX	2
 #define EXT2_OS_FREEBSD		3
 #define EXT2_OS_LITES		4
 
@@ -653,12 +626,14 @@
 #define EXT3_FEATURE_INCOMPAT_EXTENTS		0x0040
 #define EXT4_FEATURE_INCOMPAT_64BIT		0x0080
 #define EXT4_FEATURE_INCOMPAT_MMP		0x0100
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG		0x0200
 
 
 #define EXT2_FEATURE_COMPAT_SUPP	0
 #define EXT2_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE)
 #define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
 					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
 					 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
 
 /*
diff --git a/lib/ext2fs/ext2_io.h b/lib/ext2fs/ext2_io.h
index eada278..c236095 100644
--- a/lib/ext2fs/ext2_io.h
+++ b/lib/ext2fs/ext2_io.h
@@ -26,6 +26,7 @@
 
 typedef struct struct_io_manager *io_manager;
 typedef struct struct_io_channel *io_channel;
+typedef struct struct_io_stats *io_stats;
 
 #define CHANNEL_FLAGS_WRITETHROUGH	0x01
 
@@ -55,6 +56,13 @@
 	void		*app_data;
 };
 
+struct struct_io_stats {
+	int			num_fields;
+	int			reserved;
+	unsigned long long	bytes_read;
+	unsigned long long	bytes_written;
+};
+
 struct struct_io_manager {
 	errcode_t magic;
 	const char *name;
@@ -70,7 +78,12 @@
 				int count, const void *data);
 	errcode_t (*set_option)(io_channel channel, const char *option, 
 				const char *arg);
-	int		reserved[14];
+	errcode_t (*get_stats)(io_channel channel, io_stats *io_stats);
+	errcode_t (*read_blk64)(io_channel channel, unsigned long long block,
+					int count, void *data);
+	errcode_t (*write_blk64)(io_channel channel, unsigned long long block,
+					int count, const void *data);
+	int		reserved[16];
 };
 
 #define IO_FLAG_RW		0x0001
@@ -82,7 +95,9 @@
 #define io_channel_close(c) 		((c)->manager->close((c)))
 #define io_channel_set_blksize(c,s)	((c)->manager->set_blksize((c),s))
 #define io_channel_read_blk(c,b,n,d)	((c)->manager->read_blk((c),b,n,d))
+#define io_channel_read_blk64(c,b,n,d)	((c)->manager->read_blk64((c),b,n,d))
 #define io_channel_write_blk(c,b,n,d)	((c)->manager->write_blk((c),b,n,d))
+#define io_channel_write_blk64(c,b,n,d) ((c)->manager->write_blk64((c),b,n,d))
 #define io_channel_flush(c) 		((c)->manager->flush((c)))
 #define io_channel_bumpcount(c)		((c)->refcount++)
 	
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index d098961..1a7cb86 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -30,15 +30,6 @@
 #endif
 
 /*
- * Build in support for byte-swapping filesystems if we the feature
- * has been configured or if we're being built on a CPU architecture
- * with a non-native byte order.
- */
-#if defined(ENABLE_SWAPFS) || defined(WORDS_BIGENDIAN)
-#define EXT2FS_ENABLE_SWAPFS
-#endif
-
-/*
  * Where the master copy of the superblock is located, and how big
  * superblocks are supposed to be.  We define SUPERBLOCK_SIZE because
  * the size of the superblock structure is not necessarily trustworthy
@@ -74,6 +65,7 @@
 
 typedef __u32		ext2_ino_t;
 typedef __u32		blk_t;
+typedef __u64		blk64_t;
 typedef __u32		dgrp_t;
 typedef __u32		ext2_off_t;
 typedef __s64		e2_blkcnt_t;
@@ -83,10 +75,12 @@
 #include "com_err.h"
 #include "ext2_io.h"
 #include "ext2_err.h"
+#include "ext2_ext_attr.h"
 #else
 #include <et/com_err.h>
 #include <ext2fs/ext2_io.h>
 #include <ext2fs/ext2_err.h>
+#include <ext2fs/ext2_ext_attr.h>
 #endif
 
 /*
@@ -100,17 +94,6 @@
 
 typedef struct struct_ext2_filsys *ext2_filsys;
 
-struct ext2fs_struct_generic_bitmap {
-	errcode_t	magic;
-	ext2_filsys 	fs;
-	__u32		start, end;
-	__u32		real_end;
-	char	*	description;
-	char	*	bitmap;
-	errcode_t	base_error_code;
-	__u32		reserved[7];
-};
-
 #define EXT2FS_MARK_ERROR 	0
 #define EXT2FS_UNMARK_ERROR 	1
 #define EXT2FS_TEST_ERROR	2
@@ -279,6 +262,9 @@
  * BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be
  * called for data blocks only.
  *
+ * BLOCK_FLAG_READ_ONLY is a promise by the caller that it will not 
+ * modify returned block number.
+ *
  * BLOCK_FLAG_NO_LARGE is for internal use only.  It informs
  * ext2fs_block_iterate2 that large files won't be accepted.
  */
@@ -286,6 +272,7 @@
 #define BLOCK_FLAG_HOLE		1
 #define BLOCK_FLAG_DEPTH_TRAVERSE	2
 #define BLOCK_FLAG_DATA_ONLY	4
+#define BLOCK_FLAG_READ_ONLY	8
 
 #define BLOCK_FLAG_NO_LARGE	0x1000
 
@@ -306,6 +293,65 @@
 #endif
 
 /*
+ * Generic (non-filesystem layout specific) extents structure
+ */
+
+#define EXT2_EXTENT_FLAGS_LEAF		0x0001
+#define EXT2_EXTENT_FLAGS_UNINIT	0x0002
+#define EXT2_EXTENT_FLAGS_SECOND_VISIT	0x0004
+
+struct ext2fs_extent {
+	blk64_t	e_pblk;		/* first physical block */
+	blk64_t	e_lblk;		/* first logical block extent covers */
+	__u32	e_len;		/* number of blocks covered by extent */
+	__u32	e_flags;	/* extent flags */
+};
+
+typedef struct ext2_extent_handle *ext2_extent_handle_t;
+typedef struct ext2_extent_path *ext2_extent_path_t;
+
+/*
+ * Flags used by ext2fs_extent_get()
+ */
+#define EXT2_EXTENT_CURRENT	0x0000
+#define EXT2_EXTENT_MOVE_MASK	0x000F
+#define EXT2_EXTENT_ROOT	0x0001
+#define EXT2_EXTENT_LAST_LEAF	0x0002
+#define EXT2_EXTENT_FIRST_SIB	0x0003
+#define EXT2_EXTENT_LAST_SIB	0x0004
+#define EXT2_EXTENT_NEXT_SIB	0x0005
+#define EXT2_EXTENT_PREV_SIB	0x0006
+#define EXT2_EXTENT_NEXT_LEAF	0x0007
+#define EXT2_EXTENT_PREV_LEAF	0x0008
+#define EXT2_EXTENT_NEXT	0x0009
+#define EXT2_EXTENT_PREV	0x000A
+#define EXT2_EXTENT_UP		0x000B
+#define EXT2_EXTENT_DOWN	0x000C
+#define EXT2_EXTENT_DOWN_AND_LAST 0x000D
+
+/*
+ * Flags used by ext2fs_extent_insert()
+ */
+
+#define EXT2_EXTENT_INSERT_AFTER  0x0001
+
+/*
+ * Data structure returned by ext2fs_extent_get_info()
+ */
+struct ext2_extent_info {
+	int		curr_entry;
+	int		curr_level;
+	int		num_entries;
+	int		max_entries;
+	int		max_depth;
+	int		bytes_avail;
+	blk64_t		max_lblk;
+	blk64_t		max_pblk;
+	__u32		max_len;
+	__u32		max_uninit_len;
+};
+
+/*
  * Flags for directory block reading and writing functions
  */
 #define EXT2_DIRBLOCK_V2_STRUCT	0x0001
@@ -411,6 +457,11 @@
 #define BMAP_SET	0x0002
 
 /*
+ * Returned flags from ext2fs_bmap
+ */
+#define BMAP_RET_UNINIT	0x0001
+
+/*
  * Flags for imager.c functions
  */
 #define IMAGER_FLAG_INODEMAP	1
@@ -427,7 +478,7 @@
 /*
  * For ext2 compression support
  */
-#define EXT2FS_COMPRESSED_BLKADDR ((blk_t) 0xffffffff)
+#define EXT2FS_COMPRESSED_BLKADDR ((blk_t) -1)
 #define HOLE_BLKADDR(_b) ((_b) == 0 || (_b) == EXT2FS_COMPRESSED_BLKADDR)
 
 /*
@@ -453,15 +504,21 @@
 					 EXT2_FEATURE_INCOMPAT_COMPRESSION|\
 					 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
 					 EXT2_FEATURE_INCOMPAT_META_BG|\
-					 EXT3_FEATURE_INCOMPAT_RECOVER)
+					 EXT3_FEATURE_INCOMPAT_RECOVER|\
+					 EXT3_FEATURE_INCOMPAT_EXTENTS|\
+					 EXT4_FEATURE_INCOMPAT_FLEX_BG)
 #else
 #define EXT2_LIB_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE|\
 					 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
 					 EXT2_FEATURE_INCOMPAT_META_BG|\
-					 EXT3_FEATURE_INCOMPAT_RECOVER)
+					 EXT3_FEATURE_INCOMPAT_RECOVER|\
+					 EXT3_FEATURE_INCOMPAT_EXTENTS|\
+					 EXT4_FEATURE_INCOMPAT_FLEX_BG)
 #endif
 #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
-					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
+					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\
+					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\
+					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
 
 /*
  * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed
@@ -470,7 +527,6 @@
 #define EXT2_LIB_SOFTSUPP_INCOMPAT	(EXT3_FEATURE_INCOMPAT_EXTENTS)
 #define EXT2_LIB_SOFTSUPP_RO_COMPAT	(EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
 					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\
-					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\
 					 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)
 
 /*
@@ -552,15 +608,14 @@
 					ext2_badblocks_list bb_list);
 
 /* bitmaps.c */
+extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
+extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
+extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
+				    ext2fs_generic_bitmap *dest);
 extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs);
 extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs);
 extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs);
 extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs);
-extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
-						__u32 end,
-						__u32 real_end,
-						const char *descr,
-						ext2fs_generic_bitmap *ret);
 extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
 					      const char *descr,
 					      ext2fs_block_bitmap *ret);
@@ -575,6 +630,27 @@
 extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap);
 extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs);
 extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs);
+extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
+					    ext2fs_inode_bitmap bmap);
+extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
+					    ext2fs_block_bitmap bmap);
+extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
+					     ext2fs_block_bitmap bm2);
+extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
+					     ext2fs_inode_bitmap bm2);
+extern errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap,
+					ext2_ino_t start, unsigned int num,
+					void *in);
+extern errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap,
+					ext2_ino_t start, unsigned int num,
+					void *out);
+extern errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap,
+					blk_t start, unsigned int num,
+					void *in);
+extern errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap,
+					blk_t start, unsigned int num,
+					void *out);
+
 
 /* block.c */
 extern errcode_t ext2fs_block_iterate(ext2_filsys fs,
@@ -603,7 +679,10 @@
 			     struct ext2_inode *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,
+			      char *block_buf, int bmap_flags, blk64_t block,
+			      int *ret_flags, blk64_t *phys_blk);
 
 #if 0
 /* bmove.c */
@@ -628,11 +707,10 @@
 				    int *ret_meta_bg);
 extern void ext2fs_update_dynamic_rev(ext2_filsys fs);
 
-/* cmp_bitmaps.c */
-extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
-					     ext2fs_block_bitmap bm2);
-extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
-					     ext2fs_inode_bitmap bm2);
+/* 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);
+extern errcode_t ext2fs_set_gdt_csum(ext2_filsys fs);
 
 /* dblist.c */
 
@@ -718,6 +796,8 @@
 extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
 
 /* ext_attr.c */
+extern __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry,
+					void *data);
 extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
 extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
 				       void *buf);
@@ -725,6 +805,23 @@
 					   char *block_buf,
 					   int adjust, __u32 *newcount);
 
+/* extent.c */
+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 void ext2fs_extent_free(ext2_extent_handle_t handle);
+extern errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
+				   int flags, struct ext2fs_extent *extent);
+extern errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle, int flags,
+				       struct ext2fs_extent *extent);
+extern errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
+				      struct ext2fs_extent *extent);
+extern errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags);
+extern errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle,
+					struct ext2_extent_info *info);
+extern errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
+				    blk64_t blk);
+
 /* fileio.c */
 extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
 				   struct ext2_inode *inode,
@@ -754,13 +851,47 @@
 
 /* freefs.c */
 extern void ext2fs_free(ext2_filsys fs);
-extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap);
-extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
-extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
 extern void ext2fs_free_dblist(ext2_dblist dblist);
 extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb);
 extern void ext2fs_u32_list_free(ext2_u32_list bb);
 
+/* gen_bitmap.c */
+extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap);
+extern errcode_t ext2fs_make_generic_bitmap(errcode_t magic, ext2_filsys fs, 
+					    __u32 start, __u32 end, 
+					    __u32 real_end,
+					    const char *descr, char *init_map,
+					    ext2fs_generic_bitmap *ret);
+extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
+						__u32 end,
+						__u32 real_end,
+						const char *descr,
+						ext2fs_generic_bitmap *ret);
+extern errcode_t ext2fs_copy_generic_bitmap(ext2fs_generic_bitmap src,
+					    ext2fs_generic_bitmap *dest);
+extern void ext2fs_clear_generic_bitmap(ext2fs_generic_bitmap bitmap);
+extern errcode_t ext2fs_fudge_generic_bitmap_end(ext2fs_inode_bitmap bitmap,
+						 errcode_t magic, 
+						 errcode_t neq,
+						 ext2_ino_t end, 
+						 ext2_ino_t *oend);
+extern void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap map);
+extern errcode_t ext2fs_resize_generic_bitmap(errcode_t magic,
+					      __u32 new_end,
+					      __u32 new_real_end,
+					      ext2fs_generic_bitmap bmap);
+extern errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq,
+					       ext2fs_generic_bitmap bm1,
+					       ext2fs_generic_bitmap bm2);
+extern errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap,
+						 errcode_t magic,
+						 __u32 start, __u32 num,
+						 void *out);
+extern errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap,
+						 errcode_t magic,
+						 __u32 start, __u32 num,
+						 void *in);
+
 /* getsize.c */
 extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,
 					blk_t *retblocks);
@@ -931,20 +1062,13 @@
 /* res_gdt.c */
 extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
 
-/* rs_bitmap.c */
-extern errcode_t ext2fs_resize_generic_bitmap(__u32 new_end,
-					      __u32 new_real_end,
-					      ext2fs_generic_bitmap bmap);
-extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
-					    ext2fs_inode_bitmap bmap);
-extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
-					    ext2fs_block_bitmap bmap);
-extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
-				    ext2fs_generic_bitmap *dest);
-
 /* swapfs.c */
 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,
+					struct ext2_ext_attr_header *from_hdr);
+extern void ext2fs_swap_ext_attr_entry(struct ext2_ext_attr_entry *to_entry,
+				       struct ext2_ext_attr_entry *from_entry);
 extern void ext2fs_swap_super(struct ext2_super_block * super);
 extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp);
 extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
diff --git a/lib/ext2fs/ext3_extents.h b/lib/ext2fs/ext3_extents.h
index c4178c9..ba980e4 100644
--- a/lib/ext2fs/ext3_extents.h
+++ b/lib/ext2fs/ext3_extents.h
@@ -126,6 +126,26 @@
 #define EXT_MAX_BLOCK	0xffffffff
 #define EXT_CACHE_MARK	0xffff
 
+/*
+ * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
+ * initialized extent. This is 2^15 and not (2^16 - 1), since we use the
+ * MSB of ee_len field in the extent datastructure to signify if this
+ * particular extent is an initialized extent or an uninitialized (i.e.
+ * preallocated).
+ * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an
+ * uninitialized extent.
+ * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
+ * uninitialized one. In other words, if MSB of ee_len is set, it is an
+ * uninitialized extent with only one special scenario when ee_len = 0x8000.
+ * In this case we can not have an uninitialized extent of zero length and
+ * thus we make it as a special case of initialized extent with 0x8000 length.
+ * This way we get better extent-to-group alignment for initialized extents.
+ * Hence, the maximum number of blocks we can have in an *initialized*
+ * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767).
+ */
+#define EXT_INIT_MAX_LEN	(1UL << 15)
+#define EXT_UNINIT_MAX_LEN	(EXT_INIT_MAX_LEN - 1)
+
 
 #define EXT_FIRST_EXTENT(__hdr__) \
 	((struct ext3_extent *) (((char *) (__hdr__)) +		\
diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c
index 08211c3..3d208ec 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -23,6 +23,43 @@
 
 #include "ext2fs.h"
 
+#define NAME_HASH_SHIFT 5
+#define VALUE_HASH_SHIFT 16
+
+/*
+ * ext2_xattr_hash_entry()
+ *
+ * Compute the hash of an extended attribute.
+ */
+__u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
+{
+	__u32 hash = 0;
+	char *name = ((char *) entry) + sizeof(struct ext2_ext_attr_entry);
+	int n;
+
+	for (n = 0; n < entry->e_name_len; n++) {
+		hash = (hash << NAME_HASH_SHIFT) ^
+		       (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
+		       *name++;
+	}
+
+	/* The hash needs to be calculated on the data in little-endian. */
+	if (entry->e_value_block == 0 && entry->e_value_size != 0) {
+		__u32 *value = (__u32 *)data;
+		for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >>
+			 EXT2_EXT_ATTR_PAD_BITS; n; n--) {
+			hash = (hash << VALUE_HASH_SHIFT) ^
+			       (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
+			       ext2fs_le32_to_cpu(*value++);
+		}
+	}
+
+	return hash;
+}
+
+#undef NAME_HASH_SHIFT
+#undef VALUE_HASH_SHIFT
+
 errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
 {
 	errcode_t	retval;
@@ -30,10 +67,8 @@
  	retval = io_channel_read_blk(fs->io, block, 1, buf);
 	if (retval)
 		return retval;
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if ((fs->flags & (EXT2_FLAG_SWAP_BYTES|
-			  EXT2_FLAG_SWAP_BYTES_READ)) != 0)
-		ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
+#ifdef WORDS_BIGENDIAN
+	ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
 #endif
 	return 0;
 }
@@ -44,17 +79,15 @@
 	char		*write_buf;
 	char		*buf = NULL;
 
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
-		retval = ext2fs_get_mem(fs->blocksize, &buf);
-		if (retval)
-			return retval;
-		write_buf = buf;
-		ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
-	} else
+#ifdef WORDS_BIGENDIAN
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return retval;
+	write_buf = buf;
+	ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
+#else
+	write_buf = (char *) inbuf;
 #endif
-		write_buf = (char *) inbuf;
  	retval = io_channel_write_blk(fs->io, block, 1, write_buf);
 	if (buf)
 		ext2fs_free_mem(&buf);
diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
new file mode 100644
index 0000000..e7733c5
--- /dev/null
+++ b/lib/ext2fs/extent.c
@@ -0,0 +1,1149 @@
+/*
+ * extent.c --- routines to implement extents support
+ *
+ * Copyright (C) 2007 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+#include "e2image.h"
+#include "ss/ss.h"
+
+/*
+ * Definitions to be dropped in lib/ext2fs/ext2fs.h
+ */
+
+/*
+ * Private definitions
+ */
+
+struct extent_path {
+	char		*buf;
+	int		entries;
+	int		max_entries;
+	int		left;
+	int		visit_num;
+	int		flags;
+	blk64_t		end_blk;
+	void		*curr;
+};
+
+
+struct ext2_extent_handle {
+	errcode_t		magic;
+	ext2_filsys		fs;
+	ext2_ino_t 		ino;
+	struct ext2_inode	*inode;
+	int			type;
+	int			level;
+	int			max_depth;
+	struct extent_path	*path;
+};
+
+struct ext2_extent_path {
+	errcode_t		magic;
+	int			leaf_height;
+	blk64_t			lblk;
+};
+
+/*
+ *  Useful Debugging stuff
+ */
+
+#ifdef DEBUG
+static void dbg_show_header(struct ext3_extent_header *eh)
+{
+	printf("header: magic=%x entries=%u max=%u depth=%u generation=%u\n",
+	       eh->eh_magic, eh->eh_entries, eh->eh_max, eh->eh_depth,
+	       eh->eh_generation);
+}
+
+static void dbg_show_index(struct ext3_extent_idx *ix)
+{
+	printf("index: block=%u leaf=%u leaf_hi=%u unused=%u\n",
+	       ix->ei_block, ix->ei_leaf, ix->ei_leaf_hi, ix->ei_unused);
+}
+
+static void dbg_show_extent(struct ext3_extent *ex)
+{
+	printf("extent: block=%u-%u len=%u start=%u start_hi=%u\n",
+	       ex->ee_block, ex->ee_block + ex->ee_len - 1,
+	       ex->ee_len, ex->ee_start, ex->ee_start_hi);
+}
+
+static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
+{
+	if (desc)
+		printf("%s: ", desc);
+	printf("extent: lblk %llu--%llu, len %lu, pblk %llu, flags: ",
+	       extent->e_lblk, extent->e_lblk + extent->e_len - 1,
+	       extent->e_len, extent->e_pblk);
+	if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
+		fputs("LEAF ", stdout);
+	if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
+		fputs("UNINIT ", stdout);
+	if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
+		fputs("2ND_VISIT ", stdout);
+	if (!extent->e_flags)
+		fputs("(none)", stdout);
+	fputc('\n', stdout);
+
+}
+
+#define dbg_printf(fmt, args...) printf(fmt, ## args)
+#else
+#define dbg_show_header(eh) do { } while (0)
+#define dbg_show_index(ix) do { } while (0)
+#define dbg_show_extent(ex) do { } while (0)
+#define dbg_print_extent(desc, ex) do { } while (0)
+#define dbg_printf(fmt, args...) do { } while (0)
+#endif
+
+/*
+ * Verify the extent header as being sane
+ */
+errcode_t ext2fs_extent_header_verify(void *ptr, int size)
+{
+	int eh_max, entry_size;
+	struct ext3_extent_header *eh = ptr;
+
+	dbg_show_header(eh);
+	if (ext2fs_le16_to_cpu(eh->eh_magic) != EXT3_EXT_MAGIC)
+		return EXT2_ET_EXTENT_HEADER_BAD;
+	if (ext2fs_le16_to_cpu(eh->eh_entries) > ext2fs_le16_to_cpu(eh->eh_max))
+		return EXT2_ET_EXTENT_HEADER_BAD;
+	if (eh->eh_depth == 0)
+		entry_size = sizeof(struct ext3_extent);
+	else
+		entry_size = sizeof(struct ext3_extent_idx);
+
+	eh_max = (size - sizeof(*eh)) / entry_size;
+	/* Allow two extent-sized items at the end of the block, for
+	 * ext4_extent_tail with checksum in the future. */
+	if ((ext2fs_le16_to_cpu(eh->eh_max) > eh_max) || 
+	    (ext2fs_le16_to_cpu(eh->eh_max) < (eh_max - 2)))
+		return EXT2_ET_EXTENT_HEADER_BAD;
+
+	return 0;
+}
+
+
+/*
+ * Begin functions to handle an inode's extent information
+ */
+extern void ext2fs_extent_free(ext2_extent_handle_t handle)
+{
+	int			i;
+
+	if (!handle)
+		return;
+
+	if (handle->inode)
+		ext2fs_free_mem(&handle->inode);
+	if (handle->path) {
+		for (i=1; i < handle->max_depth; i++) {
+			if (handle->path[i].buf)
+				ext2fs_free_mem(&handle->path[i].buf);
+		}
+		ext2fs_free_mem(&handle->path);
+	}
+	ext2fs_free_mem(&handle);
+}
+
+extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino,
+				    ext2_extent_handle_t *ret_handle)
+{
+	struct ext2_extent_handle	*handle;
+	errcode_t			retval;
+	int				isize = EXT2_INODE_SIZE(fs->super);
+	struct ext3_extent_header	*eh;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if ((ino == 0) || (ino > fs->super->s_inodes_count))
+		return EXT2_ET_BAD_INODE_NUM;
+
+	retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle);
+	if (retval)
+		return retval;
+	memset(handle, 0, sizeof(struct ext2_extent_handle));
+
+	retval = ext2fs_get_mem(isize, &handle->inode);
+	if (retval)
+		goto errout;
+
+	handle->ino = ino;
+	handle->fs = fs;
+
+	retval = ext2fs_read_inode_full(fs, ino, handle->inode, isize);
+	if (retval)
+		goto errout;
+
+	if (!(handle->inode->i_flags & EXT4_EXTENTS_FL))
+		return EXT2_ET_INODE_NOT_EXTENT;
+
+	eh = (struct ext3_extent_header *) &handle->inode->i_block[0];
+
+	retval = ext2fs_extent_header_verify(eh, sizeof(handle->inode->i_block));
+	if (retval)
+		return (retval);
+
+	handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth);
+	handle->type = ext2fs_le16_to_cpu(eh->eh_magic);
+
+	retval = ext2fs_get_mem(((handle->max_depth+1) *
+				 sizeof(struct extent_path)),
+				&handle->path);
+	memset(handle->path, 0,
+	       (handle->max_depth+1) * sizeof(struct extent_path));
+	handle->path[0].buf = (char *) handle->inode->i_block;
+
+	handle->path[0].left = handle->path[0].entries =
+		ext2fs_le16_to_cpu(eh->eh_entries);
+	handle->path[0].max_entries = ext2fs_le16_to_cpu(eh->eh_max);
+	handle->path[0].curr = 0;
+	handle->path[0].end_blk =
+		((((__u64) handle->inode->i_size_high << 32) +
+		  handle->inode->i_size + (fs->blocksize - 1))
+		 >> EXT2_BLOCK_SIZE_BITS(fs->super));
+	handle->path[0].visit_num = 1;
+	handle->level = 0;
+	handle->magic = EXT2_ET_MAGIC_EXTENT_HANDLE;
+
+	*ret_handle = handle;
+	return 0;
+
+errout:
+	ext2fs_extent_free(handle);
+	return retval;
+}
+
+/*
+ * This function is responsible for (optionally) moving through the
+ * extent tree and then returning the current extent
+ */
+errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
+			    int flags, struct ext2fs_extent *extent)
+{
+	struct extent_path	*path, *newpath;
+	struct ext3_extent_header	*eh;
+	struct ext3_extent_idx		*ix = 0;
+	struct ext3_extent		*ex;
+	errcode_t			retval;
+	blk_t				blk;
+	blk64_t				end_blk;
+	int				orig_op, op;
+
+	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
+
+	if (!handle->path)
+		return EXT2_ET_NO_CURRENT_NODE;
+
+	orig_op = op = flags & EXT2_EXTENT_MOVE_MASK;
+
+retry:
+	path = handle->path + handle->level;
+	if ((orig_op == EXT2_EXTENT_NEXT) ||
+	    (orig_op == EXT2_EXTENT_NEXT_LEAF)) {
+		if (handle->level < handle->max_depth) {
+			/* interior node */
+			if (path->visit_num == 0) {
+				path->visit_num++;
+				op = EXT2_EXTENT_DOWN;
+			} else if (path->left > 0)
+				op = EXT2_EXTENT_NEXT_SIB;
+			else if (handle->level > 0)
+				op = EXT2_EXTENT_UP;
+			else
+				return EXT2_ET_EXTENT_NO_NEXT;
+		} else {
+			/* leaf node */
+			if (path->left > 0)
+				op = EXT2_EXTENT_NEXT_SIB;
+			else if (handle->level > 0)
+				op = EXT2_EXTENT_UP;
+			else
+				return EXT2_ET_EXTENT_NO_NEXT;
+		}
+		if (op != EXT2_EXTENT_NEXT_SIB) {
+			dbg_printf("<<<< OP = %s\n",
+			       (op == EXT2_EXTENT_DOWN) ? "down" :
+			       ((op == EXT2_EXTENT_UP) ? "up" : "unknown"));
+		}
+	}
+
+	if ((orig_op == EXT2_EXTENT_PREV) ||
+	    (orig_op == EXT2_EXTENT_PREV_LEAF)) {
+		if (handle->level < handle->max_depth) {
+			/* interior node */
+			if (path->visit_num > 0 ) {
+				/* path->visit_num = 0; */
+				op = EXT2_EXTENT_DOWN_AND_LAST;
+			} else if (path->left < path->entries-1)
+				op = EXT2_EXTENT_PREV_SIB;
+			else if (handle->level > 0)
+				op = EXT2_EXTENT_UP;
+			else
+				return EXT2_ET_EXTENT_NO_PREV;
+		} else {
+			/* leaf node */
+			if (path->left < path->entries-1)
+				op = EXT2_EXTENT_PREV_SIB;
+			else if (handle->level > 0)
+				op = EXT2_EXTENT_UP;
+			else
+				return EXT2_ET_EXTENT_NO_PREV;
+		}
+		if (op != EXT2_EXTENT_PREV_SIB) {
+			dbg_printf("<<<< OP = %s\n",
+			       (op == EXT2_EXTENT_DOWN_AND_LAST) ? "down/last" :
+			       ((op == EXT2_EXTENT_UP) ? "up" : "unknown"));
+		}
+	}
+
+	if (orig_op == EXT2_EXTENT_LAST_LEAF) {
+		if ((handle->level < handle->max_depth) &&
+		    (path->left == 0))
+			op = EXT2_EXTENT_DOWN;
+		else
+			op = EXT2_EXTENT_LAST_SIB;
+		dbg_printf("<<<< OP = %s\n",
+			   (op == EXT2_EXTENT_DOWN) ? "down" : "last_sib");
+	}
+
+	switch (op) {
+	case EXT2_EXTENT_CURRENT:
+		ix = path->curr;
+		break;
+	case EXT2_EXTENT_ROOT:
+		handle->level = 0;
+		path = handle->path + handle->level;
+	case EXT2_EXTENT_FIRST_SIB:
+		path->left = path->entries;
+		path->curr = 0;
+	case EXT2_EXTENT_NEXT_SIB:
+		if (path->left <= 0)
+			return EXT2_ET_EXTENT_NO_NEXT;
+		if (path->curr) {
+			ix = path->curr;
+			ix++;
+		} else {
+			eh = (struct ext3_extent_header *) path->buf;
+			ix = EXT_FIRST_INDEX(eh);
+		}
+		path->left--;
+		path->curr = ix;
+		path->visit_num = 0;
+		break;
+	case EXT2_EXTENT_PREV_SIB:
+		if (!path->curr ||
+		    path->left+1 >= path->entries)
+			return EXT2_ET_EXTENT_NO_PREV;
+		ix = path->curr;
+		ix--;
+		path->curr = ix;
+		path->left++;
+		if (handle->level < handle->max_depth)
+			path->visit_num = 1;
+		break;
+	case EXT2_EXTENT_LAST_SIB:
+		eh = (struct ext3_extent_header *) path->buf;
+		path->curr = EXT_LAST_EXTENT(eh);
+		ix = path->curr;
+		path->left = 0;
+		path->visit_num = 0;
+		break;
+	case EXT2_EXTENT_UP:
+		if (handle->level <= 0)
+			return EXT2_ET_EXTENT_NO_UP;
+		handle->level--;
+		path--;
+		ix = path->curr;
+		if ((orig_op == EXT2_EXTENT_PREV) ||
+		    (orig_op == EXT2_EXTENT_PREV_LEAF))
+			path->visit_num = 0;
+		break;
+	case EXT2_EXTENT_DOWN:
+	case EXT2_EXTENT_DOWN_AND_LAST:
+		if (!path->curr ||(handle->level >= handle->max_depth))
+			return EXT2_ET_EXTENT_NO_DOWN;
+
+		ix = path->curr;
+		newpath = path + 1;
+		if (!newpath->buf) {
+			retval = ext2fs_get_mem(handle->fs->blocksize,
+						&newpath->buf);
+			if (retval)
+				return retval;
+		}
+		blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
+			((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
+		if ((handle->fs->flags & EXT2_FLAG_IMAGE_FILE) &&
+		    (handle->fs->io != handle->fs->image_io))
+			memset(newpath->buf, 0, handle->fs->blocksize);
+		else {
+			retval = io_channel_read_blk(handle->fs->io,
+						     blk, 1, newpath->buf);
+			if (retval)
+				return retval;
+		}
+		handle->level++;
+
+		eh = (struct ext3_extent_header *) newpath->buf;
+
+		retval = ext2fs_extent_header_verify(eh, handle->fs->blocksize);
+		if (retval)
+			return retval;
+
+		newpath->left = newpath->entries =
+			ext2fs_le16_to_cpu(eh->eh_entries);
+		newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
+
+		if (path->left > 0) {
+			ix++;
+			newpath->end_blk = ext2fs_le32_to_cpu(ix->ei_block);
+		} else
+			newpath->end_blk = path->end_blk;
+
+		path = newpath;
+		if (op == EXT2_EXTENT_DOWN) {
+			ix = EXT_FIRST_INDEX((struct ext3_extent_header *) eh);
+			path->curr = ix;
+			path->left = path->entries - 1;
+			path->visit_num = 0;
+		} else {
+			ix = EXT_LAST_INDEX((struct ext3_extent_header *) eh);
+			path->curr = ix;
+			path->left = 0;
+			if (handle->level < handle->max_depth)
+				path->visit_num = 1;
+		}
+
+		dbg_printf("Down to level %d/%d, end_blk=%llu\n",
+			   handle->level, handle->max_depth,
+			   path->end_blk);
+
+		break;
+	default:
+		return EXT2_ET_OP_NOT_SUPPORTED;
+	}
+
+	if (!ix)
+		return EXT2_ET_NO_CURRENT_NODE;
+
+	extent->e_flags = 0;
+	dbg_printf("(Left %d)\n", path->left);
+
+	if (handle->level == handle->max_depth) {
+		ex = (struct ext3_extent *) ix;
+
+		extent->e_pblk = ext2fs_le32_to_cpu(ex->ee_start) +
+			((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32);
+		extent->e_lblk = ext2fs_le32_to_cpu(ex->ee_block);
+		extent->e_len = ext2fs_le16_to_cpu(ex->ee_len);
+		extent->e_flags |= EXT2_EXTENT_FLAGS_LEAF;
+		if (extent->e_len > EXT_INIT_MAX_LEN) {
+			extent->e_len -= EXT_INIT_MAX_LEN;
+			extent->e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
+		}
+	} else {
+		extent->e_pblk = ext2fs_le32_to_cpu(ix->ei_leaf) +
+			((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
+		extent->e_lblk = ext2fs_le32_to_cpu(ix->ei_block);
+		if (path->left > 0) {
+			ix++;
+			end_blk = ext2fs_le32_to_cpu(ix->ei_block);
+		} else
+			end_blk = path->end_blk;
+
+		extent->e_len = end_blk - extent->e_lblk;
+	}
+	if (path->visit_num)
+		extent->e_flags |= EXT2_EXTENT_FLAGS_SECOND_VISIT;
+
+	if (((orig_op == EXT2_EXTENT_NEXT_LEAF) ||
+	     (orig_op == EXT2_EXTENT_PREV_LEAF)) &&
+	    (handle->level != handle->max_depth))
+		goto retry;
+
+	if ((orig_op == EXT2_EXTENT_LAST_LEAF) &&
+	    ((handle->level != handle->max_depth) ||
+	     (path->left != 0)))
+		goto retry;
+
+	return 0;
+}
+
+static errcode_t update_path(ext2_extent_handle_t handle)
+{
+	blk64_t				blk;
+	errcode_t			retval;
+	struct ext3_extent_idx		*ix;
+
+	if (handle->level == 0) {
+		retval = ext2fs_write_inode_full(handle->fs, handle->ino,
+			   handle->inode, EXT2_INODE_SIZE(handle->fs->super));
+	} else {
+		ix = handle->path[handle->level - 1].curr;
+		blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
+			((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
+
+		retval = io_channel_write_blk(handle->fs->io,
+				      blk, 1, handle->path[handle->level].buf);
+	}
+	return retval;
+}
+
+#if 0
+errcode_t ext2fs_extent_save_path(ext2_extent_handle_t handle,
+				  ext2_extent_path_t *ret_path)
+{
+	ext2_extent_path_t	save_path;
+	struct ext2fs_extent	extent;
+	struct ext2_extent_info	info;
+	errcode_t		retval;
+
+	retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_extent_get_info(handle, &info);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_get_mem(sizeof(struct ext2_extent_path), &save_path);
+	if (retval)
+		return retval;
+	memset(save_path, 0, sizeof(struct ext2_extent_path));
+
+	save_path->magic = EXT2_ET_MAGIC_EXTENT_PATH;
+	save_path->leaf_height = info.max_depth - info.curr_level - 1;
+	save_path->lblk = extent.e_lblk;
+
+	*ret_path = save_path;
+	return 0;
+}
+
+errcode_t ext2fs_extent_free_path(ext2_extent_path_t path)
+{
+	EXT2_CHECK_MAGIC(path, EXT2_ET_MAGIC_EXTENT_PATH);
+
+	ext2fs_free_mem(&path);
+	return 0;
+}
+#endif
+
+static errcode_t extent_goto(ext2_extent_handle_t handle,
+			     int leaf_level, blk64_t blk)
+{
+	struct ext2fs_extent	extent;
+	errcode_t		retval;
+
+	retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent);
+	if (retval)
+		return retval;
+
+	dbg_print_extent("root", &extent);
+	while (1) {
+		if (handle->level - leaf_level == handle->max_depth) {
+			if ((blk >= extent.e_lblk) &&
+			    (blk < extent.e_lblk + extent.e_len))
+				return 0;
+			if (blk < extent.e_lblk)
+				return EXT2_ET_EXTENT_NOT_FOUND;
+			retval = ext2fs_extent_get(handle,
+						   EXT2_EXTENT_NEXT_SIB,
+						   &extent);
+			if (retval == EXT2_ET_EXTENT_NO_NEXT)
+				return EXT2_ET_EXTENT_NOT_FOUND;
+			if (retval)
+				return retval;
+			continue;
+		}
+
+		retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_SIB,
+					   &extent);
+		if (retval == EXT2_ET_EXTENT_NO_NEXT)
+			goto go_down;
+		if (retval)
+			return retval;
+
+		dbg_print_extent("next", &extent);
+		if (blk == extent.e_lblk)
+			goto go_down;
+		if (blk > extent.e_lblk)
+			continue;
+
+		retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_SIB,
+					   &extent);
+		if (retval)
+			return retval;
+
+		dbg_print_extent("prev", &extent);
+
+	go_down:
+		retval = ext2fs_extent_get(handle, EXT2_EXTENT_DOWN,
+					   &extent);
+		if (retval)
+			return retval;
+
+		dbg_print_extent("down", &extent);
+	}
+}
+
+errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
+			     blk64_t blk)
+{
+	return extent_goto(handle, 0, blk);
+}
+
+errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle, 
+				int flags EXT2FS_ATTR((unused)),
+				struct ext2fs_extent *extent)
+{
+	struct extent_path		*path;
+	struct ext3_extent_idx		*ix;
+	struct ext3_extent		*ex;
+
+	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
+
+	if (!(handle->fs->flags & EXT2_FLAG_RW))
+		return EXT2_ET_RO_FILSYS;
+
+	if (!handle->path)
+		return EXT2_ET_NO_CURRENT_NODE;
+
+	path = handle->path + handle->level;
+	if (!path->curr)
+		return EXT2_ET_NO_CURRENT_NODE;
+
+	if (handle->level == handle->max_depth) {
+		ex = path->curr;
+
+		ex->ee_block = ext2fs_cpu_to_le32(extent->e_lblk);
+		ex->ee_start = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF);
+		ex->ee_start_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32);
+		ex->ee_len = ext2fs_cpu_to_le16(extent->e_len);
+	} else {
+		ix = path->curr;
+
+		ix->ei_leaf = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF);
+		ix->ei_leaf_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32);
+		ix->ei_block = ext2fs_cpu_to_le32(extent->e_lblk);
+		ix->ei_unused = 0;
+	}
+	update_path(handle);
+	return 0;
+}
+
+errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
+				      struct ext2fs_extent *extent)
+{
+	struct extent_path		*path;
+	struct ext3_extent_idx		*ix;
+	struct ext3_extent_header	*eh;
+	errcode_t			retval;
+
+	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
+
+	if (!(handle->fs->flags & EXT2_FLAG_RW))
+		return EXT2_ET_RO_FILSYS;
+
+	if (!handle->path)
+		return EXT2_ET_NO_CURRENT_NODE;
+
+	path = handle->path + handle->level;
+
+	if (path->entries >= path->max_entries)
+		return EXT2_ET_CANT_INSERT_EXTENT;
+
+	eh = (struct ext3_extent_header *) path->buf;
+	if (path->curr) {
+		ix = path->curr;
+		if (flags & EXT2_EXTENT_INSERT_AFTER) {
+			ix++;
+			path->left--;
+		}
+	} else
+		ix = EXT_FIRST_INDEX(eh);
+
+	path->curr = ix;
+
+	if (path->left > 0)
+		memmove(ix + 1, ix,
+			(path->left+1) * sizeof(struct ext3_extent_idx));
+	path->left++;
+	path->entries++;
+
+	eh = (struct ext3_extent_header *) path->buf;
+	eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
+
+	retval = ext2fs_extent_replace(handle, 0, extent);
+	if (retval)
+		goto errout;
+
+	retval = update_path(handle);
+	if (retval)
+		goto errout;
+
+	return 0;
+
+errout:
+	ext2fs_extent_delete(handle, 0);
+	return retval;
+}
+
+errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, 
+			       int flags EXT2FS_ATTR((unused)))
+{
+	struct extent_path		*path;
+	char 				*cp;
+	struct ext3_extent_header	*eh;
+	errcode_t			retval;
+
+	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
+
+	if (!(handle->fs->flags & EXT2_FLAG_RW))
+		return EXT2_ET_RO_FILSYS;
+
+	if (!handle->path)
+		return EXT2_ET_NO_CURRENT_NODE;
+
+	path = handle->path + handle->level;
+	if (!path->curr)
+		return EXT2_ET_NO_CURRENT_NODE;
+
+	cp = path->curr;
+
+	if (path->left) {
+		memmove(cp, cp + sizeof(struct ext3_extent_idx),
+			path->left * sizeof(struct ext3_extent_idx));
+		path->left--;
+	} else {
+		struct ext3_extent_idx	*ix = path->curr;
+		ix--;
+		path->curr = ix;
+	}
+	path->entries--;
+	if (path->entries == 0)
+		path->curr = 0;
+
+	eh = (struct ext3_extent_header *) path->buf;
+	eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
+
+	retval = update_path(handle);
+
+	return retval;
+}
+
+errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle,
+				 struct ext2_extent_info *info)
+{
+	struct extent_path		*path;
+
+	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
+
+	memset(info, 0, sizeof(struct ext2_extent_info));
+
+	path = handle->path + handle->level;
+	if (path) {
+		if (path->curr)
+			info->curr_entry = ((char *) path->curr - path->buf) /
+				sizeof(struct ext3_extent_idx);
+		else
+			info->curr_entry = 0;
+		info->num_entries = path->entries;
+		info->max_entries = path->max_entries;
+		info->bytes_avail = (path->max_entries - path->entries) *
+			sizeof(struct ext3_extent);
+	}
+
+	info->curr_level = handle->level;
+	info->max_depth = handle->max_depth;
+	info->max_lblk = ((__u64) 1 << 32) - 1;
+	info->max_pblk = ((__u64) 1 << 48) - 1;
+	info->max_len = (1UL << 15);
+	info->max_uninit_len = (1UL << 15) - 1;
+
+	return 0;
+}
+
+#ifdef DEBUG
+
+#include "debugfs.h"
+
+/*
+ * Hook in new commands into debugfs
+ */
+const char *debug_prog_name = "tst_extents";
+extern ss_request_table extent_cmds;
+ss_request_table *extra_cmds = &extent_cmds;
+
+ext2_ino_t	current_ino = 0;
+ext2_extent_handle_t current_handle;
+
+void do_inode(int argc, char *argv[])
+{
+	ext2_ino_t	inode;
+	int		i;
+	struct ext3_extent_header *eh;
+	errcode_t retval;
+
+	if (check_fs_open(argv[0]))
+		return;
+
+	if (argc == 1) {
+		if (current_ino)
+			printf("Current inode is %d\n", current_ino);
+		else
+			printf("No current inode\n");
+		return;
+	}
+
+	if (common_inode_args_process(argc, argv, &inode, 0)) {
+		return;
+	}
+
+	current_ino = 0;
+
+	retval = ext2fs_extent_open(current_fs, inode, &current_handle);
+	if (retval) {
+		com_err(argv[1], retval, "while opening extent handle");
+		return;
+	}
+
+	current_ino = inode;
+
+	printf("Loaded inode %d\n", current_ino);
+
+	return;
+}
+
+void generic_goto_node(char *cmd_name, int op)
+{
+	struct ext2fs_extent	extent;
+	errcode_t		retval;
+
+	if (check_fs_open(cmd_name))
+		return;
+
+	if (!current_handle) {
+		com_err(cmd_name, 0, "Extent handle not open");
+		return;
+	}
+
+	retval = ext2fs_extent_get(current_handle, op, &extent);
+	if (retval) {
+		com_err(cmd_name, retval, 0);
+		return;
+	}
+	dbg_print_extent(0, &extent);
+}
+
+void do_current_node(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_CURRENT);
+}
+
+void do_root_node(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_ROOT);
+}
+
+void do_last_leaf(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_LAST_LEAF);
+}
+
+void do_first_sib(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_FIRST_SIB);
+}
+
+void do_last_sib(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_LAST_SIB);
+}
+
+void do_next_sib(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_NEXT_SIB);
+}
+
+void do_prev_sib(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_PREV_SIB);
+}
+
+void do_next_leaf(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_NEXT_LEAF);
+}
+
+void do_prev_leaf(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_PREV_LEAF);
+}
+
+void do_next(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_NEXT);
+}
+
+void do_prev(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_PREV);
+}
+
+void do_up(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_UP);
+}
+
+void do_down(int argc, char *argv[])
+{
+	generic_goto_node(argv[0], EXT2_EXTENT_DOWN);
+}
+
+void do_delete_node(int argc, char *argv[])
+{
+	errcode_t	retval;
+	int		err;
+
+	if (check_fs_read_write(argv[0]))
+		return;
+
+	retval = ext2fs_extent_delete(current_handle, 0);
+	if (retval) {
+		com_err(argv[0], retval, 0);
+		return;
+	}
+	do_current_node(argc, argv);
+}
+
+void do_replace_node(int argc, char *argv[])
+{
+	errcode_t	retval;
+	struct ext2fs_extent extent;
+	int err;
+
+	if (check_fs_read_write(argv[0]))
+		return;
+
+	if (argc != 4) {
+		fprintf(stderr, "usage: %s <lblk> <len> <pblk>\n", argv[0]);
+		return;
+	}
+
+	extent.e_lblk = parse_ulong(argv[1], argv[0],
+				    "logical block", &err);
+	if (err)
+		return;
+
+	extent.e_len = parse_ulong(argv[2], argv[0],
+				    "logical block", &err);
+	if (err)
+		return;
+
+	extent.e_pblk = parse_ulong(argv[3], argv[0],
+				    "logical block", &err);
+	if (err)
+		return;
+
+	retval = ext2fs_extent_replace(current_handle, 0, &extent);
+	if (retval) {
+		com_err(argv[0], retval, 0);
+		return;
+	}
+	do_current_node(argc, argv);
+}
+
+void do_insert_node(int argc, char *argv[])
+{
+	errcode_t	retval;
+	struct ext2fs_extent extent;
+	char *cmd;
+	int err;
+	int flags = 0;
+
+	if (check_fs_read_write(argv[0]))
+		return;
+
+	cmd = argv[0];
+
+	if (argc > 2 && !strcmp(argv[1], "--after")) {
+		argc--;
+		argv++;
+		flags |= EXT2_EXTENT_INSERT_AFTER;
+	}
+
+	if (argc != 4) {
+		fprintf(stderr, "usage: %s <lblk> <len> <pblk>\n", cmd);
+		return;
+	}
+
+	extent.e_lblk = parse_ulong(argv[1], cmd,
+				    "logical block", &err);
+	if (err)
+		return;
+
+	extent.e_len = parse_ulong(argv[2], cmd,
+				    "length", &err);
+	if (err)
+		return;
+
+	extent.e_pblk = parse_ulong(argv[3], cmd,
+				    "pysical block", &err);
+	if (err)
+		return;
+
+	retval = ext2fs_extent_insert(current_handle, flags, &extent);
+	if (retval) {
+		com_err(cmd, retval, 0);
+		return;
+	}
+	do_current_node(argc, argv);
+}
+
+void do_print_all(int argc, char **argv)
+{
+	struct ext2fs_extent	extent;
+	errcode_t		retval;
+	errcode_t		end_err = EXT2_ET_EXTENT_NO_NEXT;
+	int			op = EXT2_EXTENT_NEXT;
+	int			first_op = EXT2_EXTENT_ROOT;
+
+
+	if (check_fs_open(argv[0]))
+		return;
+
+	if (!current_handle) {
+		com_err(argv[0], 0, "Extent handle not open");
+		return;
+	}
+
+	if (argc > 2) {
+	print_usage:
+		fprintf(stderr,
+			"Usage: %s [--leaf-only|--reverse|--reverse-leaf]\n",
+			argv[0]);
+		return;
+	}
+
+	if (argc == 2) {
+		if (!strcmp(argv[1], "--leaf-only"))
+			op = EXT2_EXTENT_NEXT_LEAF;
+		else if (!strcmp(argv[1], "--reverse")) {
+			op = EXT2_EXTENT_PREV;
+			first_op = EXT2_EXTENT_LAST_LEAF;
+			end_err = EXT2_ET_EXTENT_NO_PREV;
+		} else if (!strcmp(argv[1], "--reverse-leaf")) {
+			op = EXT2_EXTENT_PREV_LEAF;
+			first_op = EXT2_EXTENT_LAST_LEAF;
+			end_err = EXT2_ET_EXTENT_NO_PREV;
+		} else
+			  goto print_usage;
+	}
+
+	retval = ext2fs_extent_get(current_handle, first_op, &extent);
+	if (retval) {
+		com_err(argv[0], retval, 0);
+		return;
+	}
+	dbg_print_extent(0, &extent);
+
+	while (1) {
+		retval = ext2fs_extent_get(current_handle, op, &extent);
+		if (retval == end_err)
+			break;
+
+		if (retval) {
+			com_err(argv[0], retval, 0);
+			return;
+		}
+		dbg_print_extent(0, &extent);
+	}
+}
+
+void do_info(int argc, char **argv)
+{
+	struct ext2_extent_info	info;
+	errcode_t		retval;
+
+	if (check_fs_open(argv[0]))
+		return;
+
+	if (!current_handle) {
+		com_err(argv[0], 0, "Extent handle not open");
+		return;
+	}
+
+	retval = ext2fs_extent_get_info(current_handle, &info);
+	if (retval) {
+		com_err(argv[0], retval, 0);
+		return;
+	}
+
+	printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n",
+	       info.curr_entry, info.num_entries, info.max_entries,
+	       info.bytes_avail, info.curr_level, info.max_depth);
+	printf("\tmax lblk: %llu, max pblk: %llu\n", info.max_lblk,
+	       info.max_pblk);
+	printf("\tmax_len: %u, max_uninit_len: %u\n", info.max_len,
+	       info.max_uninit_len);
+}
+
+void do_goto_block(int argc, char **argv)
+{
+	struct ext2fs_extent	extent;
+	errcode_t		retval;
+	int			op = EXT2_EXTENT_NEXT_LEAF;
+	blk_t			blk;
+
+	if (check_fs_open(argv[0]))
+		return;
+
+	if (!current_handle) {
+		com_err(argv[0], 0, "Extent handle not open");
+		return;
+	}
+
+	if (argc != 2) {
+		fprintf(stderr, "%s block\n", argv[0]);
+		return;
+	}
+
+	if (strtoblk(argv[0], argv[1], &blk))
+		return;
+
+	retval = ext2fs_extent_goto(current_handle, (blk64_t) blk);
+	if (retval) {
+		com_err(argv[0], retval, "while trying to go to block %lu",
+			blk);
+		return;
+	}
+
+	generic_goto_node(argv[0], EXT2_EXTENT_CURRENT);
+}
+#endif
+
diff --git a/lib/ext2fs/extent_dbg.ct b/lib/ext2fs/extent_dbg.ct
new file mode 100644
index 0000000..41299fa
--- /dev/null
+++ b/lib/ext2fs/extent_dbg.ct
@@ -0,0 +1,68 @@
+#
+# Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+# under the terms of the GNU Public License.
+#
+command_table extent_cmds;
+
+request do_inode, "Open an inode",
+	inode;
+
+request do_current_node, "Current extent node",
+	current_node, current;
+
+request do_root_node, "Goto root extent",
+	root_node, root;
+
+request do_last_leaf, "Goto last leaf",
+	last_leaf;
+
+request do_first_sib, "Goto first sibling",
+	first_sibling, first_sib;
+
+request do_last_sib, "Goto last sibling",
+	last_sibling, last_sib;
+
+request do_next_sib, "Goto next sibling",
+	next_sibling, next_sib, ns;
+
+request do_prev_sib, "Goto previous sibling",
+	prev_sibling, prev_sib, ps;
+
+request do_next_leaf, "Goto next leaf",
+	next_leaf, nl;
+
+request do_prev_leaf, "Goto previous leaf",
+	prev_leaf, pl;
+
+request do_next, "Goto next node",
+	next, n;
+
+request do_prev, "Goto previous node",
+	previous, prev, p;
+
+request do_up, "Up node",
+	up_node, up, u;
+
+request do_down, "Down node",
+	down_node, down, d;
+
+request do_delete_node, "Delete node",
+	delete_node, delete;
+
+request do_insert_node, "Insert node",
+	insert_node, insert;
+
+request do_replace_node, "Insert node",
+	replace_node, replace;
+
+request do_print_all, "Iterate over all nodes and print them",
+	print_all, all;
+
+request do_goto_block, "Goto extent containing specified block",
+	goto_block, goto;
+
+request do_info, "Print extent info",
+	info;
+
+end;
+
diff --git a/lib/ext2fs/freefs.c b/lib/ext2fs/freefs.c
index 029ffaa..d6ac901 100644
--- a/lib/ext2fs/freefs.c
+++ b/lib/ext2fs/freefs.c
@@ -58,41 +58,6 @@
 	ext2fs_free_mem(&fs);
 }
 
-void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap)
-{
-	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_GENERIC_BITMAP))
-		return;
-
-	bitmap->magic = 0;
-	if (bitmap->description) {
-		ext2fs_free_mem(&bitmap->description);
-		bitmap->description = 0;
-	}
-	if (bitmap->bitmap) {
-		ext2fs_free_mem(&bitmap->bitmap);
-		bitmap->bitmap = 0;
-	}
-	ext2fs_free_mem(&bitmap);
-}
-
-void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
-{
-	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
-		return;
-
-	bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
-	ext2fs_free_generic_bitmap(bitmap);
-}
-
-void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap)
-{
-	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
-		return;
-
-	bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
-	ext2fs_free_generic_bitmap(bitmap);
-}
-
 /*
  * Free the inode cache structure
  */
diff --git a/lib/ext2fs/gen_bitmap.c b/lib/ext2fs/gen_bitmap.c
index 700affa..66172e5 100644
--- a/lib/ext2fs/gen_bitmap.c
+++ b/lib/ext2fs/gen_bitmap.c
@@ -1,5 +1,5 @@
 /*
- * gen_bitmap.c --- Generic bitmap routines that used to be inlined.
+ * gen_bitmap.c --- Generic (32-bit) bitmap routines
  * 
  * Copyright (C) 2001 Theodore Ts'o.
  *
@@ -27,6 +27,144 @@
 #include "ext2_fs.h"
 #include "ext2fs.h"
 
+struct ext2fs_struct_generic_bitmap {
+	errcode_t	magic;
+	ext2_filsys 	fs;
+	__u32		start, end;
+	__u32		real_end;
+	char	*	description;
+	char	*	bitmap;
+	errcode_t	base_error_code;
+	__u32		reserved[7];
+};
+
+/* 
+ * Used by previously inlined function, so we have to export this and
+ * not change the function signature
+ */
+void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
+			    int code, unsigned long arg)
+{
+#ifndef OMIT_COM_ERR
+	if (bitmap->description)
+		com_err(0, bitmap->base_error_code+code,
+			"#%lu for %s", arg, bitmap->description);
+	else
+		com_err(0, bitmap->base_error_code + code, "#%lu", arg);
+#endif
+}
+
+static errcode_t check_magic(ext2fs_generic_bitmap bitmap)
+{
+	if (!bitmap || !((bitmap->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) ||
+			 (bitmap->magic == EXT2_ET_MAGIC_INODE_BITMAP) ||
+			 (bitmap->magic == EXT2_ET_MAGIC_BLOCK_BITMAP)))
+		return EXT2_ET_MAGIC_GENERIC_BITMAP;
+	return 0;
+}
+
+errcode_t ext2fs_make_generic_bitmap(errcode_t magic, ext2_filsys fs, 
+				     __u32 start, __u32 end, __u32 real_end,
+				     const char *descr, char *init_map,
+				     ext2fs_generic_bitmap *ret)
+{
+	ext2fs_generic_bitmap	bitmap;
+	errcode_t		retval;
+	size_t			size;
+
+	retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), 
+				&bitmap);
+	if (retval)
+		return retval;
+
+	bitmap->magic = magic;
+	bitmap->fs = fs;
+	bitmap->start = start;
+	bitmap->end = end;
+	bitmap->real_end = real_end;
+	switch (magic) {
+	case EXT2_ET_MAGIC_INODE_BITMAP:
+		bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
+		break;
+	case EXT2_ET_MAGIC_BLOCK_BITMAP:
+		bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
+		break;
+	default:
+		bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
+	}
+	if (descr) {
+		retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
+		if (retval) {
+			ext2fs_free_mem(&bitmap);
+			return retval;
+		}
+		strcpy(bitmap->description, descr);
+	} else
+		bitmap->description = 0;
+
+	size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
+	retval = ext2fs_get_mem(size, &bitmap->bitmap);
+	if (retval) {
+		ext2fs_free_mem(&bitmap->description);
+		ext2fs_free_mem(&bitmap);
+		return retval;
+	}
+
+	if (init_map)
+		memcpy(bitmap->bitmap, init_map, size);
+	else
+		memset(bitmap->bitmap, 0, size);
+	*ret = bitmap;
+	return 0;
+}
+
+errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
+					 __u32 end,
+					 __u32 real_end,
+					 const char *descr,
+					 ext2fs_generic_bitmap *ret)
+{
+	return ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_GENERIC_BITMAP, 0, 
+					  start, end, real_end, descr, 0, ret);
+}
+
+errcode_t ext2fs_copy_generic_bitmap(ext2fs_generic_bitmap src,
+				     ext2fs_generic_bitmap *dest)
+{
+	return (ext2fs_make_generic_bitmap(src->magic, src->fs,
+					   src->start, src->end, 
+					   src->real_end,
+					   src->description, src->bitmap,
+					   dest));
+}
+
+void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap)
+{
+	if (check_magic(bitmap))
+		return;
+
+	bitmap->magic = 0;
+	if (bitmap->description) {
+		ext2fs_free_mem(&bitmap->description);
+		bitmap->description = 0;
+	}
+	if (bitmap->bitmap) {
+		ext2fs_free_mem(&bitmap->bitmap);
+		bitmap->bitmap = 0;
+	}
+	ext2fs_free_mem(&bitmap);
+}
+
+int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
+					blk_t bitno)
+{
+	if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
+		ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
+		return 0;
+	}
+	return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
+}
+
 int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
 					 __u32 bitno)
 {
@@ -46,3 +184,191 @@
 	}
 	return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap);
 }
+
+__u32 ext2fs_get_generic_bitmap_start(ext2fs_generic_bitmap bitmap)
+{
+	return bitmap->start;
+}
+
+__u32 ext2fs_get_generic_bitmap_end(ext2fs_generic_bitmap bitmap)
+{
+	return bitmap->end;
+}
+
+void ext2fs_clear_generic_bitmap(ext2fs_generic_bitmap bitmap)
+{
+	if (check_magic(bitmap))
+		return;
+
+	memset(bitmap->bitmap, 0,
+	       (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
+}
+
+errcode_t ext2fs_fudge_generic_bitmap_end(ext2fs_inode_bitmap bitmap,
+					  errcode_t magic, errcode_t neq,
+					  ext2_ino_t end, ext2_ino_t *oend)
+{
+	EXT2_CHECK_MAGIC(bitmap, magic);
+	
+	if (end > bitmap->real_end)
+		return neq;
+	if (oend)
+		*oend = bitmap->end;
+	bitmap->end = end;
+	return 0;
+}
+
+errcode_t ext2fs_resize_generic_bitmap(errcode_t magic,
+				       __u32 new_end, __u32 new_real_end,
+				       ext2fs_generic_bitmap bmap)
+{
+	errcode_t	retval;
+	size_t		size, new_size;
+	__u32		bitno;
+
+	if (!bmap || (bmap->magic != magic))
+		return magic;
+
+	/*
+	 * If we're expanding the bitmap, make sure all of the new
+	 * parts of the bitmap are zero.
+	 */
+	if (new_end > bmap->end) {
+		bitno = bmap->real_end;
+		if (bitno > new_end)
+			bitno = new_end;
+		for (; bitno > bmap->end; bitno--)
+			ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap);
+	}
+	if (new_real_end == bmap->real_end) {
+		bmap->end = new_end;
+		return 0;
+	}
+	
+	size = ((bmap->real_end - bmap->start) / 8) + 1;
+	new_size = ((new_real_end - bmap->start) / 8) + 1;
+
+	if (size != new_size) {
+		retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap);
+		if (retval)
+			return retval;
+	}
+	if (new_size > size)
+		memset(bmap->bitmap + size, 0, new_size - size);
+
+	bmap->end = new_end;
+	bmap->real_end = new_real_end;
+	return 0;
+}
+
+errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq,
+					ext2fs_generic_bitmap bm1,
+					ext2fs_generic_bitmap bm2)
+{
+	blk_t	i;
+	
+	if (!bm1 || bm1->magic != magic)
+		return magic;
+	if (!bm2 || bm2->magic != magic)
+		return magic;
+
+	if ((bm1->start != bm2->start) ||
+	    (bm1->end != bm2->end) ||
+	    (memcmp(bm1->bitmap, bm2->bitmap,
+		    (size_t) (bm1->end - bm1->start)/8)))
+		return neq;
+
+	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
+		if (ext2fs_fast_test_block_bitmap(bm1, i) !=
+		    ext2fs_fast_test_block_bitmap(bm2, i))
+			return neq;
+
+	return 0;
+}
+
+void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap map)
+{
+	__u32	i, j;
+
+	/* Protect loop from wrap-around if map->real_end is maxed */
+	for (i=map->end+1, j = i - map->start; 
+	     i <= map->real_end && i > map->end; 
+	     i++, j++)
+		ext2fs_set_bit(j, map->bitmap);
+}
+
+errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap,
+					  errcode_t magic,
+					  __u32 start, __u32 num,
+					  void *out)
+{
+	if (!bmap || (bmap->magic != magic))
+		return magic;
+
+	if ((start < bmap->start) || (start+num-1 > bmap->real_end))
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	memcpy(out, bmap->bitmap + (start >> 3), (num+7) >> 3);
+	return 0;
+}
+
+errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap,
+					  errcode_t magic,
+					  __u32 start, __u32 num,
+					  void *in)
+{
+	if (!bmap || (bmap->magic != magic))
+		return magic;
+
+	if ((start < bmap->start) || (start+num-1 > bmap->real_end))
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	memcpy(bmap->bitmap + (start >> 3), in, (num+7) >> 3);
+	return 0;
+}
+
+int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+				   blk_t block, int num)
+{
+	int	i;
+
+	if ((block < bitmap->start) || (block+num-1 > bitmap->real_end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
+				   block, bitmap->description);
+		return 0;
+	}
+	for (i=0; i < num; i++) {
+		if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
+			return 0;
+	}
+	return 1;
+}
+
+void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+				    blk_t block, int num)
+{
+	int	i;
+	
+	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
+				   bitmap->description);
+		return;
+	}
+	for (i=0; i < num; i++)
+		ext2fs_fast_set_bit(block + i - bitmap->start, bitmap->bitmap);
+}
+
+void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+					       blk_t block, int num)
+{
+	int	i;
+	
+	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
+				   bitmap->description);
+		return;
+	}
+	for (i=0; i < num; i++)
+		ext2fs_fast_clear_bit(block + i - bitmap->start, 
+				      bitmap->bitmap);
+}
diff --git a/lib/ext2fs/icount.c b/lib/ext2fs/icount.c
index 2905676..bec0f5f 100644
--- a/lib/ext2fs/icount.c
+++ b/lib/ext2fs/icount.c
@@ -43,7 +43,7 @@
 
 struct ext2_icount_el {
 	ext2_ino_t	ino;
-	__u16	count;
+	__u32		count;
 };
 
 struct ext2_icount {
@@ -60,6 +60,15 @@
 	TDB_CONTEXT		*tdb;
 };
 
+/*
+ * We now use a 32-bit counter field because it doesn't cost us
+ * anything extra for the in-memory data structure, due to alignment
+ * padding.  But there's no point changing the interface if most of
+ * the time we only care if the number is bigger than 65,000 or not.
+ * So use the following translation function to return a 16-bit count.
+ */
+#define icount_16_xlate(x) (((x) > 65500) ? 65500 : (x))
+
 void ext2fs_free_icount(ext2_icount_t icount)
 {
 	if (!icount)
@@ -398,7 +407,7 @@
 }
 
 static errcode_t set_inode_count(ext2_icount_t icount, ext2_ino_t ino,
-				 __u16 count)
+				 __u32 count)
 {
 	struct ext2_icount_el 	*el;
 	TDB_DATA key, data;
@@ -407,7 +416,7 @@
 		key.dptr = (unsigned char *) &ino;
 		key.dsize = sizeof(ext2_ino_t);
 		data.dptr = (unsigned char *) &count;
-		data.dsize = sizeof(__u16);
+		data.dsize = sizeof(__u32);
 		if (count) {
 			if (tdb_store(icount->tdb, key, data, TDB_REPLACE))
 				return tdb_error(icount->tdb) +
@@ -429,7 +438,7 @@
 }
 
 static errcode_t get_inode_count(ext2_icount_t icount, ext2_ino_t ino,
-				 __u16 *count)
+				 __u32 *count)
 {
 	struct ext2_icount_el 	*el;
 	TDB_DATA key, data;
@@ -444,7 +453,7 @@
 			return tdb_error(icount->tdb) + EXT2_ET_TDB_SUCCESS;
 		}
 
-		*count = *((__u16 *) data.dptr);
+		*count = *((__u32 *) data.dptr);
 		free(data.dptr);
 		return 0;
 	}
@@ -483,6 +492,7 @@
 
 errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
 {
+	__u32	val;
 	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
 
 	if (!ino || (ino > icount->num_inodes))
@@ -497,14 +507,15 @@
 		*ret = 0;
 		return 0;
 	}
-	get_inode_count(icount, ino, ret);
+	get_inode_count(icount, ino, &val);
+	*ret = icount_16_xlate(val);
 	return 0;
 }
 
 errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
 				  __u16 *ret)
 {
-	__u16			curr_value;
+	__u32			curr_value;
 
 	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
 
@@ -554,14 +565,14 @@
 	if (icount->multiple)
 		ext2fs_mark_inode_bitmap(icount->multiple, ino);
 	if (ret)
-		*ret = curr_value;
+		*ret = icount_16_xlate(curr_value);
 	return 0;
 }
 
 errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
 				  __u16 *ret)
 {
-	__u16			curr_value;
+	__u32			curr_value;
 
 	if (!ino || (ino > icount->num_inodes))
 		return EXT2_ET_INVALID_ARGUMENT;
@@ -597,7 +608,7 @@
 		ext2fs_unmark_inode_bitmap(icount->multiple, ino);
 
 	if (ret)
-		*ret = curr_value;
+		*ret = icount_16_xlate(curr_value);
 	return 0;
 }
 
diff --git a/lib/ext2fs/imager.c b/lib/ext2fs/imager.c
index ac8309c..9f7534a 100644
--- a/lib/ext2fs/imager.c
+++ b/lib/ext2fs/imager.c
@@ -277,11 +277,12 @@
  */
 errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
 {
-	char		*ptr;
-	int		c, size;
-	char		zero_buf[1024];
-	ssize_t		actual;
-	errcode_t	retval;
+	ext2fs_generic_bitmap	bmap;
+	errcode_t		err, retval;
+	ssize_t			actual;
+	__u32			itr, cnt, size;
+	int			c, total_size;
+	char			buf[1024];
 
 	if (flags & IMAGER_FLAG_INODEMAP) {
 		if (!fs->inode_map) {
@@ -289,7 +290,10 @@
 			if (retval)
 				return retval;
 		}
-		ptr = fs->inode_map->bitmap;
+		bmap = fs->inode_map;
+		err = EXT2_ET_MAGIC_INODE_BITMAP;
+		itr = 1;
+		cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
 		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
 	} else {
 		if (!fs->block_map) {
@@ -297,43 +301,51 @@
 			if (retval)
 				return retval;
 		}
-		ptr = fs->block_map->bitmap;
+		bmap = fs->block_map;
+		err = EXT2_ET_MAGIC_BLOCK_BITMAP;
+		itr = fs->super->s_first_data_block;
+		cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
 		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
 	}
-	size = size * fs->group_desc_count;
+	total_size = size * fs->group_desc_count;
 
-	actual = write(fd, ptr, size);
-	if (actual == -1) {
-		retval = errno;
-		goto errout;
+	while (cnt > 0) {
+		size = sizeof(buf);
+		if (size > (cnt >> 3))
+			size = (cnt >> 3);
+
+		retval = ext2fs_get_generic_bitmap_range(bmap, 
+				 err, itr, size << 3, buf);
+		if (retval)
+			return retval;
+
+		actual = write(fd, buf, size);
+		if (actual == -1)
+			return errno;
+		if (actual != (int) size)
+			return EXT2_ET_SHORT_READ;
+		
+		itr += size << 3;
+		cnt -= size << 3;
 	}
-	if (actual != size) {
-		retval = EXT2_ET_SHORT_WRITE;
-		goto errout;
-	}
-	size = size % fs->blocksize;
-	memset(zero_buf, 0, sizeof(zero_buf));
+
+	size = total_size % fs->blocksize;
+	memset(buf, 0, sizeof(buf));
 	if (size) {
 		size = fs->blocksize - size;
 		while (size) {
 			c = size;
-			if (c > (int) sizeof(zero_buf))
-				c = sizeof(zero_buf);
-			actual = write(fd, zero_buf, c);
-			if (actual == -1) {
-				retval = errno;
-				goto errout;
-			}
-			if (actual != c) {
-				retval = EXT2_ET_SHORT_WRITE;
-				goto errout;
-			}
+			if (c > (int) sizeof(buf))
+				c = sizeof(buf);
+			actual = write(fd, buf, c);
+			if (actual == -1)
+				return errno;
+			if (actual != c)
+				return EXT2_ET_SHORT_WRITE;
 			size -= c;
 		}
 	}
-	retval = 0;
-errout:
-	return (retval);
+	return 0;
 }
 
 
@@ -342,10 +354,12 @@
  */
 errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
 {
-	char		*ptr, *buf = 0;
-	int		size;
-	ssize_t		actual;
-	errcode_t	retval;
+	ext2fs_generic_bitmap	bmap;
+	errcode_t		err, retval;
+	__u32			itr, cnt;
+	char			buf[1024];
+	unsigned int		size;
+	ssize_t			actual;
 
 	if (flags & IMAGER_FLAG_INODEMAP) {
 		if (!fs->inode_map) {
@@ -353,7 +367,10 @@
 			if (retval)
 				return retval;
 		}
-		ptr = fs->inode_map->bitmap;
+		bmap = fs->inode_map;
+		err = EXT2_ET_MAGIC_INODE_BITMAP;
+		itr = 1;
+		cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
 		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
 	} else {
 		if (!fs->block_map) {
@@ -361,29 +378,31 @@
 			if (retval)
 				return retval;
 		}
-		ptr = fs->block_map->bitmap;
+		bmap = fs->block_map;
+		err = EXT2_ET_MAGIC_BLOCK_BITMAP;
+		itr = fs->super->s_first_data_block;
+		cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
 		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
 	}
-	size = size * fs->group_desc_count;
 
-	buf = malloc(size);
-	if (!buf)
-		return ENOMEM;
+	while (cnt > 0) {
+		size = sizeof(buf);
+		if (size > (cnt >> 3))
+			size = (cnt >> 3);
 
-	actual = read(fd, buf, size);
-	if (actual == -1) {
-		retval = errno;
-		goto errout;
+		actual = read(fd, buf, size);
+		if (actual == -1)
+			return errno;
+		if (actual != (int) size)
+			return EXT2_ET_SHORT_READ;
+
+		retval = ext2fs_set_generic_bitmap_range(bmap, 
+				 err, itr, size << 3, buf);
+		if (retval)
+			return retval;
+
+		itr += size << 3;
+		cnt -= size << 3;
 	}
-	if (actual != size) {
-		retval = EXT2_ET_SHORT_WRITE;
-		goto errout;
-	}
-	memcpy(ptr, buf, size);
-	
-	retval = 0;
-errout:
-	if (buf)
-		free(buf);
-	return (retval);
+	return 0;
 }
diff --git a/lib/ext2fs/ind_block.c b/lib/ext2fs/ind_block.c
index 3519048..efd7fb1 100644
--- a/lib/ext2fs/ind_block.c
+++ b/lib/ext2fs/ind_block.c
@@ -22,9 +22,11 @@
 errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf)
 {
 	errcode_t	retval;
+#ifdef WORDS_BIGENDIAN
 	blk_t		*block_nr;
 	int		i;
 	int		limit = fs->blocksize >> 2;
+#endif
 
 	if ((fs->flags & EXT2_FLAG_IMAGE_FILE) &&
 	    (fs->io != fs->image_io))
@@ -34,31 +36,29 @@
 		if (retval)
 			return retval;
 	}
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_READ)) {
-		block_nr = (blk_t *) buf;
-		for (i = 0; i < limit; i++, block_nr++)
-			*block_nr = ext2fs_swab32(*block_nr);
-	}
+#ifdef WORDS_BIGENDIAN
+	block_nr = (blk_t *) buf;
+	for (i = 0; i < limit; i++, block_nr++)
+		*block_nr = ext2fs_swab32(*block_nr);
 #endif
 	return 0;
 }
 
 errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf)
 {
+#ifdef WORDS_BIGENDIAN
 	blk_t		*block_nr;
 	int		i;
 	int		limit = fs->blocksize >> 2;
+#endif
 
 	if (fs->flags & EXT2_FLAG_IMAGE_FILE)
 		return 0;
 
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_WRITE)) {
-		block_nr = (blk_t *) buf;
-		for (i = 0; i < limit; i++, block_nr++)
-			*block_nr = ext2fs_swab32(*block_nr);
-	}
+#ifdef WORDS_BIGENDIAN
+	block_nr = (blk_t *) buf;
+	for (i = 0; i < limit; i++, block_nr++)
+		*block_nr = ext2fs_swab32(*block_nr);
 #endif
 	return io_channel_write_blk(fs->io, blk, 1, buf);
 }
diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
index 7d06860..c2e00e8 100644
--- a/lib/ext2fs/initialize.c
+++ b/lib/ext2fs/initialize.c
@@ -67,7 +67,7 @@
 {
 	struct ext2_super_block *sb = fs->super;
 	unsigned long bpg = sb->s_blocks_per_group;
-	unsigned int gdpb = fs->blocksize / sizeof(struct ext2_group_desc);
+	unsigned int gdpb = EXT2_DESC_PER_BLOCK(sb);
 	unsigned long max_blocks = 0xffffffff;
 	unsigned long rsv_groups;
 	unsigned int rsv_gdb;
@@ -377,6 +377,7 @@
 		fs->group_desc[i].bg_free_inodes_count =
 			fs->super->s_inodes_per_group;
 		fs->group_desc[i].bg_used_dirs_count = 0;
+		ext2fs_group_desc_csum_set(fs, i);
 	}
 	
 	c = (char) 255;
diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
index 7a0cf4e..bd568b3 100644
--- a/lib/ext2fs/inode.c
+++ b/lib/ext2fs/inode.c
@@ -167,6 +167,9 @@
 	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
 				    EXT2_FEATURE_COMPAT_LAZY_BG))
 		scan->scan_flags |= EXT2_SF_DO_LAZY;
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+		scan->scan_flags |= EXT2_SF_DO_LAZY;
 	*ret_scan = scan;
 	return 0;
 }
@@ -218,18 +221,29 @@
  */
 static errcode_t get_next_blockgroup(ext2_inode_scan scan)
 {
+	ext2_filsys fs = scan->fs;
+
 	scan->current_group++;
 	scan->groups_left--;
-			
-	scan->current_block = scan->fs->
-		group_desc[scan->current_group].bg_inode_table;
+
+	scan->current_block =fs->group_desc[scan->current_group].bg_inode_table;
 
 	scan->current_inode = scan->current_group *
-		EXT2_INODES_PER_GROUP(scan->fs->super);
+		EXT2_INODES_PER_GROUP(fs->super);
 
 	scan->bytes_left = 0;
-	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
-	scan->blocks_left = scan->fs->inode_blocks_per_group;
+	scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super);
+	scan->blocks_left = fs->inode_blocks_per_group;
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+		scan->inodes_left -=
+			fs->group_desc[scan->current_group].bg_itable_unused;
+		scan->blocks_left =
+			(scan->inodes_left +
+			 (fs->blocksize / scan->inode_size - 1)) *
+			scan->inode_size / fs->blocksize;
+	}
+
 	return 0;
 }
 
@@ -417,6 +431,8 @@
 	    (scan->fs->group_desc[scan->current_group].bg_flags &
 	     EXT2_BG_INODE_UNINIT))
 		goto force_new_group;
+	if (scan->inodes_left == 0)
+		goto force_new_group;
 	if (scan->current_block == 0) {
 		if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
 			goto force_new_group;
@@ -453,32 +469,28 @@
 		scan->ptr += scan->inode_size - extra_bytes;
 		scan->bytes_left -= scan->inode_size - extra_bytes;
 
-#ifdef EXT2FS_ENABLE_SWAPFS
+#ifdef WORDS_BIGENDIAN
 		memset(inode, 0, bufsize);
-		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
-			ext2fs_swap_inode_full(scan->fs, 
-				(struct ext2_inode_large *) inode,
-				(struct ext2_inode_large *) scan->temp_buffer, 
-				0, bufsize);
-		else
+		ext2fs_swap_inode_full(scan->fs, 
+			       (struct ext2_inode_large *) inode,
+			       (struct ext2_inode_large *) scan->temp_buffer, 
+			       0, bufsize);
+#else
+		*inode = *((struct ext2_inode *) scan->temp_buffer);
 #endif
-			*inode = *((struct ext2_inode *) scan->temp_buffer);
 		if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
 			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
 		scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
 	} else {
-#ifdef EXT2FS_ENABLE_SWAPFS
+#ifdef WORDS_BIGENDIAN
 		memset(inode, 0, bufsize);
-		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
-			ext2fs_swap_inode_full(scan->fs, 
+		ext2fs_swap_inode_full(scan->fs, 
 				(struct ext2_inode_large *) inode,
 				(struct ext2_inode_large *) scan->ptr,
 				0, bufsize);
-		else
+#else
+		memcpy(inode, scan->ptr, bufsize);
 #endif
-			memcpy(inode, scan->ptr, bufsize);
 		scan->ptr += scan->inode_size;
 		scan->bytes_left -= scan->inode_size;
 		if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
@@ -583,12 +595,10 @@
 		block_nr++;
 	}
 
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
-		ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode, 
-				       (struct ext2_inode_large *) inode, 
-				       0, bufsize);
+#ifdef WORDS_BIGENDIAN
+	ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode, 
+			       (struct ext2_inode_large *) inode, 
+			       0, bufsize);
 #endif
 
 	/* Update the inode cache */
@@ -657,16 +667,14 @@
 		w_inode = &temp_inode;
 	memset(w_inode, 0, length);
 
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
-		ext2fs_swap_inode_full(fs, w_inode, 
-				       (struct ext2_inode_large *) inode, 
-				       1, bufsize);
-	else
+#ifdef WORDS_BIGENDIAN
+	ext2fs_swap_inode_full(fs, w_inode, 
+			       (struct ext2_inode_large *) inode, 
+			       1, bufsize);
+#else
+	memcpy(w_inode, inode, bufsize);
 #endif
-		memcpy(w_inode, inode, bufsize);
-	
+
 	group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
 	offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
 		EXT2_INODE_SIZE(fs->super);
diff --git a/lib/ext2fs/inode_io.c b/lib/ext2fs/inode_io.c
index b5c08b9..0e23494 100644
--- a/lib/ext2fs/inode_io.c
+++ b/lib/ext2fs/inode_io.c
@@ -56,7 +56,11 @@
 static errcode_t inode_flush(io_channel channel);
 static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
 				int size, const void *data);
-
+static errcode_t inode_read_blk64(io_channel channel, 
+				unsigned long long block, int count, void *data);
+static errcode_t inode_write_blk64(io_channel channel, 
+				unsigned long long block, int count, const void *data);
+				
 static struct struct_io_manager struct_inode_manager = {
 	EXT2_ET_MAGIC_IO_MANAGER,
 	"Inode I/O Manager",
@@ -66,7 +70,11 @@
 	inode_read_blk,
 	inode_write_blk,
 	inode_flush,
-	inode_write_byte
+	inode_write_byte,
+	NULL,
+	NULL,
+	inode_read_blk64,
+	inode_write_blk64
 };
 
 io_manager inode_io_manager = &struct_inode_manager;
@@ -197,8 +205,8 @@
 }
 
 
-static errcode_t inode_read_blk(io_channel channel, unsigned long block,
-			       int count, void *buf)
+static errcode_t inode_read_blk64(io_channel channel,
+				unsigned long long block, int count, void *buf)
 {
 	struct inode_private_data *data;
 	errcode_t	retval;
@@ -217,8 +225,14 @@
 	return ext2fs_file_read(data->file, buf, count, 0);
 }
 
-static errcode_t inode_write_blk(io_channel channel, unsigned long block,
-				int count, const void *buf)
+static errcode_t inode_read_blk(io_channel channel, unsigned long block,
+			       int count, void *buf)
+{
+	return inode_read_blk64(channel, block, count, buf);
+}
+
+static errcode_t inode_write_blk64(io_channel channel,
+				unsigned long long block, int count, const void *buf)
 {
 	struct inode_private_data *data;
 	errcode_t	retval;
@@ -237,6 +251,12 @@
 	return ext2fs_file_write(data->file, buf, count, 0);
 }
 
+static errcode_t inode_write_blk(io_channel channel, unsigned long block, 
+				int count, const void *buf)
+{
+	return inode_write_blk64(channel, block, count, buf);
+}
+
 static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
 				 int size, const void *buf)
 {
diff --git a/lib/ext2fs/ismounted.c b/lib/ext2fs/ismounted.c
index 684e91e..d6573ad 100644
--- a/lib/ext2fs/ismounted.c
+++ b/lib/ext2fs/ismounted.c
@@ -251,10 +251,8 @@
 	if (!(f = fopen("/proc/swaps", "r")))
 		return 0;
 	/* Skip the first line */
-	fgets(buf, sizeof(buf), f);
-	while (!feof(f)) {
-		if (!fgets(buf, sizeof(buf), f))
-			break;
+	if (fgets(buf, sizeof(buf), f))
+	while (fgets(buf, sizeof(buf), f)) {
 		if ((cp = strchr(buf, ' ')) != NULL)
 			*cp = 0;
 		if ((cp = strchr(buf, '\t')) != NULL)
diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c
index d705b1c..fc54afe 100644
--- a/lib/ext2fs/openfs.c
+++ b/lib/ext2fs/openfs.c
@@ -39,11 +39,10 @@
 	    (i < fs->super->s_first_meta_bg))
 		return (group_block + i + 1);
 
-	bg = (fs->blocksize / sizeof (struct ext2_group_desc)) * i;
+	bg = EXT2_DESC_PER_BLOCK(fs->super) * i;
 	if (ext2fs_bg_has_super(fs, bg))
 		has_super = 1;
-	ret_blk = (fs->super->s_first_data_block + has_super + 
-		   (bg * fs->super->s_blocks_per_group));
+	ret_blk = ext2fs_group_first_block(fs, bg) + has_super;
 	/*
 	 * If group_block is not the normal value, we're trying to use
 	 * the backup group descriptors and superblock --- so use the
@@ -87,10 +86,13 @@
 	errcode_t	retval;
 	unsigned long	i;
 	__u32		features;
-	int		j, groups_per_block, blocks_per_group, io_flags;
+	int		groups_per_block, blocks_per_group, io_flags;
 	blk_t		group_block, blk;
 	char		*dest, *cp;
+#ifdef WORDS_BIGENDIAN
 	struct ext2_group_desc *gdp;
+	int		j;
+#endif
 	
 	EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
 
@@ -178,12 +180,13 @@
 	if (fs->orig_super)
 		memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
 
-#ifdef EXT2FS_ENABLE_SWAPFS
-	if ((fs->super->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ||
-	    (fs->flags & EXT2_FLAG_SWAP_BYTES)) {
-		fs->flags |= EXT2_FLAG_SWAP_BYTES;
-
-		ext2fs_swap_super(fs->super);
+#ifdef WORDS_BIGENDIAN
+	fs->flags |= EXT2_FLAG_SWAP_BYTES;
+	ext2fs_swap_super(fs->super);
+#else
+	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+		retval = EXT2_ET_UNIMPLEMENTED;
+		goto cleanup;
 	}
 #endif
 	
@@ -287,24 +290,38 @@
 	if (!group_block)
 		group_block = fs->super->s_first_data_block;
 	dest = (char *) fs->group_desc;
-	groups_per_block = fs->blocksize / sizeof(struct ext2_group_desc);
+	groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
 	for (i=0 ; i < fs->desc_blocks; i++) {
 		blk = ext2fs_descriptor_block_loc(fs, group_block, i);
 		retval = io_channel_read_blk(fs->io, blk, 1, dest);
 		if (retval)
 			goto cleanup;
-#ifdef EXT2FS_ENABLE_SWAPFS
-		if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
-			gdp = (struct ext2_group_desc *) dest;
-			for (j=0; j < groups_per_block; j++)
-				ext2fs_swap_group_desc(gdp++);
-		}
+#ifdef WORDS_BIGENDIAN
+		gdp = (struct ext2_group_desc *) dest;
+		for (j=0; j < groups_per_block; j++)
+			ext2fs_swap_group_desc(gdp++);
 #endif
 		dest += fs->blocksize;
 	}
 
 	fs->stride = fs->super->s_raid_stride;
 
+	/*
+	 * If recovery is from backup superblock, Clear _UNININT flags &
+	 * reset bg_itable_unused to zero
+	 */
+	if (superblock > 1 && EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+		struct ext2_group_desc *gd;
+		for (i = 0, gd = fs->group_desc; i < fs->group_desc_count;
+		     i++, gd++) {
+			gd->bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
+			gd->bg_flags &= ~EXT2_BG_INODE_UNINIT;
+			gd->bg_itable_unused = 0;
+		}
+		ext2fs_mark_super_dirty(fs);
+	}
+
 	fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
 	*ret_fs = fs;
 	return 0;
diff --git a/lib/ext2fs/read_bb.c b/lib/ext2fs/read_bb.c
index c717adc..ff7e292 100644
--- a/lib/ext2fs/read_bb.c
+++ b/lib/ext2fs/read_bb.c
@@ -86,8 +86,8 @@
 
 	rb.bb_list = *bb_list;
 	rb.err = 0;
-	retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, 0, 0,
-				      mark_bad_block, &rb);
+	retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, BLOCK_FLAG_READ_ONLY,
+				       0, mark_bad_block, &rb);
 	if (retval)
 		return retval;
 
diff --git a/lib/ext2fs/rs_bitmap.c b/lib/ext2fs/rs_bitmap.c
deleted file mode 100644
index 46653f0..0000000
--- a/lib/ext2fs/rs_bitmap.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * rs_bitmap.c --- routine for changing the size of a bitmap
- *
- * Copyright (C) 1996, 1997 Theodore Ts'o.
- *
- * %Begin-Header%
- * This file may be redistributed under the terms of the GNU Public
- * License.
- * %End-Header%
- */
-
-#include <stdio.h>
-#include <string.h>
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <fcntl.h>
-#include <time.h>
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#include "ext2_fs.h"
-#include "ext2fs.h"
-
-errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, __u32 new_real_end,
-				       ext2fs_generic_bitmap bmap)
-{
-	errcode_t	retval;
-	size_t		size, new_size;
-	__u32		bitno;
-
-	if (!bmap)
-		return EXT2_ET_INVALID_ARGUMENT;
-
-	EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_GENERIC_BITMAP);
-
-	/*
-	 * If we're expanding the bitmap, make sure all of the new
-	 * parts of the bitmap are zero.
-	 */
-	if (new_end > bmap->end) {
-		bitno = bmap->real_end;
-		if (bitno > new_end)
-			bitno = new_end;
-		for (; bitno > bmap->end; bitno--)
-			ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap);
-	}
-	if (new_real_end == bmap->real_end) {
-		bmap->end = new_end;
-		return 0;
-	}
-	
-	size = ((bmap->real_end - bmap->start) / 8) + 1;
-	new_size = ((new_real_end - bmap->start) / 8) + 1;
-
-	if (size != new_size) {
-		retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap);
-		if (retval)
-			return retval;
-	}
-	if (new_size > size)
-		memset(bmap->bitmap + size, 0, new_size - size);
-
-	bmap->end = new_end;
-	bmap->real_end = new_real_end;
-	return 0;
-}
-
-errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
-				     ext2fs_inode_bitmap bmap)
-{
-	errcode_t	retval;
-	
-	if (!bmap)
-		return EXT2_ET_INVALID_ARGUMENT;
-
-	EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_INODE_BITMAP);
-
-	bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
-	retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
-					      bmap);
-	bmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
-	return retval;
-}
-
-errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
-				     ext2fs_block_bitmap bmap)
-{
-	errcode_t	retval;
-	
-	if (!bmap)
-		return EXT2_ET_INVALID_ARGUMENT;
-
-	EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
-
-	bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
-	retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
-					      bmap);
-	bmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
-	return retval;
-}
-
diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c
index cb470b8..dd5dc46 100644
--- a/lib/ext2fs/rw_bitmaps.c
+++ b/lib/ext2fs/rw_bitmaps.c
@@ -27,30 +27,6 @@
 #include "ext2fs.h"
 #include "e2image.h"
 
-#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
-/*
- * On the PowerPC, the big-endian variant of the ext2 filesystem
- * has its bitmaps stored as 32-bit words with bit 0 as the LSB
- * of each word.  Thus a bitmap with only bit 0 set would be, as
- * a string of bytes, 00 00 00 01 00 ...
- * To cope with this, we byte-reverse each word of a bitmap if
- * we have a big-endian filesystem, that is, if we are *not*
- * byte-swapping other word-sized numbers.
- */
-#define EXT2_BIG_ENDIAN_BITMAPS
-#endif
-
-#ifdef EXT2_BIG_ENDIAN_BITMAPS
-static void ext2fs_swap_bitmap(ext2_filsys fs, char *bitmap, int nbytes)
-{
-	__u32 *p = (__u32 *) bitmap;
-	int n;
-		
-	for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
-		*p = ext2fs_swab32(*p);
-}
-#endif
-
 static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
 {
 	dgrp_t 		i;
@@ -58,10 +34,11 @@
 	int		block_nbytes, inode_nbytes;
 	unsigned int	nbits;
 	errcode_t	retval;
-	char 		*block_bitmap, *inode_bitmap;
 	char 		*block_buf, *inode_buf;
 	int		lazy_flag = 0;
 	blk_t		blk;
+	blk_t		blk_itr = fs->super->s_first_data_block;
+	ext2_ino_t	ino_itr = 1;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -71,9 +48,7 @@
 				    EXT2_FEATURE_COMPAT_LAZY_BG))
 		lazy_flag = 1;
 	inode_nbytes = block_nbytes = 0;
-	block_bitmap = inode_bitmap = 0;
 	if (do_block) {
-		block_bitmap = fs->block_map->bitmap;
 		block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
 		retval = ext2fs_get_mem(fs->blocksize, &block_buf);
 		if (retval)
@@ -81,7 +56,6 @@
 		memset(block_buf, 0xff, fs->blocksize);
 	}
 	if (do_inode) {
-		inode_bitmap = fs->inode_map->bitmap;
 		inode_nbytes = (size_t) 
 			((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
 		retval = ext2fs_get_mem(fs->blocksize, &inode_buf);
@@ -91,14 +65,18 @@
 	}
 
 	for (i = 0; i < fs->group_desc_count; i++) {
-		if (!block_bitmap || !do_block)
+		if (!do_block)
 			goto skip_block_bitmap;
 
 		if (lazy_flag && fs->group_desc[i].bg_flags &
 		    EXT2_BG_BLOCK_UNINIT) 
 			goto skip_this_block_bitmap;
  
-		memcpy(block_buf, block_bitmap, block_nbytes);
+		retval = ext2fs_get_block_bitmap_range(fs->block_map, 
+				blk_itr, block_nbytes << 3, block_buf);
+		if (retval)
+			return retval;
+
 		if (i == fs->group_desc_count - 1) {
 			/* Force bitmap padding for the last group */
 			nbits = ((fs->super->s_blocks_count
@@ -110,44 +88,36 @@
 		}
 		blk = fs->group_desc[i].bg_block_bitmap;
 		if (blk) {
-#ifdef EXT2_BIG_ENDIAN_BITMAPS
-			if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-			      (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
-				ext2fs_swap_bitmap(fs, block_buf, 
-						   block_nbytes);
-#endif
 			retval = io_channel_write_blk(fs->io, blk, 1,
 						      block_buf);
 			if (retval)
 				return EXT2_ET_BLOCK_BITMAP_WRITE;
 		}
 	skip_this_block_bitmap:
-		block_bitmap += block_nbytes;
+		blk_itr += block_nbytes << 3;
 	skip_block_bitmap:
 
-		if (!inode_bitmap || !do_inode)
+		if (!do_inode)
 			continue;
 
 		if (lazy_flag && fs->group_desc[i].bg_flags &
 		    EXT2_BG_INODE_UNINIT) 
 			goto skip_this_inode_bitmap;
  
-		memcpy(inode_buf, inode_bitmap, inode_nbytes);
+		retval = ext2fs_get_inode_bitmap_range(fs->inode_map, 
+				ino_itr, inode_nbytes << 3, inode_buf);
+		if (retval)
+			return retval;
+
 		blk = fs->group_desc[i].bg_inode_bitmap;
 		if (blk) {
-#ifdef EXT2_BIG_ENDIAN_BITMAPS
-			if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-			      (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
-				ext2fs_swap_bitmap(fs, inode_buf, 
-						   inode_nbytes);
-#endif
 			retval = io_channel_write_blk(fs->io, blk, 1,
 						      inode_buf);
 			if (retval)
 				return EXT2_ET_INODE_BITMAP_WRITE;
 		}
 	skip_this_inode_bitmap:
-		inode_bitmap += inode_nbytes;
+		ino_itr += inode_nbytes << 3;
 
 	}
 	if (do_block) {
@@ -167,17 +137,25 @@
 	char *block_bitmap = 0, *inode_bitmap = 0;
 	char *buf;
 	errcode_t retval;
-	int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
-	int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8;
+	unsigned int block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+	unsigned inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
 	int lazy_flag = 0;
+	int do_image = fs->flags & EXT2_FLAG_IMAGE_FILE;
+	unsigned int	cnt;
 	blk_t	blk;
+	blk_t	blk_itr = fs->super->s_first_data_block;
+	blk_t   blk_cnt;
+	ext2_ino_t ino_itr = 1;
+	ext2_ino_t ino_cnt;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
 	fs->write_bitmaps = ext2fs_write_bitmaps;
 
-	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
-				    EXT2_FEATURE_COMPAT_LAZY_BG))
+	if (EXT2_HAS_COMPAT_FEATURE(fs->super,
+				    EXT2_FEATURE_COMPAT_LAZY_BG) ||
+	    EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
 		lazy_flag = 1;
 
 	retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
@@ -190,8 +168,12 @@
 		retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
 		if (retval)
 			goto cleanup;
-		block_bitmap = fs->block_map->bitmap;
-	}
+		retval = ext2fs_get_mem(do_image ? fs->blocksize : 
+					block_nbytes, &block_bitmap);
+		if (retval)
+			goto cleanup;
+	} else
+		block_nbytes = 0;
 	if (do_inode) {
 		if (fs->inode_map)
 			ext2fs_free_inode_bitmap(fs->inode_map);
@@ -199,37 +181,62 @@
 		retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
 		if (retval)
 			goto cleanup;
-		inode_bitmap = fs->inode_map->bitmap;
-	}
+		retval = ext2fs_get_mem(do_image ? fs->blocksize : 
+					inode_nbytes, &inode_bitmap);
+		if (retval)
+			goto cleanup;
+	} else
+		inode_nbytes = 0;
 	ext2fs_free_mem(&buf);
 
 	if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
-		if (inode_bitmap) {
-			blk = (fs->image_header->offset_inodemap /
-			       fs->blocksize);
-			retval = io_channel_read_blk(fs->image_io, blk,
-			     -(inode_nbytes * fs->group_desc_count),
-			     inode_bitmap);
+		blk = (fs->image_header->offset_inodemap / fs->blocksize);
+		ino_cnt = fs->super->s_inodes_count;
+		while (inode_nbytes > 0) {
+			retval = io_channel_read_blk(fs->image_io, blk++,
+						     1, inode_bitmap);
 			if (retval)
 				goto cleanup;
-		}
-		if (block_bitmap) {
-			blk = (fs->image_header->offset_blockmap /
-			       fs->blocksize);
-			retval = io_channel_read_blk(fs->image_io, blk, 
-			     -(block_nbytes * fs->group_desc_count),
-			     block_bitmap);
+			cnt = fs->blocksize << 3;
+			if (cnt > ino_cnt)
+				cnt = ino_cnt;
+			retval = ext2fs_set_inode_bitmap_range(fs->inode_map, 
+					       ino_itr, cnt, inode_bitmap);
 			if (retval)
 				goto cleanup;
+			ino_itr += fs->blocksize << 3;
+			ino_cnt -= fs->blocksize << 3;
+			inode_nbytes -= fs->blocksize;
 		}
-		return 0;
+		blk = (fs->image_header->offset_blockmap /
+		       fs->blocksize);
+		blk_cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * 
+			fs->group_desc_count;
+		while (block_nbytes > 0) {
+			retval = io_channel_read_blk(fs->image_io, blk++,
+						     1, block_bitmap);
+			if (retval)
+				goto cleanup;
+			cnt = fs->blocksize << 3;
+			if (cnt > blk_cnt)
+				cnt = blk_cnt;
+			retval = ext2fs_set_block_bitmap_range(fs->block_map, 
+				       blk_itr, cnt, block_bitmap);
+			if (retval)
+				goto cleanup;
+			blk_itr += fs->blocksize << 3;
+			blk_cnt -= fs->blocksize << 3;
+			block_nbytes -= fs->blocksize;
+		}
+		goto success_cleanup;
 	}
 
 	for (i = 0; i < fs->group_desc_count; i++) {
 		if (block_bitmap) {
 			blk = fs->group_desc[i].bg_block_bitmap;
 			if (lazy_flag && fs->group_desc[i].bg_flags &
-			    EXT2_BG_BLOCK_UNINIT)
+			    EXT2_BG_BLOCK_UNINIT &&
+			    ext2fs_group_desc_csum_verify(fs, i))
 				blk = 0;
 			if (blk) {
 				retval = io_channel_read_blk(fs->io, blk,
@@ -238,19 +245,20 @@
 					retval = EXT2_ET_BLOCK_BITMAP_READ;
 					goto cleanup;
 				}
-#ifdef EXT2_BIG_ENDIAN_BITMAPS
-				if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-				      (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
-					ext2fs_swap_bitmap(fs, block_bitmap, block_nbytes);
-#endif
 			} else
 				memset(block_bitmap, 0xff, block_nbytes);
-			block_bitmap += block_nbytes;
+			cnt = block_nbytes << 3;
+			retval = ext2fs_set_block_bitmap_range(fs->block_map, 
+					       blk_itr, cnt, block_bitmap);
+			if (retval)
+				goto cleanup;
+			blk_itr += block_nbytes << 3;
 		}
 		if (inode_bitmap) {
 			blk = fs->group_desc[i].bg_inode_bitmap;
 			if (lazy_flag && fs->group_desc[i].bg_flags &
-			    EXT2_BG_INODE_UNINIT)
+			    EXT2_BG_INODE_UNINIT &&
+			    ext2fs_group_desc_csum_verify(fs, i))
 				blk = 0;
 			if (blk) {
 				retval = io_channel_read_blk(fs->io, blk,
@@ -259,16 +267,21 @@
 					retval = EXT2_ET_INODE_BITMAP_READ;
 					goto cleanup;
 				}
-#ifdef EXT2_BIG_ENDIAN_BITMAPS
-				if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
-				      (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
-					ext2fs_swap_bitmap(fs, inode_bitmap, inode_nbytes);
-#endif
 			} else
 				memset(inode_bitmap, 0xff, inode_nbytes);
-			inode_bitmap += inode_nbytes;
+			cnt = inode_nbytes << 3;
+			retval = ext2fs_set_inode_bitmap_range(fs->inode_map, 
+					       ino_itr, cnt, inode_bitmap);
+			if (retval)
+				goto cleanup;
+			ino_itr += inode_nbytes << 3;
 		}
 	}
+success_cleanup:
+	if (inode_bitmap)
+		ext2fs_free_mem(&inode_bitmap);
+	if (block_bitmap)
+		ext2fs_free_mem(&block_bitmap);
 	return 0;
 	
 cleanup:
@@ -280,6 +293,10 @@
 		ext2fs_free_mem(&fs->inode_map);
 		fs->inode_map = 0;
 	}
+	if (inode_bitmap)
+		ext2fs_free_mem(&inode_bitmap);
+	if (block_bitmap)
+		ext2fs_free_mem(&block_bitmap);
 	if (buf)
 		ext2fs_free_mem(&buf);
 	return retval;
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index e07e87c..33c7ab3 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -20,7 +20,7 @@
 #include "ext2fs.h"
 #include <ext2fs/ext2_ext_attr.h>
 
-#ifdef EXT2FS_ENABLE_SWAPFS
+#ifdef WORDS_BIGENDIAN
 void ext2fs_swap_super(struct ext2_super_block * sb)
 {
   	int i;
@@ -90,6 +90,29 @@
 	gdp->bg_checksum = ext2fs_swab16(gdp->bg_checksum);
 }
 
+void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header,
+				 struct ext2_ext_attr_header *from_header)
+{
+	int n;
+
+	to_header->h_magic    = ext2fs_swab32(from_header->h_magic);
+	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_reserved[n] =
+			ext2fs_swab32(from_header->h_reserved[n]);
+}
+
+void ext2fs_swap_ext_attr_entry(struct ext2_ext_attr_entry *to_entry,
+				struct ext2_ext_attr_entry *from_entry)
+{
+	to_entry->e_value_offs  = ext2fs_swab16(from_entry->e_value_offs);
+	to_entry->e_value_block = ext2fs_swab32(from_entry->e_value_block);
+	to_entry->e_value_size  = ext2fs_swab32(from_entry->e_value_size);
+	to_entry->e_hash	= ext2fs_swab32(from_entry->e_hash);
+}
+
 void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
 {
 	struct ext2_ext_attr_header *from_header =
@@ -98,32 +121,22 @@
 		(struct ext2_ext_attr_header *)to;
 	struct ext2_ext_attr_entry *from_entry, *to_entry;
 	char *from_end = (char *)from_header + bufsize;
-	int n;
 
 	if (to_header != from_header)
 		memcpy(to_header, from_header, bufsize);
 
-	from_entry = (struct ext2_ext_attr_entry *)from_header;
-	to_entry   = (struct ext2_ext_attr_entry *)to_header;
-
 	if (has_header) {
-		to_header->h_magic    = ext2fs_swab32(from_header->h_magic);
-		to_header->h_blocks   = ext2fs_swab32(from_header->h_blocks);
-		to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
-		for (n=0; n<4; n++)
-			to_header->h_reserved[n] =
-				ext2fs_swab32(from_header->h_reserved[n]);
+		ext2fs_swap_ext_attr_header(to_header, from_header);
+
 		from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
 		to_entry   = (struct ext2_ext_attr_entry *)(to_header+1);
+	} else {
+		from_entry = (struct ext2_ext_attr_entry *)from_header;
+		to_entry   = (struct ext2_ext_attr_entry *)to_header;
 	}
 
 	while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
-		to_entry->e_value_offs  =	
-			ext2fs_swab16(from_entry->e_value_offs);
-		to_entry->e_value_block =	
-			ext2fs_swab32(from_entry->e_value_block);
-		to_entry->e_value_size  =	
-			ext2fs_swab32(from_entry->e_value_size);
+		ext2fs_swap_ext_attr_entry(to_entry, from_entry);
 		from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
 		to_entry   = EXT2_EXT_ATTR_NEXT(to_entry);
 	}
@@ -134,6 +147,7 @@
 			    int bufsize)
 {
 	unsigned i, has_data_blocks, extra_isize, attr_magic;
+	int has_extents = 0;
 	int islnk = 0;
 	__u32 *eaf, *eat;
 
@@ -158,9 +172,14 @@
 	if (!hostorder)
 		has_data_blocks = ext2fs_inode_data_blocks(fs, 
 					   (struct ext2_inode *) t);
+	if (hostorder && (f->i_flags & EXT4_EXTENTS_FL))
+		has_extents = 1;
 	t->i_flags = ext2fs_swab32(f->i_flags);
+	if (!hostorder && (t->i_flags & EXT4_EXTENTS_FL))
+		has_extents = 1;
 	t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
-	if (!islnk || has_data_blocks ) {
+	/* extent data are swapped on access, not here */
+	if (!has_extents && (!islnk || has_data_blocks)) {
 		for (i = 0; i < EXT2_N_BLOCKS; i++)
 			t->i_block[i] = ext2fs_swab32(f->i_block[i]);
 	} else if (t != f) {
@@ -198,16 +217,7 @@
 		t->osd2.hurd2.h_i_author =
 		  ext2fs_swab32 (f->osd2.hurd2.h_i_author);
 		break;
-	case EXT2_OS_MASIX:
-		t->osd1.masix1.m_i_reserved1 =
-			ext2fs_swab32(f->osd1.masix1.m_i_reserved1);
-		t->osd2.masix2.m_i_frag = f->osd2.masix2.m_i_frag;
-		t->osd2.masix2.m_i_fsize = f->osd2.masix2.m_i_fsize;
-		t->osd2.masix2.m_pad1 = ext2fs_swab16(f->osd2.masix2.m_pad1);
-		t->osd2.masix2.m_i_reserved2[0] =
-			ext2fs_swab32(f->osd2.masix2.m_i_reserved2[0]);
-		t->osd2.masix2.m_i_reserved2[1] =
-			ext2fs_swab32(f->osd2.masix2.m_i_reserved2[1]);
+	default:
 		break;
 	}
 
diff --git a/lib/ext2fs/test_io.c b/lib/ext2fs/test_io.c
index 03d63ce..2fe10d2 100644
--- a/lib/ext2fs/test_io.c
+++ b/lib/ext2fs/test_io.c
@@ -66,6 +66,8 @@
 				 int count, const void *buf);
 static errcode_t test_set_option(io_channel channel, const char *option, 
 				 const char *arg);
+static errcode_t test_get_stats(io_channel channel, io_stats *stats);
+
 
 static struct struct_io_manager struct_test_manager = {
 	EXT2_ET_MAGIC_IO_MANAGER,
@@ -77,7 +79,8 @@
 	test_write_blk,
 	test_flush,
 	test_write_byte,
-	test_set_option
+	test_set_option,
+	test_get_stats,
 };
 
 io_manager test_io_manager = &struct_test_manager;
@@ -409,3 +412,18 @@
 	}
 	return retval;
 }
+
+static errcode_t test_get_stats(io_channel channel, io_stats *stats)
+{
+	struct test_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct test_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+	if (data->real && data->real->manager->get_stats) {
+		retval = (data->real->manager->get_stats)(data->real, stats);
+	}
+	return retval;
+}
diff --git a/lib/ext2fs/tst_csum.c b/lib/ext2fs/tst_csum.c
new file mode 100644
index 0000000..eb7377d
--- /dev/null
+++ b/lib/ext2fs/tst_csum.c
@@ -0,0 +1,127 @@
+/*
+ * This testing program verifies checksumming operations
+ *
+ * Copyright (C) 2006, 2007 by Andreas Dilger <adilger@clusterfs.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU General Public
+ * License, Version 2.  See the file COPYING for more details.
+ * %End-Header%
+ */
+
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+void print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
+{
+	__u16 crc1, crc2, crc3;
+	dgrp_t swabgroup;
+	struct ext2_group_desc *desc = &fs->group_desc[group];
+	struct ext2_super_block *sb = fs->super;
+
+#ifdef WORDS_BIGENDIAN
+	struct ext2_group_desc swabdesc = fs->group_desc[group];
+
+	/* Have to swab back to little-endian to do the checksum */
+	ext2fs_swap_group_desc(&swabdesc);
+	desc = &swabdesc;
+
+	swabgroup = ext2fs_swab32(group);
+#else
+	swabgroup = group;
+#endif
+
+	crc1 = crc16(~0, sb->s_uuid, sizeof(fs->super->s_uuid));
+	crc2 = crc16(crc1, &swabgroup, sizeof(swabgroup));
+	crc3 = crc16(crc2, desc, offsetof(struct ext2_group_desc, bg_checksum));
+	printf("%s: UUID %016Lx%016Lx(%04x), grp %u(%04x): %04x=%04x\n",
+	       msg, *(long long *)&sb->s_uuid, *(long long *)&sb->s_uuid[8],
+	       crc1, group, crc2, crc3, ext2fs_group_desc_csum(fs, group));
+}
+
+unsigned char sb_uuid[16] = { 0x4f, 0x25, 0xe8, 0xcf, 0xe7, 0x97, 0x48, 0x23,
+			      0xbe, 0xfa, 0xa7, 0x88, 0x4b, 0xae, 0xec, 0xdb };
+
+main(int argc, char **argv)
+{
+	struct ext2_super_block param;
+	errcode_t		retval;
+	ext2_filsys		fs;
+	int			i;
+	__u16 csum1, csum2, csum_known = 0xd3a4;
+
+	memset(&param, 0, sizeof(param));
+	param.s_blocks_count = 32768;
+
+	retval = ext2fs_initialize("test fs", 0, &param,
+				   test_io_manager, &fs);
+	if (retval) {
+		com_err("setup", retval,
+			"While initializing filesystem");
+		exit(1);
+	}
+	memcpy(fs->super->s_uuid, sb_uuid, 16);
+	fs->super->s_feature_ro_compat = EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
+
+	for (i=0; i < fs->group_desc_count; i++) {
+		fs->group_desc[i].bg_block_bitmap = 124;
+		fs->group_desc[i].bg_inode_bitmap = 125;
+		fs->group_desc[i].bg_inode_table = 126;
+		fs->group_desc[i].bg_free_blocks_count = 31119;
+		fs->group_desc[i].bg_free_inodes_count = 15701;
+		fs->group_desc[i].bg_used_dirs_count = 2;
+		fs->group_desc[i].bg_flags = 0;
+	};
+
+	csum1 = ext2fs_group_desc_csum(fs, 0);
+	print_csum("csum0000", fs, 0);
+
+	if (csum1 != csum_known) {
+		printf("checksum for group 0 should be %04x\n", csum_known);
+		exit(1);
+	}
+	csum2 = ext2fs_group_desc_csum(fs, 1);
+	print_csum("csum0001", fs, 1);
+	if (csum1 == csum2) {
+		printf("checksums for different groups shouldn't match\n");
+		exit(1);
+	}
+	csum2 = ext2fs_group_desc_csum(fs, 2);
+	print_csum("csumffff", fs, 2);
+	if (csum1 == csum2) {
+		printf("checksums for different groups shouldn't match\n");
+		exit(1);
+	}
+	fs->group_desc[0].bg_checksum = csum1;
+	csum2 = ext2fs_group_desc_csum(fs, 0);
+	print_csum("csum_set", fs, 0);
+	if (csum1 != csum2) {
+		printf("checksums should not depend on checksum field\n");
+		exit(1);
+	}
+	if (!ext2fs_group_desc_csum_verify(fs, 0)) {
+		printf("checksums should verify against gd_checksum\n");
+		exit(1);
+	}
+	memset(fs->super->s_uuid, 0x30, sizeof(fs->super->s_uuid));
+	print_csum("new_uuid", fs, 0);
+	if (ext2fs_group_desc_csum_verify(fs, 0) != 0) {
+		printf("checksums for different filesystems shouldn't match\n");
+		exit(1);
+	}
+	csum1 = fs->group_desc[0].bg_checksum = ext2fs_group_desc_csum(fs, 0);
+	print_csum("csum_new", fs, 0);
+	fs->group_desc[0].bg_free_blocks_count = 1;
+	csum2 = ext2fs_group_desc_csum(fs, 0);
+	print_csum("csum_blk", fs, 0);
+	if (csum1 == csum2) {
+		printf("checksums for different data shouldn't match\n");
+		exit(1);
+	}
+
+	return 0;
+}
diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index 4ede000..eedbcdb 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -70,6 +70,7 @@
 	int	access_time;
 	ext2_loff_t offset;
 	struct unix_cache cache[CACHE_SIZE];
+	struct struct_io_stats io_stats;
 };
 
 static errcode_t unix_open(const char *name, int flags, io_channel *channel);
@@ -84,9 +85,14 @@
 				int size, const void *data);
 static errcode_t unix_set_option(io_channel channel, const char *option, 
 				 const char *arg);
-
+static errcode_t unix_get_stats(io_channel channel, io_stats *stats)
+;
 static void reuse_cache(io_channel channel, struct unix_private_data *data,
-		 struct unix_cache *cache, unsigned long block);
+		 struct unix_cache *cache, unsigned long long block);
+static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
+			       int count, void *data);
+static errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
+				int count, const void *data);
 
 /* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
  * does not know buffered block devices - everything is raw. */
@@ -110,18 +116,37 @@
 #else
 	unix_write_byte,
 #endif
-	unix_set_option
+	unix_set_option,
+	unix_get_stats,
+	unix_read_blk64,
+	unix_write_blk64,
 };
 
 io_manager unix_io_manager = &struct_unix_manager;
 
+static errcode_t unix_get_stats(io_channel channel, io_stats *stats)
+{
+	errcode_t 	retval = 0;
+
+	struct unix_private_data *data;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct unix_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+	if (stats)
+		*stats = &data->io_stats;
+
+	return retval;
+}
+
 /*
  * Here are the raw I/O functions
  */
 #ifndef NEED_BOUNCE_BUFFER
 static errcode_t raw_read_blk(io_channel channel,
 			      struct unix_private_data *data,
-			      unsigned long block,
+			      unsigned long long block,
 			      int count, void *buf)
 {
 	errcode_t	retval;
@@ -130,6 +155,7 @@
 	int		actual = 0;
 
 	size = (count < 0) ? -count : count * channel->block_size;
+	data->io_stats.bytes_read += size;
 	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
 	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
 		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
@@ -168,6 +194,7 @@
 	char		sector[BLOCKALIGN];
 
 	size = (count < 0) ? -count : count * channel->block_size;
+	data->io_stats.bytes_read += size;
 	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
 #ifdef DEBUG
 	printf("count=%d, size=%d, block=%lu, blk_size=%d, location=%llx\n",
@@ -208,7 +235,7 @@
 
 static errcode_t raw_write_blk(io_channel channel,
 			       struct unix_private_data *data,
-			       unsigned long block,
+			       unsigned long long block,
 			       int count, const void *buf)
 {
 	ssize_t		size;
@@ -224,6 +251,7 @@
 		else
 			size = count * channel->block_size;
 	}
+	data->io_stats.bytes_written += size;
 
 	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
 	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
@@ -296,7 +324,7 @@
  * entry to that should be reused.
  */
 static struct unix_cache *find_cached_block(struct unix_private_data *data,
-					    unsigned long block,
+					    unsigned long long block,
 					    struct unix_cache **eldest)
 {
 	struct unix_cache	*cache, *unused_cache, *oldest_cache;
@@ -326,7 +354,7 @@
  * Reuse a particular cache entry for another block.
  */
 static void reuse_cache(io_channel channel, struct unix_private_data *data,
-		 struct unix_cache *cache, unsigned long block)
+		 struct unix_cache *cache, unsigned long long block)
 {
 	if (cache->dirty && cache->in_use)
 		raw_write_blk(channel, data, cache->block, 1, cache->buf);
@@ -407,6 +435,7 @@
 
 	memset(data, 0, sizeof(struct unix_private_data));
 	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
+	data->io_stats.num_fields = 2;
 
 	if ((retval = alloc_cache(io, data)))
 		goto cleanup;
@@ -522,7 +551,7 @@
 }
 
 
-static errcode_t unix_read_blk(io_channel channel, unsigned long block,
+static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
 			       int count, void *buf)
 {
 	struct unix_private_data *data;
@@ -587,7 +616,13 @@
 #endif /* NO_IO_CACHE */
 }
 
-static errcode_t unix_write_blk(io_channel channel, unsigned long block,
+static errcode_t unix_read_blk(io_channel channel, unsigned long block,
+			       int count, void *buf)
+{
+	return unix_read_blk64(channel, block, count, buf);
+}
+
+static errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
 				int count, const void *buf)
 {
 	struct unix_private_data *data;
@@ -639,6 +674,12 @@
 #endif /* NO_IO_CACHE */
 }
 
+static errcode_t unix_write_blk(io_channel channel, unsigned long block,
+				int count, const void *buf)
+{
+	return unix_write_blk64(channel, block, count, buf);
+}
+
 static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
 				 int size, const void *buf)
 {
diff --git a/lib/ss/ss.pc.in b/lib/ss/ss.pc.in
index 0218fd5..ce284fc 100644
--- a/lib/ss/ss.pc.in
+++ b/lib/ss/ss.pc.in
@@ -8,4 +8,5 @@
 Version: @E2FSPROGS_VERSION@
 Requires: com_err
 Cflags: -I${includedir} 
-Libs: -L${libdir} -lss @DLOPEN_LIB@
+Libs: -L${libdir} -lss
+Libs.private: @DLOPEN_LIB@
diff --git a/misc/Makefile.in b/misc/Makefile.in
index b4c39ee..bf04e65 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -80,7 +80,7 @@
 
 default_profile.c: $(srcdir)/mke2fs.conf $(srcdir)/profile-to-c.awk
 	@echo "	PROFILE_TO_C mke2fs.conf"
-	$(AWK) -f $(srcdir)/profile-to-c.awk < $(srcdir)/mke2fs.conf \
+	@$(AWK) -f $(srcdir)/profile-to-c.awk < $(srcdir)/mke2fs.conf \
 		>  default_profile.c
 profile.o:
 	@echo "	CC $<"
diff --git a/misc/badblocks.c b/misc/badblocks.c
index 88c5a74..709effe 100644
--- a/misc/badblocks.c
+++ b/misc/badblocks.c
@@ -67,13 +67,13 @@
 static int force = 0;			/* force check of mounted device */
 static int t_flag = 0;			/* number of test patterns */
 static int t_max = 0;			/* allocated test patterns */
-static unsigned long *t_patts = NULL;	/* test patterns */
+static unsigned int *t_patts = NULL;	/* test patterns */
 static int current_O_DIRECT = 0;	/* Current status of O_DIRECT flag */
 static int exclusive_ok = 0;
 
 #define T_INC 32
 
-int sys_page_size = 4096;
+unsigned int sys_page_size = 4096;
 
 static void usage(void)
 {
@@ -90,8 +90,8 @@
 	exit(1);
 }
 
-static unsigned long currently_testing = 0;
-static unsigned long num_blocks = 0;
+static blk_t currently_testing = 0;
+static blk_t num_blocks = 0;
 static ext2_badblocks_list bb_list = NULL;
 static FILE *out;
 static blk_t next_bad = 0;
@@ -124,14 +124,14 @@
  * This routine reports a new bad block.  If the bad block has already
  * been seen before, then it returns 0; otherwise it returns 1.
  */
-static int bb_output (unsigned long bad)
+static int bb_output (blk_t bad)
 {
 	errcode_t errcode;
 
 	if (ext2fs_badblocks_list_test(bb_list, bad))
 		return 0;
 
-	fprintf(out, "%lu\n", bad);
+	fprintf(out, "%lu\n", (unsigned long) bad);
 	fflush(out);
 
 	errcode = ext2fs_badblocks_list_add (bb_list, bad);
@@ -151,7 +151,8 @@
 
 static void print_status(void)
 {
-	fprintf(stderr, "%15ld/%15ld", currently_testing, num_blocks);
+	fprintf(stderr, "%15lu/%15lu", (unsigned long) currently_testing, 
+		(unsigned long) num_blocks);
 	fputs("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", stderr);
 	fflush (stderr);
 }
@@ -197,7 +198,7 @@
 }
 
 static void set_o_direct(int dev, unsigned char *buffer, size_t size,
-			 unsigned long current_block)
+			 blk_t current_block)
 {
 #ifdef O_DIRECT
 	int new_flag = O_DIRECT;
@@ -221,13 +222,13 @@
 }
 
 
-static void pattern_fill(unsigned char *buffer, unsigned long pattern,
+static void pattern_fill(unsigned char *buffer, unsigned int pattern,
 			 size_t n)
 {
 	unsigned int	i, nb;
 	unsigned char	bpattern[sizeof(pattern)], *ptr;
 	
-	if (pattern == (unsigned long) ~0) {
+	if (pattern == (unsigned int) ~0) {
 		for (ptr = buffer; ptr < buffer + n; ptr++) {
 			(*ptr) = random() % (1 << (8 * sizeof(char)));
 		}
@@ -262,8 +263,8 @@
  * Perform a read of a sequence of blocks; return the number of blocks
  *    successfully sequentially read.
  */
-static long do_read (int dev, unsigned char * buffer, int try, int block_size,
-		     unsigned long current_block)
+static int do_read (int dev, unsigned char * buffer, int try, int block_size,
+		    blk_t current_block)
 {
 	long got;
 
@@ -291,8 +292,8 @@
  * Perform a write of a sequence of blocks; return the number of blocks
  *    successfully sequentially written.
  */
-static long do_write (int dev, unsigned char * buffer, int try, int block_size,
-		     unsigned long current_block)
+static int do_write(int dev, unsigned char * buffer, int try, int block_size,
+		    unsigned long current_block)
 {
 	long got;
 
@@ -327,13 +328,13 @@
 		com_err(program_name, retval, _("during ext2fs_sync_device"));
 }
 
-static unsigned int test_ro (int dev, unsigned long last_block,
-			     int block_size, unsigned long from_count,
-			     unsigned long blocks_at_once)
+static unsigned int test_ro (int dev, blk_t last_block,
+			     int block_size, blk_t from_count,
+			     unsigned int blocks_at_once)
 {
 	unsigned char * blkbuf;
 	int try;
-	long got;
+	int got;
 	unsigned int bb_count = 0;
 	errcode_t errcode;
 
@@ -358,8 +359,9 @@
 		exit (1);
 	}
 	if (v_flag) {
-	    fprintf (stderr, _("Checking blocks %lu to %lu\n"), from_count,
-		     last_block - 1);
+		fprintf (stderr, _("Checking blocks %lu to %lu\n"), 
+			 (unsigned long) from_count, 
+			 (unsigned long) last_block - 1);
 	}
 	if (t_flag) {
 		fputs(_("Checking for bad blocks in read-only mode\n"), stderr);
@@ -404,7 +406,7 @@
 		if (got == try) {
 			try = blocks_at_once;
 			/* recover page-aligned offset for O_DIRECT */
-			if ( blocks_at_once >= (unsigned long) (sys_page_size >> 9)
+			if ( (blocks_at_once >= sys_page_size >> 9)
 			     && (currently_testing % (sys_page_size >> 9)!= 0))
 				try -= (sys_page_size >> 9)
 					- (currently_testing 
@@ -430,13 +432,13 @@
 	return bb_count;
 }
 
-static unsigned int test_rw (int dev, unsigned long last_block,
-			     int block_size, unsigned long from_count,
-			     unsigned long blocks_at_once)
+static unsigned int test_rw (int dev, blk_t last_block,
+			     int block_size, blk_t from_count,
+			     unsigned int blocks_at_once)
 {
 	unsigned char *buffer, *read_buffer;
-	const unsigned long patterns[] = {0xaa, 0x55, 0xff, 0x00};
-	const unsigned long *pattern;
+	const unsigned int patterns[] = {0xaa, 0x55, 0xff, 0x00};
+	const unsigned int *pattern;
 	int i, try, got, nr_pattern, pat_idx;
 	unsigned int bb_count = 0;
 
@@ -454,7 +456,8 @@
 		fputs(_("Checking for bad blocks in read-write mode\n"), 
 		      stderr);
 		fprintf(stderr, _("From block %lu to %lu\n"),
-			 from_count, last_block);
+			(unsigned long) from_count, 
+			(unsigned long) last_block);
 	}
 	if (t_flag) {
 		pattern = t_patts;
@@ -484,7 +487,7 @@
 			if (got == try) {
 				try = blocks_at_once;
 				/* recover page-aligned offset for O_DIRECT */
-				if ( blocks_at_once >= (unsigned long) (sys_page_size >> 9)
+				if ( (blocks_at_once >= sys_page_size >> 9)
 				     && (currently_testing % 
 					 (sys_page_size >> 9)!= 0))
 					try -= (sys_page_size >> 9)
@@ -528,7 +531,7 @@
 			}
 			currently_testing += got;
 			/* recover page-aligned offset for O_DIRECT */
-			if ( blocks_at_once >= (unsigned long) (sys_page_size >> 9)
+			if ( (blocks_at_once >= sys_page_size >> 9)
 			     && (currently_testing % (sys_page_size >> 9)!= 0))
 				try = blocks_at_once - (sys_page_size >> 9)
 					- (currently_testing 
@@ -555,17 +558,18 @@
 	int	num;
 };
 
-static unsigned int test_nd (int dev, unsigned long last_block,
-			     int block_size, unsigned long from_count,
-			     unsigned long blocks_at_once)
+static unsigned int test_nd (int dev, blk_t last_block,
+			     int block_size, blk_t from_count,
+			     unsigned int blocks_at_once)
 {
 	unsigned char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
 	unsigned char *test_base, *save_base, *read_base;
 	int try, i;
-	const unsigned long patterns[] = { ~0 };
-	const unsigned long *pattern;
+	const unsigned int patterns[] = { ~0 };
+	const unsigned int *pattern;
 	int nr_pattern, pat_idx;
-	long got, used2, written, save_currently_testing;
+	int got, used2, written;
+	blk_t save_currently_testing;
 	struct saved_blk_record *test_record;
 	/* This is static to prevent being clobbered by the longjmp */
 	static int num_saved;
@@ -601,7 +605,8 @@
 	flush_bufs();
 	if (v_flag) {
 	    fputs(_("Checking for bad blocks in non-destructive read-write mode\n"), stderr);
-	    fprintf (stderr, _("From block %lu to %lu\n"), from_count, last_block);
+	    fprintf (stderr, _("From block %lu to %lu\n"), 
+		     (unsigned long) from_count, (unsigned long) last_block);
 	}
 	if (s_flag || v_flag > 1) {
 		fputs(_("Checking for bad blocks (non-destructive read-write test)\n"), stderr);
@@ -682,7 +687,8 @@
 			if (written != got)
 				com_err (program_name, errno,
 					 _("during test data write, block %lu"),
-					 currently_testing + written);
+					 (unsigned long) currently_testing + 
+					 written);
 
 			buf_used += got;
 			save_ptr += got * block_size;
@@ -813,27 +819,43 @@
 
 }
 
+/*
+ * This function will convert a string to an unsigned long, printing
+ * an error message if it fails, and returning success or failure in err.
+ */
+static unsigned int parse_uint(const char *str, const char *descr)
+{
+	char		*tmp;
+	unsigned long	ret;
+	
+	ret = strtoul(str, &tmp, 0);
+	if (*tmp || errno || (ret > UINT_MAX) ||
+	    (ret == ULONG_MAX && errno == ERANGE)) {
+		com_err (program_name, 0, _("invalid %s - %s"), descr, str);
+		exit (1);
+	}
+	return ret;
+}
 
 int main (int argc, char ** argv)
 {
 	int c;
-	char * tmp;
 	char * device_name;
 	char * host_device_name = NULL;
 	char * input_file = NULL;
 	char * output_file = NULL;
 	FILE * in = NULL;
 	int block_size = 1024;
-	unsigned long blocks_at_once = 64;
+	unsigned int blocks_at_once = 64;
 	blk_t last_block, from_count;
 	int num_passes = 0;
 	int passes_clean = 0;
 	int dev;
 	errcode_t errcode;
-	unsigned long pattern;
-	unsigned int (*test_func)(int, unsigned long,
-				  int, unsigned long,
-				  unsigned long);
+	unsigned int pattern;
+	unsigned int (*test_func)(int, blk_t,
+				  int, blk_t,
+				  unsigned int);
 	int open_flag = 0;
 	long sysval;
 
@@ -865,8 +887,8 @@
 	while ((c = getopt (argc, argv, "b:fi:o:svwnc:p:h:t:X")) != EOF) {
 		switch (c) {
 		case 'b':
-			block_size = strtoul (optarg, &tmp, 0);
-			if (*tmp || block_size > 4096) {
+			block_size = parse_uint(optarg, "block size");
+			if (block_size > 4096) {
 				com_err (program_name, 0,
 					 _("bad block size - %s"), optarg);
 				exit (1);
@@ -900,27 +922,18 @@
 			w_flag = 2;
 			break;
 		case 'c':
-			blocks_at_once = strtoul (optarg, &tmp, 0);
-			if (*tmp) {
-				com_err (program_name, 0,
-					 "bad simultaneous block count - %s", optarg);
-				exit (1);
-			}
+			blocks_at_once = parse_uint(optarg, "blocks at once");
 			break;
 		case 'p':
-			num_passes = strtoul (optarg, &tmp, 0);
-			if (*tmp) {
-				com_err (program_name, 0,
-				    "bad number of clean passes - %s", optarg);
-				exit (1);
-			}
+			num_passes = parse_uint(optarg, 
+						"number of clean passes");
 			break;
 		case 'h':
 			host_device_name = optarg;
 			break;
 		case 't':
 			if (t_flag + 1 > t_max) {
-				unsigned long *t_patts_new;
+				unsigned int *t_patts_new;
 
 				t_patts_new = realloc(t_patts, t_max + T_INC);
 				if (!t_patts_new) {
@@ -936,14 +949,8 @@
 			if (!strcmp(optarg, "r") || !strcmp(optarg,"random")) {
 				t_patts[t_flag++] = ~0;
 			} else {
-				pattern = strtoul(optarg, &tmp, 0);
-				if (*tmp) {
-					com_err(program_name, 0,
-					_("invalid test_pattern: %s\n"),
-						optarg);
-					exit(1);
-				}
-				if (pattern == (unsigned long) ~0)
+				pattern = parse_uint(optarg, "test pattern");
+				if (pattern == (unsigned int) ~0)
 					pattern = 0xffff;
 				t_patts[t_flag++] = pattern;
 			}
@@ -962,7 +969,7 @@
 			  "in read-only mode"));
 			exit(1);
 		}
-		if (t_patts && (t_patts[0] == (unsigned long) ~0)) {
+		if (t_patts && (t_patts[0] == (unsigned int) ~0)) {
 			com_err(program_name, 0,
 			_("Random test_pattern is not allowed "
 			  "in read-only mode"));
@@ -989,30 +996,18 @@
 		}
 	} else {
 		errno = 0;
-		last_block = strtoul (argv[optind], &tmp, 0);
+		last_block = parse_uint(argv[optind], "last block");
 		printf("last_block = %d (%s)\n", last_block, argv[optind]);
-		if (*tmp || errno || 
-		    (last_block == ULONG_MAX && errno == ERANGE)) {
-			com_err (program_name, 0, _("invalid blocks count - %s"),
-				 argv[optind]);
-			exit (1);
-		}
 		last_block++;
 		optind++;
 	}
 	if (optind <= argc-1) {
 		errno = 0;
-		from_count = strtoul (argv[optind], &tmp, 0);
+		from_count = parse_uint(argv[optind], "start block");
 		printf("from_count = %d\n", from_count);
-		if (*tmp || errno ||
-		    (from_count == ULONG_MAX && errno == ERANGE)) {
-			com_err (program_name, 0, _("invalid starting block - %s"),
-				 argv[optind]);
-			exit (1);
-		}
 	} else from_count = 0;
 	if (from_count >= last_block) {
-	    com_err (program_name, 0, _("invalid starting block (%d): must be less than %lu"),
+	    com_err (program_name, 0, _("invalid starting block (%lu): must be less than %lu"),
 		     (unsigned long) from_count, (unsigned long) last_block);
 	    exit (1);
 	}
diff --git a/misc/chattr.1.in b/misc/chattr.1.in
index 2b48fb0..2334675 100644
--- a/misc/chattr.1.in
+++ b/misc/chattr.1.in
@@ -5,7 +5,7 @@
 .SH SYNOPSIS
 .B chattr
 [
-.B \-RV
+.B \-RVf
 ]
 [
 .B \-v
@@ -34,12 +34,13 @@
 .TP
 .B \-R
 Recursively change attributes of directories and their contents.
-Symbolic links encountered during recursive directory traversals are
-ignored.
 .TP
 .B \-V
 Be verbose with chattr's output and print the program version.
 .TP
+.B \-f
+Suppress most error messages.
+.TP
 .BI \-v " version"
 Set the file's version/generation number.
 .SH ATTRIBUTES
diff --git a/misc/chattr.c b/misc/chattr.c
index c6d8d9f..daae163 100644
--- a/misc/chattr.c
+++ b/misc/chattr.c
@@ -65,6 +65,7 @@
 
 static int recursive;
 static int verbose;
+static int silent;
 
 static unsigned long af;
 static unsigned long rf;
@@ -80,8 +81,8 @@
 
 static void usage(void)
 {
-	fprintf(stderr, 
-		_("Usage: %s [-RV] [-+=AacDdijsSu] [-v version] files...\n"),
+	fprintf(stderr,
+		_("Usage: %s [-RVf] [-+=AacDdijsSu] [-v version] files...\n"),
 		program_name);
 	exit(1);
 }
@@ -137,6 +138,10 @@
 				verbose = 1;
 				continue;
 			}
+			if (*p == 'f') {
+				silent = 1;
+				continue;
+			}
 			if (*p == 'v') {
 				(*i)++;
 				if (*i >= argc)
@@ -144,7 +149,7 @@
 				version = strtol (argv[*i], &tmp, 0);
 				if (*tmp) {
 					com_err (program_name, 0,
-						 _("bad version - %s\n"), 
+						 _("bad version - %s\n"),
 						 argv[*i]);
 					usage ();
 				}
@@ -180,28 +185,19 @@
 	return 1;
 }
 
-static int chattr_dir_proc (const char *, struct dirent *, void *);
+static int chattr_dir_proc(const char *, struct dirent *, void *);
 
-static void change_attributes (const char * name)
+static int change_attributes(const char * name)
 {
 	unsigned long flags;
 	STRUCT_STAT	st;
 
 	if (LSTAT (name, &st) == -1) {
-		com_err (program_name, errno, _("while trying to stat %s"), 
-			 name);
-		return;
+		if (!silent)
+			com_err (program_name, errno,
+				 _("while trying to stat %s"), name);
+		return -1;
 	}
-	if (S_ISLNK(st.st_mode) && recursive)
-		return;
-
-	/* Don't try to open device files, fifos etc.  We probably
-           ought to display an error if the file was explicitly given
-           on the command line (whether or not recursive was
-           requested).  */
-	if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) &&
-	    !S_ISDIR(st.st_mode))
-		return;
 
 	if (set) {
 		if (verbose) {
@@ -212,10 +208,12 @@
 		if (fsetflags (name, sf) == -1)
 			perror (name);
 	} else {
-		if (fgetflags (name, &flags) == -1)
-			com_err (program_name, errno,
-			         _("while reading flags on %s"), name);
-		else {
+		if (fgetflags (name, &flags) == -1) {
+			if (!silent)
+				com_err (program_name, errno,
+					 _("while reading flags on %s"), name);
+			return -1;
+		} else {
 			if (rem)
 				flags &= ~rf;
 			if (add)
@@ -227,25 +225,36 @@
 			}
 			if (!S_ISDIR(st.st_mode))
 				flags &= ~EXT2_DIRSYNC_FL;
-			if (fsetflags (name, flags) == -1)
-				com_err (program_name, errno,
-				         _("while setting flags on %s"), name);
+			if (fsetflags (name, flags) == -1) {
+				if (!silent)
+					com_err(program_name, errno,
+						_("while setting flags on %s"),
+						name);
+				return -1;
+			}
 		}
 	}
 	if (set_version) {
 		if (verbose)
 			printf (_("Version of %s set as %lu\n"), name, version);
-		if (fsetversion (name, version) == -1)
-			com_err (program_name, errno,
-			         _("while setting version on %s"), name);
+		if (fsetversion (name, version) == -1) {
+			if (!silent)
+				com_err (program_name, errno,
+					 _("while setting version on %s"),
+					 name);
+			return -1;
+		}
 	}
 	if (S_ISDIR(st.st_mode) && recursive)
-		iterate_on_dir (name, chattr_dir_proc, NULL);
+		return iterate_on_dir (name, chattr_dir_proc, NULL);
+	return 0;
 }
 
 static int chattr_dir_proc (const char * dir_name, struct dirent * de,
 			    void * private EXT2FS_ATTR((unused)))
 {
+	int ret = 0;
+
 	if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) {
 	        char *path;
 
@@ -253,19 +262,20 @@
 		if (!path) {
 			fprintf(stderr, _("Couldn't allocate path variable "
 					  "in chattr_dir_proc"));
-			exit(1);
+			return -1;
 		}
-		sprintf (path, "%s/%s", dir_name, de->d_name);
-		change_attributes (path);
+		sprintf(path, "%s/%s", dir_name, de->d_name);
+		ret = change_attributes(path);
 		free(path);
 	}
-	return 0;
+	return ret;
 }
 
 int main (int argc, char ** argv)
 {
 	int i, j;
 	int end_arg = 0;
+	int err, retval = 0;
 
 #ifdef ENABLE_NLS
 	setlocale(LC_MESSAGES, "");
@@ -303,7 +313,10 @@
 	if (verbose)
 		fprintf (stderr, "chattr %s (%s)\n",
 			 E2FSPROGS_VERSION, E2FSPROGS_DATE);
-	for (j = i; j < argc; j++)
-		change_attributes (argv[j]);
-	exit(0);
+	for (j = i; j < argc; j++) {
+		err = change_attributes (argv[j]);
+		if (err)
+			retval = 1;
+	}
+	exit(retval);
 }
diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
index 394f8b2..b0bdd7d 100644
--- a/misc/dumpe2fs.c
+++ b/misc/dumpe2fs.c
@@ -112,14 +112,17 @@
 {
 	int first = 1, bg_flags;
 
-	if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_LAZY_BG)
+	if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_LAZY_BG ||
+	    fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
 		bg_flags = fs->group_desc[i].bg_flags;
 	else
 		bg_flags = 0;
 
-	print_bg_opt(bg_flags, EXT2_BG_INODE_UNINIT, "Inode not init",
+	print_bg_opt(bg_flags, EXT2_BG_INODE_UNINIT, "INODE_UNINIT",
  		     &first);
-	print_bg_opt(bg_flags, EXT2_BG_BLOCK_UNINIT, "Block not init",
+	print_bg_opt(bg_flags, EXT2_BG_BLOCK_UNINIT, "BLOCK_UNINIT",
+ 		     &first);
+	print_bg_opt(bg_flags, EXT2_BG_INODE_ZEROED, "ITABLE_ZEROED",
  		     &first);
 	if (!first)
 		fputc(']', stdout);
@@ -134,12 +137,18 @@
 	blk_t	super_blk, old_desc_blk, new_desc_blk;
 	char *block_bitmap=NULL, *inode_bitmap=NULL;
 	int inode_blocks_per_group, old_desc_blocks, reserved_gdt;
+	int		block_nbytes, inode_nbytes;
 	int has_super;
+	blk_t		blk_itr = fs->super->s_first_data_block;
+	ext2_ino_t	ino_itr = 1;
+
+	block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+	inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
 
 	if (fs->block_map)
-		block_bitmap = fs->block_map->bitmap;
+		block_bitmap = malloc(block_nbytes);
 	if (fs->inode_map)
-		inode_bitmap = fs->inode_map->bitmap;
+		inode_bitmap = malloc(inode_nbytes);
 
 	inode_blocks_per_group = ((fs->super->s_inodes_per_group *
 				   EXT2_INODE_SIZE(fs->super)) +
@@ -163,6 +172,10 @@
 		print_range(first_block, last_block);
 		fputs(")", stdout);
 		print_bg_opts(fs, i);
+		if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
+			printf(_("  Checksum 0x%04x, unused inodes %d\n"),
+			       fs->group_desc[i].bg_checksum,
+			       fs->group_desc[i].bg_itable_unused);
 		has_super = ((i==0) || super_blk);
 		if (has_super) {
 			printf (_("  %s superblock at "),
@@ -204,25 +217,33 @@
 		diff = fs->group_desc[i].bg_inode_table - first_block;
 		if (diff > 0)
 			printf(" (+%ld)", diff);
-		printf (_("\n  %d free blocks, %d free inodes, "
-			  "%d directories\n"),
+		printf (_("\n  %u free blocks, %u free inodes, "
+			  "%u directories%s"),
 			fs->group_desc[i].bg_free_blocks_count,
 			fs->group_desc[i].bg_free_inodes_count,
-			fs->group_desc[i].bg_used_dirs_count);
+			fs->group_desc[i].bg_used_dirs_count,
+			fs->group_desc[i].bg_itable_unused ? "" : "\n");
+		if (fs->group_desc[i].bg_itable_unused)
+			printf (_(", %u unused inodes\n"),
+				fs->group_desc[i].bg_itable_unused);
 		if (block_bitmap) {
 			fputs(_("  Free blocks: "), stdout);
+			ext2fs_get_block_bitmap_range(fs->block_map, 
+				 blk_itr, block_nbytes << 3, block_bitmap);
 			print_free (i, block_bitmap,
 				    fs->super->s_blocks_per_group,
 				    fs->super->s_first_data_block);
 			fputc('\n', stdout);
-			block_bitmap += fs->super->s_blocks_per_group / 8;
+			blk_itr += fs->super->s_blocks_per_group;
 		}
 		if (inode_bitmap) {
 			fputs(_("  Free inodes: "), stdout);
+			ext2fs_get_inode_bitmap_range(fs->inode_map, 
+				 ino_itr, inode_nbytes << 3, inode_bitmap);
 			print_free (i, inode_bitmap,
 				    fs->super->s_inodes_per_group, 1);
 			fputc('\n', stdout);
-			inode_bitmap += fs->super->s_inodes_per_group / 8;
+			ino_itr += fs->super->s_inodes_per_group;
 		}
 	}
 }
@@ -326,9 +347,9 @@
 static void parse_extended_opts(const char *opts, blk_t *superblock, 
 				int *blocksize)
 {
-	char	*buf, *token, *next, *p, *arg, *badopt = "";
+	char	*buf, *token, *next, *p, *arg, *badopt = 0;
 	int	len;
-	int	usage = 0;
+	int	do_usage = 0;
 
 	len = strlen(opts);
 	buf = malloc(len+1);
@@ -353,7 +374,7 @@
 		if (strcmp(token, "superblock") == 0 ||
 		    strcmp(token, "sb") == 0) {
 			if (!arg) {
-				usage++;
+				do_usage++;
 				badopt = token;
 				continue;
 			}
@@ -362,13 +383,13 @@
 				fprintf(stderr,
 					_("Invalid superblock parameter: %s\n"),
 					arg);
-				usage++;
+				do_usage++;
 				continue;
 			}
 		} else if (strcmp(token, "blocksize") == 0 ||
 			   strcmp(token, "bs") == 0) {
 			if (!arg) {
-				usage++;
+				do_usage++;
 				badopt = token;
 				continue;
 			}
@@ -377,15 +398,15 @@
 				fprintf(stderr,
 					_("Invalid blocksize parameter: %s\n"),
 					arg);
-				usage++;
+				do_usage++;
 				continue;
 			}
 		} else {
-			usage++;
+			do_usage++;
 			badopt = token;
 		}
 	}
-	if (usage) {
+	if (do_usage) {
 		fprintf(stderr, _("\nBad extended option(s) specified: %s\n\n"
 			"Extended options are separated by commas, "
 			"and may take an argument which\n"
@@ -393,7 +414,7 @@
 			"Valid extended options are:\n"
 			"\tsuperblock=<superblock number>\n"
 			"\tblocksize=<blocksize>\n"),
-			badopt);
+			badopt ? badopt : "");
 		free(buf);
 		exit(1);
 	}
@@ -405,13 +426,12 @@
 	errcode_t	retval;
 	ext2_filsys	fs;
 	int		print_badblocks = 0;
-	int		use_superblock = 0;
+	blk_t		use_superblock = 0;
 	int		use_blocksize = 0;
 	int		image_dump = 0;
 	int		force = 0;
 	int		flags;
 	int		header_only = 0;
-	int		big_endian;
 	int		c;
 
 #ifdef ENABLE_NLS
@@ -488,12 +508,6 @@
 	if (print_badblocks) {
 		list_bad_blocks(fs, 1);
 	} else {
-		big_endian = ((fs->flags & EXT2_FLAG_SWAP_BYTES) != 0);
-#ifdef WORDS_BIGENDIAN
-		big_endian = !big_endian;
-#endif
-		if (big_endian)
-			printf(_("Note: This is a byte-swapped filesystem\n"));
 		list_super (fs->super);
 		if (fs->super->s_feature_incompat &
 		      EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
diff --git a/misc/e2image.c b/misc/e2image.c
index e10554e..081c66f 100644
--- a/misc/e2image.c
+++ b/misc/e2image.c
@@ -347,9 +347,8 @@
 	for (p = buf; p < end-8; p += rec_len) {
 		dirent = (struct ext2_dir_entry_2 *) p;
 		rec_len = dirent->rec_len;
-#ifdef EXT2FS_ENABLE_SWAPFS
-		if (fs->flags & EXT2_FLAG_SWAP_BYTES) 
-			rec_len = ext2fs_swab16(rec_len);
+#ifdef WORDS_BIGENDIAN
+		rec_len = ext2fs_swab16(rec_len);
 #endif
 #if 0
 		printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len);
@@ -360,8 +359,7 @@
 			       "bad rec_len (%d)\n", (unsigned long) blk, 
 			       rec_len);
 			rec_len = end - p;
-#ifdef EXT2FS_ENABLE_SWAPFS
-			if (fs->flags & EXT2_FLAG_SWAP_BYTES) 
+#ifdef WORDS_BIGENDIAN
 				dirent->rec_len = ext2fs_swab16(rec_len);
 #endif
 			continue;
@@ -516,8 +514,9 @@
 		    (LINUX_S_ISLNK(inode.i_mode) &&
 		     ext2fs_inode_has_valid_blocks(&inode)) ||
 		    ino == fs->super->s_journal_inum) {
-			retval = ext2fs_block_iterate2(fs, ino, 0, 
-				       block_buf, process_dir_block, &pb);
+			retval = ext2fs_block_iterate2(fs, ino,
+					BLOCK_FLAG_READ_ONLY, block_buf,
+					process_dir_block, &pb);
 			if (retval) {
 				com_err(program_name, retval,
 					"while iterating over inode %u",
@@ -525,11 +524,12 @@
 				exit(1);
 			}
 		} else {
-			if (inode.i_block[EXT2_IND_BLOCK] ||
+			if ((inode.i_flags & EXT4_EXTENTS_FL) ||
+			    inode.i_block[EXT2_IND_BLOCK] ||
 			    inode.i_block[EXT2_DIND_BLOCK] ||
 			    inode.i_block[EXT2_TIND_BLOCK]) {
 				retval = ext2fs_block_iterate2(fs,
-				       ino, 0, block_buf,
+				       ino, BLOCK_FLAG_READ_ONLY, block_buf,
 				       process_file_block, &pb);
 				if (retval) {
 					com_err(program_name, retval,
diff --git a/misc/fsck.c b/misc/fsck.c
index 139afd0..9510261 100644
--- a/misc/fsck.c
+++ b/misc/fsck.c
@@ -813,7 +813,7 @@
  * This function returns true if a particular option appears in a
  * comma-delimited options list
  */
-static int opt_in_list(char *opt, char *optlist)
+static int opt_in_list(const char *opt, char *optlist)
 {
 	char	*list, *s;
 
diff --git a/misc/fsck.h b/misc/fsck.h
index 55cb525..8a0f70e 100644
--- a/misc/fsck.h
+++ b/misc/fsck.h
@@ -68,3 +68,6 @@
 
 extern char *base_device(const char *device);
 extern const char *identify_fs(const char *fs_name, const char *fs_types);
+
+/* ismounted.h */
+extern int is_mounted(const char *file);
diff --git a/misc/ismounted.c b/misc/ismounted.c
index 72f4cba..94a2d6e 100644
--- a/misc/ismounted.c
+++ b/misc/ismounted.c
@@ -28,6 +28,9 @@
 #endif
 #include <string.h>
 #include <sys/stat.h>
+#include <ctype.h>
+
+#include "fsck.h"
 
 /*
  * ext2fs_check_if_mounted flags
@@ -80,7 +83,6 @@
 	ino_t		file_ino=0;
 	FILE 		*f;
 	char		buf[1024], *device = 0, *mnt_dir = 0, *cp;
-	int		fd;
 
 	*mount_flags = 0;
 	if ((f = fopen(mtab_file, "r")) == NULL)
diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in
index aaf017d..6cd10b1 100644
--- a/misc/mke2fs.8.in
+++ b/misc/mke2fs.8.in
@@ -438,6 +438,13 @@
 @JDEV@must be created with the same
 @JDEV@block size as the filesystems that will be using it.
 .TP
+.B uninit_groups
+Create a filesystem without initializing all of the groups.  This speeds
+up filesystem creation time noticably, and can also reduce
+.BR e2fsck time
+dramatically.  This feature is only supported by the ext4 filesystem in
+recent Linux kernels.
+.TP
 .B resize_inode
 Reserve space so the block group descriptor table may grow in the future.
 Useful for online resizing using 
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index fc086a4..fd48b83 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -433,6 +433,8 @@
 					num, blk, error_message(retval));
 				exit(1);
 			}
+			/* The kernel doesn't need to zero the itable blocks */
+			fs->group_desc[i].bg_flags |= EXT2_BG_INODE_ZEROED;
 		}
 		if (sync_kludge) {
 			if (sync_kludge == 1)
@@ -448,34 +450,49 @@
 static void setup_lazy_bg(ext2_filsys fs)
 {
 	dgrp_t i;
-	int blks;
+	int blks, csum_flag;
 	struct ext2_super_block *sb = fs->super;
 	struct ext2_group_desc *bg = fs->group_desc;
 
-	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
-				    EXT2_FEATURE_COMPAT_LAZY_BG)) {
+	csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					       EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+	if (EXT2_HAS_COMPAT_FEATURE(fs->super, EXT2_FEATURE_COMPAT_LAZY_BG) ||
+	    csum_flag) {
 		for (i = 0; i < fs->group_desc_count; i++, bg++) {
 			if ((i == 0) ||
-			    (i == fs->group_desc_count-1))
+			    (i == fs->group_desc_count - 1 && !csum_flag))
 				continue;
 			if (bg->bg_free_inodes_count ==
 			    sb->s_inodes_per_group) {
-				bg->bg_free_inodes_count = 0;
 				bg->bg_flags |= EXT2_BG_INODE_UNINIT;
-				sb->s_free_inodes_count -= 
-					sb->s_inodes_per_group;
+				if (!csum_flag) {
+					bg->bg_free_inodes_count = 0;
+					sb->s_free_inodes_count -=
+						sb->s_inodes_per_group;
+				}
 			}
+
+			/* Skip groups with GDT backups because the resize
+			 * inode has blocks allocated in them, and the last
+			 * group because it needs block bitmap padding. */
+			if ((ext2fs_bg_has_super(fs, i) &&
+			     sb->s_reserved_gdt_blocks) ||
+			    i == fs->group_desc_count - 1)
+				continue;
+
 			blks = ext2fs_super_and_bgd_loc(fs, i, 0, 0, 0, 0);
-			if (bg->bg_free_blocks_count == blks) {
-				bg->bg_free_blocks_count = 0;
+			if (bg->bg_free_blocks_count == blks &&
+			    bg->bg_flags & EXT2_BG_INODE_UNINIT) {
 				bg->bg_flags |= EXT2_BG_BLOCK_UNINIT;
-				sb->s_free_blocks_count -= blks;
+				if (!csum_flag) {
+					bg->bg_free_blocks_count = 0;
+					sb->s_free_blocks_count -= blks;
+				}
 			}
 		}
 	}
 }
 
-
 static void create_root_dir(ext2_filsys fs)
 {
 	errcode_t		retval;
@@ -513,11 +530,11 @@
 
 static void create_lost_and_found(ext2_filsys fs)
 {
+	unsigned int		lpf_size = 0;
 	errcode_t		retval;
 	ext2_ino_t		ino;
 	const char		*name = "lost+found";
 	int			i;
-	int			lpf_size = 0;
 
 	fs->umask = 077;
 	retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name);
@@ -535,7 +552,10 @@
 	}
 	
 	for (i=1; i < EXT2_NDIR_BLOCKS; i++) {
-		if ((lpf_size += fs->blocksize) >= 16*1024)
+		/* Ensure that lost+found is at least 2 blocks, so we always
+		 * test large empty blocks for big-block filesystems.  */
+		if ((lpf_size += fs->blocksize) >= 16*1024 &&
+		    lpf_size >= 2 * fs->blocksize)
 			break;
 		retval = ext2fs_expand_dir(fs, ino);
 		if (retval) {
@@ -694,8 +714,7 @@
 	if (s->s_reserved_gdt_blocks)
 		printf(_("Maximum filesystem blocks=%lu\n"),
 		       (s->s_reserved_gdt_blocks + fs->desc_blocks) *
-		       (fs->blocksize / sizeof(struct ext2_group_desc)) *
-		       s->s_blocks_per_group);
+		       EXT2_DESC_PER_BLOCK(s) * s->s_blocks_per_group);
 	if (fs->group_desc_count > 1)
 		printf(_("%u block groups\n"), fs->group_desc_count);
 	else
@@ -741,8 +760,6 @@
 		sb->s_creator_os = EXT2_OS_LINUX;
 	else if (strcasecmp(os, "GNU") == 0 || strcasecmp(os, "hurd") == 0)
 		sb->s_creator_os = EXT2_OS_HURD;
-	else if (strcasecmp(os, "masix") == 0)
-		sb->s_creator_os = EXT2_OS_MASIX;
 	else if (strcasecmp(os, "freebsd") == 0)
 		sb->s_creator_os = EXT2_OS_FREEBSD;
 	else if (strcasecmp(os, "lites") == 0)
@@ -757,7 +774,7 @@
 static void parse_extended_opts(struct ext2_super_block *param, 
 				const char *opts)
 {
-	char	*buf, *token, *next, *p, *arg, *badopt = "";
+	char	*buf, *token, *next, *p, *arg, *badopt = 0;
 	int	len;
 	int	r_usage = 0;
 
@@ -844,7 +861,7 @@
 			bpg = param->s_blocks_per_group;
 			if (!bpg)
 				bpg = blocksize * 8;
-			gdpb = blocksize / sizeof(struct ext2_group_desc);
+			gdpb = EXT2_DESC_PER_BLOCK(param);
 			group_desc_count = 
 				ext2fs_div_ceil(param->s_blocks_count, bpg);
 			desc_blocks = (group_desc_count +
@@ -884,7 +901,7 @@
 			"\tstripe-width=<RAID stride * data disks in blocks>\n"
 			"\tresize=<resize maximum size in blocks>\n\n"
 			"\ttest_fs\n"),
-			badopt);
+			badopt ? badopt : "");
 		free(buf);
 		exit(1);
 	}
@@ -906,11 +923,14 @@
 		EXT2_FEATURE_COMPAT_EXT_ATTR,
 	/* Incompat */
 	EXT2_FEATURE_INCOMPAT_FILETYPE|
+		EXT3_FEATURE_INCOMPAT_EXTENTS|
 		EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
-		EXT2_FEATURE_INCOMPAT_META_BG,
+		EXT2_FEATURE_INCOMPAT_META_BG|
+		EXT4_FEATURE_INCOMPAT_FLEX_BG,
 	/* R/O compat */
 	EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
-		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|
+		EXT4_FEATURE_RO_COMPAT_GDT_CSUM
 };
 
 
@@ -1475,19 +1495,6 @@
 		}
 	}
 
-	if (!force && fs_param.s_blocks_count >= ((unsigned) 1 << 31)) {
-		com_err(program_name, 0,
-			_("Filesystem too large.  No more than 2**31-1 blocks\n"
-			  "\t (8TB using a blocksize of 4k) are currently supported."));
-             exit(1);
-	}
-
-	if ((blocksize > 4096) &&
-	    (fs_param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
-		fprintf(stderr, _("\nWarning: some 2.4 kernels do not support "
-			"blocksizes greater than 4096\n\tusing ext3.  "
-			"Use -b 4096 if this is an issue for you.\n\n"));
-
 	if (inode_size == 0) {
 		profile_get_integer(profile, "defaults", "inode_size", NULL,
 				    0, &inode_size);
@@ -1506,10 +1513,6 @@
 				blocksize);
 			exit(1);
 		}
-		if (inode_size != EXT2_GOOD_OLD_INODE_SIZE)
-			fprintf(stderr, _("Warning: %d-byte inodes not usable "
-				"on older systems\n"),
-				inode_size);
 		fs_param.s_inode_size = inode_size;
 	}
 
@@ -1562,7 +1565,7 @@
 	errcode_t	retval = 0;
 	ext2_filsys	fs;
 	badblocks_list	bb_list = 0;
-	int		journal_blocks;
+	unsigned int	journal_blocks;
 	unsigned int	i;
 	int		val;
 	io_manager	io_ptr;
@@ -1773,7 +1776,7 @@
 			goto no_journal;
 		}
 		if (!quiet) {
-			printf(_("Creating journal (%d blocks): "),
+			printf(_("Creating journal (%u blocks): "),
 			       journal_blocks);
 			fflush(stdout);
 		}
@@ -1789,6 +1792,14 @@
 	}
 no_journal:
 
+	if (!super_only) {
+		retval = ext2fs_set_gdt_csum(fs);
+		if (retval) {
+			com_err(program_name, retval, 
+				_("\n\twhile setting block group checksum info"));
+			exit(1);
+		}
+	}
 	if (!quiet)
 		printf(_("Writing superblocks and "
 		       "filesystem accounting information: "));
diff --git a/misc/tune2fs.8.in b/misc/tune2fs.8.in
index 260e76f..66d9d52 100644
--- a/misc/tune2fs.8.in
+++ b/misc/tune2fs.8.in
@@ -439,10 +439,19 @@
 future.
 .B Tune2fs 
 only supports clearing this filesystem feature.
+.TP
+.B uninit_groups
+Allow the kernel to initialize bitmaps and inode tables and keep a high
+watermark for the unused inodes in a filesystem, to reduce
+.BR e2fsck (8)
+time.  This first e2fsck run after enabling this feature will take the
+full time, but subsequent e2fsck runs will take only a fraction of the
+original time, depending on how full the file system is.
 .RE
 .IP
 After setting or clearing 
 .BR sparse_super ,
+.BR uninit_groups ,
 .BR filetype ,
 or
 .B resize_inode
@@ -457,6 +466,12 @@
 feature, 
 .B e2fsck -D
 can be run to convert existing directories to the hashed B-tree format.
+Enabling certain filesystem features may prevent the filesystem from being
+mounted by kernels which do not support those features.  In particular the
+.BR uninit_groups
+and
+.BR flex_bg
+features are only supported by the ext4 filesystem.
 .TP
 .BI \-r " reserved-blocks-count"
 Set the number of reserved filesystem blocks.
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 4e731f5..85046e2 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -113,9 +113,12 @@
 	EXT3_FEATURE_COMPAT_HAS_JOURNAL |
 		EXT2_FEATURE_COMPAT_DIR_INDEX,
 	/* Incompat */
-	EXT2_FEATURE_INCOMPAT_FILETYPE,
+	EXT2_FEATURE_INCOMPAT_FILETYPE |
+		EXT3_FEATURE_INCOMPAT_EXTENTS |
+		EXT4_FEATURE_INCOMPAT_FLEX_BG,
 	/* R/O compat */
 	EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
+		EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
 		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
 };
 
@@ -125,9 +128,11 @@
 		EXT2_FEATURE_COMPAT_RESIZE_INODE |
 		EXT2_FEATURE_COMPAT_DIR_INDEX,
 	/* Incompat */
-	EXT2_FEATURE_INCOMPAT_FILETYPE,
+	EXT2_FEATURE_INCOMPAT_FILETYPE |
+		EXT4_FEATURE_INCOMPAT_FLEX_BG,
 	/* R/O compat */
-	EXT2_FEATURE_RO_COMPAT_LARGE_FILE
+	EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
+		EXT4_FEATURE_RO_COMPAT_GDT_CSUM
 };
 
 /*
@@ -242,6 +247,7 @@
 	ext2fs_unmark_block_bitmap(fs->block_map,block);
 	group = ext2fs_group_of_blk(fs, block);
 	fs->group_desc[group].bg_free_blocks_count++;
+	ext2fs_group_desc_csum_set(fs, group);
 	fs->super->s_free_blocks_count++;
 	return 0;
 }
@@ -268,7 +274,8 @@
 				_("while reading bitmaps"));
 			exit(1);
 		}
-		retval = ext2fs_block_iterate(fs, ino, 0, NULL,
+		retval = ext2fs_block_iterate(fs, ino,
+					      BLOCK_FLAG_READ_ONLY, NULL,
 					      release_blocks_proc, NULL);
 		if (retval) {
 			com_err(program_name, retval,
@@ -311,7 +318,6 @@
 static void update_feature_set(ext2_filsys fs, char *features)
 {
 	struct ext2_super_block *sb= fs->super;
-	__u32	old_compat, old_incompat, old_ro_compat;
 	__u32		old_features[3];
 	int		type_err;
 	unsigned int	mask_err;
@@ -390,6 +396,15 @@
 			uuid_generate((unsigned char *) sb->s_hash_seed);
 	}
 
+	if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+		if (ext2fs_check_desc(fs)) {
+			fputs(_("Clearing the flex_bg flag would "
+				"cause the the filesystem to be\n"
+				"inconsistent.\n"), stderr);
+			exit(1);
+		}
+	}
+
 	if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
 	    (sb->s_feature_compat || sb->s_feature_ro_compat ||
 	     sb->s_feature_incompat))
@@ -397,6 +412,8 @@
 
 	if (FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT,
 			    EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
+	    FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT,
+			    EXT4_FEATURE_RO_COMPAT_GDT_CSUM) ||
 	    FEATURE_CHANGED(E2P_FEATURE_INCOMPAT,
 			    EXT2_FEATURE_INCOMPAT_FILETYPE) ||
 	    FEATURE_CHANGED(E2P_FEATURE_COMPAT,
diff --git a/misc/util.c b/misc/util.c
index 7522e9b..7c99a2a 100644
--- a/misc/util.c
+++ b/misc/util.c
@@ -71,8 +71,8 @@
 	fflush(stderr);
 	fputs(_("Proceed anyway? (y,n) "), stdout);
 	buf[0] = 0;
-	fgets(buf, sizeof(buf), stdin);
-	if (strchr(short_yes, buf[0]) == 0)
+	if (!fgets(buf, sizeof(buf), stdin) ||
+	    strchr(short_yes, buf[0]) == 0)
 		exit(1);
 }
 
@@ -249,7 +249,7 @@
  * in the filesystem.  For very small filesystems, it is not reasonable to
  * have a journal that fills more than half of the filesystem.
  */
-int figure_journal_size(int size, ext2_filsys fs)
+unsigned int figure_journal_size(int size, ext2_filsys fs)
 {
 	int j_blocks;
 
@@ -269,7 +269,7 @@
 				j_blocks);
 			exit(1);
 		}
-		if (j_blocks > fs->super->s_free_blocks_count / 2) {
+		if ((unsigned) j_blocks > fs->super->s_free_blocks_count / 2) {
 			fputs(_("\nJournal size too big for filesystem.\n"),
 			      stderr);
 			exit(1);
diff --git a/misc/util.h b/misc/util.h
index 3b6a881..0df2aac 100644
--- a/misc/util.h
+++ b/misc/util.h
@@ -22,5 +22,5 @@
 extern void check_plausibility(const char *device);
 extern void parse_journal_opts(const char *opts);
 extern void check_mount(const char *device, int force, const char *type);
-extern int figure_journal_size(int size, ext2_filsys fs);
+extern unsigned int figure_journal_size(int size, ext2_filsys fs);
 extern void print_check_message(ext2_filsys fs);
diff --git a/misc/uuidd.c b/misc/uuidd.c
index c964b4e..1af8c86 100644
--- a/misc/uuidd.c
+++ b/misc/uuidd.c
@@ -206,12 +206,12 @@
 			int debug, int timeout, int quiet)
 {
 	struct sockaddr_un	my_addr, from_addr;
-	unsigned char		reply_buf[1024], *cp;
 	struct flock		fl;
 	socklen_t		fromlen;
 	int32_t			reply_len = 0;
 	uuid_t			uu;
 	mode_t			save_umask;
+	char			reply_buf[1024], *cp;
 	char			op, str[37];
 	int			i, s, ns, len, num;
 	int			fd_pidfile, ret;
@@ -329,12 +329,12 @@
 
 		switch(op) {
 		case UUIDD_OP_GETPID:
-			sprintf((char *) reply_buf, "%d", getpid());
-			reply_len = strlen((char *) reply_buf)+1;
+			sprintf(reply_buf, "%d", getpid());
+			reply_len = strlen(reply_buf)+1;
 			break;
 		case UUIDD_OP_GET_MAXOP:
-			sprintf((char *) reply_buf, "%d", UUIDD_MAX_OP);
-			reply_len = strlen((char *) reply_buf)+1;
+			sprintf(reply_buf, "%d", UUIDD_MAX_OP);
+			reply_len = strlen(reply_buf)+1;
 			break;
 		case UUIDD_OP_TIME_UUID:
 			num = 1;
@@ -375,12 +375,13 @@
 				num = 1000;
 			if (num*16 > (int) (sizeof(reply_buf)-sizeof(num)))
 				num = (sizeof(reply_buf)-sizeof(num)) / 16;
-			uuid__generate_random(reply_buf+sizeof(num), &num);
+			uuid__generate_random((unsigned char *) reply_buf +
+					      sizeof(num), &num);
 			if (debug) {
 				printf(_("Generated %d UUID's:\n"), num);
 				for (i=0, cp=reply_buf+sizeof(num);
 				     i < num; i++, cp+=16) {
-					uuid_unparse(cp, str);
+					uuid_unparse((unsigned char *)cp, str);
 					printf("\t%s\n", str);
 				}
 			}
diff --git a/resize/main.c b/resize/main.c
index f283e41..2e5c89c 100644
--- a/resize/main.c
+++ b/resize/main.c
@@ -36,8 +36,8 @@
 
 static void usage (char *prog)
 {
-	fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-p] "
-			   "device [new_size]\n\n"), prog);
+	fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P] "
+			   "[-p] device [new_size]\n\n"), prog);
 
 	exit (1);
 }
@@ -152,6 +152,8 @@
 	int		flush = 0;
 	int		force = 0;
 	int		io_flags = 0;
+	int		force_min_size = 0;
+	int		print_min_size = 0;
 	int		fd, ret;
 	blk_t		new_size = 0;
 	blk_t		max_size = 0;
@@ -183,7 +185,7 @@
 	if (argc && *argv)
 		program_name = *argv;
 
-	while ((c = getopt (argc, argv, "d:fFhpS:")) != EOF) {
+	while ((c = getopt (argc, argv, "d:fFhMPpS:")) != EOF) {
 		switch (c) {
 		case 'h':
 			usage(program_name);
@@ -194,6 +196,12 @@
 		case 'F':
 			flush = 1;
 			break;
+		case 'M':
+			force_min_size = 1;
+			break;
+		case 'P':
+			print_min_size = 1;
+			break;
 		case 'd':
 			flags |= atoi(optarg);
 			break;
@@ -298,6 +306,13 @@
 		printf (_("Couldn't find valid filesystem superblock.\n"));
 		exit (1);
 	}
+
+	if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+		com_err(program_name, EXT2_ET_RO_UNSUPP_FEATURE,
+			":- uninit_groups");
+		exit(1);
+	}
+
 	/*
 	 * Check for compatibility with the feature sets.  We need to
 	 * be more stringent than ext2fs_open().
@@ -308,6 +323,12 @@
 		exit(1);
 	}
 	
+	if (print_min_size) {
+		printf("Estimated minimum size of the filesystem: %lu\n",
+		       calculate_minimum_resize_size(fs));
+		exit(0);
+	}
+
 	/* Determine the system page size if possible */
 #ifdef HAVE_SYSCONF
 #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
@@ -332,14 +353,11 @@
 			_("while trying to determine filesystem size"));
 		exit(1);
 	}
-	if (new_size_str) {
+	if (force_min_size)
+		new_size = calculate_minimum_resize_size(fs);
+	else if (new_size_str) {
 		new_size = parse_num_blocks(new_size_str, 
 					    fs->super->s_log_block_size);
-		if (!new_size) {
-			com_err(program_name, 0, _("bad filesystem size - %s"),
-				new_size_str);
-			exit(1);
-		}
 	} else {
 		new_size = max_size;
 		/* Round down to an even multiple of a pagesize */
diff --git a/resize/resize2fs.8.in b/resize/resize2fs.8.in
index d43adad..719ef99 100644
--- a/resize/resize2fs.8.in
+++ b/resize/resize2fs.8.in
@@ -8,6 +8,9 @@
 .SH SYNOPSIS
 .B resize2fs
 [
+.B \-fFpPM
+]
+[
 .B \-d 
 .I debug-flags
 ]
@@ -15,15 +18,6 @@
 .B \-S
 .I RAID-stride
 ]
-[
-.B \-f
-]
-[
-.B \-F
-]
-[
-.B \-p
-]
 .I device
 [
 .I size
@@ -99,19 +93,6 @@
 \	8\	\-\ Debug inode relocations
 .br
 \	16\	\-\ Debug moving the inode table
-.TP
-.B \-S \fIRAID-stride
-The 
-.B resize2fs
-program will heuristically determine the RAID stride that was specified 
-when the filesystem was created.  This option allows the user to 
-explicitly specify a RAID stride setting to be used by resize2fs instead.
-.TP
-.B \-p
-Prints out a percentage completion bars for each 
-.B resize2fs
-operation, so that the user can keep track of what
-the program is doing.
 .TP 
 .B \-f
 Forces resize2fs to proceed with the filesystem resize operation, overriding 
@@ -122,6 +103,28 @@
 really useful for doing 
 .B resize2fs
 time trials.
+.TP
+.B \-M
+Shrink the filesystem to the minimum size.
+.TP
+.B \-p
+Prints out a percentage completion bars for each
+.B resize2fs
+operation, so that the user can keep track of what
+the program is doing.
+.TP
+.B \-P
+Print the minimum size of the filesystem and exit.
+.TP
+.B \-S \fIRAID-stride
+The
+.B resize2fs
+program will heuristically determine the RAID stride that was specified
+when the filesystem was created.  This option allows the user to
+explicitly specify a RAID stride setting to be used by resize2fs instead.
+.SH KNOWN BUGS
+The minimum size of the filesystem as estimated by resize2fs may be
+incorrect, especially for filesystems with 1k and 2k blocksizes.
 .SH AUTHOR
 .B resize2fs
 was written by Theodore Ts'o <tytso@mit.edu>.
diff --git a/resize/resize2fs.c b/resize/resize2fs.c
index 6dec3eb..1062ffa 100644
--- a/resize/resize2fs.c
+++ b/resize/resize2fs.c
@@ -63,7 +63,9 @@
 				 ((blk) < (FS_INODE_TB((fs), (i)) + \
 					   (fs)->inode_blocks_per_group)))
 
-
+#define META_OVERHEAD(fs) (2 + (fs)->inode_blocks_per_group)
+#define SUPER_OVERHEAD(fs) (1 + (fs)->desc_blocks +\
+			    (fs)->super->s_reserved_gdt_blocks)
 
 /*
  * This is the top-level routine which does the dirty deed....
@@ -339,7 +341,8 @@
 		numblocks = fs->super->s_blocks_per_group;
 	i = old_fs->group_desc_count - 1;
 	fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
-		
+	ext2fs_group_desc_csum_set(fs, i);
+
 	/*
 	 * If the number of block groups is staying the same, we're
 	 * done and can exit now.  (If the number block groups is
@@ -383,8 +386,7 @@
 			ext2fs_mark_block_bitmap(fs->block_map, group_block);
 			adjblocks++;
 		}
-		meta_bg_size = (fs->blocksize /
-				sizeof (struct ext2_group_desc));
+		meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
 		meta_bg = i / meta_bg_size;
 		if (!(fs->super->s_feature_incompat &
 		      EXT2_FEATURE_INCOMPAT_META_BG) ||
@@ -415,6 +417,7 @@
 		fs->group_desc[i].bg_free_inodes_count =
 			fs->super->s_inodes_per_group;
 		fs->group_desc[i].bg_used_dirs_count = 0;
+		ext2fs_group_desc_csum_set(fs, i);
 
 		retval = ext2fs_allocate_group_table(fs, i, 0);
 		if (retval) goto errout;
@@ -550,7 +553,7 @@
 	unsigned long		meta_bg_size;
 	unsigned int		old_desc_blocks;
 
-	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
+	meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
 	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
 		old_desc_blocks = fs->super->s_first_meta_bg;
 	else
@@ -717,7 +720,7 @@
 	 * If we're increasing the number of descriptor blocks, life
 	 * gets interesting....  
 	 */
-	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
+	meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
 	for (i = 0; i < max_groups; i++) {
 		has_super = ext2fs_bg_has_super(fs, i);
 		if (has_super)
@@ -1232,9 +1235,11 @@
 		if (retval) goto errout;
 
 		group = (new_inode-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
-		if (LINUX_S_ISDIR(inode->i_mode))
+		if (LINUX_S_ISDIR(inode->i_mode)) {
 			rfs->new_fs->group_desc[group].bg_used_dirs_count++;
-		
+			ext2fs_group_desc_csum_set(rfs->new_fs, group);
+		}
+
 #ifdef RESIZE2FS_DEBUG
 		if (rfs->flags & RESIZE_DEBUG_INODEMAP)
 			printf("Inode moved %u->%u\n", ino, new_inode);
@@ -1489,6 +1494,7 @@
 			ext2fs_unmark_block_bitmap(fs->block_map, blk);
 
 		rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
+		ext2fs_group_desc_csum_set(rfs->old_fs, i);
 		ext2fs_mark_super_dirty(rfs->old_fs);
 		ext2fs_flush(rfs->old_fs);
 
@@ -1586,8 +1592,10 @@
 		count++;
 		if ((count == fs->super->s_blocks_per_group) ||
 		    (blk == fs->super->s_blocks_count-1)) {
-			fs->group_desc[group++].bg_free_blocks_count =
+			fs->group_desc[group].bg_free_blocks_count =
 				group_free;
+			ext2fs_group_desc_csum_set(fs, group);
+			group++;
 			count = 0;
 			group_free = 0;
 		}
@@ -1611,8 +1619,10 @@
 		count++;
 		if ((count == fs->super->s_inodes_per_group) ||
 		    (ino == fs->super->s_inodes_count)) {
-			fs->group_desc[group++].bg_free_inodes_count =
+			fs->group_desc[group].bg_free_inodes_count =
 				group_free;
+			ext2fs_group_desc_csum_set(fs, group);
+			group++;
 			count = 0;
 			group_free = 0;
 		}
@@ -1621,3 +1631,139 @@
 	ext2fs_mark_super_dirty(fs);
 	return 0;
 }
+
+/*
+ * calcluate the minimum number of blocks the given fs can be resized to
+ */
+blk_t calculate_minimum_resize_size(ext2_filsys fs)
+{
+	blk_t inode_count, blks_needed, groups, blk, data_blocks;
+	blk_t grp, data_needed, last_start;
+	int overhead = 0, old_group = -1, num_of_superblocks = 0;
+
+	/*
+	 * first figure out how many group descriptors we need to
+	 * handle the number of inodes we have
+	 */
+	inode_count = fs->super->s_inodes_count -
+		fs->super->s_free_inodes_count;
+	blks_needed = ext2fs_div_ceil(inode_count,
+				      fs->super->s_inodes_per_group) *
+		EXT2_BLOCKS_PER_GROUP(fs->super);
+	groups = ext2fs_div_ceil(blks_needed,
+				 EXT2_BLOCKS_PER_GROUP(fs->super));
+
+	/*
+	 * we need to figure out how many backup superblocks we have so we can
+	 * account for that in the metadata
+	 */
+	for (grp = 0; grp < fs->group_desc_count; grp++) {
+		if (ext2fs_bg_has_super(fs, grp))
+			num_of_superblocks++;
+	}
+
+	/* calculate how many blocks are needed for data */
+	data_needed = fs->super->s_blocks_count -
+		fs->super->s_free_blocks_count;
+	data_needed -= SUPER_OVERHEAD(fs) * num_of_superblocks;
+	data_needed -= META_OVERHEAD(fs) * fs->group_desc_count;
+
+	/*
+	 * figure out how many data blocks we have given the number of groups
+	 * we need for our inodes
+	 */
+	data_blocks = groups * EXT2_BLOCKS_PER_GROUP(fs->super);
+	last_start = 0;
+	for (grp = 0; grp < groups; grp++) {
+		overhead = META_OVERHEAD(fs);
+
+		if (ext2fs_bg_has_super(fs, grp))
+			overhead += SUPER_OVERHEAD(fs);
+
+		/*
+		 * we want to keep track of how much data we can store in
+		 * the groups leading up to the last group so we can determine
+		 * how big the last group needs to be
+		 */
+		if (grp != (groups - 1))
+			last_start += EXT2_BLOCKS_PER_GROUP(fs->super) -
+				overhead;
+
+		data_blocks -= overhead;
+	}
+
+	/*
+	 * if we need more group descriptors in order to accomodate our data
+	 * then we need to add them here
+	 */
+	while (data_needed > data_blocks) {
+		blk_t remainder = data_needed - data_blocks;
+		blk_t extra_grps;
+
+		/* figure out how many more groups we need for the data */
+		extra_grps = ext2fs_div_ceil(remainder,
+					     EXT2_BLOCKS_PER_GROUP(fs->super));
+
+		data_blocks += extra_grps * EXT2_BLOCKS_PER_GROUP(fs->super);
+
+		/* ok we have to account for the last group */
+		overhead = META_OVERHEAD(fs);
+		if (ext2fs_bg_has_super(fs, groups-1))
+			overhead += SUPER_OVERHEAD(fs);
+		last_start += EXT2_BLOCKS_PER_GROUP(fs->super) - overhead;
+
+		for (grp = groups; grp < groups+extra_grps; grp++) {
+			overhead = META_OVERHEAD(fs);
+			if (ext2fs_bg_has_super(fs, grp))
+				overhead += SUPER_OVERHEAD(fs);
+
+			/*
+			 * again, we need to see how much data we cram into
+			 * all of the groups leading up to the last group
+			 */
+			if (grp != (groups + extra_grps - 1))
+				last_start += EXT2_BLOCKS_PER_GROUP(fs->super)
+					- overhead;
+
+			data_blocks -= overhead;
+		}
+
+		groups += extra_grps;
+	}
+
+	/* now for the fun voodoo */
+	overhead = META_OVERHEAD(fs);
+
+	/*
+	 * if this is the case then the last group is going to have data in it
+	 * so we need to adjust the size of the last group accordingly
+	 */
+	if (last_start < data_needed) {
+		blk_t remainder = data_needed - last_start;
+
+		/*
+		 * 50 is a magic number that mkfs/resize uses to see if its
+		 * even worth making/resizing the fs.  basically you need to
+		 * have at least 50 blocks in addition to the blocks needed
+		 * for the metadata in the last group
+		 */
+		if (remainder > 50)
+			overhead += remainder;
+		else
+			overhead += 50;
+	} else
+		overhead += 50;
+
+	if (ext2fs_bg_has_super(fs, groups-1))
+		overhead += SUPER_OVERHEAD(fs);
+
+	/*
+	 * since our last group doesn't have to be BLOCKS_PER_GROUP large, we
+	 * only do groups-1, and then add the number of blocks needed to
+	 * handle the group descriptor metadata+data that we need
+	 */
+	blks_needed = (groups-1) * EXT2_BLOCKS_PER_GROUP(fs->super);
+	blks_needed += overhead;
+
+	return blks_needed;
+}
diff --git a/resize/resize2fs.h b/resize/resize2fs.h
index f87d04e..49b77d8 100644
--- a/resize/resize2fs.h
+++ b/resize/resize2fs.h
@@ -129,6 +129,7 @@
 
 extern errcode_t adjust_fs_info(ext2_filsys fs, ext2_filsys old_fs, 
 				blk_t new_size);
+extern blk_t calculate_minimum_resize_size(ext2_filsys fs);
 
 
 /* extent.c */
diff --git a/tests/f_bad_disconnected_inode/expect.1 b/tests/f_bad_disconnected_inode/expect.1
index b4851f0..11862f6 100644
--- a/tests/f_bad_disconnected_inode/expect.1
+++ b/tests/f_bad_disconnected_inode/expect.1
@@ -1,4 +1,13 @@
 Pass 1: Checking inodes, blocks, and sizes
+Inode 1 has EXTENTS_FL flag set on filesystem without extents support.
+Clear? yes
+
+Inode 15 has EXTENTS_FL flag set on filesystem without extents support.
+Clear? yes
+
+Inode 16 has EXTENTS_FL flag set on filesystem without extents support.
+Clear? yes
+
 Pass 2: Checking directory structure
 Pass 3: Checking directory connectivity
 /lost+found not found.  Create? yes
@@ -18,26 +27,6 @@
 Inode 14 (...) has invalid mode (0154247).
 Clear? yes
 
-i_file_acl for inode 15 (...) is 1143674715, should be zero.
-Clear? yes
-
-Inode 15 (...) has invalid mode (074044).
-Clear? yes
-
-i_file_acl for inode 16 (...) is 2007517039, should be zero.
-Clear? yes
-
-i_faddr for inode 16 (...) is 1003914917, should be zero.
-Clear? yes
-
-i_blocks_hi for inode 16 (...) is 62762, should be zero.
-Clear? yes
-
-Unattached inode 16
-Connect to /lost+found? yes
-
-Inode 16 ref count is 5925, should be 1.  Fix? yes
-
 Pass 5: Checking group summary information
 Block bitmap differences:  -(9--19)
 Fix? yes
@@ -48,19 +37,16 @@
 Free blocks count wrong (79, counted=91).
 Fix? yes
 
-Inode bitmap differences:  +16
-Fix? yes
-
-Free inodes count wrong for group #0 (7, counted=4).
+Free inodes count wrong for group #0 (6, counted=5).
 Fix? yes
 
 Directories count wrong for group #0 (3, counted=2).
 Fix? yes
 
-Free inodes count wrong (7, counted=4).
+Free inodes count wrong (6, counted=5).
 Fix? yes
 
 
 test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 12/16 files (0.0% non-contiguous), 9/100 blocks
+test_filesys: 11/16 files (0.0% non-contiguous), 9/100 blocks
 Exit status is 1
diff --git a/tests/f_bad_disconnected_inode/expect.2 b/tests/f_bad_disconnected_inode/expect.2
index 1739210..8dfeb70 100644
--- a/tests/f_bad_disconnected_inode/expect.2
+++ b/tests/f_bad_disconnected_inode/expect.2
@@ -3,5 +3,5 @@
 Pass 3: Checking directory connectivity
 Pass 4: Checking reference counts
 Pass 5: Checking group summary information
-test_filesys: 12/16 files (0.0% non-contiguous), 9/100 blocks
+test_filesys: 11/16 files (0.0% non-contiguous), 9/100 blocks
 Exit status is 0
diff --git a/tests/f_dupfsblks/expect.1 b/tests/f_dupfsblks/expect.1
index 661e164..32ce89b 100644
--- a/tests/f_dupfsblks/expect.1
+++ b/tests/f_dupfsblks/expect.1
@@ -44,7 +44,8 @@
 Directory inode 12, block 3, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (12) has deleted/unused inode 32.  Clear? yes
+Entry '' in ??? (12) has a zero-length name.
+Clear? yes
 
 Directory inode 12, block 4, offset 100: directory corrupted
 Salvage? yes
diff --git a/tests/f_ea_checks/expect.1 b/tests/f_ea_checks/expect.1
new file mode 100644
index 0000000..eb215a2
--- /dev/null
+++ b/tests/f_ea_checks/expect.1
@@ -0,0 +1,57 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 13 has a bad extended attribute block 26.  Clear? yes
+
+Inode 13, i_blocks is 4, should be 2.  Fix? yes
+
+Extended attribute in inode 14 has a hash (1649340189) which is invalid
+Clear? yes
+
+Inode 14, i_blocks is 2, should be 0.  Fix? yes
+
+Inode 17 has a bad extended attribute block 28.  Clear? yes
+
+Inode 17, i_blocks is 4, should be 2.  Fix? yes
+
+Inode 16 has a bad extended attribute block 29.  Clear? yes
+
+Inode 16, i_blocks is 2, should be 0.  Fix? yes
+
+Inode 19 has a bad extended attribute block 33.  Clear? yes
+
+Inode 19, i_blocks is 2, should be 0.  Fix? yes
+
+Inode 12 has a bad extended attribute block 55.  Clear? yes
+
+Inode 12, i_blocks is 2, should be 0.  Fix? yes
+
+Inode 15, i_blocks is 2, should be 0.  Fix? yes
+
+Pass 2: Checking directory structure
+Extended attribute block for inode 15 (/far) is invalid (999).
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -(26--29) -33 -55
+Fix? yes
+
+Free blocks count wrong for group #0 (481, counted=484).
+Fix? yes
+
+Free blocks count wrong (481, counted=484).
+Fix? yes
+
+Inode bitmap differences:  -18
+Fix? yes
+
+Free inodes count wrong for group #0 (47, counted=46).
+Fix? yes
+
+Free inodes count wrong (47, counted=46).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 18/64 files (0.0% non-contiguous), 28/512 blocks
+Exit status is 1
diff --git a/tests/f_ea_checks/expect.2 b/tests/f_ea_checks/expect.2
new file mode 100644
index 0000000..2a11cd2
--- /dev/null
+++ b/tests/f_ea_checks/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 18/64 files (0.0% non-contiguous), 28/512 blocks
+Exit status is 0
diff --git a/tests/f_ea_checks/image.gz b/tests/f_ea_checks/image.gz
new file mode 100644
index 0000000..253da06
--- /dev/null
+++ b/tests/f_ea_checks/image.gz
Binary files differ
diff --git a/tests/f_ea_checks/name b/tests/f_ea_checks/name
new file mode 100644
index 0000000..160fdea
--- /dev/null
+++ b/tests/f_ea_checks/name
@@ -0,0 +1 @@
+extended attribute block checks
diff --git a/tests/f_extents/expect.1 b/tests/f_extents/expect.1
new file mode 100644
index 0000000..2abe32e
--- /dev/null
+++ b/tests/f_extents/expect.1
@@ -0,0 +1,52 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 is in extent format, but superblock is missing EXTENTS feature
+Fix? yes
+
+Inode 12 has an invalid extent
+	(logical block 0, invalid physical block 21994527527949, len 17)
+Clear? yes
+
+Inode 12, i_blocks is 34, should be 0.  Fix? yes
+
+Inode 13 missing EXTENT_FL, but is in extents format
+Fix? yes
+
+Inode 17 has an invalid extent
+	(logical block 0, invalid physical block 22011707397135, len 15)
+Clear? yes
+
+Inode 17, i_blocks is 32, should be 0.  Fix? yes
+
+Error while reading over extent tree in inode 18: Corrupt extent header
+Clear inode? yes
+
+Inode 18, i_blocks is 2, should be 0.  Fix? yes
+
+Pass 2: Checking directory structure
+Entry 'fbad-flag' in / (2) has deleted/unused inode 18.  Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -1081 +4611 -(5121--5142)
+Fix? yes
+
+Free blocks count wrong for group #0 (7081, counted=7098).
+Fix? yes
+
+Free blocks count wrong (7081, counted=7098).
+Fix? yes
+
+Inode bitmap differences:  -18
+Fix? yes
+
+Free inodes count wrong for group #0 (237, counted=238).
+Fix? yes
+
+Free inodes count wrong (237, counted=238).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 18/256 files (0.0% non-contiguous), 1094/8192 blocks
+Exit status is 1
diff --git a/tests/f_extents/expect.2 b/tests/f_extents/expect.2
new file mode 100644
index 0000000..6162cdf
--- /dev/null
+++ b/tests/f_extents/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 18/256 files (0.0% non-contiguous), 1094/8192 blocks
+Exit status is 0
diff --git a/tests/f_extents/name b/tests/f_extents/name
new file mode 100644
index 0000000..edede57
--- /dev/null
+++ b/tests/f_extents/name
@@ -0,0 +1 @@
+basic extents support
diff --git a/tests/f_extents/script b/tests/f_extents/script
deleted file mode 100644
index c046675..0000000
--- a/tests/f_extents/script
+++ /dev/null
@@ -1,2 +0,0 @@
-rm -f $test_name.ok $test_name.failed
-echo "skipped"
diff --git a/tests/f_fast_symlink_extents/expect.1 b/tests/f_fast_symlink_extents/expect.1
new file mode 100644
index 0000000..dc16c97
--- /dev/null
+++ b/tests/f_fast_symlink_extents/expect.1
@@ -0,0 +1,11 @@
+Pass 1: Checking inodes, blocks, and sizes
+Fast symlink 13 has EXTENT_FL set.  Clear? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 13/16 files (0.0% non-contiguous), 21/100 blocks
+Exit status is 1
diff --git a/tests/f_fast_symlink_extents/expect.2 b/tests/f_fast_symlink_extents/expect.2
new file mode 100644
index 0000000..416f49c
--- /dev/null
+++ b/tests/f_fast_symlink_extents/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 13/16 files (0.0% non-contiguous), 21/100 blocks
+Exit status is 0
diff --git a/tests/f_fast_symlink_extents/image.gz b/tests/f_fast_symlink_extents/image.gz
new file mode 100644
index 0000000..37eb0af
--- /dev/null
+++ b/tests/f_fast_symlink_extents/image.gz
Binary files differ
diff --git a/tests/f_fast_symlink_extents/name b/tests/f_fast_symlink_extents/name
new file mode 100644
index 0000000..333cb52
--- /dev/null
+++ b/tests/f_fast_symlink_extents/name
@@ -0,0 +1 @@
+fast symlink with extents flag set
diff --git a/tests/f_swapfs/debugfs.cmd b/tests/f_swapfs/debugfs.cmd
deleted file mode 100644
index df583b2..0000000
--- a/tests/f_swapfs/debugfs.cmd
+++ /dev/null
@@ -1,5 +0,0 @@
-ls
-stat sym
-stat double-indirect-test
-cat fluff
-quit
diff --git a/tests/f_swapfs/expect b/tests/f_swapfs/expect
deleted file mode 100644
index ecbb990..0000000
--- a/tests/f_swapfs/expect
+++ /dev/null
@@ -1,133 +0,0 @@
-Swapfs test
-e2fsck -yf -N test_filesys
-Pass 1: Checking inodes, blocks, and sizes
-Pass 2: Checking directory structure
-Pass 3: Checking directory connectivity
-Pass 4: Checking reference counts
-Pass 5: Checking group summary information
-test_filesys: 25/256 files (0.0% non-contiguous), 418/1024 blocks
-Exit status is 0
-e2fsck -Sy -N test_filesys
-Pass 0: Doing byte-swap of filesystem
-Pass 1: Checking inodes, blocks, and sizes
-Pass 2: Checking directory structure
-Pass 3: Checking directory connectivity
-Pass 4: Checking reference counts
-Pass 5: Checking group summary information
-test_filesys: 25/256 files (0.0% non-contiguous), 418/1024 blocks
-Exit status is 0
-Running debugfs....
-debugfs: ls
- 2  (12) .    2  (12) ..    11  (20) lost+found    12  (16) fluff   
- 13  (28) indirect-fluff-test    14  (28) double-indirect-test   
- 15  (20) sym    16  (24) long-sym-test    17  (864) dir-test   
-debugfs: stat sym
-Inode: 15   Type: symlink    Mode:  0777   Flags: 0x0   Generation: 1
-User:     0   Group:     0   Size: 5
-File ACL: 0    Directory ACL: 0
-Links: 1   Blockcount: 0
-Fragment:  Address: 0    Number: 0    Size: 0
-ctime: 0x322737e2 -- Fri Aug 30 18:50:10 1996
-atime: 0x322737e2 -- Fri Aug 30 18:50:10 1996
-mtime: 0x322737e2 -- Fri Aug 30 18:50:10 1996
-Fast_link_dest: fluff
-debugfs: stat double-indirect-test
-Inode: 14   Type: regular    Mode:  0644   Flags: 0x0   Generation: 1
-User:     0   Group:     0   Size: 348960
-File ACL: 0    Directory ACL: 0
-Links: 1   Blockcount: 688
-Fragment:  Address: 0    Number: 0    Size: 0
-ctime: 0x322488cf -- Wed Aug 28 17:58:39 1996
-atime: 0x322488cf -- Wed Aug 28 17:58:39 1996
-mtime: 0x322488cf -- Wed Aug 28 17:58:39 1996
-BLOCKS:
-(0-11):70-81, (IND):82, (12-267):83-338, (DIND):339, (IND):340, (268-340):341-413
-TOTAL: 344
-
-debugfs: cat fluff
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-
-debugfs: quit
-Exit status is 0
-e2fsck -yf -N test_filesys
-Pass 1: Checking inodes, blocks, and sizes
-Pass 2: Checking directory structure
-Pass 3: Checking directory connectivity
-Pass 4: Checking reference counts
-Pass 5: Checking group summary information
-test_filesys: 25/256 files (0.0% non-contiguous), 418/1024 blocks
-Exit status is 0
-e2fsck -sy -N test_filesys
-Pass 0: Doing byte-swap of filesystem
-Pass 1: Checking inodes, blocks, and sizes
-Pass 2: Checking directory structure
-Pass 3: Checking directory connectivity
-Pass 4: Checking reference counts
-Pass 5: Checking group summary information
-test_filesys: 25/256 files (0.0% non-contiguous), 418/1024 blocks
-Exit status is 0
-Running debugfs....
-debugfs: ls
- 2  (12) .    2  (12) ..    11  (20) lost+found    12  (16) fluff   
- 13  (28) indirect-fluff-test    14  (28) double-indirect-test   
- 15  (20) sym    16  (24) long-sym-test    17  (864) dir-test   
-debugfs: stat sym
-Inode: 15   Type: symlink    Mode:  0777   Flags: 0x0   Generation: 1
-User:     0   Group:     0   Size: 5
-File ACL: 0    Directory ACL: 0
-Links: 1   Blockcount: 0
-Fragment:  Address: 0    Number: 0    Size: 0
-ctime: 0x322737e2 -- Fri Aug 30 18:50:10 1996
-atime: 0x322737e2 -- Fri Aug 30 18:50:10 1996
-mtime: 0x322737e2 -- Fri Aug 30 18:50:10 1996
-Fast_link_dest: fluff
-debugfs: stat double-indirect-test
-Inode: 14   Type: regular    Mode:  0644   Flags: 0x0   Generation: 1
-User:     0   Group:     0   Size: 348960
-File ACL: 0    Directory ACL: 0
-Links: 1   Blockcount: 688
-Fragment:  Address: 0    Number: 0    Size: 0
-ctime: 0x322488cf -- Wed Aug 28 17:58:39 1996
-atime: 0x322488cf -- Wed Aug 28 17:58:39 1996
-mtime: 0x322488cf -- Wed Aug 28 17:58:39 1996
-BLOCKS:
-(0-11):70-81, (IND):82, (12-267):83-338, (DIND):339, (IND):340, (268-340):341-413
-TOTAL: 344
-
-debugfs: cat fluff
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-yabba dabba doo.  cocka doodle doo.  yabba dabba doo.  cocka doodle doo. yipyip
-
-debugfs: quit
-Exit status is 0
-e2fsck -yf -N test_filesys
-Pass 1: Checking inodes, blocks, and sizes
-Pass 2: Checking directory structure
-Pass 3: Checking directory connectivity
-Pass 4: Checking reference counts
-Pass 5: Checking group summary information
-test_filesys: 25/256 files (0.0% non-contiguous), 418/1024 blocks
-Exit status is 0
diff --git a/tests/f_swapfs/image b/tests/f_swapfs/image
deleted file mode 100644
index e7b24b9..0000000
--- a/tests/f_swapfs/image
+++ /dev/null
Binary files differ
diff --git a/tests/f_swapfs/image.gz b/tests/f_swapfs/image.gz
deleted file mode 100644
index 852231b..0000000
--- a/tests/f_swapfs/image.gz
+++ /dev/null
Binary files differ
diff --git a/tests/f_swapfs/name b/tests/f_swapfs/name
deleted file mode 100644
index b4520ba..0000000
--- a/tests/f_swapfs/name
+++ /dev/null
@@ -1 +0,0 @@
-checking the e2fsck swapfs functionality
diff --git a/tests/f_swapfs/script b/tests/f_swapfs/script
deleted file mode 100644
index 75f9fb4..0000000
--- a/tests/f_swapfs/script
+++ /dev/null
@@ -1,79 +0,0 @@
-if $FSCK -SV > /dev/null 2>&1 ; then
-    IMAGE=$test_dir/image.gz
-    VERIFY_FSCK_OPT=-yf
-    SWAP_FSCK_OPT=-Sy
-    NATIVE_FSCK_OPT=-sy
-    OUT=$test_name.log
-    EXP=$test_dir/expect
-    
-    gunzip < $IMAGE > $TMPFILE
-    
-    echo "Swapfs test" > $OUT
-    
-    echo e2fsck $VERIFY_FSCK_OPT -N test_filesys > $OUT.new
-    $FSCK $VERIFY_FSCK_OPT -N test_filesys $TMPFILE >> $OUT.new 2>&1
-    status=$?
-    echo Exit status is $status >> $OUT.new
-    sed -e '2d' $OUT.new >> $OUT
-    
-    echo e2fsck $SWAP_FSCK_OPT -N test_filesys > $OUT.new
-    $FSCK $SWAP_FSCK_OPT -N test_filesys $TMPFILE >> $OUT.new 2>&1
-    status=$?
-    echo Exit status is $status >> $OUT.new
-    sed -e '2d' $OUT.new >> $OUT
-    
-    echo Running debugfs.... >> $OUT
-    $DEBUGFS -f $test_dir/debugfs.cmd $TMPFILE > $OUT.new 2>&1 
-    status=$?
-    echo Exit status is $status >> $OUT.new
-    sed -e '1d' $OUT.new >> $OUT
-    
-    echo e2fsck $VERIFY_FSCK_OPT -N test_filesys > $OUT.new
-    $FSCK $VERIFY_FSCK_OPT -N test_filesys $TMPFILE >> $OUT.new 2>&1
-    status=$?
-    echo Exit status is $status >> $OUT.new
-    sed -e '2d' $OUT.new >> $OUT
-    
-    echo e2fsck $NATIVE_FSCK_OPT -N test_filesys > $OUT.new
-    $FSCK $NATIVE_FSCK_OPT -N test_filesys $TMPFILE >> $OUT.new 2>&1
-    status=$?
-    echo Exit status is $status >> $OUT.new
-    sed -e '2d' $OUT.new >> $OUT
-    
-    echo Running debugfs.... >> $OUT
-    $DEBUGFS -f $test_dir/debugfs.cmd $TMPFILE > $OUT.new 2>&1 
-    status=$?
-    echo Exit status is $status >> $OUT.new
-    sed -e '1d' $OUT.new >> $OUT
-    
-    echo e2fsck $VERIFY_FSCK_OPT -N test_filesys > $OUT.new
-    $FSCK $VERIFY_FSCK_OPT -N test_filesys $TMPFILE >> $OUT.new 2>&1
-    status=$?
-    echo Exit status is $status >> $OUT.new
-    sed -e '2d' $OUT.new >> $OUT
-    rm -f $OUT.new
-    
-    rm $TMPFILE
-    
-    #
-    # Do the verification
-    #
-    
-    rm -f $test_name.ok $test_name.failed
-    cmp -s $OUT $EXP
-    status=$?
-    
-    if [ "$status" = 0 ] ; then
-	    echo "ok"
-	    touch $test_name.ok
-    else
-	    echo "failed"
-	    diff $DIFF_OPTS $EXP $OUT > $test_name.failed
-    fi
-    
-    unset IMAGE VERIFY_FSCK_OPT SWAP_FSCK_OPT NATIVE_FSCK_OPT OUT EXP 
-
-else
-    rm -f $test_name.ok $test_name.failed
-    echo "skipped"
-fi
diff --git a/tests/f_uninit_last_uninit/expect.1 b/tests/f_uninit_last_uninit/expect.1
new file mode 100644
index 0000000..85f05ee
--- /dev/null
+++ b/tests/f_uninit_last_uninit/expect.1
@@ -0,0 +1,9 @@
+Last group block bitmap uninitialized.  Fix? yes
+
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/32 files (9.1% non-contiguous), 105/10000 blocks
+Exit status is 0
diff --git a/tests/f_uninit_last_uninit/expect.2 b/tests/f_uninit_last_uninit/expect.2
new file mode 100644
index 0000000..435a8a7
--- /dev/null
+++ b/tests/f_uninit_last_uninit/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/32 files (9.1% non-contiguous), 105/10000 blocks
+Exit status is 0
diff --git a/tests/f_uninit_last_uninit/name b/tests/f_uninit_last_uninit/name
new file mode 100644
index 0000000..4f93e23
--- /dev/null
+++ b/tests/f_uninit_last_uninit/name
@@ -0,0 +1,2 @@
+last group has BLOCK_UNINIT set
+
diff --git a/tests/f_uninit_last_uninit/script b/tests/f_uninit_last_uninit/script
new file mode 100644
index 0000000..477357a
--- /dev/null
+++ b/tests/f_uninit_last_uninit/script
@@ -0,0 +1,20 @@
+SKIP_GUNZIP="true"
+
+touch $TMPFILE
+$MKE2FS -N 32 -F -o Linux -O uninit_groups -b 1024 $TMPFILE 10000 > /dev/null 2>&1 
+$DEBUGFS -w $TMPFILE << EOF > /dev/null 2>&1
+set_current_time 200704102100
+set_super_value lastcheck 0
+set_super_value hash_seed null
+set_super_value mkfs_time 0
+set_bg 1 flags 0x7
+set_bg 1 checksum calc
+q
+EOF
+
+E2FSCK_TIME=200704102100
+export E2FSCK_TIME
+
+. $cmd_dir/run_e2fsck
+
+unset E2FSCK_TIME
diff --git a/tests/f_unsorted_EAs/expect.1 b/tests/f_unsorted_EAs/expect.1
new file mode 100644
index 0000000..7d588d7
--- /dev/null
+++ b/tests/f_unsorted_EAs/expect.1
@@ -0,0 +1,11 @@
+Adding dirhash hint to filesystem.
+
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 12/2048 files (0.0% non-contiguous), 1294/2048 blocks
+Exit status is 1
diff --git a/tests/f_unsorted_EAs/expect.2 b/tests/f_unsorted_EAs/expect.2
new file mode 100644
index 0000000..414cc29
--- /dev/null
+++ b/tests/f_unsorted_EAs/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 12/2048 files (0.0% non-contiguous), 1294/2048 blocks
+Exit status is 0
diff --git a/tests/f_unsorted_EAs/image.gz b/tests/f_unsorted_EAs/image.gz
new file mode 100644
index 0000000..42ab502
--- /dev/null
+++ b/tests/f_unsorted_EAs/image.gz
Binary files differ
diff --git a/tests/f_unsorted_EAs/name b/tests/f_unsorted_EAs/name
new file mode 100644
index 0000000..da9c9c3
--- /dev/null
+++ b/tests/f_unsorted_EAs/name
@@ -0,0 +1 @@
+unsorted EAs in inode should not be deleted
diff --git a/tests/filter_dumpe2fs b/tests/filter_dumpe2fs
index 51211f3..daa2c97 100644
--- a/tests/filter_dumpe2fs
+++ b/tests/filter_dumpe2fs
@@ -10,3 +10,4 @@
 /^Maximum mount count:/d
 /Reserved blocks uid:/s/ (user .*)//
 /Reserved blocks gid:/s/ (group .*)//
+/^  Checksum /d
diff --git a/tests/m_large_file/expect.1 b/tests/m_large_file/expect.1
index 2323eac..6a6c856 100644
--- a/tests/m_large_file/expect.1
+++ b/tests/m_large_file/expect.1
@@ -1,4 +1,3 @@
-Warning: 256-byte inodes not usable on older systems
 Filesystem label=
 OS type: Linux
 Block size=4096 (log=2)
diff --git a/tests/m_lazy/expect.1 b/tests/m_lazy/expect.1
new file mode 100644
index 0000000..88bd5c6
--- /dev/null
+++ b/tests/m_lazy/expect.1
@@ -0,0 +1,158 @@
+Filesystem label=
+OS type: Linux
+Block size=1024 (log=0)
+Fragment size=1024 (log=0)
+32768 inodes, 131072 blocks
+6553 blocks (5.00%) reserved for the super user
+First data block=1
+16 block groups
+8192 blocks per group, 8192 fragments per group
+2048 inodes per group
+Superblock backups stored on blocks: 
+	8193, 24577, 40961, 57345, 73729
+
+Writing inode tables: done                            
+Writing superblocks and filesystem accounting information: done
+
+Filesystem features: ext_attr dir_index lazy_bg filetype sparse_super
+ 
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 28683/32768 files (0.0% non-contiguous), 115220/131072 blocks
+Exit status is 0
+
+Filesystem volume name:   <none>
+Last mounted on:          <not available>
+Filesystem magic number:  0xEF53
+Filesystem revision #:    1 (dynamic)
+Filesystem features:      ext_attr dir_index lazy_bg filetype sparse_super
+Default mount options:    (none)
+Filesystem state:         clean
+Errors behavior:          Continue
+Filesystem OS type:       Linux
+Inode count:              32768
+Block count:              131072
+Reserved block count:     6553
+Free blocks:              15852
+Free inodes:              4085
+First block:              1
+Block size:               1024
+Fragment size:            1024
+Blocks per group:         8192
+Fragments per group:      8192
+Inodes per group:         2048
+Inode blocks per group:   256
+Mount count:              0
+Check interval:           15552000 (6 months)
+Reserved blocks uid:      0
+Reserved blocks gid:      0
+First inode:              11
+Inode size:		  128
+Default directory hash:   tea
+
+
+Group 0: (Blocks 1-8192) [ITABLE_ZEROED]
+  Primary superblock at 1, Group descriptors at 2-2
+  Block bitmap at 3 (+2), Inode bitmap at 4 (+3)
+  Inode table at 5-260 (+4)
+  7919 free blocks, 2037 free inodes, 2 directories
+  Free blocks: 274-8192
+  Free inodes: 12-2048
+Group 1: (Blocks 8193-16384) [INODE_UNINIT, BLOCK_UNINIT]
+  Backup superblock at 8193, Group descriptors at 8194-8194
+  Block bitmap at 8195 (+2), Inode bitmap at 8196 (+3)
+  Inode table at 8197-8452 (+4)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 2: (Blocks 16385-24576) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 16385 (+0), Inode bitmap at 16386 (+1)
+  Inode table at 16387-16642 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 3: (Blocks 24577-32768) [INODE_UNINIT, BLOCK_UNINIT]
+  Backup superblock at 24577, Group descriptors at 24578-24578
+  Block bitmap at 24579 (+2), Inode bitmap at 24580 (+3)
+  Inode table at 24581-24836 (+4)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 4: (Blocks 32769-40960) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 32769 (+0), Inode bitmap at 32770 (+1)
+  Inode table at 32771-33026 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 5: (Blocks 40961-49152) [INODE_UNINIT, BLOCK_UNINIT]
+  Backup superblock at 40961, Group descriptors at 40962-40962
+  Block bitmap at 40963 (+2), Inode bitmap at 40964 (+3)
+  Inode table at 40965-41220 (+4)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 6: (Blocks 49153-57344) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 49153 (+0), Inode bitmap at 49154 (+1)
+  Inode table at 49155-49410 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 7: (Blocks 57345-65536) [INODE_UNINIT, BLOCK_UNINIT]
+  Backup superblock at 57345, Group descriptors at 57346-57346
+  Block bitmap at 57347 (+2), Inode bitmap at 57348 (+3)
+  Inode table at 57349-57604 (+4)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 8: (Blocks 65537-73728) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 65537 (+0), Inode bitmap at 65538 (+1)
+  Inode table at 65539-65794 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 9: (Blocks 73729-81920) [INODE_UNINIT, BLOCK_UNINIT]
+  Backup superblock at 73729, Group descriptors at 73730-73730
+  Block bitmap at 73731 (+2), Inode bitmap at 73732 (+3)
+  Inode table at 73733-73988 (+4)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 10: (Blocks 81921-90112) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 81921 (+0), Inode bitmap at 81922 (+1)
+  Inode table at 81923-82178 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 11: (Blocks 90113-98304) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 90113 (+0), Inode bitmap at 90114 (+1)
+  Inode table at 90115-90370 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 12: (Blocks 98305-106496) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 98305 (+0), Inode bitmap at 98306 (+1)
+  Inode table at 98307-98562 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 13: (Blocks 106497-114688) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 106497 (+0), Inode bitmap at 106498 (+1)
+  Inode table at 106499-106754 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 14: (Blocks 114689-122880) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 114689 (+0), Inode bitmap at 114690 (+1)
+  Inode table at 114691-114946 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 15: (Blocks 122881-131071) [ITABLE_ZEROED]
+  Block bitmap at 122881 (+0), Inode bitmap at 122882 (+1)
+  Inode table at 122883-123138 (+2)
+  7933 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 123139-131071
+  Free inodes: 30721-32768
diff --git a/tests/m_lazy/script b/tests/m_lazy/script
new file mode 100644
index 0000000..aaac8f0
--- /dev/null
+++ b/tests/m_lazy/script
@@ -0,0 +1,4 @@
+DESCRIPTION="lazy group feature"
+FS_SIZE=131072
+MKE2FS_OPTS="-O ^resize_inode,lazy_bg"
+. $cmd_dir/run_mke2fs
diff --git a/tests/m_lazy_resize/expect.1 b/tests/m_lazy_resize/expect.1
new file mode 100644
index 0000000..b1f6b5e
--- /dev/null
+++ b/tests/m_lazy_resize/expect.1
@@ -0,0 +1,166 @@
+Filesystem label=
+OS type: Linux
+Block size=1024 (log=0)
+Fragment size=1024 (log=0)
+32768 inodes, 131072 blocks
+6553 blocks (5.00%) reserved for the super user
+First data block=1
+Maximum filesystem blocks=67371008
+16 block groups
+8192 blocks per group, 8192 fragments per group
+2048 inodes per group
+Superblock backups stored on blocks: 
+	8193, 24577, 40961, 57345, 73729
+
+Writing inode tables: done                            
+Writing superblocks and filesystem accounting information: done
+
+Filesystem features: ext_attr resize_inode dir_index lazy_bg filetype sparse_super
+ 
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 28683/32768 files (0.0% non-contiguous), 77097/131072 blocks
+Exit status is 0
+
+Filesystem volume name:   <none>
+Last mounted on:          <not available>
+Filesystem magic number:  0xEF53
+Filesystem revision #:    1 (dynamic)
+Filesystem features:      ext_attr resize_inode dir_index lazy_bg filetype sparse_super
+Default mount options:    (none)
+Filesystem state:         clean
+Errors behavior:          Continue
+Filesystem OS type:       Linux
+Inode count:              32768
+Block count:              131072
+Reserved block count:     6553
+Free blocks:              53975
+Free inodes:              4085
+First block:              1
+Block size:               1024
+Fragment size:            1024
+Reserved GDT blocks:      256
+Blocks per group:         8192
+Fragments per group:      8192
+Inodes per group:         2048
+Inode blocks per group:   256
+Mount count:              0
+Check interval:           15552000 (6 months)
+Reserved blocks uid:      0
+Reserved blocks gid:      0
+First inode:              11
+Inode size:		  128
+Default directory hash:   tea
+
+
+Group 0: (Blocks 1-8192) [ITABLE_ZEROED]
+  Primary superblock at 1, Group descriptors at 2-2
+  Reserved GDT blocks at 3-258
+  Block bitmap at 259 (+258), Inode bitmap at 260 (+259)
+  Inode table at 261-516 (+260)
+  7662 free blocks, 2037 free inodes, 2 directories
+  Free blocks: 531-8192
+  Free inodes: 12-2048
+Group 1: (Blocks 8193-16384) [INODE_UNINIT]
+  Backup superblock at 8193, Group descriptors at 8194-8194
+  Reserved GDT blocks at 8195-8450
+  Block bitmap at 8451 (+258), Inode bitmap at 8452 (+259)
+  Inode table at 8453-8708 (+260)
+  7676 free blocks, 0 free inodes, 0 directories
+  Free blocks: 8709-16384
+  Free inodes: 
+Group 2: (Blocks 16385-24576) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 16385 (+0), Inode bitmap at 16386 (+1)
+  Inode table at 16387-16642 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 3: (Blocks 24577-32768) [INODE_UNINIT]
+  Backup superblock at 24577, Group descriptors at 24578-24578
+  Reserved GDT blocks at 24579-24834
+  Block bitmap at 24835 (+258), Inode bitmap at 24836 (+259)
+  Inode table at 24837-25092 (+260)
+  7676 free blocks, 0 free inodes, 0 directories
+  Free blocks: 25093-32768
+  Free inodes: 
+Group 4: (Blocks 32769-40960) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 32769 (+0), Inode bitmap at 32770 (+1)
+  Inode table at 32771-33026 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 5: (Blocks 40961-49152) [INODE_UNINIT]
+  Backup superblock at 40961, Group descriptors at 40962-40962
+  Reserved GDT blocks at 40963-41218
+  Block bitmap at 41219 (+258), Inode bitmap at 41220 (+259)
+  Inode table at 41221-41476 (+260)
+  7676 free blocks, 0 free inodes, 0 directories
+  Free blocks: 41477-49152
+  Free inodes: 
+Group 6: (Blocks 49153-57344) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 49153 (+0), Inode bitmap at 49154 (+1)
+  Inode table at 49155-49410 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 7: (Blocks 57345-65536) [INODE_UNINIT]
+  Backup superblock at 57345, Group descriptors at 57346-57346
+  Reserved GDT blocks at 57347-57602
+  Block bitmap at 57603 (+258), Inode bitmap at 57604 (+259)
+  Inode table at 57605-57860 (+260)
+  7676 free blocks, 0 free inodes, 0 directories
+  Free blocks: 57861-65536
+  Free inodes: 
+Group 8: (Blocks 65537-73728) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 65537 (+0), Inode bitmap at 65538 (+1)
+  Inode table at 65539-65794 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 9: (Blocks 73729-81920) [INODE_UNINIT]
+  Backup superblock at 73729, Group descriptors at 73730-73730
+  Reserved GDT blocks at 73731-73986
+  Block bitmap at 73987 (+258), Inode bitmap at 73988 (+259)
+  Inode table at 73989-74244 (+260)
+  7676 free blocks, 0 free inodes, 0 directories
+  Free blocks: 74245-81920
+  Free inodes: 
+Group 10: (Blocks 81921-90112) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 81921 (+0), Inode bitmap at 81922 (+1)
+  Inode table at 81923-82178 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 11: (Blocks 90113-98304) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 90113 (+0), Inode bitmap at 90114 (+1)
+  Inode table at 90115-90370 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 12: (Blocks 98305-106496) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 98305 (+0), Inode bitmap at 98306 (+1)
+  Inode table at 98307-98562 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 13: (Blocks 106497-114688) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 106497 (+0), Inode bitmap at 106498 (+1)
+  Inode table at 106499-106754 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 14: (Blocks 114689-122880) [INODE_UNINIT, BLOCK_UNINIT]
+  Block bitmap at 114689 (+0), Inode bitmap at 114690 (+1)
+  Inode table at 114691-114946 (+2)
+  0 free blocks, 0 free inodes, 0 directories
+  Free blocks: 
+  Free inodes: 
+Group 15: (Blocks 122881-131071) [ITABLE_ZEROED]
+  Block bitmap at 122881 (+0), Inode bitmap at 122882 (+1)
+  Inode table at 122883-123138 (+2)
+  7933 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 123139-131071
+  Free inodes: 30721-32768
diff --git a/tests/m_lazy_resize/script b/tests/m_lazy_resize/script
new file mode 100644
index 0000000..2ba081f
--- /dev/null
+++ b/tests/m_lazy_resize/script
@@ -0,0 +1,4 @@
+DESCRIPTION="lazy group feature with resize_inode"
+FS_SIZE=131072
+MKE2FS_OPTS="-O resize_inode,lazy_bg"
+. $cmd_dir/run_mke2fs
diff --git a/tests/m_raid_opt/expect.1 b/tests/m_raid_opt/expect.1
index 9bd7894..25b283a 100644
--- a/tests/m_raid_opt/expect.1
+++ b/tests/m_raid_opt/expect.1
@@ -46,57 +46,68 @@
 Directory inode 11, block 1, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1063.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Directory inode 11, block 2, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1064.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Directory inode 11, block 3, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1065.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Directory inode 11, block 4, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1066.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Directory inode 11, block 5, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1067.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Directory inode 11, block 6, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1068.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Directory inode 11, block 7, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1069.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Directory inode 11, block 8, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1070.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Directory inode 11, block 9, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1071.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Directory inode 11, block 10, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1072.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Directory inode 11, block 11, offset 0: directory corrupted
 Salvage? yes
 
-Entry '' in ??? (11) has deleted/unused inode 1073.  Clear? yes
+Entry '' in ??? (11) has a zero-length name.
+Clear? yes
 
 Pass 3: Checking directory connectivity
 '..' in / (2) is <The NULL inode> (0), should be / (2).
diff --git a/tests/m_uninit/expect.1 b/tests/m_uninit/expect.1
new file mode 100644
index 0000000..93cea7b
--- /dev/null
+++ b/tests/m_uninit/expect.1
@@ -0,0 +1,166 @@
+Filesystem label=
+OS type: Linux
+Block size=1024 (log=0)
+Fragment size=1024 (log=0)
+32768 inodes, 131072 blocks
+6553 blocks (5.00%) reserved for the super user
+First data block=1
+Maximum filesystem blocks=67371008
+16 block groups
+8192 blocks per group, 8192 fragments per group
+2048 inodes per group
+Superblock backups stored on blocks: 
+	8193, 24577, 40961, 57345, 73729
+
+Writing inode tables: done                            
+Writing superblocks and filesystem accounting information: done
+
+Filesystem features: ext_attr resize_inode dir_index filetype sparse_super uninit_groups
+ 
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/32768 files (9.1% non-contiguous), 5691/131072 blocks
+Exit status is 0
+
+Filesystem volume name:   <none>
+Last mounted on:          <not available>
+Filesystem magic number:  0xEF53
+Filesystem revision #:    1 (dynamic)
+Filesystem features:      ext_attr resize_inode dir_index filetype sparse_super uninit_groups
+Default mount options:    (none)
+Filesystem state:         clean
+Errors behavior:          Continue
+Filesystem OS type:       Linux
+Inode count:              32768
+Block count:              131072
+Reserved block count:     6553
+Free blocks:              125381
+Free inodes:              32757
+First block:              1
+Block size:               1024
+Fragment size:            1024
+Reserved GDT blocks:      256
+Blocks per group:         8192
+Fragments per group:      8192
+Inodes per group:         2048
+Inode blocks per group:   256
+Mount count:              0
+Check interval:           15552000 (6 months)
+Reserved blocks uid:      0
+Reserved blocks gid:      0
+First inode:              11
+Inode size:		  128
+Default directory hash:   tea
+
+
+Group 0: (Blocks 1-8192) [ITABLE_ZEROED]
+  Primary superblock at 1, Group descriptors at 2-2
+  Reserved GDT blocks at 3-258
+  Block bitmap at 259 (+258), Inode bitmap at 260 (+259)
+  Inode table at 261-516 (+260)
+  7662 free blocks, 2037 free inodes, 2 directories, 2037 unused inodes
+  Free blocks: 531-8192
+  Free inodes: 12-2048
+Group 1: (Blocks 8193-16384) [INODE_UNINIT, ITABLE_ZEROED]
+  Backup superblock at 8193, Group descriptors at 8194-8194
+  Reserved GDT blocks at 8195-8450
+  Block bitmap at 8451 (+258), Inode bitmap at 8452 (+259)
+  Inode table at 8453-8708 (+260)
+  7676 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 8709-16384
+  Free inodes: 
+Group 2: (Blocks 16385-24576) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
+  Block bitmap at 16385 (+0), Inode bitmap at 16386 (+1)
+  Inode table at 16387-16642 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 
+  Free inodes: 
+Group 3: (Blocks 24577-32768) [INODE_UNINIT, ITABLE_ZEROED]
+  Backup superblock at 24577, Group descriptors at 24578-24578
+  Reserved GDT blocks at 24579-24834
+  Block bitmap at 24835 (+258), Inode bitmap at 24836 (+259)
+  Inode table at 24837-25092 (+260)
+  7676 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 25093-32768
+  Free inodes: 
+Group 4: (Blocks 32769-40960) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
+  Block bitmap at 32769 (+0), Inode bitmap at 32770 (+1)
+  Inode table at 32771-33026 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 
+  Free inodes: 
+Group 5: (Blocks 40961-49152) [INODE_UNINIT, ITABLE_ZEROED]
+  Backup superblock at 40961, Group descriptors at 40962-40962
+  Reserved GDT blocks at 40963-41218
+  Block bitmap at 41219 (+258), Inode bitmap at 41220 (+259)
+  Inode table at 41221-41476 (+260)
+  7676 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 41477-49152
+  Free inodes: 
+Group 6: (Blocks 49153-57344) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
+  Block bitmap at 49153 (+0), Inode bitmap at 49154 (+1)
+  Inode table at 49155-49410 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 
+  Free inodes: 
+Group 7: (Blocks 57345-65536) [INODE_UNINIT, ITABLE_ZEROED]
+  Backup superblock at 57345, Group descriptors at 57346-57346
+  Reserved GDT blocks at 57347-57602
+  Block bitmap at 57603 (+258), Inode bitmap at 57604 (+259)
+  Inode table at 57605-57860 (+260)
+  7676 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 57861-65536
+  Free inodes: 
+Group 8: (Blocks 65537-73728) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
+  Block bitmap at 65537 (+0), Inode bitmap at 65538 (+1)
+  Inode table at 65539-65794 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 
+  Free inodes: 
+Group 9: (Blocks 73729-81920) [INODE_UNINIT, ITABLE_ZEROED]
+  Backup superblock at 73729, Group descriptors at 73730-73730
+  Reserved GDT blocks at 73731-73986
+  Block bitmap at 73987 (+258), Inode bitmap at 73988 (+259)
+  Inode table at 73989-74244 (+260)
+  7676 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 74245-81920
+  Free inodes: 
+Group 10: (Blocks 81921-90112) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
+  Block bitmap at 81921 (+0), Inode bitmap at 81922 (+1)
+  Inode table at 81923-82178 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 
+  Free inodes: 
+Group 11: (Blocks 90113-98304) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
+  Block bitmap at 90113 (+0), Inode bitmap at 90114 (+1)
+  Inode table at 90115-90370 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 
+  Free inodes: 
+Group 12: (Blocks 98305-106496) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
+  Block bitmap at 98305 (+0), Inode bitmap at 98306 (+1)
+  Inode table at 98307-98562 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 
+  Free inodes: 
+Group 13: (Blocks 106497-114688) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
+  Block bitmap at 106497 (+0), Inode bitmap at 106498 (+1)
+  Inode table at 106499-106754 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 
+  Free inodes: 
+Group 14: (Blocks 114689-122880) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
+  Block bitmap at 114689 (+0), Inode bitmap at 114690 (+1)
+  Inode table at 114691-114946 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 
+  Free inodes: 
+Group 15: (Blocks 122881-131071) [INODE_UNINIT, ITABLE_ZEROED]
+  Block bitmap at 122881 (+0), Inode bitmap at 122882 (+1)
+  Inode table at 122883-123138 (+2)
+  7933 free blocks, 2048 free inodes, 0 directories, 2048 unused inodes
+  Free blocks: 123139-131071
+  Free inodes: 
diff --git a/tests/m_uninit/script b/tests/m_uninit/script
new file mode 100644
index 0000000..0de2699
--- /dev/null
+++ b/tests/m_uninit/script
@@ -0,0 +1,4 @@
+DESCRIPTION="uninitialized group feature"
+FS_SIZE=131072
+MKE2FS_OPTS="-O uninit_groups"
+. $cmd_dir/run_mke2fs