Index: e2fsprogs.git/e2fsprogs.spec.in
===================================================================
--- e2fsprogs.git.orig/e2fsprogs.spec.in
+++ e2fsprogs.git/e2fsprogs.spec.in
@@ -132,6 +132,7 @@ exit 0
 %{_root_sbindir}/mkfs.ext4dev
 %{_root_sbindir}/resize2fs
 %{_root_sbindir}/tune2fs
+%{_root_sbindir}/mmpstatus
 %{_sbindir}/filefrag
 %{_sbindir}/mklost+found
 %{_sbindir}/e2freefrag
@@ -180,6 +181,7 @@ exit 0
 %{_mandir}/man8/tune2fs.8*
 %{_mandir}/man8/filefrag.8*
 %{_mandir}/man8/e2freefrag.8*
+%{_mandir}/man8/mmpstatus.8*

 %files devel
 %defattr(-,root,root)
Index: e2fsprogs.git/misc/mmpstatus.8.in
===================================================================
--- /dev/null
+++ e2fsprogs.git/misc/mmpstatus.8.in
@@ -0,0 +1,58 @@
+.\" -*- nroff -*-
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH MMPSTATUS 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs
version @E2FSPROGS_VERSION@"
+.SH NAME
+mmpstatus \- Check MMP status of an ext4 file system
+.SH SYNOPSIS
+.B mmpstatus
+[
+.B \-c | \--check
+]
+[
+.B \-n | \--nodename
+]
+.I [filesys]
+.SH DESCRIPTION
+.B mmpstatus
+is used to check MMP status of an ext4 file system.
+.I filesys
+can be a device name (e.g.
+.IR /dev/hdc1 ", " /dev/sdb2 ),
+or an ext4 label or UUID specifier (e.g.
+UUID=8868abf6-88c5-4a83-98b8-bfc24057f7bd or LABEL=root).
+The
+.B mmpstatus
+program checks whether it is safe to mount the file system without taking
+the risk of mounting it more than once.
+.PP
+MMP (multiple-mount protection) is a feature which protects
+the file system from being mounted simultaneously to more than one node.
+It is NOT safe to mount a file system when one of the following condition
+is true:
+.br
+\    1. The MMP shows that fsck is running on the file system.
+.br
+\    2. The MMP are being updated by some node.
+.br
+The
+.B mmpstatus
+program might wait for some time to see whether MMP is updated by any node
+during this period.
+.PP
+Normaly, the exit code returned by
+.B mmpstatus
+is 0 when it is safe to mount the filesystem, 1 when it is NOT safe to mount
+the filesystem, and -1 on failure. When
+.B \-i
+flag is specified, the exit code
+is 0 on success, -1 on failure.
+.SH OPTIONS
+.TP
+.B \-i,
+Display the MMP field values rather than check them.
+.SH SEE ALSO
+.BR debugfs (8),
+.BR dumpe2fs (8),
+.BR tune2fs (8),
+.BR fsck (8)
Index: e2fsprogs.git/misc/Makefile.in
===================================================================
--- e2fsprogs.git.orig/misc/Makefile.in
+++ e2fsprogs.git/misc/Makefile.in
@@ -27,12 +27,12 @@ INSTALL = @INSTALL@
 @BLKID_CMT@FINDFS_MAN= findfs.8

 SPROGS=        mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \
-            $(E2IMAGE_PROG) @FSCK_PROG@ e2undo
+            $(E2IMAGE_PROG) @FSCK_PROG@ @MMPSTATUS_PROG@ e2undo
 USPROGS=    mklost+found filefrag e2freefrag $(UUIDD_PROG) $(E4DEFRAG_PROG)
 SMANPAGES=    tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
             e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \
             logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \
-            $(UUIDD_MAN) $(E4DEFRAG_MAN) @FSCK_MAN@
+            $(UUIDD_MAN) $(E4DEFRAG_MAN) @FSCK_MAN@ @MMPSTATUS_MAN@
 FMANPAGES=    mke2fs.conf.5

 UPROGS=        chattr lsattr @UUID_CMT@ uuidgen
@@ -51,6 +51,7 @@ DUMPE2FS_OBJS=    dumpe2fs.o
 BADBLOCKS_OBJS=    badblocks.o
 E2IMAGE_OBJS=    e2image.o
 FSCK_OBJS=    fsck.o base_device.o ismounted.o
+MMPSTATUS_OBJS=    mmpstatus.o
 BLKID_OBJS=    blkid.o
 FILEFRAG_OBJS=    filefrag.o
 E2UNDO_OBJS=  e2undo.o
@@ -70,6 +71,7 @@ PROFILED_BADBLOCKS_OBJS=    profiled/badblo
 PROFILED_E2IMAGE_OBJS=    profiled/e2image.o
 PROFILED_FSCK_OBJS=    profiled/fsck.o profiled/base_device.o \
             profiled/ismounted.o
+PROFILED_MMPSTATUS_OBJS=profiled/mmpstatus.o
 PROFILED_BLKID_OBJS=    profiled/blkid.o
 PROFILED_FILEFRAG_OBJS=    profiled/filefrag.o
 PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o
@@ -82,7 +84,8 @@ SRCS=    $(srcdir)/tune2fs.c $(srcdir)/mklo
         $(srcdir)/uuidgen.c $(srcdir)/blkid.c $(srcdir)/logsave.c \
         $(srcdir)/filefrag.c $(srcdir)/base_device.c \
         $(srcdir)/ismounted.c $(srcdir)/../e2fsck/profile.c \
-        $(srcdir)/e2undo.c $(srcdir)/e2freefrag.c
+        $(srcdir)/e2undo.c $(srcdir)/e2freefrag.c \
+        $(srcdir)/mmpstatus.c

 LIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
 DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR)
@@ -300,6 +303,16 @@ fsck.profiled: $(FSCK_OBJS) $(PROFILED_D
     $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o fsck.profiled $(PROFILED_FSCK_OBJS) \
         $(PROFILED_LIBBLKID) $(LIBINTL)

+mmpstatus: $(MMPSTATUS_OBJS) $(DEPLIBBLKID)
+    $(E) "    LD $@"
+    $(Q) $(CC) $(ALL_LDFLAGS) -o mmpstatus $(MMPSTATUS_OBJS) $(LIBBLKID) \
+        $(LIBINTL) $(LIBS)
+
+mmpstatus.profiled: $(MMPSTATUS_OBJS) $(PROFILED_DEPLIBBLKID)
+    $(E) "    LD $@"
+    $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o mmpstatus.profiled \
+        $(PROFILED_MMPSTATUS_OBJS) $(PROFILED_LIBBLKID) $(LIBINTL)
+
 badblocks: $(BADBLOCKS_OBJS) $(DEPLIBS)
     $(E) "    LD $@"
     $(Q) $(CC) $(ALL_LDFLAGS) -o badblocks $(BADBLOCKS_OBJS) $(LIBS) $(LIBINTL)
@@ -384,6 +397,10 @@ badblocks.8: $(DEP_SUBSTITUTE) $(srcdir)
     $(E) "    SUBST $@"
     $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/badblocks.8.in badblocks.8

+mmpstatus.8: $(DEP_SUBSTITUTE) $(srcdir)/mmpstatus.8.in
+    $(E) "    SUBST $@"
+    $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/mmpstatus.8.in mmpstatus.8
+
 fsck.8: $(DEP_SUBSTITUTE) $(srcdir)/fsck.8.in
     $(E) "    SUBST $@"
     $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/fsck.8.in fsck.8
@@ -575,7 +592,8 @@ clean:
         e2undo.profiled mke2fs.profiled dumpe2fs.profiled \
         logsave.profiled filefrag.profiled uuidgen.profiled \
         uuidd.profiled e2image.profiled mke2fs.conf \
-        profiled/*.o \#* *.s *.o *.a *~ core gmon.out
+        mmpstatus.profiled profiled/*.o \#* *.s *.o *.a *~ core \
+        gmon.out

 mostlyclean: clean
 distclean: clean
@@ -644,6 +662,9 @@ badblocks.o: $(srcdir)/badblocks.c $(top
 fsck.o: $(srcdir)/fsck.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/version.h \
  $(srcdir)/nls-enable.h $(srcdir)/fsck.h
+mmpstatus.o: $(srcdir)/mmpstatus.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/version.h \
+ $(srcdir)/nls-enable.h $(top_srcdir)/lib/ext2fs/ext2fs.h
 util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
  $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
Index: e2fsprogs.git/misc/mmpstatus.c
===================================================================
--- /dev/null
+++ e2fsprogs.git/misc/mmpstatus.c
@@ -0,0 +1,103 @@
+/*
+ * mmpstatus.c --- check MMP status of an ext4 file system
+ *
+ * Copyright (C) 2013 DataDirect Networks, Inc.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <time.h>
+#include <getopt.h>
+#include <sys/time.h>
+#include "ext2fs/ext2fs.h"
+#include "blkid/blkid.h"
+#include "../version.h"
+#include "nls-enable.h"
+
+/*
+ * return 1 when MMP is being updated,
+ * 0 if not, and -1 on falure
+*/
+int main (int argc, char ** argv)
+{
+    char        *device;
+    int        open_flags = EXT2_FLAG_64BITS;
+    ext2_filsys    filesystem = NULL;
+    int        retval;
+    const char    *usage =
+        "usage: %s [-i] device";
+    int c;
+    int info = 0;
+    const char *debug_prog_name = "mmpstatus";
+
+    add_error_table(&et_ext2_error_table);
+    fprintf(stderr, "%s %s (%s)\n", debug_prog_name,
+        E2FSPROGS_VERSION, E2FSPROGS_DATE);
+    while ((c = getopt(argc, argv, "i")) != EOF) {
+        switch (c) {
+        case 'i':
+            info++;
+            break;
+        default:
+            com_err(argv[0], 0, usage, debug_prog_name);
+            return -1;
+        }
+    }
+
+    if (optind != argc - 1) {
+        com_err(argv[0], 0, usage, debug_prog_name);
+        return -1;
+    }
+
+    device = blkid_get_devname(NULL, argv[optind], NULL);
+    if (device == NULL) {
+        com_err(argv[0], 0, _("Unable to resolve '%s'"), device);
+        return -1;
+    }
+
+    retval = ext2fs_open(device, open_flags, 0, 0,
+                 unix_io_manager, &filesystem);
+    if (retval) {
+        com_err(argv[0], retval, _("while trying to open %s"),
+            device);
+        retval = -1;
+        goto out_free_device;
+    }
+
+    if (info) {
+        retval = ext2fs_mmp_dump(filesystem);
+        if (retval) {
+            com_err(argv[0], retval, _("while trying to dump %s"),
+                device);
+        }
+    } else {
+        retval = ext2fs_mmp_start(filesystem);
+        switch (retval) {
+        case EXT2_ET_MMP_FAILED:
+            com_err(argv[0], retval,
+                _("while checking MMP status of %s"), device);
+            retval = 1;
+            break;
+        case 0:
+            com_err(argv[0], 0, "device '%s' is not used now\n",
+                device);
+            break;
+        default:
+            com_err(argv[0], retval,
+                _("while checking MMP status of %s"), device);
+            retval = -1;
+            break;
+        }
+    }
+    ext2fs_close(filesystem);
+out_free_device:
+    free(device);
+    return retval;
+}
Index: e2fsprogs.git/configure.in
===================================================================
--- e2fsprogs.git.orig/configure.in
+++ e2fsprogs.git/configure.in
@@ -718,6 +718,32 @@ esac]
 AC_SUBST(FSCK_PROG)
 AC_SUBST(FSCK_MAN)
 dnl
+dnl See whether to install the `mmpstatus' program
+dnl
+AC_ARG_ENABLE([mmpstatus],
+[  --enable-mmpstatus           build mmpstatus program],
+[if test "$enableval" = "no"
+then
+    MMPSTATUS_PROG='' MMPSTATUS_MAN=''
+    AC_MSG_RESULT([Not building mmpstatus])
+else
+    MMPSTATUS_PROG=mmpstatus MMPSTATUS_MAN=mmpstatus.8
+    AC_MSG_RESULT([Building mmpstatus])
+fi]
+,
+[case "$host_os" in
+  gnu*)
+    MMPSTATUS_PROG='' MMPSTATUS_MAN=''
+    AC_MSG_RESULT([Not building mmpstatus by default])
+    ;;
+  *)
+    MMPSTATUS_PROG=mmpstatus MMPSTATUS_MAN=mmpstatus.8
+    AC_MSG_RESULT([Building mmpstatus by default])
+esac]
+)
+AC_SUBST(MMPSTATUS_PROG)
+AC_SUBST(MMPSTATUS_MAN)
+dnl
 dnl See whether to install the `e2initrd-helper' program
 dnl
 AC_ARG_ENABLE([e2initrd-helper],
Index: e2fsprogs.git/debugfs/debugfs.c
===================================================================
--- e2fsprogs.git.orig/debugfs/debugfs.c
+++ e2fsprogs.git/debugfs/debugfs.c
@@ -2316,50 +2316,12 @@ try_again:
 void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[])
 {
 #if CONFIG_MMP
-    struct ext2_super_block *sb;
-    struct mmp_struct *mmp_s;
-    time_t t;
-    errcode_t retval = 0;
-
+    int retval;
     if (check_fs_open(argv[0]))
         return;
-
-    sb  = current_fs->super;
-    if (sb->s_mmp_block <= sb->s_first_data_block ||
-        sb->s_mmp_block >= ext2fs_blocks_count(sb)) {
-        com_err(argv[0], EXT2_ET_MMP_BAD_BLOCK, "while dumping it.\n");
-        return;
-    }
-
-    if (current_fs->mmp_buf == NULL) {
-        retval = ext2fs_get_mem(current_fs->blocksize,
-                    &current_fs->mmp_buf);
-        if (retval) {
-            com_err(argv[0], retval, "allocating MMP buffer.\n");
-            return;
-        }
-    }
-
-    mmp_s = current_fs->mmp_buf;
-
-    retval = ext2fs_mmp_read(current_fs, current_fs->super->s_mmp_block,
-                 current_fs->mmp_buf);
-    if (retval) {
-        com_err(argv[0], retval, "reading MMP block.\n");
-        return;
-    }
-
-    t = mmp_s->mmp_time;
-    fprintf(stdout, "block_number: %llu\n", current_fs->super->s_mmp_block);
-    fprintf(stdout, "update_interval: %d\n",
-        current_fs->super->s_mmp_update_interval);
-    fprintf(stdout, "check_interval: %d\n", mmp_s->mmp_check_interval);
-    fprintf(stdout, "sequence: %08x\n", mmp_s->mmp_seq);
-    fprintf(stdout, "time: %lld -- %s", mmp_s->mmp_time, ctime(&t));
-    fprintf(stdout, "node_name: %s\n", mmp_s->mmp_nodename);
-    fprintf(stdout, "device_name: %s\n", mmp_s->mmp_bdevname);
-    fprintf(stdout, "magic: 0x%x\n", mmp_s->mmp_magic);
-    fprintf(stdout, "checksum: 0x%08x\n", mmp_s->mmp_checksum);
+    retval = ext2fs_mmp_dump(current_fs);
+    if (retval)
+        com_err(argv[0], retval, "while dumping it.\n");
 #else
     fprintf(stdout, "MMP is unsupported, please recompile with "
                     "--enable-mmp\n");
Index: e2fsprogs.git/lib/ext2fs/ext2fs.h
===================================================================
--- e2fsprogs.git.orig/lib/ext2fs/ext2fs.h
+++ e2fsprogs.git/lib/ext2fs/ext2fs.h
@@ -1468,6 +1468,7 @@ errcode_t ext2fs_symlink(ext2_filsys fs,
 /* mmp.c */
 errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf);
 errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf);
+errcode_t ext2fs_mmp_dump(ext2_filsys fs);
 errcode_t ext2fs_mmp_clear(ext2_filsys fs);
 errcode_t ext2fs_mmp_init(ext2_filsys fs);
 errcode_t ext2fs_mmp_start(ext2_filsys fs);
Index: e2fsprogs.git/lib/ext2fs/mmp.c
===================================================================
--- e2fsprogs.git.orig/lib/ext2fs/mmp.c
+++ e2fsprogs.git/lib/ext2fs/mmp.c
@@ -19,7 +19,7 @@
 #include <unistd.h>
 #endif
 #include <sys/time.h>
-
+#include <time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -259,6 +259,52 @@ out:
 #endif
 }

+errcode_t ext2fs_mmp_dump(ext2_filsys fs)
+{
+#ifdef CONFIG_MMP
+    struct ext2_super_block *sb;
+    struct mmp_struct *mmp_s;
+    time_t t;
+    errcode_t retval = 0;
+
+    sb  = fs->super;
+    if (sb->s_mmp_block <= sb->s_first_data_block ||
+        sb->s_mmp_block >= ext2fs_blocks_count(sb)) {
+        return EXT2_ET_MMP_BAD_BLOCK;
+    }
+
+    if (fs->mmp_buf == NULL) {
+        retval = ext2fs_get_mem(fs->blocksize,
+                    &fs->mmp_buf);
+        if (retval)
+            return retval;
+    }
+
+    mmp_s = fs->mmp_buf;
+
+    retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block,
+                 fs->mmp_buf);
+    if (retval)
+        return retval;
+
+    t = mmp_s->mmp_time;
+    fprintf(stdout, "block_number: %llu\n", fs->super->s_mmp_block);
+    fprintf(stdout, "update_interval: %d\n",
+        fs->super->s_mmp_update_interval);
+    fprintf(stdout, "check_interval: %d\n", mmp_s->mmp_check_interval);
+    fprintf(stdout, "sequence: %08x\n", mmp_s->mmp_seq);
+    fprintf(stdout, "time: %lld -- %s", mmp_s->mmp_time, ctime(&t));
+    fprintf(stdout, "node_name: %s\n", mmp_s->mmp_nodename);
+    fprintf(stdout, "device_name: %s\n", mmp_s->mmp_bdevname);
+    fprintf(stdout, "magic: 0x%x\n", mmp_s->mmp_magic);
+    fprintf(stdout, "checksum: 0x%08x\n", mmp_s->mmp_checksum);
+
+    return 0;
+#else
+    return EXT2_ET_OP_NOT_SUPPORTED;
+#endif
+}
+
 /*
  * Make sure that the fs is not mounted or being fsck'ed while opening the fs.
  */
