Merge branch 'maint' into next
diff --git a/configure b/configure
index 814b2f4..3c5a5ff 100755
--- a/configure
+++ b/configure
@@ -11456,8 +11456,13 @@
 
 # Check whether --with-multiarch was given.
 if test "${with_multiarch+set}" = set; then :
-  withval=$with_multiarch; libdir=$libdir/$withval
-root_libdir=$root_libdir/$withval
+  withval=$with_multiarch; if test "$withval" = "lib64"; then
+    libdir=/usr/lib64
+    root_libdir=/lib64
+else
+    libdir=$libdir/$withval
+    root_libdir=$root_libdir/$withval
+fi
 
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can link with -static" >&5
diff --git a/configure.in b/configure.in
index 93c581a..28d7557 100644
--- a/configure.in
+++ b/configure.in
@@ -1279,8 +1279,13 @@
 dnl
 AC_ARG_WITH([multiarch],
 [  --with-multiarch=ARCH specify the multiarch triplet],
-libdir=$libdir/$withval
-root_libdir=$root_libdir/$withval
+if test "$withval" = "lib64"; then
+    libdir=/usr/lib64
+    root_libdir=/lib64
+else
+    libdir=$libdir/$withval
+    root_libdir=$root_libdir/$withval
+fi
 )dnl
 dnl
 dnl See if -static works.  This could fail if the linker does not
diff --git a/debian/control.in b/debian/control.in
index f4c915f..3e81c36 100644
--- a/debian/control.in
+++ b/debian/control.in
@@ -124,6 +124,7 @@
  different CPU’s. It is used by libuuid as well as the uuidgen
  program.
 
+ifdef(`UDEV_PKGS',``
 Package: libuuid1-udeb
 XC-Package-Type: udeb
 Section: debian-installer
@@ -135,6 +136,7 @@
  See RFC 4122 for more information.
  .
  This is a minimal package for debian-installer.
+'')dnl
 
 Package: uuid-dev
 Section: libdevel
@@ -159,6 +161,7 @@
  filesystems by hard-coded device names, but via a logical naming 
  system instead.
 
+ifdef(`UDEV_PKGS',``
 Package: libblkid1-udeb
 XC-Package-Type: udeb
 Section: debian-installer
@@ -173,6 +176,7 @@
  system instead.
  .
  This is a minimal package for debian-installer.
+'')dnl
 
 Package: libblkid-dev
 Section: libdevel
@@ -189,6 +193,7 @@
  This package contains the development environment for the blkid library.
 '')dnl
 
+ifdef(`UDEV_PKGS',``
 Package: e2fsprogs-udeb
 XC-Package-Type: udeb
 Section: debian-installer
@@ -201,6 +206,7 @@
  .
  Don't attempt to install this package, it has no support for a couple of
  features you surely want.  Anyway it should refuse to install.
+'')dnl
 
 Package: e2fslibs
 Section: libs
@@ -253,7 +259,7 @@
  hard disks on Debian and other Linux systems.
  .
  This package contains programs for creating, checking, and maintaining
- ext2/3/4-based file systems.  It also includes the "badbocks" program,
+ ext2/3/4-based file systems.  It also includes the "badblocks" program,
  which can be used to scan for bad blocks on a disk or other storage device.
 
 Package: e2fsprogs-dbg
diff --git a/debian/rules b/debian/rules
index f5ee6a6..2f722aa 100755
--- a/debian/rules
+++ b/debian/rules
@@ -139,6 +139,10 @@
 E2FSCK_STATIC = ${staticbuilddir}/e2fsck/e2fsck.static
 endif
 
+ifneq ($(SKIP_UDEB),)
+SKIP_BF ?= yes
+endif
+
 ifeq ($(SKIP_BF),yes)
 BUILD_BF =
 bfbuilddir	?= ${stdbuilddir}
@@ -222,6 +226,13 @@
 M4_ARGS+=-UE2FSCK_STATIC
 endif
 
+ifeq ($(SKIP_UDEB),)
+INSTALL_UDEB = install-udeb
+M4_ARGS+=-DUDEB_PKGS
+else
+M4_ARGS+=-UUDEB_PKGS
+endif
+
 FILES_FIXUP= libcomerr2.files comerr-dev.files libss2.files ss-dev.files \
 	libuuid1.files uuid-dev.files libblkid1.files libblkid-dev.files \
 	e2fslibs.files e2fslibs-dev.files
@@ -469,7 +480,7 @@
   # no arch-independant debs.
 
 binary-arch: DH_OPTIONS= -a
-binary-arch: install install-udeb
+binary-arch: install $(INSTALL_UDEB)
 	dh_testdir
 	dh_testroot
 
@@ -557,7 +568,9 @@
 
 	dh_fixperms
 	dh_strip -pe2fsprogs --dbg-package=e2fsprogs-dbg
+ifneq ($(BUILD_E2FSCK_STATIC),no)
 	dh_strip -pe2fsck-static --dbg-package=e2fsprogs-dbg
+endif
 ifneq ($(ismips),)
 	dh_strip -pe2fslibs --dbg-package=e2fslibs-dbg -Xlib64ext2fs-nopic.a
 else
@@ -616,6 +629,7 @@
 	dh_compress
 
 	dh_makeshlibs -Ne2fsprogs-udeb -Nlibblkid1-udeb -Nlibuuid1-udeb
+ifeq ($(SKIP_UDEB),)
 	dh_makeshlibs --add-udeb=e2fsprogs-udeb -plibcomerr${COMERR_SOVERSION} \
 		-V 'libcomerr2 (>= 1.33-3)'
 ifneq ($(UTIL_LINUX_NG),yes)
@@ -624,13 +638,16 @@
 		debian/libblkid1/DEBIAN/shlibs
 	echo "udeb: libuuid 1 libuuid1-udeb" >> debian/libuuid1/DEBIAN/shlibs
 endif
+endif
 
 	dh_installdeb
 	dh_shlibdeps -l${stdbuilddir}/lib
 	dh_shlibdeps -pe2fsprogs -l${stdbuilddir}/lib \
 		-u"-Ldebian/e2fsprogs.shlibs.local"
+ifeq ($(SKIP_UDEB),)
 	dh_shlibdeps -pe2fsprogs-udeb -l${stdbuilddir}/lib \
 		-u"-Ldebian/e2fsprogs-udeb.shlibs.local"
+endif
 
 	dh_gencontrol -Ncomerr-dev -Nss-dev -Nuuid-dev \
 		-Ne2fsprogs-udeb -Nlibblkid1-udeb -Nlibuuid1-udeb
@@ -642,24 +659,30 @@
 	DH_OPTIONS= dh_gencontrol -puuid-dev \
 	  -u '-v${UUID_VERSION}-${MAIN_VERSION} -VmainBinary=${MAIN_VERSION}'
 endif
+ifeq ($(SKIP_UDEB),)
 	dh_gencontrol	-pe2fsprogs-udeb -- -fdebian/files~
 ifneq ($(UTIL_LINUX_NG),yes)
 	dh_gencontrol	-plibblkid1-udeb -- -fdebian/files~
 	dh_gencontrol	-plibuuid1-udeb -- -fdebian/files~
 endif
+endif
 
+ifeq ($(SKIP_UDEB),)
 	dpkg-distaddfile $(UDEB_NAME) debian-installer $(UDEB_PRIORITY)
 ifneq ($(UTIL_LINUX_NG),yes)
 	dpkg-distaddfile $(BLKID_UDEB_NAME) debian-installer $(BLKID_UDEB_PRIORITY)
 	dpkg-distaddfile $(UUID_UDEB_NAME) debian-installer $(UUID_UDEB_PRIORITY)
 endif
+endif
 	dh_md5sums -Ne2fsprogs-udeb -Nlibblkid1-udeb -Nlibuuid1-udeb
 	dh_builddeb -Ne2fsprogs-udeb -Nlibblkid1-udeb -Nlibuuid1-udeb
+ifeq ($(SKIP_UDEB),)
 	dh_builddeb -pe2fsprogs-udeb --filename=$(UDEB_NAME)
 ifneq ($(UTIL_LINUX_NG),yes)
 	dh_builddeb -plibblkid1-udeb --filename=$(BLKID_UDEB_NAME)
 	dh_builddeb -plibuuid1-udeb --filename=$(UUID_UDEB_NAME)
 endif
+endif
 
 binary: binary-indep binary-arch
 
diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index b944c27..db2fd72 100644
--- a/lib/ext2fs/bmap.c
+++ b/lib/ext2fs/bmap.c
@@ -255,8 +255,10 @@
 	set_extent:
 		retval = ext2fs_extent_set_bmap(handle, block,
 						blk64, 0);
-		if (retval)
+		if (retval) {
+			ext2fs_block_alloc_stats2(fs, blk64, -1);
 			return retval;
+		}
 		/* Update inode after setting extent */
 		retval = ext2fs_read_inode(fs, ino, inode);
 		if (retval)
diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
index e96fa5f..3ccae66 100644
--- a/lib/ext2fs/extent.c
+++ b/lib/ext2fs/extent.c
@@ -1440,13 +1440,17 @@
 			goto done;
 	} else {
 		__u32	orig_length;
+		blk64_t	orig_lblk;
+		struct ext2fs_extent orig_extent;
+		errcode_t r2;
 
 #ifdef DEBUG
 		printf("(re/un)mapping in middle of extent\n");
 #endif
 		/* need to split this extent; later */
-
+		orig_lblk = extent.e_lblk;
 		orig_length = extent.e_len;
+		orig_extent = extent;
 
 		/* shorten pre-split extent */
 		extent.e_len = (logical - extent.e_lblk);
@@ -1458,8 +1462,13 @@
 			/* insert new extent after current */
 			retval = ext2fs_extent_insert(handle,
 					EXT2_EXTENT_INSERT_AFTER, &newextent);
-			if (retval)
+			if (retval) {
+				r2 = ext2fs_extent_goto(handle, orig_lblk);
+				if (r2 == 0)
+					ext2fs_extent_replace(handle, 0,
+							      &orig_extent);
 				goto done;
+			}
 		}
 		/* add post-split extent */
 		extent.e_pblk += extent.e_len + 1;
@@ -1467,8 +1476,18 @@
 		extent.e_len = orig_length - extent.e_len - 1;
 		retval = ext2fs_extent_insert(handle,
 				EXT2_EXTENT_INSERT_AFTER, &extent);
-		if (retval)
+		if (retval) {
+			if (physical) {
+				r2 = ext2fs_extent_goto(handle,
+							newextent.e_lblk);
+				if (r2 == 0)
+					ext2fs_extent_delete(handle, 0);
+			}
+			r2 = ext2fs_extent_goto(handle, orig_lblk);
+			if (r2 == 0)
+				ext2fs_extent_replace(handle, 0, &orig_extent);
 			goto done;
+		}
 	}
 
 done:
diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c
index 25d7953..a3d020e 100644
--- a/lib/ext2fs/punch.c
+++ b/lib/ext2fs/punch.c
@@ -288,8 +288,12 @@
 			   (unsigned long long) end,
 			   (unsigned long long) next);
 		if (start <= extent.e_lblk) {
+			/*
+			 * Have we iterated past the end of the punch region?
+			 * If so, we can stop.
+			 */
 			if (end < extent.e_lblk)
-				goto next_extent;
+				break;
 			dbg_printf("Case #%d\n", 1);
 			/* Start of deleted region before extent; 
 			   adjust beginning of extent */
@@ -303,8 +307,13 @@
 			extent.e_lblk += free_count;
 			extent.e_pblk += free_count;
 		} else if (end >= next-1) {
+			/*
+			 * Is the punch region beyond this extent?  This can
+			 * happen if start is already inside a hole.  Try to
+			 * advance to the next extent if this is the case.
+			 */
 			if (start >= next)
-				break;
+				goto next_extent;
 			/* End of deleted region after extent;
 			   adjust end of extent */
 			dbg_printf("Case #%d\n", 2);
@@ -344,6 +353,9 @@
 		if (extent.e_len) {
 			dbg_print_extent("replacing", &extent);
 			retval = ext2fs_extent_replace(handle, 0, &extent);
+			if (retval)
+				goto errout;
+			retval = ext2fs_extent_fix_parents(handle);
 		} else {
 			struct ext2fs_extent	newex;
 			blk64_t			old_lblk, next_lblk;
@@ -378,6 +390,11 @@
 			if (retval)
 				goto errout;
 
+			retval = ext2fs_extent_fix_parents(handle);
+			if (retval && retval != EXT2_ET_NO_CURRENT_NODE)
+				goto errout;
+			retval = 0;
+
 			/* Jump forward to the next extent. */
 			ext2fs_extent_goto(handle, next_lblk);
 			op = EXT2_EXTENT_CURRENT;
diff --git a/misc/mk_hugefiles.c b/misc/mk_hugefiles.c
index eb91f0c..debc3fe 100644
--- a/misc/mk_hugefiles.c
+++ b/misc/mk_hugefiles.c
@@ -349,8 +349,8 @@
 	align = parse_num_blocks2(t, fs->super->s_log_block_size);
 	free(t);
 	num_blocks = round_up_align(num_blocks, align);
-	zero_hugefile = get_int_from_profile(fs_types, "zero_hugefiles",
-					     zero_hugefile);
+	zero_hugefile = get_bool_from_profile(fs_types, "zero_hugefiles",
+					      zero_hugefile);
 
 	t = get_string_from_profile(fs_types, "hugefiles_dir", "/");
 	retval = create_directory(fs, t, &dir);
@@ -402,6 +402,11 @@
 	goal = get_start_block(fs, num_slack);
 	goal = round_up_align(goal, align);
 
+	if ((num_blocks ? num_blocks : fs_blocks) >
+	    (0x80000000UL / fs->blocksize))
+		fs->super->s_feature_ro_compat |=
+			EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+
 	if (!quiet) {
 		if (zero_hugefile && verbose)
 			printf(_("Huge files will be zero'ed\n"));
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 7b69595..facbe4c 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -27,6 +27,7 @@
 #include <time.h>
 #ifdef __linux__
 #include <sys/utsname.h>
+#include <linux/version.h>
 #endif
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
@@ -173,7 +174,29 @@
 	rev = strtol(cp, &endptr, 10);
 	if (cp == endptr)
 		return 0;
-	return ((((major * 256) + minor) * 256) + rev);
+	return KERNEL_VERSION(major, minor, rev);
+}
+
+static int is_before_linux_ver(unsigned int major, unsigned int minor)
+{
+	struct		utsname ut;
+	static int	linux_version_code = -1;
+
+	if (uname(&ut)) {
+		perror("uname");
+		exit(1);
+	}
+	if (linux_version_code < 0)
+		linux_version_code = parse_version_number(ut.release);
+	if (linux_version_code == 0)
+		return 0;
+
+	return linux_version_code < KERNEL_VERSION(major, minor, 0);
+}
+#else
+static int is_before_linux_ver(unsigned int major, unsigned int minor)
+{
+	return 0;
 }
 #endif
 
@@ -1425,9 +1448,6 @@
 	 * Finally, we complain about fs_blocks_count > 2^32 on a non-64bit fs.
 	 */
 	blk64_t		fs_blocks_count = 0;
-#ifdef __linux__
-	struct 		utsname ut;
-#endif
 	long		sysval;
 	int		s_opt = -1, r_opt = -1;
 	char		*fs_features = 0;
@@ -1493,15 +1513,8 @@
 	memset(&fs_param, 0, sizeof(struct ext2_super_block));
 	fs_param.s_rev_level = 1;  /* Create revision 1 filesystems now */
 
-#ifdef __linux__
-	if (uname(&ut)) {
-		perror("uname");
-		exit(1);
-	}
-	linux_version_code = parse_version_number(ut.release);
-	if (linux_version_code && linux_version_code < (2*65536 + 2*256))
+	if (is_before_linux_ver(2, 2))
 		fs_param.s_rev_level = 0;
-#endif
 
 	if (argc && *argv) {
 		program_name = get_progname(*argv);
@@ -1939,8 +1952,7 @@
 
 		if (use_bsize == -1) {
 			use_bsize = sys_page_size;
-			if ((linux_version_code < (2*65536 + 6*256)) &&
-			    (use_bsize > 4096))
+			if (is_before_linux_ver(2, 6) && use_bsize > 4096)
 				use_bsize = 4096;
 		}
 		if (lsector_size && use_bsize < lsector_size)
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 4327ca0..8ff47d2 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -931,6 +931,19 @@
 				return 1;
 		}
 	}
+
+	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
+		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+		if (sb->s_feature_incompat &
+			EXT2_FEATURE_INCOMPAT_META_BG) {
+			fputs(_("Setting filesystem feature 'sparse_super' "
+				"not supported\nfor filesystems with "
+				"the meta_bg feature enabled.\n"),
+				stderr);
+			return 1;
+		}
+	}
+
 	if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP)) {
 		int error;
 
@@ -2582,10 +2595,18 @@
 	}
 	if (s_flag == 1) {
 		if (sb->s_feature_ro_compat &
-		    EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
+		    EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) {
 			fputs(_("\nThe filesystem already has sparse "
 				"superblocks.\n"), stderr);
-		else {
+		} else if (sb->s_feature_incompat &
+			EXT2_FEATURE_INCOMPAT_META_BG) {
+			fputs(_("\nSetting the sparse superblock flag not "
+				"supported\nfor filesystems with "
+				"the meta_bg feature enabled.\n"),
+				stderr);
+			rc = 1;
+			goto closefs;
+		} else {
 			sb->s_feature_ro_compat |=
 				EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
 			sb->s_state &= ~EXT2_VALID_FS;
@@ -2595,7 +2616,7 @@
 		}
 	}
 	if (s_flag == 0) {
-		fputs(_("\nClearing the sparse superflag not supported.\n"),
+		fputs(_("\nClearing the sparse superblock flag not supported.\n"),
 		      stderr);
 		rc = 1;
 		goto closefs;