Merge branch 'maint'

Conflicts:

	configure
diff --git a/MCONFIG.in b/MCONFIG.in
index 8cd2ccf..80ddbd8 100644
--- a/MCONFIG.in
+++ b/MCONFIG.in
@@ -72,7 +72,7 @@
 STATIC_DEVMAPPER_LIBS = @STATIC_DEVMAPPER_LIBS@
 
 LIB = $(top_builddir)/lib
-LIBSS = $(LIB)/libss@LIB_EXT@
+LIBSS = $(LIB)/libss@LIB_EXT@ @DLOPEN_LIB@
 LIBCOM_ERR = $(LIB)/libcom_err@LIB_EXT@
 LIBE2P = $(LIB)/libe2p@LIB_EXT@
 LIBEXT2FS = $(LIB)/libext2fs@LIB_EXT@
@@ -82,7 +82,7 @@
 DEPLIBUUID = $(LIB)/libuuid@LIB_EXT@
 DEPLIBBLKID = $(LIB)/libblkid@LIB_EXT@
 
-STATIC_LIBSS = $(LIB)/libss@STATIC_LIB_EXT@
+STATIC_LIBSS = $(LIB)/libss@STATIC_LIB_EXT@ @DLOPEN_LIB@
 STATIC_LIBCOM_ERR = $(LIB)/libcom_err@STATIC_LIB_EXT@
 STATIC_LIBE2P = $(LIB)/libe2p@STATIC_LIB_EXT@
 STATIC_LIBEXT2FS = $(LIB)/libext2fs@STATIC_LIB_EXT@
@@ -91,7 +91,7 @@
 DEPSTATIC_LIBUUID = $(LIB)/libuuid@STATIC_LIB_EXT@
 DEPSTATIC_LIBBLKID = $(LIB)/libblkid@STATIC_LIB_EXT@
 
-PROFILED_LIBSS = $(LIB)/libss@PROFILED_LIB_EXT@
+PROFILED_LIBSS = $(LIB)/libss@PROFILED_LIB_EXT@ @DLOPEN_LIB@
 PROFILED_LIBCOM_ERR = $(LIB)/libcom_err@PROFILED_LIB_EXT@
 PROFILED_LIBE2P = $(LIB)/libe2p@PROFILED_LIB_EXT@
 PROFILED_LIBEXT2FS = $(LIB)/libext2fs@PROFILED_LIB_EXT@
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/README b/README
index 7988b85..5e231dd 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
-	This is the new version (1.40.10) of the second extended file
-system management programs.
+	This is the new version (1.41-WIP-0427) of the second extended
+file system management programs.
 
 	From time to time, I release new versions of e2fsprogs, to fix
 bugs and to make the utilities more robust.  You can always find
diff --git a/configure b/configure
index bdef3cc..7ec9091 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
@@ -1373,7 +1372,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
@@ -4002,32 +4000,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"
@@ -16095,8 +16067,8 @@
 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
 _ACEOF
 
   if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 73; then
@@ -16170,7 +16142,6 @@
 ac_delim='%!_!# '
 for ac_last_try in false false false false false :; do
   cat >conf$$subs.sed <<_ACEOF
-IMAGER_CMT!$IMAGER_CMT$ac_delim
 RESIZER_CMT!$RESIZER_CMT$ac_delim
 FSCK_PROG!$FSCK_PROG$ac_delim
 FSCK_MAN!$FSCK_MAN$ac_delim
@@ -16259,7 +16230,7 @@
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 87; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 86; 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 5f91d4a..9a43f99 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/Makefile.in b/debugfs/Makefile.in
index bdba326..cb3efcb 100644
--- a/debugfs/Makefile.in
+++ b/debugfs/Makefile.in
@@ -8,7 +8,6 @@
 top_builddir = ..
 my_dir = debugfs
 INSTALL = @INSTALL@
-DLOPEN_LIB = @DLOPEN_LIB@
 
 @MCONFIG@
 
@@ -26,7 +25,7 @@
 	$(srcdir)/htree.c $(srcdir)/unused.c
 
 LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \
-	$(LIBUUID) $(DLOPEN_LIB)
+	$(LIBUUID)
 DEPLIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(DEPLIBBLKID) $(DEPLIBUUID)
 
 .c.o:
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..85facac 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)
@@ -525,7 +539,13 @@
 	const char *i_type;
 	char frag, fsize;
 	int os = current_fs->super->s_creator_os;
-	
+	struct ext2_inode_large *large_inode;
+	int is_large_inode = 0;
+
+	if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
+		is_large_inode = 1;
+	large_inode = (struct ext2_inode_large *) inode;
+
 	if (LINUX_S_ISDIR(inode->i_mode)) i_type = "directory";
 	else if (LINUX_S_ISREG(inode->i_mode)) i_type = "regular";
 	else if (LINUX_S_ISLNK(inode->i_mode)) i_type = "symlink";
@@ -535,9 +555,16 @@
 	else if (LINUX_S_ISSOCK(inode->i_mode)) i_type = "socket";
 	else i_type = "bad type";
 	fprintf(out, "%sInode: %u   Type: %s    ", prefix, inode_num, i_type);
-	fprintf(out, "%sMode:  %04o   Flags: 0x%x   Generation: %u\n",
-		prefix, 
-		inode->i_mode & 0777, inode->i_flags, inode->i_generation);
+	fprintf(out, "%sMode:  %04o   Flags: 0x%x\n",
+		prefix, inode->i_mode & 0777, inode->i_flags);
+	if (is_large_inode && large_inode->i_extra_isize >= 24) {
+		fprintf(out, "%sGeneration: %u    Version: 0x%08x:%08x\n", 
+			prefix, inode->i_generation, large_inode->i_version_hi,
+			inode->osd1.linux1.l_i_version);
+	} else {
+		fprintf(out, "%sGeneration: %u    Version: 0x%08x\n", prefix, 
+			inode->i_generation, inode->osd1.linux1.l_i_version);
+	}
 	fprintf(out, "%sUser: %5d   Group: %5d   Size: ",
 		prefix, inode_uid(*inode), inode_gid(*inode));
 	if (LINUX_S_ISREG(inode->i_mode)) {
@@ -571,21 +598,32 @@
 		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;
 	}
 	fprintf(out, "%sFragment:  Address: %d    Number: %d    Size: %d\n",
 		prefix, inode->i_faddr, frag, fsize);
-	fprintf(out, "%sctime: 0x%08x -- %s", prefix, inode->i_ctime,
-		time_to_string(inode->i_ctime));
-	fprintf(out, "%satime: 0x%08x -- %s", prefix, inode->i_atime,
-		time_to_string(inode->i_atime));
-	fprintf(out, "%smtime: 0x%08x -- %s", prefix, inode->i_mtime,
-		time_to_string(inode->i_mtime));
+	if (is_large_inode && large_inode->i_extra_isize >= 24) {
+		fprintf(out, "%s ctime: 0x%08x:%08x -- %s", prefix, 
+			inode->i_ctime, large_inode->i_ctime_extra,
+			time_to_string(inode->i_ctime));
+		fprintf(out, "%s atime: 0x%08x:%08x -- %s", prefix, 
+			inode->i_atime, large_inode->i_atime_extra,
+			time_to_string(inode->i_atime));
+		fprintf(out, "%s mtime: 0x%08x:%08x -- %s", prefix,
+			inode->i_mtime, large_inode->i_mtime_extra,
+			time_to_string(inode->i_mtime));
+		fprintf(out, "%scrtime: 0x%08x:%08x -- %s", prefix,
+			large_inode->i_crtime, large_inode->i_crtime_extra,
+			time_to_string(large_inode->i_crtime));
+	} else {
+		fprintf(out, "%sctime: 0x%08x -- %s", prefix, inode->i_ctime,
+			time_to_string(inode->i_ctime));
+		fprintf(out, "%satime: 0x%08x -- %s", prefix, inode->i_atime,
+			time_to_string(inode->i_atime));
+		fprintf(out, "%smtime: 0x%08x -- %s", prefix, inode->i_mtime,
+			time_to_string(inode->i_mtime));
+	}
 	if (inode->i_dtime) 
 	  fprintf(out, "%sdtime: 0x%08x -- %s", prefix, inode->i_dtime,
 		  time_to_string(inode->i_dtime));
@@ -791,7 +829,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 +851,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 +873,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 +942,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 +1050,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 +1058,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 +1150,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 +1163,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 +1548,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 +1847,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 +1858,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 +1899,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 +1908,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 +1921,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..25343f0 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 },
@@ -127,6 +132,7 @@
 	{ "mmp_interval", &set_sb.s_mmp_interval, 2, parse_uint },
 	{ "mmp_block", &set_sb.s_mmp_block, 8, parse_uint },
 	{ "raid_stripe_width", &set_sb.s_raid_stripe_width, 4, parse_uint },
+	{ "log_groups_per_flex", &set_sb.s_log_groups_per_flex, 1, parse_uint },
 	{ 0, 0, 0, 0 }
 };
 
@@ -175,7 +181,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 +405,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 +537,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 b887ad6..a4b6c6a 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..32743bc 100644
--- a/e2fsck/Makefile.in
+++ b/e2fsck/Makefile.in
@@ -61,22 +61,24 @@
 #
 #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 \
-	ehandler.o problem.o message.o recovery.o region.o revoke.o \
-	ea_refcount.o rehash.o profile.o prof_err.o $(MTRACE_OBJ)
+OBJS= crc32.o dict.o unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o \
+	pass3.o pass4.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)
 
 PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \
 	profiled/super.o profiled/pass1.o profiled/pass1b.o \
 	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
 
 SRCS= $(srcdir)/e2fsck.c \
+	$(srcdir)/crc32.c \
+	$(srcdir)/gen_crc32table.c \
 	$(srcdir)/dict.c \
 	$(srcdir)/super.c \
 	$(srcdir)/pass1.c \
@@ -96,7 +98,6 @@
 	$(srcdir)/ehandler.c \
 	$(srcdir)/problem.c \
 	$(srcdir)/message.c \
-	$(srcdir)/swapfs.c \
 	$(srcdir)/ea_refcount.c \
 	$(srcdir)/rehash.c \
 	$(srcdir)/region.c \
@@ -126,6 +127,19 @@
 	@$(LD) $(ALL_LDFLAGS) -g -pg -o e2fsck.profiled $(PROFILED_OBJS) \
 		$(PROFILED_LIBS) 
 
+gen_crc32table: $(srcdir)/gen_crc32table.c
+	@echo "	CC $@"
+	@$(BUILD_CC) $(ALL_CFLAGS) -o gen_crc32table \
+		$(srcdir)/gen_crc32table.c
+
+crc32table.h: gen_crc32table
+	@echo "	GEN32TABLE $@"
+	@./gen_crc32table > crc32table.h
+
+tst_crc32: $(srcdir)/crc32.c $(LIBEXT2FS)
+	@$(CC) $(BUILD_LDFLAGS) $(ALL_CFLAGS) -o tst_crc32 $(srcdir)/crc32.c \
+		-DUNITTEST $(LIBEXT2FS)
+
 tst_refcount: ea_refcount.c
 	@echo "	LD $@"
 	@$(CC) -o tst_refcount $(srcdir)/ea_refcount.c \
@@ -136,6 +150,11 @@
 	@$(CC) -o tst_region $(srcdir)/region.c \
 		$(ALL_CFLAGS) -DTEST_PROGRAM -lcom_err
 
+check:: tst_refcount tst_region tst_crc32
+	./tst_refcount
+	./tst_region
+	./tst_crc32
+
 extend: extend.o
 	@echo "	LD $@"
 	@$(LD) $(ALL_LDFLAGS) -o extend extend.o $(CHECKLIB)
@@ -183,6 +202,12 @@
 	@echo "	LINK $(root_sbindir)/fsck.ext3"
 	@$(LN) -f $(DESTDIR)$(root_sbindir)/e2fsck \
 			$(DESTDIR)$(root_sbindir)/fsck.ext3
+	@echo "	LINK $(root_sbindir)/fsck.ext4"
+	@$(LN) -f $(DESTDIR)$(root_sbindir)/e2fsck \
+			$(DESTDIR)$(root_sbindir)/fsck.ext4
+	@echo "	LINK $(root_sbindir)/fsck.ext4dev"
+	@$(LN) -f $(DESTDIR)$(root_sbindir)/e2fsck \
+			$(DESTDIR)$(root_sbindir)/fsck.ext4dev
 	@for i in $(MANPAGES); do \
 		for j in $(COMPRESS_EXT); do \
 			$(RM) -f $(DESTDIR)$(man8dir)/$$i.$$j; \
@@ -203,6 +228,12 @@
 	@echo "	LINK $(man8dir)/fsck.ext3.8"
 	@$(LN) -f $(DESTDIR)$(man8dir)/e2fsck.8 \
 		$(DESTDIR)$(man8dir)/fsck.ext3.8
+	@echo "	LINK $(man8dir)/fsck.ext4.8"
+	@$(LN) -f $(DESTDIR)$(man8dir)/e2fsck.8 \
+		$(DESTDIR)$(man8dir)/fsck.ext4.8
+	@echo "	LINK $(man8dir)/fsck.ext4.8"
+	@$(LN) -f $(DESTDIR)$(man8dir)/e2fsck.8 \
+		$(DESTDIR)$(man8dir)/fsck.ext4dev.8
 
 install-strip: install
 	@for i in $(PROGS); do \
@@ -215,7 +246,9 @@
 		$(RM) -f $(DESTDIR)$(root_sbindir)/$$i; \
 	done
 	$(RM) -f $(DESTDIR)$(root_sbindir)/fsck.ext2 \
-		$(DESTDIR)$(root_sbindir)/fsck.ext3
+		$(DESTDIR)$(root_sbindir)/fsck.ext3 \
+		$(DESTDIR)$(root_sbindir)/fsck.ext4 \
+		$(DESTDIR)$(root_sbindir)/fsck.ext4dev
 	for i in $(MANPAGES); do \
 		$(RM) -f $(DESTDIR)$(man8dir)/$$i; \
 	done
@@ -223,11 +256,16 @@
 		$(RM) -f $(DESTDIR)$(man5dir)/$$i; \
 	done
 	$(RM) -f $(DESTDIR)$(root_sbindir)/fsck.ext2 \
-			$(DESTDIR)$(root_sbindir)/fsck.ext3
+			$(DESTDIR)$(root_sbindir)/fsck.ext3 \
+			$(DESTDIR)$(root_sbindir)/fsck.ext4 \
+			$(DESTDIR)$(root_sbindir)/fsck.ext4dev
 
 clean:
 	$(RM) -f $(PROGS) \#* *\# *.s *.o *.a *~ core e2fsck.static \
-		e2fsck.shared e2fsck.profiled flushb e2fsck.8
+		e2fsck.shared e2fsck.profiled flushb e2fsck.8 \
+		tst_crc32 tst_region tst_refcount gen_crc32table \
+		crc32table.h e2fsck.conf.5 prof_err.c prof_err.h \
+		test_profile
 	$(RM) -rf profiled
 
 mostlyclean: clean
@@ -242,66 +280,83 @@
 e2fsck.o: $(srcdir)/e2fsck.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
+crc32.o: $(srcdir)/crc32.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 \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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)/crc32defs.h crc32table.h
+gen_crc32table.o: $(srcdir)/gen_crc32table.c $(srcdir)/crc32defs.h
 dict.o: $(srcdir)/dict.c $(srcdir)/dict.h
 super.o: $(srcdir)/super.c $(top_srcdir)/lib/uuid/uuid.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/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
 pass1.o: $(srcdir)/pass1.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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 $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h \
- $(srcdir)/problem.h
+ $(srcdir)/profile.h prof_err.h $(srcdir)/problem.h
 pass1b.o: $(srcdir)/pass1b.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/ext2fs/ext2_fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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 $(srcdir)/dict.h
 pass2.o: $(srcdir)/pass2.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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 $(srcdir)/dict.h
 pass3.o: $(srcdir)/pass3.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
 pass4.o: $(srcdir)/pass4.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
 pass5.o: $(srcdir)/pass5.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
 journal.o: $(srcdir)/journal.c $(srcdir)/jfs_user.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/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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 $(top_srcdir)/lib/ext2fs/kernel-jbd.h \
  $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h \
@@ -309,103 +364,111 @@
 recovery.o: $(srcdir)/recovery.c $(srcdir)/jfs_user.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/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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 $(top_srcdir)/lib/ext2fs/kernel-jbd.h \
  $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h
 revoke.o: $(srcdir)/revoke.c $(srcdir)/jfs_user.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/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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 $(top_srcdir)/lib/ext2fs/kernel-jbd.h \
  $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h
 badblocks.o: $(srcdir)/badblocks.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/ext2fs/ext2_fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
 util.o: $(srcdir)/util.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
-unix.o: $(srcdir)/unix.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 \
+unix.o: $(srcdir)/unix.c $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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 $(top_srcdir)/version.h
 dirinfo.o: $(srcdir)/dirinfo.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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)/profile.h prof_err.h $(top_srcdir)/lib/uuid/uuid.h \
+ $(top_srcdir)/lib/ext2fs/tdb.h
 dx_dirinfo.o: $(srcdir)/dx_dirinfo.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
 ehandler.o: $(srcdir)/ehandler.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
 problem.o: $(srcdir)/problem.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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 $(srcdir)/problemP.h
 message.o: $(srcdir)/message.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
 rehash.o: $(srcdir)/rehash.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
 region.o: $(srcdir)/region.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 \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.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
-profile.o: $(srcdir)/profile.c $(srcdir)/profile.h prof_err.h \
- $(top_srcdir)/lib/et/com_err.h
+profile.o: $(srcdir)/profile.c $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/profile.h prof_err.h
 prof_err.o: prof_err.c
diff --git a/e2fsck/crc32.c b/e2fsck/crc32.c
new file mode 100644
index 0000000..e9fd244
--- /dev/null
+++ b/e2fsck/crc32.c
@@ -0,0 +1,566 @@
+/*
+ * crc32.c --- CRC32 function
+ *
+ * Copyright (C) 2008 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/*
+ * Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Nicer crc32 functions/docs submitted by linux@horizon.com.  Thanks!
+ * Code was from the public domain, copyright abandoned.  Code was
+ * subsequently included in the kernel, thus was re-licensed under the
+ * GNU GPL v2.
+ *
+ * Oct 12, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Same crc32 function was used in 5 other places in the kernel.
+ * I made one version, and deleted the others.
+ * There are various incantations of crc32().  Some use a seed of 0 or ~0.
+ * Some xor at the end with ~0.  The generic crc32() function takes
+ * seed as an argument, and doesn't xor at the end.  Then individual
+ * users can do whatever they need.
+ *   drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
+ *   fs/jffs2 uses seed 0, doesn't xor with ~0.
+ *   fs/partitions/efi.c uses seed ~0, xor's with ~0.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "e2fsck.h"
+
+#include "crc32defs.h"
+#if CRC_LE_BITS == 8
+#define tole(x) __constant_cpu_to_le32(x)
+#define tobe(x) __constant_cpu_to_be32(x)
+#else
+#define tole(x) (x)
+#define tobe(x) (x)
+#endif
+#include "crc32table.h"
+
+#ifdef UNITTEST
+
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *	other uses, or the previous crc32 value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+__u32 crc32_le(__u32 crc, unsigned char const *p, size_t len);
+
+#if CRC_LE_BITS == 1
+/*
+ * In fact, the table-based code will work in this case, but it can be
+ * simplified by inlining the table in ?: form.
+ */
+
+__u32 crc32_le(__u32 crc, unsigned char const *p, size_t len)
+{
+	int i;
+	while (len--) {
+		crc ^= *p++;
+		for (i = 0; i < 8; i++)
+			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+	}
+	return crc;
+}
+#else				/* Table-based approach */
+
+__u32 crc32_le(__u32 crc, unsigned char const *p, size_t len)
+{
+# if CRC_LE_BITS == 8
+	const __u32      *b =(__u32 *)p;
+	const __u32      *tab = crc32table_le;
+
+# ifdef __LITTLE_ENDIAN
+#  define DO_CRC(x) crc = tab[ (crc ^ (x)) & 255 ] ^ (crc>>8)
+# else
+#  define DO_CRC(x) crc = tab[ ((crc >> 24) ^ (x)) & 255] ^ (crc<<8)
+# endif
+
+	crc = __cpu_to_le32(crc);
+	/* Align it */
+	if(unlikely(((long)b)&3 && len)){
+		do {
+			__u8 *p = (__u8 *)b;
+			DO_CRC(*p++);
+			b = (void *)p;
+		} while ((--len) && ((long)b)&3 );
+	}
+	if(likely(len >= 4)){
+		/* load data 32 bits wide, xor data 32 bits wide. */
+		size_t save_len = len & 3;
+	        len = len >> 2;
+		--b; /* use pre increment below(*++b) for speed */
+		do {
+			crc ^= *++b;
+			DO_CRC(0);
+			DO_CRC(0);
+			DO_CRC(0);
+			DO_CRC(0);
+		} while (--len);
+		b++; /* point to next byte(s) */
+		len = save_len;
+	}
+	/* And the last few bytes */
+	if(len){
+		do {
+			__u8 *p = (__u8 *)b;
+			DO_CRC(*p++);
+			b = (void *)p;
+		} while (--len);
+	}
+
+	return __le32_to_cpu(crc);
+#undef ENDIAN_SHIFT
+#undef DO_CRC
+
+# elif CRC_LE_BITS == 4
+	while (len--) {
+		crc ^= *p++;
+		crc = (crc >> 4) ^ crc32table_le[crc & 15];
+		crc = (crc >> 4) ^ crc32table_le[crc & 15];
+	}
+	return crc;
+# elif CRC_LE_BITS == 2
+	while (len--) {
+		crc ^= *p++;
+		crc = (crc >> 2) ^ crc32table_le[crc & 3];
+		crc = (crc >> 2) ^ crc32table_le[crc & 3];
+		crc = (crc >> 2) ^ crc32table_le[crc & 3];
+		crc = (crc >> 2) ^ crc32table_le[crc & 3];
+	}
+	return crc;
+# endif
+}
+#endif
+
+#endif /* UNITTEST */
+
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *	other uses, or the previous crc32 value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+__u32 crc32_be(__u32 crc, unsigned char const *p, size_t len);
+
+#if CRC_BE_BITS == 1
+/*
+ * In fact, the table-based code will work in this case, but it can be
+ * simplified by inlining the table in ?: form.
+ */
+
+__u32 crc32_be(__u32 crc, unsigned char const *p, size_t len)
+{
+	int i;
+	while (len--) {
+		crc ^= *p++ << 24;
+		for (i = 0; i < 8; i++)
+			crc =
+			    (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
+					  0);
+	}
+	return crc;
+}
+
+#else				/* Table-based approach */
+__u32 crc32_be(__u32 crc, unsigned char const *p, size_t len)
+{
+# if CRC_BE_BITS == 8
+	const __u32      *b =(const __u32 *)p;
+	const __u32      *tab = crc32table_be;
+
+# ifdef __LITTLE_ENDIAN
+#  define DO_CRC(x) crc = tab[ (crc ^ (x)) & 255 ] ^ (crc>>8)
+# else
+#  define DO_CRC(x) crc = tab[ ((crc >> 24) ^ (x)) & 255] ^ (crc<<8)
+# endif
+
+	crc = __cpu_to_be32(crc);
+	/* Align it */
+	if(unlikely(((long)b)&3 && len)){
+		do {
+			const __u8 *q = (const __u8 *)b;
+			DO_CRC(*q++);
+			b = (const __u32 *)q;
+		} while ((--len) && ((long)b)&3 );
+	}
+	if(likely(len >= 4)){
+		/* load data 32 bits wide, xor data 32 bits wide. */
+		size_t save_len = len & 3;
+	        len = len >> 2;
+		--b; /* use pre increment below(*++b) for speed */
+		do {
+			crc ^= *++b;
+			DO_CRC(0);
+			DO_CRC(0);
+			DO_CRC(0);
+			DO_CRC(0);
+		} while (--len);
+		b++; /* point to next byte(s) */
+		len = save_len;
+	}
+	/* And the last few bytes */
+	if(len){
+		do {
+			const __u8 *q = (const __u8 *)b;
+			DO_CRC(*q++);
+			b = (const void *)q;
+		} while (--len);
+	}
+	return __be32_to_cpu(crc);
+#undef ENDIAN_SHIFT
+#undef DO_CRC
+
+# elif CRC_BE_BITS == 4
+	while (len--) {
+		crc ^= *p++ << 24;
+		crc = (crc << 4) ^ crc32table_be[crc >> 28];
+		crc = (crc << 4) ^ crc32table_be[crc >> 28];
+	}
+	return crc;
+# elif CRC_BE_BITS == 2
+	while (len--) {
+		crc ^= *p++ << 24;
+		crc = (crc << 2) ^ crc32table_be[crc >> 30];
+		crc = (crc << 2) ^ crc32table_be[crc >> 30];
+		crc = (crc << 2) ^ crc32table_be[crc >> 30];
+		crc = (crc << 2) ^ crc32table_be[crc >> 30];
+	}
+	return crc;
+# endif
+}
+#endif
+
+/*
+ * A brief CRC tutorial.
+ *
+ * A CRC is a long-division remainder.  You add the CRC to the message,
+ * and the whole thing (message+CRC) is a multiple of the given
+ * CRC polynomial.  To check the CRC, you can either check that the
+ * CRC matches the recomputed value, *or* you can check that the
+ * remainder computed on the message+CRC is 0.  This latter approach
+ * is used by a lot of hardware implementations, and is why so many
+ * protocols put the end-of-frame flag after the CRC.
+ *
+ * It's actually the same long division you learned in school, except that
+ * - We're working in binary, so the digits are only 0 and 1, and
+ * - When dividing polynomials, there are no carries.  Rather than add and
+ *   subtract, we just xor.  Thus, we tend to get a bit sloppy about
+ *   the difference between adding and subtracting.
+ *
+ * A 32-bit CRC polynomial is actually 33 bits long.  But since it's
+ * 33 bits long, bit 32 is always going to be set, so usually the CRC
+ * is written in hex with the most significant bit omitted.  (If you're
+ * familiar with the IEEE 754 floating-point format, it's the same idea.)
+ *
+ * Note that a CRC is computed over a string of *bits*, so you have
+ * to decide on the endianness of the bits within each byte.  To get
+ * the best error-detecting properties, this should correspond to the
+ * order they're actually sent.  For example, standard RS-232 serial is
+ * little-endian; the most significant bit (sometimes used for parity)
+ * is sent last.  And when appending a CRC word to a message, you should
+ * do it in the right order, matching the endianness.
+ *
+ * Just like with ordinary division, the remainder is always smaller than
+ * the divisor (the CRC polynomial) you're dividing by.  Each step of the
+ * division, you take one more digit (bit) of the dividend and append it
+ * to the current remainder.  Then you figure out the appropriate multiple
+ * of the divisor to subtract to being the remainder back into range.
+ * In binary, it's easy - it has to be either 0 or 1, and to make the
+ * XOR cancel, it's just a copy of bit 32 of the remainder.
+ *
+ * When computing a CRC, we don't care about the quotient, so we can
+ * throw the quotient bit away, but subtract the appropriate multiple of
+ * the polynomial from the remainder and we're back to where we started,
+ * ready to process the next bit.
+ *
+ * A big-endian CRC written this way would be coded like:
+ * for (i = 0; i < input_bits; i++) {
+ * 	multiple = remainder & 0x80000000 ? CRCPOLY : 0;
+ * 	remainder = (remainder << 1 | next_input_bit()) ^ multiple;
+ * }
+ * Notice how, to get at bit 32 of the shifted remainder, we look
+ * at bit 31 of the remainder *before* shifting it.
+ *
+ * But also notice how the next_input_bit() bits we're shifting into
+ * the remainder don't actually affect any decision-making until
+ * 32 bits later.  Thus, the first 32 cycles of this are pretty boring.
+ * Also, to add the CRC to a message, we need a 32-bit-long hole for it at
+ * the end, so we have to add 32 extra cycles shifting in zeros at the
+ * end of every message,
+ *
+ * So the standard trick is to rearrage merging in the next_input_bit()
+ * until the moment it's needed.  Then the first 32 cycles can be precomputed,
+ * and merging in the final 32 zero bits to make room for the CRC can be
+ * skipped entirely.
+ * This changes the code to:
+ * for (i = 0; i < input_bits; i++) {
+ *      remainder ^= next_input_bit() << 31;
+ * 	multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * 	remainder = (remainder << 1) ^ multiple;
+ * }
+ * With this optimization, the little-endian code is simpler:
+ * for (i = 0; i < input_bits; i++) {
+ *      remainder ^= next_input_bit();
+ * 	multiple = (remainder & 1) ? CRCPOLY : 0;
+ * 	remainder = (remainder >> 1) ^ multiple;
+ * }
+ *
+ * Note that the other details of endianness have been hidden in CRCPOLY
+ * (which must be bit-reversed) and next_input_bit().
+ *
+ * However, as long as next_input_bit is returning the bits in a sensible
+ * order, we can actually do the merging 8 or more bits at a time rather
+ * than one bit at a time:
+ * for (i = 0; i < input_bytes; i++) {
+ * 	remainder ^= next_input_byte() << 24;
+ * 	for (j = 0; j < 8; j++) {
+ * 		multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * 		remainder = (remainder << 1) ^ multiple;
+ * 	}
+ * }
+ * Or in little-endian:
+ * for (i = 0; i < input_bytes; i++) {
+ * 	remainder ^= next_input_byte();
+ * 	for (j = 0; j < 8; j++) {
+ * 		multiple = (remainder & 1) ? CRCPOLY : 0;
+ * 		remainder = (remainder << 1) ^ multiple;
+ * 	}
+ * }
+ * If the input is a multiple of 32 bits, you can even XOR in a 32-bit
+ * word at a time and increase the inner loop count to 32.
+ *
+ * You can also mix and match the two loop styles, for example doing the
+ * bulk of a message byte-at-a-time and adding bit-at-a-time processing
+ * for any fractional bytes at the end.
+ *
+ * The only remaining optimization is to the byte-at-a-time table method.
+ * Here, rather than just shifting one bit of the remainder to decide
+ * in the correct multiple to subtract, we can shift a byte at a time.
+ * This produces a 40-bit (rather than a 33-bit) intermediate remainder,
+ * but again the multiple of the polynomial to subtract depends only on
+ * the high bits, the high 8 bits in this case.
+ *
+ * The multiple we need in that case is the low 32 bits of a 40-bit
+ * value whose high 8 bits are given, and which is a multiple of the
+ * generator polynomial.  This is simply the CRC-32 of the given
+ * one-byte message.
+ *
+ * Two more details: normally, appending zero bits to a message which
+ * is already a multiple of a polynomial produces a larger multiple of that
+ * polynomial.  To enable a CRC to detect this condition, it's common to
+ * invert the CRC before appending it.  This makes the remainder of the
+ * message+crc come out not as zero, but some fixed non-zero value.
+ *
+ * The same problem applies to zero bits prepended to the message, and
+ * a similar solution is used.  Instead of starting with a remainder of
+ * 0, an initial remainder of all ones is used.  As long as you start
+ * the same way on decoding, it doesn't make a difference.
+ */
+
+#ifdef UNITTEST
+
+#include <stdlib.h>
+#include <stdio.h>
+
+const __u8 byte_rev_table[256] = {
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+static inline __u8 bitrev8(__u8 byte)
+{
+	return byte_rev_table[byte];
+}
+
+static inline __u16 bitrev16(__u16 x)
+{
+	return (bitrev8(x & 0xff) << 8) | bitrev8(x >> 8);
+}
+
+/**
+ * bitrev32 - reverse the order of bits in a u32 value
+ * @x: value to be bit-reversed
+ */
+static __u32 bitrev32(__u32 x)
+{
+	return (bitrev16(x & 0xffff) << 16) | bitrev16(x >> 16);
+}
+
+#if 0				/*Not used at present */
+
+static void
+buf_dump(char const *prefix, unsigned char const *buf, size_t len)
+{
+	fputs(prefix, stdout);
+	while (len--)
+		printf(" %02x", *buf++);
+	putchar('\n');
+
+}
+#endif
+
+static void bytereverse(unsigned char *buf, size_t len)
+{
+	while (len--) {
+		unsigned char x = bitrev8(*buf);
+		*buf++ = x;
+	}
+}
+
+static void random_garbage(unsigned char *buf, size_t len)
+{
+	while (len--)
+		*buf++ = (unsigned char) random();
+}
+
+#if 0				/* Not used at present */
+static void store_le(__u32 x, unsigned char *buf)
+{
+	buf[0] = (unsigned char) x;
+	buf[1] = (unsigned char) (x >> 8);
+	buf[2] = (unsigned char) (x >> 16);
+	buf[3] = (unsigned char) (x >> 24);
+}
+#endif
+
+static void store_be(__u32 x, unsigned char *buf)
+{
+	buf[0] = (unsigned char) (x >> 24);
+	buf[1] = (unsigned char) (x >> 16);
+	buf[2] = (unsigned char) (x >> 8);
+	buf[3] = (unsigned char) x;
+}
+
+/*
+ * This checks that CRC(buf + CRC(buf)) = 0, and that
+ * CRC commutes with bit-reversal.  This has the side effect
+ * of bytewise bit-reversing the input buffer, and returns
+ * the CRC of the reversed buffer.
+ */
+static __u32 test_step(__u32 init, unsigned char *buf, size_t len)
+{
+	__u32 crc1, crc2;
+	size_t i;
+
+	crc1 = crc32_be(init, buf, len);
+	store_be(crc1, buf + len);
+	crc2 = crc32_be(init, buf, len + 4);
+	if (crc2)
+		printf("\nCRC cancellation fail: 0x%08x should be 0\n",
+		       crc2);
+
+	for (i = 0; i <= len + 4; i++) {
+		crc2 = crc32_be(init, buf, i);
+		crc2 = crc32_be(crc2, buf + i, len + 4 - i);
+		if (crc2)
+			printf("\nCRC split fail: 0x%08x\n", crc2);
+	}
+
+	/* Now swap it around for the other test */
+
+	bytereverse(buf, len + 4);
+	init = bitrev32(init);
+	crc2 = bitrev32(crc1);
+	if (crc1 != bitrev32(crc2))
+		printf("\nBit reversal fail: 0x%08x -> 0x%08x -> 0x%08x\n",
+		       crc1, crc2, bitrev32(crc2));
+	crc1 = crc32_le(init, buf, len);
+	if (crc1 != crc2)
+		printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
+		       crc2);
+	crc2 = crc32_le(init, buf, len + 4);
+	if (crc2)
+		printf("\nCRC cancellation fail: 0x%08x should be 0\n",
+		       crc2);
+
+	for (i = 0; i <= len + 4; i++) {
+		crc2 = crc32_le(init, buf, i);
+		crc2 = crc32_le(crc2, buf + i, len + 4 - i);
+		if (crc2)
+			printf("\nCRC split fail: 0x%08x\n", crc2);
+	}
+
+	return crc1;
+}
+
+#define SIZE 64
+#define INIT1 0
+#define INIT2 0
+
+int main(int argc, char **argv)
+{
+	unsigned char buf1[SIZE + 4];
+	unsigned char buf2[SIZE + 4];
+	unsigned char buf3[SIZE + 4];
+	int i, j;
+	__u32 crc1, crc2, crc3;
+	int exit_status = 0;
+
+	for (i = 0; i <= SIZE; i++) {
+		printf("\rTesting length %d...", i);
+		fflush(stdout);
+		random_garbage(buf1, i);
+		random_garbage(buf2, i);
+		for (j = 0; j < i; j++)
+			buf3[j] = buf1[j] ^ buf2[j];
+
+		crc1 = test_step(INIT1, buf1, i);
+		crc2 = test_step(INIT2, buf2, i);
+		/* Now check that CRC(buf1 ^ buf2) = CRC(buf1) ^ CRC(buf2) */
+		crc3 = test_step(INIT1 ^ INIT2, buf3, i);
+		if (crc3 != (crc1 ^ crc2)) {
+			printf("CRC XOR fail: 0x%08x != 0x%08x ^ 0x%08x\n",
+			       crc3, crc1, crc2);
+			exit_status++;
+		}
+	}
+	printf("\nAll test complete.  No failures expected.\n");
+	return 0;
+}
+
+#endif				/* UNITTEST */
diff --git a/e2fsck/crc32defs.h b/e2fsck/crc32defs.h
new file mode 100644
index 0000000..7d770d3
--- /dev/null
+++ b/e2fsck/crc32defs.h
@@ -0,0 +1,64 @@
+/*
+ * There are multiple 16-bit CRC polynomials in common use, but this is
+ * *the* standard CRC-32 polynomial, first popularized by Ethernet.
+ * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
+ */
+#define CRCPOLY_LE 0xedb88320
+#define CRCPOLY_BE 0x04c11db7
+
+/* How many bits at a time to use.  Requires a table of 4<<CRC_xx_BITS bytes. */
+/* For less performance-sensitive, use 4 */
+#ifndef CRC_LE_BITS
+# define CRC_LE_BITS 8
+#endif
+#ifndef CRC_BE_BITS
+# define CRC_BE_BITS 8
+#endif
+
+/*
+ * Little-endian CRC computation.  Used with serial bit streams sent
+ * lsbit-first.  Be sure to use cpu_to_le32() to append the computed CRC.
+ */
+#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
+# error CRC_LE_BITS must be a power of 2 between 1 and 8
+#endif
+
+/*
+ * Big-endian CRC computation.  Used with serial bit streams sent
+ * msbit-first.  Be sure to use cpu_to_be32() to append the computed CRC.
+ */
+#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
+# error CRC_BE_BITS must be a power of 2 between 1 and 8
+#endif
+
+#define ___constant_swab32(x) \
+	((__u32)( \
+		(((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
+		(((__u32)(x) & (__u32)0x0000ff00UL) <<  8) | \
+		(((__u32)(x) & (__u32)0x00ff0000UL) >>  8) | \
+		(((__u32)(x) & (__u32)0xff000000UL) >> 24) ))
+
+
+#ifdef WORDS_BIGENDIAN
+#define __constant_cpu_to_le32(x) ___constant_swab32((x))
+#define __constant_cpu_to_be32(x) (x)
+#define __be32_to_cpu(x) (x)
+#define __cpu_to_be32(x) (x)
+#define __cpu_to_le32(x) (ext2fs_swab32((x)))
+#define __le32_to_cpu(x) (ext2fs_swab32((x)))
+#else
+#define __constant_cpu_to_le32(x) (x)
+#define __constant_cpu_to_be32(x) ___constant_swab32((x))
+#define __be32_to_cpu(x) (ext2fs_swab32((x)))
+#define __cpu_to_be32(x) (ext2fs_swab32((x)))
+#define __cpu_to_le32(x) (x)
+#define __le32_to_cpu(x) (x)
+#endif
+
+#ifdef __GNUC__
+#define likely(x)	__builtin_expect(!!(x), 1)
+#define unlikely(x)	__builtin_expect(!!(x), 0)
+#else
+#define likely(x)	(x)
+#define unlikely(x)	(x)
+#endif
diff --git a/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..5523ed6 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
 
@@ -372,6 +374,9 @@
 extern void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file,
 				 int replace_bad_blocks);
 
+/* crc32.c */
+extern __u32 crc32_be(__u32 crc, unsigned char const *p, size_t len);
+
 /* dirinfo.c */
 extern void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent);
 extern void e2fsck_free_dir_info(e2fsck_t ctx);
@@ -427,8 +432,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 +464,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 +474,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/emptydir.c b/e2fsck/emptydir.c
index 5dbf021..6baab76 100644
--- a/e2fsck/emptydir.c
+++ b/e2fsck/emptydir.c
@@ -168,8 +168,7 @@
 
 	if (edi->freed_blocks) {
 		edi->inode.i_size -= edi->freed_blocks * fs->blocksize;
-		edi->inode.i_blocks -= edi->freed_blocks *
-			(fs->blocksize / 512);
+		ext2fs_iblk_add_blocks(fs, &edi->inode, edi->freed_blocks);
 		retval = ext2fs_write_inode(fs, db->ino, &edi->inode);
 		if (retval)
 			return 0;
diff --git a/e2fsck/gen_crc32table.c b/e2fsck/gen_crc32table.c
new file mode 100644
index 0000000..89b32b2
--- /dev/null
+++ b/e2fsck/gen_crc32table.c
@@ -0,0 +1,95 @@
+/*
+ * gen_crc32table.c --- Generate CRC32 tables.
+ *
+ * Copyright (C) 2008 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include "crc32defs.h"
+#include <inttypes.h>
+
+#define ENTRIES_PER_LINE 4
+
+#define LE_TABLE_SIZE (1 << CRC_LE_BITS)
+#define BE_TABLE_SIZE (1 << CRC_BE_BITS)
+
+static uint32_t crc32table_le[LE_TABLE_SIZE];
+static uint32_t crc32table_be[BE_TABLE_SIZE];
+
+/**
+ * crc32init_le() - allocate and initialize LE table data
+ *
+ * crc is the crc of the byte i; other entries are filled in based on the
+ * fact that crctable[i^j] = crctable[i] ^ crctable[j].
+ *
+ */
+static void crc32init_le(void)
+{
+	unsigned i, j;
+	uint32_t crc = 1;
+
+	crc32table_le[0] = 0;
+
+	for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
+		crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+		for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
+			crc32table_le[i + j] = crc ^ crc32table_le[j];
+	}
+}
+
+/**
+ * crc32init_be() - allocate and initialize BE table data
+ */
+static void crc32init_be(void)
+{
+	unsigned i, j;
+	uint32_t crc = 0x80000000;
+
+	crc32table_be[0] = 0;
+
+	for (i = 1; i < BE_TABLE_SIZE; i <<= 1) {
+		crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
+		for (j = 0; j < i; j++)
+			crc32table_be[i + j] = crc ^ crc32table_be[j];
+	}
+}
+
+static void output_table(uint32_t table[], int len, const char *trans)
+{
+	int i;
+
+	for (i = 0; i < len - 1; i++) {
+		if (i % ENTRIES_PER_LINE == 0)
+			printf("\n");
+		printf("%s(0x%8.8xL), ", trans, table[i]);
+	}
+	printf("%s(0x%8.8xL)\n", trans, table[len - 1]);
+}
+
+int main(int argc, char** argv)
+{
+	printf("/* this file is generated - do not edit */\n\n");
+
+	printf("#ifdef UNITTEST\n");
+	if (CRC_LE_BITS > 1) {
+		crc32init_le();
+		printf("static const __u32 crc32table_le[] = {");
+		output_table(crc32table_le, LE_TABLE_SIZE, "tole");
+		printf("};\n");
+	}
+	printf("#endif /* UNITTEST */\n");
+
+	if (CRC_BE_BITS > 1) {
+		crc32init_be();
+		printf("static const __u32 crc32table_be[] = {");
+		output_table(crc32table_be, BE_TABLE_SIZE, "tobe");
+		printf("};\n");
+	}
+
+	return 0;
+}
diff --git a/e2fsck/jfs_user.h b/e2fsck/jfs_user.h
index 9da5a16..09d348c 100644
--- a/e2fsck/jfs_user.h
+++ b/e2fsck/jfs_user.h
@@ -70,6 +70,13 @@
 extern kmem_cache_t * do_cache_create(int len);
 extern void do_cache_destroy(kmem_cache_t *cache);
 	
+#define __init
+
+/*
+ * Now pull in the real linux/jfs.h definitions.
+ */
+#include <ext2fs/kernel-jbd.h>
+
 #if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
 #ifdef E2FSCK_INCLUDE_INLINE_FUNCS
 #define _INLINE_ extern
@@ -94,15 +101,20 @@
 {
 	free(cache);
 }
-#undef _INLINE_
-#endif
-
-#define __init
 
 /*
- * Now pull in the real linux/jfs.h definitions.
+ * helper functions to deal with 32 or 64bit block numbers.
  */
-#include <ext2fs/kernel-jbd.h>
+_INLINE_ size_t journal_tag_bytes(journal_t *journal)
+{
+	if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
+		return JBD_TAG_SIZE64;
+	else
+		return JBD_TAG_SIZE32;
+}
+
+#undef _INLINE_
+#endif
 
 /*
  * Kernel compatibility functions are defined in journal.c
diff --git a/e2fsck/journal.c b/e2fsck/journal.c
index dbe1bf1..b701d19 100644
--- a/e2fsck/journal.c
+++ b/e2fsck/journal.c
@@ -73,8 +73,12 @@
 	if (!bh)
 		return NULL;
 
+#ifdef CONFIG_JBD_DEBUG
+	if (journal_enable_debug >= 3)
+		bh_count++;
+#endif
 	jfs_debug(4, "getblk for block %lu (%d bytes)(total %d)\n",
-		  (unsigned long) blocknr, blocksize, ++bh_count);
+		  (unsigned long) blocknr, blocksize, bh_count);
 
 	bh->b_ctx = kdev->k_ctx;
 	if (kdev->k_dev == K_DEV_FS)
@@ -385,7 +389,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
@@ -798,9 +802,12 @@
 
 static errcode_t recover_ext3_journal(e2fsck_t ctx)
 {
+	struct problem_context	pctx;
 	journal_t *journal;
 	int retval;
 
+	clear_problem_context(&pctx);
+
 	journal_init_revoke_caches();
 	retval = e2fsck_get_journal(ctx, &journal);
 	if (retval)
@@ -818,6 +825,14 @@
 	if (retval)
 		goto errout;
 	
+	if (journal->j_failed_commit) {
+		pctx.ino = journal->j_failed_commit;
+		fix_problem(ctx, PR_0_JNL_TXN_CORRUPT, &pctx);
+		ctx->fs->super->s_state |= EXT2_ERROR_FS;
+		ext2fs_mark_super_dirty(ctx->fs);
+	}
+
+
 	if (journal->j_superblock->s_errno) {
 		ctx->fs->super->s_state |= EXT2_ERROR_FS;
 		ext2fs_mark_super_dirty(ctx->fs);
@@ -988,6 +1003,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..4736671 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
@@ -273,7 +275,12 @@
 		printf("%u", large_inode->i_extra_isize);
 		break;
 	case 'b':
-		printf("%u", inode->i_blocks);
+		if (inode->i_flags & EXT4_HUGE_FILE_FL)
+			printf("%llu", inode->i_blocks +
+			       (((long long) inode->osd2.linux2.l_i_blocks_hi)
+				<< 32));
+		else
+			printf("%u", inode->i_blocks);
 		break;
 	case 'l':
 		printf("%d", inode->i_links_count);
@@ -388,7 +395,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 +409,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..ee57497 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,163 @@
 	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,
+			     blk64_t start_block,
+			     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;
+	struct ext2_extent_info	info;
+
+	pctx->errcode = ext2fs_extent_get_info(ehandle, &info);
+	if (pctx->errcode)
+		return;
+
+	pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB,
+					  &extent);
+	while (!pctx->errcode && info.num_entries-- > 0) {
+		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_lblk < start_block)
+			problem = PR_1_OUT_OF_ORDER_EXTENTS;
+		else if (is_leaf &&
+			 (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;
+				}
+				pctx->errcode = ext2fs_extent_get(ehandle,
+								  EXT2_EXTENT_CURRENT,
+								  &extent);
+				if (pctx->errcode == EXT2_ET_NO_CURRENT_NODE) {
+					pctx->errcode = 0;
+					break;
+				}
+				continue;
+			}
+			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, extent.e_lblk, 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;
+		start_block = 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, 0, 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 +1788,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 +1815,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,19 +1857,16 @@
 		
 	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;
 		}
 	}
 
-	pb.num_blocks *= (fs->blocksize / 512);
+	if (!(fs->super->s_feature_ro_compat &
+	      EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
+	    !(inode->i_flags & EXT4_HUGE_FILE_FL))
+		pb.num_blocks *= (fs->blocksize / 512);
 #if 0
 	printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
 	       ino, inode->i_size, pb.last_block, inode->i_blocks,
@@ -1639,10 +1910,15 @@
 	if (LINUX_S_ISREG(inode->i_mode) &&
 	    (inode->i_size_high || inode->i_size & 0x80000000UL))
 		ctx->large_files++;
-	if (pb.num_blocks != inode->i_blocks) {
+	if ((pb.num_blocks != inode->i_blocks) ||
+	    ((fs->super->s_feature_ro_compat &
+	      EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
+	     (inode->i_flags & EXT4_HUGE_FILE_FL) &&
+	     (inode->osd2.linux2.l_i_blocks_hi != 0))) {
 		pctx->num = pb.num_blocks;
 		if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
 			inode->i_blocks = pb.num_blocks;
+			inode->osd2.linux2.l_i_blocks_hi = 0;
 			dirty_inode++;
 		}
 		pctx->num = 0;
@@ -2240,6 +2516,48 @@
 	return 0;
 }
 
+static errcode_t e2fsck_get_alloc_block(ext2_filsys fs, blk64_t goal,
+					blk64_t *ret)
+{
+	e2fsck_t ctx = (e2fsck_t) fs->priv_data;
+	errcode_t	retval;
+	blk_t		new_block;
+
+	if (ctx->block_found_map) {
+		retval = ext2fs_new_block(fs, (blk_t) goal, 
+					  ctx->block_found_map, &new_block);
+		if (retval)
+			return retval;
+	} else {
+		if (!fs->block_map) {
+			retval = ext2fs_read_block_bitmap(fs);
+			if (retval)
+				return retval;
+		}
+
+		retval = ext2fs_new_block(fs, (blk_t) goal, 0, &new_block);
+		if (retval)
+			return retval;
+	}
+		
+	*ret = new_block;
+	return (0);
+}
+
+static void e2fsck_block_alloc_stats(ext2_filsys fs, blk64_t blk, int inuse)
+{
+	e2fsck_t ctx = (e2fsck_t) fs->priv_data;
+
+	if (ctx->block_found_map) {
+		if (inuse > 0)
+			ext2fs_mark_block_bitmap(ctx->block_found_map, 
+						 (blk_t) blk);
+		else
+			ext2fs_unmark_block_bitmap(ctx->block_found_map, 
+						   (blk_t) blk);
+	}
+}
+
 void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
 {
 	ext2_filsys fs = ctx->fs;
@@ -2250,6 +2568,11 @@
 		fs->read_inode = pass1_read_inode;
 		fs->write_inode = pass1_write_inode;
 		ctx->stashed_ino = 0;
+		ext2fs_set_alloc_block_callback(fs, e2fsck_get_alloc_block,
+						0);
+		ext2fs_set_block_alloc_stats_callback(fs,
+						      e2fsck_block_alloc_stats,
+						      0);
 	} else {
 		fs->get_blocks = 0;
 		fs->check_directory = 0;
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..7aa693b 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;
 	}
@@ -1381,7 +1429,7 @@
 	 * Update the inode block count
 	 */
 	e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
-	inode.i_blocks += fs->blocksize / 512;
+	ext2fs_iblk_add_blocks(fs, &inode, 1);
 	if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
 		inode.i_size = (db->blockcnt+1) * fs->blocksize;
 	e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index b9c6edd..4ef1446 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
 }
@@ -226,7 +227,7 @@
 	inode.i_size = fs->blocksize;
 	inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
 	inode.i_links_count = 2;
-	inode.i_blocks = fs->blocksize / 512;
+	ext2fs_iblk_set(fs, &inode, 1);
 	inode.i_block[0] = blk;
 
 	/*
@@ -471,7 +472,7 @@
 	inode.i_size = fs->blocksize;
 	inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
 	inode.i_links_count = 2;
-	inode.i_blocks = fs->blocksize / 512;
+	ext2fs_iblk_set(fs, &inode, 1);
 	inode.i_block[0] = blk;
 
 	/*
@@ -802,7 +803,7 @@
 		return retval;
 	
 	inode.i_size = (es.last_block + 1) * fs->blocksize;
-	inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
+	ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
 
 	e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
 
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..cc17820 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		csum_flag;
 	int		skip_group = 0;
 
 	clear_problem_context(&pctx);
@@ -158,15 +158,14 @@
 		goto errout;
 	}
 
-	if (EXT2_HAS_COMPAT_FEATURE(fs->super, EXT2_FEATURE_COMPAT_LAZY_BG))
-		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 (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;
@@ -175,11 +174,30 @@
 		actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
 
 		if (skip_group) {
-			if ((i >= super) &&
-			    (i <= super + fs->desc_blocks) &&
-			    ext2fs_bg_has_super(fs, group))
+			blk_t	super_blk, old_desc_blk, new_desc_blk;
+			int	old_desc_blocks;
+
+			ext2fs_super_and_bgd_loc(fs, group, &super_blk,
+					 &old_desc_blk, &new_desc_blk, 0);
+
+			if (fs->super->s_feature_incompat &
+			    EXT2_FEATURE_INCOMPAT_META_BG)
+				old_desc_blocks = fs->super->s_first_meta_bg;
+			else
+				old_desc_blocks = fs->desc_blocks +
+					fs->super->s_reserved_gdt_blocks;
+
+			bitmap = 0;
+			if (i == super_blk)
 				bitmap = 1;
-			else if (i == fs->group_desc[group].bg_block_bitmap)
+			if (old_desc_blk && old_desc_blocks &&
+			    (i >= old_desc_blk) &&
+			    (i < old_desc_blk + old_desc_blocks))
+				bitmap = 1;
+			if (new_desc_blk &&
+			    (i == new_desc_blk))
+				bitmap = 1;
+			if (i == fs->group_desc[group].bg_block_bitmap)
 				bitmap = 1;
 			else if (i == fs->group_desc[group].bg_inode_bitmap)
 				bitmap = 1;
@@ -187,8 +205,6 @@
 				 (i < fs->group_desc[group].bg_inode_table
 				  + fs->inode_blocks_per_group))
 				bitmap = 1;
-			else
-				bitmap = 0;
 			actual = (actual != 0);
 		} else
 			bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
@@ -206,6 +222,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 +251,7 @@
 		had_problem++;
 
 	do_counts:
-		if (!bitmap && !skip_group) {
+		if (!bitmap && (!skip_group || csum_flag)) {
 			group_free++;
 			free_blocks++;
 		}
@@ -241,7 +268,7 @@
 				if ((ctx->progress)(ctx, 5, group,
 						    fs->group_desc_count*2))
 					goto errout;
-			if (lazy_bg &&
+			if (csum_flag &&
 			    (i != fs->super->s_blocks_count-1) &&
 			    (fs->group_desc[group].bg_flags &
 			     EXT2_BG_BLOCK_UNINIT))
@@ -321,7 +348,7 @@
 	errcode_t	retval;
 	struct problem_context	pctx;
 	int		problem, save_problem, fixit, had_problem;
-	int		lazy_bg = 0;
+	int		csum_flag;
 	int		skip_group = 0;
 
 	clear_problem_context(&pctx);
@@ -358,16 +385,14 @@
 		goto errout;
 	}
 
-	if (EXT2_HAS_COMPAT_FEATURE(fs->super,
-				    EXT2_FEATURE_COMPAT_LAZY_BG))
-		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 (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 +415,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 +451,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 +470,7 @@
 					    group + fs->group_desc_count,
 					    fs->group_desc_count*2))
 					goto errout;
-			if (lazy_bg &&
+			if (csum_flag &&
 			    (i != fs->super->s_inodes_count) &&
 			    (fs->group_desc[group].bg_flags &
 			     EXT2_BG_INODE_UNINIT))
@@ -563,7 +603,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..0fbcd89 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,46 @@
 	  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 },
+
+	/* Journal transaction found corrupt */
+	{ PR_0_JNL_TXN_CORRUPT,
+	  N_("Journal transaction %i was corrupt, replay was aborted.\n"),
+	  PROMPT_NONE, 0 },
+
 	/* 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 +446,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 +470,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 +487,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 +500,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 +514,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 +542,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 +598,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 +643,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 +656,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 +683,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 +697,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 +724,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 +743,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 +779,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 +814,51 @@
 	  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 },
+
+	/* Extents are out of order */
+	{ PR_1_OUT_OF_ORDER_EXTENTS,
+	  N_("@i %i has out of order extents\n\t(@n logical @b %c, physical @b %b, len %N)\n"),
+	  PROMPT_CLEAR, 0 },
+
 	/* Pass 1b errors */
 
 	/* Pass 1B: Rescan for duplicate/bad blocks */
@@ -793,12 +868,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 +881,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 +908,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 +943,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 +958,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 +985,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 +1018,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 +1050,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 +1087,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 +1103,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 +1183,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 +1207,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 +1242,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 +1266,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 +1330,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 +1359,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 +1372,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 +1425,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 +1461,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 +1486,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 +1506,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 +1551,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 +1562,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 +1577,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 +1588,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 +1647,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 +1687,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 +1804,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..24e7ed7 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,24 @@
 /* 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
+
+/* Journal transaction found corrupt */
+#define PR_0_JNL_TXN_CORRUPT			0x00003A
+
 /*
  * Pass 1 errors
  */
@@ -253,7 +271,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 +280,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 +305,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 +334,7 @@
 
 /* Error allocating icount structure */
 #define PR_1_ALLOCATE_ICOUNT		0x010026
-	
+
 /* Error allocating dbcount */
 #define PR_1_ALLOCATE_DBCOUNT		0x010027
 
@@ -326,10 +344,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 +385,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 +398,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 +431,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 +452,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 +473,33 @@
 /* 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
+
+/* Extents are out of order */
+#define PR_1_OUT_OF_ORDER_EXTENTS	0x01005E
+
 /*
  * Pass 1b errors
  */
@@ -470,7 +515,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 +539,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 +559,7 @@
 
 /* Couldn't clone file (error) */
 #define PR_1D_CLONE_ERROR	0x013008
-		
+
 /*
  * Pass 2 errors
  */
@@ -546,10 +591,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 +617,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 +647,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 +756,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 +802,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 +814,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 +848,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 +884,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 +896,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 +908,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 +944,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 +978,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/recovery.c b/e2fsck/recovery.c
index 43bc5e5..2edb576 100644
--- a/e2fsck/recovery.c
+++ b/e2fsck/recovery.c
@@ -178,19 +178,20 @@
  * Count the number of in-use tags in a journal descriptor block.
  */
 
-static int count_tags(struct buffer_head *bh, int size)
+static int count_tags(journal_t *journal, struct buffer_head *bh)
 {
 	char *			tagp;
 	journal_block_tag_t *	tag;
-	int			nr = 0;
+	int			nr = 0, size = journal->j_blocksize;
+	int			tag_bytes = journal_tag_bytes(journal);
 
 	tagp = &bh->b_data[sizeof(journal_header_t)];
 
-	while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
+	while ((tagp - bh->b_data + tag_bytes) <= size) {
 		tag = (journal_block_tag_t *) tagp;
 
 		nr++;
-		tagp += sizeof(journal_block_tag_t);
+		tagp += tag_bytes;
 		if (!(tag->t_flags & cpu_to_be32(JFS_FLAG_SAME_UUID)))
 			tagp += 16;
 
@@ -307,6 +308,46 @@
 	return err;
 }
 
+static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag)
+{
+	unsigned long long block = be32_to_cpu(tag->t_blocknr);
+	if (tag_bytes > JBD_TAG_SIZE32)
+		block |= (__u64)be32_to_cpu(tag->t_blocknr_high) << 32;
+	return block;
+}
+
+/*
+ * calc_chksums calculates the checksums for the blocks described in the
+ * descriptor block.
+ */
+static int calc_chksums(journal_t *journal, struct buffer_head *bh,
+			unsigned long *next_log_block, __u32 *crc32_sum)
+{
+	int i, num_blks, err;
+	unsigned long io_block;
+	struct buffer_head *obh;
+
+	num_blks = count_tags(journal, bh);
+	/* Calculate checksum of the descriptor block. */
+	*crc32_sum = crc32_be(*crc32_sum, (void *)bh->b_data, bh->b_size);
+
+	for (i = 0; i < num_blks; i++) {
+		io_block = (*next_log_block)++;
+		wrap(journal, *next_log_block);
+		err = jread(&obh, journal, io_block);
+		if (err) {
+			printk(KERN_ERR "JBD: IO error %d recovering block "
+				"%lu in log\n", err, io_block);
+			return 1;
+		} else {
+			*crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data,
+				     obh->b_size);
+		}
+		brelse(obh);
+	}
+	return 0;
+}
+
 static int do_one_pass(journal_t *journal,
 			struct recovery_info *info, enum passtype pass)
 {
@@ -318,11 +359,13 @@
 	struct buffer_head *	bh;
 	unsigned int		sequence;
 	int			blocktype;
+	int			tag_bytes = journal_tag_bytes(journal);
+	__u32			crc32_sum = ~0; /* Transactional Checksums */
 
 	/* Precompute the maximum metadata descriptors in a descriptor block */
 	int			MAX_BLOCKS_PER_DESC;
 	MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
-			       / sizeof(journal_block_tag_t));
+			       / tag_bytes);
 
 	/*
 	 * First thing is to establish what we expect to find in the log
@@ -409,11 +452,24 @@
 		switch(blocktype) {
 		case JFS_DESCRIPTOR_BLOCK:
 			/* If it is a valid descriptor block, replay it
-			 * in pass REPLAY; otherwise, just skip over the
-			 * blocks it describes. */
+			 * in pass REPLAY; if journal_checksums enabled, then
+			 * calculate checksums in PASS_SCAN, otherwise,
+			 * just skip over the blocks it describes. */
 			if (pass != PASS_REPLAY) {
-				next_log_block +=
-					count_tags(bh, journal->j_blocksize);
+				if (pass == PASS_SCAN &&
+				    JFS_HAS_COMPAT_FEATURE(journal,
+					    JFS_FEATURE_COMPAT_CHECKSUM) &&
+				    !info->end_transaction) {
+					if (calc_chksums(journal, bh,
+							&next_log_block,
+							&crc32_sum)) {
+						brelse(bh);
+						break;
+					}
+					brelse(bh);
+					continue;
+				}
+				next_log_block += count_tags(journal, bh);
 				wrap(journal, next_log_block);
 				brelse(bh);
 				continue;
@@ -424,7 +480,7 @@
 			 * getting done here! */
 
 			tagp = &bh->b_data[sizeof(journal_header_t)];
-			while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
+			while ((tagp - bh->b_data + tag_bytes)
 			       <= journal->j_blocksize) {
 				unsigned long io_block;
 
@@ -494,7 +550,7 @@
 				}
 
 			skip_write:
-				tagp += sizeof(journal_block_tag_t);
+				tagp += tag_bytes;
 				if (!(flags & JFS_FLAG_SAME_UUID))
 					tagp += 16;
 
@@ -506,9 +562,98 @@
 			continue;
 
 		case JFS_COMMIT_BLOCK:
-			/* Found an expected commit block: not much to
-			 * do other than move on to the next sequence
+			jbd_debug(3, "Commit block for #%u found\n",
+				  next_commit_ID);
+			/*     How to differentiate between interrupted commit
+			 *               and journal corruption ?
+			 *
+			 * {nth transaction}
+			 *        Checksum Verification Failed
+			 *			 |
+			 *		 ____________________
+			 *		|		     |
+			 * 	async_commit             sync_commit
+			 *     		|                    |
+			 *		| GO TO NEXT    "Journal Corruption"
+			 *		| TRANSACTION
+			 *		|
+			 * {(n+1)th transanction}
+			 *		|
+			 * 	 _______|______________
+			 * 	|	 	      |
+			 * Commit block found	Commit block not found
+			 *      |		      |
+			 * "Journal Corruption"       |
+			 *		 _____________|_________
+			 *     		|	           	|
+			 *	nth trans corrupt	OR   nth trans
+			 *	and (n+1)th interrupted     interrupted
+			 *	before commit block
+			 *      could reach the disk.
+			 *	(Cannot find the difference in above
+			 *	 mentioned conditions. Hence assume
+			 *	 "Interrupted Commit".)
+			 */
+
+			/* Found an expected commit block: if checksums
+			 * are present verify them in PASS_SCAN; else not
+			 * much to do other than move on to the next sequence
 			 * number. */
+			if (pass == PASS_SCAN &&
+			    JFS_HAS_COMPAT_FEATURE(journal,
+				    JFS_FEATURE_COMPAT_CHECKSUM)) {
+				int chksum_err, chksum_seen;
+				struct commit_header *cbh =
+					(struct commit_header *)bh->b_data;
+				unsigned found_chksum =
+					be32_to_cpu(cbh->h_chksum[0]);
+
+				chksum_err = chksum_seen = 0;
+
+				jbd_debug(3, "Checksums %x %x\n",
+					  crc32_sum, found_chksum);
+				if (info->end_transaction) {
+					journal->j_failed_commit =
+						info->end_transaction;
+					brelse(bh);
+					break;
+				}
+
+				if (crc32_sum == found_chksum &&
+				    cbh->h_chksum_type == JBD2_CRC32_CHKSUM &&
+				    cbh->h_chksum_size ==
+						JBD2_CRC32_CHKSUM_SIZE)
+				       chksum_seen = 1;
+				else if (!(cbh->h_chksum_type == 0 &&
+					     cbh->h_chksum_size == 0 &&
+					     found_chksum == 0 &&
+					     !chksum_seen))
+				/*
+				 * If fs is mounted using an old kernel and then
+				 * kernel with journal_chksum is used then we
+				 * get a situation where the journal flag has
+				 * checksum flag set but checksums are not
+				 * present i.e chksum = 0, in the individual
+				 * commit blocks.
+				 * Hence to avoid checksum failures, in this
+				 * situation, this extra check is added.
+				 */
+						chksum_err = 1;
+
+				if (chksum_err) {
+					info->end_transaction = next_commit_ID;
+					jbd_debug(1, "Checksum_err\n");
+
+					if (!JFS_HAS_INCOMPAT_FEATURE(journal,
+					   JFS_FEATURE_INCOMPAT_ASYNC_COMMIT)){
+						journal->j_failed_commit =
+							next_commit_ID;
+						brelse(bh);
+						break;
+					}
+				}
+				crc32_sum = ~0;
+			}
 			brelse(bh);
 			next_commit_ID++;
 			continue;
@@ -544,9 +689,10 @@
 	 * transaction marks the end of the valid log.
 	 */
 
-	if (pass == PASS_SCAN)
-		info->end_transaction = next_commit_ID;
-	else {
+	if (pass == PASS_SCAN) {
+		if (!info->end_transaction)
+			info->end_transaction = next_commit_ID;
+	} else {
 		/* It's really bad news if different passes end up at
 		 * different places (but possible due to IO errors). */
 		if (info->end_transaction != next_commit_ID) {
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 8e25f52..e75774a 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -668,7 +668,7 @@
 	else
 		inode.i_flags |= EXT2_INDEX_FL;
 	inode.i_size = outdir->num * fs->blocksize;
-	inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
+	ext2fs_iblk_sub_blocks(fs, &inode, wd.cleared);
 	e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
 
 	return 0;
@@ -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..f5abac9 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -195,8 +195,7 @@
 	e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
 
 	if (pb.truncated_blocks)
-		inode->i_blocks -= pb.truncated_blocks *
-			(fs->blocksize / 512);
+		ext2fs_iblk_sub_blocks(fs, inode, pb.truncated_blocks);
 
 	if (inode->i_file_acl) {
 		retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
@@ -467,7 +466,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     csum_flag;
 
 	inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
 	ipg_max = inodes_per_block * (blocks_per_group - 4);
@@ -574,13 +575,19 @@
 	/*
 	 * 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;
 
+	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 +628,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 (!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 +858,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 303cec9..4ab0802 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -47,13 +47,12 @@
 #endif
 
 #include "et/com_err.h"
+#include "e2p/e2p.h"
 #include "e2fsck.h"
 #include "problem.h"
 #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 +70,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 +267,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;
@@ -739,20 +737,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 +748,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 +785,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 +850,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 +898,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 +1219,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,16 +1347,26 @@
 		}
 	}
 
+	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->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/e2fsprogs.spec.in b/e2fsprogs.spec.in
index 3e7d1ee..a7cc975 100644
--- a/e2fsprogs.spec.in
+++ b/e2fsprogs.spec.in
@@ -119,11 +119,15 @@
 %{_root_sbindir}/fsck
 %{_root_sbindir}/fsck.ext2
 %{_root_sbindir}/fsck.ext3
+%{_root_sbindir}/fsck.ext4
+%{_root_sbindir}/fsck.ext4dev
 %{_root_sbindir}/logsave
 %{_root_sbindir}/mke2fs
 %{_root_etcdir}/mke2fs.conf
 %{_root_sbindir}/mkfs.ext2
 %{_root_sbindir}/mkfs.ext3
+%{_root_sbindir}/mkfs.ext4
+%{_root_sbindir}/mkfs.ext4dev
 %{_root_sbindir}/resize2fs
 %{_root_sbindir}/tune2fs
 %{_sbindir}/filefrag
@@ -156,6 +160,8 @@
 %{_mandir}/man8/findfs.8*
 %{_mandir}/man8/fsck.ext2.8*
 %{_mandir}/man8/fsck.ext3.8*
+%{_mandir}/man8/fsck.ext4.8*
+%{_mandir}/man8/fsck.ext4dev.8*
 %{_mandir}/man8/e2image.8*
 %{_mandir}/man8/e2label.8*
 %{_mandir}/man8/fsck.8*
@@ -163,6 +169,8 @@
 %{_mandir}/man8/mke2fs.8*
 %{_mandir}/man8/mkfs.ext2.8*
 %{_mandir}/man8/mkfs.ext3.8*
+%{_mandir}/man8/mkfs.ext4.8*
+%{_mandir}/man8/mkfs.ext4dev.8*
 %{_mandir}/man8/mklost+found.8*
 %{_mandir}/man8/resize2fs.8*
 %{_mandir}/man8/tune2fs.8*
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..7d9e99f 100644
--- a/lib/Makefile.library
+++ b/lib/Makefile.library
@@ -21,3 +21,4 @@
 	@$(RM) -f ../$@
 	@$(LN) $@ ../$@
 
+$(LIB)/$(LIBRARY).a: $(LIBRARY).a
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 f548d08..2746928 100644
--- a/lib/blkid/probe.c
+++ b/lib/blkid/probe.c
@@ -793,6 +793,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);
@@ -840,7 +841,7 @@
 }
 
 static int probe_swap1(struct blkid_probe *probe,
-		       struct blkid_magic *id __BLKID_ATTR((unused)),
+		       struct blkid_magic *id,
 		       unsigned char *buf __BLKID_ATTR((unused)))
 {
 	struct swap_id_block *sws;
@@ -856,6 +857,11 @@
 	if (!sws)
 		return 1;
 
+	/* check for wrong version or zeroed pagecount, for sanity */
+	if (!memcmp(id->bim_magic, "SWAPSPACE2", id->bim_len) &&
+			(sws->sws_version != 1 || sws->sws_lastpage == 0))
+		return 1;
+
 	/* arbitrary sanity check.. is there any garbage down there? */
 	if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0)  {
 		if (sws->sws_volume[0])
diff --git a/lib/blkid/test_probe.in b/lib/blkid/test_probe.in
index 02d42bb..87ac2b2 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,15 @@
 		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.$$
+	# swap is native-endian, so regenerate before testing
+	if [ "$i" = "swap0" ]; then
+		mkswap -v0 tests/tmp/test.img.$$ > /dev/null
+	elif [ "$i" = "swap1" ]; then
+		mkswap -v1 -L SWAP-TEST -U 8ff8e77f-8553-485e-8656-58be67a81666 tests/tmp/test.img.$$ >/dev/null
+	fi
+	./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..12cb8a3 100644
--- a/lib/e2p/feature.c
+++ b/lib/e2p/feature.c
@@ -45,7 +45,9 @@
 	{	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_bg" },
+	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,
+			"uninit_groups" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK,
 			"dir_nlink" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE,
@@ -60,13 +62,15 @@
 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
 			"journal_dev" },
 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
+			"extent" },
+	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
 			"extents" },
 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
 			"meta_bg" },
-	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
-			"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/e2p/ls.c b/lib/e2p/ls.c
index d249f88..c211dce 100644
--- a/lib/e2p/ls.c
+++ b/lib/e2p/ls.c
@@ -242,6 +242,9 @@
 	if (sb->s_first_meta_bg)
 		fprintf(f, "First meta block group:   %u\n",
 			sb->s_first_meta_bg);
+	if (sb->s_log_groups_per_flex)
+		fprintf(f, "Flex block group size:    %u\n",
+			1 << sb->s_log_groups_per_flex);
 	if (sb->s_mkfs_time) {
 		tm = sb->s_mkfs_time;
 		fprintf(f, "Filesystem created:       %s", ctime(&tm));
@@ -270,7 +273,13 @@
 	print_group(sb->s_def_resgid, f);
 	if (sb->s_rev_level >= EXT2_DYNAMIC_REV) {
 		fprintf(f, "First inode:              %d\n", sb->s_first_ino);
-		fprintf(f, "Inode size:		  %d\n", sb->s_inode_size);
+		fprintf(f, "Inode size:	          %d\n", sb->s_inode_size);
+		if (sb->s_min_extra_isize)
+			fprintf(f, "Required extra isize:     %d\n", 
+				sb->s_min_extra_isize);
+		if (sb->s_want_extra_isize)
+			fprintf(f, "Desired extra isize:      %d\n", 
+				sb->s_want_extra_isize);
 	}
 	if (!e2p_is_null_uuid(sb->s_journal_uuid))
 		fprintf(f, "Journal UUID:             %s\n",
diff --git a/lib/e2p/pf.c b/lib/e2p/pf.c
index 3e9a7cd..05a961a 100644
--- a/lib/e2p/pf.c
+++ b/lib/e2p/pf.c
@@ -45,6 +45,7 @@
 	{ EXT2_NOTAIL_FL, "t", "No_Tailmerging" },
 	{ EXT2_TOPDIR_FL, "T", "Top_of_Directory_Hierarchies" },
 	{ EXT4_EXTENTS_FL, "e", "Extents" },
+	{ EXT4_HUGE_FILE_FL, "h", "Huge_file" },
 	{ 0, NULL, NULL }
 };
 
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..56c6349 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 \
@@ -42,6 +47,7 @@
 	get_pathname.o \
 	getsize.o \
 	getsectsize.o \
+	i_block.o \
 	icount.o \
 	ind_block.o \
 	initialize.o \
@@ -63,6 +69,7 @@
 	rw_bitmaps.o \
 	swapfs.o \
 	tdb.o \
+	undo_io.o \
 	unix_io.o \
 	unlink.o \
 	valid_blk.o \
@@ -82,7 +89,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 +99,7 @@
 	$(srcdir)/dupfs.c \
 	$(srcdir)/expanddir.c \
 	$(srcdir)/ext_attr.c \
+	$(srcdir)/extent.c \
 	$(srcdir)/fileio.c \
 	$(srcdir)/finddev.c \
 	$(srcdir)/flushb.c \
@@ -99,6 +108,7 @@
 	$(srcdir)/get_pathname.c \
 	$(srcdir)/getsize.c \
 	$(srcdir)/getsectsize.c \
+	$(srcdir)/i_block.c \
 	$(srcdir)/icount.c \
 	$(srcdir)/ind_block.c \
 	$(srcdir)/initialize.c \
@@ -120,21 +130,22 @@
 	$(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)/undo_io.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 +198,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 +248,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) \
+		$(STATIC_LIBEXT2FS) $(LIBBLKID) $(LIBUUID) $(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 +358,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 +382,349 @@
 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
+undo_io.o: $(srcdir)/undo_io.c $(srcdir)/tdb.h $(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
+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.c b/lib/ext2fs/alloc.c
index 65f3ea1..f8d8a5f 100644
--- a/lib/ext2fs/alloc.c
+++ b/lib/ext2fs/alloc.c
@@ -118,16 +118,25 @@
 	}
 	memset(block_buf, 0, fs->blocksize);
 
-	if (!fs->block_map) {
-		retval = ext2fs_read_block_bitmap(fs);
+	if (fs->get_alloc_block) {
+		blk64_t	new;
+
+		retval = (fs->get_alloc_block)(fs, (blk64_t) goal, &new);
+		if (retval)
+			goto fail;
+		block = (blk_t) new;
+	} else {
+		if (!fs->block_map) {
+			retval = ext2fs_read_block_bitmap(fs);
+			if (retval)
+				goto fail;
+		}
+
+		retval = ext2fs_new_block(fs, goal, 0, &block);
 		if (retval)
 			goto fail;
 	}
 
-	retval = ext2fs_new_block(fs, goal, 0, &block);
-	if (retval)
-		goto fail;
-
 	retval = io_channel_write_blk(fs->io, block, 1, block_buf);
 	if (retval)
 		goto fail;
@@ -170,3 +179,19 @@
 	return EXT2_ET_BLOCK_ALLOC_FAIL;
 }
 
+void ext2fs_set_alloc_block_callback(ext2_filsys fs, 
+				     errcode_t (*func)(ext2_filsys fs,
+						       blk64_t goal,
+						       blk64_t *ret),
+				     errcode_t (**old)(ext2_filsys fs,
+						       blk64_t goal,
+						       blk64_t *ret))
+{
+	if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
+		return;
+
+	if (old)
+		*old = fs->get_alloc_block;
+
+	fs->get_alloc_block = func;
+}
diff --git a/lib/ext2fs/alloc_sb.c b/lib/ext2fs/alloc_sb.c
index ef40b93..200ce5c 100644
--- a/lib/ext2fs/alloc_sb.c
+++ b/lib/ext2fs/alloc_sb.c
@@ -27,6 +27,19 @@
 #include "ext2_fs.h"
 #include "ext2fs.h"
 
+/*
+ * This function reserves the superblock and block group descriptors
+ * for a given block group.  It currently returns the number of free
+ * blocks assuming that inode table and allocation bitmaps will be in
+ * the group.  This is not necessarily the case when the flex_bg
+ * feature is enabled, so callers should take care!  It was only
+ * really intended for use by mke2fs, and even there it's not that
+ * useful.  In the future, when we redo this function for 64-bit block
+ * numbers, we should probably return the number of blocks used by the
+ * super block and group descriptors instead.
+ *
+ * See also the comment for ext2fs_super_and_bgd_loc()
+ */
 int ext2fs_reserve_super_and_bgd(ext2_filsys fs, 
 				 dgrp_t group,
 				 ext2fs_block_bitmap bmap)
@@ -47,6 +60,8 @@
 		ext2fs_mark_block_bitmap(bmap, super_blk);
 
 	if (old_desc_blk) {
+		if (fs->super->s_reserved_gdt_blocks && fs->block_map == bmap)
+			fs->group_desc[group].bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
 		for (j=0; j < old_desc_blocks; j++)
 			ext2fs_mark_block_bitmap(bmap, old_desc_blk + j);
 	}
diff --git a/lib/ext2fs/alloc_stats.c b/lib/ext2fs/alloc_stats.c
index 4088f7b..a8514cc 100644
--- a/lib/ext2fs/alloc_stats.c
+++ b/lib/ext2fs/alloc_stats.c
@@ -27,6 +27,23 @@
 	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 the uninit flag if inuse < 0
+	 * (i.e. freeing inodes) but it also means something is bad. */
+	fs->group_desc[group].bg_flags &= ~EXT2_BG_INODE_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,7 +63,28 @@
 	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);
+	if (fs->block_alloc_stats)
+		(fs->block_alloc_stats)(fs, (blk64_t) blk, inuse);
+}
+
+void ext2fs_set_block_alloc_stats_callback(ext2_filsys fs, 
+					   void (*func)(ext2_filsys fs,
+							blk64_t blk,
+							int inuse),
+					   void (**old)(ext2_filsys fs,
+							blk64_t blk,
+							int inuse))
+{
+	if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
+		return;
+	if (old)
+		*old = fs->block_alloc_stats;
+
+	fs->block_alloc_stats = func;
 }
diff --git a/lib/ext2fs/alloc_tables.c b/lib/ext2fs/alloc_tables.c
index 4ad2ba9..d87585b 100644
--- a/lib/ext2fs/alloc_tables.c
+++ b/lib/ext2fs/alloc_tables.c
@@ -27,18 +27,80 @@
 #include "ext2_fs.h"
 #include "ext2fs.h"
 
+/*
+ * This routine searches for free blocks that can allocate a full
+ * group of bitmaps or inode tables for a flexbg group.  Returns the
+ * block number with a correct offset were the bitmaps and inode
+ * tables can be allocated continously and in order.
+ */
+static blk_t flexbg_offset(ext2_filsys fs, dgrp_t group, blk_t start_blk,
+			   ext2fs_block_bitmap bmap, int offset, int size)
+{
+	int		flexbg, flexbg_size, elem_size;
+	blk_t		last_blk, first_free = 0;
+	dgrp_t	       	last_grp;
+
+	flexbg_size = 1 << fs->super->s_log_groups_per_flex;
+	flexbg = group / flexbg_size;
+
+	if (size > fs->super->s_blocks_per_group / 8)
+		size = fs->super->s_blocks_per_group / 8;
+
+	/*
+	 * Dont do a long search if the previous block
+	 * search is still valid.
+	 */
+	if (start_blk && group % flexbg_size) {
+		if (size > flexbg_size)
+			elem_size = fs->inode_blocks_per_group;
+		else
+			elem_size = 1;
+		if (ext2fs_test_block_bitmap_range(bmap, start_blk + elem_size,
+						   size))
+			return start_blk + elem_size;
+	}
+
+	start_blk = ext2fs_group_first_block(fs, flexbg_size * flexbg);
+	last_grp = group | (flexbg_size - 1);
+	if (last_grp > fs->group_desc_count)
+		last_grp = fs->group_desc_count;
+	last_blk = ext2fs_group_last_block(fs, last_grp);
+
+	/* Find the first available block */
+	if (ext2fs_get_free_blocks(fs, start_blk, last_blk, 1, bmap,
+				   &first_free))
+		return first_free;
+
+	if (ext2fs_get_free_blocks(fs, first_free + offset, last_blk, size,
+				   bmap, &first_free))
+		return first_free;
+
+	return first_free;
+}
+
 errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
 				      ext2fs_block_bitmap bmap)
 {
 	errcode_t	retval;
 	blk_t		group_blk, start_blk, last_blk, new_blk, blk;
-	int		j;
+	dgrp_t		last_grp;
+	int		j, rem_grps, flexbg_size = 0;
 
 	group_blk = ext2fs_group_first_block(fs, group);
 	last_blk = ext2fs_group_last_block(fs, group);
 
 	if (!bmap)
 		bmap = fs->block_map;
+
+	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+				      EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
+	    fs->super->s_log_groups_per_flex) {
+		flexbg_size = 1 << fs->super->s_log_groups_per_flex;
+		last_grp = group | (flexbg_size - 1);
+		rem_grps = last_grp - group;
+		if (last_grp > fs->group_desc_count)
+			last_grp = fs->group_desc_count;
+	}
 	
 	/*
 	 * Allocate the block and inode bitmaps, if necessary
@@ -56,6 +118,15 @@
 	} else
 		start_blk = group_blk;
 
+	if (flexbg_size) {
+		int prev_block = 0;
+		if (group && fs->group_desc[group-1].bg_block_bitmap)
+			prev_block = fs->group_desc[group-1].bg_block_bitmap;
+		start_blk = flexbg_offset(fs, group, prev_block, bmap,
+						 0, rem_grps);
+		last_blk = ext2fs_group_last_block(fs, last_grp);
+	}
+
 	if (!fs->group_desc[group].bg_block_bitmap) {
 		retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
 						1, bmap, &new_blk);
@@ -66,6 +137,22 @@
 			return retval;
 		ext2fs_mark_block_bitmap(bmap, new_blk);
 		fs->group_desc[group].bg_block_bitmap = new_blk;
+		if (flexbg_size) {
+			dgrp_t gr = ext2fs_group_of_blk(fs, new_blk);
+			fs->group_desc[gr].bg_free_blocks_count--;
+			fs->super->s_free_blocks_count--;
+			fs->group_desc[gr].bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
+			ext2fs_group_desc_csum_set(fs, gr);
+		}
+	}
+
+	if (flexbg_size) {
+		int prev_block = 0;
+		if (group && fs->group_desc[group-1].bg_inode_bitmap)
+			prev_block = fs->group_desc[group-1].bg_inode_bitmap;
+		start_blk = flexbg_offset(fs, group, prev_block, bmap,
+						 flexbg_size, rem_grps);
+		last_blk = ext2fs_group_last_block(fs, last_grp);
 	}
 
 	if (!fs->group_desc[group].bg_inode_bitmap) {
@@ -78,11 +165,29 @@
 			return retval;
 		ext2fs_mark_block_bitmap(bmap, new_blk);
 		fs->group_desc[group].bg_inode_bitmap = new_blk;
+		if (flexbg_size) {
+			dgrp_t gr = ext2fs_group_of_blk(fs, new_blk);
+			fs->group_desc[gr].bg_free_blocks_count--;
+			fs->super->s_free_blocks_count--;
+			fs->group_desc[gr].bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
+			ext2fs_group_desc_csum_set(fs, gr);
+		}
 	}
 
 	/*
 	 * Allocate the inode table
 	 */
+	if (flexbg_size) {
+		int prev_block = 0;
+		if (group && fs->group_desc[group-1].bg_inode_table)
+			prev_block = fs->group_desc[group-1].bg_inode_table;
+		group_blk = flexbg_offset(fs, group, prev_block, bmap,
+						 flexbg_size * 2,
+						 fs->inode_blocks_per_group *
+						 rem_grps);
+		last_blk = ext2fs_group_last_block(fs, last_grp);
+	}
+
 	if (!fs->group_desc[group].bg_inode_table) {
 		retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
 						fs->inode_blocks_per_group,
@@ -91,17 +196,22 @@
 			return retval;
 		for (j=0, blk = new_blk;
 		     j < fs->inode_blocks_per_group;
-		     j++, blk++)
+		     j++, blk++) {
 			ext2fs_mark_block_bitmap(bmap, blk);
+			if (flexbg_size) {
+				dgrp_t gr = ext2fs_group_of_blk(fs, blk);
+				fs->group_desc[gr].bg_free_blocks_count--;
+				fs->super->s_free_blocks_count--;
+				fs->group_desc[gr].bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
+				ext2fs_group_desc_csum_set(fs, gr);
+			}
+		}
 		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/bb_inode.c b/lib/ext2fs/bb_inode.c
index 1f5b4e8..dbda79f 100644
--- a/lib/ext2fs/bb_inode.c
+++ b/lib/ext2fs/bb_inode.c
@@ -127,7 +127,7 @@
 	inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(0);
 	if (!inode.i_ctime)
 		inode.i_ctime = fs->now ? fs->now : time(0);
-	inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512);
+	ext2fs_iblk_set(fs, &inode, rec.bad_block_count);
 	inode.i_size = rec.bad_block_count * fs->blocksize;
 
 	retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
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..391b8cd 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,7 +274,6 @@
 }
 #endif
 
-#ifdef EXT2FS_ENABLE_SWAPFS
 _INLINE_ __u32 ext2fs_swab32(__u32 val)
 {
 #ifdef EXT2FS_REQUIRE_486
@@ -295,7 +301,6 @@
 	return (ext2fs_swab32(val >> 32) |
 		(((__u64)ext2fs_swab32(val & 0xFFFFFFFFUL)) << 32));
 }
-#endif
 
 #undef EXT2FS_ADDR
 
@@ -339,7 +344,7 @@
 #endif /* __mc68000__ */
 
 
-#if !defined(_EXT2_HAVE_ASM_SWAB_) && defined(EXT2FS_ENABLE_SWAPFS)
+#if !defined(_EXT2_HAVE_ASM_SWAB_)
 
 _INLINE_ __u16 ext2fs_swab16(__u16 val)
 {
@@ -355,6 +360,7 @@
 #endif /* !_EXT2_HAVE_ASM_SWAB */
 
 #if !defined(_EXT2_HAVE_ASM_FINDBIT_)
+#include <strings.h>
 _INLINE_ int ext2fs_find_first_bit_set(void * addr, unsigned size)
 {
 	char	*cp = (char *) addr;
@@ -401,24 +407,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 +452,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..4575cf3 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 */
+	int	r, ret = 0;
 	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,108 @@
 					   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, new_blk;
+		int			op = EXT2_EXTENT_ROOT;
+		unsigned int		j;
+
+		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)) {
+				if (ctx.flags & BLOCK_FLAG_DATA_ONLY)
+					continue;
+				if ((!(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);
+					if (ret & BLOCK_CHANGED) {
+						ctx.errcode = EXT2_ET_EXTENT_NOT_SUPPORTED;
+						goto errout;
+					}
+				}
+				continue;
+			}
+			for (blockcnt = extent.e_lblk, j = 0;
+			     j < extent.e_len;
+			     blk++, blockcnt++, j++) {
+				new_blk = blk;
+				r = (*ctx.func)(fs, &new_blk, blockcnt,
+						0, 0, priv_data);
+				ret |= r;
+				check_for_ro_violation_goto(&ctx, ret,
+							    extent_errout);
+				if (r & BLOCK_CHANGED) {
+					ctx.errcode =
+						ext2fs_extent_set_bmap(handle,
+						       (blk64_t) blockcnt,
+						       (blk64_t) new_blk, 0);
+					if (ctx.errcode)
+						goto errout;
+				}
+				if (ret & BLOCK_ABORT) {
+					ext2fs_extent_free(handle);
+					goto errout;
+				}
+			}
+		}
+
+	extent_errout:
+		ext2fs_extent_free(handle);
+		ret |= BLOCK_ERROR | BLOCK_ABORT;
+		goto errout;
+	}
+
 	/*
 	 * 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,18 +463,11 @@
 
 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;
 	}
-
+errout:
 	if (!block_buf)
 		ext2fs_free_mem(&ctx.ind_buf);
 
diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index 754fc49..e56a99a 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,49 @@
 	}
 	addr_per_block = (blk_t) fs->blocksize >> 2;
 
+	if (inode->i_flags & EXT4_EXTENTS_FL) {
+		struct ext2fs_extent	extent;
+		unsigned int		offset;
+
+		retval = ext2fs_extent_open(fs, ino, &handle);
+		if (retval)
+			goto done;
+		if (bmap_flags & BMAP_SET) {
+			retval = ext2fs_extent_set_bmap(handle, block,
+							*phys_blk, 0);
+			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;
+		}
+		if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
+			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+			if (retval)
+				goto done;
+			retval = ext2fs_extent_set_bmap(handle, block,
+							(blk64_t) b, 0);
+			if (retval)
+				goto done;
+			blocks_alloc++;
+			*phys_blk = b;
+		}
+		retval = 0;
+		goto done;
+	}
+
 	if (!block_buf) {
 		retval = ext2fs_get_array(2, fs->blocksize, &buf);
 		if (retval)
@@ -167,10 +209,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 +233,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 +251,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 +276,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,16 +300,34 @@
 		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;
+		ext2fs_iblk_add_blocks(fs, inode, blocks_alloc);
 		retval = ext2fs_write_inode(fs, ino, inode);
 	}
 	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..206faa6 100644
--- a/lib/ext2fs/closefs.c
+++ b/lib/ext2fs/closefs.c
@@ -45,6 +45,19 @@
 	return 0;
 }
 
+/*
+ * This function returns the location of the superblock, block group
+ * descriptors for a given block group.  It currently returns the
+ * number of free blocks assuming that inode table and allocation
+ * bitmaps will be in the group.  This is not necessarily the case
+ * when the flex_bg feature is enabled, so callers should take care!
+ * It was only really intended for use by mke2fs, and even there it's
+ * not that useful.  In the future, when we redo this function for
+ * 64-bit block numbers, we should probably return the number of
+ * blocks used by the super block and group descriptors instead.
+ *
+ * See also the comment for ext2fs_reserve_super_and_bgd()
+ */
 int ext2fs_super_and_bgd_loc(ext2_filsys fs, 
 			     dgrp_t group,
 			     blk_t *ret_super_blk,
@@ -54,11 +67,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 +93,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 +203,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 +216,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 +236,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 +266,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 +343,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 +358,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..1091d73
--- /dev/null
+++ b/lib/ext2fs/csum.c
@@ -0,0 +1,135 @@
+/*
+ * 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)
+{
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+		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, dirty = 0;
+	dgrp_t i;
+
+	if (!fs->inode_map)
+		return EXT2_ET_NO_INODE_BITMAP;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+		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;
+
+		if (bg->bg_free_inodes_count == sb->s_inodes_per_group) {
+			bg->bg_flags |= EXT2_BG_INODE_UNINIT;
+			bg->bg_itable_unused = sb->s_inodes_per_group;
+		} else {
+			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);
+		}
+
+		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/expanddir.c b/lib/ext2fs/expanddir.c
index 10a5149..c124d3e 100644
--- a/lib/ext2fs/expanddir.c
+++ b/lib/ext2fs/expanddir.c
@@ -116,7 +116,7 @@
 		return retval;
 	
 	inode.i_size += fs->blocksize;
-	inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
+	ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
 
 	retval = ext2fs_write_inode(fs, dir, &inode);
 	if (retval)
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 7451242..a072fb8 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,88 @@
 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_CANT_SPLIT_EXTENT,
+	"Splitting would result in empty node"
+
+ec	EXT2_ET_EXTENT_NOT_FOUND,
+	"Extent not found"
+
+ec	EXT2_ET_EXTENT_NOT_SUPPORTED,
+	"Operation not supported for inodes containing extents"
+
+ec	EXT2_ET_EXTENT_INVALID_LENGTH,
+	"Extent length is invalid"
+
+	end
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index be8d773..bba5be8 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
 
 /*
@@ -263,6 +271,7 @@
 #define EXT2_NOTAIL_FL			0x00008000 /* file tail should not be merged */
 #define EXT2_DIRSYNC_FL 		0x00010000 /* Synchronous directory modifications */
 #define EXT2_TOPDIR_FL			0x00020000 /* Top of directory hierarchies*/
+#define EXT4_HUGE_FILE_FL               0x00040000 /* Set to each huge file */
 #define EXT4_EXTENTS_FL 		0x00080000 /* Inode uses extents */
 #define EXT2_RESERVED_FL		0x80000000 /* reserved for ext2 lib */
 
@@ -319,9 +328,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) */
@@ -331,7 +337,7 @@
 	union {
 		struct {
 			__u16	l_i_blocks_hi;
-			__u16	i_pad1;
+			__u16	l_i_file_acl_high;
 			__u16	l_i_uid_high;	/* these 2 fields    */
 			__u16	l_i_gid_high;	/* were reserved2[0] */
 			__u32	l_i_reserved2;
@@ -344,12 +350,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 +375,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) */
@@ -387,7 +384,7 @@
 	union {
 		struct {
 			__u16	l_i_blocks_hi;
-			__u16	i_pad1;
+			__u16	l_i_file_acl_high;
 			__u16	l_i_uid_high;	/* these 2 fields    */
 			__u16	l_i_gid_high;	/* were reserved2[0] */
 			__u32	l_i_reserved2;
@@ -400,12 +397,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;
@@ -414,6 +405,7 @@
 	__u32	i_atime_extra;	/* extra Access time (nsec << 2 | epoch) */
 	__u32	i_crtime;	/* File creation time */
 	__u32	i_crtime_extra;	/* extra File creation time (nsec << 2 | epoch)*/
+	__u32	i_version_hi;	/* high 32 bits for 64-bit version */
 };
 
 #define i_size_high	i_dir_acl
@@ -437,30 +429,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
@@ -590,7 +565,10 @@
 	__u16   s_mmp_interval;         /* # seconds to wait in MMP checking */
 	__u64   s_mmp_block;            /* Block for multi-mount protection */
 	__u32   s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
-	__u32   s_reserved[163];        /* Padding to the end of the block */
+	__u8	s_log_groups_per_flex;	/* FLEX_BG group size */
+	__u8    s_reserved_char_pad;
+	__u16	s_reserved_pad;		/* Padding to next 32bits */
+	__u32   s_reserved[162];        /* Padding to the end of the block */
 };
 
 /*
@@ -598,7 +576,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 +631,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..d9bbcca 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++)
 	
@@ -96,6 +111,11 @@
 /* unix_io.c */
 extern io_manager unix_io_manager;
 
+/* undo_io.c */
+extern io_manager undo_io_manager;
+extern errcode_t set_undo_io_backing_manager(io_manager manager);
+extern errcode_t set_undo_io_backup_file(char *file_name);
+
 /* test_io.c */
 extern io_manager test_io_manager, test_io_backing_manager;
 extern void (*test_io_cb_read_blk)
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index d098961..ebad54e 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
@@ -246,6 +229,13 @@
 	 */
 	struct ext2_inode_cache		*icache;
 	io_channel			image_io;
+
+	/*
+	 * More callback functions
+	 */
+	errcode_t (*get_alloc_block)(ext2_filsys fs, blk64_t goal,
+				     blk64_t *ret);
+	void (*block_alloc_stats)(ext2_filsys fs, blk64_t blk, int inuse);
 };
 
 #if EXT2_FLAT_INCLUDES
@@ -279,6 +269,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 +279,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 +300,75 @@
 #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 /* insert after handle loc'n */
+#define EXT2_EXTENT_INSERT_NOSPLIT	0x0002 /* insert may not cause split */
+
+/*
+ * Flags used by ext2fs_extent_delete()
+ */
+#define EXT2_EXTENT_DELETE_KEEP_EMPTY	0x001 /* keep node if last extnt gone */
+
+/*
+ * Flags used by ext2fs_extent_set_bmap()
+ */
+#define EXT2_EXTENT_SET_BMAP_UNINIT	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 +474,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 +495,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)
 
 /*
@@ -438,7 +506,6 @@
 					 EXT3_FEATURE_COMPAT_HAS_JOURNAL|\
 					 EXT2_FEATURE_COMPAT_RESIZE_INODE|\
 					 EXT2_FEATURE_COMPAT_DIR_INDEX|\
-					 EXT2_FEATURE_COMPAT_LAZY_BG|\
 					 EXT2_FEATURE_COMPAT_EXT_ATTR)
 
 /* This #ifdef is temporary until compression is fully supported */
@@ -453,25 +520,29 @@
 					 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)
+					 EXT4_FEATURE_RO_COMPAT_HUGE_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
  * to ext2fs_openfs()
  */
-#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)
+#define EXT2_LIB_SOFTSUPP_INCOMPAT	(0)
+#define EXT2_LIB_SOFTSUPP_RO_COMPAT	(EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)
 
 /*
  * function prototypes
@@ -488,11 +559,25 @@
 					blk_t *ret);
 extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
 				    char *block_buf, blk_t *ret);
+extern void ext2fs_set_alloc_block_callback(ext2_filsys fs, 
+					    errcode_t (*func)(ext2_filsys fs,
+							      blk64_t goal,
+							      blk64_t *ret),
+					    errcode_t (**old)(ext2_filsys fs,
+							      blk64_t goal,
+							      blk64_t *ret));
 
 /* alloc_sb.c */
 extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs, 
 					dgrp_t group,
 					ext2fs_block_bitmap bmap);
+extern void ext2fs_set_block_alloc_stats_callback(ext2_filsys fs, 
+						  void (*func)(ext2_filsys fs,
+							       blk64_t blk,
+							       int inuse),
+						  void (**old)(ext2_filsys fs,
+							       blk64_t blk,
+							       int inuse));
 
 /* alloc_stats.c */
 void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse);
@@ -552,15 +637,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 +659,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 +708,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 +736,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 +825,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 +834,26 @@
 					   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_set_bmap(ext2_extent_handle_t handle,
+					blk64_t logical, blk64_t physical,
+					int flags);
+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 +883,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);
@@ -768,6 +931,13 @@
 /* getsectsize.c */
 errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize);
 
+/* i_block.c */
+errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
+				 blk64_t num_blocks);
+errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
+				 blk64_t num_blocks);
+errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b);
+
 /* imager.c */
 extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags);
 extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags);
@@ -878,6 +1048,8 @@
 			      const char *name);
 
 /* mkjournal.c */
+extern errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num,
+				    blk_t *ret_blk, int *ret_count);
 extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
 						  __u32 size, int flags,
 						  char  **ret_jsb);
@@ -931,20 +1103,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..d4c84d0
--- /dev/null
+++ b/lib/ext2fs/extent.c
@@ -0,0 +1,1809 @@
+/*
+ * 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);
+	int				i;
+	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;
+
+	eh = (struct ext3_extent_header *) &handle->inode->i_block[0];
+
+	for (i=0; i < EXT2_N_BLOCKS; i++)
+		if (handle->inode->i_block[i])
+			break;
+	if (i >= EXT2_N_BLOCKS) {
+		eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
+		eh->eh_depth = 0;
+		eh->eh_entries = 0;
+		i = (sizeof(handle->inode->i_block) - sizeof(*eh)) /
+			sizeof(struct ext3_extent);
+		eh->eh_max = ext2fs_cpu_to_le16(i);
+		handle->inode->i_flags |= EXT4_EXTENTS_FL;
+	}
+
+	if (!(handle->inode->i_flags & EXT4_EXTENTS_FL))
+		return EXT2_ET_INODE_NOT_EXTENT;
+
+	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
+
+/*
+ * Go to the node at leaf_level which contains logical block blk.
+ *
+ * leaf_level is height from the leaf node level, i.e.
+ * leaf_level 0 is at leaf node, leaf_level 1 is 1 above etc.
+ *
+ * If "blk" has no mapping (hole) then handle is left at last
+ * extent before blk.
+ */
+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;
+
+	if (leaf_level > handle->max_depth) {
+		dbg_printf("leaf level %d greater than tree depth %d\n",
+			leaf_level, handle->max_depth);
+		return EXT2_ET_OP_NOT_SUPPORTED;
+	}
+
+	dbg_print_extent("root", &extent);
+	while (1) {
+		if (handle->max_depth - handle->level == leaf_level) {
+			/* block is in this &extent */
+			if ((blk >= extent.e_lblk) &&
+			    (blk < extent.e_lblk + extent.e_len))
+				return 0;
+			if (blk < extent.e_lblk) {
+				retval = ext2fs_extent_get(handle,
+							   EXT2_EXTENT_PREV_SIB,
+							   &extent);
+				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);
+}
+
+/*
+ * Traverse back up to root fixing parents of current node as needed.
+ *
+ * If we changed start of first entry in a node, fix parent index start
+ * and so on.
+ *
+ * Safe to call for any position in node; if not at the first entry,
+ * will  simply return.
+ */
+static errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
+{
+	int				retval = 0;
+	blk64_t				start;
+	struct extent_path		*path;
+	struct ext2fs_extent		extent;
+
+	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;
+
+	retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
+	if (retval)
+		goto done;
+
+	/* modified node's start block */
+	start = extent.e_lblk;
+
+	/* traverse up until index not first, or startblk matches, or top */
+	while (handle->level > 0 &&
+	       (path->left == path->entries - 1)) {
+		retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
+		if (retval)
+			goto done;
+		if (extent.e_lblk == start)
+			break;
+		path = handle->path + handle->level;
+		extent.e_len += (extent.e_lblk - start);
+		extent.e_lblk = start;
+		retval = ext2fs_extent_replace(handle, 0, &extent);
+		if (retval)
+			goto done;
+		update_path(handle);
+	}
+
+	/* put handle back to where we started */
+	retval = ext2fs_extent_goto(handle, start);
+done:
+	return retval;
+}
+
+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);
+		if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) {
+			if (extent->e_len > EXT_UNINIT_MAX_LEN)
+				return EXT2_ET_EXTENT_INVALID_LENGTH;
+			ex->ee_len = ext2fs_cpu_to_le16(extent->e_len +
+							EXT_INIT_MAX_LEN);
+		} else {
+			if (extent->e_len > EXT_INIT_MAX_LEN)
+				return EXT2_ET_EXTENT_INVALID_LENGTH;
+			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;
+}
+
+/*
+ * allocate a new block, move half the current node to it, and update parent
+ *
+ * handle will be left pointing at original record.
+ */
+static errcode_t extent_node_split(ext2_extent_handle_t handle, int flags)
+{
+	errcode_t			retval = 0;
+	blk_t				new_node_pblk;
+	blk64_t				new_node_start;
+	blk64_t				orig_lblk;
+	blk64_t				goal_blk = 0;
+	int				orig_height;
+	char				*block_buf = NULL;
+	struct ext2fs_extent		extent;
+	struct extent_path		*path, *newpath = 0;
+	struct ext3_extent		*ex;
+	struct ext3_extent_header	*eh, *neweh;
+	char				*cp;
+	int				tocopy;
+	int				new_root = 0;
+	struct ext2_extent_info		info;
+
+	/* basic sanity */
+	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;
+
+	dbg_printf("splitting node at level %d\n", handle->level);
+
+	retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
+	if (retval)
+		goto done;
+
+	retval = ext2fs_extent_get_info(handle, &info);
+	if (retval)
+		goto done;
+
+	/* save the position we were originally splitting... */
+	orig_height = info.max_depth - info.curr_level;
+	orig_lblk = extent.e_lblk;
+
+	/* Is there room in the parent for a new entry? */
+	if (handle->level &&
+			(handle->path[handle->level - 1].entries >=
+			 handle->path[handle->level - 1].max_entries)) {
+
+		dbg_printf("parent level %d full; splitting it too\n",
+							handle->level - 1);
+		/* split the parent */
+		retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
+		if (retval)
+			goto done;
+		goal_blk = extent.e_pblk;
+
+		retval = extent_node_split(handle, 0);
+		if (retval)
+			goto done;
+
+		/* get handle back to our original split position */
+		retval = extent_goto(handle, orig_height, orig_lblk);
+		if (retval)
+			goto done;
+	}
+
+	/* At this point, parent should have room for this split */
+	path = handle->path + handle->level;
+	if (!path->curr)
+		return EXT2_ET_NO_CURRENT_NODE;
+
+	/* extent header of the current node we'll split */
+	eh = (struct ext3_extent_header *)path->buf;
+
+	/* splitting root level means moving them all out */
+	if (handle->level == 0) {
+		new_root = 1;
+		tocopy = ext2fs_le16_to_cpu(eh->eh_entries);
+		retval = ext2fs_get_mem(((handle->max_depth+2) *
+					 sizeof(struct extent_path)),
+					&newpath);
+		if (retval)
+			goto done;
+		memset(newpath, 0,
+		       ((handle->max_depth+2) * sizeof(struct extent_path)));
+	} else {
+		tocopy = ext2fs_le16_to_cpu(eh->eh_entries) / 2;
+	}
+
+	dbg_printf("will copy out %d of %d entries at level %d\n",
+				tocopy, ext2fs_le16_to_cpu(eh->eh_entries),
+				handle->level);
+
+	if (!tocopy) {
+		dbg_printf("Nothing to copy to new block!\n");
+		retval = EXT2_ET_CANT_SPLIT_EXTENT;
+		goto done;
+	}
+
+	/* first we need a new block, or can do nothing. */
+	block_buf = malloc(handle->fs->blocksize);
+	if (!block_buf) {
+		retval = ENOMEM;
+		goto done;
+	}
+
+	if (!goal_blk) {
+		dgrp_t	group = ext2fs_group_of_ino(handle->fs, handle->ino);
+		__u8	log_flex = handle->fs->super->s_log_groups_per_flex;
+
+		if (log_flex)
+			group = group & ~((1 << (log_flex)) - 1);
+		goal_blk = (group * handle->fs->super->s_blocks_per_group) +
+			handle->fs->super->s_first_data_block;
+	}
+	retval = ext2fs_alloc_block(handle->fs, (blk_t) goal_blk, block_buf,
+				    &new_node_pblk);
+	if (retval)
+		goto done;
+
+	dbg_printf("will copy to new node at block %lu\n", new_node_pblk);
+
+	/* Copy data into new block buffer */
+	/* First the header for the new block... */
+	neweh = (struct ext3_extent_header *) block_buf;
+	memcpy(neweh, eh, sizeof(struct ext3_extent_header));
+	neweh->eh_entries = ext2fs_cpu_to_le16(tocopy);
+	neweh->eh_max = ext2fs_cpu_to_le16((handle->fs->blocksize -
+			 sizeof(struct ext3_extent_header)) /
+				sizeof(struct ext3_extent));
+
+	/* then the entries for the new block... */
+	memcpy(EXT_FIRST_INDEX(neweh),
+		EXT_FIRST_INDEX(eh) +
+			(ext2fs_le16_to_cpu(eh->eh_entries) - tocopy),
+		sizeof(struct ext3_extent_idx) * tocopy);
+
+	new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block);
+
+	/* ...and write the new node block out to disk. */
+	retval = io_channel_write_blk(handle->fs->io, new_node_pblk, 1, block_buf);
+
+	if (retval)
+		goto done;
+
+	/* OK! we've created the new node; now adjust the tree */
+
+	/* current path now has fewer active entries, we copied some out */
+	if (handle->level == 0) {
+		memcpy(newpath, path,
+		       sizeof(struct extent_path) * (handle->max_depth+1));
+		handle->path = newpath;
+		newpath = path;
+		path = handle->path;
+		path->entries = 1;
+		path->left = path->max_entries - 1;
+		handle->max_depth++;
+		eh->eh_depth = ext2fs_cpu_to_le16(handle->max_depth);
+	} else {
+		path->entries -= tocopy;
+		path->left -= tocopy;
+	}
+
+	eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
+	/* this writes out the node, incl. the modified header */
+	retval = update_path(handle);
+	if (retval)
+		goto done;
+
+	/* now go up and insert/replace index for new node we created */
+	if (new_root) {
+		retval = ext2fs_extent_get(handle, EXT2_EXTENT_FIRST_SIB, &extent);
+		if (retval)
+			goto done;
+
+		extent.e_lblk = new_node_start;
+		extent.e_pblk = new_node_pblk;
+		extent.e_len = handle->path[0].end_blk - extent.e_lblk;
+		retval = ext2fs_extent_replace(handle, 0, &extent);
+		if (retval)
+			goto done;
+	} else {
+		__u32 new_node_length;
+
+		retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
+		/* will insert after this one; it's length is shorter now */
+		new_node_length = new_node_start - extent.e_lblk;
+		extent.e_len -= new_node_length;
+		retval = ext2fs_extent_replace(handle, 0, &extent);
+		if (retval)
+			goto done;
+
+		/* now set up the new extent and insert it */
+		extent.e_lblk = new_node_start;
+		extent.e_pblk = new_node_pblk;
+		extent.e_len = new_node_length;
+		retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, &extent);
+		if (retval)
+			goto done;
+	}
+
+	/* get handle back to our original position */
+	retval = extent_goto(handle, orig_height, orig_lblk);
+	if (retval)
+		goto done;
+
+	/* new node hooked in, so update inode block count (do this here?) */
+	handle->inode->i_blocks += handle->fs->blocksize / 512;
+	retval = ext2fs_write_inode_full(handle->fs, handle->ino,
+		handle->inode, EXT2_INODE_SIZE(handle->fs->super));
+	if (retval)
+		goto done;
+
+done:
+	if (newpath)
+		ext2fs_free_mem(&newpath);
+	if (block_buf)
+		free(block_buf);
+
+	return retval;
+}
+
+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) {
+		if (flags & EXT2_EXTENT_INSERT_NOSPLIT) {
+			return EXT2_ET_CANT_INSERT_EXTENT;
+		} else {
+			dbg_printf("node full - splitting\n");
+			retval = extent_node_split(handle, 0);
+			if (retval)
+				goto errout;
+			path = handle->path + handle->level;
+		}
+	}
+
+	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;
+}
+
+/*
+ * Sets the physical block for a logical file block in the extent tree.
+ *
+ * May: map unmapped, unmap mapped, or remap mapped blocks.
+ *
+ * Mapping an unmapped block adds a single-block extent.
+ *
+ * Unmapping first or last block modifies extent in-place
+ *  - But may need to fix parent's starts too in first-block case
+ *
+ * Mapping any unmapped block requires adding a (single-block) extent
+ * and inserting into proper point in tree.
+ *
+ * Modifying (unmapping or remapping) a block in the middle
+ * of an extent requires splitting the extent.
+ *  - Remapping case requires new single-block extent.
+ *
+ * Remapping first or last block adds an extent.
+ *
+ * We really need extent adding to be smart about merging.
+ */
+
+errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
+				 blk64_t logical, blk64_t physical, int flags)
+{
+	errcode_t		ec, retval = 0;
+	int			mapped = 1; /* logical is mapped? */
+	int			orig_height;
+	int			extent_uninit = 0;
+	int			new_uninit = 0;
+	int			max_len = EXT_INIT_MAX_LEN;
+	blk64_t			orig_lblk;
+	struct extent_path	*path;
+	struct ext2fs_extent	extent;
+	struct ext2fs_extent	newextent;
+	struct ext2_extent_info	info;
+
+	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 (flags & EXT2_EXTENT_SET_BMAP_UNINIT) {
+		new_uninit = 1;
+		max_len = EXT_UNINIT_MAX_LEN;
+	}
+
+	/* if (re)mapping, set up new extent to insert */
+	if (physical) {
+		newextent.e_len = 1;
+		newextent.e_pblk = physical;
+		newextent.e_lblk = logical;
+		newextent.e_flags = EXT2_EXTENT_FLAGS_LEAF;
+		if (new_uninit)
+			newextent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
+	}
+
+	/* special case if the extent tree is completely empty */
+	if ((handle->max_depth == 0) && (path->entries == 0)) {
+		retval = ext2fs_extent_insert(handle, 0, &newextent);
+		goto done;
+	}
+
+	/* save our original location in the extent tree */
+	if ((retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
+					&extent))) {
+		if (retval != EXT2_ET_NO_CURRENT_NODE)
+			return retval;
+		memset(&extent, 0, sizeof(extent));
+	}
+	if ((retval = ext2fs_extent_get_info(handle, &info)))
+		return retval;
+	orig_height = info.max_depth - info.curr_level;
+	orig_lblk = extent.e_lblk;
+
+	/* go to the logical spot we want to (re/un)map */
+	retval = ext2fs_extent_goto(handle, logical);
+	if (retval) {
+		if (retval == EXT2_ET_EXTENT_NOT_FOUND) {
+			retval = 0;
+			mapped = 0;
+			if (!physical) {
+				dbg_printf("block already unmapped\n");
+				goto done;
+			}
+		} else
+			goto done;
+	}
+
+	/*
+	 * This may be the extent *before* the requested logical,
+	 * if it's currently unmapped.
+	 */
+	retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
+	if (retval)
+		goto done;
+	if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
+		extent_uninit = 1;
+
+	/* check if already pointing to the requested physical */
+	if (mapped && (new_uninit == extent_uninit) &&
+	    (extent.e_pblk + (logical - extent.e_lblk) == physical)) {
+		dbg_printf("physical block unchanged\n");
+		goto done;
+	}
+
+	if (!mapped) {
+		dbg_printf("mapping unmapped logical block\n");
+		if ((logical == extent.e_lblk + extent.e_len) &&
+		    (physical == extent.e_pblk + extent.e_len) &&
+		    (new_uninit == extent_uninit) &&
+		    (extent.e_len < max_len-1)) {
+			extent.e_len++;
+			retval = ext2fs_extent_replace(handle, 0, &extent);
+		} else
+			retval = ext2fs_extent_insert(handle,
+				      EXT2_EXTENT_INSERT_AFTER, &newextent);
+		if (retval)
+			goto done;
+		retval = ext2fs_extent_fix_parents(handle);
+		if (retval)
+			goto done;
+	} else if ((logical == extent.e_lblk) && (extent.e_len == 1))  {
+		dbg_printf("(re/un)mapping only block in extent\n");
+		if (physical) {
+			extent.e_pblk = physical;
+			retval = ext2fs_extent_replace(handle, 0, &extent);
+		} else {
+			retval = ext2fs_extent_delete(handle, 0);
+			if (retval)
+				goto done;
+			ec = ext2fs_extent_fix_parents(handle);
+			if (ec != EXT2_ET_NO_CURRENT_NODE)
+				retval = ec;
+		}
+
+		if (retval)
+			goto done;
+	} else if (logical == extent.e_lblk + extent.e_len - 1)  {
+		dbg_printf("(re/un)mapping last block in extent\n");
+		extent.e_len--;
+		retval = ext2fs_extent_replace(handle, 0, &extent);
+		if (retval)
+			goto done;
+		if (physical) {
+			retval = ext2fs_extent_insert(handle,
+					EXT2_EXTENT_INSERT_AFTER, &newextent);
+			if (retval)
+				goto done;
+		}
+	} else if (logical == extent.e_lblk) {
+		dbg_printf("(re/un)mapping first block in extent\n");
+		extent.e_pblk++;
+		extent.e_lblk++;
+		extent.e_len--;
+		retval = ext2fs_extent_replace(handle, 0, &extent);
+		if (retval)
+			goto done;
+		if (physical) {
+			/* insert new extent ahead of current */
+			retval = ext2fs_extent_insert(handle,
+					0, &newextent);
+			if (retval)
+				goto done;
+		} else {
+			retval = ext2fs_extent_fix_parents(handle);
+			if (retval)
+				goto done;
+		}
+	} else {
+		__u32	orig_length;
+
+		dbg_printf("(re/un)mapping in middle of extent\n");
+		/* need to split this extent; later */
+
+		orig_length = extent.e_len;
+
+		/* shorten pre-split extent */
+		extent.e_len = (logical - extent.e_lblk);
+		retval = ext2fs_extent_replace(handle, 0, &extent);
+		if (retval)
+			goto done;
+		/* insert our new extent, if any */
+		if (physical) {
+			/* insert new extent after current */
+			retval = ext2fs_extent_insert(handle,
+					EXT2_EXTENT_INSERT_AFTER, &newextent);
+			if (retval)
+				goto done;
+		}
+		/* add post-split extent */
+		extent.e_pblk += extent.e_len + 1;
+		extent.e_lblk += extent.e_len + 1;
+		extent.e_len = orig_length - extent.e_len - 1;
+		retval = ext2fs_extent_insert(handle,
+				EXT2_EXTENT_INSERT_AFTER, &extent);
+		if (retval)
+			goto done;
+	}
+
+done:
+	/* get handle back to its position */
+	if (orig_height > handle->max_depth)
+		orig_height = handle->max_depth; /* In case we shortened the tree */
+	extent_goto(handle, orig_height, orig_lblk);
+	return retval;
+}
+
+errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags)
+{
+	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;
+	}
+	if (--path->entries == 0)
+		path->curr = 0;
+
+	/* if non-root node has no entries left, remove it & parent ptr to it */
+	if (path->entries == 0 && handle->level) {
+		if (!(flags & EXT2_EXTENT_DELETE_KEEP_EMPTY)) {
+			struct ext2fs_extent	extent;
+
+			retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP,
+								&extent);
+			if (retval)
+				return retval;
+
+			retval = ext2fs_extent_delete(handle, flags);
+			handle->inode->i_blocks -= handle->fs->blocksize / 512;
+			retval = ext2fs_write_inode_full(handle->fs,
+					handle->ino, handle->inode,
+					EXT2_INODE_SIZE(handle->fs->super));
+			ext2fs_block_alloc_stats(handle->fs, extent.e_pblk, -1);
+		}
+	} else {
+		eh = (struct ext3_extent_header *) path->buf;
+		eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
+		if ((path->entries == 0) && (handle->level == 0))
+			eh->eh_depth = handle->max_depth = 0;
+		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;
+
+int common_extent_args_process(int argc, char *argv[], int min_argc,
+			       int max_argc, const char *cmd,
+			       const char *usage, int flags)
+{
+	if (common_args_process(argc, argv, min_argc, max_argc, cmd,
+				usage, flags))
+		return 1;
+	
+	if (!current_handle) {
+		com_err(cmd, 0, "Extent handle not open");
+		return 1;
+	}
+	return 0;
+}
+
+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 (common_extent_args_process(argc, argv, 1, 1, "delete_node",
+				       "", CHECK_FS_RW | CHECK_FS_BITMAPS))
+		return;
+
+	retval = ext2fs_extent_delete(current_handle, 0);
+	if (retval) {
+		com_err(argv[0], retval, 0);
+		return;
+	}
+	if (current_handle->path && current_handle->path[0].curr)
+		do_current_node(argc, argv);
+}
+
+void do_replace_node(int argc, char *argv[])
+{
+	const char	*usage = "[--uninit] <lblk> <len> <pblk>";
+	errcode_t	retval;
+	struct ext2fs_extent extent;
+	int err;
+
+	if (common_extent_args_process(argc, argv, 3, 5, "replace_node",
+				       usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
+		return;
+
+	extent.e_flags = 0;
+
+	if (!strcmp(argv[1], "--uninit")) {
+		argc--;
+		argv++;
+		extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
+	}
+
+	if (argc != 4) {
+		fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
+		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_split_node(int argc, char *argv[])
+{
+	errcode_t	retval;
+	struct ext2fs_extent extent;
+	int err;
+	int flags = 0;
+
+	if (common_extent_args_process(argc, argv, 1, 1, "split_node",
+				       "", CHECK_FS_RW | CHECK_FS_BITMAPS))
+		return;
+
+	retval = extent_node_split(current_handle, flags);
+	if (retval) {
+		com_err(argv[0], retval, 0);
+		return;
+	}
+	do_current_node(argc, argv);
+}
+
+void do_insert_node(int argc, char *argv[])
+{
+	const char	*usage = "[--after] [--uninit] <lblk> <len> <pblk>";
+	errcode_t	retval;
+	struct ext2fs_extent extent;
+	char *cmd;
+	int err;
+	int flags = 0;
+
+	if (common_extent_args_process(argc, argv, 3, 6, "insert_node",
+				       usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
+		return;
+
+	cmd = argv[0];
+
+	extent.e_flags = 0;
+
+	while (argc > 2) {
+		if (!strcmp(argv[1], "--after")) {
+			argc--;
+			argv++;
+			flags |= EXT2_EXTENT_INSERT_AFTER;
+			continue;
+		}
+		if (!strcmp(argv[1], "--uninit")) {
+			argc--;
+			argv++;
+			extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
+			continue;
+		}
+		break;
+	}
+
+	if (argc != 4) {
+		fprintf(stderr, "usage: %s %s\n", cmd, usage);
+		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_set_bmap(int argc, char **argv)
+{
+	const char	*usage = "[--uninit] <lblk> <pblk>";
+	errcode_t	retval;
+	blk_t		logical;
+	blk_t		physical;
+	char		*cmd = argv[0];
+	int		flags = 0;
+	int		err;
+
+	if (common_extent_args_process(argc, argv, 3, 5, "set_bmap",
+				       usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
+		return;
+
+	if (argc > 2 && !strcmp(argv[1], "--uninit")) {
+		argc--;
+		argv++;
+		flags |= EXT2_EXTENT_SET_BMAP_UNINIT;
+	}
+
+	if (argc != 3) {
+		fprintf(stderr, "Usage: %s %s\n", cmd, usage);
+		return;
+	}
+
+	logical = parse_ulong(argv[1], cmd,
+				    "logical block", &err);
+	if (err)
+		return;
+
+	physical = parse_ulong(argv[2], cmd,
+				    "physical block", &err);
+	if (err)
+		return;
+
+	retval = ext2fs_extent_set_bmap(current_handle, logical,
+					(blk64_t) physical, flags);
+	if (retval) {
+		com_err(cmd, retval, 0);
+		return;
+	}
+	if (current_handle->path && current_handle->path[0].curr)
+		do_current_node(argc, argv);
+}
+
+void do_print_all(int argc, char **argv)
+{
+	const char	*usage = "[--leaf-only|--reverse|--reverse-leaf]";
+	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 (common_extent_args_process(argc, argv, 1, 2, "print_all",
+				       usage, 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 {
+			fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
+			return;
+		}
+	}
+
+	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 ext2fs_extent	extent;
+	struct ext2_extent_info	info;
+	errcode_t		retval;
+
+	if (common_extent_args_process(argc, argv, 1, 1, "info", "", 0))
+		return;
+
+	retval = ext2fs_extent_get_info(current_handle, &info);
+	if (retval) {
+		com_err(argv[0], retval, 0);
+		return;
+	}
+
+	retval = ext2fs_extent_get(current_handle,
+				   EXT2_EXTENT_CURRENT, &extent);
+	if (retval) {
+		com_err(argv[0], retval, 0);
+		return;
+	}
+
+	dbg_print_extent(0, &extent);
+
+	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;
+	int			level = 0;
+
+	if (common_extent_args_process(argc, argv, 2, 3, "goto_block",
+				       "block [level]", 0))
+		return;
+
+	if (strtoblk(argv[0], argv[1], &blk))
+		return;
+
+	if (argc == 3)
+		if (strtoblk(argv[0], argv[2], &level))
+			return;
+
+	retval = extent_goto(current_handle, level, (blk64_t) blk);
+
+	if (retval) {
+		com_err(argv[0], retval, "while trying to go to block %lu, level %d",
+			blk, level);
+		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..d0571f4
--- /dev/null
+++ b/lib/ext2fs/extent_dbg.ct
@@ -0,0 +1,74 @@
+#
+# 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_split_node, "Split node",
+	split_node, split;
+
+request do_set_bmap, "Set block mapping",
+	set_bmap;
+
+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/i_block.c b/lib/ext2fs/i_block.c
new file mode 100644
index 0000000..c7e5c44
--- /dev/null
+++ b/lib/ext2fs/i_block.c
@@ -0,0 +1,75 @@
+/*
+ * i_block.c --- Manage the i_block field for i_blocks
+ *
+ * Copyright (C) 2008 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+#include <string.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_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
+				 blk64_t num_blocks)
+{
+	unsigned long long b;
+
+	if ((fs->super->s_feature_ro_compat &
+	     EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
+	    (inode->i_flags & EXT4_HUGE_FILE_FL)) {
+		b = inode->i_blocks +
+			(((long long) inode->osd2.linux2.l_i_blocks_hi) << 32);
+		b += num_blocks;
+		inode->i_blocks = b & 0xFFFFFFFF;
+		inode->osd2.linux2.l_i_blocks_hi = b >> 32;
+	} else
+		inode->i_blocks += (fs->blocksize / 512) * num_blocks;
+	return 0;
+}
+
+
+errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
+				 blk64_t num_blocks)
+{
+	unsigned long long b;
+
+	if ((fs->super->s_feature_ro_compat &
+	     EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
+	    (inode->i_flags & EXT4_HUGE_FILE_FL)) {
+		b = inode->i_blocks +
+			(((long long) inode->osd2.linux2.l_i_blocks_hi) << 32);
+		b -= num_blocks;
+		inode->i_blocks = b & 0xFFFFFFFF;
+		inode->osd2.linux2.l_i_blocks_hi = b >> 32;
+	} else
+		inode->i_blocks -= (fs->blocksize / 512) * num_blocks;
+	return 0;
+}
+
+errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b)
+{
+	if ((fs->super->s_feature_ro_compat &
+	     EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
+	    (inode->i_flags & EXT4_HUGE_FILE_FL)) {
+		inode->i_blocks = b & 0xFFFFFFFF;
+		inode->osd2.linux2.l_i_blocks_hi = b >> 32;
+	} else
+		inode->i_blocks = (fs->blocksize / 512) * b;
+	return 0;
+}
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..011656f 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;
@@ -103,6 +103,7 @@
 	dgrp_t		i;
 	blk_t		numblocks;
 	int		rsv_gdt;
+	int		csum_flag;
 	int		io_flags;
 	char		*buf;
 	char		c;
@@ -158,6 +159,7 @@
 	set_field(s_first_meta_bg, 0);
 	set_field(s_raid_stride, 0);		/* default stride size: 0 */
 	set_field(s_raid_stripe_width, 0);	/* default stripe width: 0 */
+	set_field(s_log_groups_per_flex, 0);
 	set_field(s_flags, 0);
 	if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
 		retval = EXT2_ET_UNSUPP_FEATURE;
@@ -172,6 +174,15 @@
 	if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
 		set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
 		set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
+		if (super->s_inode_size >= sizeof(struct ext2_inode_large)) {
+			int extra_isize = sizeof(struct ext2_inode_large) -
+				EXT2_GOOD_OLD_INODE_SIZE;
+			set_field(s_min_extra_isize, extra_isize);
+			set_field(s_want_extra_isize, extra_isize);
+		}
+	} else {
+		super->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
+		super->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
 	}
 
 	set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
@@ -367,16 +378,39 @@
 	 * Note that although the block bitmap, inode bitmap, and
 	 * inode table have not been allocated (and in fact won't be
 	 * by this routine), they are accounted for nevertheless.
+	 *
+	 * If FLEX_BG meta-data grouping is used, only account for the
+	 * superblock and group descriptors (the inode tables and
+	 * bitmaps will be accounted for when allocated).
 	 */
 	super->s_free_blocks_count = 0;
+	csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+					       EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
 	for (i = 0; i < fs->group_desc_count; i++) {
+		/*
+		 * Don't set the BLOCK_UNINIT group for the last group
+		 * because the block bitmap needs to be padded.
+		 */
+		if (csum_flag) {
+			if (i != fs->group_desc_count - 1)
+				fs->group_desc[i].bg_flags |=
+					EXT2_BG_BLOCK_UNINIT;
+			fs->group_desc[i].bg_flags |= EXT2_BG_INODE_UNINIT;
+			numblocks = super->s_inodes_per_group;
+			if (i == 0)
+				numblocks -= super->s_first_ino;
+			fs->group_desc[i].bg_itable_unused = numblocks;
+		}
 		numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
+		if (fs->super->s_log_groups_per_flex)
+			numblocks += 2 + fs->inode_blocks_per_group;
 
 		super->s_free_blocks_count += numblocks;
 		fs->group_desc[i].bg_free_blocks_count = numblocks;
 		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..8908423 100644
--- a/lib/ext2fs/inode.c
+++ b/lib/ext2fs/inode.c
@@ -146,6 +146,15 @@
 		group_desc[scan->current_group].bg_inode_table;
 	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
 	scan->blocks_left = scan->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;
+	}
 	retval = ext2fs_get_array(scan->inode_buffer_blocks,
 					  fs->blocksize,
 				&scan->inode_buffer);
@@ -164,8 +173,8 @@
 	}
 	if (scan->fs->badblocks && scan->fs->badblocks->num)
 		scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
-	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
-				    EXT2_FEATURE_COMPAT_LAZY_BG))
+	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 +227,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 +437,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 +475,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 +601,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 +673,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/jfs_compat.h b/lib/ext2fs/jfs_compat.h
index 30ad1ef..7b8aafd 100644
--- a/lib/ext2fs/jfs_compat.h
+++ b/lib/ext2fs/jfs_compat.h
@@ -45,6 +45,7 @@
 	tid_t			j_transaction_sequence;
 	__u8			j_uuid[16];
 	struct jbd_revoke_table_s *j_revoke;
+	tid_t			j_failed_commit;
 };
 
 #define J_ASSERT(assert)						\
diff --git a/lib/ext2fs/kernel-jbd.h b/lib/ext2fs/kernel-jbd.h
index 2a099d8..158d764 100644
--- a/lib/ext2fs/kernel-jbd.h
+++ b/lib/ext2fs/kernel-jbd.h
@@ -108,6 +108,30 @@
 	__u32		h_sequence;
 } journal_header_t;
 
+/*
+ * Checksum types.
+ */
+#define JBD2_CRC32_CHKSUM   1
+#define JBD2_MD5_CHKSUM     2
+#define JBD2_SHA1_CHKSUM    3
+
+#define JBD2_CRC32_CHKSUM_SIZE 4
+
+#define JBD2_CHECKSUM_BYTES (32 / sizeof(__u32))
+/*
+ * Commit block header for storing transactional checksums:
+ */
+struct commit_header {
+	__u32		h_magic;
+	__u32		h_blocktype;
+	__u32		h_sequence;
+	unsigned char	h_chksum_type;
+	unsigned char	h_chksum_size;
+	unsigned char	h_padding[2];
+	__u32		h_chksum[JBD2_CHECKSUM_BYTES];
+	__u64		h_commit_sec;
+	__u32		h_commit_nsec;
+};
 
 /* 
  * The block tag: used to describe a single buffer in the journal 
@@ -116,8 +140,12 @@
 {
 	__u32		t_blocknr;	/* The on-disk block number */
 	__u32		t_flags;	/* See below */
+	__u32		t_blocknr_high; /* most-significant high 32bits. */
 } journal_block_tag_t;
 
+#define JBD_TAG_SIZE64 (sizeof(journal_block_tag_t))
+#define JBD_TAG_SIZE32 (8)
+
 /* 
  * The revoke descriptor: used on disk to describe a series of blocks to
  * be revoked from the log 
@@ -194,12 +222,19 @@
 	((j)->j_format_version >= 2 &&					\
 	 ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
 
+#define JFS_FEATURE_COMPAT_CHECKSUM	0x00000001
+
 #define JFS_FEATURE_INCOMPAT_REVOKE	0x00000001
 
+#define JFS_FEATURE_INCOMPAT_REVOKE		0x00000001
+#define JFS_FEATURE_INCOMPAT_64BIT		0x00000002
+#define JFS_FEATURE_INCOMPAT_ASYNC_COMMIT	0x00000004
+
 /* Features known to this kernel version: */
 #define JFS_KNOWN_COMPAT_FEATURES	0
 #define JFS_KNOWN_ROCOMPAT_FEATURES	0
-#define JFS_KNOWN_INCOMPAT_FEATURES	JFS_FEATURE_INCOMPAT_REVOKE
+#define JFS_KNOWN_INCOMPAT_FEATURES	(JFS_FEATURE_INCOMPAT_REVOKE|\
+					 JFS_FEATURE_INCOMPAT_ASYNC_COMMIT)
 
 #ifdef __KERNEL__
 
@@ -548,6 +583,9 @@
 	/* The revoke table: maintains the list of revoked blocks in the
            current transaction. */
 	struct jbd_revoke_table_s *j_revoke;
+
+	/* Failed journal commit ID */
+	unsigned int		j_failed_commit;
 };
 
 /* 
diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
index 45e6820..34242df 100644
--- a/lib/ext2fs/mkdir.c
+++ b/lib/ext2fs/mkdir.c
@@ -82,7 +82,7 @@
 	memset(&inode, 0, sizeof(struct ext2_inode));
 	inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
 	inode.i_uid = inode.i_gid = 0;
-	inode.i_blocks = fs->blocksize / 512;
+	ext2fs_iblk_set(fs, &inode, 1);
 	inode.i_block[0] = blk;
 	inode.i_links_count = 2;
 	inode.i_ctime = inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(NULL);
diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c
index 61d10a6..ca8e733 100644
--- a/lib/ext2fs/mkjournal.c
+++ b/lib/ext2fs/mkjournal.c
@@ -135,11 +135,69 @@
 }
 
 /*
+ * Convenience 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.)
+ */
+#define STRIDE_LENGTH 8
+errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num,
+			     blk_t *ret_blk, int *ret_count)
+{
+	int		j, count;
+	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)
+			return ENOMEM;
+		memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
+	}
+	/* OK, do the write loop */
+	j=0;
+	while (j < num) {
+		if (blk % STRIDE_LENGTH)
+			count = STRIDE_LENGTH - (blk % STRIDE_LENGTH);
+		else {
+			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;
+		}
+		j += count; blk += count;
+	}
+	return 0;
+}
+
+/*
  * Helper function for creating the journal using direct I/O routines
  */
 struct mkjournal_struct {
 	int		num_blocks;
 	int		newblocks;
+	blk_t		blk_to_zero;
+	int		zero_count;
 	char		*buf;
 	errcode_t	err;
 };
@@ -169,7 +227,27 @@
 		es->num_blocks--;
 
 	es->newblocks++;
-	retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
+	retval = 0;
+	if (blockcnt <= 0)
+		retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
+	else {
+		if (es->zero_count) {
+			if ((es->blk_to_zero + es->zero_count == new_blk) &&
+			    (es->zero_count < 1024))
+				es->zero_count++;
+			else {
+				retval = ext2fs_zero_blocks(fs,
+							    es->blk_to_zero,
+							    es->zero_count,
+							    0, 0);
+				es->zero_count = 0;
+			}
+		}
+		if (es->zero_count == 0) {
+			es->blk_to_zero = new_blk;
+			es->zero_count = 1;
+		}
+	}
 
 	if (blockcnt == 0)
 		memset(es->buf, 0, fs->blocksize);
@@ -216,6 +294,7 @@
 	es.newblocks = 0;
 	es.buf = buf;
 	es.err = 0;
+	es.zero_count = 0;
 
 	retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
 				       0, mkjournal_proc, &es);
@@ -223,12 +302,18 @@
 		retval = es.err;
 		goto errout;
 	}
+	if (es.zero_count) {
+		retval = ext2fs_zero_blocks(fs, es.blk_to_zero,
+					    es.zero_count, 0, 0);
+		if (retval)
+			goto errout;
+	}
 
 	if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
 		goto errout;
 
  	inode.i_size += fs->blocksize * size;
-	inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
+	ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
 	inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0);
 	inode.i_links_count = 1;
 	inode.i_mode = LINUX_S_IFREG | 0600;
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..875be9f 100644
--- a/lib/ext2fs/read_bb.c
+++ b/lib/ext2fs/read_bb.c
@@ -74,10 +74,15 @@
 		retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
 		if (retval)
 			return retval;
-		if (inode.i_blocks < 500)
-			numblocks = (inode.i_blocks /
-				     (fs->blocksize / 512)) + 20;
-		else
+		numblocks = inode.i_blocks;
+		if (!((fs->super->s_feature_ro_compat &
+		       EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
+		      (inode.i_flags & EXT4_HUGE_FILE_FL)))
+			numblocks = numblocks / (fs->blocksize / 512);
+		numblocks += 20;
+		if (numblocks < 50)
+			numblocks = 50;
+		if (numblocks > 50000)
 			numblocks = 500;
 		retval = ext2fs_badblocks_list_create(bb_list, numblocks);
 		if (retval)
@@ -86,8 +91,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/res_gdt.c b/lib/ext2fs/res_gdt.c
index ef87ab7..848a02a 100644
--- a/lib/ext2fs/res_gdt.c
+++ b/lib/ext2fs/res_gdt.c
@@ -64,7 +64,6 @@
 	struct ext2_super_block	*sb;
 	struct ext2_inode	inode;
 	__u32			*dindir_buf, *gdt_buf;
-	int			rsv_add;
 	unsigned long long	apb, inode_size;
 	blk_t			dindir_blk, rsv_off, gdt_off, gdt_blk;
 	int			dindir_dirty = 0, inode_dirty = 0;
@@ -84,7 +83,6 @@
 
 	/* Maximum possible file size (we donly use the dindirect blocks) */
 	apb = EXT2_ADDR_PER_BLOCK(sb);
-	rsv_add = fs->blocksize / 512;
 	if ((dindir_blk = inode.i_block[EXT2_DIND_BLOCK])) {
 #ifdef RES_GDT_DEBUG
 		printf("reading GDT dindir %u\n", dindir_blk);
@@ -103,7 +101,7 @@
 		inode.i_mode = LINUX_S_IFREG | 0600;
 		inode.i_links_count = 1;
 		inode.i_block[EXT2_DIND_BLOCK] = dindir_blk;
-		inode.i_blocks = rsv_add;
+		ext2fs_iblk_set(fs, &inode, 1);
 		memset(dindir_buf, 0, fs->blocksize);
 #ifdef RES_GDT_DEBUG
 		printf("allocated GDT dindir %u\n", dindir_blk);
@@ -144,7 +142,7 @@
 			gdt_dirty = dindir_dirty = inode_dirty = 1;
 			memset(gdt_buf, 0, fs->blocksize);
 			dindir_buf[gdt_off] = gdt_blk;
-			inode.i_blocks += rsv_add;
+			ext2fs_iblk_add_blocks(fs, &inode, 1);
 #ifdef RES_GDT_DEBUG
 			printf("added primary GDT block %u at %u[%u]\n",
 			       gdt_blk, dindir_blk, gdt_off);
@@ -175,7 +173,7 @@
 				       expect, grp, gdt_blk, last);
 #endif
 				gdt_buf[last] = expect;
-				inode.i_blocks += rsv_add;
+				ext2fs_iblk_add_blocks(fs, &inode, 1);
 				gdt_dirty = inode_dirty = 1;
 			} else if (gdt_buf[last] != expect) {
 #ifdef RES_GDT_DEBUG
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..b7fda5a 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,22 +34,23 @@
 	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;
+	int		csum_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);
 
 	if (!(fs->flags & EXT2_FLAG_RW))
 		return EXT2_ET_RO_FILSYS;
-	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
-				    EXT2_FEATURE_COMPAT_LAZY_BG))
-		lazy_flag = 1;
+
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+		csum_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 +58,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 +67,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 &
+		if (csum_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 +90,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 &
+		if (csum_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,18 +139,24 @@
 	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;
-	int lazy_flag = 0;
+	unsigned int block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+	unsigned inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
+	int csum_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))
-		lazy_flag = 1;
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+		csum_flag = 1;
 
 	retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
 	if (retval)
@@ -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)
+			if (csum_flag && fs->group_desc[i].bg_flags &
+			    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)
+			if (csum_flag && fs->group_desc[i].bg_flags &
+			    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..5fe3292 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) {
@@ -176,7 +195,8 @@
 			ext2fs_swab32(f->osd1.linux1.l_i_version);
 		t->osd2.linux2.l_i_blocks_hi = 
 			ext2fs_swab16(f->osd2.linux2.l_i_blocks_hi);
-		t->osd2.linux2.i_pad1 = ext2fs_swab16(f->osd2.linux2.i_pad1);
+		t->osd2.linux2.l_i_file_acl_high =
+			ext2fs_swab16(f->osd2.linux2.l_i_file_acl_high);
 		t->osd2.linux2.l_i_uid_high =
 		  ext2fs_swab16 (f->osd2.linux2.l_i_uid_high);
 		t->osd2.linux2.l_i_gid_high =
@@ -198,16 +218,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..c2f5449 100644
--- a/lib/ext2fs/test_io.c
+++ b/lib/ext2fs/test_io.c
@@ -52,6 +52,8 @@
 	void (*write_blk)(unsigned long block, int count, errcode_t err);
 	void (*set_blksize)(int blksize, errcode_t err);
 	void (*write_byte)(unsigned long block, int count, errcode_t err);
+	void (*read_blk64)(unsigned long long block, int count, errcode_t err);
+	void (*write_blk64)(unsigned long long block, int count, errcode_t err);
 };
 
 static errcode_t test_open(const char *name, int flags, io_channel *channel);
@@ -61,11 +63,17 @@
 			       int count, void *data);
 static errcode_t test_write_blk(io_channel channel, unsigned long block,
 				int count, const void *data);
+static errcode_t test_read_blk64(io_channel channel, unsigned long long block,
+			       int count, void *data);
+static errcode_t test_write_blk64(io_channel channel, unsigned long long block,
+				int count, const void *data);
 static errcode_t test_flush(io_channel channel);
 static errcode_t test_write_byte(io_channel channel, unsigned long offset,
 				 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 +85,10 @@
 	test_write_blk,
 	test_flush,
 	test_write_byte,
-	test_set_option
+	test_set_option,
+	test_get_stats,
+	test_read_blk64,
+	test_write_blk64,
 };
 
 io_manager test_io_manager = &struct_test_manager;
@@ -91,6 +102,10 @@
 	(unsigned long block, int count, errcode_t err) = 0;
 void (*test_io_cb_write_blk)
 	(unsigned long block, int count, errcode_t err) = 0;
+void (*test_io_cb_read_blk64)
+	(unsigned long long block, int count, errcode_t err) = 0;
+void (*test_io_cb_write_blk64)
+	(unsigned long long block, int count, errcode_t err) = 0;
 void (*test_io_cb_set_blksize)
 	(int blksize, errcode_t err) = 0;
 void (*test_io_cb_write_byte)
@@ -205,6 +220,8 @@
 	data->write_blk = 	test_io_cb_write_blk;
 	data->set_blksize = 	test_io_cb_set_blksize;
 	data->write_byte = 	test_io_cb_write_byte;
+	data->read_blk64 = 	test_io_cb_read_blk64;
+	data->write_blk64 = 	test_io_cb_write_blk64;
 
 	data->outfile = NULL;
 	if ((value = safe_getenv("TEST_IO_LOGFILE")) != NULL)
@@ -340,6 +357,60 @@
 	return retval;
 }
 
+static errcode_t test_read_blk64(io_channel channel, unsigned long long block,
+			       int count, void *buf)
+{
+	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)
+		retval = io_channel_read_blk64(data->real, block, count, buf);
+	if (data->read_blk64)
+		data->read_blk64(block, count, retval);
+	if (data->flags & TEST_FLAG_READ)
+		fprintf(data->outfile,
+			"Test_io: read_blk64(%llu, %d) returned %s\n",
+			block, count, retval ? error_message(retval) : "OK");
+	if (data->block && data->block == block) {
+		if (data->flags & TEST_FLAG_DUMP)
+			test_dump_block(channel, data, block, buf);
+		if (--data->read_abort_count == 0)
+			test_abort(channel, block);
+	} 
+	return retval;
+}
+
+static errcode_t test_write_blk64(io_channel channel, unsigned long long block,
+			       int count, const void *buf)
+{
+	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)
+		retval = io_channel_write_blk64(data->real, block, count, buf);
+	if (data->write_blk64)
+		data->write_blk64(block, count, retval);
+	if (data->flags & TEST_FLAG_WRITE)
+		fprintf(data->outfile,
+			"Test_io: write_blk64(%llu, %d) returned %s\n",
+			block, count, retval ? error_message(retval) : "OK");
+	if (data->block && data->block == block) {
+		if (data->flags & TEST_FLAG_DUMP)
+			test_dump_block(channel, data, block, buf);
+		if (--data->write_abort_count == 0)
+			test_abort(channel, block);
+	}
+	return retval;
+}
+
 static errcode_t test_write_byte(io_channel channel, unsigned long offset,
 			       int count, const void *buf)
 {
@@ -409,3 +480,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/undo_io.c b/lib/ext2fs/undo_io.c
new file mode 100644
index 0000000..e1e6458
--- /dev/null
+++ b/lib/ext2fs/undo_io.c
@@ -0,0 +1,575 @@
+/*
+ * undo_io.c --- This is the undo io manager that copies the old data that
+ * copies the old data being overwritten into a tdb database
+ *
+ * Copyright IBM Corporation, 2007
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include "tdb.h"
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+	  if ((struct)->magic != (code)) return (code)
+
+struct undo_private_data {
+	int	magic;
+	TDB_CONTEXT *tdb;
+	char *tdb_file;
+
+	/* The backing io channel */
+	io_channel real;
+
+	int tdb_data_size;
+	int tdb_written;
+
+	/* to support offset in unix I/O manager */
+	ext2_loff_t offset;
+};
+
+static errcode_t undo_open(const char *name, int flags, io_channel *channel);
+static errcode_t undo_close(io_channel channel);
+static errcode_t undo_set_blksize(io_channel channel, int blksize);
+static errcode_t undo_read_blk(io_channel channel, unsigned long block,
+			       int count, void *data);
+static errcode_t undo_write_blk(io_channel channel, unsigned long block,
+				int count, const void *data);
+static errcode_t undo_flush(io_channel channel);
+static errcode_t undo_write_byte(io_channel channel, unsigned long offset,
+				int size, const void *data);
+static errcode_t undo_set_option(io_channel channel, const char *option,
+				 const char *arg);
+
+static struct struct_io_manager struct_undo_manager = {
+	EXT2_ET_MAGIC_IO_MANAGER,
+	"Undo I/O Manager",
+	undo_open,
+	undo_close,
+	undo_set_blksize,
+	undo_read_blk,
+	undo_write_blk,
+	undo_flush,
+	undo_write_byte,
+	undo_set_option
+};
+
+io_manager undo_io_manager = &struct_undo_manager;
+static io_manager undo_io_backing_manager ;
+static char *tdb_file;
+static int actual_size;
+
+errcode_t set_undo_io_backing_manager(io_manager manager)
+{
+	/*
+	 * We may want to do some validation later
+	 */
+	undo_io_backing_manager = manager;
+	return 0;
+}
+
+errcode_t set_undo_io_backup_file(char *file_name)
+{
+	tdb_file = strdup(file_name);
+
+	if (tdb_file == NULL) {
+		return EXT2_ET_NO_MEMORY;
+	}
+
+	return 0;
+}
+
+static errcode_t write_file_system_identity(io_channel undo_channel,
+							TDB_CONTEXT *tdb)
+{
+	errcode_t retval;
+	struct ext2_super_block super;
+	TDB_DATA tdb_key, tdb_data;
+	struct undo_private_data *data;
+	io_channel channel;
+	int block_size ;
+
+	data = (struct undo_private_data *) undo_channel->private_data;
+	channel = data->real;
+	block_size = channel->block_size;
+
+	io_channel_set_blksize(channel, SUPERBLOCK_OFFSET);
+	retval = io_channel_read_blk(channel, 1, -SUPERBLOCK_SIZE, &super);
+	if (retval)
+		goto err_out;
+
+	/* Write to tdb file in the file system byte order */
+	tdb_key.dptr = "filesystem MTIME";
+	tdb_key.dsize = sizeof("filesystem MTIME");
+	tdb_data.dptr = (unsigned char *) &(super.s_mtime);
+	tdb_data.dsize = sizeof(super.s_mtime);
+
+	retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT);
+	if (retval == -1) {
+		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+		goto err_out;
+	}
+
+	tdb_key.dptr = "filesystem UUID";
+	tdb_key.dsize = sizeof("filesystem UUID");
+	tdb_data.dptr = (unsigned char *)&(super.s_uuid);
+	tdb_data.dsize = sizeof(super.s_uuid);
+
+	retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT);
+	if (retval == -1) {
+		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+	}
+
+err_out:
+	io_channel_set_blksize(channel, block_size);
+	return retval;
+}
+
+static errcode_t write_block_size(TDB_CONTEXT *tdb, int block_size)
+{
+	errcode_t retval;
+	TDB_DATA tdb_key, tdb_data;
+
+	tdb_key.dptr = "filesystem BLKSIZE";
+	tdb_key.dsize = sizeof("filesystem BLKSIZE");
+	tdb_data.dptr = (unsigned char *)&(block_size);
+	tdb_data.dsize = sizeof(block_size);
+
+	retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT);
+	if (retval == -1) {
+		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+	}
+
+	return retval;
+}
+
+static errcode_t undo_write_tdb(io_channel channel,
+				unsigned long block, int count)
+
+{
+	int size, i, sz;
+	unsigned long block_num, backing_blk_num;
+	errcode_t retval = 0;
+	ext2_loff_t offset;
+	struct undo_private_data *data;
+	TDB_DATA tdb_key, tdb_data;
+	char *read_ptr;
+	unsigned long end_block;
+
+	data = (struct undo_private_data *) channel->private_data;
+
+	if (data->tdb == NULL) {
+		/*
+		 * Transaction database not initialized
+		 */
+		return 0;
+	}
+
+	if (count == 1)
+		size = channel->block_size;
+	else {
+		if (count < 0)
+			size = -count;
+		else
+			size = count * channel->block_size;
+	}
+	/*
+	 * Data is stored in tdb database as blocks of tdb_data_size size
+	 * This helps in efficient lookup further.
+	 *
+	 * We divide the disk to blocks of tdb_data_size.
+	 */
+	offset = (block * channel->block_size) + data->offset ;
+	block_num = offset / data->tdb_data_size;
+	end_block = (offset + size) / data->tdb_data_size;
+
+	tdb_transaction_start(data->tdb);
+	while (block_num <= end_block ) {
+
+		tdb_key.dptr = (unsigned char *)&block_num;
+		tdb_key.dsize = sizeof(block_num);
+		/*
+		 * Check if we have the record already
+		 */
+		if (tdb_exists(data->tdb, tdb_key)) {
+			/* Try the next block */
+			block_num++;
+			continue;
+		}
+		/*
+		 * Read one block using the backing I/O manager
+		 * The backing I/O manager block size may be
+		 * different from the tdb_data_size.
+		 * Also we need to recalcuate the block number with respect
+		 * to the backing I/O manager.
+		 */
+		offset = block_num * data->tdb_data_size;
+		backing_blk_num = (offset - data->offset) / channel->block_size;
+
+		count = data->tdb_data_size +
+				((offset - data->offset) % channel->block_size);
+		retval = ext2fs_get_mem(count, &read_ptr);
+		if (retval) {
+			tdb_transaction_cancel(data->tdb);
+			return retval;
+		}
+
+		memset(read_ptr, 0, count);
+		actual_size = 0;
+		if ((count % channel->block_size) == 0)
+			sz = count / channel->block_size;
+		else
+			sz = -count;
+		retval = io_channel_read_blk(data->real, backing_blk_num,
+					     sz, read_ptr);
+		if (retval) {
+			if (retval != EXT2_ET_SHORT_READ) {
+				free(read_ptr);
+				tdb_transaction_cancel(data->tdb);
+				return retval;
+			}
+			/*
+			 * short read so update the record size
+			 * accordingly
+			 */
+			tdb_data.dsize = actual_size;
+		} else {
+			tdb_data.dsize = data->tdb_data_size;
+		}
+		tdb_data.dptr = read_ptr +
+				((offset - data->offset) % channel->block_size);
+#ifdef DEBUG
+		printf("Printing with key %ld data %x and size %d\n",
+		       block_num,
+		       tdb_data.dptr,
+		       tdb_data.dsize);
+#endif
+		if (!data->tdb_written) {
+			data->tdb_written = 1;
+			/* Write the blocksize to tdb file */
+			retval = write_block_size(data->tdb,
+						  data->tdb_data_size);
+			if (retval) {
+				tdb_transaction_cancel(data->tdb);
+				retval = EXT2_ET_TDB_ERR_IO;
+				free(read_ptr);
+				return retval;
+			}
+		}
+		retval = tdb_store(data->tdb, tdb_key, tdb_data, TDB_INSERT);
+		if (retval == -1) {
+			/*
+			 * TDB_ERR_EXISTS cannot happen because we
+			 * have already verified it doesn't exist
+			 */
+			tdb_transaction_cancel(data->tdb);
+			retval = EXT2_ET_TDB_ERR_IO;
+			free(read_ptr);
+			return retval;
+		}
+		free(read_ptr);
+		/* Next block */
+		block_num++;
+	}
+	tdb_transaction_commit(data->tdb);
+
+	return retval;
+}
+
+static errcode_t undo_io_read_error(io_channel channel,
+			unsigned long block, int count, void *data,
+			size_t size, int actual, errcode_t error)
+{
+	actual_size = actual;
+	return error;
+}
+
+static void undo_err_handler_init(io_channel channel)
+{
+	channel->read_error = undo_io_read_error;
+}
+
+static errcode_t undo_open(const char *name, int flags, io_channel *channel)
+{
+	io_channel	io = NULL;
+	struct undo_private_data *data = NULL;
+	errcode_t	retval;
+	int		open_flags;
+	struct stat	st;
+
+	if (name == 0)
+		return EXT2_ET_BAD_DEVICE_NAME;
+	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+	if (retval)
+		return retval;
+	memset(io, 0, sizeof(struct struct_io_channel));
+	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+	retval = ext2fs_get_mem(sizeof(struct undo_private_data), &data);
+	if (retval)
+		goto cleanup;
+
+	io->manager = undo_io_manager;
+	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+	if (retval)
+		goto cleanup;
+
+	strcpy(io->name, name);
+	io->private_data = data;
+	io->block_size = 1024;
+	io->read_error = 0;
+	io->write_error = 0;
+	io->refcount = 1;
+
+	memset(data, 0, sizeof(struct undo_private_data));
+	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
+
+	if (undo_io_backing_manager) {
+		retval = undo_io_backing_manager->open(name, flags,
+						       &data->real);
+		if (retval)
+			goto cleanup;
+	} else {
+		data->real = 0;
+	}
+
+	/* setup the tdb file */
+	data->tdb = tdb_open(tdb_file, 0, TDB_CLEAR_IF_FIRST,
+			     O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600);
+	if (!data->tdb) {
+		retval = errno;
+		goto cleanup;
+	}
+
+	/*
+	 * setup err handler for read so that we know
+	 * when the backing manager fails do short read
+	 */
+	undo_err_handler_init(data->real);
+
+	*channel = io;
+	return 0;
+
+cleanup:
+	if (data->real)
+		io_channel_close(data->real);
+	if (data)
+		ext2fs_free_mem(&data);
+	if (io)
+		ext2fs_free_mem(&io);
+	return retval;
+}
+
+static errcode_t undo_close(io_channel channel)
+{
+	struct undo_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct undo_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+	if (--channel->refcount > 0)
+		return 0;
+	/* Before closing write the file system identity */
+	retval = write_file_system_identity(channel, data->tdb);
+	if (retval)
+		return retval;
+	if (data->real)
+		retval = io_channel_close(data->real);
+	if (data->tdb)
+		tdb_close(data->tdb);
+	ext2fs_free_mem(&channel->private_data);
+	if (channel->name)
+		ext2fs_free_mem(&channel->name);
+	ext2fs_free_mem(&channel);
+
+	return retval;
+}
+
+static errcode_t undo_set_blksize(io_channel channel, int blksize)
+{
+	struct undo_private_data *data;
+	errcode_t		retval;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct undo_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+	if (data->real)
+		retval = io_channel_set_blksize(data->real, blksize);
+	/*
+	 * Set the block size used for tdb
+	 */
+	if (!data->tdb_data_size) {
+		data->tdb_data_size = blksize;
+	}
+	channel->block_size = blksize;
+	return retval;
+}
+
+static errcode_t undo_read_blk(io_channel channel, unsigned long block,
+			       int count, void *buf)
+{
+	errcode_t	retval;
+	struct undo_private_data *data;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct undo_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+	if (data->real)
+		retval = io_channel_read_blk(data->real, block, count, buf);
+
+	return retval;
+}
+
+static errcode_t undo_write_blk(io_channel channel, unsigned long block,
+				int count, const void *buf)
+{
+	struct undo_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct undo_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+	/*
+	 * First write the existing content into database
+	 */
+	retval = undo_write_tdb(channel, block, count);
+	if (retval)
+		 return retval;
+	if (data->real)
+		retval = io_channel_write_blk(data->real, block, count, buf);
+
+	return retval;
+}
+
+static errcode_t undo_write_byte(io_channel channel, unsigned long offset,
+				 int size, const void *buf)
+{
+	struct undo_private_data *data;
+	errcode_t	retval = 0;
+	ssize_t		actual;
+	ext2_loff_t	location;
+	unsigned long blk_num, count;;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct undo_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+	location = offset + data->offset;
+	blk_num = location/channel->block_size;
+	/*
+	 * the size specified may spread across multiple blocks
+	 * also make sure we account for the fact that block start
+	 * offset for tdb is different from the backing I/O manager
+	 * due to possible different block size
+	 */
+	count = (size + (location % channel->block_size) +
+			channel->block_size  -1)/channel->block_size;
+	retval = undo_write_tdb(channel, blk_num, count);
+	if (retval)
+		return retval;
+	if (data->real && data->real->manager->write_byte)
+		retval = io_channel_write_byte(data->real, offset, size, buf);
+
+	return retval;
+}
+
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t undo_flush(io_channel channel)
+{
+	errcode_t	retval = 0;
+	struct undo_private_data *data;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct undo_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+	if (data->real)
+		retval = io_channel_flush(data->real);
+
+	return retval;
+}
+
+static errcode_t undo_set_option(io_channel channel, const char *option,
+				 const char *arg)
+{
+	errcode_t	retval = 0;
+	struct undo_private_data *data;
+	unsigned long tmp;
+	char *end;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct undo_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+	if (!strcmp(option, "tdb_data_size")) {
+		if (!arg)
+			return EXT2_ET_INVALID_ARGUMENT;
+
+		tmp = strtoul(arg, &end, 0);
+		if (*end)
+			return EXT2_ET_INVALID_ARGUMENT;
+		if (!data->tdb_data_size || !data->tdb_written) {
+			data->tdb_data_size = tmp;
+		}
+		return 0;
+	}
+	/*
+	 * Need to support offset option to work with
+	 * Unix I/O manager
+	 */
+	if (data->real && data->real->manager->set_option) {
+		retval = data->real->manager->set_option(data->real,
+							option, arg);
+	}
+	if (!retval && !strcmp(option, "offset")) {
+		if (!arg)
+			return EXT2_ET_INVALID_ARGUMENT;
+
+		tmp = strtoul(arg, &end, 0);
+		if (*end)
+			return EXT2_ET_INVALID_ARGUMENT;
+		data->offset = tmp;
+	}
+	return retval;
+}
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..63a16a3 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -18,11 +18,11 @@
 @UUIDD_CMT@UUIDD_MAN= uuidd.8
 
 SPROGS=		mke2fs badblocks tune2fs dumpe2fs blkid logsave \
-			$(E2IMAGE_PROG) @FSCK_PROG@
+			$(E2IMAGE_PROG) @FSCK_PROG@ e2undo
 USPROGS=	mklost+found filefrag $(UUIDD_PROG)
 SMANPAGES=	tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
 			e2label.8 findfs.8 blkid.8 $(E2IMAGE_MAN) \
-			logsave.8 filefrag.8 $(UUIDD_MAN) @FSCK_MAN@
+			logsave.8 filefrag.8 e2undo.8 $(UUIDD_MAN) @FSCK_MAN@
 FMANPAGES=	mke2fs.conf.5
 
 UPROGS=		chattr lsattr uuidgen
@@ -43,6 +43,7 @@
 FSCK_OBJS=	fsck.o base_device.o ismounted.o
 BLKID_OBJS=	blkid.o
 FILEFRAG_OBJS=	filefrag.o
+E2UNDO_OBJS=  e2undo.o
 
 XTRA_CFLAGS=	-I$(srcdir)/../e2fsck -I.
 
@@ -51,7 +52,8 @@
 		$(srcdir)/badblocks.c $(srcdir)/fsck.c $(srcdir)/util.c \
 		$(srcdir)/uuidgen.c $(srcdir)/blkid.c $(srcdir)/logsave.c \
 		$(srcdir)/filefrag.c $(srcdir)/base_device.c \
-		$(srcdir)/ismounted.c $(srcdir)/../e2fsck/profile.c
+		$(srcdir)/ismounted.c $(srcdir)/../e2fsck/profile.c \
+		$(srcdir)/e2undo.c
 
 LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) 
 DEPLIBS= $(LIBEXT2FS) $(LIBCOM_ERR) 
@@ -80,7 +82,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 $<"
@@ -112,6 +114,10 @@
 	@echo "	LD $@"
 	@$(CC) $(ALL_LDFLAGS) -o e2image $(E2IMAGE_OBJS) $(LIBS) $(LIBINTL)
 
+e2undo: $(E2UNDO_OBJS) $(DEPLIBS)
+	@echo "	LD $@"
+	@$(CC) $(ALL_LDFLAGS) -o e2undo $(E2UNDO_OBJS) $(LIBS)
+
 base_device: base_device.c
 	@echo "	LD $@"
 	@$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(srcdir)/base_device.c \
@@ -197,6 +203,10 @@
 	@echo "	SUBST $@"
 	@$(SUBSTITUTE_UPTIME) $(srcdir)/e2label.8.in e2label.8
 
+e2undo.8: $(DEP_SUBSTITUTE) $(srcdir)/e2undo.8.in
+	@echo "	SUBST $@"
+	@$(SUBSTITUTE_UPTIME) $(srcdir)/e2undo.8.in e2undo.8
+
 findfs.8: $(DEP_SUBSTITUTE) $(srcdir)/findfs.8.in
 	@echo "	SUBST $@"
 	@$(SUBSTITUTE_UPTIME) $(srcdir)/findfs.8.in findfs.8
@@ -272,6 +282,12 @@
 	@echo "	LINK $(root_sbindir)/mkfs.ext3"
 	@$(LN) -f $(DESTDIR)$(root_sbindir)/mke2fs \
 		$(DESTDIR)$(root_sbindir)/mkfs.ext3
+	@echo "	LINK $(root_sbindir)/mkfs.ext4"
+	@$(LN) -f $(DESTDIR)$(root_sbindir)/mke2fs \
+		$(DESTDIR)$(root_sbindir)/mkfs.ext4
+	@echo "	LINK $(root_sbindir)/mkfs.ext4dev"
+	@$(LN) -f $(DESTDIR)$(root_sbindir)/mke2fs \
+		$(DESTDIR)$(root_sbindir)/mkfs.ext4dev
 	@echo "	LINK $(root_sbindir)/e2label"
 	@$(LN) -f $(DESTDIR)$(root_sbindir)/tune2fs \
 		$(DESTDIR)$(root_sbindir)/e2label
@@ -301,6 +317,12 @@
 	@echo "	LINK mkfs.ext3.8"
 	@$(LN) -f $(DESTDIR)$(man8dir)/mke2fs.8 \
 		$(DESTDIR)$(man8dir)/mkfs.ext3.8
+	@echo "	LINK mkfs.ext4.8"
+	@$(LN) -f $(DESTDIR)$(man8dir)/mke2fs.8 \
+		$(DESTDIR)$(man8dir)/mkfs.ext4.8
+	@echo "	LINK mkfs.ext4dev.8"
+	@$(LN) -f $(DESTDIR)$(man8dir)/mke2fs.8 \
+		$(DESTDIR)$(man8dir)/mkfs.ext4dev.8
 	@for i in $(UMANPAGES); do \
 		for j in $(COMPRESS_EXT); do \
 			$(RM) -f $(DESTDIR)$(man1dir)/$$i.$$j; \
@@ -342,7 +364,9 @@
 		$(RM) -f $(DESTDIR)$(libdir)/$$i; \
 	done
 	$(RM) -f $(DESTDIR)$(root_sbindir)/mkfs.ext2 \
-			$(DESTDIR)$(root_sbindir)/mkfs.ext3
+			$(DESTDIR)$(root_sbindir)/mkfs.ext3 \
+			$(DESTDIR)$(root_sbindir)/mkfs.ext4 \
+			$(DESTDIR)$(root_sbindir)/mkfs.ext4dev
 	for i in $(UPROGS); do \
 		$(RM) -f $(DESTDIR)$(bindir)/$$i; \
 	done
@@ -350,16 +374,15 @@
 		$(RM) -f $(DESTDIR)$(man8dir)/$$i; \
 	done
 	$(RM) -f $(DESTDIR)$(man8dir)/mkfs.ext2.8 \
-		$(DESTDIR)$(man8dir)/mkfs.ext3.8
+		$(DESTDIR)$(man8dir)/mkfs.ext3.8 \
+		$(DESTDIR)$(man8dir)/mkfs.ext4.8 \
+		$(DESTDIR)$(man8dir)/mkfs.ext4dev.8
 	for i in $(UMANPAGES); do \
 		$(RM) -f $(DESTDIR)$(man1dir)/$$i; \
 	done
 	for i in findfs e2label ; do \
 		$(RM) -f $(DESTDIR)$(root_sbindir)/$$i; \
 	done
-	for i in fsck.ext2.8 fsck.ext3.8 ; do \
-		$(RM) -f $(DESTDIR)$(man8dir)/$$i; \
-	done
 	for i in $(FMANPAGES); do \
 		$(RM) -f $(DESTDIR)$(man5dir)/$$i; \
 	done
@@ -451,3 +474,4 @@
 ismounted.o: $(srcdir)/ismounted.c $(top_srcdir)/lib/et/com_err.h
 profile.o: $(srcdir)/../e2fsck/profile.c $(top_srcdir)/lib/et/com_err.h \
  $(srcdir)/../e2fsck/profile.h prof_err.h
+e2undo.o: $(srcdir)/e2undo.c $(top_srcdir)/lib/ext2fs/tdb.h
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..98a6315 100644
--- a/misc/dumpe2fs.c
+++ b/misc/dumpe2fs.c
@@ -110,16 +110,16 @@
 }
 static void print_bg_opts(ext2_filsys fs, dgrp_t i)
 {
-	int first = 1, bg_flags;
+	int first = 1, bg_flags = 0;
 
-	if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_LAZY_BG)
+	if (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 +134,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 +169,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 +214,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;
 		}
 	}
 }
@@ -275,7 +293,12 @@
 		exit(1);
 	}
 	fputs(_("Journal size:             "), stdout);
-	size = inode.i_blocks >> 1;
+	if ((fs->super->s_feature_ro_compat &
+	     EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
+	    (inode.i_flags & EXT4_HUGE_FILE_FL))
+		size = inode.i_blocks / (fs->blocksize / 1024);
+	else
+		size = inode.i_blocks >> 1;
 	if (size < 8192)
 		printf("%uk\n", size);
 	else
@@ -326,9 +349,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 +376,7 @@
 		if (strcmp(token, "superblock") == 0 ||
 		    strcmp(token, "sb") == 0) {
 			if (!arg) {
-				usage++;
+				do_usage++;
 				badopt = token;
 				continue;
 			}
@@ -362,13 +385,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 +400,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 +416,7 @@
 			"Valid extended options are:\n"
 			"\tsuperblock=<superblock number>\n"
 			"\tblocksize=<blocksize>\n"),
-			badopt);
+			badopt ? badopt : "");
 		free(buf);
 		exit(1);
 	}
@@ -405,13 +428,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 +510,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/e2undo.8.in b/misc/e2undo.8.in
new file mode 100644
index 0000000..4bf0798
--- /dev/null
+++ b/misc/e2undo.8.in
@@ -0,0 +1,44 @@
+.\" -*- nroff -*-
+.\" Copyright 2008 by Theodore Ts'o.  All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH E2UNDO 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+e2undo \- Replay an undo log for an ext2/ext3/ext4 filesystem
+.SH SYNOPSIS
+.B e2undo
+[
+.B \-f
+]
+.I undo_log device
+.SH DESCRIPTION
+.B e2undo
+will replay the undo log
+.I undo_log
+for an ext2/ext3/ext4 filesystem found on
+.IR device .
+This can be
+used to undo a failed operation by an e2fsprogs program.
+.SH OPTIONS
+.TP
+.B \-f
+Normally,
+.B e2undo
+will check the filesystem UUID and last modified time to make sure the
+undo log matches with the filesystem on the device.  If they do not
+match,
+.B e2undo
+will refuse to apply the undo log as a safety mechanism.  The
+.B \-f
+option disables this safety mechanism.
+.SH AUTHOR
+.B e2undo
+was written by Aneesh Kumar K.V. (aneesh.kumar@linux.vnet.ibm.com)
+.SH AVAILABILITY
+.B e2undo
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR mke2fs (8),
+.BR tune2fs (8)
+
diff --git a/misc/e2undo.c b/misc/e2undo.c
new file mode 100644
index 0000000..ca24303
--- /dev/null
+++ b/misc/e2undo.c
@@ -0,0 +1,213 @@
+/*
+ * e2undo.c - Replay an undo log onto an ext2/3/4 filesystem
+ *
+ * Copyright IBM Corporation, 2007
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#include <fcntl.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include "ext2fs/tdb.h"
+#include "ext2fs/ext2fs.h"
+#include "nls-enable.h"
+
+unsigned char mtime_key[] = "filesystem MTIME";
+unsigned char uuid_key[] = "filesystem UUID";
+unsigned char blksize_key[] = "filesystem BLKSIZE";
+
+static void usage(char *prg_name)
+{
+	fprintf(stderr,
+		_("Usage: %s <transaction file> <filesystem>\n"), prg_name);
+	exit(1);
+
+}
+
+static int check_filesystem(TDB_CONTEXT *tdb, io_channel channel)
+{
+	__u32   s_mtime;
+	__u8    s_uuid[16];
+	errcode_t retval;
+	TDB_DATA tdb_key, tdb_data;
+	struct ext2_super_block super;
+
+	io_channel_set_blksize(channel, SUPERBLOCK_OFFSET);
+	retval = io_channel_read_blk(channel, 1, -SUPERBLOCK_SIZE, &super);
+	if (retval) {
+		com_err(__FUNCTION__,
+			retval, _("Failed to read the file system data \n"));
+		return retval;
+	}
+
+	tdb_key.dptr = mtime_key;
+	tdb_key.dsize = sizeof(mtime_key);
+	tdb_data = tdb_fetch(tdb, tdb_key);
+	if (!tdb_data.dptr) {
+		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+		com_err(__FUNCTION__, retval,
+			_("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+		return retval;
+	}
+
+	s_mtime = *(__u32 *)tdb_data.dptr;
+	if (super.s_mtime != s_mtime) {
+
+		com_err(__FUNCTION__, 0,
+			_("The file system Mount time didn't match %u\n"),
+			s_mtime);
+
+		return  -1;
+	}
+
+
+	tdb_key.dptr = uuid_key;
+	tdb_key.dsize = sizeof(uuid_key);
+	tdb_data = tdb_fetch(tdb, tdb_key);
+	if (!tdb_data.dptr) {
+		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+		com_err(__FUNCTION__, retval,
+			_("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+		return retval;
+	}
+	memcpy(s_uuid, tdb_data.dptr, sizeof(s_uuid));
+	if (memcmp(s_uuid, super.s_uuid, sizeof(s_uuid))) {
+		com_err(__FUNCTION__, 0,
+			_("The file system UUID didn't match \n"));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int set_blk_size(TDB_CONTEXT *tdb, io_channel channel)
+{
+	int block_size;
+	errcode_t retval;
+	TDB_DATA tdb_key, tdb_data;
+
+	tdb_key.dptr = blksize_key;
+	tdb_key.dsize = sizeof(blksize_key);
+	tdb_data = tdb_fetch(tdb, tdb_key);
+	if (!tdb_data.dptr) {
+		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+		com_err(__FUNCTION__, retval,
+			_("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+		return retval;
+	}
+
+	block_size = *(int *)tdb_data.dptr;
+#ifdef DEBUG
+	printf("Block size %d\n", block_size);
+#endif
+	io_channel_set_blksize(channel, block_size);
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int c,force = 0;
+	TDB_CONTEXT *tdb;
+	TDB_DATA key, data;
+	io_channel channel;
+	errcode_t retval;
+	int  mount_flags;
+	unsigned long  blk_num;
+	char *device_name, *tdb_file, *prg_name;
+	io_manager manager = unix_io_manager;
+
+	prg_name = argv[0];
+	while((c = getopt(argc, argv, "f")) != EOF) {
+		switch (c) {
+			case 'f':
+				force = 1;
+				break;
+			default:
+				usage(prg_name);
+		}
+	}
+
+	if (argc != optind+2)
+		usage(prg_name);
+
+	tdb_file = argv[optind];
+	device_name = argv[optind+1];
+
+	tdb = tdb_open(tdb_file, 0, 0, O_RDONLY, 0600);
+
+	if (!tdb) {
+		com_err(prg_name, errno,
+				_("Failed tdb_open %s\n"), tdb_file);
+		exit(1);
+	}
+
+	retval = ext2fs_check_if_mounted(device_name, &mount_flags);
+	if (retval) {
+		com_err(prg_name, retval, _("Error while determining whether "
+				"%s is mounted.\n"), device_name);
+		exit(1);
+	}
+
+	if (mount_flags & EXT2_MF_MOUNTED) {
+		com_err(prg_name, retval, _("undoe2fs should only be run on "
+				"unmounted file system\n"));
+		exit(1);
+	}
+
+	retval = manager->open(device_name,
+				IO_FLAG_EXCLUSIVE | IO_FLAG_RW,  &channel);
+	if (retval) {
+		com_err(prg_name, retval,
+				_("Failed to open %s\n"), device_name);
+		exit(1);
+	}
+
+	if (!force && check_filesystem(tdb, channel)) {
+		exit(1);
+	}
+
+	if (set_blk_size(tdb, channel)) {
+		exit(1);
+	}
+
+	for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key)) {
+		if (!strcmp((char *) key.dptr, (char *) mtime_key) ||
+		    !strcmp((char *) key.dptr, (char *) uuid_key) ||
+		    !strcmp((char *) key.dptr, (char *) blksize_key)) {
+			continue;
+		}
+
+		data = tdb_fetch(tdb, key);
+		if (!data.dptr) {
+			com_err(prg_name, 0,
+				_("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+			exit(1);
+		}
+		blk_num = *(unsigned long *)key.dptr;
+		printf(_("Replayed transaction of size %d at location %ld\n"),
+							data.dsize, blk_num);
+		retval = io_channel_write_blk(channel, blk_num,
+						-data.dsize, data.dptr);
+		if (retval == -1) {
+			com_err(prg_name, retval,
+					_("Failed write %s\n"),
+					strerror(errno));
+			exit(1);
+		}
+	}
+	io_channel_close(channel);
+	tdb_close(tdb);
+
+}
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..8dc3b6d 100644
--- a/misc/mke2fs.8.in
+++ b/misc/mke2fs.8.in
@@ -26,6 +26,10 @@
 .I blocks-per-group
 ]
 [
+.B \-G
+.I number-of-groups
+]
+[
 .B \-i
 .I bytes-per-inode
 ]
@@ -88,8 +92,12 @@
 .B \-S
 ]
 [
+.B \-t
+.I fs-type
+]
+[
 .B \-T
-.I filesystem-type
+.I usage-type
 ]
 [
 .B \-V
@@ -185,7 +193,7 @@
 filesystem blocks. This is the number of blocks read or written to disk
 before moving to next disk. This mostly affects placement of filesystem
 metadata like bitmaps at
-.BR mke2fs (2)
+.B mke2fs
 time to avoid placing them on a single disk, which can hurt the performanace.
 It may also be used by block allocator.
 .TP
@@ -201,6 +209,16 @@
 Reserve enough space so that the block group descriptor table can grow
 to support a filesystem that has max-online-resize blocks.
 .TP
+.B lazy_itable_init\fR[\fb= \fI<0 to disable, 1 to enable>\fR]
+If enabled and the uninit_bg feature is enabled, the inode table will
+not fully initialized by 
+.BR mke2fs .
+This speeds up filesystem
+initialization noitceably, but it requires the kernel to finish
+initializing the filesystem in the background when the filesystem is
+first mounted.  If the option value is omitted, it defaults to 1 to
+enable lazy inode table initialization.
+.TP
 .B test_fs
 Set a flag in the filesystem superblock indicating that it may be
 mounted using experimental kernel code, such as the ext4dev filesystem.
@@ -232,6 +250,13 @@
 This option is generally used by developers who
 are developing test cases.  
 .TP
+.BI \-G " number-of-groups"
+Specify the number of block goups that will be packed together to
+create one large virtual block group on an ext4 filesystem.  This
+improves meta-data locality and performance on meta-data heavy
+workloads.  The number of goups must be a power of 2 and may only be
+specified if the flex_bg filesystem feature is enabled.
+.TP
 .BI \-i " bytes-per-inode"
 Specify the bytes/inode ratio. 
 .B mke2fs
@@ -384,19 +409,26 @@
 .TP
 .B "\-O \fIfeature\fR[,...]"
 Create filesystem with given features (filesystem options), overriding 
-the default filesystem options.  The default features which are 
+the default filesystem options.  The default features which are
 enabled by default are specified by the
 .I base_features
 relation, either in the
 .I [libdefaults]
 section in the
 .B /etc/mke2fs.conf
-configuration file, or in the subsection of the 
+configuration file,
+or in the subsection of the
 .I [fs_types]
-section for the filesystem type as specified by the
+section for the usage types as specified by the
 .B -T
-option.  The filesystem type-specific configuration setting found in
-the 
+option, further modified by the
+.I features
+relation found in the
+.I [fs_types] section
+based on the filesystem and usage types.  See the
+.BR mke2fs.conf (5)
+manual page for more details.
+The filesystem type-specific configuration setting found in the
 .I [fs_types]
 section will override the global default found in
 .IR [libdefaults] .
@@ -425,6 +457,11 @@
 .B filetype
 Store file type information in directory entries.
 .TP
+.B flex_bg
+Allow bitmaps and inode tables for a block group to be placed anywhere
+on the storage media (use with -G option to group meta-data in order
+to create a large virtual block group).
+.TP
 .B has_journal
 Create an ext3 journal (as if using the
 .B \-j
@@ -438,6 +475,22 @@
 @JDEV@must be created with the same
 @JDEV@block size as the filesystems that will be using it.
 .TP
+.B extent
+Instead of using the indirect block scheme for storing the location of
+data blocks in an inode, use extents instead.  This is a much more
+efficient encoding which speeds up filesystem access, especially for
+large files.
+.TP
+.B uninit_bg
+Create a filesystem without initializing all of the block groups.  This 
+feature also enables checksums and highest-inode-used statistics in each
+blockgroup.  This feature can
+speed up filesystem creation time noticably (if lazy_itable_init is
+enabled), and can also reduce
+.BR e2fsck time
+dramatically.  It 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 
@@ -483,14 +536,40 @@
 .\" Check the device for bad blocks before creating the file system
 .\" using the specified test.
 .TP
-.BI \-T " fs-type"
+.BI
+.BI \-t " fs-type"
+Specify the filesystem (i.e., ext2, ext3, ext4, etc., is to be created.
+If this option is not specified mke2fs will pick a default either how
+the command was run (if it was run using a name of the form mkfs.ext2,
+mkfs.ext3, etc.) or via a default as defined by the
+.BR /etc/mke2fs.conf (5)
+file.
+.TP
+.BI \-T " usage-type[,...]"
 Specify how the filesystem is going to be used, so that 
 .B mke2fs 
-can choose optimal filesystem parameters for that use.  The filesystem
-types that are can be supported are defined in the configuration file 
+can choose optimal filesystem parameters for that use.  The usage
+types that are supported are defined in the configuration file
 .BR /etc/mke2fs.conf (5).
-The default configuration file contains definitions for the filesystem
-types: small, floppy, news, largefile, and largefile4.  
+The user may specify one or more usage types
+using a comma separated list.
+.sp
+If this option is is not specified,
+.B mke2fs
+will pick a single default usage type based on the size of the filesystem to
+be created.  If the filesystem size is less than or equal to 3 megabytes,
+.B mke2fs
+will use the filesystem type
+.IR floppy .
+If the filesystem size is greater than 3 but less than or equal to
+512 megabytes,
+.BR mke2fs (8)
+will use the filesystem
+.IR small .
+Otherwise,
+.BR mke2fs (8)
+will use the default filesystem type
+.IR default .
 .TP
 .B \-v
 Verbose execution.
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index cf5e918..a955af1 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -44,6 +44,7 @@
 #endif
 #include <sys/ioctl.h>
 #include <sys/types.h>
+#include <libgen.h>
 
 #include "ext2fs/ext2_fs.h"
 #include "et/com_err.h"
@@ -77,6 +78,7 @@
 int	noaction;
 int	journal_size;
 int	journal_flags;
+int	lazy_itable_init;
 char	*bad_blocks_filename;
 __u32	fs_stride;
 
@@ -86,6 +88,7 @@
 char *mount_dir;
 char *journal_device;
 int sync_kludge;	/* Set using the MKE2FS_SYNC env. option */
+char **fs_types;
 
 profile_t	profile;
 
@@ -97,8 +100,9 @@
 	fprintf(stderr, _("Usage: %s [-c|-l filename] [-b block-size] "
 	"[-f fragment-size]\n\t[-i bytes-per-inode] [-I inode-size] "
 	"[-J journal-options]\n"
-	"\t[-N number-of-inodes] [-m reserved-blocks-percentage] "
-	"[-o creator-os]\n\t[-g blocks-per-group] [-L volume-label] "
+	"\t[-G meta group size] [-N number-of-inodes]\n"
+	"\t[-m reserved-blocks-percentage] [-o creator-os]\n"
+	"\t[-g blocks-per-group] [-L volume-label] "
 	"[-M last-mounted-directory]\n\t[-O feature[,...]] "
 	"[-r fs-revision] [-E extended-option[,...]]\n"
 	"\t[-T fs-type] [-jnqvFSV] device [blocks-count]\n"),
@@ -264,6 +268,7 @@
 				group_bad++;
 				group = ext2fs_group_of_blk(fs, group_block+j);
 				fs->group_desc[group].bg_free_blocks_count++;
+				ext2fs_group_desc_csum_set(fs, group);
 				fs->super->s_free_blocks_count++;
 			}
 		}
@@ -337,76 +342,13 @@
 	fputs(_("done                            \n"), stdout);
 }
 
-
-/*
- * 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.)
- */
-static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num,
-			     struct progress_struct *progress,
-			     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;
-		}
-		if (progress && j > next_update) {
-			next_update += num / 100;
-			progress_update(progress, blk);
-		}
-	}
-	return 0;
-}	
-
-static void write_inode_tables(ext2_filsys fs)
+static void write_inode_tables(ext2_filsys fs, int lazy_flag)
 {
 	errcode_t	retval;
 	blk_t		blk;
 	dgrp_t		i;
-	int		num;
+	int		num, ipb;
 	struct progress_struct progress;
-	int		lazy_flag = 0;
 
 	if (quiet)
 		memset(&progress, 0, sizeof(progress));
@@ -414,25 +356,30 @@
 		progress_init(&progress, _("Writing inode tables: "),
 			      fs->group_desc_count);
 
-	if (EXT2_HAS_COMPAT_FEATURE(fs->super, 
-				    EXT2_FEATURE_COMPAT_LAZY_BG))
-		lazy_flag = 1;
-
 	for (i = 0; i < fs->group_desc_count; i++) {
 		progress_update(&progress, i);
 		
 		blk = fs->group_desc[i].bg_inode_table;
 		num = fs->inode_blocks_per_group;
 
-		if (!(lazy_flag &&
-		      (fs->group_desc[i].bg_flags & EXT2_BG_INODE_UNINIT))) {
-			retval = zero_blocks(fs, blk, num, 0, &blk, &num);
-			if (retval) {
-				fprintf(stderr, _("\nCould not write %d "
-				"blocks in inode table starting at %u: %s\n"),
-					num, blk, error_message(retval));
-				exit(1);
-			}
+		if (lazy_flag) {
+			ipb = fs->blocksize / EXT2_INODE_SIZE(fs->super);
+			num = ((((fs->super->s_inodes_per_group -
+				  fs->group_desc[i].bg_itable_unused) *
+				 EXT2_INODE_SIZE(fs->super)) +
+				EXT2_BLOCK_SIZE(fs->super) - 1) /
+			       EXT2_BLOCK_SIZE(fs->super));
+		} else {
+			/* The kernel doesn't need to zero the itable blocks */
+			fs->group_desc[i].bg_flags |= EXT2_BG_INODE_ZEROED;
+			ext2fs_group_desc_csum_set(fs, i);
+		}
+		retval = ext2fs_zero_blocks(fs, blk, num, &blk, &num);
+		if (retval) {
+			fprintf(stderr, _("\nCould not write %d "
+				  "blocks in inode table starting at %u: %s\n"),
+				num, blk, error_message(retval));
+			exit(1);
 		}
 		if (sync_kludge) {
 			if (sync_kludge == 1)
@@ -441,41 +388,10 @@
 				sync();
 		}
 	}
-	zero_blocks(0, 0, 0, 0, 0, 0);
+	ext2fs_zero_blocks(0, 0, 0, 0, 0);
 	progress_close(&progress);
 }
 
-static void setup_lazy_bg(ext2_filsys fs)
-{
-	dgrp_t i;
-	int blks;
-	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)) {
-		for (i = 0; i < fs->group_desc_count; i++, bg++) {
-			if ((i == 0) ||
-			    (i == fs->group_desc_count-1))
-				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;
-			}
-			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;
-				bg->bg_flags |= EXT2_BG_BLOCK_UNINIT;
-				sb->s_free_blocks_count -= blks;
-			}
-		}
-	}
-}
-
-
 static void create_root_dir(ext2_filsys fs)
 {
 	errcode_t		retval;
@@ -513,11 +429,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 +451,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) {
@@ -551,8 +470,7 @@
 	errcode_t	retval;
 	
 	ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO);
-	fs->group_desc[0].bg_free_inodes_count--;
-	fs->super->s_free_inodes_count--;
+	ext2fs_inode_alloc_stats2(fs, EXT2_BAD_INO, +1, 0);
 	retval = ext2fs_update_bb_inode(fs, bb_list);
 	if (retval) {
 		com_err("ext2fs_update_bb_inode", retval,
@@ -567,12 +485,8 @@
 	ext2_ino_t	i;
 	int		group;
 
-	for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++) {
-		ext2fs_mark_inode_bitmap(fs->inode_map, i);
-		group = ext2fs_group_of_ino(fs, i);
-		fs->group_desc[group].bg_free_inodes_count--;
-		fs->super->s_free_inodes_count--;
-	}
+	for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++)
+		ext2fs_inode_alloc_stats2(fs, i, +1, 0);
 	ext2fs_mark_ib_dirty(fs);
 }
 
@@ -623,8 +537,8 @@
 	struct progress_struct progress;
 	errcode_t		retval;
 	char			*buf;
-	blk_t			blk;
-	int			count;
+	blk_t			blk, err_blk;
+	int			c, count, err_count;
 
 	retval = ext2fs_create_journal_superblock(fs,
 				  fs->super->s_blocks_count, 0, &buf);
@@ -639,15 +553,26 @@
 		progress_init(&progress, _("Zeroing journal device: "),
 			      fs->super->s_blocks_count);
 
-	retval = zero_blocks(fs, 0, fs->super->s_blocks_count,
-			     &progress, &blk, &count);
-	if (retval) {
-		com_err("create_journal_dev", retval,
-			_("while zeroing journal device (block %u, count %d)"),
-			blk, count);
-		exit(1);
+	blk = 0;
+	count = fs->super->s_blocks_count;
+	while (count > 0) {
+		if (count > 1024)
+			c = 1024;
+		else
+			c = count;
+		retval = ext2fs_zero_blocks(fs, blk, c, &err_blk, &err_count);
+		if (retval) {
+			com_err("create_journal_dev", retval,
+				_("while zeroing journal device "
+				  "(block %u, count %d)"),
+				err_blk, err_count);
+			exit(1);
+		}
+		blk += c;
+		count -= c;
+		progress_update(&progress, blk);
 	}
-	zero_blocks(0, 0, 0, 0, 0, 0);
+	ext2fs_zero_blocks(0, 0, 0, 0, 0);
 
 	retval = io_channel_write_blk(fs->io,
 				      fs->super->s_first_data_block+1,
@@ -694,8 +619,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 +665,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 +679,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 +766,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 +
@@ -869,6 +791,11 @@
 			}
 		} else if (!strcmp(token, "test_fs")) {
 			param->s_flags |= EXT2_FLAGS_TEST_FILESYS;
+		} else if (!strcmp(token, "lazy_itable_init")) {
+			if (arg)
+				lazy_itable_init = strtoul(arg, &p, 0);
+			else
+				lazy_itable_init = 1;
 		} else {
 			r_usage++;
 			badopt = token;
@@ -882,9 +809,10 @@
 			"Valid extended options are:\n"
 			"\tstride=<RAID per-disk data chunk in blocks>\n"
 			"\tstripe-width=<RAID stride * data disks in blocks>\n"
-			"\tresize=<resize maximum size in blocks>\n\n"
-			"\ttest_fs\n"),
-			badopt);
+			"\tresize=<resize maximum size in blocks>\n"
+			"\tlazy_itable_init=<0 to disable, 1 to enable>\n"
+			"\ttest_fs\n\n"),
+			badopt ? badopt : "");
 		free(buf);
 		exit(1);
 	}
@@ -902,15 +830,17 @@
 	EXT3_FEATURE_COMPAT_HAS_JOURNAL |
 		EXT2_FEATURE_COMPAT_RESIZE_INODE |
 		EXT2_FEATURE_COMPAT_DIR_INDEX |
-		EXT2_FEATURE_COMPAT_LAZY_BG |
 		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
 };
 
 
@@ -936,6 +866,181 @@
 	}
 }
 
+struct str_list {
+	char **list;
+	int num;
+	int max;
+};
+
+static errcode_t init_list(struct str_list *sl)
+{
+	sl->num = 0;
+	sl->max = 0;
+	sl->list = malloc((sl->max+1) * sizeof(char *));
+	if (!sl->list)
+		return ENOMEM;
+	sl->list[0] = 0;
+	return 0;
+}
+
+static errcode_t push_string(struct str_list *sl, const char *str)
+{
+	char **new_list;
+
+	if (sl->num >= sl->max) {
+		sl->max += 2;
+		new_list = realloc(sl->list, (sl->max+1) * sizeof(char *));
+		if (!new_list)
+			return ENOMEM;
+		sl->list = new_list;
+	}
+	sl->list[sl->num] = malloc(strlen(str)+1);
+	if (sl->list[sl->num] == 0)
+		return ENOMEM;
+	strcpy(sl->list[sl->num], str);
+	sl->num++;
+	sl->list[sl->num] = 0;
+	return 0;
+}
+
+static void print_str_list(char **list)
+{
+	char **cpp;
+
+	for (cpp = list; *cpp; cpp++) {
+		printf("'%s'", *cpp);
+		if (cpp[1])
+			fputs(", ", stdout);
+	}
+	fputc('\n', stdout);
+}
+
+static char **parse_fs_type(const char *fs_type,
+			    const char *usage_types,
+			    struct ext2_super_block *fs_param,
+			    char *progname)
+{
+	const char	*ext_type = 0;
+	char		*parse_str;
+	char		*profile_type = 0;
+	char		*cp, *t;
+	const char	*size_type;
+	struct str_list	list;
+	int		state = 0;
+	unsigned long	meg;
+
+	if (init_list(&list))
+		return 0;
+
+	if (fs_type)
+		ext_type = fs_type;
+	else if (progname) {
+		ext_type = strrchr(progname, '/');
+		if (ext_type)
+			ext_type++;
+		else
+			ext_type = progname;
+
+		if (!strncmp(ext_type, "mkfs.", 5)) {
+			ext_type += 5;
+			if (ext_type[0] == 0)
+				ext_type = 0;
+		} else
+			ext_type = 0;
+	}
+
+	if (!ext_type) {
+		profile_get_string(profile, "defaults", "fs_type", 0,
+				   "ext2", &profile_type);
+		ext_type = profile_type;
+		if (!strcmp(ext_type, "ext2") && (journal_size != 0))
+			ext_type = "ext3";
+	}
+
+	meg = (1024 * 1024) / EXT2_BLOCK_SIZE(fs_param);
+	if (fs_param->s_blocks_count < 3 * meg)
+		size_type = "floppy";
+	else if (fs_param->s_blocks_count < 512 * meg)
+		size_type = "small";
+	else
+		size_type = "default";
+
+	if (!usage_types)
+		usage_types = size_type;
+
+	parse_str = malloc(usage_types ? strlen(usage_types)+1 : 1);
+	if (!parse_str) {
+		free(list.list);
+		return 0;
+	}
+	if (usage_types)
+		strcpy(parse_str, usage_types);
+	else
+		*parse_str = '\0';
+
+	if (ext_type)
+		push_string(&list, ext_type);
+	cp = parse_str;
+	while (1) {
+		t = strchr(cp, ',');
+		if (t)
+			*t = '\0';
+
+		if (*cp)
+			push_string(&list, cp);
+		if (t)
+			cp = t+1;
+		else {
+			cp = "";
+			break;
+		}
+	}
+	free(parse_str);
+	if (profile_type)
+		free(profile_type);
+	return (list.list);
+}
+
+static char *get_string_from_profile(char **fs_types, const char *opt,
+				     const char *def_val)
+{
+	char *ret = 0;
+	char **cpp;
+	int i;
+
+	for (i=0; fs_types[i]; i++);
+	for (i-=1; i >=0 ; i--) {
+		profile_get_string(profile, "fs_types", fs_types[i],
+				   opt, 0, &ret);
+		if (ret)
+			return ret;
+	}
+	profile_get_string(profile, "defaults", opt, 0, def_val, &ret);
+	return (ret);
+}
+
+static int get_int_from_profile(char **fs_types, const char *opt, int def_val)
+{
+	int ret;
+	char **cpp;
+
+	profile_get_integer(profile, "defaults", opt, 0, def_val, &ret);
+	for (cpp = fs_types; *cpp; cpp++)
+		profile_get_integer(profile, "fs_types", *cpp, opt, ret, &ret);
+	return ret;
+}
+
+static int get_bool_from_profile(char **fs_types, const char *opt, int def_val)
+{
+	int ret;
+	char **cpp;
+
+	profile_get_boolean(profile, "defaults", opt, 0, def_val, &ret);
+	for (cpp = fs_types; *cpp; cpp++)
+		profile_get_boolean(profile, "fs_types", *cpp, opt, ret, &ret);
+	return ret;
+}
+
 extern const char *mke2fs_default_profile;
 static const char *default_files[] = { "<default>", 0 };
 
@@ -943,10 +1048,11 @@
 {
 	int		b, c;
 	int		size;
-	char 		*tmp, *tmp2;
+	char 		*tmp, *tmp2, **cpp;
 	int		blocksize = 0;
 	int		inode_ratio = 0;
 	int		inode_size = 0;
+	unsigned long	flex_bg_size = 0;
 	double		reserved_ratio = 5.0;
 	int		sector_size = 0;
 	int		show_version_only = 0;
@@ -955,6 +1061,7 @@
 	char *		oldpath = getenv("PATH");
 	char *		extended_opts = 0;
 	const char *	fs_type = 0;
+	const char *	usage_types = 0;
 	blk_t		dev_size;
 #ifdef __linux__
 	struct 		utsname ut;
@@ -1029,7 +1136,7 @@
 	}
 
 	while ((c = getopt (argc, argv,
-		    "b:cf:g:i:jl:m:no:qr:s:tvE:FI:J:L:M:N:O:R:ST:V")) != EOF) {
+		    "b:cf:g:G:i:jl:m:no:qr:s:t:vE:FI:J:L:M:N:O:R:ST:V")) != EOF) {
 		switch (c) {
 		case 'b':
 			blocksize = strtol(optarg, &tmp, 0);
@@ -1050,7 +1157,6 @@
 						 EXT2_MIN_BLOCK_LOG_SIZE);
 			break;
 		case 'c':	/* Check for bad blocks */
-		case 't':	/* deprecated */
 			cflag++;
 			break;
 		case 'f':
@@ -1080,6 +1186,20 @@
 				exit(1);
 			}
 			break;
+		case 'G':
+			flex_bg_size = strtoul(optarg, &tmp, 0);
+			if (*tmp) {
+				com_err(program_name, 0,
+					_("Illegal number for flex_bg size"));
+				exit(1);
+			}
+			if (flex_bg_size < 2 ||
+			    (flex_bg_size & (flex_bg_size-1)) != 0) {
+				com_err(program_name, 0,
+					_("flex_bg size must be a power of 2"));
+				exit(1);
+			}
+			break;
 		case 'i':
 			inode_ratio = strtoul(optarg, &tmp, 0);
 			if (inode_ratio < EXT2_MIN_BLOCK_SIZE ||
@@ -1176,9 +1296,12 @@
 		case 'S':
 			super_only = 1;
 			break;
-		case 'T':
+		case 't':
 			fs_type = optarg;
 			break;
+		case 'T':
+			usage_types = optarg;
+			break;
 		case 'V':
 			/* Print version number and exit */
 			show_version_only++;
@@ -1320,6 +1443,16 @@
 		proceed_question();
 	}
 
+	fs_types = parse_fs_type(fs_type, usage_types, &fs_param, argv[0]);
+	if (!fs_types) {
+		fprintf(stderr, _("Failed to parse fs types list\n"));
+		exit(1);
+	}
+	if (verbose) {
+		fputs("Fs_types for mke2fs.conf resolution: ", stdout);
+		print_str_list(fs_types);
+	}
+
 	if (!fs_type) {
 		int megs = (__u64)fs_param.s_blocks_count *
 			(EXT2_BLOCK_SIZE(&fs_param) / 1024) / 1024;
@@ -1337,29 +1470,29 @@
 
 	/* Figure out what features should be enabled */
 
-	tmp = tmp2 = NULL;
+	tmp = NULL;
 	if (fs_param.s_rev_level != EXT2_GOOD_OLD_REV) {
-		profile_get_string(profile, "defaults", "base_features", 0,
-				   "sparse_super,filetype,resize_inode,dir_index",
-				   &tmp);
-		profile_get_string(profile, "fs_types", fs_type, 
-				   "base_features", tmp, &tmp2);
-		edit_feature(tmp2, &fs_param.s_feature_compat);
+		tmp = get_string_from_profile(fs_types, "base_features",
+		      "sparse_super,filetype,resize_inode,dir_index");
+		edit_feature(tmp, &fs_param.s_feature_compat);
 		free(tmp);
-		free(tmp2);
 
-		tmp = tmp2 = NULL;
-		profile_get_string(profile, "defaults", "default_features", 0,
-				   "", &tmp);
-		profile_get_string(profile, "fs_types", fs_type, 
-				   "default_features", tmp, &tmp2);
+		for (cpp = fs_types; *cpp; cpp++) {
+			tmp = NULL;
+			profile_get_string(profile, "fs_types", *cpp,
+					   "features", "", &tmp);
+			if (tmp && *tmp)
+				edit_feature(tmp, &fs_param.s_feature_compat);
+			if (tmp)
+				free(tmp);
+		}
+		tmp = get_string_from_profile(fs_types, "default_features",
+					      "");
 	}
-	edit_feature(fs_features ? fs_features : tmp2, 
+	edit_feature(fs_features ? fs_features : tmp,
 		     &fs_param.s_feature_compat);
 	if (tmp)
 		free(tmp);
-	if (tmp2)
-		free(tmp2);
 
 	if (r_opt == EXT2_GOOD_OLD_REV && 
 	    (fs_param.s_feature_compat || fs_param.s_feature_incompat ||
@@ -1426,10 +1559,7 @@
 		sector_size = atoi(tmp);
 	
 	if (blocksize <= 0) {
-		profile_get_integer(profile, "defaults", "blocksize", 0,
-				    4096, &use_bsize);
-		profile_get_integer(profile, "fs_types", fs_type, 
-				    "blocksize", use_bsize, &use_bsize);
+		use_bsize = get_int_from_profile(fs_types, "blocksize", 4096);
 
 		if (use_bsize == -1) {
 			use_bsize = sys_page_size;
@@ -1446,12 +1576,8 @@
 	}
 
 	if (inode_ratio == 0) {
-		profile_get_integer(profile, "defaults", "inode_ratio", 0,
-				    8192, &inode_ratio);
-		profile_get_integer(profile, "fs_types", fs_type, 
-				    "inode_ratio", inode_ratio, 
-				    &inode_ratio);
-
+		inode_ratio = get_int_from_profile(fs_types, "inode_ratio",
+						   8192);
 		if (inode_ratio < blocksize)
 			inode_ratio = blocksize;
 	}
@@ -1460,7 +1586,20 @@
 		int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
 
 	blocksize = EXT2_BLOCK_SIZE(&fs_param);
+
+	lazy_itable_init = get_bool_from_profile(fs_types, 
+						 "lazy_itable_init", 0);
 	
+	/* Get options from profile */
+	for (cpp = fs_types; *cpp; cpp++) {
+		tmp = NULL;
+		profile_get_string(profile, "fs_types", *cpp, "options", "", &tmp);
+			if (tmp && *tmp)
+				parse_extended_opts(&fs_param, tmp);
+			if (tmp)
+				free(tmp);
+	}
+
 	if (extended_opts)
 		parse_extended_opts(&fs_param, extended_opts);
 
@@ -1484,25 +1623,21 @@
 		}
 	}
 
-	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);
-		profile_get_integer(profile, "fs_types", fs_type,
-				    "inode_size", inode_size,
-				    &inode_size);
+	if (inode_size == 0)
+		inode_size = get_int_from_profile(fs_types, "inode_size", 0);
+	if (!flex_bg_size && (fs_param.s_feature_incompat &
+			      EXT4_FEATURE_INCOMPAT_FLEX_BG))
+		flex_bg_size = get_int_from_profile(fs_types,
+						    "flex_bg_size", 16);
+	if (flex_bg_size) {
+		if (!(fs_param.s_feature_incompat &
+		      EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+			com_err(program_name, 0,
+				_("Flex_bg feature not enabled, so "
+				  "flex_bg size may not be specified"));
+			exit(1);
+		}
+		fs_param.s_log_groups_per_flex = int_log2(flex_bg_size);
 	}
 
 	if (inode_size && fs_param.s_rev_level >= EXT2_DYNAMIC_REV) {
@@ -1515,10 +1650,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;
 	}
 
@@ -1566,15 +1697,112 @@
 						fs_param.s_blocks_count);
 }
 
+static int should_do_undo(const char *name)
+{
+	errcode_t retval;
+	io_channel channel;
+	__u16	s_magic;
+	struct ext2_super_block super;
+	io_manager manager = unix_io_manager;
+	int csum_flag, force_undo;
+
+	csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(&fs_param,
+					       EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+	force_undo = get_int_from_profile(fs_types, "force_undo", 0);
+	if (!force_undo && (!csum_flag || !lazy_itable_init))
+		return 0;
+
+	retval = manager->open(name, IO_FLAG_EXCLUSIVE,  &channel);
+	if (retval) {
+		/*
+		 * We don't handle error cases instead we
+		 * declare that the file system doesn't exist
+		 * and let the rest of mke2fs take care of
+		 * error
+		 */
+		retval = 0;
+		goto open_err_out;
+	}
+
+	io_channel_set_blksize(channel, SUPERBLOCK_OFFSET);
+	retval = io_channel_read_blk(channel, 1, -SUPERBLOCK_SIZE, &super);
+	if (retval) {
+		retval = 0;
+		goto err_out;
+	}
+
+#if defined(WORDS_BIGENDIAN)
+	s_magic = ext2fs_swab16(super.s_magic);
+#else
+	s_magic = super.s_magic;
+#endif
+
+	if (s_magic == EXT2_SUPER_MAGIC)
+		retval = 1;
+
+err_out:
+	io_channel_close(channel);
+
+open_err_out:
+
+	return retval;
+}
+
+static int mke2fs_setup_tdb(const char *name, io_manager *io_ptr)
+{
+	errcode_t retval = 0;
+	char *tdb_dir, tdb_file[PATH_MAX];
+	char *device_name, *tmp_name;
+
+	/*
+	 * Configuration via a conf file would be
+	 * nice
+	 */
+	tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
+	if (!tdb_dir)
+		profile_get_string(profile, "defaults",
+				   "undo_dir", 0, "/var/lib/e2fsprogs",
+				   &tdb_dir);
+
+	if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
+	    access(tdb_dir, W_OK))
+		return 0;
+
+	tmp_name = strdup(name);
+	device_name = basename(tmp_name);
+	sprintf(tdb_file, "%s/mke2fs-%s.e2undo", tdb_dir, device_name);
+
+	if (!access(tdb_file, F_OK)) {
+		if (unlink(tdb_file) < 0) {
+			retval = errno;
+			com_err(program_name, retval,
+				_("while trying to delete %s"),
+				tdb_file);
+			return retval;
+		}
+	}
+
+	set_undo_io_backing_manager(*io_ptr);
+	*io_ptr = undo_io_manager;
+	set_undo_io_backup_file(tdb_file);
+	printf(_("Overwriting existing filesystem; this can be undone "
+		 "using the command:\n"
+		 "    e2undo %s %s\n\n"), tdb_file, name);
+err_out:
+	free(tmp_name);
+	return retval;
+}
+
 int main (int argc, char *argv[])
 {
 	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;
+	char		tdb_string[40];
 
 #ifdef ENABLE_NLS
 	setlocale(LC_MESSAGES, "");
@@ -1591,6 +1819,12 @@
 	io_ptr = unix_io_manager;
 #endif
 
+	if (should_do_undo(device_name)) {
+		retval = mke2fs_setup_tdb(device_name, &io_ptr);
+		if (retval)
+			exit(1);
+	}
+
 	/*
 	 * Initialize the superblock....
 	 */
@@ -1600,6 +1834,9 @@
 		com_err(device_name, retval, _("while setting up superblock"));
 		exit(1);
 	}
+	sprintf(tdb_string, "tdb_data_size=%d", fs->blocksize <= 4096 ?
+		32768 : fs->blocksize * 8);
+	io_channel_set_options(fs->io, tdb_string);
 
 	if (fs_param.s_flags & EXT2_FLAGS_TEST_FILESYS)
 		fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS;
@@ -1714,16 +1951,15 @@
 		if (start > rsv)
 			start -= rsv;
 		if (start > 0)
-			retval = zero_blocks(fs, start, blocks - start,
-					     NULL, &ret_blk, NULL);
+			retval = ext2fs_zero_blocks(fs, start, blocks - start,
+						    &ret_blk, NULL);
 
 		if (retval) {
 			com_err(program_name, retval,
 				_("while zeroing block %u at end of filesystem"),
 				ret_blk);
 		}
-		setup_lazy_bg(fs);
-		write_inode_tables(fs);
+		write_inode_tables(fs, lazy_itable_init);
 		create_root_dir(fs);
 		create_lost_and_found(fs);
 		reserve_inodes(fs);
@@ -1782,7 +2018,7 @@
 			goto no_journal;
 		}
 		if (!quiet) {
-			printf(_("Creating journal (%d blocks): "),
+			printf(_("Creating journal (%u blocks): "),
 			       journal_blocks);
 			fflush(stdout);
 		}
@@ -1814,5 +2050,6 @@
 	val = ext2fs_close(fs);
 	remove_error_table(&et_ext2_error_table);
 	remove_error_table(&et_prof_error_table);
+	profile_release(profile);
 	return (retval || val) ? 1 : 0;
 }
diff --git a/misc/mke2fs.conf b/misc/mke2fs.conf
index d67593a..ea6d7bf 100644
--- a/misc/mke2fs.conf
+++ b/misc/mke2fs.conf
@@ -5,6 +5,18 @@
 	inode_ratio = 16384
 
 [fs_types]
+	ext3 = {
+		features = has_journal
+	}
+	ext4 = {
+		features = has_journal,extents,flex_bg
+		inode_size = 256
+	}
+	ext4dev = {
+		features = has_journal,extents,flex_bg
+		inode_size = 256
+		options = test_fs=1
+	}
 	small = {
 		blocksize = 1024
 		inode_size = 128
@@ -20,7 +32,9 @@
 	}
 	largefile = {
 		inode_ratio = 1048576
+		blocksize = -1
 	}
 	largefile4 = {
 		inode_ratio = 4194304
+		blocksize = -1
 	}
diff --git a/misc/mke2fs.conf.5.in b/misc/mke2fs.conf.5.in
index 6089031..04bffc5 100644
--- a/misc/mke2fs.conf.5.in
+++ b/misc/mke2fs.conf.5.in
@@ -79,20 +79,6 @@
 .B -T
 option to
 .BR mke2fs (8).
-If no filesystem type is specified, 
-.BR mke2fs (8)
-will use the filesystem type 
-.I floppy
-if the filesystem size is less than or equal to 3 megabytes.  
-If the filesystem size is greater than 3 but less than or equal to 
-512 megabytes, 
-.BR mke2fs (8)
-will use the filesystem
-.IR small .
-Otherwise, 
-.BR mke2fs (8)
-will use the default filesystem type
-.IR default .
 .SH THE [defaults] STANZA
 The following relations are defined in the 
 .I [defaults]
@@ -102,7 +88,7 @@
 This relation specifies the filesystems features which are enabled in
 newly created filesystems.  It may be overridden by the
 .I base_features
-relation found in the filesystem-type-specific subsection of
+relation found in the filesystem or usage type subsection of
 the
 .I [fs_types] 
 stanza.
@@ -113,7 +99,7 @@
 .I base_features
 relation.  It may be overridden by the filesystem-specific 
 .I default_features
-in the filesystem-type subsection of
+in the filesystem or usage type subsection of
 .IR [fs_types] ,
 and by the 
 .B -O
@@ -121,6 +107,30 @@
 to 
 .BR mke2fs (8).
 .TP
+.I force_undo
+This relation, if set to a boolean value of true, forces
+.B mke2fs
+to always try to create an undo file, even if the undo file might be
+huge and it might extend the time to create the filesystem image
+because the inode table isn't being initialized lazily.
+.TP
+.I fs_type
+This relation specifies the default filesystem type if the user does not
+specify it via the
+.B \-t
+option, or if
+.B mke2fs
+is not started using a program name of the form
+.BI mkfs. fs-type\fR.
+If both the user and the
+.B mke2fs.conf
+file does not specify a default filesystem type, mke2fs will use a
+default filesystem type of
+.IR ext3
+if a journal was requested via a command-line option, or
+.I ext2
+if not.
+.TP
 .I blocksize
 This relation specifies the default blocksize if the user does not
 specify a blocksize on the command line, and the filesystem-type
@@ -137,19 +147,69 @@
 specify one on the command line, and the filesystem-type
 specific section of the configuration file does not specify a default
 inode size.
+.TP
+.I undo_dir
+This relation specifies the directory where the undo file should be
+stored.  It can be overriden via the
+.B E2FSPROGS_UNDO_DIR
+environemnt variable.  If the directory location is set to the value
+.IR none ,
+.B mke2fs
+will not create an undo file.
 .SH THE [fs_types] STANZA
 Each tag in the
 .I [fs_types] 
-stanza names a filesystem type which can be specified via the 
-.B -T
-option to
-.BR mke2fs (8).
-The value of the tag is a subsection where the relations in that
-subsection define the defaults for that filesystem type. For
-example:
+stanza names a filesystem type or usage type which can be specified via the
+.B \-t
+or
+.B \-T
+options to
+.BR mke2fs (8),
+respectively.
 .P
+The
+.B mke2fs
+program constructs a list of fs_types by concatenating the filesystem
+type (i.e., ext2, ext3, etc.) with the usage type list.  For most
+configuration options,
+.B mke2fs
+will look for a subsection in the
+.I [fs_types]
+stanza corresponding with each entry in the constructed list, with later
+entries overriding earlier filesystem or usage types.
+For
+example, consider the following
+.B mke2fs.conf
+fragment:
+.P
+[defaults]
+.br
+	base_features = sparse_super,filetype,resize_inode,dir_index
+.br
+	blocksize = 4096
+.br
+	inode_size = 256
+.br
+	inode_ratio = 16384
+.br
+
+.br
 [fs_types]
 .br
+	ext3 = {
+.br
+		features = has_journal
+.br
+	}
+.br
+	ext4 = {
+.br
+		features = extents,flex_bg
+.br
+		inode_size = 256
+.br
+	}
+.br
 	small = {
 .br
 		blocksize = 1024
@@ -160,22 +220,76 @@
 .br
 	floppy = {
 .br
+		features = ^resize_inode
+.br
 		blocksize = 1024
 .br
+		inode_size = 128
+.br
 	}
 .P
+If mke2fs started with a program name of
+.BR mke2fs.ext4 ,
+then the filesystem type of ext4 will be used.  If the filesystem is
+smaller than 3 megabytes, and no usage type is specified, then
+.B mke2fs
+will use a default
+usage type of
+.IR floppy .
+This results in an fs_types list of "ext4, floppy".   Both the ext4
+subsection and the floppy subsection define an
+.I inode_size
+relation, but since the later entries in the fs_types list supercede
+earlier ones, the configuration parameter for fs_types.floppy.inode_size
+will be used, so the filesystem  will have an inode size of 128.
+.P
+The exception to this resolution is the
+.I features
+tag, which is specifies a set of changes to the features used by the
+filesystem, and which is cumulative.  So in the above example, first
+the configuration relation defaults.base_features would enable an
+initial feature set with the sparse_super, filetype, resize_inode, and
+dir_index features enabled.  Then configuration relation
+fs_types.ext4.features would enable the extents and flex_bg
+features, and finally the configuration relation
+fs_types.floppy.features would remove
+the resize_inode feature, resulting in a filesystem feature set
+consisting of the sparse_super, filetype, resize_inode, dir_index,
+extents_and flex_bg features.
+.P
 For each filesystem type, the following tags may be used in that 
 fs_type's subsection:
 .TP
 .I base_features
-This relation specifies the features which are enabled for this
-filesystem type.
+This relation specifies the features which are initially enabled for this
+filesystem type.  Only one
+.I base_features
+will be used, so if there are multiple entries in the fs_types list
+whose subsections define the
+.I base_features
+relation, only the last will be used by
+.BR mke2fs (8).
+.TP
+.I features
+This relation specifies a comma-separated list of features edit
+requests which modify the feature set
+used by the newly constructed filesystem.  The syntax is the same as the
+.B -O
+command-line option to
+.BR mke2fs (8);
+that is, a feature can be prefixed by a caret ('^') symbol to disable
+a named feature.  Each
+.I feature
+relation specified in the fs_types list will be applied in the order
+found in the fs_types list.
 .TP
 .I default_features
 This relation specifies set of features which should be enabled or 
-disabled to the features listed in the
+disabled after applying the features listed in the
 .I base_features
-relation.  It may be overridden by the 
+and
+.I features
+relations.  It may be overridden by the
 .B -O
 command-line option to
 .BR mke2fs (8).
@@ -184,6 +298,18 @@
 This relation specifies the default blocksize if the user does not
 specify a blocksize on the command line.
 .TP
+.I lazy_itable_init
+This relation is a boolean which specifies whether the inode table should 
+be lazily initialized.  It only has meaning if the uninit_bg feature is
+enabled.  If lazy_itable_init is true and the uninit_bg feature is
+enabled,  the inode table will
+not fully initialized by 
+.BR mke2fs (8).
+This speeds up filesystem
+initialization noitceably, but it requires the kernel to finish
+initializing the filesystem in the background when the filesystem is
+first mounted.
+.TP
 .I inode_ratio
 This relation specifies the default inode ratio if the user does not
 specify one on the command line.
@@ -191,6 +317,23 @@
 .I inode_size
 This relation specifies the default inode size if the user does not
 specify one on the command line.
+.TP
+.I flex_bg_size
+This relation specifies the number of block goups that will be packed
+together to create one large virtual block group on an ext4 filesystem.
+This improves meta-data locality and performance on meta-data heavy
+workloads.  The number of goups must be a power of 2 and may only be
+specified if the flex_bg filesystem feature is enabled.
+.I options
+This relation specifies additional extended options which should be
+treated by
+.BR mke2fs (8)
+as if they were prepended to the argument of the
+.B -E
+option.  This can be used to configure the default extended options used
+by
+.BR mke2fs (8)
+on a per-filesystem type basis.
 .SH FILES
 .TP
 .I /etc/mke2fs.conf
diff --git a/misc/tune2fs.8.in b/misc/tune2fs.8.in
index 260e76f..9f8f23a 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_bg
+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_bg ,
 .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_bg
+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..527991a 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -42,6 +42,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <libgen.h>
 
 #include "ext2fs/ext2_fs.h"
 #include "ext2fs/ext2fs.h"
@@ -71,6 +72,7 @@
 char * io_options;
 static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
 static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
+static int I_flag;
 static time_t last_check_time;
 static int print_label;
 static int max_mount_count, mount_count, mount_flags;
@@ -84,10 +86,20 @@
 static int stride, stripe_width;
 static int stride_set, stripe_width_set;
 static char *extended_cmd;
+static unsigned long int new_inode_size;
 
 int journal_size, journal_flags;
 char *journal_device;
 
+static struct list_head blk_move_list;
+
+struct blk_move {
+	struct list_head list;
+	blk_t old_loc;
+	blk_t new_loc;
+};
+
+
 static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
 
 void do_findfs(int argc, char **argv);
@@ -104,7 +116,7 @@
 		  "[-L volume_label]\n"
 		  "\t[-M last_mounted_dir] [-O [^]feature[,...]]\n"
 		  "\t[-E extended-option[,...]] [-T last_check_time] "
-		  "[-U UUID] device\n"), program_name);
+		  "[-U UUID]\n\t[ -I new_inode_size ] device\n"), program_name);
 	exit (1);
 }
 
@@ -113,9 +125,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 +140,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 +259,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 +286,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 +330,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 +408,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 +424,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,
@@ -554,7 +583,7 @@
 	open_flag = EXT2_FLAG_SOFTSUPP_FEATURES;
 
 	printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
-	while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:E:J:L:M:O:T:U:")) != EOF)
+	while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:")) != EOF)
 		switch (c)
 		{
 			case 'c':
@@ -755,6 +784,25 @@
 				open_flag = EXT2_FLAG_RW |
 					EXT2_FLAG_JOURNAL_DEV_OK;
 				break;
+			case 'I':
+				new_inode_size = strtoul (optarg, &tmp, 0);
+				if (*tmp) {
+					com_err (program_name, 0,
+						_("bad inode size - %s"),
+							optarg);
+					usage();
+				}
+				if (!((new_inode_size &
+						(new_inode_size - 1)) == 0)) {
+					com_err (program_name, 0,
+						_("Inode size must be a "
+						"power of two- %s"),
+							optarg);
+					usage();
+				}
+				open_flag = EXT2_FLAG_RW;
+				I_flag = 1;
+				break;
 			default:
 				usage();
 		}
@@ -880,6 +928,465 @@
 	free(buf);
 }	
 
+static int get_move_bitmap(ext2_filsys fs, int new_ino_blks_per_grp,
+					ext2fs_block_bitmap bmap)
+{
+	dgrp_t i;
+	blk_t j, needed_blocks = 0;
+	blk_t start_blk, end_blk;
+
+	for (i = 0; i < fs->group_desc_count; i++) {
+
+		start_blk = fs->group_desc[i].bg_inode_table +
+					fs->inode_blocks_per_group;
+
+		end_blk = fs->group_desc[i].bg_inode_table +
+					new_ino_blks_per_grp;
+
+		for (j = start_blk; j < end_blk; j++) {
+
+			if (ext2fs_test_block_bitmap(fs->block_map, j)) {
+				/* FIXME!!
+				 * What happens if the block is marked
+				 * as a bad block
+				 */
+				ext2fs_mark_block_bitmap(bmap, j);
+				needed_blocks++;
+			} else {
+				/*
+				 * We are going to use this block for
+				 * inode table. So mark them used.
+				 */
+				ext2fs_mark_block_bitmap(fs->block_map, j);
+			}
+		}
+	}
+
+	if (needed_blocks > fs->super->s_free_blocks_count ) {
+		return ENOSPC;
+	}
+
+	return 0;
+}
+
+static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
+{
+	char *buf;
+	errcode_t retval;
+	blk_t blk, new_blk;
+	struct blk_move *bmv;
+
+
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return retval;
+
+	for (blk = fs->super->s_first_data_block;
+			blk < fs->super->s_blocks_count; blk++) {
+
+		if (!ext2fs_test_block_bitmap(bmap, blk))
+			continue;
+
+		retval = ext2fs_new_block(fs, blk, NULL, &new_blk);
+		if (retval)
+			goto err_out;
+
+		/* Mark this block as allocated */
+		ext2fs_mark_block_bitmap(fs->block_map, new_blk);
+
+		/* Add it to block move list */
+		retval = ext2fs_get_mem(sizeof(struct blk_move), &bmv);
+		if (retval)
+			goto err_out;
+
+		bmv->old_loc = blk;
+		bmv->new_loc = new_blk;
+
+		list_add(&(bmv->list), &blk_move_list);
+
+		retval = io_channel_read_blk(fs->io, blk, 1, buf);
+		if (retval)
+			goto err_out;
+
+		retval = io_channel_write_blk(fs->io, new_blk, 1, buf);
+		if (retval)
+			goto err_out;
+	}
+
+err_out:
+	ext2fs_free_mem(&buf);
+	return retval;
+}
+
+static blk_t transalate_block(blk_t blk)
+{
+	struct list_head *entry;
+	struct blk_move *bmv;
+
+	list_for_each(entry, &blk_move_list) {
+
+		bmv = list_entry(entry, struct blk_move, list);
+		if (bmv->old_loc == blk)
+			return bmv->new_loc;
+	}
+
+	return 0;
+}
+
+static int process_block(ext2_filsys fs, blk_t	*block_nr,
+			 e2_blkcnt_t blockcnt,
+			 blk_t ref_block EXT2FS_ATTR((unused)),
+			 int ref_offset EXT2FS_ATTR((unused)),
+			 void *priv_data EXT2FS_ATTR((unused)))
+{
+	int ret = 0;
+	blk_t new_blk;
+
+
+	new_blk = transalate_block(*block_nr);
+	if (new_blk) {
+		*block_nr = new_blk;
+		/*
+		 * This will force the ext2fs_write_inode in the iterator
+		 */
+		ret |= BLOCK_CHANGED;
+	}
+
+	return ret;
+}
+
+static int inode_scan_and_fix(ext2_filsys fs)
+{
+	errcode_t retval = 0;
+	ext2_ino_t ino;
+	blk_t blk;
+	char *block_buf = 0;
+	struct ext2_inode inode;
+	ext2_inode_scan	scan = NULL;
+
+	retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_open_inode_scan(fs, 0, &scan);
+	if (retval)
+		goto err_out;
+
+	while (1) {
+
+		retval = ext2fs_get_next_inode(scan, &ino, &inode);
+		if (retval)
+			goto err_out;
+
+		if (!ino)
+			break;
+
+		if (inode.i_links_count == 0)
+			continue; /* inode not in use */
+
+		/* FIXME!!
+		 * If we end up modifying the journal inode
+		 * the sb->s_jnl_blocks will differ. But a
+		 * subsequent e2fsck fixes that.
+		 * Do we need to fix this ??
+		 */
+
+		if (inode.i_file_acl) {
+
+			blk = transalate_block(inode.i_file_acl);
+			if (!blk)
+				continue;
+
+			inode.i_file_acl = blk;
+
+			/*
+			 * Write the inode to disk so that inode table
+			 * resizing can work
+			 */
+			retval = ext2fs_write_inode(fs, ino, &inode);
+			if (retval)
+				goto err_out;
+		}
+
+		if (!ext2fs_inode_has_valid_blocks(&inode))
+			continue;
+
+		retval = ext2fs_block_iterate2(fs, ino, 0,
+						block_buf, process_block,
+						0);
+		if (retval)
+			goto err_out;
+
+	}
+
+err_out:
+	ext2fs_free_mem(&block_buf);
+
+	return retval;
+
+}
+
+static int expand_inode_table(ext2_filsys fs, unsigned long int new_inode_size)
+{
+	dgrp_t i;
+	blk_t blk;
+	errcode_t retval;
+	int new_ino_blks_per_grp, j;
+	char *old_itable = NULL, *new_itable = NULL;
+	char *tmp_old_itable = NULL, *tmp_new_itable = NULL;
+	unsigned long int old_inode_size;
+	int old_itable_size, new_itable_size;
+
+	old_itable_size = fs->inode_blocks_per_group * fs->blocksize;
+	old_inode_size = EXT2_INODE_SIZE(fs->super);
+
+	new_ino_blks_per_grp = ext2fs_div_ceil(
+					EXT2_INODES_PER_GROUP(fs->super) *
+					new_inode_size,
+					fs->blocksize);
+
+	new_itable_size = new_ino_blks_per_grp * fs->blocksize;
+
+	retval = ext2fs_get_mem(old_itable_size, &old_itable);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_get_mem(new_itable_size, &new_itable);
+	if (retval)
+		goto err_out;
+
+	tmp_old_itable = old_itable;
+	tmp_new_itable = new_itable;
+
+	for (i = 0; i < fs->group_desc_count; i++) {
+
+		blk = fs->group_desc[i].bg_inode_table;
+		retval = io_channel_read_blk(fs->io, blk,
+				fs->inode_blocks_per_group, old_itable);
+		if (retval)
+			goto err_out;
+
+		for (j = 0; j < EXT2_INODES_PER_GROUP(fs->super); j++) {
+
+			memcpy(new_itable, old_itable, old_inode_size);
+
+			memset(new_itable+old_inode_size, 0,
+					new_inode_size - old_inode_size);
+
+			new_itable +=  new_inode_size;
+			old_itable += old_inode_size;
+		}
+
+		/* reset the pointer */
+		old_itable = tmp_old_itable;
+		new_itable = tmp_new_itable;
+
+		retval = io_channel_write_blk(fs->io, blk,
+					new_ino_blks_per_grp, new_itable);
+		if (retval)
+			goto err_out;
+	}
+
+	/* Update the meta data */
+	fs->inode_blocks_per_group = new_ino_blks_per_grp;
+	fs->super->s_inode_size = new_inode_size;
+
+err_out:
+	if (old_itable)
+		ext2fs_free_mem(&old_itable);
+
+	if (new_itable)
+		ext2fs_free_mem(&new_itable);
+
+	return retval;
+
+}
+
+static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
+{
+	blk_t		blk;
+	ext2_ino_t	ino;
+	unsigned int	group = 0;
+	unsigned int	count = 0;
+	int		total_free = 0;
+	int		group_free = 0;
+
+	/*
+	 * First calculate the block statistics
+	 */
+	for (blk = fs->super->s_first_data_block;
+	     blk < fs->super->s_blocks_count; blk++) {
+		if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
+			group_free++;
+			total_free++;
+		}
+		count++;
+		if ((count == fs->super->s_blocks_per_group) ||
+		    (blk == fs->super->s_blocks_count-1)) {
+			fs->group_desc[group++].bg_free_blocks_count =
+				group_free;
+			count = 0;
+			group_free = 0;
+		}
+	}
+	fs->super->s_free_blocks_count = total_free;
+
+	/*
+	 * Next, calculate the inode statistics
+	 */
+	group_free = 0;
+	total_free = 0;
+	count = 0;
+	group = 0;
+
+	/* Protect loop from wrap-around if s_inodes_count maxed */
+	for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
+		if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
+			group_free++;
+			total_free++;
+		}
+		count++;
+		if ((count == fs->super->s_inodes_per_group) ||
+		    (ino == fs->super->s_inodes_count)) {
+			fs->group_desc[group++].bg_free_inodes_count =
+				group_free;
+			count = 0;
+			group_free = 0;
+		}
+	}
+	fs->super->s_free_inodes_count = total_free;
+	ext2fs_mark_super_dirty(fs);
+	return 0;
+}
+
+#define list_for_each_safe(pos, pnext, head) \
+	for (pos = (head)->next, pnext = pos->next; pos != (head); \
+	     pos = pnext, pnext = pos->next)
+
+static void free_blk_move_list()
+{
+	struct list_head *entry, *tmp;
+	struct blk_move *bmv;
+
+	list_for_each_safe(entry, tmp, &blk_move_list) {
+
+		bmv = list_entry(entry, struct blk_move, list);
+		list_del(entry);
+		ext2fs_free_mem(&bmv);
+	}
+
+	return ;
+}
+static int resize_inode(ext2_filsys fs, unsigned long int new_inode_size)
+{
+	errcode_t retval;
+	int new_ino_blks_per_grp;
+	ext2fs_block_bitmap bmap;
+
+	if (new_inode_size <= EXT2_INODE_SIZE(fs->super)) {
+		fprintf(stderr, _("New inode size too small\n"));
+		return EXT2_ET_INVALID_ARGUMENT;
+	}
+
+	ext2fs_read_inode_bitmap(fs);
+	ext2fs_read_block_bitmap(fs);
+	INIT_LIST_HEAD(&blk_move_list);
+
+
+	new_ino_blks_per_grp = ext2fs_div_ceil(
+					EXT2_INODES_PER_GROUP(fs->super)*
+					new_inode_size,
+					fs->blocksize);
+
+	/* We may change the file system.
+	 * Mark the file system as invalid so that
+	 * the user is prompted to run fsck.
+	 */
+	fs->super->s_state &= ~EXT2_VALID_FS;
+
+	retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
+						&bmap);
+	if (retval)
+		return retval;
+
+	retval = get_move_bitmap(fs, new_ino_blks_per_grp, bmap);
+	if (retval)
+		goto err_out;
+
+	retval = move_block(fs, bmap);
+	if (retval)
+		goto err_out;
+
+	retval = inode_scan_and_fix(fs);
+	if (retval)
+		goto err_out;
+
+	retval = expand_inode_table(fs, new_inode_size);
+	if (retval)
+		goto err_out;
+
+	ext2fs_calculate_summary_stats(fs);
+
+	fs->super->s_state |= EXT2_VALID_FS;
+	/* mark super block and block bitmap as dirty */
+	ext2fs_mark_super_dirty(fs);
+	ext2fs_mark_bb_dirty(fs);
+
+err_out:
+	free_blk_move_list();
+	ext2fs_free_block_bitmap(bmap);
+
+	return retval;
+}
+
+static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
+{
+	errcode_t retval = 0;
+	char *tdb_dir, tdb_file[PATH_MAX];
+	char *device_name, *tmp_name;
+
+#if 0 /* FIXME!! */
+	/*
+	 * Configuration via a conf file would be
+	 * nice
+	 */
+	profile_get_string(profile, "scratch_files",
+					"directory", 0, 0,
+					&tdb_dir);
+#endif
+	tmp_name = strdup(name);
+	device_name = basename(tmp_name);
+
+	tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
+	if (!tdb_dir)
+		tdb_dir="/var/lib/e2fsprogs";
+
+	if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
+	    access(tdb_dir, W_OK))
+		return 0;
+
+	sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, device_name);
+
+	if (!access(tdb_file, F_OK)) {
+		if (unlink(tdb_file) < 0) {
+			retval = errno;
+			com_err(program_name, retval,
+				_("while trying to delete %s"),
+				tdb_file);
+			return retval;
+		}
+	}
+
+	set_undo_io_backing_manager(*io_ptr);
+	*io_ptr = undo_io_manager;
+	set_undo_io_backup_file(tdb_file);
+	printf(_("To undo the tune2fs operations please run "
+		 "the command\n    undoe2fs %s %s\n\n"),
+		 tdb_file, name);
+err_out:
+	free(tmp_name);
+	return retval;
+}
 
 int main (int argc, char ** argv)
 {
@@ -911,6 +1418,17 @@
 #else
 	io_ptr = unix_io_manager;
 #endif
+
+	if (I_flag) {
+		/*
+		 * If inode resize is requested use the
+		 * Undo I/O manager
+		 */
+		retval = tune2fs_setup_tdb(device_name, &io_ptr);
+		if (retval)
+			exit(1);
+	}
+
 	retval = ext2fs_open2(device_name, io_options, open_flag, 
 			      0, 0, io_ptr, &fs);
         if (retval) {
@@ -1059,6 +1577,27 @@
 		}
 		ext2fs_mark_super_dirty(fs);
 	}
+	if (I_flag) {
+		if (mount_flags & EXT2_MF_MOUNTED) {
+			fputs(_("The inode size may only be "
+				"changed when the filesystem is "
+				"unmounted.\n"), stderr);
+			exit(1);
+		}
+		/*
+		 * We want to update group descriptor also
+		 * with the new free inode count
+		 */
+		fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+		if (resize_inode(fs, new_inode_size)) {
+			fputs(_("Error in resizing the inode size.\n"
+				"Run undoe2fs to undo the "
+				"file system changes. \n"), stderr);
+		} else {
+			printf (_("Setting inode size  %d\n"),
+							new_inode_size);
+		}
+	}
 
 	if (l_flag)
 		list_super (sb);
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..8b90e96 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_bg");
+		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..5fb3501 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);
 
@@ -1530,7 +1536,7 @@
 	retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
 	if (retval) goto errout;
 
-	inode.i_blocks = fs->blocksize/512;
+	ext2fs_iblk_set(fs, &inode, 1);
 
 	retval = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
 	if (retval) goto errout;
@@ -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/Makefile.in b/tests/Makefile.in
index f9d5d78..2c3ac76 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -13,7 +13,7 @@
 
 all:: @DO_TEST_SUITE@
 
-test_script: test_script.in Makefile
+test_script: test_script.in Makefile mke2fs.conf
 	@echo "Creating test_script..."
 	@echo "#!/bin/sh" > test_script
 @HTREE_CMT@	@echo "HTREE=y" >> test_script
@@ -23,6 +23,9 @@
 	@cat $(srcdir)/test_script.in >> test_script
 	@chmod +x test_script
 
+mke2fs.conf: $(srcdir)/../misc/mke2fs.conf
+	sed -e 's/blocksize = -1/blocksize = 4096/' $< >mke2fs.conf
+
 check:: test_script
 	@echo "Running e2fsprogs test suite..."
 	@echo " "
@@ -63,7 +66,7 @@
 	@echo "If all is well, edit ${TDIR}/name and rename ${TDIR}."
 
 clean::
-	$(RM) -f *~ *.log *.new *.failed *.ok test.img test_script
+	$(RM) -f *~ *.log *.new *.failed *.ok test.img test_script mke2fs.conf
 
 distclean:: clean
 	$(RM) -f Makefile
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_extents2/expect.1 b/tests/f_extents2/expect.1
new file mode 100644
index 0000000..62ce0ab
--- /dev/null
+++ b/tests/f_extents2/expect.1
@@ -0,0 +1,70 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 has out of order extents
+	(invalid logical block 0, physical block 23, len 12)
+Clear? yes
+
+Inode 12, i_blocks is 86, should be 62.  Fix? yes
+
+Inode 13, i_size is 13295, should be 14336.  Fix? yes
+
+Inode 13, i_blocks is 26, should be 28.  Fix? yes
+
+Inode 15, i_size is 42197, should be 44032.  Fix? yes
+
+Inode 15, i_blocks is 84, should be 86.  Fix? yes
+
+Inode 16 has an invalid extent
+	(logical block 0, invalid physical block 500, len 10)
+Clear? yes
+
+Inode 17 has an invalid extent
+	(logical block 0, physical block 120, invalid len 6000)
+Clear? yes
+
+Inode 18 has out of order extents
+	(invalid logical block 10, physical block 155, len 45)
+Clear? yes
+
+Inode 18, i_blocks is 116, should be 24.  Fix? yes
+
+
+Running additional passes to resolve blocks claimed by more than one inode...
+Pass 1B: Rescanning for multiply-claimed blocks
+Multiply-claimed block(s) in inode 13: 80 80
+Multiply-claimed block(s) in inode 14: 85
+Multiply-claimed block(s) in inode 15: 85
+Pass 1C: Scanning directories for inodes with multiply-claimed blocks
+Pass 1D: Reconciling multiply-claimed blocks
+(There are 3 inodes containing multiply-claimed blocks.)
+
+File /block.c (inode #13, mod time Mon Jun  2 05:20:22 2008) 
+  has 2 multiply-claimed block(s), shared with 0 file(s):
+Clone multiply-claimed blocks? yes
+
+File /inode.c (inode #14, mod time Mon Jun  2 05:28:16 2008) 
+  has 1 multiply-claimed block(s), shared with 1 file(s):
+	/ext2fs.h (inode #15, mod time Mon Jun  2 07:22:57 2008)
+Clone multiply-claimed blocks? yes
+
+File /ext2fs.h (inode #15, mod time Mon Jun  2 07:22:57 2008) 
+  has 1 multiply-claimed block(s), shared with 1 file(s):
+	/inode.c (inode #14, mod time Mon Jun  2 05:28:16 2008)
+Multiply-claimed blocks already reassigned or cloned.
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -(26--34) -(154--199)
+Fix? yes
+
+Free blocks count wrong for group #0 (65535, counted=55).
+Fix? yes
+
+Free blocks count wrong (4294967295, counted=55).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 18/32 files (0.0% non-contiguous), 145/200 blocks
+Exit status is 1
diff --git a/tests/f_extents2/expect.2 b/tests/f_extents2/expect.2
new file mode 100644
index 0000000..a81164e
--- /dev/null
+++ b/tests/f_extents2/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/32 files (0.0% non-contiguous), 145/200 blocks
+Exit status is 0
diff --git a/tests/f_extents2/image.gz b/tests/f_extents2/image.gz
new file mode 100644
index 0000000..52df257
--- /dev/null
+++ b/tests/f_extents2/image.gz
Binary files differ
diff --git a/tests/f_extents2/name b/tests/f_extents2/name
new file mode 100644
index 0000000..4a7e4eb
--- /dev/null
+++ b/tests/f_extents2/name
@@ -0,0 +1 @@
+multiply claimed blocks in extents and other illegal extents
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..8700329
--- /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_bg -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_dasd_bs/expect.1 b/tests/m_dasd_bs/expect.1
index ffaa4aa..6ad145e 100644
--- a/tests/m_dasd_bs/expect.1
+++ b/tests/m_dasd_bs/expect.1
@@ -52,7 +52,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
diff --git a/tests/m_large_file/expect.1 b/tests/m_large_file/expect.1
index 2323eac..212ed60 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)
@@ -51,7 +50,9 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  256
+Inode size:	          256
+Required extra isize:     28
+Desired extra isize:      28
 Default directory hash:   tea
 
 
diff --git a/tests/m_meta_bg/expect.1 b/tests/m_meta_bg/expect.1
index df9a405..7401fd9 100644
--- a/tests/m_meta_bg/expect.1
+++ b/tests/m_meta_bg/expect.1
@@ -50,7 +50,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
diff --git a/tests/m_no_opt/expect.1 b/tests/m_no_opt/expect.1
index cec95af..a63358b 100644
--- a/tests/m_no_opt/expect.1
+++ b/tests/m_no_opt/expect.1
@@ -50,7 +50,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
diff --git a/tests/m_raid_opt/expect.1 b/tests/m_raid_opt/expect.1
index e8ca020..f3c14b6 100644
--- a/tests/m_raid_opt/expect.1
+++ b/tests/m_raid_opt/expect.1
@@ -53,7 +53,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
diff --git a/tests/m_std/expect.1 b/tests/m_std/expect.1
index 376d188..1139dab 100644
--- a/tests/m_std/expect.1
+++ b/tests/m_std/expect.1
@@ -52,7 +52,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
diff --git a/tests/m_uninit/expect.1 b/tests/m_uninit/expect.1
new file mode 100644
index 0000000..ed57e42
--- /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_bg
+ 
+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_bg
+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..0b565ac
--- /dev/null
+++ b/tests/m_uninit/script
@@ -0,0 +1,4 @@
+DESCRIPTION="uninitialized group feature"
+FS_SIZE=131072
+MKE2FS_OPTS="-O uninit_bg"
+. $cmd_dir/run_mke2fs
diff --git a/tests/r_inline_xattr/expect b/tests/r_inline_xattr/expect
index f72ce87..8e59de3 100644
--- a/tests/r_inline_xattr/expect
+++ b/tests/r_inline_xattr/expect
@@ -1,6 +1,6 @@
 resize2fs test
 debugfs -R ''stat file'' ./test.img 2>&1 | grep ''^Inode\|in inode body\|name = ''
-Inode: 1550   Type: regular    Mode:  0644   Flags: 0x0   Generation: 3498507810
+Inode: 1550   Type: regular    Mode:  0644   Flags: 0x0
 Extended attributes stored in inode body: 
   name = "propervalue" (11)
 Exit status is 0
@@ -10,7 +10,7 @@
 
 Exit status is 0
 debugfs -R ''stat file'' ./test.img 2>&1 | grep ''^Inode\|in inode body\|name = ''
-Inode: 12   Type: regular    Mode:  0644   Flags: 0x0   Generation: 3498507810
+Inode: 12   Type: regular    Mode:  0644   Flags: 0x0
 Extended attributes stored in inode body: 
   name = "propervalue" (11)
 Exit status is 0
diff --git a/tests/r_move_itable/expect b/tests/r_move_itable/expect
index e514553..4078f2c 100644
--- a/tests/r_move_itable/expect
+++ b/tests/r_move_itable/expect
@@ -41,7 +41,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
@@ -342,7 +342,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
@@ -879,7 +879,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
@@ -1652,7 +1652,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
diff --git a/tests/r_resize_inode/expect b/tests/r_resize_inode/expect
index 129cdc4..f286f6f 100644
--- a/tests/r_resize_inode/expect
+++ b/tests/r_resize_inode/expect
@@ -39,7 +39,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
@@ -487,7 +487,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
@@ -644,7 +644,7 @@
 Reserved blocks uid:      0
 Reserved blocks gid:      0
 First inode:              11
-Inode size:		  128
+Inode size:	          128
 Default directory hash:   tea
 
 
diff --git a/tests/r_resize_inode/script b/tests/r_resize_inode/script
index 5820fbe..aced9c4 100644
--- a/tests/r_resize_inode/script
+++ b/tests/r_resize_inode/script
@@ -37,6 +37,8 @@
 
 echo "--------------------------------" >> $OUT
 
+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1
+
 echo mke2fs -q -F -O resize_inode -o Linux -b 1024 -g 1024 test.img 65536 >> $OUT
 $MKE2FS -q -F -O resize_inode -o Linux -b 1024 -g 1024 $TMPFILE 65536 2>&1 \
 	| sed -e '1d' | grep -v "automatically checked" | 
diff --git a/tests/test_config b/tests/test_config
index f5ae0fe..6abc746 100644
--- a/tests/test_config
+++ b/tests/test_config
@@ -13,6 +13,7 @@
 TEST_BITS="../debugfs/debugfs"
 RESIZE2FS_EXE="../resize/resize2fs"
 RESIZE2FS="$USE_VALGRIND $RESIZE2FS_EXE"
+UNDOE2FS_EXE="../misc/undoe2fs"
 TEST_REL=../tests/progs/test_rel
 TEST_ICOUNT=../tests/progs/test_icount
 LD_LIBRARY_PATH=../lib:../lib/ext2fs:../lib/e2p:../lib/et:../lib/ss
@@ -26,6 +27,6 @@
 export LC_ALL
 E2FSCK_CONFIG=/dev/null
 export E2FSCK_CONFIG
-MKE2FS_CONFIG=$SRCDIR/../misc/mke2fs.conf
+MKE2FS_CONFIG=./mke2fs.conf
 export MKE2FS_CONFIG
 
diff --git a/tests/u_undoe2fs_mke2fs/script b/tests/u_undoe2fs_mke2fs/script
new file mode 100644
index 0000000..11e9449
--- /dev/null
+++ b/tests/u_undoe2fs_mke2fs/script
@@ -0,0 +1,35 @@
+printf "undoe2fs with mke2fs: "
+if test -x $UNDOE2FS_EXE; then
+
+export E2FSPROGS_UNDO_DIR=./
+TDB_FILE=./mke2fs-test.img.e2undo
+OUT=$test_name.log
+rm -f $TDB_FILE >/dev/null 2>&1
+
+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1
+
+echo mke2fs -q -F -o Linux -b 1024 test.img  > $OUT
+$MKE2FS -F -o Linux -I 128 -b 1024 $TMPFILE  >> $OUT 2>&1
+md5=$(md5sum $TMPFILE | cut -d " " -f 1)
+echo md5sum before mke2fs $md5 >> $OUT
+
+echo using mke2fs to test undoe2fs >> $OUT
+$MKE2FS -q -F -o Linux -I 256 -O uninit_bg -E lazy_itable_init=1 -b 1024 $TMPFILE  >> $OUT 2>&1
+new_md5=$(md5sum $TMPFILE | cut -d " " -f 1)
+echo md5sum after mke2fs $new_md5 >> $OUT
+
+$UNDOE2FS_EXE  $TDB_FILE $TMPFILE  >> $OUT 2>&1
+new_md5=$(md5sum $TMPFILE | cut -d " " -f 1)
+echo md5sum after undoe2fs $new_md5 >> $OUT
+
+if [ $md5 = $new_md5 ]; then
+	echo "ok"
+	touch $test_name.ok
+	rm -f $test_name.failed
+else
+	rm -f $test_name.ok
+	ln -f $test_name.log $test_name.failed
+	echo "failed"
+fi
+rm -f $TDB_FILE $TMPFILE
+fi
diff --git a/tests/u_undoe2fs_tune2fs/script b/tests/u_undoe2fs_tune2fs/script
new file mode 100644
index 0000000..5931ba6
--- /dev/null
+++ b/tests/u_undoe2fs_tune2fs/script
@@ -0,0 +1,35 @@
+printf "undoe2fs with tune2fs: "
+if test -x $UNDOE2FS_EXE; then
+
+export E2FSPROGS_UNDO_DIR=./
+TDB_FILE=./tune2fs-test.img.e2undo
+OUT=$test_name.log
+rm -f $TDB_FILE >/dev/null 2>&1
+
+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1
+
+echo mke2fs -q -F -o Linux -b 1024 $TMPFILE  > $OUT
+$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE  >> $OUT 2>&1
+md5=$(md5sum $TMPFILE | cut -d " " -f 1)
+echo md5sum before tune2fs $md5 >> $OUT
+
+echo using tune2fs to test undoe2fs >> $OUT
+$TUNE2FS -I 256 $TMPFILE  >> $OUT 2>&1
+new_md5=$(md5sum $TMPFILE | cut -d " " -f 1)
+echo md5sum after tune2fs $new_md5 >> $OUT
+
+$UNDOE2FS_EXE  $TDB_FILE $TMPFILE  >> $OUT 2>&1
+new_md5=$(md5sum $TMPFILE | cut -d " " -f 1)
+echo md5sum after undoe2fs $new_md5 >> $OUT
+
+if [ $md5 = $new_md5 ]; then
+	echo "ok"
+	touch $test_name.ok
+	rm -f $test_name.failed
+else
+	rm -f $test_name.ok
+	ln -f $test_name.log $test_name.failed
+	echo "failed"
+fi
+rm -f $TDB_FILE $TMPFILE
+fi
diff --git a/version.h b/version.h
index 95704e6..0e9c492 100644
--- a/version.h
+++ b/version.h
@@ -7,5 +7,5 @@
  * redistributed under the GNU Public License.
  */
 
-#define E2FSPROGS_VERSION "1.40.10"
-#define E2FSPROGS_DATE "21-May-2008"
+#define E2FSPROGS_VERSION "1.41-WIP"
+#define E2FSPROGS_DATE "27-Apr-2008"