Merge branch 'maint' into next
diff --git a/MCONFIG.in b/MCONFIG.in
index 852286a..7ca86ac 100644
--- a/MCONFIG.in
+++ b/MCONFIG.in
@@ -32,6 +32,14 @@
 infodir = @infodir@
 datadir = @datadir@
 pkgconfigdir = $(libdir)/pkgconfig
+pkglibdir = $(libdir)/e2fsprogs
+
+HAVE_UDEV = @have_udev@
+UDEV_RULES_DIR = @pkg_udev_rules_dir@
+HAVE_CROND = @have_crond@
+CROND_DIR = @crond_dir@
+HAVE_SYSTEMD = @have_systemd@
+SYSTEMD_SYSTEM_UNIT_DIR = @systemd_system_unit_dir@
 
 @SET_MAKE@
 
@@ -73,21 +81,24 @@
 @ifNotGNUmake@ CHECK_CMD=true
 @ifNotGNUmake@ CPPCHECK_CMD=true
 
+SANITIZER_CFLAGS = @lto_cflags@ @ubsan_cflags@ @addrsan_cflags@ @threadsan_cflags@
+SANITIZER_LDFLAGS = @lto_ldflags@ @ubsan_ldflags@ @addrsan_ldflags@ @threadsan_ldflags@
+
 CC = @CC@
 BUILD_CC = @BUILD_CC@
 CFLAGS = @CFLAGS@
 CFLAGS_SHLIB = @CFLAGS_SHLIB@
 CFLAGS_STLIB = @CFLAGS_STLIB@
 CPPFLAGS = @INCLUDES@
-ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) $(CFLAGS_WARN) @DEFS@ $(LOCAL_CFLAGS)
-ALL_CFLAGS_SHLIB = $(CPPFLAGS) $(CFLAGS_SHLIB) $(CFLAGS_WARN) @DEFS@ $(LOCAL_CFLAGS)
-ALL_CFLAGS_STLIB = $(CPPFLAGS) $(CFLAGS_STLIB) $(CFLAGS_WARN) @DEFS@ $(LOCAL_CFLAGS)
-LDFLAGS = @LDFLAGS@
-LDFLAGS_SHLIB = @LDFLAGS_SHLIB@
+ALL_CFLAGS = $(CPPFLAGS) $(SANITIZER_CFLAGS) $(CFLAGS) $(CFLAGS_WARN) @DEFS@ $(LOCAL_CFLAGS)
+ALL_CFLAGS_SHLIB = $(CPPFLAGS) $(SANITIZER_CFLAGS) $(CFLAGS_SHLIB) $(CFLAGS_WARN) @DEFS@ $(LOCAL_CFLAGS)
+ALL_CFLAGS_STLIB = $(CPPFLAGS) $(SANITIZER_CFLAGS) $(CFLAGS_STLIB) $(CFLAGS_WARN) @DEFS@ $(LOCAL_CFLAGS)
+LDFLAGS = $(SANITIZER_LDFLAGS) @LDFLAGS@
+LDFLAGS_SHLIB = $(SANITIZER_LDFLAGS) @LDFLAGS_SHLIB@
 ALL_LDFLAGS = $(LDFLAGS) @LDFLAG_DYNAMIC@
-LDFLAGS_STATIC = @LDFLAGS_STATIC@
-BUILD_CFLAGS = @BUILD_CFLAGS@
-BUILD_LDFLAGS = @BUILD_LDFLAGS@
+LDFLAGS_STATIC = $(SANITIZER_LDFLAGS) @LDFLAGS_STATIC@
+BUILD_CFLAGS = $(SANITIZER_CFLAGS) @BUILD_CFLAGS@
+BUILD_LDFLAGS = $(SANITIZER_LDFLAGS) @BUILD_LDFLAGS@
 RDYNAMIC = @RDYNAMIC@
 LINK_BUILD_FLAGS = @LINK_BUILD_FLAGS@
 LINK_INSTALL_FLAGS = @LINK_INSTALL_FLAGS@
diff --git a/Makefile.in b/Makefile.in
index 4627314..b951c01 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -13,6 +13,7 @@
 @DEBUGFS_CMT@DEBUGFS_DIR= debugfs
 @UUID_CMT@UUID_LIB_SUBDIR= lib/uuid
 @BLKID_CMT@BLKID_LIB_SUBDIR= lib/blkid
+@E2SCRUB_CMT@E2SCRUB_DIR= scrub
 @ALL_CMT@SUPPORT_LIB_SUBDIR= lib/support
 @ALL_CMT@E2P_LIB_SUBDIR= lib/e2p
 @ALL_CMT@EXT2FS_LIB_SUBDIR= lib/ext2fs
@@ -20,7 +21,9 @@
 LIB_SUBDIRS=lib/et lib/ss $(E2P_LIB_SUBDIR) $(UUID_LIB_SUBDIR) \
 	$(BLKID_LIB_SUBDIR) $(SUPPORT_LIB_SUBDIR) $(EXT2FS_LIB_SUBDIR) intl
 
-PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po
+PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po \
+	$(E2SCRUB_DIR)
+
 SUBDIRS=util $(LIB_SUBDIRS) $(PROG_SUBDIRS) tests
 
 SUBS= util/subst.conf lib/config.h $(top_builddir)/lib/dirpaths.h \
diff --git a/config/ltmain.sh b/config/ltmain.sh
new file mode 120000
index 0000000..8cff389
--- /dev/null
+++ b/config/ltmain.sh
@@ -0,0 +1 @@
+/usr/share/libtool/build-aux/ltmain.sh
\ No newline at end of file
diff --git a/configure b/configure
index 1ac0654..af71919 100755
--- a/configure
+++ b/configure
@@ -625,6 +625,16 @@
 ac_func_list=
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
+systemd_system_unit_dir
+have_systemd
+systemd_LIBS
+systemd_CFLAGS
+crond_dir
+have_crond
+pkg_udev_rules_dir
+have_udev
+udev_LIBS
+udev_CFLAGS
 LDFLAGS_SHLIB
 CFLAGS_STLIB
 CFLAGS_SHLIB
@@ -638,9 +648,24 @@
 root_sbindir
 root_bindir
 root_prefix
+E2SCRUB_CMT
 UNIX_CMT
 CYGWIN_CMT
 LINUX_CMT
+threadsan_ldflags
+threadsan_cflags
+have_threadsan
+addrsan_ldflags
+addrsan_cflags
+have_addrsan
+ubsan_ldflags
+ubsan_cflags
+have_ubsan
+lto_ldflags
+lto_cflags
+have_lto
+gcc_ranlib
+gcc_ar
 UNI_DIFF_OPTS
 SEM_INIT_LIB
 FUSE_CMT
@@ -796,6 +821,7 @@
 build_vendor
 build_cpu
 build
+E2FSPROGS_DATE
 E2FSPROGS_PKGVER
 E2FSPROGS_VERSION
 E2FSPROGS_DAY
@@ -893,7 +919,14 @@
 with_included_gettext
 with_libintl_prefix
 enable_fuse2fs
+enable_lto
+enable_ubsan
+enable_addrsan
+enable_threadsan
 with_multiarch
+with_udev_rules_dir
+with_crond_dir
+with_systemd_unit_dir
 '
       ac_precious_vars='build_alias
 host_alias
@@ -906,7 +939,11 @@
 CPP
 PKG_CONFIG
 PKG_CONFIG_PATH
-PKG_CONFIG_LIBDIR'
+PKG_CONFIG_LIBDIR
+udev_CFLAGS
+udev_LIBS
+systemd_CFLAGS
+systemd_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1565,6 +1602,10 @@
   --disable-threads       build without multithread safety
   --disable-rpath         do not hardcode runtime library paths
   --disable-fuse2fs	  do not build fuse2fs
+  --enable-lto		  enable link time optimization
+  --enable-ubsan	  enable undefined behavior sanitizer
+  --enable-addrsan	  enable address sanitizer
+  --enable-threadsan	  enable thread sanitizer
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1583,6 +1624,11 @@
   --with-libintl-prefix[=DIR]  search for libintl in DIR/include and DIR/lib
   --without-libintl-prefix     don't search for libintl in includedir and libdir
   --with-multiarch=ARCH specify the multiarch triplet
+  --with-udev-rules-dir[=DIR]
+                          Install udev rules into DIR.
+  --with-crond-dir[=DIR]  Install system crontabs into DIR.
+  --with-systemd-unit-dir[=DIR]
+                          Install systemd system units into DIR.
 
 Some influential environment variables:
   CC          C compiler command
@@ -1598,6 +1644,12 @@
               directories to add to pkg-config's search path
   PKG_CONFIG_LIBDIR
               path overriding pkg-config's built-in search path
+  udev_CFLAGS C compiler flags for udev, overriding pkg-config
+  udev_LIBS   linker flags for udev, overriding pkg-config
+  systemd_CFLAGS
+              C compiler flags for systemd, overriding pkg-config
+  systemd_LIBS
+              linker flags for systemd, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -2761,11 +2813,11 @@
 BINARY_TYPE=bin
 E2FSPROGS_VERSION=`grep E2FSPROGS_VERSION ${srcdir}/version.h  \
 	| awk '{print $3}' | tr \" " " | awk '{print $1}'`
-DATE=`grep E2FSPROGS_DATE ${srcdir}/version.h | awk '{print $3}' \
-	| tr \" " "`
-E2FSPROGS_DAY=$(echo $DATE | awk -F- '{print $1}' | sed -e '/^[1-9]$/s/^/0/')
-MONTH=`echo $DATE | awk -F- '{print $2}'`
-YEAR=`echo $DATE | awk -F- '{print $3}'`
+E2FSPROGS_DATE=`grep E2FSPROGS_DATE ${srcdir}/version.h | awk '{print $3}' \
+	| tr \" " " | awk '{print $1}'`
+E2FSPROGS_DAY=$(echo $E2FSPROGS_DATE | awk -F- '{print $1}' | sed -e '/^[1-9]$/s/^/0/')
+MONTH=`echo $E2FSPROGS_DATE | awk -F- '{print $2}'`
+YEAR=`echo $E2FSPROGS_DATE | awk -F- '{print $3}'`
 
 if expr $YEAR ">" 1900 > /dev/null ; then
 	E2FSPROGS_YEAR=$YEAR
@@ -2816,6 +2868,7 @@
 
 
 
+
 WITH_DIET_LIBC=
 
 # Check whether --with-diet-libc was given.
@@ -13721,6 +13774,282 @@
 
 	;;
 esac
+# Check whether --enable-lto was given.
+if test "${enable_lto+set}" = set; then :
+  enableval=$enable_lto;
+else
+  enable_lto=no
+fi
+
+if test "$enable_lto" = "yes" || test "$enable_lto" = "probe"; then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if C compiler supports LTO" >&5
+$as_echo_n "checking if C compiler supports LTO... " >&6; }
+	OLD_CFLAGS="$CFLAGS"
+	OLD_LDFLAGS="$LDFLAGS"
+	LTO_FLAGS="-g -flto -ffat-lto-objects"
+	CFLAGS="$CFLAGS $LTO_FLAGS"
+	LDFLAGS="$LDFLAGS $LTO_FLAGS"
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+		lto_cflags=$LTO_FLAGS
+		lto_ldflags=$LTO_FLAGS
+		# Extract the first word of "gcc-ar", so it can be a program name with args.
+set dummy gcc-ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_gcc_ar+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $gcc_ar in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_gcc_ar="$gcc_ar" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_gcc_ar="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+gcc_ar=$ac_cv_path_gcc_ar
+if test -n "$gcc_ar"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_ar" >&5
+$as_echo "$gcc_ar" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+		# Extract the first word of "gcc-ranlib", so it can be a program name with args.
+set dummy gcc-ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_gcc_ranlib+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $gcc_ranlib in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_gcc_ranlib="$gcc_ranlib" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_gcc_ranlib="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+gcc_ranlib=$ac_cv_path_gcc_ranlib
+if test -n "$gcc_ranlib"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_ranlib" >&5
+$as_echo "$gcc_ranlib" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	if test -x "$gcc_ar" && test -x "$gcc_ranlib"; then
+		have_lto=yes
+		AR="${gcc_ar}"
+		RANLIB="${gcc_ranlib}"
+	fi
+	CFLAGS="${OLD_CFLAGS}"
+	LDFLAGS="${OLD_LDFLAGS}"
+
+
+
+fi
+if test "$enable_lto" = "yes" && test "$have_lto" != "yes"; then
+	as_fn_error $? "LTO not supported by compiler." "$LINENO" 5
+fi
+# Check whether --enable-ubsan was given.
+if test "${enable_ubsan+set}" = set; then :
+  enableval=$enable_ubsan;
+else
+  enable_ubsan=no
+fi
+
+if test "$enable_ubsan" = "yes" || test "$enable_ubsan" = "probe"; then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if C compiler supports UBSAN" >&5
+$as_echo_n "checking if C compiler supports UBSAN... " >&6; }
+	OLD_CFLAGS="$CFLAGS"
+	OLD_LDFLAGS="$LDFLAGS"
+	UBSAN_FLAGS="-fsanitize=undefined"
+	CFLAGS="$CFLAGS $UBSAN_FLAGS"
+	LDFLAGS="$LDFLAGS $UBSAN_FLAGS"
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+		ubsan_cflags=$UBSAN_FLAGS
+		ubsan_ldflags=$UBSAN_FLAGS
+		have_ubsan=yes
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	CFLAGS="${OLD_CFLAGS}"
+	LDFLAGS="${OLD_LDFLAGS}"
+
+
+
+fi
+if test "$enable_ubsan" = "yes" && test "$have_ubsan" != "yes"; then
+	as_fn_error $? "UBSAN not supported by compiler." "$LINENO" 5
+fi
+# Check whether --enable-addrsan was given.
+if test "${enable_addrsan+set}" = set; then :
+  enableval=$enable_addrsan;
+else
+  enable_addrsan=no
+fi
+
+if test "$enable_addrsan" = "yes" || test "$enable_addrsan" = "probe"; then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if C compiler supports ADDRSAN" >&5
+$as_echo_n "checking if C compiler supports ADDRSAN... " >&6; }
+	OLD_CFLAGS="$CFLAGS"
+	OLD_LDFLAGS="$LDFLAGS"
+	ADDRSAN_FLAGS="-fsanitize=address"
+	CFLAGS="$CFLAGS $ADDRSAN_FLAGS"
+	LDFLAGS="$LDFLAGS $ADDRSAN_FLAGS"
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+		addrsan_cflags=$ADDRSAN_FLAGS
+		addrsan_ldflags=$ADDRSAN_FLAGS
+		have_addrsan=yes
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	CFLAGS="${OLD_CFLAGS}"
+	LDFLAGS="${OLD_LDFLAGS}"
+
+
+
+fi
+if test "$enable_addrsan" = "yes" && test "$have_addrsan" != "yes"; then
+	as_fn_error $? "ADDRSAN not supported by compiler." "$LINENO" 5
+fi
+# Check whether --enable-threadsan was given.
+if test "${enable_threadsan+set}" = set; then :
+  enableval=$enable_threadsan;
+else
+  enable_threadsan=no
+fi
+
+if test "$enable_threadsan" = "yes" || test "$enable_threadsan" = "probe"; then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if C compiler supports THREADSAN" >&5
+$as_echo_n "checking if C compiler supports THREADSAN... " >&6; }
+	OLD_CFLAGS="$CFLAGS"
+	OLD_LDFLAGS="$LDFLAGS"
+	THREADSAN_FLAGS="-fsanitize=thread"
+	CFLAGS="$CFLAGS $THREADSAN_FLAGS"
+	LDFLAGS="$LDFLAGS $THREADSAN_FLAGS"
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+		threadsan_cflags=$THREADSAN_FLAGS
+		threadsan_ldflags=$THREADSAN_FLAGS
+		have_threadsan=yes
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	CFLAGS="${OLD_CFLAGS}"
+	LDFLAGS="${OLD_LDFLAGS}"
+
+
+
+fi
+if test "$enable_threadsan" = "yes" && test "$have_threadsan" != "yes"; then
+	as_fn_error $? "THREADSAN not supported by compiler." "$LINENO" 5
+fi
+if test "$have_threadsan" = "yes" && test "$have_addrsan" = "yes"; then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ADDRSAN and THREADSAN are not known to work together." >&5
+$as_echo "$as_me: WARNING: ADDRSAN and THREADSAN are not known to work together." >&2;}
+fi
 LINUX_CMT="#"
 CYGWIN_CMT="#"
 UNIX_CMT=
@@ -13736,6 +14065,8 @@
 
 
 
+E2SCRUB_CMT="$LINUX_CMT"
+
 case "$host_os" in
 linux* | gnu* | k*bsd*-gnu)
 	if test "$prefix" = NONE -a "$root_prefix" = NONE ; then
@@ -13812,6 +14143,7 @@
 fi
 
 fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can link with -static" >&5
 $as_echo_n "checking whether we can link with -static... " >&6; }
 if ${ac_cv_e2fsprogs_use_static+:} false; then :
@@ -13888,6 +14220,282 @@
 
 
 
+
+
+# Check whether --with-udev_rules_dir was given.
+if test "${with_udev_rules_dir+set}" = set; then :
+  withval=$with_udev_rules_dir;
+else
+  with_udev_rules_dir=yes
+fi
+
+if test "x${with_udev_rules_dir}" != "xno"; then :
+
+	if test "x${with_udev_rules_dir}" = "xyes"; then :
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for udev" >&5
+$as_echo_n "checking for udev... " >&6; }
+
+if test -n "$udev_CFLAGS"; then
+    pkg_cv_udev_CFLAGS="$udev_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"udev\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "udev") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_udev_CFLAGS=`$PKG_CONFIG --cflags "udev" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$udev_LIBS"; then
+    pkg_cv_udev_LIBS="$udev_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"udev\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "udev") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_udev_LIBS=`$PKG_CONFIG --libs "udev" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        udev_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "udev" 2>&1`
+        else
+	        udev_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "udev" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$udev_PKG_ERRORS" >&5
+
+
+			with_udev_rules_dir=""
+
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+			with_udev_rules_dir=""
+
+else
+	udev_CFLAGS=$pkg_cv_udev_CFLAGS
+	udev_LIBS=$pkg_cv_udev_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+			with_udev_rules_dir="$($PKG_CONFIG --variable=udevdir udev)/rules.d"
+
+fi
+
+fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for udev rules dir" >&5
+$as_echo_n "checking for udev rules dir... " >&6; }
+	pkg_udev_rules_dir="${with_udev_rules_dir}"
+	if test -n "${pkg_udev_rules_dir}"; then :
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${pkg_udev_rules_dir}" >&5
+$as_echo "${pkg_udev_rules_dir}" >&6; }
+		have_udev="yes"
+
+else
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		have_udev="no"
+
+fi
+
+else
+
+	have_udev="disabled"
+
+fi
+
+
+
+
+# Check whether --with-crond_dir was given.
+if test "${with_crond_dir+set}" = set; then :
+  withval=$with_crond_dir;
+else
+  with_crond_dir=yes
+fi
+
+if test "x${with_crond_dir}" != "xno"; then :
+
+	if test "x${with_crond_dir}" = "xyes"; then :
+
+		if test -d "/etc/cron.d"; then :
+  with_crond_dir="/etc/cron.d"
+fi
+
+fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for system crontab dir" >&5
+$as_echo_n "checking for system crontab dir... " >&6; }
+	crond_dir="${with_crond_dir}"
+	if test -n "${crond_dir}"; then :
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${crond_dir}" >&5
+$as_echo "${crond_dir}" >&6; }
+		have_crond="yes"
+
+else
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		have_crond="no"
+
+fi
+
+else
+
+	have_crond="disabled"
+
+fi
+
+
+
+
+# Check whether --with-systemd_unit_dir was given.
+if test "${with_systemd_unit_dir+set}" = set; then :
+  withval=$with_systemd_unit_dir;
+else
+  with_systemd_unit_dir=yes
+fi
+
+if test "x${with_systemd_unit_dir}" != "xno"; then :
+
+	if test "x${with_systemd_unit_dir}" = "xyes"; then :
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for systemd" >&5
+$as_echo_n "checking for systemd... " >&6; }
+
+if test -n "$systemd_CFLAGS"; then
+    pkg_cv_systemd_CFLAGS="$systemd_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "systemd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_systemd_CFLAGS=`$PKG_CONFIG --cflags "systemd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$systemd_LIBS"; then
+    pkg_cv_systemd_LIBS="$systemd_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "systemd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_systemd_LIBS=`$PKG_CONFIG --libs "systemd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        systemd_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "systemd" 2>&1`
+        else
+	        systemd_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "systemd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$systemd_PKG_ERRORS" >&5
+
+
+			with_systemd_unit_dir=""
+
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+			with_systemd_unit_dir=""
+
+else
+	systemd_CFLAGS=$pkg_cv_systemd_CFLAGS
+	systemd_LIBS=$pkg_cv_systemd_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+			with_systemd_unit_dir="$($PKG_CONFIG --variable=systemdsystemunitdir systemd)"
+
+fi
+
+
+fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for systemd system unit dir" >&5
+$as_echo_n "checking for systemd system unit dir... " >&6; }
+	systemd_system_unit_dir="${with_systemd_unit_dir}"
+	if test -n "${systemd_system_unit_dir}"; then :
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${systemd_system_unit_dir}" >&5
+$as_echo "${systemd_system_unit_dir}" >&6; }
+		have_systemd="yes"
+
+else
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		have_systemd="no"
+
+fi
+
+else
+
+	have_systemd="disabled"
+
+fi
+
+
+
 test -d lib || mkdir lib
 test -d include || mkdir include
 test -d include/linux || mkdir include/linux
@@ -13909,7 +14517,7 @@
 	misc/Makefile ext2ed/Makefile e2fsck/Makefile \
 	debugfs/Makefile tests/Makefile tests/progs/Makefile \
 	resize/Makefile doc/Makefile intl/Makefile \
-	intl/libgnuintl.h po/Makefile.in ; do
+	intl/libgnuintl.h po/Makefile.in scrub/Makefile; do
 	if test -d `dirname ${srcdir}/$i` ; then
 		outlist="$outlist $i"
 	fi
diff --git a/configure.ac b/configure.ac
index 51a446d..c378b81 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11,11 +11,11 @@
 dnl
 E2FSPROGS_VERSION=`grep E2FSPROGS_VERSION ${srcdir}/version.h  \
 	| awk '{print $3}' | tr \" " " | awk '{print $1}'`
-DATE=`grep E2FSPROGS_DATE ${srcdir}/version.h | awk '{print $3}' \
-	| tr \" " "`
-E2FSPROGS_DAY=$(echo $DATE | awk -F- '{print $1}' | sed -e '/^[[1-9]]$/s/^/0/')
-MONTH=`echo $DATE | awk -F- '{print $2}'`
-YEAR=`echo $DATE | awk -F- '{print $3}'`
+E2FSPROGS_DATE=`grep E2FSPROGS_DATE ${srcdir}/version.h | awk '{print $3}' \
+	| tr \" " " | awk '{print $1}'`
+E2FSPROGS_DAY=$(echo $E2FSPROGS_DATE | awk -F- '{print $1}' | sed -e '/^[[1-9]]$/s/^/0/')
+MONTH=`echo $E2FSPROGS_DATE | awk -F- '{print $2}'`
+YEAR=`echo $E2FSPROGS_DATE | awk -F- '{print $3}'`
 
 if expr $YEAR ">" 1900 > /dev/null ; then
 	E2FSPROGS_YEAR=$YEAR
@@ -63,6 +63,7 @@
 AC_SUBST(E2FSPROGS_DAY)
 AC_SUBST(E2FSPROGS_VERSION)
 AC_SUBST(E2FSPROGS_PKGVER)
+AC_SUBST(E2FSPROGS_DATE)
 dnl
 dnl Use diet libc
 dnl 
@@ -1314,6 +1315,127 @@
 	;;
 esac
 dnl
+dnl Enable LTO for all packages
+dnl
+AC_ARG_ENABLE([lto],
+[  --enable-lto		  enable link time optimization],,
+enable_lto=no)
+if test "$enable_lto" = "yes" || test "$enable_lto" = "probe"; then
+	AC_MSG_CHECKING([if C compiler supports LTO])
+	OLD_CFLAGS="$CFLAGS"
+	OLD_LDFLAGS="$LDFLAGS"
+	LTO_FLAGS="-g -flto -ffat-lto-objects"
+	CFLAGS="$CFLAGS $LTO_FLAGS"
+	LDFLAGS="$LDFLAGS $LTO_FLAGS"
+	AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+		[AC_MSG_RESULT([yes])]
+		[lto_cflags=$LTO_FLAGS]
+		[lto_ldflags=$LTO_FLAGS]
+		[AC_PATH_PROG(gcc_ar, gcc-ar,,)]
+		[AC_PATH_PROG(gcc_ranlib, gcc-ranlib,,)],
+		[AC_MSG_RESULT([no])])
+	if test -x "$gcc_ar" && test -x "$gcc_ranlib"; then
+		have_lto=yes
+		AR="${gcc_ar}"
+		RANLIB="${gcc_ranlib}"
+	fi
+	CFLAGS="${OLD_CFLAGS}"
+	LDFLAGS="${OLD_LDFLAGS}"
+	AC_SUBST(have_lto)
+	AC_SUBST(lto_cflags)
+	AC_SUBST(lto_ldflags)
+fi
+if test "$enable_lto" = "yes" && test "$have_lto" != "yes"; then
+	AC_MSG_ERROR([LTO not supported by compiler.])
+fi
+dnl
+dnl Enable UBSAN for all packages
+dnl
+AC_ARG_ENABLE([ubsan],
+[  --enable-ubsan	  enable undefined behavior sanitizer],,
+enable_ubsan=no)
+if test "$enable_ubsan" = "yes" || test "$enable_ubsan" = "probe"; then
+	AC_MSG_CHECKING([if C compiler supports UBSAN])
+	OLD_CFLAGS="$CFLAGS"
+	OLD_LDFLAGS="$LDFLAGS"
+	UBSAN_FLAGS="-fsanitize=undefined"
+	CFLAGS="$CFLAGS $UBSAN_FLAGS"
+	LDFLAGS="$LDFLAGS $UBSAN_FLAGS"
+	AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+		[AC_MSG_RESULT([yes])]
+		[ubsan_cflags=$UBSAN_FLAGS]
+		[ubsan_ldflags=$UBSAN_FLAGS]
+		[have_ubsan=yes],
+		[AC_MSG_RESULT([no])])
+	CFLAGS="${OLD_CFLAGS}"
+	LDFLAGS="${OLD_LDFLAGS}"
+	AC_SUBST(have_ubsan)
+	AC_SUBST(ubsan_cflags)
+	AC_SUBST(ubsan_ldflags)
+fi
+if test "$enable_ubsan" = "yes" && test "$have_ubsan" != "yes"; then
+	AC_MSG_ERROR([UBSAN not supported by compiler.])
+fi
+dnl
+dnl Enable ADDRSAN for all packages
+dnl
+AC_ARG_ENABLE([addrsan],
+[  --enable-addrsan	  enable address sanitizer],,
+enable_addrsan=no)
+if test "$enable_addrsan" = "yes" || test "$enable_addrsan" = "probe"; then
+	AC_MSG_CHECKING([if C compiler supports ADDRSAN])
+	OLD_CFLAGS="$CFLAGS"
+	OLD_LDFLAGS="$LDFLAGS"
+	ADDRSAN_FLAGS="-fsanitize=address"
+	CFLAGS="$CFLAGS $ADDRSAN_FLAGS"
+	LDFLAGS="$LDFLAGS $ADDRSAN_FLAGS"
+	AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+		[AC_MSG_RESULT([yes])]
+		[addrsan_cflags=$ADDRSAN_FLAGS]
+		[addrsan_ldflags=$ADDRSAN_FLAGS]
+		[have_addrsan=yes],
+		[AC_MSG_RESULT([no])])
+	CFLAGS="${OLD_CFLAGS}"
+	LDFLAGS="${OLD_LDFLAGS}"
+	AC_SUBST(have_addrsan)
+	AC_SUBST(addrsan_cflags)
+	AC_SUBST(addrsan_ldflags)
+fi
+if test "$enable_addrsan" = "yes" && test "$have_addrsan" != "yes"; then
+	AC_MSG_ERROR([ADDRSAN not supported by compiler.])
+fi
+dnl
+dnl Enable THREADSAN for all packages
+dnl
+AC_ARG_ENABLE([threadsan],
+[  --enable-threadsan	  enable thread sanitizer],,
+enable_threadsan=no)
+if test "$enable_threadsan" = "yes" || test "$enable_threadsan" = "probe"; then
+	AC_MSG_CHECKING([if C compiler supports THREADSAN])
+	OLD_CFLAGS="$CFLAGS"
+	OLD_LDFLAGS="$LDFLAGS"
+	THREADSAN_FLAGS="-fsanitize=thread"
+	CFLAGS="$CFLAGS $THREADSAN_FLAGS"
+	LDFLAGS="$LDFLAGS $THREADSAN_FLAGS"
+	AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+		[AC_MSG_RESULT([yes])]
+		[threadsan_cflags=$THREADSAN_FLAGS]
+		[threadsan_ldflags=$THREADSAN_FLAGS]
+		[have_threadsan=yes],
+		[AC_MSG_RESULT([no])])
+	CFLAGS="${OLD_CFLAGS}"
+	LDFLAGS="${OLD_LDFLAGS}"
+	AC_SUBST(have_threadsan)
+	AC_SUBST(threadsan_cflags)
+	AC_SUBST(threadsan_ldflags)
+fi
+if test "$enable_threadsan" = "yes" && test "$have_threadsan" != "yes"; then
+	AC_MSG_ERROR([THREADSAN not supported by compiler.])
+fi
+if test "$have_threadsan" = "yes" && test "$have_addrsan" = "yes"; then
+	AC_MSG_WARN([ADDRSAN and THREADSAN are not known to work together.])
+fi
+dnl
 dnl OS-specific uncomment control
 dnl
 LINUX_CMT="#"
@@ -1332,6 +1454,11 @@
 AC_SUBST(CYGWIN_CMT)
 AC_SUBST(UNIX_CMT)
 dnl
+dnl e2scrub only builds on linux
+dnl
+E2SCRUB_CMT="$LINUX_CMT"
+AC_SUBST(E2SCRUB_CMT)
+dnl
 dnl Linux and Hurd places root files in the / by default
 dnl
 case "$host_os" in
@@ -1406,7 +1533,8 @@
     libdir=$libdir/$withval
     root_libdir=$root_libdir/$withval
 fi
-)dnl
+)
+dnl
 dnl
 dnl See if -static works.  This could fail if the linker does not
 dnl support -static, or if required external libraries are not available
@@ -1488,6 +1616,115 @@
 AC_SUBST(CFLAGS_SHLIB)
 AC_SUBST(CFLAGS_STLIB)
 AC_SUBST(LDFLAGS_SHLIB)
+
+dnl
+dnl Where do udev rules go?
+dnl
+AC_ARG_WITH([udev_rules_dir],
+  [AS_HELP_STRING([--with-udev-rules-dir@<:@=DIR@:>@],
+	[Install udev rules into DIR.])],
+  [],
+  [with_udev_rules_dir=yes])
+AS_IF([test "x${with_udev_rules_dir}" != "xno"],
+  [
+	AS_IF([test "x${with_udev_rules_dir}" = "xyes"],
+	  [
+		PKG_CHECK_MODULES([udev], [udev],
+		  [
+			with_udev_rules_dir="$($PKG_CONFIG --variable=udevdir udev)/rules.d"
+		  ], [
+			with_udev_rules_dir=""
+		  ])
+	  ])
+	AC_MSG_CHECKING([for udev rules dir])
+	pkg_udev_rules_dir="${with_udev_rules_dir}"
+	AS_IF([test -n "${pkg_udev_rules_dir}"],
+	  [
+		AC_MSG_RESULT(${pkg_udev_rules_dir})
+		have_udev="yes"
+	  ],
+	  [
+		AC_MSG_RESULT(no)
+		have_udev="no"
+	  ])
+  ],
+  [
+	have_udev="disabled"
+  ])
+AC_SUBST(have_udev)
+AC_SUBST(pkg_udev_rules_dir)
+
+dnl
+dnl Where do cron jobs go?
+dnl
+AC_ARG_WITH([crond_dir],
+  [AS_HELP_STRING([--with-crond-dir@<:@=DIR@:>@],
+	[Install system crontabs into DIR.])],
+  [],
+  [with_crond_dir=yes])
+AS_IF([test "x${with_crond_dir}" != "xno"],
+  [
+	AS_IF([test "x${with_crond_dir}" = "xyes"],
+	  [
+		AS_IF([test -d "/etc/cron.d"],
+		  [with_crond_dir="/etc/cron.d"])
+	  ])
+	AC_MSG_CHECKING([for system crontab dir])
+	crond_dir="${with_crond_dir}"
+	AS_IF([test -n "${crond_dir}"],
+	  [
+		AC_MSG_RESULT(${crond_dir})
+		have_crond="yes"
+	  ],
+	  [
+		AC_MSG_RESULT(no)
+		have_crond="no"
+	  ])
+  ],
+  [
+	have_crond="disabled"
+  ])
+AC_SUBST(have_crond)
+AC_SUBST(crond_dir)
+
+dnl
+dnl Where do systemd services go?
+dnl
+AC_ARG_WITH([systemd_unit_dir],
+  [AS_HELP_STRING([--with-systemd-unit-dir@<:@=DIR@:>@],
+	[Install systemd system units into DIR.])],
+  [],
+  [with_systemd_unit_dir=yes])
+AS_IF([test "x${with_systemd_unit_dir}" != "xno"],
+  [
+	AS_IF([test "x${with_systemd_unit_dir}" = "xyes"],
+	  [
+		PKG_CHECK_MODULES([systemd], [systemd],
+		  [
+			with_systemd_unit_dir="$($PKG_CONFIG --variable=systemdsystemunitdir systemd)"
+		  ], [
+			with_systemd_unit_dir=""
+		  ])
+		m4_pattern_allow([^PKG_(MAJOR|MINOR|BUILD|REVISION)$])
+	  ])
+	AC_MSG_CHECKING([for systemd system unit dir])
+	systemd_system_unit_dir="${with_systemd_unit_dir}"
+	AS_IF([test -n "${systemd_system_unit_dir}"],
+	  [
+		AC_MSG_RESULT(${systemd_system_unit_dir})
+		have_systemd="yes"
+	  ],
+	  [
+		AC_MSG_RESULT(no)
+		have_systemd="no"
+	  ])
+  ],
+  [
+	have_systemd="disabled"
+  ])
+AC_SUBST(have_systemd)
+AC_SUBST(systemd_system_unit_dir)
+
 dnl
 dnl Make our output files, being sure that we create the some miscellaneous 
 dnl directories
@@ -1513,7 +1750,7 @@
 	misc/Makefile ext2ed/Makefile e2fsck/Makefile \
 	debugfs/Makefile tests/Makefile tests/progs/Makefile \
 	resize/Makefile doc/Makefile intl/Makefile \
-	intl/libgnuintl.h po/Makefile.in ; do
+	intl/libgnuintl.h po/Makefile.in scrub/Makefile; do
 	if test -d `dirname ${srcdir}/$i` ; then
 		outlist="$outlist $i"
 	fi
diff --git a/debian/compat b/debian/compat
index ec63514..b4de394 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-9
+11
diff --git a/debian/control b/debian/control
index 054b5ac..e40a84b 100644
--- a/debian/control
+++ b/debian/control
@@ -191,7 +191,7 @@
 Pre-Depends: ${shlibs:Depends}, ${misc:Depends}, libblkid1, libuuid1
 Multi-Arch: foreign
 Suggests: gpart, parted, fuse2fs, e2fsck-static
-Recommends: e2fsprogs-l10n
+Recommends: e2fsprogs-l10n, lvm2, util-linux, coreutils
 Architecture: any
 Description: ext2/ext3/ext4 file system utilities
  The ext2, ext3 and ext4 file systems are successors of the original ext
diff --git a/debian/e2fsprogs.files b/debian/e2fsprogs.files
index 0a22f31..e0e49ce 100644
--- a/debian/e2fsprogs.files
+++ b/debian/e2fsprogs.files
@@ -1,5 +1,9 @@
 sbin
 usr/bin
+usr/lib
 usr/sbin
 usr/share/man
 etc
+lib/udev/rules.d
+lib/systemd/system
+usr/lib
diff --git a/debian/e2fsprogs.postinst.dh9 b/debian/e2fsprogs.postinst.dh9
new file mode 100644
index 0000000..e7acb0e
--- /dev/null
+++ b/debian/e2fsprogs.postinst.dh9
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Abort on error.
+set -e
+
+if [ -x /usr/sbin/update-initramfs -a \
+	-e /etc/initramfs-tools/initramfs.conf ]; then
+    update-initramfs -u
+fi
+
+#DEBHELPER#
+
+# debhelper doesn't know what timers are...
+update_svc() {
+	deb-systemd-helper unmask "$1" >/dev/null || true
+
+	if deb-systemd-helper --quiet was-enabled "$1"; then
+		deb-systemd-helper enable "$1" >/dev/null || true
+	else
+		deb-systemd-helper update-state "$1" >/dev/null || true
+	fi
+}
+update_svc e2scrub_all.timer
+update_svc e2scrub_reap.service
+
+# Start our new services
+if [ -d /run/systemd/system ]; then
+	systemctl --system daemon-reload >/dev/null || true
+	deb-systemd-invoke start e2scrub_all.timer >/dev/null || true
+fi
+
+exit 0
diff --git a/debian/e2fsprogs.postrm.dh9 b/debian/e2fsprogs.postrm.dh9
new file mode 100644
index 0000000..32cb642
--- /dev/null
+++ b/debian/e2fsprogs.postrm.dh9
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+update_svc() {
+	deb-systemd-helper mask "$1" >/dev/null || true
+
+	if deb-systemd-helper --quiet was-enabled "$1"; then
+		# Enables the unit on first installation, creates new
+		# symlinks on upgrades if the unit file has changed.
+		deb-systemd-helper disable "$1" >/dev/null || true
+	fi
+}
+
+if [ "$1" != "upgrade" ]; then
+	# Abort on error.
+	set -e
+
+	if [ -x /usr/sbin/update-initramfs -a \
+		-e /etc/initramfs-tools/initramfs.conf ]; then
+	    update-initramfs -u
+	fi
+
+	#DEBHELPER#
+
+	# debhelper doesn't know what timers are...
+	update_svc e2scrub_all.timer
+	update_svc e2scrub_reap.service
+
+	# Start our new services
+	if [ -d /run/systemd/system ]; then
+		deb-systemd-invoke stop e2scrub_all.timer >/dev/null || true
+	fi
+fi
+
+exit 0
+
diff --git a/debian/rules b/debian/rules
index 36085bb..d75ce76 100755
--- a/debian/rules
+++ b/debian/rules
@@ -47,6 +47,8 @@
 
 DH_VERSION := $(shell dpkg-query -W -f '$${Version}' debhelper)
 
+USE_DH9 ?= $(shell if dpkg --compare-versions $(DH_VERSION) lt 11 ; then echo yes ; fi)
+
 # USE_DBGSYM :=
 USE_DBGSYM ?= $(shell if dpkg --compare-versions $(DH_VERSION) ">=" 9.20160114 ; then echo yes ; fi)
 
@@ -99,6 +101,7 @@
 UDEB_PRIORITY	?= $(shell grep '^Package: e2fsprogs-udeb' debian/control -A 10 | grep ^Priority: | cut -d ' ' -f 2)
 
 STAMPSDIR	?= debian/stampdir
+CFGDH		?= ${STAMPSDIR}/configure-dh
 CFGSTDSTAMP	?= ${STAMPSDIR}/configure-std-stamp
 CFGBFSTAMP	?= ${STAMPSDIR}/configure-bf-stamp
 BUILDSTDSTAMP	?= ${STAMPSDIR}/build-std-stamp
@@ -164,7 +167,8 @@
 
 BACKTRACE_CONF_FLAGS ?= $(shell if ${debdir}/scripts/test-backtrace ; then echo --disable-backtrace ; fi)
 
-COMMON_CONF_FLAGS = --disable-e2initrd-helper \
+COMMON_CONF_FLAGS = --enable-lto --disable-ubsan --disable-addrsan \
+	--disable-threadsan --disable-e2initrd-helper \
 	--infodir=/usr/share/info  --enable-symlink-install \
 	--with-multiarch=$(DEB_HOST_MULTIARCH) \
 	$(BACKTRACE_CONF_FLAGS) $(UTIL_CONF_FLAGS)
@@ -195,7 +199,18 @@
 		mv debian/control.save debian/control ; \
 	fi
 
-${CFGSTDSTAMP}:
+${CFGDH}:
+ifeq ($(USE_DH9),yes)
+	mv debian/compat debian/compat.save
+	echo 9 > debian/compat
+	mv debian/e2fsprogs.postinst debian/e2fsprogs.postinst.save
+	cp debian/e2fsprogs.postinst.dh9 debian/e2fsprogs.postinst
+	cp debian/e2fsprogs.postrm.dh9 debian/e2fsprogs.postrm
+endif
+	mkdir -p ${STAMPSDIR}
+	touch ${CFGDH}
+
+${CFGSTDSTAMP}: ${CFGDH}
 	dh_testdir
 	if which dh_update_autotools_config > /dev/null 2>&1 ; then \
 		dh_update_autotools_config ;\
@@ -228,7 +243,7 @@
 	mkdir -p ${STAMPSDIR}
 	touch ${CFGSTDSTAMP}
 
-${CFGBFSTAMP}:
+${CFGBFSTAMP}: ${CFGDH}
 	dh_testdir
 	if which dh_update_autotools_config > /dev/null 2>&1 ; then \
 		dh_update_autotools_config ;\
@@ -300,6 +315,15 @@
 		mv debian/orig-gmo/* po ; \
 		rmdir debian/orig-gmo ; \
 	fi
+	if test -f debian/compat.save; then \
+		mv debian/compat.save debian/compat ; \
+	fi
+	if test -f debian/e2fsprogs.postinst.save; then \
+		mv debian/e2fsprogs.postinst.save debian/e2fsprogs.postinst ; \
+	fi
+	if test -f debian/e2fsprogs.postrm; then \
+		rm -f debian/e2fsprogs.postrm ; \
+	fi
 	rm -rf ${STAMPSDIR}
 	[ ! -f ${stdbuilddir}/Makefile ] || $(MAKE) -C ${stdbuilddir} V=1 distclean
 	[ ! -f ${bfbuilddir}/Makefile ] || $(MAKE) -C ${bfbuilddir} V=1 distclean
@@ -440,7 +464,9 @@
 	dh_compress -a
 
 	dh_makeshlibs -a --add-udeb=e2fsprogs-udeb
-
+ifneq ($(USE_DH9),yes)
+	dh_installsystemd -p e2fsprogs
+endif
 	$(INSTALL) -D -p -m644 debian/e2fsprogs-udeb.lintian-overrides \
 	    debian/e2fsprogs-udeb/usr/share/lintian/overrides/e2fsprogs-udeb
 	dh_installdeb -a
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 0b04508..e03519c 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -50,7 +50,7 @@
 
 ss_request_table *extra_cmds;
 const char *debug_prog_name;
-int sci_idx;
+int ss_sci_idx;
 
 ext2_filsys	current_fs;
 quota_ctx_t	current_qctx;
@@ -218,7 +218,8 @@
 		com_err(device, retval, "while trying to close filesystem");
 }
 
-void do_open_filesys(int argc, char **argv)
+void do_open_filesys(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		     void *infop EXT2FS_ATTR((unused)))
 {
 	int	c, err;
 	int	catastrophic = 0;
@@ -294,7 +295,8 @@
 		"<device>\n", argv[0]);
 }
 
-void do_lcd(int argc, char **argv)
+void do_lcd(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+	    void *infop EXT2FS_ATTR((unused)))
 {
 	if (argc != 2) {
 		com_err(argv[0], 0, "Usage: %s %s", argv[0], "<native dir>");
@@ -331,7 +333,8 @@
 	return;
 }
 
-void do_close_filesys(int argc, char **argv)
+void do_close_filesys(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		      void *infop EXT2FS_ATTR((unused)))
 {
 	int	c;
 
@@ -359,7 +362,8 @@
 }
 
 #ifndef READ_ONLY
-void do_init_filesys(int argc, char **argv)
+void do_init_filesys(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		     void *infop EXT2FS_ATTR((unused)))
 {
 	struct ext2_super_block param;
 	errcode_t	retval;
@@ -419,7 +423,9 @@
 	}
 }
 
-void do_show_super_stats(int argc, char *argv[])
+void do_show_super_stats(int argc, char *argv[],
+			 int sci_idx EXT2FS_ATTR((unused)),
+			 void *infop EXT2FS_ATTR((unused)))
 {
 	const char *units ="block";
 	dgrp_t	i;
@@ -514,7 +520,9 @@
 
 #ifndef READ_ONLY
 void do_dirty_filesys(int argc EXT2FS_ATTR((unused)),
-		      char **argv EXT2FS_ATTR((unused)))
+		      char **argv EXT2FS_ATTR((unused)),
+		      int sci_idx EXT2FS_ATTR((unused)),
+		      void *infop EXT2FS_ATTR((unused)))
 {
 	if (check_fs_open(argv[0]))
 		return;
@@ -965,7 +973,8 @@
 	close_pager(out);
 }
 
-void do_stat(int argc, char *argv[])
+void do_stat(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	inode;
 	struct ext2_inode * inode_buf;
@@ -996,7 +1005,8 @@
 	return;
 }
 
-void do_dump_extents(int argc, char **argv)
+void do_dump_extents(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		     void *infop EXT2FS_ATTR((unused)))
 {
 	struct ext2_inode inode;
 	ext2_ino_t	ino;
@@ -1067,7 +1077,8 @@
 	return 0;
 }
 
-void do_blocks(int argc, char *argv[])
+void do_blocks(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	       void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	inode;
 
@@ -1084,7 +1095,8 @@
 	return;
 }
 
-void do_chroot(int argc, char *argv[])
+void do_chroot(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	       void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t inode;
 	int retval;
@@ -1101,7 +1113,8 @@
 }
 
 #ifndef READ_ONLY
-void do_clri(int argc, char *argv[])
+void do_clri(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t inode;
 	struct ext2_inode inode_buf;
@@ -1116,7 +1129,8 @@
 		return;
 }
 
-void do_freei(int argc, char *argv[])
+void do_freei(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int	len = 1;
 	int		err = 0;
@@ -1146,7 +1160,8 @@
 	ext2fs_mark_ib_dirty(current_fs);
 }
 
-void do_seti(int argc, char *argv[])
+void do_seti(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int	len = 1;
 	int		err = 0;
@@ -1177,7 +1192,8 @@
 }
 #endif /* READ_ONLY */
 
-void do_testi(int argc, char *argv[])
+void do_testi(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t inode;
 
@@ -1191,7 +1207,8 @@
 }
 
 #ifndef READ_ONLY
-void do_freeb(int argc, char *argv[])
+void do_freeb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	blk64_t block;
 	blk64_t count = 1;
@@ -1210,7 +1227,8 @@
 	ext2fs_mark_bb_dirty(current_fs);
 }
 
-void do_setb(int argc, char *argv[])
+void do_setb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	blk64_t block;
 	blk64_t count = 1;
@@ -1230,7 +1248,8 @@
 }
 #endif /* READ_ONLY */
 
-void do_testb(int argc, char *argv[])
+void do_testb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	blk64_t block;
 	blk64_t count = 1;
@@ -1314,7 +1333,8 @@
 }
 
 
-void do_modify_inode(int argc, char *argv[])
+void do_modify_inode(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		     void *infop EXT2FS_ATTR((unused)))
 {
 	struct ext2_inode inode;
 	ext2_ino_t	inode_num;
@@ -1391,7 +1411,9 @@
 }
 #endif /* READ_ONLY */
 
-void do_change_working_dir(int argc, char *argv[])
+void do_change_working_dir(int argc, char *argv[],
+			   int sci_idx EXT2FS_ATTR((unused)),
+			   void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	inode;
 	int		retval;
@@ -1408,7 +1430,9 @@
 	return;
 }
 
-void do_print_working_directory(int argc, char *argv[])
+void do_print_working_directory(int argc, char *argv[],
+				int sci_idx EXT2FS_ATTR((unused)),
+				void *infop EXT2FS_ATTR((unused)))
 {
 	int	retval;
 	char	*pathname = NULL;
@@ -1497,7 +1521,8 @@
 }
 
 
-void do_link(int argc, char *argv[])
+void do_link(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	if (common_args_process(argc, argv, 3, 3, "link",
 				"<source file> <dest_name>", CHECK_FS_RW))
@@ -1519,7 +1544,8 @@
 	return 0;
 }
 
-void do_undel(int argc, char *argv[])
+void do_undel(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	ino;
 	struct ext2_inode inode;
@@ -1582,7 +1608,8 @@
 	return;
 }
 
-void do_unlink(int argc, char *argv[])
+void do_unlink(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	       void *infop EXT2FS_ATTR((unused)))
 {
 	if (common_args_process(argc, argv, 2, 2, "link",
 				"<pathname>", CHECK_FS_RW))
@@ -1591,7 +1618,8 @@
 	unlink_file_by_name(argv[1]);
 }
 
-void do_copy_inode(int argc, char *argv[])
+void do_copy_inode(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		   void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	src_ino, dest_ino;
 	unsigned char	buf[4096];
@@ -1619,7 +1647,9 @@
 
 #endif /* READ_ONLY */
 
-void do_find_free_block(int argc, char *argv[])
+void do_find_free_block(int argc, char *argv[],
+			int sci_idx EXT2FS_ATTR((unused)),
+			void *infop EXT2FS_ATTR((unused)))
 {
 	blk64_t	free_blk, goal, first_free = 0;
  	int		count;
@@ -1671,7 +1701,9 @@
  	printf("\n");
 }
 
-void do_find_free_inode(int argc, char *argv[])
+void do_find_free_inode(int argc, char *argv[],
+			int sci_idx EXT2FS_ATTR((unused)),
+			void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	free_inode, dir;
 	int		mode;
@@ -1711,7 +1743,8 @@
 }
 
 #ifndef READ_ONLY
-void do_write(int argc, char *argv[])
+void do_write(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t	retval;
 
@@ -1724,7 +1757,8 @@
 		com_err(argv[0], retval, 0);
 }
 
-void do_mknod(int argc, char *argv[])
+void do_mknod(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned long	major, minor;
 	errcode_t 	retval;
@@ -1774,7 +1808,8 @@
 		com_err(argv[0], retval, 0);
 }
 
-void do_mkdir(int argc, char *argv[])
+void do_mkdir(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t retval;
 
@@ -1827,7 +1862,8 @@
 }
 
 
-void do_kill_file(int argc, char *argv[])
+void do_kill_file(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t inode_num;
 
@@ -1837,7 +1873,8 @@
 	kill_file_by_inode(inode_num);
 }
 
-void do_rm(int argc, char *argv[])
+void do_rm(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	   void *infop EXT2FS_ATTR((unused)))
 {
 	int retval;
 	ext2_ino_t inode_num;
@@ -1898,7 +1935,8 @@
 	return 0;
 }
 
-void do_rmdir(int argc, char *argv[])
+void do_rmdir(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	int retval;
 	ext2_ino_t inode_num;
@@ -1956,7 +1994,9 @@
 #endif /* READ_ONLY */
 
 void do_show_debugfs_params(int argc EXT2FS_ATTR((unused)),
-			    char *argv[] EXT2FS_ATTR((unused)))
+			    char *argv[] EXT2FS_ATTR((unused)),
+			    int sci_idx EXT2FS_ATTR((unused)),
+			    void *infop EXT2FS_ATTR((unused)))
 {
 	if (current_fs)
 		printf("Open mode: read-%s\n",
@@ -1966,7 +2006,8 @@
 }
 
 #ifndef READ_ONLY
-void do_expand_dir(int argc, char *argv[])
+void do_expand_dir(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t inode;
 	int retval;
@@ -1980,7 +2021,8 @@
 	return;
 }
 
-void do_features(int argc, char *argv[])
+void do_features(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	int	i;
 
@@ -2001,7 +2043,8 @@
 }
 #endif /* READ_ONLY */
 
-void do_bmap(int argc, char *argv[])
+void do_bmap(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	ino;
 	blk64_t		blk, pblk = 0;
@@ -2064,7 +2107,8 @@
 	fputc('\n', stdout);
 }
 
-void do_imap(int argc, char *argv[])
+void do_imap(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	ino;
 	unsigned long 	group, block, block_nr, offset;
@@ -2095,7 +2139,8 @@
 
 }
 
-void do_idump(int argc, char *argv[])
+void do_idump(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	struct ext2_inode_large *inode;
 	ext2_ino_t	ino;
@@ -2165,7 +2210,9 @@
 }
 
 #ifndef READ_ONLY
-void do_set_current_time(int argc, char *argv[])
+void do_set_current_time(int argc, char *argv[],
+			 int sci_idx EXT2FS_ATTR((unused)),
+			 void *infop EXT2FS_ATTR((unused)))
 {
 	__s64 now;
 
@@ -2224,7 +2271,9 @@
 	return 0;
 }
 
-void do_supported_features(int argc, char *argv[])
+void do_supported_features(int argc, char *argv[],
+			   int sci_idx EXT2FS_ATTR((unused)),
+			   void *infop EXT2FS_ATTR((unused)))
 {
         int	ret;
 	__u32	supp[3] = { EXT2_LIB_FEATURE_COMPAT_SUPP,
@@ -2252,7 +2301,8 @@
 }
 
 #ifndef READ_ONLY
-void do_punch(int argc, char *argv[])
+void do_punch(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	ino;
 	blk64_t		start, end;
@@ -2287,7 +2337,8 @@
 	}
 }
 
-void do_fallocate(int argc, char *argv[])
+void do_fallocate(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	ino;
 	blk64_t		start, end;
@@ -2324,7 +2375,8 @@
 }
 #endif /* READ_ONLY */
 
-void do_symlink(int argc, char *argv[])
+void do_symlink(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t	retval;
 
@@ -2339,7 +2391,9 @@
 }
 
 #if CONFIG_MMP
-void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[])
+void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[],
+		 int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	struct mmp_struct *mmp_s;
 	unsigned long long mmp_block;
@@ -2399,7 +2453,9 @@
 }
 #else
 void do_dump_mmp(int argc EXT2FS_ATTR((unused)),
-		 char *argv[] EXT2FS_ATTR((unused)))
+		 char *argv[] EXT2FS_ATTR((unused)),
+		 int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	fprintf(stdout, "MMP is unsupported, please recompile with "
 	                "--enable-mmp\n");
@@ -2557,39 +2613,39 @@
 				superblock, blocksize, catastrophic,
 				data_filename, undo_file);
 
-	sci_idx = ss_create_invocation(debug_prog_name, "0.0", (char *) NULL,
-				       &debug_cmds, &retval);
+	ss_sci_idx = ss_create_invocation(debug_prog_name, "0.0", (char *) NULL,
+					  &debug_cmds, &retval);
 	if (retval) {
-		ss_perror(sci_idx, retval, "creating invocation");
+		ss_perror(ss_sci_idx, retval, "creating invocation");
 		exit(1);
 	}
-	ss_get_readline(sci_idx);
+	ss_get_readline(ss_sci_idx);
 
-	(void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval);
+	(void) ss_add_request_table(ss_sci_idx, &ss_std_requests, 1, &retval);
 	if (retval) {
-		ss_perror(sci_idx, retval, "adding standard requests");
+		ss_perror(ss_sci_idx, retval, "adding standard requests");
 		exit (1);
 	}
 	if (extra_cmds)
-		ss_add_request_table (sci_idx, extra_cmds, 1, &retval);
+		ss_add_request_table(ss_sci_idx, extra_cmds, 1, &retval);
 	if (retval) {
-		ss_perror(sci_idx, retval, "adding extra requests");
+		ss_perror(ss_sci_idx, retval, "adding extra requests");
 		exit (1);
 	}
 	if (request) {
 		retval = 0;
-		retval = ss_execute_line(sci_idx, request);
+		retval = ss_execute_line(ss_sci_idx, request);
 		if (retval) {
-			ss_perror(sci_idx, retval, request);
+			ss_perror(ss_sci_idx, retval, request);
 			exit_status++;
 		}
 	} else if (cmd_file) {
-		exit_status = source_file(cmd_file, sci_idx);
+		exit_status = source_file(cmd_file, ss_sci_idx);
 	} else {
-		ss_listen(sci_idx);
+		ss_listen(ss_sci_idx);
 	}
 
-	ss_delete_invocation(sci_idx);
+	ss_delete_invocation(ss_sci_idx);
 
 	if (current_fs)
 		close_filesystem();
diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
index 93f036d..d1d13b4 100644
--- a/debugfs/debugfs.h
+++ b/debugfs/debugfs.h
@@ -25,7 +25,7 @@
 extern ext2_filsys current_fs;
 extern quota_ctx_t current_qctx;
 extern ext2_ino_t	root, cwd;
-extern int sci_idx;
+extern int ss_sci_idx;
 extern ss_request_table debug_cmds, extent_cmds;
 
 extern void reset_getopt(void);
@@ -67,127 +67,127 @@
 /* ss command functions */
 
 /* dump.c */
-extern void do_dump(int argc, char **argv);
-extern void do_cat(int argc, char **argv);
-extern void do_rdump(int argc, char **argv);
+extern void do_dump(int argc, char **argv, int sci_idx, void *infop);
+extern void do_cat(int argc, char **argv, int sci_idx, void *infop);
+extern void do_rdump(int argc, char **argv, int sci_idx, void *infop);
 
 /* extent_inode.c */
-extern void do_extent_open(int argc, char **argv);
-extern void do_extent_close(int argc, char **argv);
-extern void do_current_node(int argc, char **argv);
-extern void do_root_node(int argc, char **argv);
-extern void do_last_leaf(int argc, char **argv);
-extern void do_first_sib(int argc, char **argv);
-extern void do_last_sib(int argc, char **argv);
-extern void do_next_sib(int argc, char **argv);
-extern void do_prev_sib(int argc, char **argv);
-extern void do_next_leaf(int argc, char **argv);
-extern void do_prev_leaf(int argc, char **argv);
-extern void do_next(int argc, char **argv);
-extern void do_prev(int argc, char **argv);
-extern void do_up(int argc, char **argv);
-extern void do_down(int argc, char **argv);
-extern void do_delete_node(int argc, char **argv);
-extern void do_replace_node(int argc, char **argv);
-extern void do_split_node(int argc, char **argv);
-extern void do_insert_node(int argc, char **argv);
-extern void do_set_bmap(int argc, char **argv);
-extern void do_print_all(int argc, char **argv);
-extern void do_fix_parents(int argc, char **argv);
-extern void do_info(int argc, char **argv);
-extern void do_goto_block(int argc, char **argv);
+extern void do_extent_open(int argc, char **argv, int sci_idx, void *infop);
+extern void do_extent_close(int argc, char **argv, int sci_idx, void *infop);
+extern void do_current_node(int argc, char **argv, int sci_idx, void *infop);
+extern void do_root_node(int argc, char **argv, int sci_idx, void *infop);
+extern void do_last_leaf(int argc, char **argv, int sci_idx, void *infop);
+extern void do_first_sib(int argc, char **argv, int sci_idx, void *infop);
+extern void do_last_sib(int argc, char **argv, int sci_idx, void *infop);
+extern void do_next_sib(int argc, char **argv, int sci_idx, void *infop);
+extern void do_prev_sib(int argc, char **argv, int sci_idx, void *infop);
+extern void do_next_leaf(int argc, char **argv, int sci_idx, void *infop);
+extern void do_prev_leaf(int argc, char **argv, int sci_idx, void *infop);
+extern void do_next(int argc, char **argv, int sci_idx, void *infop);
+extern void do_prev(int argc, char **argv, int sci_idx, void *infop);
+extern void do_up(int argc, char **argv, int sci_idx, void *infop);
+extern void do_down(int argc, char **argv, int sci_idx, void *infop);
+extern void do_delete_node(int argc, char **argv, int sci_idx, void *infop);
+extern void do_replace_node(int argc, char **argv, int sci_idx, void *infop);
+extern void do_split_node(int argc, char **argv, int sci_idx, void *infop);
+extern void do_insert_node(int argc, char **argv, int sci_idx, void *infop);
+extern void do_set_bmap(int argc, char **argv, int sci_idx, void *infop);
+extern void do_print_all(int argc, char **argv, int sci_idx, void *infop);
+extern void do_fix_parents(int argc, char **argv, int sci_idx, void *infop);
+extern void do_info(int argc, char **argv, int sci_idx, void *infop);
+extern void do_goto_block(int argc, char **argv, int sci_idx, void *infop);
 
 /* htree.c */
-extern void do_htree_dump(int argc, char **argv);
-extern void do_dx_hash(int argc, char **argv);
-extern void do_dirsearch(int argc, char **argv);
+extern void do_htree_dump(int argc, char **argv, int sci_idx, void *infop);
+extern void do_dx_hash(int argc, char **argv, int sci_idx, void *infop);
+extern void do_dirsearch(int argc, char **argv, int sci_idx, void *infop);
 
 /* logdump.c */
-extern void do_logdump(int argc, char **argv);
+extern void do_logdump(int argc, char **argv, int sci_idx, void *infop);
 
 /* lsdel.c */
-extern void do_lsdel(int argc, char **argv);
+extern void do_lsdel(int argc, char **argv, int sci_idx, void *infop);
 
 /* icheck.c */
-extern void do_icheck(int argc, char **argv);
+extern void do_icheck(int argc, char **argv, int sci_idx, void *infop);
 
 /* ncheck.c */
-extern void do_ncheck(int argc, char **argv);
+extern void do_ncheck(int argc, char **argv, int sci_idx, void *infop);
 
 /* 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 **);
+extern void do_set_super(int argc, char **, int sci_idx, void *infop);
+extern void do_set_inode(int argc, char **, int sci_idx, void *infop);
+extern void do_set_block_group_descriptor(int argc, char **, int sci_idx, void *infop);
 
 /* unused.c */
-extern void do_dump_unused(int argc, char **argv);
+extern void do_dump_unused(int argc, char **argv, int sci_idx, void *infop);
 
 /* debugfs.c */
 extern void internal_dump_inode(FILE *, const char *, ext2_ino_t,
 				struct ext2_inode *, int);
 
-extern void do_dirty_filesys(int argc, char **argv);
-extern void do_open_filesys(int argc, char **argv);
-extern void do_close_filesys(int argc, char **argv);
-extern void do_lcd(int argc, char **argv);
-extern void do_init_filesys(int argc, char **argv);
-extern void do_show_super_stats(int argc, char **argv);
-extern void do_kill_file(int argc, char **argv);
-extern void do_rm(int argc, char **argv);
-extern void do_link(int argc, char **argv);
-extern void do_undel(int argc, char **argv);
-extern void do_unlink(int argc, char **argv);
-extern void do_copy_inode(int argc, char *argv[]);
-extern void do_find_free_block(int argc, char **argv);
-extern void do_find_free_inode(int argc, char **argv);
-extern void do_stat(int argc, char **argv);
-extern void do_dump_extents(int argc, char **argv);
-extern void do_blocks(int argc, char *argv[]);
+extern void do_dirty_filesys(int argc, char **argv, int sci_idx, void *infop);
+extern void do_open_filesys(int argc, char **argv, int sci_idx, void *infop);
+extern void do_close_filesys(int argc, char **argv, int sci_idx, void *infop);
+extern void do_lcd(int argc, char **argv, int sci_idx, void *infop);
+extern void do_init_filesys(int argc, char **argv, int sci_idx, void *infop);
+extern void do_show_super_stats(int argc, char **argv, int sci_idx, void *infop);
+extern void do_kill_file(int argc, char **argv, int sci_idx, void *infop);
+extern void do_rm(int argc, char **argv, int sci_idx, void *infop);
+extern void do_link(int argc, char **argv, int sci_idx, void *infop);
+extern void do_undel(int argc, char **argv, int sci_idx, void *infop);
+extern void do_unlink(int argc, char **argv, int sci_idx, void *infop);
+extern void do_copy_inode(int argc, char *argv[], int sci_idx, void *infop);
+extern void do_find_free_block(int argc, char **argv, int sci_idx, void *infop);
+extern void do_find_free_inode(int argc, char **argv, int sci_idx, void *infop);
+extern void do_stat(int argc, char **argv, int sci_idx, void *infop);
+extern void do_dump_extents(int argc, char **argv, int sci_idx, void *infop);
+extern void do_blocks(int argc, char *argv[], int sci_idx, void *infop);
 
-extern void do_chroot(int argc, char **argv);
-extern void do_clri(int argc, char **argv);
-extern void do_freei(int argc, char **argv);
-extern void do_seti(int argc, char **argv);
-extern void do_testi(int argc, char **argv);
-extern void do_freeb(int argc, char **argv);
-extern void do_setb(int argc, char **argv);
-extern void do_testb(int argc, char **argv);
-extern void do_modify_inode(int argc, char **argv);
-extern void do_list_dir(int argc, char **argv);
-extern void do_change_working_dir(int argc, char **argv);
-extern void do_print_working_directory(int argc, char **argv);
-extern void do_write(int argc, char **argv);
-extern void do_mknod(int argc, char **argv);
-extern void do_mkdir(int argc, char **argv);
-extern void do_rmdir(int argc, char **argv);
-extern void do_show_debugfs_params(int argc, char **argv);
-extern void do_expand_dir(int argc, char **argv);
-extern void do_features(int argc, char **argv);
-extern void do_bmap(int argc, char **argv);
-extern void do_imap(int argc, char **argv);
-extern void do_idump(int argc, char *argv[]);
-extern void do_set_current_time(int argc, char **argv);
-extern void do_supported_features(int argc, char **argv);
-extern void do_punch(int argc, char **argv);
-extern void do_fallocate(int argc, char **argv);
-extern void do_symlink(int argc, char **argv);
+extern void do_chroot(int argc, char **argv, int sci_idx, void *infop);
+extern void do_clri(int argc, char **argv, int sci_idx, void *infop);
+extern void do_freei(int argc, char **argv, int sci_idx, void *infop);
+extern void do_seti(int argc, char **argv, int sci_idx, void *infop);
+extern void do_testi(int argc, char **argv, int sci_idx, void *infop);
+extern void do_freeb(int argc, char **argv, int sci_idx, void *infop);
+extern void do_setb(int argc, char **argv, int sci_idx, void *infop);
+extern void do_testb(int argc, char **argv, int sci_idx, void *infop);
+extern void do_modify_inode(int argc, char **argv, int sci_idx, void *infop);
+extern void do_list_dir(int argc, char **argv, int sci_idx, void *infop);
+extern void do_change_working_dir(int argc, char **argv, int sci_idx, void *infop);
+extern void do_print_working_directory(int argc, char **argv, int sci_idx, void *infop);
+extern void do_write(int argc, char **argv, int sci_idx, void *infop);
+extern void do_mknod(int argc, char **argv, int sci_idx, void *infop);
+extern void do_mkdir(int argc, char **argv, int sci_idx, void *infop);
+extern void do_rmdir(int argc, char **argv, int sci_idx, void *infop);
+extern void do_show_debugfs_params(int argc, char **argv, int sci_idx, void *infop);
+extern void do_expand_dir(int argc, char **argv, int sci_idx, void *infop);
+extern void do_features(int argc, char **argv, int sci_idx, void *infop);
+extern void do_bmap(int argc, char **argv, int sci_idx, void *infop);
+extern void do_imap(int argc, char **argv, int sci_idx, void *infop);
+extern void do_idump(int argc, char *argv[], int sci_idx, void *infop);
+extern void do_set_current_time(int argc, char **argv, int sci_idx, void *infop);
+extern void do_supported_features(int argc, char **argv, int sci_idx, void *infop);
+extern void do_punch(int argc, char **argv, int sci_idx, void *infop);
+extern void do_fallocate(int argc, char **argv, int sci_idx, void *infop);
+extern void do_symlink(int argc, char **argv, int sci_idx, void *infop);
 
-extern void do_dump_mmp(int argc, char **argv);
-extern void do_set_mmp_value(int argc, char **argv);
+extern void do_dump_mmp(int argc, char **argv, int sci_idx, void *infop);
+extern void do_set_mmp_value(int argc, char **argv, int sci_idx, void *infop);
 
-extern void do_freefrag(int argc, char **argv);
-extern void do_filefrag(int argc, char *argv[]);
+extern void do_freefrag(int argc, char **argv, int sci_idx, void *infop);
+extern void do_filefrag(int argc, char *argv[], int sci_idx, void *infop);
 
 /* do_journal.c */
 
-extern void do_journal_write(int argc, char *argv[]);
-extern void do_journal_open(int argc, char *argv[]);
-extern void do_journal_close(int argc, char *argv[]);
-extern void do_journal_run(int argc, char *argv[]);
+extern void do_journal_write(int argc, char *argv[], int sci_idx, void *infop);
+extern void do_journal_open(int argc, char *argv[], int sci_idx, void *infop);
+extern void do_journal_close(int argc, char *argv[], int sci_idx, void *infop);
+extern void do_journal_run(int argc, char *argv[], int sci_idx, void *infop);
 
 /* quota.c */
-extern void do_list_quota(int argc, char *argv[]);
-extern void do_get_quota(int argc, char *argv[]);
+extern void do_list_quota(int argc, char *argv[], int sci_idx, void *infop);
+extern void do_get_quota(int argc, char *argv[], int sci_idx, void *infop);
 
 /* util.c */
 extern __s64 string_to_time(const char *arg);
@@ -195,14 +195,14 @@
 
 /* xattrs.c */
 void dump_inode_attributes(FILE *out, ext2_ino_t ino);
-void do_get_xattr(int argc, char **argv);
-void do_set_xattr(int argc, char **argv);
-void do_rm_xattr(int argc, char **argv);
-void do_list_xattr(int argc, char **argv);
+void do_get_xattr(int argc, char **argv, int sci_idx, void *infop);
+void do_set_xattr(int argc, char **argv, int sci_idx, void *infop);
+void do_rm_xattr(int argc, char **argv, int sci_idx, void *infop);
+void do_list_xattr(int argc, char **argv, int sci_idx, void *infop);
 void raw_inode_xattr_dump(FILE *f, unsigned char *buf, unsigned int len);
 void block_xattr_dump(FILE *f, unsigned char *buf, unsigned int len);
 
 /* zap.c */
-extern void do_zap_block(int argc, char **argv);
-extern void do_block_dump(int argc, char **argv);
+extern void do_zap_block(int argc, char **argv, int sci_idx, void *infop);
+extern void do_block_dump(int argc, char **argv, int sci_idx, void *infop);
 extern void do_byte_hexdump(FILE *fp, unsigned char *buf, size_t bufsize);
diff --git a/debugfs/do_journal.c b/debugfs/do_journal.c
index d7ab916..eeb363e 100644
--- a/debugfs/do_journal.c
+++ b/debugfs/do_journal.c
@@ -534,7 +534,8 @@
 	return err;
 }
 
-void do_journal_write(int argc, char *argv[])
+void do_journal_write(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		      void *infop EXT2FS_ATTR((unused)))
 {
 	blk64_t *blist = NULL, *rlist = NULL;
 	size_t bn = 0, rn = 0;
@@ -856,7 +857,8 @@
 	jfs_set_feature_64bit(journal);
 }
 
-void do_journal_open(int argc, char *argv[])
+void do_journal_open(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		     void *infop EXT2FS_ATTR((unused)))
 {
 	int opt, enable_csum = 0, csum_ver = 3;
 	journal_t *journal;
@@ -926,7 +928,9 @@
 }
 
 void do_journal_close(int argc EXT2FS_ATTR((unused)),
-		      char *argv[] EXT2FS_ATTR((unused)))
+		      char *argv[] EXT2FS_ATTR((unused)),
+		      int sci_idx EXT2FS_ATTR((unused)),
+		      void *infop EXT2FS_ATTR((unused)))
 {
 	if (current_journal == NULL) {
 		printf("Journal not open.\n");
@@ -936,7 +940,9 @@
 	ext2fs_close_journal(current_fs, &current_journal);
 }
 
-void do_journal_run(int argc EXT2FS_ATTR((unused)), char *argv[])
+void do_journal_run(int argc EXT2FS_ATTR((unused)), char *argv[],
+		    int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t err;
 
diff --git a/debugfs/dump.c b/debugfs/dump.c
index 4d5daf0..fdd6619 100644
--- a/debugfs/dump.c
+++ b/debugfs/dump.c
@@ -144,7 +144,8 @@
 	return;
 }
 
-void do_dump(int argc, char **argv)
+void do_dump(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	inode;
 	int		fd;
@@ -322,7 +323,8 @@
 	return 0;
 }
 
-void do_rdump(int argc, char **argv)
+void do_rdump(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	struct stat st;
 	char *dest_dir;
@@ -366,7 +368,8 @@
 	}
 }
 
-void do_cat(int argc, char **argv)
+void do_cat(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+	    void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	inode;
 
diff --git a/debugfs/extent_inode.c b/debugfs/extent_inode.c
index c7a92a7..ada1308 100644
--- a/debugfs/extent_inode.c
+++ b/debugfs/extent_inode.c
@@ -64,7 +64,8 @@
 
 static char *orig_prompt, *extent_prompt;
 
-void do_extent_open(int argc, char *argv[])
+void do_extent_open(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	inode;
 	int		ret;
@@ -113,7 +114,8 @@
 	return;
 }
 
-void do_extent_close(int argc, char *argv[])
+void do_extent_close(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		     void *infop EXT2FS_ATTR((unused)))
 {
 	int ret;
 
@@ -158,72 +160,86 @@
 	dbg_print_extent(0, &extent);
 }
 
-void do_current_node(int argc, char *argv[])
+void do_current_node(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		     void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("current_node", argc, argv, EXT2_EXTENT_CURRENT);
 }
 
-void do_root_node(int argc, char *argv[])
+void do_root_node(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("root_node", argc, argv, EXT2_EXTENT_ROOT);
 }
 
-void do_last_leaf(int argc, char *argv[])
+void do_last_leaf(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("last_leaf", argc, argv, EXT2_EXTENT_LAST_LEAF);
 }
 
-void do_first_sib(int argc, char *argv[])
+void do_first_sib(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("first_sib", argc, argv, EXT2_EXTENT_FIRST_SIB);
 }
 
-void do_last_sib(int argc, char *argv[])
+void do_last_sib(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_LAST_SIB);
 }
 
-void do_next_sib(int argc, char *argv[])
+void do_next_sib(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_NEXT_SIB);
 }
 
-void do_prev_sib(int argc, char *argv[])
+void do_prev_sib(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("prev_sib", argc, argv, EXT2_EXTENT_PREV_SIB);
 }
 
-void do_next_leaf(int argc, char *argv[])
+void do_next_leaf(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("next_leaf", argc, argv, EXT2_EXTENT_NEXT_LEAF);
 }
 
-void do_prev_leaf(int argc, char *argv[])
+void do_prev_leaf(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("prev_leaf", argc, argv, EXT2_EXTENT_PREV_LEAF);
 }
 
-void do_next(int argc, char *argv[])
+void do_next(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("next", argc, argv, EXT2_EXTENT_NEXT);
 }
 
-void do_prev(int argc, char *argv[])
+void do_prev(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("prev", argc, argv, EXT2_EXTENT_PREV);
 }
 
-void do_up(int argc, char *argv[])
+void do_up(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	   void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("up", argc, argv, EXT2_EXTENT_UP);
 }
 
-void do_down(int argc, char *argv[])
+void do_down(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	generic_goto_node("down", argc, argv, EXT2_EXTENT_DOWN);
 }
 
-void do_delete_node(int argc, char *argv[])
+void do_delete_node(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	struct ext2fs_extent extent;
 	errcode_t	retval;
@@ -245,7 +261,8 @@
 	dbg_print_extent(0, &extent);
 }
 
-void do_replace_node(int argc, char *argv[])
+void do_replace_node(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		     void *infop EXT2FS_ATTR((unused)))
 {
 	const char	*usage = "[--uninit] <lblk> <len> <pblk>";
 	errcode_t	retval;
@@ -289,7 +306,8 @@
 	generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
 }
 
-void do_split_node(int argc, char *argv[])
+void do_split_node(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		   void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t	retval;
 
@@ -305,7 +323,8 @@
 	generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
 }
 
-void do_insert_node(int argc, char *argv[])
+void do_insert_node(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	const char	*usage = "[--after] [--uninit] <lblk> <len> <pblk>";
 	errcode_t	retval;
@@ -363,7 +382,8 @@
 	generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
 }
 
-void do_set_bmap(int argc, char **argv)
+void do_set_bmap(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	const char	*usage = "[--uninit] <lblk> <pblk>";
 	struct ext2fs_extent extent;
@@ -411,7 +431,8 @@
 	dbg_print_extent(0, &extent);
 }
 
-void do_print_all(int argc, char **argv)
+void do_print_all(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	const char	*usage = "[--leaf-only|--reverse|--reverse-leaf]";
 	struct ext2fs_extent	extent;
@@ -462,7 +483,8 @@
 	}
 }
 
-void do_fix_parents(int argc, char **argv)
+void do_fix_parents(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t		retval;
 
@@ -477,7 +499,8 @@
 	}
 }
 
-void do_info(int argc, char **argv)
+void do_info(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	struct ext2fs_extent	extent;
 	struct ext2_extent_info	info;
@@ -510,7 +533,8 @@
 	       info.max_uninit_len);
 }
 
-void do_goto_block(int argc, char **argv)
+void do_goto_block(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		   void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t		retval;
 	blk64_t			blk;
diff --git a/debugfs/filefrag.c b/debugfs/filefrag.c
index 128598b..961b696 100644
--- a/debugfs/filefrag.c
+++ b/debugfs/filefrag.c
@@ -260,7 +260,8 @@
 	}
 }
 
-void do_filefrag(int argc, char *argv[])
+void do_filefrag(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	struct filefrag_struct fs;
 	struct ext2_inode inode;
diff --git a/debugfs/htree.c b/debugfs/htree.c
index cf7d78a..0c6a385 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -227,7 +227,8 @@
 
 
 
-void do_htree_dump(int argc, char *argv[])
+void do_htree_dump(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		   void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	ino;
 	struct ext2_inode inode;
@@ -302,7 +303,8 @@
 /*
  * This function prints the hash of a given file.
  */
-void do_dx_hash(int argc, char *argv[])
+void do_dx_hash(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_dirhash_t hash, minor_hash;
 	errcode_t	err;
@@ -362,7 +364,8 @@
 			    e2_blkcnt_t blockcnt, blk64_t ref_blk,
 			    int ref_offset, void *priv_data);
 
-void do_dirsearch(int argc, char *argv[])
+void do_dirsearch(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	inode;
 	struct process_block_struct pb;
diff --git a/debugfs/icheck.c b/debugfs/icheck.c
index 3b9bd14..71164cf 100644
--- a/debugfs/icheck.c
+++ b/debugfs/icheck.c
@@ -53,7 +53,8 @@
 	return 0;
 }
 
-void do_icheck(int argc, char **argv)
+void do_icheck(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+	       void *infop EXT2FS_ATTR((unused)))
 {
 	struct block_walk_struct bw;
 	struct block_info	*binfo;
diff --git a/debugfs/logdump.c b/debugfs/logdump.c
index 03edb44..e286ae8 100644
--- a/debugfs/logdump.c
+++ b/debugfs/logdump.c
@@ -72,7 +72,8 @@
 		blocknr -= (be32_to_cpu((jsb)->s_maxlen) -	\
 			    be32_to_cpu((jsb)->s_first));
 
-void do_logdump(int argc, char **argv)
+void do_logdump(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	int		c;
 	int		retval;
diff --git a/debugfs/ls.c b/debugfs/ls.c
index bfc28cb..a1e8f4e 100644
--- a/debugfs/ls.c
+++ b/debugfs/ls.c
@@ -189,7 +189,8 @@
 	return 0;
 }
 
-void do_list_dir(int argc, char *argv[])
+void do_list_dir(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	struct ext2_inode inode;
 	ext2_ino_t	ino;
diff --git a/debugfs/lsdel.c b/debugfs/lsdel.c
index 946b268..c0d5890 100644
--- a/debugfs/lsdel.c
+++ b/debugfs/lsdel.c
@@ -71,7 +71,8 @@
 	return 0;
 }
 
-void do_lsdel(int argc, char **argv)
+void do_lsdel(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	struct lsdel_struct 	lsd;
 	struct deleted_info	*delarray;
diff --git a/debugfs/ncheck.c b/debugfs/ncheck.c
index 158e865..011f26d 100644
--- a/debugfs/ncheck.c
+++ b/debugfs/ncheck.c
@@ -90,7 +90,8 @@
 	return 0;
 }
 
-void do_ncheck(int argc, char **argv)
+void do_ncheck(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+	       void *infop EXT2FS_ATTR((unused)))
 {
 	struct inode_walk_struct iw;
 	int			c, i;
diff --git a/debugfs/quota.c b/debugfs/quota.c
index 0b7c2ee..f792bd7 100644
--- a/debugfs/quota.c
+++ b/debugfs/quota.c
@@ -102,7 +102,8 @@
 	return 0;
 }
 
-void do_list_quota(int argc, char *argv[])
+void do_list_quota(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		   void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t	retval;
 	int		type;
@@ -131,7 +132,8 @@
 	}
 }
 
-void do_get_quota(int argc, char *argv[])
+void do_get_quota(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	int		err, type;
 	struct quota_handle *qh;
diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
index e1e23a5..e237761 100644
--- a/debugfs/set_fields.c
+++ b/debugfs/set_fields.c
@@ -723,7 +723,8 @@
 }
 
 
-void do_set_super(int argc, char *argv[])
+void do_set_super(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	const char *usage = "<field> <value>\n"
 		"\t\"set_super_value -l\" will list the names of "
@@ -750,7 +751,8 @@
 	}
 }
 
-void do_set_inode(int argc, char *argv[])
+void do_set_inode(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	const char *usage = "<inode> <field> <value>\n"
 		"\t\"set_inode_field -l\" will list the names of "
@@ -788,7 +790,9 @@
 	}
 }
 
-void do_set_block_group_descriptor(int argc, char *argv[])
+void do_set_block_group_descriptor(int argc, char *argv[],
+				   int sci_idx EXT2FS_ATTR((unused)),
+				   void *infop EXT2FS_ATTR((unused)))
 {
 	const char *usage = "<bg number> <field> <value>\n"
 		"\t\"set_block_group -l\" will list the names of "
@@ -866,7 +870,8 @@
 }
 
 #ifdef CONFIG_MMP
-void do_set_mmp_value(int argc, char *argv[])
+void do_set_mmp_value(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		      void *infop EXT2FS_ATTR((unused)))
 {
 	const char *usage = "<field> <value>\n"
 		"\t\"set_mmp_value -l\" will list the names of "
@@ -925,7 +930,9 @@
 }
 #else
 void do_set_mmp_value(int argc EXT2FS_ATTR((unused)),
-		      char *argv[] EXT2FS_ATTR((unused)))
+		      char *argv[] EXT2FS_ATTR((unused)),
+		      int sci_idx EXT2FS_ATTR((unused)),
+		      void *infop EXT2FS_ATTR((unused)))
 {
 	fprintf(stdout, "MMP is unsupported, please recompile with "
 	                "--enable-mmp\n");
diff --git a/debugfs/unused.c b/debugfs/unused.c
index 4cb1191..a6b44b5 100644
--- a/debugfs/unused.c
+++ b/debugfs/unused.c
@@ -25,7 +25,9 @@
 
 #include "debugfs.h"
 
-void do_dump_unused(int argc EXT2FS_ATTR((unused)), char **argv)
+void do_dump_unused(int argc EXT2FS_ATTR((unused)), char **argv,
+		    int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	blk64_t		blk;
 	unsigned char	buf[EXT2_MAX_BLOCK_SIZE];
diff --git a/debugfs/xattrs.c b/debugfs/xattrs.c
index c29761e..8bbaaed 100644
--- a/debugfs/xattrs.c
+++ b/debugfs/xattrs.c
@@ -117,7 +117,8 @@
 	err = ext2fs_xattrs_close(&h);
 }
 
-void do_list_xattr(int argc, char **argv)
+void do_list_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		   void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t ino;
 
@@ -137,7 +138,8 @@
 	dump_inode_attributes(stdout, ino);
 }
 
-void do_get_xattr(int argc, char **argv)
+void do_get_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t ino;
 	struct ext2_xattr_handle *h;
@@ -234,7 +236,8 @@
 		fclose(fp);
 }
 
-void do_set_xattr(int argc, char **argv)
+void do_set_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		  void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t ino;
 	struct ext2_xattr_handle *h;
@@ -317,7 +320,8 @@
 	}
 }
 
-void do_rm_xattr(int argc, char **argv)
+void do_rm_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t ino;
 	struct ext2_xattr_handle *h;
diff --git a/debugfs/zap.c b/debugfs/zap.c
index a849b90..c7996b2 100644
--- a/debugfs/zap.c
+++ b/debugfs/zap.c
@@ -25,7 +25,8 @@
 
 #include "debugfs.h"
 
-void do_zap_block(int argc, char *argv[])
+void do_zap_block(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned long	pattern = 0;
 	unsigned char	*buf;
@@ -167,7 +168,8 @@
 	return;
 }
 
-void do_block_dump(int argc, char *argv[])
+void do_block_dump(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned char	*buf;
 	ext2_ino_t	inode;
diff --git a/e2fsck/jfs_user.h b/e2fsck/jfs_user.h
index 8289795..a1c6951 100644
--- a/e2fsck/jfs_user.h
+++ b/e2fsck/jfs_user.h
@@ -27,6 +27,7 @@
 /*
  * Pull in the definition of the e2fsck context structure
  */
+#include "config.h"
 #include "e2fsck.h"
 #endif
 
diff --git a/lib/ext2fs/bitmaps.c b/lib/ext2fs/bitmaps.c
index 8402191..e25db2c 100644
--- a/lib/ext2fs/bitmaps.c
+++ b/lib/ext2fs/bitmaps.c
@@ -125,6 +125,7 @@
 {
 	__u64			start, end, real_end;
 	ext2fs_generic_bitmap	bmap;
+	ext2fs_generic_bitmap_64 bmap64;
 	errcode_t		retval;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@@ -147,14 +148,15 @@
 					   end, real_end, descr, &bmap);
 	if (retval)
 		return retval;
-	bmap->cluster_bits = 0;
+	bmap64 = (ext2fs_generic_bitmap_64) bmap;
+	bmap64->cluster_bits = 0;
 	*ret = bmap;
 	return 0;
 }
 
 int ext2fs_get_bitmap_granularity(ext2fs_block_bitmap bitmap)
 {
-	ext2fs_generic_bitmap bmap = bitmap;
+	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) bitmap;
 
 	if (!EXT2FS_IS_64_BITMAP(bmap))
 		return 0;
diff --git a/lib/ext2fs/blkmap64_ba.c b/lib/ext2fs/blkmap64_ba.c
index 3707a61..85cb38d 100644
--- a/lib/ext2fs/blkmap64_ba.c
+++ b/lib/ext2fs/blkmap64_ba.c
@@ -40,7 +40,7 @@
 
 typedef struct ext2fs_ba_private_struct *ext2fs_ba_private;
 
-static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap bitmap)
+static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap_64 bitmap)
 {
 	ext2fs_ba_private bp;
 	errcode_t	retval;
@@ -69,7 +69,7 @@
 }
 
 static errcode_t ba_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)),
-			     ext2fs_generic_bitmap bitmap)
+			     ext2fs_generic_bitmap_64 bitmap)
 {
 	ext2fs_ba_private bp;
 	errcode_t	retval;
@@ -86,7 +86,7 @@
 	return 0;
 }
 
-static void ba_free_bmap(ext2fs_generic_bitmap bitmap)
+static void ba_free_bmap(ext2fs_generic_bitmap_64 bitmap)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
 
@@ -101,8 +101,8 @@
 	bp = 0;
 }
 
-static errcode_t ba_copy_bmap(ext2fs_generic_bitmap src,
-			      ext2fs_generic_bitmap dest)
+static errcode_t ba_copy_bmap(ext2fs_generic_bitmap_64 src,
+			      ext2fs_generic_bitmap_64 dest)
 {
 	ext2fs_ba_private src_bp = (ext2fs_ba_private) src->private;
 	ext2fs_ba_private dest_bp;
@@ -121,7 +121,7 @@
 	return 0;
 }
 
-static errcode_t ba_resize_bmap(ext2fs_generic_bitmap bmap,
+static errcode_t ba_resize_bmap(ext2fs_generic_bitmap_64 bmap,
 				__u64 new_end, __u64 new_real_end)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bmap->private;
@@ -162,7 +162,7 @@
 
 }
 
-static int ba_mark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
+static int ba_mark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
 	blk64_t bitno = (blk64_t) arg;
@@ -170,7 +170,7 @@
 	return ext2fs_set_bit64(bitno - bitmap->start, bp->bitarray);
 }
 
-static int ba_unmark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
+static int ba_unmark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
 	blk64_t bitno = (blk64_t) arg;
@@ -178,7 +178,7 @@
 	return ext2fs_clear_bit64(bitno - bitmap->start, bp->bitarray);
 }
 
-static int ba_test_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
+static int ba_test_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
 	blk64_t bitno = (blk64_t) arg;
@@ -186,7 +186,7 @@
 	return ext2fs_test_bit64(bitno - bitmap->start, bp->bitarray);
 }
 
-static void ba_mark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg,
+static void ba_mark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
 				unsigned int num)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
@@ -197,7 +197,7 @@
 		ext2fs_fast_set_bit64(bitno + i - bitmap->start, bp->bitarray);
 }
 
-static void ba_unmark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg,
+static void ba_unmark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
 				  unsigned int num)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
@@ -208,7 +208,7 @@
 		ext2fs_fast_clear_bit64(bitno + i - bitmap->start, bp->bitarray);
 }
 
-static int ba_test_clear_bmap_extent(ext2fs_generic_bitmap bitmap,
+static int ba_test_clear_bmap_extent(ext2fs_generic_bitmap_64 bitmap,
 				     __u64 start, unsigned int len)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
@@ -282,7 +282,7 @@
 }
 
 
-static errcode_t ba_set_bmap_range(ext2fs_generic_bitmap bitmap,
+static errcode_t ba_set_bmap_range(ext2fs_generic_bitmap_64 bitmap,
 				     __u64 start, size_t num, void *in)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
@@ -292,7 +292,7 @@
 	return 0;
 }
 
-static errcode_t ba_get_bmap_range(ext2fs_generic_bitmap bitmap,
+static errcode_t ba_get_bmap_range(ext2fs_generic_bitmap_64 bitmap,
 				     __u64 start, size_t num, void *out)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
@@ -302,7 +302,7 @@
 	return 0;
 }
 
-static void ba_clear_bmap(ext2fs_generic_bitmap bitmap)
+static void ba_clear_bmap(ext2fs_generic_bitmap_64 bitmap)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
 
@@ -311,20 +311,20 @@
 }
 
 #ifdef ENABLE_BMAP_STATS
-static void ba_print_stats(ext2fs_generic_bitmap bitmap)
+static void ba_print_stats(ext2fs_generic_bitmap_64 bitmap)
 {
 	fprintf(stderr, "%16llu Bytes used by bitarray\n",
 		((bitmap->real_end - bitmap->start) >> 3) + 1 +
 		sizeof(struct ext2fs_ba_private_struct));
 }
 #else
-static void ba_print_stats(ext2fs_generic_bitmap bitmap EXT2FS_ATTR((unused)))
+static void ba_print_stats(ext2fs_generic_bitmap_64 bitmap EXT2FS_ATTR((unused)))
 {
 }
 #endif
 
 /* Find the first zero bit between start and end, inclusive. */
-static errcode_t ba_find_first_zero(ext2fs_generic_bitmap bitmap,
+static errcode_t ba_find_first_zero(ext2fs_generic_bitmap_64 bitmap,
 				    __u64 start, __u64 end, __u64 *out)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private;
@@ -398,7 +398,7 @@
 }
 
 /* Find the first one bit between start and end, inclusive. */
-static errcode_t ba_find_first_set(ext2fs_generic_bitmap bitmap,
+static errcode_t ba_find_first_set(ext2fs_generic_bitmap_64 bitmap,
 				    __u64 start, __u64 end, __u64 *out)
 {
 	ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private;
diff --git a/lib/ext2fs/blkmap64_rb.c b/lib/ext2fs/blkmap64_rb.c
index 4cbfb1e..1fd5527 100644
--- a/lib/ext2fs/blkmap64_rb.c
+++ b/lib/ext2fs/blkmap64_rb.c
@@ -177,7 +177,7 @@
 	ext2fs_free_mem(&ext);
 }
 
-static errcode_t rb_alloc_private_data (ext2fs_generic_bitmap bitmap)
+static errcode_t rb_alloc_private_data (ext2fs_generic_bitmap_64 bitmap)
 {
 	struct ext2fs_rb_private *bp;
 	errcode_t	retval;
@@ -201,7 +201,7 @@
 }
 
 static errcode_t rb_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)),
-			     ext2fs_generic_bitmap bitmap)
+			     ext2fs_generic_bitmap_64 bitmap)
 {
 	errcode_t	retval;
 
@@ -225,7 +225,7 @@
 	}
 }
 
-static void rb_free_bmap(ext2fs_generic_bitmap bitmap)
+static void rb_free_bmap(ext2fs_generic_bitmap_64 bitmap)
 {
 	struct ext2fs_rb_private *bp;
 
@@ -236,8 +236,8 @@
 	bp = 0;
 }
 
-static errcode_t rb_copy_bmap(ext2fs_generic_bitmap src,
-			      ext2fs_generic_bitmap dest)
+static errcode_t rb_copy_bmap(ext2fs_generic_bitmap_64 src,
+			      ext2fs_generic_bitmap_64 dest)
 {
 	struct ext2fs_rb_private *src_bp, *dest_bp;
 	struct bmap_rb_extent *src_ext, *dest_ext;
@@ -302,7 +302,7 @@
 	}
 }
 
-static errcode_t rb_resize_bmap(ext2fs_generic_bitmap bmap,
+static errcode_t rb_resize_bmap(ext2fs_generic_bitmap_64 bmap,
 				__u64 new_end, __u64 new_real_end)
 {
 	struct ext2fs_rb_private *bp;
@@ -575,7 +575,7 @@
 	return retval;
 }
 
-static int rb_mark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
+static int rb_mark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
 {
 	struct ext2fs_rb_private *bp;
 	int retval;
@@ -588,7 +588,7 @@
 	return retval;
 }
 
-static int rb_unmark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
+static int rb_unmark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
 {
 	struct ext2fs_rb_private *bp;
 	int retval;
@@ -603,7 +603,7 @@
 }
 
 inline
-static int rb_test_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
+static int rb_test_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
 {
 	struct ext2fs_rb_private *bp;
 
@@ -613,7 +613,7 @@
 	return rb_test_bit(bp, arg);
 }
 
-static void rb_mark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg,
+static void rb_mark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
 				unsigned int num)
 {
 	struct ext2fs_rb_private *bp;
@@ -625,7 +625,7 @@
 	check_tree(&bp->root, __func__);
 }
 
-static void rb_unmark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg,
+static void rb_unmark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
 				  unsigned int num)
 {
 	struct ext2fs_rb_private *bp;
@@ -637,7 +637,7 @@
 	check_tree(&bp->root, __func__);
 }
 
-static int rb_test_clear_bmap_extent(ext2fs_generic_bitmap bitmap,
+static int rb_test_clear_bmap_extent(ext2fs_generic_bitmap_64 bitmap,
 				     __u64 start, unsigned int len)
 {
 	struct rb_node *parent = NULL, **n;
@@ -693,7 +693,7 @@
 	return retval;
 }
 
-static errcode_t rb_set_bmap_range(ext2fs_generic_bitmap bitmap,
+static errcode_t rb_set_bmap_range(ext2fs_generic_bitmap_64 bitmap,
 				     __u64 start, size_t num, void *in)
 {
 	struct ext2fs_rb_private *bp;
@@ -739,7 +739,7 @@
 	return 0;
 }
 
-static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap bitmap,
+static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap_64 bitmap,
 				     __u64 start, size_t num, void *out)
 {
 
@@ -804,7 +804,7 @@
 	return 0;
 }
 
-static void rb_clear_bmap(ext2fs_generic_bitmap bitmap)
+static void rb_clear_bmap(ext2fs_generic_bitmap_64 bitmap)
 {
 	struct ext2fs_rb_private *bp;
 
@@ -817,7 +817,7 @@
 	check_tree(&bp->root, __func__);
 }
 
-static errcode_t rb_find_first_zero(ext2fs_generic_bitmap bitmap,
+static errcode_t rb_find_first_zero(ext2fs_generic_bitmap_64 bitmap,
 				   __u64 start, __u64 end, __u64 *out)
 {
 	struct rb_node *parent = NULL, **n;
@@ -853,7 +853,7 @@
 	return 0;
 }
 
-static errcode_t rb_find_first_set(ext2fs_generic_bitmap bitmap,
+static errcode_t rb_find_first_set(ext2fs_generic_bitmap_64 bitmap,
 				   __u64 start, __u64 end, __u64 *out)
 {
 	struct rb_node *parent = NULL, **n;
@@ -902,7 +902,7 @@
 }
 
 #ifdef ENABLE_BMAP_STATS
-static void rb_print_stats(ext2fs_generic_bitmap bitmap)
+static void rb_print_stats(ext2fs_generic_bitmap_64 bitmap)
 {
 	struct ext2fs_rb_private *bp;
 	struct rb_node *node = NULL;
@@ -963,7 +963,7 @@
 		eff);
 }
 #else
-static void rb_print_stats(ext2fs_generic_bitmap bitmap EXT2FS_ATTR((unused)))
+static void rb_print_stats(ext2fs_generic_bitmap_64 bitmap EXT2FS_ATTR((unused)))
 {
 }
 #endif
diff --git a/lib/ext2fs/bmap64.h b/lib/ext2fs/bmap64.h
index d8c7a3c..de33454 100644
--- a/lib/ext2fs/bmap64.h
+++ b/lib/ext2fs/bmap64.h
@@ -37,7 +37,7 @@
 };
 
 
-struct ext2fs_struct_generic_bitmap {
+struct ext2fs_struct_generic_bitmap_64 {
 	errcode_t		magic;
 	ext2_filsys 		fs;
 	struct ext2_bitmap_ops	*bitmap_ops;
@@ -53,6 +53,8 @@
 #endif
 };
 
+typedef struct ext2fs_struct_generic_bitmap_64 *ext2fs_generic_bitmap_64;
+
 #define EXT2FS_IS_32_BITMAP(bmap) \
 	(((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) || \
 	 ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP) || \
@@ -66,37 +68,37 @@
 struct ext2_bitmap_ops {
 	int	type;
 	/* Generic bmap operators */
-	errcode_t (*new_bmap)(ext2_filsys fs, ext2fs_generic_bitmap bmap);
-	void	(*free_bmap)(ext2fs_generic_bitmap bitmap);
-	errcode_t (*copy_bmap)(ext2fs_generic_bitmap src,
-			     ext2fs_generic_bitmap dest);
-	errcode_t (*resize_bmap)(ext2fs_generic_bitmap bitmap,
+	errcode_t (*new_bmap)(ext2_filsys fs, ext2fs_generic_bitmap_64 bmap);
+	void	(*free_bmap)(ext2fs_generic_bitmap_64 bitmap);
+	errcode_t (*copy_bmap)(ext2fs_generic_bitmap_64 src,
+			     ext2fs_generic_bitmap_64 dest);
+	errcode_t (*resize_bmap)(ext2fs_generic_bitmap_64 bitmap,
 			       __u64 new_end,
 			       __u64 new_real_end);
 	/* bit set/test operators */
-	int	(*mark_bmap)(ext2fs_generic_bitmap bitmap, __u64 arg);
-	int	(*unmark_bmap)(ext2fs_generic_bitmap bitmap, __u64 arg);
-	int	(*test_bmap)(ext2fs_generic_bitmap bitmap, __u64 arg);
-	void	(*mark_bmap_extent)(ext2fs_generic_bitmap bitmap, __u64 arg,
+	int	(*mark_bmap)(ext2fs_generic_bitmap_64 bitmap, __u64 arg);
+	int	(*unmark_bmap)(ext2fs_generic_bitmap_64 bitmap, __u64 arg);
+	int	(*test_bmap)(ext2fs_generic_bitmap_64 bitmap, __u64 arg);
+	void	(*mark_bmap_extent)(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
 				    unsigned int num);
-	void	(*unmark_bmap_extent)(ext2fs_generic_bitmap bitmap, __u64 arg,
+	void	(*unmark_bmap_extent)(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
 				      unsigned int num);
-	int	(*test_clear_bmap_extent)(ext2fs_generic_bitmap bitmap,
+	int	(*test_clear_bmap_extent)(ext2fs_generic_bitmap_64 bitmap,
 					  __u64 arg, unsigned int num);
-	errcode_t (*set_bmap_range)(ext2fs_generic_bitmap bitmap,
+	errcode_t (*set_bmap_range)(ext2fs_generic_bitmap_64 bitmap,
 				    __u64 start, size_t num, void *in);
-	errcode_t (*get_bmap_range)(ext2fs_generic_bitmap bitmap,
+	errcode_t (*get_bmap_range)(ext2fs_generic_bitmap_64 bitmap,
 				    __u64 start, size_t num, void *out);
-	void (*clear_bmap)(ext2fs_generic_bitmap bitmap);
-	void (*print_stats)(ext2fs_generic_bitmap);
+	void (*clear_bmap)(ext2fs_generic_bitmap_64 bitmap);
+	void (*print_stats)(ext2fs_generic_bitmap_64);
 
 	/* Find the first zero bit between start and end, inclusive.
 	 * May be NULL, in which case a generic function is used. */
-	errcode_t (*find_first_zero)(ext2fs_generic_bitmap bitmap,
+	errcode_t (*find_first_zero)(ext2fs_generic_bitmap_64 bitmap,
 				     __u64 start, __u64 end, __u64 *out);
 	/* Find the first set bit between start and end, inclusive.
 	 * May be NULL, in which case a generic function is used. */
-	errcode_t (*find_first_set)(ext2fs_generic_bitmap bitmap,
+	errcode_t (*find_first_set)(ext2fs_generic_bitmap_64 bitmap,
 				    __u64 start, __u64 end, __u64 *out);
 };
 
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index c86596a..185be5d 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -111,9 +111,14 @@
 #define EXT2FS_UNMARK_ERROR 	1
 #define EXT2FS_TEST_ERROR	2
 
-typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap;
-typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap;
-typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap;
+struct ext2fs_struct_generic_bitmap_base {
+	errcode_t		magic;
+	ext2_filsys 		fs;
+};
+
+typedef struct ext2fs_struct_generic_bitmap_base *ext2fs_generic_bitmap;
+typedef struct ext2fs_struct_generic_bitmap_base *ext2fs_inode_bitmap;
+typedef struct ext2fs_struct_generic_bitmap_base *ext2fs_block_bitmap;
 
 #define EXT2_FIRST_INODE(s)	EXT2_FIRST_INO(s)
 
diff --git a/lib/ext2fs/gen_bitmap.c b/lib/ext2fs/gen_bitmap.c
index d0061b8..181371c 100644
--- a/lib/ext2fs/gen_bitmap.c
+++ b/lib/ext2fs/gen_bitmap.c
@@ -28,7 +28,7 @@
 #include "ext2_fs.h"
 #include "ext2fsP.h"
 
-struct ext2fs_struct_generic_bitmap {
+struct ext2fs_struct_generic_bitmap_32 {
 	errcode_t	magic;
 	ext2_filsys 	fs;
 	__u32		start, end;
@@ -39,6 +39,8 @@
 	__u32		reserved[7];
 };
 
+typedef struct ext2fs_struct_generic_bitmap_32 *ext2fs_generic_bitmap_32;
+
 #define EXT2FS_IS_32_BITMAP(bmap) \
 	(((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) || \
 	 ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP) || \
@@ -53,9 +55,11 @@
  * 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,
+void ext2fs_warn_bitmap2(ext2fs_generic_bitmap gen_bitmap,
 			    int code, unsigned long arg)
 {
+	ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
+
 #ifndef OMIT_COM_ERR
 	if (bitmap->description)
 		com_err(0, bitmap->base_error_code+code,
@@ -79,11 +83,11 @@
 				     const char *descr, char *init_map,
 				     ext2fs_generic_bitmap *ret)
 {
-	ext2fs_generic_bitmap	bitmap;
+	ext2fs_generic_bitmap_32 bitmap;
 	errcode_t		retval;
 	size_t			size;
 
-	retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
+	retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap_32),
 				&bitmap);
 	if (retval)
 		return retval;
@@ -127,7 +131,7 @@
 		memcpy(bitmap->bitmap, init_map, size);
 	else
 		memset(bitmap->bitmap, 0, size);
-	*ret = bitmap;
+	*ret = (ext2fs_generic_bitmap) bitmap;
 	return 0;
 }
 
@@ -141,9 +145,11 @@
 					  start, end, real_end, descr, 0, ret);
 }
 
-errcode_t ext2fs_copy_generic_bitmap(ext2fs_generic_bitmap src,
+errcode_t ext2fs_copy_generic_bitmap(ext2fs_generic_bitmap gen_src,
 				     ext2fs_generic_bitmap *dest)
 {
+	ext2fs_generic_bitmap_32 src = (ext2fs_generic_bitmap_32) gen_src;
+
 	return (ext2fs_make_generic_bitmap(src->magic, src->fs,
 					   src->start, src->end,
 					   src->real_end,
@@ -151,9 +157,11 @@
 					   dest));
 }
 
-void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap)
+void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap gen_bitmap)
 {
-	if (check_magic(bitmap))
+	ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
+
+	if (check_magic(gen_bitmap))
 		return;
 
 	bitmap->magic = 0;
@@ -171,6 +179,8 @@
 int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
 					blk_t bitno)
 {
+	ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
+
 	if (!EXT2FS_IS_32_BITMAP(bitmap)) {
 		if (EXT2FS_IS_64_BITMAP(bitmap)) {
 			ext2fs_warn_bitmap32(bitmap, __func__);
@@ -183,16 +193,18 @@
 		return 0;
 	}
 
-	if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
+	if ((bitno < bitmap32->start) || (bitno > bitmap32->end)) {
 		ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
 		return 0;
 	}
-	return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
+	return ext2fs_test_bit(bitno - bitmap32->start, bitmap32->bitmap);
 }
 
 int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
 					 __u32 bitno)
 {
+	ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
+
 	if (!EXT2FS_IS_32_BITMAP(bitmap)) {
 		if (EXT2FS_IS_64_BITMAP(bitmap)) {
 			ext2fs_warn_bitmap32(bitmap, __func__);
@@ -205,16 +217,18 @@
 		return 0;
 	}
 
-	if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
+	if ((bitno < bitmap32->start) || (bitno > bitmap32->end)) {
 		ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno);
 		return 0;
 	}
-	return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap);
+	return ext2fs_set_bit(bitno - bitmap32->start, bitmap32->bitmap);
 }
 
 int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
 					   blk_t bitno)
 {
+	ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
+
 	if (!EXT2FS_IS_32_BITMAP(bitmap)) {
 		if (EXT2FS_IS_64_BITMAP(bitmap)) {
 			ext2fs_warn_bitmap32(bitmap, __func__);
@@ -227,15 +241,17 @@
 		return 0;
 	}
 
-	if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
+	if ((bitno < bitmap32->start) || (bitno > bitmap32->end)) {
 		ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
 		return 0;
 	}
-	return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap);
+	return ext2fs_clear_bit(bitno - bitmap32->start, bitmap32->bitmap);
 }
 
 __u32 ext2fs_get_generic_bitmap_start(ext2fs_generic_bitmap bitmap)
 {
+	ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
+
 	if (!EXT2FS_IS_32_BITMAP(bitmap)) {
 		if (EXT2FS_IS_64_BITMAP(bitmap)) {
 			ext2fs_warn_bitmap32(bitmap, __func__);
@@ -248,11 +264,13 @@
 		return 0;
 	}
 
-	return bitmap->start;
+	return bitmap32->start;
 }
 
 __u32 ext2fs_get_generic_bitmap_end(ext2fs_generic_bitmap bitmap)
 {
+	ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
+
 	if (!EXT2FS_IS_32_BITMAP(bitmap)) {
 		if (EXT2FS_IS_64_BITMAP(bitmap)) {
 			ext2fs_warn_bitmap32(bitmap, __func__);
@@ -264,11 +282,13 @@
 #endif
 		return 0;
 	}
-	return bitmap->end;
+	return bitmap32->end;
 }
 
 void ext2fs_clear_generic_bitmap(ext2fs_generic_bitmap bitmap)
 {
+	ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
+
 	if (!EXT2FS_IS_32_BITMAP(bitmap)) {
 		if (EXT2FS_IS_64_BITMAP(bitmap)) {
 			ext2fs_warn_bitmap32(bitmap, __func__);
@@ -282,14 +302,16 @@
 		return;
 	}
 
-	memset(bitmap->bitmap, 0,
-	       (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
+	memset(bitmap32->bitmap, 0,
+	       (size_t) (((bitmap32->real_end - bitmap32->start) / 8) + 1));
 }
 
-errcode_t ext2fs_fudge_generic_bitmap_end(ext2fs_inode_bitmap bitmap,
+errcode_t ext2fs_fudge_generic_bitmap_end(ext2fs_inode_bitmap gen_bitmap,
 					  errcode_t magic, errcode_t neq,
 					  ext2_ino_t end, ext2_ino_t *oend)
 {
+	ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
+
 	EXT2_CHECK_MAGIC(bitmap, magic);
 
 	if (end > bitmap->real_end)
@@ -302,8 +324,9 @@
 
 errcode_t ext2fs_resize_generic_bitmap(errcode_t magic,
 				       __u32 new_end, __u32 new_real_end,
-				       ext2fs_generic_bitmap bmap)
+				       ext2fs_generic_bitmap gen_bmap)
 {
+	ext2fs_generic_bitmap_32 bmap = (ext2fs_generic_bitmap_32) gen_bmap;
 	errcode_t	retval;
 	size_t		size, new_size;
 	__u32		bitno;
@@ -344,9 +367,11 @@
 }
 
 errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq,
-					ext2fs_generic_bitmap bm1,
-					ext2fs_generic_bitmap bm2)
+					ext2fs_generic_bitmap gen_bm1,
+					ext2fs_generic_bitmap gen_bm2)
 {
+	ext2fs_generic_bitmap_32 bm1 = (ext2fs_generic_bitmap_32) gen_bm1;
+	ext2fs_generic_bitmap_32 bm2 = (ext2fs_generic_bitmap_32) gen_bm2;
 	blk_t	i;
 
 	if (!bm1 || bm1->magic != magic)
@@ -361,15 +386,16 @@
 		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))
+		if (ext2fs_fast_test_block_bitmap(gen_bm1, i) !=
+		    ext2fs_fast_test_block_bitmap(gen_bm2, i))
 			return neq;
 
 	return 0;
 }
 
-void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap map)
+void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap gen_map)
 {
+	ext2fs_generic_bitmap_32 map = (ext2fs_generic_bitmap_32) gen_map;
 	__u32	i, j;
 
 	/* Protect loop from wrap-around if map->real_end is maxed */
@@ -379,11 +405,13 @@
 		ext2fs_set_bit(j, map->bitmap);
 }
 
-errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap,
+errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap gen_bmap,
 					  errcode_t magic,
 					  __u32 start, __u32 num,
 					  void *out)
 {
+	ext2fs_generic_bitmap_32 bmap = (ext2fs_generic_bitmap_32) gen_bmap;
+
 	if (!bmap || (bmap->magic != magic))
 		return magic;
 
@@ -394,11 +422,13 @@
 	return 0;
 }
 
-errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap,
+errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap gen_bmap,
 					  errcode_t magic,
 					  __u32 start, __u32 num,
 					  void *in)
 {
+	ext2fs_generic_bitmap_32 bmap = (ext2fs_generic_bitmap_32) gen_bmap;
+
 	if (!bmap || (bmap->magic != magic))
 		return magic;
 
@@ -432,10 +462,11 @@
 /*
  * Return true if all of the bits in a specified range are clear
  */
-static int ext2fs_test_clear_generic_bitmap_range(ext2fs_generic_bitmap bitmap,
+static int ext2fs_test_clear_generic_bitmap_range(ext2fs_generic_bitmap gen_bitmap,
 						  unsigned int start,
 						  unsigned int len)
 {
+	ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
 	size_t start_byte, len_byte = len >> 3;
 	unsigned int start_bit, len_bit = len % 8;
 	int first_bit = 0;
@@ -504,14 +535,15 @@
 	return ext2fs_mem_is_zero(ADDR + start_byte, len_byte);
 }
 
-errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap bitmap,
+errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap gen_bitmap,
 						__u32 start, __u32 end,
 						__u32 *out)
 {
+	ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
 	blk_t b;
 
 	if (start < bitmap->start || end > bitmap->end || start > end) {
-		ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
+		ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR, start);
 		return EINVAL;
 	}
 
@@ -527,14 +559,15 @@
 	return ENOENT;
 }
 
-errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap bitmap,
+errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap gen_bitmap,
 					       __u32 start, __u32 end,
 					       __u32 *out)
 {
+	ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
 	blk_t b;
 
 	if (start < bitmap->start || end > bitmap->end || start > end) {
-		ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
+		ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR, start);
 		return EINVAL;
 	}
 
@@ -550,9 +583,11 @@
 	return ENOENT;
 }
 
-int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap gen_bitmap,
 				   blk_t block, int num)
 {
+	ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
+
 	EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
 	if ((block < bitmap->start) || (block+num-1 > bitmap->real_end)) {
 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
@@ -563,9 +598,11 @@
 						      bitmap, block, num);
 }
 
-int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap,
+int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap gen_bitmap,
 				   ext2_ino_t inode, int num)
 {
+	ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
+
 	EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
 	if ((inode < bitmap->start) || (inode+num-1 > bitmap->real_end)) {
 		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
@@ -576,9 +613,10 @@
 						      bitmap, inode, num);
 }
 
-void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap gen_bitmap,
 				    blk_t block, int num)
 {
+	ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
 	int	i;
 
 	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
@@ -590,9 +628,10 @@
 		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)
+void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap gen_bitmap,
+				      blk_t block, int num)
 {
+	ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
 	int	i;
 
 	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
diff --git a/lib/ext2fs/gen_bitmap64.c b/lib/ext2fs/gen_bitmap64.c
index 3fc7349..d6f3ac1 100644
--- a/lib/ext2fs/gen_bitmap64.c
+++ b/lib/ext2fs/gen_bitmap64.c
@@ -68,7 +68,7 @@
  * e2fsck can request an encoding which is optimized for that.
  */
 
-static void warn_bitmap(ext2fs_generic_bitmap bitmap,
+static void warn_bitmap(ext2fs_generic_bitmap_64 bitmap,
 			int code, __u64 arg)
 {
 #ifndef OMIT_COM_ERR
@@ -93,7 +93,7 @@
 				    const char *descr,
 				    ext2fs_generic_bitmap *ret)
 {
-	ext2fs_generic_bitmap	bitmap;
+	ext2fs_generic_bitmap_64 bitmap;
 	struct ext2_bitmap_ops	*ops;
 	ext2_ino_t num_dirs;
 	errcode_t retval;
@@ -119,7 +119,7 @@
 		return EINVAL;
 	}
 
-	retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap),
+	retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
 				    &bitmap);
 	if (retval)
 		return retval;
@@ -170,12 +170,12 @@
 		return retval;
 	}
 
-	*ret = bitmap;
+	*ret = (ext2fs_generic_bitmap) bitmap;
 	return 0;
 }
 
 #ifdef ENABLE_BMAP_STATS
-static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap)
+static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap_64 bitmap)
 {
 	struct ext2_bmap_statistics *stats = &bitmap->stats;
 #ifdef ENABLE_BMAP_STATS_OPS
@@ -241,13 +241,15 @@
 }
 #endif
 
-void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap)
+void ext2fs_free_generic_bmap(ext2fs_generic_bitmap gen_bmap)
 {
+	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
+
 	if (!bmap)
 		return;
 
 	if (EXT2FS_IS_32_BITMAP(bmap)) {
-		ext2fs_free_generic_bitmap(bmap);
+		ext2fs_free_generic_bitmap(gen_bmap);
 		return;
 	}
 
@@ -271,24 +273,25 @@
 	ext2fs_free_mem(&bmap);
 }
 
-errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src,
+errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap gen_src,
 				   ext2fs_generic_bitmap *dest)
 {
+	ext2fs_generic_bitmap_64 src = (ext2fs_generic_bitmap_64) gen_src;
 	char *descr, *new_descr;
-	ext2fs_generic_bitmap	new_bmap;
+	ext2fs_generic_bitmap_64 new_bmap;
 	errcode_t retval;
 
 	if (!src)
 		return EINVAL;
 
 	if (EXT2FS_IS_32_BITMAP(src))
-		return ext2fs_copy_generic_bitmap(src, dest);
+		return ext2fs_copy_generic_bitmap(gen_src, dest);
 
 	if (!EXT2FS_IS_64_BITMAP(src))
 		return EINVAL;
 
 	/* Allocate a new bitmap struct */
-	retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap),
+	retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
 				    &new_bmap);
 	if (retval)
 		return retval;
@@ -336,21 +339,23 @@
 		return retval;
 	}
 
-	*dest = new_bmap;
+	*dest = (ext2fs_generic_bitmap) new_bmap;
 
 	return 0;
 }
 
-errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap,
+errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap gen_bmap,
 				     __u64 new_end,
 				     __u64 new_real_end)
 {
+	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
+
 	if (!bmap)
 		return EINVAL;
 
 	if (EXT2FS_IS_32_BITMAP(bmap))
-		return ext2fs_resize_generic_bitmap(bmap->magic, new_end,
-						    new_real_end, bmap);
+		return ext2fs_resize_generic_bitmap(gen_bmap->magic, new_end,
+						    new_real_end, gen_bmap);
 
 	if (!EXT2FS_IS_64_BITMAP(bmap))
 		return EINVAL;
@@ -360,10 +365,12 @@
 	return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
 }
 
-errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap,
+errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap,
 					errcode_t neq,
 					__u64 end, __u64 *oend)
 {
+	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
+
 	if (!bitmap)
 		return EINVAL;
 
@@ -371,7 +378,8 @@
 		ext2_ino_t tmp_oend;
 		int retval;
 
-		retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic,
+		retval = ext2fs_fudge_generic_bitmap_end(gen_bitmap,
+							 bitmap->magic,
 							 neq, end, &tmp_oend);
 		if (oend)
 			*oend = tmp_oend;
@@ -389,13 +397,15 @@
 	return 0;
 }
 
-__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap)
+__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap gen_bitmap)
 {
+	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
+
 	if (!bitmap)
 		return EINVAL;
 
 	if (EXT2FS_IS_32_BITMAP(bitmap))
-		return ext2fs_get_generic_bitmap_start(bitmap);
+		return ext2fs_get_generic_bitmap_start(gen_bitmap);
 
 	if (!EXT2FS_IS_64_BITMAP(bitmap))
 		return EINVAL;
@@ -403,13 +413,15 @@
 	return bitmap->start;
 }
 
-__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap)
+__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap)
 {
+	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
+
 	if (!bitmap)
 		return EINVAL;
 
 	if (EXT2FS_IS_32_BITMAP(bitmap))
-		return ext2fs_get_generic_bitmap_end(bitmap);
+		return ext2fs_get_generic_bitmap_end(gen_bitmap);
 
 	if (!EXT2FS_IS_64_BITMAP(bitmap))
 		return EINVAL;
@@ -417,27 +429,31 @@
 	return bitmap->end;
 }
 
-void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap)
+void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap gen_bitmap)
 {
+	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
+
 	if (EXT2FS_IS_32_BITMAP(bitmap))
-		ext2fs_clear_generic_bitmap(bitmap);
+		ext2fs_clear_generic_bitmap(gen_bitmap);
 	else
-		bitmap->bitmap_ops->clear_bmap (bitmap);
+		bitmap->bitmap_ops->clear_bmap(bitmap);
 }
 
-int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap,
+int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
 			     __u64 arg)
 {
+	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
+
 	if (!bitmap)
 		return 0;
 
 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
 		if (arg & ~0xffffffffULL) {
-			ext2fs_warn_bitmap2(bitmap,
+			ext2fs_warn_bitmap2(gen_bitmap,
 					    EXT2FS_MARK_ERROR, 0xffffffff);
 			return 0;
 		}
-		return ext2fs_mark_generic_bitmap(bitmap, arg);
+		return ext2fs_mark_generic_bitmap(gen_bitmap, arg);
 	}
 
 	if (!EXT2FS_IS_64_BITMAP(bitmap))
@@ -462,19 +478,21 @@
 	return bitmap->bitmap_ops->mark_bmap(bitmap, arg);
 }
 
-int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap,
+int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
 			       __u64 arg)
 {
+	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
+
 	if (!bitmap)
 		return 0;
 
 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
 		if (arg & ~0xffffffffULL) {
-			ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR,
+			ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_UNMARK_ERROR,
 					    0xffffffff);
 			return 0;
 		}
-		return ext2fs_unmark_generic_bitmap(bitmap, arg);
+		return ext2fs_unmark_generic_bitmap(gen_bitmap, arg);
 	}
 
 	if (!EXT2FS_IS_64_BITMAP(bitmap))
@@ -492,19 +510,20 @@
 	return bitmap->bitmap_ops->unmark_bmap(bitmap, arg);
 }
 
-int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap,
+int ext2fs_test_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
 			     __u64 arg)
 {
+	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
 	if (!bitmap)
 		return 0;
 
 	if (EXT2FS_IS_32_BITMAP(bitmap)) {
 		if (arg & ~0xffffffffULL) {
-			ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR,
+			ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR,
 					    0xffffffff);
 			return 0;
 		}
-		return ext2fs_test_generic_bitmap(bitmap, arg);
+		return ext2fs_test_generic_bitmap(gen_bitmap, arg);
 	}
 
 	if (!EXT2FS_IS_64_BITMAP(bitmap))
@@ -529,20 +548,22 @@
 	return bitmap->bitmap_ops->test_bmap(bitmap, arg);
 }
 
-errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap,
+errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
 					__u64 start, unsigned int num,
 					void *in)
 {
+	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
+
 	if (!bmap)
 		return EINVAL;
 
 	if (EXT2FS_IS_32_BITMAP(bmap)) {
 		if ((start+num-1) & ~0xffffffffULL) {
-			ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR,
+			ext2fs_warn_bitmap2(gen_bmap, EXT2FS_UNMARK_ERROR,
 					    0xffffffff);
 			return EINVAL;
 		}
-		return ext2fs_set_generic_bitmap_range(bmap, bmap->magic,
+		return ext2fs_set_generic_bitmap_range(gen_bmap, bmap->magic,
 						       start, num, in);
 	}
 
@@ -554,20 +575,22 @@
 	return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
 }
 
-errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap,
+errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
 					__u64 start, unsigned int num,
 					void *out)
 {
+	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
+
 	if (!bmap)
 		return EINVAL;
 
 	if (EXT2FS_IS_32_BITMAP(bmap)) {
 		if ((start+num-1) & ~0xffffffffULL) {
-			ext2fs_warn_bitmap2(bmap,
+			ext2fs_warn_bitmap2(gen_bmap,
 					    EXT2FS_UNMARK_ERROR, 0xffffffff);
 			return EINVAL;
 		}
-		return ext2fs_get_generic_bitmap_range(bmap, bmap->magic,
+		return ext2fs_get_generic_bitmap_range(gen_bmap, bmap->magic,
 						       start, num, out);
 	}
 
@@ -580,9 +603,11 @@
 }
 
 errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
-				      ext2fs_generic_bitmap bm1,
-				      ext2fs_generic_bitmap bm2)
+				      ext2fs_generic_bitmap gen_bm1,
+				      ext2fs_generic_bitmap gen_bm2)
 {
+	ext2fs_generic_bitmap_64 bm1 = (ext2fs_generic_bitmap_64) gen_bm1;
+	ext2fs_generic_bitmap_64 bm2 = (ext2fs_generic_bitmap_64) gen_bm2;
 	blk64_t	i;
 
 	if (!bm1 || !bm2)
@@ -592,7 +617,8 @@
 
 	/* Now we know both bitmaps have the same magic */
 	if (EXT2FS_IS_32_BITMAP(bm1))
-		return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2);
+		return ext2fs_compare_generic_bitmap(bm1->magic, neq,
+						     gen_bm1, gen_bm2);
 
 	if (!EXT2FS_IS_64_BITMAP(bm1))
 		return EINVAL;
@@ -602,19 +628,20 @@
 		return neq;
 
 	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
-		if (ext2fs_test_generic_bmap(bm1, i) !=
-		    ext2fs_test_generic_bmap(bm2, i))
+		if (ext2fs_test_generic_bmap(gen_bm1, i) !=
+		    ext2fs_test_generic_bmap(gen_bm2, i))
 			return neq;
 
 	return 0;
 }
 
-void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap)
+void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap gen_bmap)
 {
+	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
 	__u64	start, num;
 
 	if (EXT2FS_IS_32_BITMAP(bmap)) {
-		ext2fs_set_generic_bitmap_padding(bmap);
+		ext2fs_set_generic_bitmap_padding(gen_bmap);
 		return;
 	}
 
@@ -624,9 +651,10 @@
 	/* XXX ought to warn on error */
 }
 
-int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap,
+int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
 				    blk64_t block, unsigned int num)
 {
+	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
 	__u64	end = block + num;
 
 	if (!bmap)
@@ -666,9 +694,10 @@
 	return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
 }
 
-void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap,
+void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
 				     blk64_t block, unsigned int num)
 {
+	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
 	__u64	end = block + num;
 
 	if (!bmap)
@@ -704,9 +733,10 @@
 	bmap->bitmap_ops->mark_bmap_extent(bmap, block, num);
 }
 
-void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap,
+void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
 				       blk64_t block, unsigned int num)
 {
+	ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
 	__u64	end = block + num;
 
 	if (!bmap)
@@ -742,8 +772,10 @@
 	bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num);
 }
 
-void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func)
+void ext2fs_warn_bitmap32(ext2fs_generic_bitmap gen_bitmap, const char *func)
 {
+	ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
+
 #ifndef OMIT_COM_ERR
 	if (bitmap && bitmap->description)
 		com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
@@ -758,21 +790,22 @@
 errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
 					   ext2fs_block_bitmap *bitmap)
 {
-	ext2fs_block_bitmap	cmap, bmap;
+	ext2fs_generic_bitmap_64 bmap, cmap;
+	ext2fs_block_bitmap	gen_bmap = *bitmap, gen_cmap;
 	errcode_t		retval;
 	blk64_t			i, b_end, c_end;
 	int			n, ratio;
 
-	bmap = *bitmap;
-
-	if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(bmap))
+	bmap = (ext2fs_generic_bitmap_64) gen_bmap;
+	if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(gen_bmap))
 		return 0;	/* Nothing to do */
 
 	retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap",
-					      &cmap);
+					      &gen_cmap);
 	if (retval)
 		return retval;
 
+	cmap = (ext2fs_generic_bitmap_64) gen_cmap;
 	i = bmap->start;
 	b_end = bmap->end;
 	bmap->end = bmap->real_end;
@@ -781,8 +814,8 @@
 	n = 0;
 	ratio = 1 << fs->cluster_ratio_bits;
 	while (i < bmap->real_end) {
-		if (ext2fs_test_block_bitmap2(bmap, i)) {
-			ext2fs_mark_block_bitmap2(cmap, i);
+		if (ext2fs_test_block_bitmap2(gen_bmap, i)) {
+			ext2fs_mark_block_bitmap2(gen_cmap, i);
 			i += ratio - n;
 			n = 0;
 			continue;
@@ -793,14 +826,15 @@
 	}
 	bmap->end = b_end;
 	cmap->end = c_end;
-	ext2fs_free_block_bitmap(bmap);
-	*bitmap = cmap;
+	ext2fs_free_block_bitmap(gen_bmap);
+	*bitmap = (ext2fs_block_bitmap) cmap;
 	return 0;
 }
 
 errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap,
 					      __u64 start, __u64 end, __u64 *out)
 {
+	ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
 	__u64 cstart, cend, cout;
 	errcode_t retval;
 
@@ -826,27 +860,27 @@
 	if (!EXT2FS_IS_64_BITMAP(bitmap))
 		return EINVAL;
 
-	cstart = start >> bitmap->cluster_bits;
-	cend = end >> bitmap->cluster_bits;
+	cstart = start >> bmap64->cluster_bits;
+	cend = end >> bmap64->cluster_bits;
 
-	if (cstart < bitmap->start || cend > bitmap->end || start > end) {
-		warn_bitmap(bitmap, EXT2FS_TEST_ERROR, start);
+	if (cstart < bmap64->start || cend > bmap64->end || start > end) {
+		warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
 		return EINVAL;
 	}
 
-	if (bitmap->bitmap_ops->find_first_zero) {
-		retval = bitmap->bitmap_ops->find_first_zero(bitmap, cstart,
+	if (bmap64->bitmap_ops->find_first_zero) {
+		retval = bmap64->bitmap_ops->find_first_zero(bmap64, cstart,
 							     cend, &cout);
 		if (retval)
 			return retval;
 	found:
-		cout <<= bitmap->cluster_bits;
+		cout <<= bmap64->cluster_bits;
 		*out = (cout >= start) ? cout : start;
 		return 0;
 	}
 
 	for (cout = cstart; cout <= cend; cout++)
-		if (!bitmap->bitmap_ops->test_bmap(bitmap, cout))
+		if (!bmap64->bitmap_ops->test_bmap(bmap64, cout))
 			goto found;
 
 	return ENOENT;
@@ -855,6 +889,7 @@
 errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap,
 					     __u64 start, __u64 end, __u64 *out)
 {
+	ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
 	__u64 cstart, cend, cout;
 	errcode_t retval;
 
@@ -880,27 +915,27 @@
 	if (!EXT2FS_IS_64_BITMAP(bitmap))
 		return EINVAL;
 
-	cstart = start >> bitmap->cluster_bits;
-	cend = end >> bitmap->cluster_bits;
+	cstart = start >> bmap64->cluster_bits;
+	cend = end >> bmap64->cluster_bits;
 
-	if (cstart < bitmap->start || cend > bitmap->end || start > end) {
-		warn_bitmap(bitmap, EXT2FS_TEST_ERROR, start);
+	if (cstart < bmap64->start || cend > bmap64->end || start > end) {
+		warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
 		return EINVAL;
 	}
 
-	if (bitmap->bitmap_ops->find_first_set) {
-		retval = bitmap->bitmap_ops->find_first_set(bitmap, cstart,
+	if (bmap64->bitmap_ops->find_first_set) {
+		retval = bmap64->bitmap_ops->find_first_set(bmap64, cstart,
 							    cend, &cout);
 		if (retval)
 			return retval;
 	found:
-		cout <<= bitmap->cluster_bits;
+		cout <<= bmap64->cluster_bits;
 		*out = (cout >= start) ? cout : start;
 		return 0;
 	}
 
 	for (cout = cstart; cout <= cend; cout++)
-		if (bitmap->bitmap_ops->test_bmap(bitmap, cout))
+		if (bmap64->bitmap_ops->test_bmap(bmap64, cout))
 			goto found;
 
 	return ENOENT;
diff --git a/lib/ext2fs/tst_bitmaps.c b/lib/ext2fs/tst_bitmaps.c
index 574fb7a..f6196b3 100644
--- a/lib/ext2fs/tst_bitmaps.c
+++ b/lib/ext2fs/tst_bitmaps.c
@@ -190,7 +190,8 @@
 	ext2fs_close_free(&test_fs);
 }
 
-void setup_cmd(int argc, char **argv)
+void setup_cmd(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+	       void *infop EXT2FS_ATTR((unused)))
 {
 	int		c, err;
 	unsigned int	blocks = 128;
@@ -234,7 +235,8 @@
 	setup_filesystem(argv[0], blocks, inodes, type, flags);
 }
 
-void close_cmd(int argc, char **argv)
+void close_cmd(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+	       void *infop EXT2FS_ATTR((unused)))
 {
 	if (check_fs_open(argv[0]))
 		return;
@@ -269,7 +271,9 @@
 	free(buf);
 }
 
-void dump_inode_bitmap_cmd(int argc, char **argv)
+void dump_inode_bitmap_cmd(int argc, char **argv,
+			   int sci_idx EXT2FS_ATTR((unused)),
+			   void *infop EXT2FS_ATTR((unused)))
 {
 	if (check_fs_open(argv[0]))
 		return;
@@ -278,7 +282,9 @@
 	dump_bitmap(test_fs->inode_map, 1, test_fs->super->s_inodes_count);
 }
 	
-void dump_block_bitmap_cmd(int argc, char **argv)
+void dump_block_bitmap_cmd(int argc, char **argv,
+			   int sci_idx EXT2FS_ATTR((unused)),
+			   void *infop EXT2FS_ATTR((unused)))
 {
 	if (check_fs_open(argv[0]))
 		return;
@@ -288,7 +294,8 @@
 		    test_fs->super->s_blocks_count);
 }
 	
-void do_setb(int argc, char *argv[])
+void do_setb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int block, num;
 	int err;
@@ -326,7 +333,8 @@
 			test_result, op_result);
 }
 
-void do_clearb(int argc, char *argv[])
+void do_clearb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	       void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int block, num;
 	int err;
@@ -364,7 +372,8 @@
 			test_result, op_result);
 }
 
-void do_testb(int argc, char *argv[])
+void do_testb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int block, num;
 	int err;
@@ -399,7 +408,8 @@
 	printf("Block %u is %s\n", block, test_result ? "set" : "clear");
 }
 
-void do_ffzb(int argc, char *argv[])
+void do_ffzb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int start, end;
 	int err;
@@ -432,7 +442,8 @@
 	printf("First unmarked block is %llu\n", out);
 }
 
-void do_ffsb(int argc, char *argv[])
+void do_ffsb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int start, end;
 	int err;
@@ -466,7 +477,8 @@
 }
 
 
-void do_zerob(int argc, char *argv[])
+void do_zerob(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	if (check_fs_open(argv[0]))
 		return;
@@ -475,7 +487,8 @@
 	ext2fs_clear_block_bitmap(test_fs->block_map);
 }
 
-void do_seti(int argc, char *argv[])
+void do_seti(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int inode;
 	int err;
@@ -504,7 +517,8 @@
 	}
 }
 
-void do_cleari(int argc, char *argv[])
+void do_cleari(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	       void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int inode;
 	int err;
@@ -533,7 +547,8 @@
 	}
 }
 
-void do_testi(int argc, char *argv[])
+void do_testi(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int inode;
 	int err;
@@ -555,7 +570,8 @@
 	printf("Inode %u is %s\n", inode, test_result ? "set" : "clear");
 }
 
-void do_ffzi(int argc, char *argv[])
+void do_ffzi(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int start, end;
 	int err;
@@ -588,7 +604,8 @@
 	printf("First unmarked inode is %u\n", out);
 }
 
-void do_ffsi(int argc, char *argv[])
+void do_ffsi(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	     void *infop EXT2FS_ATTR((unused)))
 {
 	unsigned int start, end;
 	int err;
@@ -621,7 +638,8 @@
 	printf("First marked inode is %u\n", out);
 }
 
-void do_zeroi(int argc, char *argv[])
+void do_zeroi(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
+	      void *infop EXT2FS_ATTR((unused)))
 {
 	if (check_fs_open(argv[0]))
 		return;
diff --git a/lib/ext2fs/tst_libext2fs.c b/lib/ext2fs/tst_libext2fs.c
index a90bff2..3e7497c 100644
--- a/lib/ext2fs/tst_libext2fs.c
+++ b/lib/ext2fs/tst_libext2fs.c
@@ -43,7 +43,8 @@
 }
 
 
-void do_block_iterate(int argc, char **argv)
+void do_block_iterate(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		      void *infop EXT2FS_ATTR((unused)))
 {
 	const char	*usage = "block_iterate <file> <flags";
 	ext2_ino_t	ino;
diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index 7a4c9bf..16e2052 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -1081,6 +1081,38 @@
 #define BLKDISCARD		_IO(0x12,119)
 #endif
 
+/*
+ * Try a PUNCH_HOLE to unmap blocks, then BLKDISCARD if that doesn't work.
+ * We prefer PUNCH_HOLE because it invalidates the page cache, even on block
+ * devices.
+ */
+static int __unix_discard(int fd, int is_bdev, off_t offset, off_t len)
+{
+#ifdef BLKDISCARD
+	__u64 range[2];
+#endif
+	int ret = -1;
+
+#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)
+	ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+			offset, len);
+	if (ret == 0)
+		return 0;
+#endif
+#ifdef BLKDISCARD
+	if (is_bdev) {
+		range[0] = (__u64)offset;
+		range[1] = (__u64)len;
+
+		ret = ioctl(fd, BLKDISCARD, &range);
+		if (ret == 0)
+			return 0;
+	}
+#endif
+	errno = EOPNOTSUPP;
+	return ret;
+}
+
 static errcode_t unix_discard(io_channel channel, unsigned long long block,
 			      unsigned long long count)
 {
@@ -1091,31 +1123,10 @@
 	data = (struct unix_private_data *) channel->private_data;
 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
 
-	if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) {
-#ifdef BLKDISCARD
-		__u64 range[2];
-
-		range[0] = (__u64)(block) * channel->block_size + data->offset;
-		range[1] = (__u64)(count) * channel->block_size;
-
-		ret = ioctl(data->dev, BLKDISCARD, &range);
-#else
-		goto unimplemented;
-#endif
-	} else {
-#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE)
-		/*
-		 * If we are not on block device, try to use punch hole
-		 * to reclaim free space.
-		 */
-		ret = fallocate(data->dev,
-				FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
-				(off_t)(block) * channel->block_size + data->offset,
-				(off_t)(count) * channel->block_size);
-#else
-		goto unimplemented;
-#endif
-	}
+	ret = __unix_discard(data->dev,
+			(channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE),
+			(off_t)(block) * channel->block_size + data->offset,
+			(off_t)(count) * channel->block_size);
 	if (ret < 0) {
 		if (errno == EOPNOTSUPP)
 			goto unimplemented;
@@ -1126,6 +1137,31 @@
 	return EXT2_ET_UNIMPLEMENTED;
 }
 
+/*
+ * If we know about ZERO_RANGE, try that before we try PUNCH_HOLE because
+ * ZERO_RANGE doesn't unmap preallocated blocks.  We prefer fallocate because
+ * it always invalidates page cache, and libext2fs requires that reads after
+ * ZERO_RANGE return zeroes.
+ */
+static int __unix_zeroout(int fd, off_t offset, off_t len)
+{
+	int ret = -1;
+
+#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_ZERO_RANGE)
+	ret = fallocate(fd, FALLOC_FL_ZERO_RANGE, offset, len);
+	if (ret == 0)
+		return 0;
+#endif
+#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)
+	ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+			offset,  len);
+	if (ret == 0)
+		return 0;
+#endif
+	errno = EOPNOTSUPP;
+	return ret;
+}
+
 /* parameters might not be used if OS doesn't support zeroout */
 #if __GNUC_PREREQ (4, 6)
 #pragma GCC diagnostic push
@@ -1144,10 +1180,7 @@
 	if (safe_getenv("UNIX_IO_NOZEROOUT"))
 		goto unimplemented;
 
-	if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) {
-		/* Not implemented until the BLKZEROOUT mess is fixed */
-		goto unimplemented;
-	} else {
+	if (!(channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE)) {
 		/* Regular file, try to use truncate/punch/zero. */
 		struct stat statbuf;
 
@@ -1167,26 +1200,11 @@
 			if (ret)
 				goto err;
 		}
-#if defined(HAVE_FALLOCATE) && (defined(FALLOC_FL_ZERO_RANGE) || \
-	(defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)))
-#if defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)
-		ret = fallocate(data->dev,
-				FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
-				(off_t)(block) * channel->block_size + data->offset,
-				(off_t)(count) * channel->block_size);
-		if (ret == 0)
-			goto err;
-#endif
-#ifdef FALLOC_FL_ZERO_RANGE
-		ret = fallocate(data->dev,
-				FALLOC_FL_ZERO_RANGE,
-				(off_t)(block) * channel->block_size + data->offset,
-				(off_t)(count) * channel->block_size);
-#endif
-#else
-		goto unimplemented;
-#endif /* HAVE_FALLOCATE && (ZERO_RANGE || (PUNCH_HOLE && KEEP_SIZE)) */
 	}
+
+	ret = __unix_zeroout(data->dev,
+			(off_t)(block) * channel->block_size + data->offset,
+			(off_t)(count) * channel->block_size);
 err:
 	if (ret < 0) {
 		if (errno == EOPNOTSUPP)
diff --git a/misc/e2freefrag.c b/misc/e2freefrag.c
index 268fac9..6eb4c73 100644
--- a/misc/e2freefrag.c
+++ b/misc/e2freefrag.c
@@ -371,7 +371,8 @@
 #ifdef DEBUGFS
 #include "debugfs.h"
 
-void do_freefrag(int argc, char **argv)
+void do_freefrag(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		 void *infop EXT2FS_ATTR((unused)))
 #else
 int main(int argc, char *argv[])
 #endif
diff --git a/misc/tune2fs.8.in b/misc/tune2fs.8.in
index 740d166..f1def2b 100644
--- a/misc/tune2fs.8.in
+++ b/misc/tune2fs.8.in
@@ -238,6 +238,10 @@
 This superblock setting is only honored in 2.6.35+ kernels;
 and not at all by the ext2 and ext3 file system drivers.
 .TP
+.B force_fsck
+Set a flag in the filesystem superblock indicating that errors have been found.
+This will force fsck to run at the next mount.
+.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.
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index ec977b8..a680b46 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -2125,6 +2125,10 @@
 			       intv);
 			fs->super->s_mmp_update_interval = intv;
 			ext2fs_mark_super_dirty(fs);
+		} else if (!strcmp(token, "force_fsck")) {
+			fs->super->s_state |= EXT2_ERROR_FS;
+			printf(_("Setting filesystem error flag to force fsck.\n"));
+			ext2fs_mark_super_dirty(fs);
 		} else if (!strcmp(token, "test_fs")) {
 			fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS;
 			printf("Setting test filesystem flag\n");
@@ -2207,6 +2211,7 @@
 			"\tmmp_update_interval=<mmp update interval in seconds>\n"
 			"\tstride=<RAID per-disk chunk size in blocks>\n"
 			"\tstripe_width=<RAID stride*data disks in blocks>\n"
+			"\tforce_fsck\n"
 			"\ttest_fs\n"
 			"\t^test_fs\n"));
 		free(buf);
diff --git a/scrub/Makefile.in b/scrub/Makefile.in
new file mode 100644
index 0000000..769c35b
--- /dev/null
+++ b/scrub/Makefile.in
@@ -0,0 +1,185 @@
+#
+# Makefile for e2scrub
+#
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+top_builddir = ..
+my_dir = scrub
+INSTALL = @INSTALL@
+
+@MCONFIG@
+
+PROGS=		e2scrub e2scrub_all
+MANPAGES=	e2scrub.8 e2scrub_all.8
+CONFFILES=	e2scrub.conf
+
+ifeq ($(HAVE_UDEV),yes)
+UDEV_RULES	= e2scrub.rules
+INSTALLDIRS_TGT	+= installdirs-udev
+INSTALL_TGT	+= install-udev
+UNINSTALL_TGT	+= uninstall-udev
+endif
+
+ifeq ($(HAVE_CROND),yes)
+CRONTABS	= e2scrub_all.cron
+LIBPROGS	+= e2scrub_all_cron
+INSTALLDIRS_TGT	+= installdirs-crond installdirs-libprogs
+INSTALL_TGT	+= install-crond install-libprogs
+UNINSTALL_TGT	+= uninstall-crond uninstall-libprogs
+endif
+
+ifeq ($(HAVE_SYSTEMD),yes)
+SERVICE_FILES	= e2scrub@.service e2scrub_all.service e2scrub_all.timer e2scrub_fail@.service e2scrub_reap.service
+LIBPROGS	+= e2scrub_fail
+INSTALLDIRS_TGT	+= installdirs-systemd installdirs-libprogs
+INSTALL_TGT	+= install-systemd install-libprogs
+UNINSTALL_TGT	+= uninstall-systemd uninstall-libprogs
+endif
+
+all:: $(PROGS) $(MANPAGES) $(CONFFILES) $(UDEV_RULES) $(SERVICE_FILES) $(CRONTABS) $(LIBPROGS)
+
+e2scrub: $(DEP_SUBSTITUTE) e2scrub.in
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2scrub.in $@
+	$(Q) chmod a+x $@
+
+e2scrub_all: e2scrub_all.in
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2scrub_all.in $@
+	$(Q) chmod a+x $@
+
+e2scrub_fail: e2scrub_fail.in
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2scrub_fail.in $@
+	$(Q) chmod a+x $@
+
+e2scrub_all_cron: e2scrub_all_cron.in
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2scrub_all_cron.in $@
+	$(Q) chmod a+x $@
+
+%.8: %.8.in $(DEP_SUBSTITUTE)
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $< $@
+
+%.conf: %.conf.in $(DEP_SUBSTITUTE)
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $< $@
+
+%.rules: %.rules.in $(DEP_SUBSTITUTE)
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $< $@
+
+%.service: %.service.in $(DEP_SUBSTITUTE)
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $< $@
+
+%.cron: %.cron.in $(DEP_SUBSTITUTE)
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $< $@
+
+%.timer: %.timer.in $(DEP_SUBSTITUTE)
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $< $@
+
+installdirs-udev:
+	$(E) "	MKDIR_P $(UDEV_RULES_DIR)"
+	$(Q) $(MKDIR_P) $(DESTDIR)$(UDEV_RULES_DIR)
+
+installdirs-crond:
+	$(E) "	MKDIR_P $(CROND_DIR)"
+	$(Q) $(MKDIR_P) $(DESTDIR)$(CROND_DIR)
+
+installdirs-libprogs:
+	$(E) "	MKDIR_P $(pkglibdir)"
+	$(Q) $(MKDIR_P) $(DESTDIR)$(pkglibdir)
+
+installdirs-systemd:
+	$(E) "	MKDIR_P $(SYSTEMD_SYSTEM_UNIT_DIR)"
+	$(Q) $(MKDIR_P) $(DESTDIR)$(SYSTEMD_SYSTEM_UNIT_DIR)
+
+installdirs: $(INSTALLDIRS_TGT)
+	$(E) "	MKDIR_P $(root_sbindir) $(man8dir) $(root_sysconfdir)"
+	$(Q) $(MKDIR_P) $(DESTDIR)$(root_sbindir) \
+		$(DESTDIR)$(man8dir) $(DESTDIR)$(root_sysconfdir)
+
+install-udev:
+	$(Q) for i in $(UDEV_RULES); do \
+		$(ES) "	INSTALL $(UDEV_RULES_DIR)/$$i"; \
+		$(INSTALL_PROGRAM) $$i $(DESTDIR)$(UDEV_RULES_DIR)/96-$$i; \
+	done
+
+install-crond:
+	$(Q) for i in $(CRONTABS); do \
+		$(ES) "	INSTALL $(CROND_DIR)/$$i"; \
+		$(INSTALL_PROGRAM) $$i $(DESTDIR)$(CROND_DIR)/$$i; \
+	done
+
+install-libprogs: $(LIBPROGS)
+	$(Q) for i in $(LIBPROGS); do \
+		$(ES) "	INSTALL $(pkglibdir)/$$i"; \
+		$(INSTALL_PROGRAM) $$i $(DESTDIR)$(pkglibdir)/$$i; \
+	done
+
+install-systemd: $(SERVICE_FILES)
+	$(Q) for i in $(SERVICE_FILES); do \
+		$(ES) "	INSTALL_DATA $(SYSTEMD_SYSTEM_UNIT_DIR)/$$i"; \
+		$(INSTALL_DATA) $$i $(DESTDIR)$(SYSTEMD_SYSTEM_UNIT_DIR)/$$i; \
+	done
+
+install: $(PROGS) $(MANPAGES) $(FMANPAGES) installdirs $(INSTALL_TGT)
+	$(Q) for i in $(PROGS); do \
+		$(ES) "	INSTALL $(root_sbindir)/$$i"; \
+		$(INSTALL_PROGRAM) $$i $(DESTDIR)$(root_sbindir)/$$i; \
+	done
+	$(Q) for i in $(MANPAGES); do \
+		for j in $(COMPRESS_EXT); do \
+			$(RM) -f $(DESTDIR)$(man8dir)/$$i.$$j; \
+		done; \
+		$(ES) "	INSTALL_DATA $(man8dir)/$$i"; \
+		$(INSTALL_DATA) $$i $(DESTDIR)$(man8dir)/$$i; \
+	done
+	$(Q) for i in $(CONFFILES); do \
+		$(ES) "	INSTALL_DATA $(root_sysconfdir)/$$i"; \
+		$(INSTALL_DATA) $$i $(DESTDIR)$(root_sysconfdir)/$$i; \
+	done
+
+uninstall-udev:
+	for i in $(UDEV_RULES); do \
+		$(RM) -f $(DESTDIR)$(UDEV_RULES_DIR)/96-$$i; \
+	done
+
+uninstall-crond:
+	for i in $(CRONTABS); do \
+		$(RM) -f $(DESTDIR)$(CROND_DIR)/$$i; \
+	done
+
+uninstall-libprogs:
+	for i in $(LIBPROGS); do \
+		$(RM) -f $(DESTDIR)$(pkglibdir)/$$i; \
+	done
+
+uninstall-systemd:
+	for i in $(SERVICE_FILES); do \
+		$(RM) -f $(DESTDIR)$(SYSTEMD_SYSTEM_UNIT_DIR)/$$i; \
+	done
+
+uninstall: $(UNINSTALL_TGT)
+	for i in $(PROGS); do \
+		$(RM) -f $(DESTDIR)$(root_sbindir)/$$i; \
+	done
+	for i in $(MANPAGES); do \
+		$(RM) -f $(DESTDIR)$(man8dir)/$$i; \
+	done
+	for i in $(CONFFILES); do \
+		$(RM) -f $(DESTDIR)$(root_sysconfdir)/$$i; \
+	done
+
+clean::
+	$(RM) -f $(PROGS)
+
+mostlyclean: clean
+distclean: clean
+	$(RM) -f .depend Makefile $(srcdir)/TAGS $(srcdir)/Makefile.in.old
diff --git a/scrub/e2scrub.8.in b/scrub/e2scrub.8.in
new file mode 100644
index 0000000..ff03523
--- /dev/null
+++ b/scrub/e2scrub.8.in
@@ -0,0 +1,60 @@
+.TH E2SCRUB 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+e2scrub - check the contents of a mounted ext[234] filesystem
+.SH SYNOPSYS
+.B
+e2scrub [OPTION] MOUNTPOINT | DEVICE
+.SH DESCRIPTION
+.B e2scrub
+attempts to check (but not repair) all metadata in a mounted ext[234]
+filesystem if the filesystem resides on a LVM logical volume.
+The block device of the LVM logical volume can also be passed in.
+
+This program snapshots the volume and runs a file system check on the snapshot
+to look for corruption errors.
+The LVM volume group must have at least 256MiB of unallocated space to
+dedicate to the snapshot or the logical volume will be skipped.
+The snapshot will be named
+.IR lvname ".e2scrub"
+and
+.B udev
+will not create symbolic links to it under
+.IR /dev/disk .
+Every attempt will be made to remove the snapshots prior to running
+.BR e2scrub ,
+but in a dire situation it may be necessary to remove the snapshot manually.
+
+If no errors are found,
+.B fstrim
+can be called on the file system if it is mounted.
+If errors are found, the file system will be marked as having errors.
+The filesystem should be taken offline and
+.B e2fsck
+run as soon as possible, because
+.B e2scrub
+does not fix corruptions.
+If the filesystem is not repaired,
+.B e2fsck
+will be run before the next mount.
+.SH OPTIONS
+.TP
+\fB-r\fR
+Remove the e2scrub snapshot and exit without checking anything.
+.TP
+\fB-t\fR
+Run
+.B
+fstrim(1)
+on the mounted filesystem if no errors are found.
+.TP
+\fB-V\fR
+Print version information and exit.
+.SH EXIT CODE
+The exit codes are the same as in
+.BR e2fsck (8)
+.SH SEE ALSO
+.BR e2fsck (8)
+.SH AUTHOR
+Darrick J. Wong <darrick.wong@oracle.com>
+.SH COPYRIGHT
+Copyright ©2018 Oracle.  License is GPLv2+. <http://www.gnu.org/licenses/gpl-2.0.html>
diff --git a/scrub/e2scrub.conf.in b/scrub/e2scrub.conf.in
new file mode 100644
index 0000000..69f997f
--- /dev/null
+++ b/scrub/e2scrub.conf.in
@@ -0,0 +1,13 @@
+# e2scrub configuration file
+
+# Snapshots will be created to run fsck; the snapshot will be of this size.
+# snap_size_mb=256
+
+# Set this to 1 to enable fstrim for everyone.
+# fstrim=0
+
+# Arguments passed into e2fsck.
+# e2fsck_opts="-vtt"
+
+# Set this to 1 to have e2scrub_all scrub all LVs, not just the mounted ones.
+# scrub_all=0
diff --git a/scrub/e2scrub.in b/scrub/e2scrub.in
new file mode 100644
index 0000000..e1965db
--- /dev/null
+++ b/scrub/e2scrub.in
@@ -0,0 +1,261 @@
+#!/bin/bash
+
+#  Copyright (C) 2018 Oracle.  All Rights Reserved.
+#
+#  Author: Darrick J. Wong <darrick.wong@oracle.com>
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it would be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write the Free Software Foundation,
+#  Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+
+# Automatically check a LVM-managed filesystem online.
+# We use lvm snapshots to do this, which means that we can only
+# check filesystems in VGs that have at least 256MB (or so) of
+# free space.
+
+snap_size_mb=256
+fstrim=0
+reap=0
+e2fsck_opts=""
+conffile="@root_sysconfdir@/e2scrub.conf"
+
+test -f "${conffile}" && . "${conffile}"
+
+print_help() {
+	echo "Usage: $0 [OPTIONS] mountpoint | device"
+	echo
+	echo "mountpoint must be on a LVM-managed block device"
+	echo "-r: Remove e2scrub snapshot and exit, do not check anything."
+	echo "-t: Run fstrim if successful."
+	echo "-V: Print version information and exit."
+}
+
+print_version() {
+	echo "e2scrub @E2FSPROGS_VERSION@ (@E2FSPROGS_DATE@)"
+}
+
+exitcode() {
+	ret="$1"
+
+	# If we're being run as a service, the return code must fit the LSB
+	# init script action error guidelines, which is to say that we
+	# compress all errors to 1 ("generic or unspecified error", LSB 5.0
+	# section 22.2) and hope the admin will scan the log for what
+	# actually happened.
+
+	# We have to sleep 2 seconds here because journald uses the pid to
+	# connect our log messages to the systemd service.  This is critical
+	# for capturing all the log messages if the scrub fails, because the
+	# fail service uses the service name to gather log messages for the
+	# error report.
+	if [ -n "${SERVICE_MODE}" ]; then
+		test "${ret}" -ne 0 && ret=1
+		sleep 2
+	fi
+
+	exit "${ret}"
+}
+
+while getopts "rtV" opt; do
+	case "${opt}" in
+	"r") reap=1;;
+	"t") fstrim=1;;
+	"V") print_version; exitcode 0;;
+	*) print_help; exitcode 2;;
+	esac
+done
+shift "$((OPTIND - 1))"
+
+arg="$1"
+if [ -z "${arg}" ]; then
+	print_help
+	exitcode 1
+fi
+
+# Find the device for a given mountpoint
+dev_from_mount() {
+	local mountpt="$(realpath "$1")"
+
+	lsblk -o NAME,FSTYPE,MOUNTPOINT -p -P -n 2> /dev/null | while read vars; do
+		eval "${vars}"
+		if [ "${mountpt}" != "${MOUNTPOINT}" ]; then
+			continue
+		fi
+		case "${FSTYPE}" in
+		ext[234])
+			echo "${NAME}"
+			return 0
+			;;
+		esac
+	done
+	return 1
+}
+
+# Check a device argument
+dev_from_arg() {
+	local dev="$1"
+	local fstype="$(lsblk -o FSTYPE -n "${dev}" 2> /dev/null)"
+
+	case "${fstype}" in
+	ext[234])
+		echo "${dev}"
+		return 0
+		;;
+	esac
+	return 1
+}
+
+mnt_from_dev() {
+	local dev="$1"
+
+	if [ -n "${dev}" ]; then
+		lsblk -o MOUNTPOINT -n "${dev}"
+	fi
+}
+
+# Construct block device path and mountpoint from argument
+if [ -b "${arg}" ]; then
+	dev="$(dev_from_arg "${arg}")"
+	mnt="$(mnt_from_dev "${dev}")"
+else
+	dev="$(dev_from_mount "${arg}")"
+	mnt="${arg}"
+fi
+if [ ! -e "${dev}" ]; then
+	echo "${arg}: Not an ext[234] filesystem."
+	print_help
+	exitcode 16
+fi
+
+# Make sure this is an LVM device we can snapshot
+lvm_vars="$(lvs --nameprefixes -o name,vgname,lv_role --noheadings "${dev}" 2> /dev/null)"
+eval "${lvm_vars}"
+if [ -z "${LVM2_VG_NAME}" ] || [ -z "${LVM2_LV_NAME}" ] ||
+   echo "${LVM2_LV_ROLE}" | grep -q "snapshot"; then
+	echo "${arg}: Not connnected to a LVM logical volume."
+	print_help
+	exitcode 16
+fi
+start_time="$(date +'%Y%m%d%H%M%S')"
+snap="${LVM2_LV_NAME}.e2scrub"
+snap_dev="/dev/${LVM2_VG_NAME}/${snap}"
+
+teardown() {
+	# Remove and wait for removal to succeed.
+	${DBG} lvremove -f "${LVM2_VG_NAME}/${snap}" 3>&-
+	while [ -e "${snap_dev}" ] && [ "$?" -eq "5" ]; do
+		sleep 0.5
+		${DBG} lvremove -f "${LVM2_VG_NAME}/${snap}" 3>&-
+	done
+}
+
+check() {
+	# First we recover the journal, then we see if e2fsck tries any
+	# non-optimization repairs.  If either of these two returns a
+	# non-zero status (errors fixed or remaining) then this fs is bad.
+	E2FSCK_FIXES_ONLY=1
+	export E2FSCK_FIXES_ONLY
+	${DBG} "@root_sbindir@/e2fsck" -E journal_only -p ${e2fsck_opts} "${snap_dev}" || return $?
+	${DBG} "@root_sbindir@/e2fsck" -f -y ${e2fsck_opts} "${snap_dev}"
+}
+
+mark_clean() {
+	${DBG} "@root_sbindir@/tune2fs" -C 0 -T "${start_time}" "${dev}"
+}
+
+mark_corrupt() {
+	${DBG} "@root_sbindir@/tune2fs" -E force_fsck "${dev}"
+}
+
+setup() {
+	# Try to remove snapshot for 30s, bail out if we can't remove it.
+	lveremove_deadline="$(( $(date "+%s") + 30))"
+	${DBG} lvremove -f "${LVM2_VG_NAME}/${snap}" 3>&- 2>/dev/null
+	while [ -e "${snap_dev}" ] && [ "$?" -eq "5" ] &&
+	      [ "$(date "+%s")" -lt "${lvremove_deadline}" ]; do
+		sleep 0.5
+		${DBG} lvremove -f "${LVM2_VG_NAME}/${snap}" 3>&-
+	done
+	if [ -e "${snap_dev}" ]; then
+		echo "${arg}: e2scrub snapshot is in use, cannot check!"
+		return 1
+	fi
+	# Create the snapshot, wait for device to appear.
+	${DBG} lvcreate -s -L "${snap_size_mb}m" -n "${snap}" "${LVM2_VG_NAME}/${LVM2_LV_NAME}" 3>&-
+	if [ $? -ne 0 ]; then
+		echo "${arg}: e2scrub snapshot FAILED, will not check!"
+		return 1
+	fi
+	${DBG} udevadm settle 2> /dev/null
+	return 0
+}
+
+if [ "${reap}" -gt 0 ]; then
+	if [ -e "${snap_dev}" ]; then
+		teardown 2> /dev/null
+	fi
+	exit 0
+fi
+if ! setup; then
+	exitcode 8
+fi
+trap "teardown; exit 1" EXIT INT QUIT TERM
+
+# Check and react
+check
+case "$?" in
+"0")
+	# Clean check!
+	echo "${arg}: Scrub succeeded."
+	mark_clean
+	teardown
+	trap '' EXIT
+
+	# Trim the free space, which requires the snapshot be deleted.
+	if [ "${fstrim}" -eq 1 ] && [ -d "${mnt}" ] && type fstrim > /dev/null 2>&1; then
+		echo "${arg}: Trimming free space."
+		fstrim -v "${mnt}"
+	fi
+
+	ret=0
+	;;
+"8")
+	# Operational error, what now?
+	echo "${arg}: e2fsck operational error."
+	teardown
+	trap '' EXIT
+	ret=8
+	;;
+*)
+	# fsck failed.  Check if the snapshot is invalid; if so, make a
+	# note of that at the end of the log.  This isn't necessarily a
+	# failure because the mounted fs could have overflowed the
+	# snapshot with regular disk writes /or/ our repair process
+	# could have done it by repairing too much.
+	#
+	# If it's really corrupt we ought to fsck at next boot.
+	is_invalid="$(lvs -o lv_snapshot_invalid --noheadings "${snap_dev}" | awk '{print $1}')"
+	if [ -n "${is_invalid}" ]; then
+		echo "${arg}: Scrub FAILED due to invalid snapshot."
+		ret=8
+	else
+		echo "${arg}: Scrub FAILED due to corruption!  Unmount and run e2fsck -y."
+		mark_corrupt
+		ret=6
+	fi
+	teardown
+	trap '' EXIT
+	;;
+esac
+
+exitcode "${ret}"
diff --git a/scrub/e2scrub.rules.in b/scrub/e2scrub.rules.in
new file mode 100644
index 0000000..5e1b35b
--- /dev/null
+++ b/scrub/e2scrub.rules.in
@@ -0,0 +1,2 @@
+# Try to hide our fsck snapshots from udev's /dev/disk linking...
+ACTION=="add|change", ENV{DM_LV_NAME}=="*.e2scrub", OPTIONS="link_priority=-100"
diff --git a/scrub/e2scrub@.service.in b/scrub/e2scrub@.service.in
new file mode 100644
index 0000000..496f894
--- /dev/null
+++ b/scrub/e2scrub@.service.in
@@ -0,0 +1,20 @@
+[Unit]
+Description=Online ext4 Metadata Check for %I
+OnFailure=e2scrub_fail@%i.service
+Documentation=man:e2scrub(8)
+
+[Service]
+Type=oneshot
+WorkingDirectory=/
+PrivateNetwork=true
+ProtectSystem=true
+ProtectHome=read-only
+PrivateTmp=yes
+AmbientCapabilities=CAP_SYS_ADMIN CAP_SYS_RAWIO
+NoNewPrivileges=yes
+User=root
+IOSchedulingClass=idle
+CPUSchedulingPolicy=idle
+Environment=SERVICE_MODE=1
+ExecStart=@root_sbindir@/e2scrub -t %I
+SyslogIdentifier=%N
diff --git a/scrub/e2scrub_all.8.in b/scrub/e2scrub_all.8.in
new file mode 100644
index 0000000..ba3b873
--- /dev/null
+++ b/scrub/e2scrub_all.8.in
@@ -0,0 +1,36 @@
+.TH E2SCRUB 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+e2scrub_all - check all mounted ext[234] filesystems for errors.
+.SH SYNOPSYS
+.B
+e2scrub_all [OPTION]
+.SH DESCRIPTION
+Searches the system for all LVM logical volumes containing an ext2, ext3, or
+ext4 file system, and checks them for problems.
+The checking is performed by invoking the
+.B e2scrub
+tool, which will look for corruptions.
+Corrupt filesystems will be tagged as having errors so that fsck will be
+invoked before the next mount.
+If no errors are encountered,
+.B fstrim
+will be called on the filesystem if it is mounted.
+See the
+.B e2scrub
+manual page for more information about how the checking is performed.
+.SH OPTIONS
+.TP
+\fB-A\fR
+Scrub all ext[234] filesystems even if they are not mounted.
+.TP
+\fB-r\fR
+Remove e2scrub snapshots but do not check anything.
+.TP
+\fB-V\fR
+Print version information and exit.
+.SH SEE ALSO
+.BR e2scrub "(8)"
+.SH AUTHOR
+Darrick J. Wong <darrick.wong@oracle.com>
+.SH COPYRIGHT
+Copyright ©2018 Oracle.  License is GPLv2+. <http://www.gnu.org/licenses/gpl-2.0.html>
diff --git a/scrub/e2scrub_all.cron.in b/scrub/e2scrub_all.cron.in
new file mode 100644
index 0000000..7d42c3f
--- /dev/null
+++ b/scrub/e2scrub_all.cron.in
@@ -0,0 +1,2 @@
+30 3 * * 0 root test -e /run/systemd/system || @pkglibdir@/e2scrub_all_cron
+10 3 * * * root test -e /run/systemd/system || @root_sbindir@/e2scrub_all -A -r
diff --git a/scrub/e2scrub_all.in b/scrub/e2scrub_all.in
new file mode 100644
index 0000000..9581dc2
--- /dev/null
+++ b/scrub/e2scrub_all.in
@@ -0,0 +1,132 @@
+#!/bin/bash
+
+#  Copyright (C) 2018 Oracle.  All Rights Reserved.
+#
+#  Author: Darrick J. Wong <darrick.wong@oracle.com>
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it would be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write the Free Software Foundation,
+#  Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+
+scrub_all=0
+conffile="@root_sysconfdir@/e2scrub.conf"
+
+test -f "${conffile}" && . "${conffile}"
+
+scrub_args=""
+
+print_help() {
+	echo "Usage: $0 [OPTIONS]"
+	echo " -A: Scrub all ext[234] filesystems even if not mounted."
+	echo " -r: Remove e2scrub snapshots."
+	echo " -V: Print version information and exit."
+}
+
+print_version() {
+	echo "e2scrub_all @E2FSPROGS_VERSION@ (@E2FSPROGS_DATE@)"
+}
+
+exitcode() {
+	ret="$1"
+
+	# If we're being run as a service, the return code must fit the LSB
+	# init script action error guidelines, which is to say that we
+	# compress all errors to 1 ("generic or unspecified error", LSB 5.0
+	# section 22.2) and hope the admin will scan the log for what
+	# actually happened.
+
+	# We have to sleep 2 seconds here because journald uses the pid to
+	# connect our log messages to the systemd service.  This is critical
+	# for capturing all the log messages if the scrub fails, because the
+	# fail service uses the service name to gather log messages for the
+	# error report.
+	if [ -n "${SERVICE_MODE}" ]; then
+		test "${ret}" -ne 0 && ret=1
+		sleep 2
+	fi
+
+	exit "${ret}"
+}
+
+while getopts "ArV" opt; do
+	case "${opt}" in
+	"A") scrub_all=1;;
+	"r") scrub_args="${scrub_args} -r";;
+	"V") print_version; exitcode 0;;
+	*) print_help; exitcode 2;;
+	esac
+done
+shift "$((OPTIND - 1))"
+
+# Find scrub targets, make sure we only do this once.
+ls_scrub_targets() {
+	lsblk -o NAME,FSTYPE,MOUNTPOINT -p -P -n | while read vars; do
+		eval "${vars}"
+
+		# Skip non-ext[234]
+		case "${FSTYPE}" in
+		ext[234])	;;
+		*)		continue;;
+		esac
+
+		# Skip unmounted filesystems unless -A
+		if [ "${scrub_all}" -eq 0 ] && [ -z "${MOUNTPOINT}" ]; then
+			continue;
+		fi
+
+		# Skip non-lvm devices and lvm snapshots
+		lvm_vars="$(lvs --nameprefixes -o vg_name,lv_name,lv_role --noheadings "${NAME}" 2> /dev/null)"
+		test $? -ne 0 && continue
+		eval "${lvm_vars}"
+		echo "${LVM2_LV_ROLE}" | grep -q "snapshot" && continue
+
+		if [ -n "${MOUNTPOINT}" ]; then
+			echo "${MOUNTPOINT}"
+		else
+			echo "${NAME}"
+		fi
+	done | sort | uniq
+}
+
+# systemd doesn't know to do path escaping on the instance variable we pass
+# to the e2scrub service, which breaks things if there is a dash in the path
+# name.  Therefore, do the path escaping ourselves if needed.
+escape_path_for_systemd() {
+	local path="$1"
+
+	if echo "${path}" | grep -q -- "-"; then
+		echo "-$(systemd-escape --path "${path}")"
+	else
+		echo "${path}"
+	fi
+}
+
+# Scrub any mounted fs on lvm by creating a snapshot and fscking that.
+stdin="$(realpath /dev/stdin)"
+ls_scrub_targets | while read tgt; do
+	# If we're not reaping and systemd is present, try invoking the
+	# systemd service.
+	if [ -z "${scrub_args}" ] && type systemctl > /dev/null 2>&1; then
+		tgt_esc="$(escape_path_for_systemd "${tgt}")"
+		${DBG} systemctl start "e2scrub@${tgt_esc}" 2> /dev/null < "${stdin}"
+		res=$?
+		if [ "${res}" -eq 0 ] || [ "${res}" -eq 1 ]; then
+			continue;
+		fi
+	fi
+
+	# Otherwise use direct invocation
+	${DBG} "@root_sbindir@/e2scrub" ${scrub_args} "${tgt}" < "${stdin}"
+done
+
+exitcode 0
diff --git a/scrub/e2scrub_all.service.in b/scrub/e2scrub_all.service.in
new file mode 100644
index 0000000..bc05184
--- /dev/null
+++ b/scrub/e2scrub_all.service.in
@@ -0,0 +1,10 @@
+[Unit]
+Description=Online ext4 Metadata Check for All Filesystems
+ConditionACPower=true
+Documentation=man:e2scrub_all(8)
+
+[Service]
+Type=oneshot
+Environment=SERVICE_MODE=1
+ExecStart=@root_sbindir@/e2scrub_all
+SyslogIdentifier=e2scrub_all
diff --git a/scrub/e2scrub_all.timer.in b/scrub/e2scrub_all.timer.in
new file mode 100644
index 0000000..3d558bb
--- /dev/null
+++ b/scrub/e2scrub_all.timer.in
@@ -0,0 +1,11 @@
+[Unit]
+Description=Periodic ext4 Online Metadata Check for All Filesystems
+
+[Timer]
+# Run on Sunday at 3:10am, to avoid running afoul of DST changes
+OnCalendar=Sun *-*-* 03:10:00
+RandomizedDelaySec=60
+Persistent=true
+
+[Install]
+WantedBy=timers.target
diff --git a/scrub/e2scrub_all_cron.in b/scrub/e2scrub_all_cron.in
new file mode 100644
index 0000000..f9cff87
--- /dev/null
+++ b/scrub/e2scrub_all_cron.in
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+#  Copyright (C) 2018 Oracle.  All Rights Reserved.
+#
+#  Author: Darrick J. Wong <darrick.wong@oracle.com>
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it would be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write the Free Software Foundation,
+#  Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+
+# Run e2scrub_all from a cronjob if we don't have systemd and we're not
+# running on AC power.
+
+on_ac_power() {
+	local any_known=no
+
+	# try sysfs power class first
+	if [ -d /sys/class/power_supply ]; then
+		for psu in /sys/class/power_supply/*; do
+			if [ -r "$psu/type" ]; then
+				type=$(cat "$psu/type")
+
+				# ignore batteries
+				[ "$type" = "Battery" ] && continue
+
+				online=$(cat "$psu/online")
+
+				[ "$online" = 1 ] && return 0
+				[ "$online" = 0 ] && any_known=yes
+			fi
+		done
+
+		[ "$any_known" = "yes" ] && return 1
+	fi
+
+	# else fall back to AC adapters in /proc
+	if [ -d /proc/acpi/ac_adapter ]; then
+		for ac in /proc/acpi/ac_adapter/*; do
+			if [ -r "$ac/state" ]; then
+				grep -q on-line "$ac/state" && return 0
+				grep -q off-line "$ac/state" && any_known=yes
+			elif [ -r "$ac/status" ]; then
+				grep -q on-line "$ac/status" && return 0
+				grep -q off-line "$ac/status" && any_known=yes
+			fi
+		done
+
+		[ "$any_known" = "yes" ] && return 1
+	fi
+
+	# Can't tell, just assume we're on AC.
+	return 0
+}
+
+test -e /run/systemd/system && exit 0
+on_ac_power || exit 0
+
+exec @root_sbindir@/e2scrub_all
diff --git a/scrub/e2scrub_fail.in b/scrub/e2scrub_fail.in
new file mode 100644
index 0000000..f27197a
--- /dev/null
+++ b/scrub/e2scrub_fail.in
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Email logs of failed e2scrub unit runs when the systemd service fails.
+
+recipient="$1"
+test -z "${recipient}" && exit 0
+device="$2"
+test -z "${device}" && exit 0
+hostname="$(hostname -f 2>/dev/null)"
+test -z "${hostname}" && hostname="${HOSTNAME}"
+if ! type sendmail > /dev/null 2>&1; then
+	echo "$0: sendmail program not found."
+	exit 1
+fi
+
+(cat << ENDL
+To: $1
+From: <e2scrub@${hostname}>
+Subject: e2scrub failure on ${device}
+
+So sorry, the automatic e2scrub of ${device} on ${hostname} failed.
+
+A log of what happened follows:
+ENDL
+systemctl status --full --lines 4294967295 "e2scrub@${device}") | sendmail -t -i
diff --git a/scrub/e2scrub_fail@.service.in b/scrub/e2scrub_fail@.service.in
new file mode 100644
index 0000000..df87949
--- /dev/null
+++ b/scrub/e2scrub_fail@.service.in
@@ -0,0 +1,10 @@
+[Unit]
+Description=Online ext4 Metadata Check Failure Reporting for %I
+
+[Service]
+Type=oneshot
+Environment=EMAIL_ADDR=root
+ExecStart=@pkglibdir@/e2scrub_fail "${EMAIL_ADDR}" %I
+User=mail
+Group=mail
+SupplementaryGroups=systemd-journal
diff --git a/scrub/e2scrub_reap.service.in b/scrub/e2scrub_reap.service.in
new file mode 100644
index 0000000..8a32077
--- /dev/null
+++ b/scrub/e2scrub_reap.service.in
@@ -0,0 +1,21 @@
+[Unit]
+Description=Remove Stale Online ext4 Metadata Check Snapshots
+
+[Service]
+Type=oneshot
+WorkingDirectory=/
+PrivateNetwork=true
+ProtectSystem=true
+ProtectHome=read-only
+PrivateTmp=yes
+AmbientCapabilities=CAP_SYS_ADMIN CAP_SYS_RAWIO
+NoNewPrivileges=yes
+User=root
+IOSchedulingClass=idle
+CPUSchedulingPolicy=idle
+ExecStart=@root_sbindir@/e2scrub_all -A -r
+SyslogIdentifier=%N
+RemainAfterExit=no
+
+[Install]
+WantedBy=default.target
diff --git a/tests/progs/test_icount.c b/tests/progs/test_icount.c
index 0a0f306..8b01ea4 100644
--- a/tests/progs/test_icount.c
+++ b/tests/progs/test_icount.c
@@ -61,7 +61,8 @@
 	return 0;
 }
 
-void do_create_icount(int argc, char **argv)
+void do_create_icount(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		      void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t	retval;
 	char		*progname;
@@ -91,7 +92,8 @@
 	}
 }
 
-void do_free_icount(int argc, char **argv)
+void do_free_icount(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	if (argc != 1) {
 		printf("Usage: free_icount\n");
@@ -104,7 +106,8 @@
 	test_icount = 0;
 }
 
-void do_fetch(int argc, char **argv)
+void do_fetch(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	const char	*usage = "usage: %s inode\n";
 	errcode_t	retval;
@@ -127,7 +130,8 @@
 	printf("Count is %u\n", count);
 }
 
-void do_increment(int argc, char **argv)
+void do_increment(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	const char	*usage = "usage: %s inode\n";
 	errcode_t	retval;
@@ -151,7 +155,8 @@
 	printf("Count is now %u\n", count);
 }
 
-void do_decrement(int argc, char **argv)
+void do_decrement(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	const char	*usage = "usage: %s inode\n";
 	errcode_t	retval;
@@ -175,7 +180,8 @@
 	printf("Count is now %u\n", count);
 }
 
-void do_store(int argc, char **argv)
+void do_store(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	const char	*usage = "usage: %s inode count\n";
 	errcode_t	retval;
@@ -204,7 +210,8 @@
 	}
 }
 
-void do_dump(int argc, char **argv)
+void do_dump(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t	retval;
 	ext2_ino_t	i;
@@ -228,7 +235,8 @@
 	}
 }
 
-void do_validate(int argc, char **argv)
+void do_validate(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	errcode_t	retval;
 
@@ -246,7 +254,8 @@
 	printf("Icount structure successfully validated\n");
 }
 
-void do_get_size(int argc, char **argv)
+void do_get_size(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
+		    void *infop EXT2FS_ATTR((unused)))
 {
 	ext2_ino_t	size;
 
diff --git a/tests/progs/test_icount.h b/tests/progs/test_icount.h
index 59ea1a4..29d56ab 100644
--- a/tests/progs/test_icount.h
+++ b/tests/progs/test_icount.h
@@ -1,10 +1,10 @@
-void do_create_icount(int argc, char **argv);
-void do_free_icount(int argc, char **argv);
-void do_fetch(int argc, char **argv);
-void do_increment(int argc, char **argv);
-void do_decrement(int argc, char **argv);
-void do_store(int argc, char **argv);
-void do_get_size(int argc, char **argv);
-void do_dump(int argc, char **argv);
-void do_validate(int argc, char **argv);
+void do_create_icount(int argc, char **argv, int sci_idx, void *infop);
+void do_free_icount(int argc, char **argv, int sci_idx, void *infop);
+void do_fetch(int argc, char **argv, int sci_idx, void *infop);
+void do_increment(int argc, char **argv, int sci_idx, void *infop);
+void do_decrement(int argc, char **argv, int sci_idx, void *infop);
+void do_store(int argc, char **argv, int sci_idx, void *infop);
+void do_get_size(int argc, char **argv, int sci_idx, void *infop);
+void do_dump(int argc, char **argv, int sci_idx, void *infop);
+void do_validate(int argc, char **argv, int sci_idx, void *infop);
 
diff --git a/util/subst.conf.in b/util/subst.conf.in
index fbc044d..0da4554 100644
--- a/util/subst.conf.in
+++ b/util/subst.conf.in
@@ -2,6 +2,7 @@
 SED			@SED@
 E2FSPROGS_MONTH		@E2FSPROGS_MONTH@
 E2FSPROGS_YEAR		@E2FSPROGS_YEAR@
+E2FSPROGS_DATE		@E2FSPROGS_DATE@
 E2FSPROGS_VERSION	@E2FSPROGS_VERSION@
 SIZEOF_LONG_LONG	@SIZEOF_LONG_LONG@
 SIZEOF_LONG		@SIZEOF_LONG@
@@ -18,3 +19,8 @@
 JDEV			
 # Enable the documentation for the tdb profile in e2fsck.conf's man page
 TDB_MAN_COMMENT		@TDB_MAN_COMMENT@
+root_sbindir		@root_sbindir@
+root_bindir		@root_bindir@
+libdir			@libdir@
+$exec_prefix		@exec_prefix@
+pkglibdir		@libdir@/e2fsprogs