[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20180504100612.3saqwh2bkkcwhuvi@rh_laptop>
Date: Fri, 4 May 2018 12:06:12 +0200
From: Lukas Czerner <lczerner@...hat.com>
To: Andreas Dilger <adilger@...ger.ca>
Cc: tytso@....edu, linux-ext4@...r.kernel.org,
Shuichi Ihara <sihara@....com>, Li Xi <lixi@....com>,
Wang Shilong <wshilong@....com>
Subject: Re: [PATCH 10/10] misc: add e2mmpstatus utility via debugfs
On Tue, May 01, 2018 at 10:26:06PM -0600, Andreas Dilger wrote:
> From: Shuichi Ihara <sihara@....com>
>
> e2mmpstatus is a Multi-Mount Protection (MMP) helper utility to read
> an MMP block to see if it is being updated. It can also output the
> latest update time, nodename, and device from the MMP block.
>
> This is useful for HA and other maintenance scripts to determine if
> the filesystem is in use on another node, and which node it is.
>
> Signed-off-by: Shuichi Ihara <sihara@....com>
> Signed-off-by: Li Xi <lixi@....com>
> Signed-off-by: Wang Shilong <wshilong@....com>
>
> Moved e2mmpstatus checking/dumping code to be part of dumpe2fs rather
> than a standalone program, using the "-m" option to check MMP status,
> and "-i" to dump info. If dumpe2fs is called as "e2mmpstatus" (and
> also "mmpstatus" for compatibility reasons), assume "-m" is specified.
Hmm, why do we need an alias to dumpe2fs options ? For what
compatibility you need mmpstatus as well ? I do not like it, see below.
>
> Re-use the existing MMP block handing routines (with some changes) to
> check and dump the MMP block, rather than adding duplicate versions.
>
> Modify dumpe2fs to exit with a non-zero error code if there is an
> error while reading the filesystem metadata or MMP block, or if
> "-m" is used with the "mmp" feature and is in use by another node.
>
> Add a configure check for gethostname() rather than depending on
> _BSD_SOURCE or _XOPEN_SOURCE to be set.
>
> Update the f_mmp, m_mmp, m_mmp_bad_csum, and m_mmp_bad_magic tests
> to use e2mmpstatus to check and dump the MMP state before and after
> e2fsck is run to verify that the tool is working correctly.
>
> Signed-off-by: Andreas Dilger <adilger@...ger.ca>
> ---
> .gitignore | 2 +
> configure | 2 +-
> configure.ac | 1 +
> e2fsck/e2fsck.h | 2 +-
> e2fsck/problem.c | 2 +-
> e2fsck/unix.c | 3 +-
> e2fsck/util.c | 22 +++--
> e2fsprogs.spec.in | 2 +
> lib/config.h.in | 15 +++-
> lib/ext2fs/ext2_err.et.in | 4 +-
> lib/ext2fs/mmp.c | 12 ++-
> misc/Makefile.in | 11 ++-
> misc/dumpe2fs.8.in | 22 ++++-
> misc/dumpe2fs.c | 202 ++++++++++++++++++++++++++++++++++---------
> misc/e2mmpstatus.8.in | 59 +++++++++++++
> tests/f_mmp/script | 7 ++
> tests/m_mmp/expect.1 | 8 ++
> tests/m_mmp_bad_csum/expect | 16 +++-
> tests/m_mmp_bad_csum/script | 9 +-
> tests/m_mmp_bad_magic/expect | 13 +++
> tests/m_mmp_bad_magic/script | 9 +-
> tests/test_config | 1 +
> 22 files changed, 360 insertions(+), 64 deletions(-)
> create mode 100644 misc/e2mmpstatus.8.in
>
> diff --git a/.gitignore b/.gitignore
> index ac5c2c1..3352ccc 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -170,6 +170,8 @@ misc/e2image
> misc/e2image.8
> misc/e2initrd_helper
> misc/e2label.8
> +misc/e2mmpstatus
> +misc/e2mmpstatus.8
> misc/e2undo
> misc/e2undo.8
> misc/e4crypt
> diff --git a/configure b/configure
> index b2701d2..c7853d1 100755
> --- a/configure
> +++ b/configure
> @@ -13097,7 +13097,7 @@ fi
> if test -n "$DLOPEN_LIB" ; then
> ac_cv_func_dlopen=yes
> fi
> -for ac_func in __secure_getenv add_key backtrace blkid_probe_get_topology blkid_probe_enable_partitions chflags dlopen fadvise64 fallocate fallocate64 fchown fcntl fdatasync fstat64 fsync ftruncate64 futimes getcwd getdtablesize getmntinfo getpwuid_r getrlimit getrusage jrand48 keyctl llistxattr llseek lseek64 mallinfo mbstowcs memalign mempcpy mmap msync nanosleep open64 pathconf posix_fadvise posix_fadvise64 posix_memalign prctl pread pwrite pread64 pwrite64 secure_getenv setmntent setresgid setresuid snprintf srandom stpcpy strcasecmp strdup strnlen strptime strtoull sync_file_range sysconf usleep utime utimes valloc
> +for ac_func in __secure_getenv add_key backtrace blkid_probe_get_topology blkid_probe_enable_partitions chflags dlopen fadvise64 fallocate fallocate64 fchown fcntl fdatasync fstat64 fsync ftruncate64 futimes getcwd getdtablesize gethostname getmntinfo getpwuid_r getrlimit getrusage jrand48 keyctl llistxattr llseek lseek64 mallinfo mbstowcs memalign mempcpy mmap msync nanosleep open64 pathconf posix_fadvise posix_fadvise64 posix_memalign prctl pread pwrite pread64 pwrite64 secure_getenv setmntent setresgid setresuid snprintf srandom stpcpy strcasecmp strdup strnlen strptime strtoull sync_file_range sysconf usleep utime utimes valloc
> do :
> as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
> ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
> diff --git a/configure.ac b/configure.ac
> index 7392959..5e837c9 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1124,6 +1124,7 @@ AC_CHECK_FUNCS(m4_flatten([
> futimes
> getcwd
> getdtablesize
> + gethostname
> getmntinfo
> getpwuid_r
> getrlimit
> diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
> index 5269650..d151bfd 100644
> --- a/e2fsck/e2fsck.h
> +++ b/e2fsck/e2fsck.h
> @@ -634,7 +634,7 @@ extern blk64_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs,
> const char *name, io_manager manager);
> extern int ext2_file_type(unsigned int mode);
> extern int write_all(int fd, char *buf, size_t count);
> -void dump_mmp_msg(struct mmp_struct *mmp, const char *msg);
> +void dump_mmp_msg(struct mmp_struct *mmp, const char *fmt, ...);
> errcode_t e2fsck_mmp_update(ext2_filsys fs);
>
> extern void e2fsck_set_bitmap_type(ext2_filsys fs,
> diff --git a/e2fsck/problem.c b/e2fsck/problem.c
> index ff289b4..be79fdb 100644
> --- a/e2fsck/problem.c
> +++ b/e2fsck/problem.c
> @@ -450,7 +450,7 @@ static struct e2fsck_problem problem_table[] = {
>
> /* Superblock MMP block checksum does not match MMP block. */
> { PR_0_MMP_CSUM_INVALID,
> - N_("@S MMP @b checksum does not match MMP @b. "),
> + N_("@S MMP @b checksum does not match. "),
> PROMPT_FIX, PR_PREEN_OK | PR_NO_OK},
>
> /* Superblock 64bit filesystem needs extents to access the whole disk */
> diff --git a/e2fsck/unix.c b/e2fsck/unix.c
> index cbe5ec5..beeaed2 100644
> --- a/e2fsck/unix.c
> +++ b/e2fsck/unix.c
> @@ -1250,7 +1250,8 @@ check_error:
> dump_mmp_msg(fs->mmp_buf,
> _("If you are sure the filesystem is not "
> "in use on any node, run:\n"
> - "'tune2fs -f -E clear_mmp {device}'\n"));
> + "'tune2fs -f -E clear_mmp %s'\n"),
> + ctx->device_name);
> } else if (retval == EXT2_ET_MMP_MAGIC_INVALID) {
> if (fix_problem(ctx, PR_0_MMP_INVALID_MAGIC, &pctx)) {
> ext2fs_mmp_clear(fs);
> diff --git a/e2fsck/util.c b/e2fsck/util.c
> index ed94702..5793b65 100644
> --- a/e2fsck/util.c
> +++ b/e2fsck/util.c
> @@ -756,16 +756,28 @@ int write_all(int fd, char *buf, size_t count)
> return c;
> }
>
> -void dump_mmp_msg(struct mmp_struct *mmp, const char *msg)
> +void dump_mmp_msg(struct mmp_struct *mmp, const char *fmt, ...)
> {
> + va_list pvar;
>
> - if (msg)
> - printf("MMP check failed: %s\n", msg);
> + if (fmt) {
> + printf("MMP check failed: ");
> + va_start(pvar, fmt);
> + vprintf(fmt, pvar);
> + va_end(pvar);
> + }
> if (mmp) {
> time_t t = mmp->mmp_time;
>
> - printf("MMP error info: last update: %s node: %s device: %s\n",
> - ctime(&t), mmp->mmp_nodename, mmp->mmp_bdevname);
> + printf("MMP_block:\n");
> + printf(" mmp_magic: 0x%x\n", mmp->mmp_magic);
> + printf(" mmp_check_interval: %d\n",
> + mmp->mmp_check_interval);
> + printf(" mmp_sequence: %08x\n", mmp->mmp_seq);
> + printf(" mmp_update_date: %s", ctime(&t));
> + printf(" mmp_update_time: %lld\n", mmp->mmp_time);
> + printf(" mmp_node_name: %s\n", mmp->mmp_nodename);
> + printf(" mmp_device_name: %s\n", mmp->mmp_bdevname);
> }
> }
>
> diff --git a/e2fsprogs.spec.in b/e2fsprogs.spec.in
> index b188b75..f42c4be 100644
> --- a/e2fsprogs.spec.in
> +++ b/e2fsprogs.spec.in
> @@ -116,6 +116,7 @@ exit 0
> %{_root_sbindir}/e2fsck
> %{_root_sbindir}/e2image
> %{_root_sbindir}/e2label
> +%{_root_sbindir}/e2mmpstatus
> %{_root_sbindir}/e2undo
> %{_root_sbindir}/findfs
> %{_root_sbindir}/fsck
> @@ -167,6 +168,7 @@ exit 0
> %{_mandir}/man8/fsck.ext4dev.8*
> %{_mandir}/man8/e2image.8*
> %{_mandir}/man8/e2label.8*
> +%{_mandir}/man8/e2mmpstatus.8*
> %{_mandir}/man8/e2undo.8*
> %{_mandir}/man8/fsck.8*
> %{_mandir}/man8/logsave.8*
> diff --git a/lib/config.h.in b/lib/config.h.in
> index 9cc0793..67a0548 100644
> --- a/lib/config.h.in
> +++ b/lib/config.h.in
> @@ -147,6 +147,9 @@
> /* Define to 1 if you have the `fchown' function. */
> #undef HAVE_FCHOWN
>
> +/* Define to 1 if you have the `fcntl' function. */
> +#undef HAVE_FCNTL
> +
> /* Define to 1 if you have the `fdatasync' function. */
> #undef HAVE_FDATASYNC
>
> @@ -156,6 +159,9 @@
> /* Define to 1 if you have the `fstat64' function. */
> #undef HAVE_FSTAT64
>
> +/* Define to 1 if you have the `fsync' function. */
> +#undef HAVE_FSYNC
> +
> /* Define to 1 if you have the `ftruncate64' function. */
> #undef HAVE_FTRUNCATE64
>
> @@ -183,6 +189,9 @@
> /* Define to 1 if you have the `getgid' function. */
> #undef HAVE_GETGID
>
> +/* Define to 1 if you have the `gethostname' function. */
> +#undef HAVE_GETHOSTNAME
> +
> /* Define to 1 if you have the `getmntinfo' function. */
> #undef HAVE_GETMNTINFO
>
> @@ -253,6 +262,9 @@
> /* Define to 1 if you have the <linux/major.h> header file. */
> #undef HAVE_LINUX_MAJOR_H
>
> +/* Define to 1 if you have the <linux/types.h> header file. */
> +#undef HAVE_LINUX_TYPES_H
> +
> /* Define to 1 if you have the `llistxattr' function. */
> #undef HAVE_LLISTXATTR
>
> @@ -470,9 +482,6 @@
> /* Define to 1 if you have the `sync_file_range' function. */
> #undef HAVE_SYNC_FILE_RANGE
>
> -/* Define to 1 if you have the 'fsync' function. */
> -#undef HAVE_FSYNC
> -
> /* Define to 1 if you have the `sysconf' function. */
> #undef HAVE_SYSCONF
>
> diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> index 16abd23..b2ba71a 100644
> --- a/lib/ext2fs/ext2_err.et.in
> +++ b/lib/ext2fs/ext2_err.et.in
> @@ -429,7 +429,7 @@ ec EXT2_ET_MMP_FAILED,
> "MMP: device currently active"
>
> ec EXT2_ET_MMP_FSCK_ON,
> - "MMP: fsck being run"
> + "MMP: e2fsck being run"
>
> ec EXT2_ET_MMP_BAD_BLOCK,
> "MMP: block number beyond filesystem range"
> @@ -471,7 +471,7 @@ ec EXT2_ET_UNKNOWN_CSUM,
> "Unknown checksum algorithm"
>
> ec EXT2_ET_MMP_CSUM_INVALID,
> - "MMP block checksum does not match MMP block"
> + "MMP block checksum does not match"
>
> ec EXT2_ET_FILE_EXISTS,
> "Ext2 file already exists"
> diff --git a/lib/ext2fs/mmp.c b/lib/ext2fs/mmp.c
> index 9a771de..0cf0d0d 100644
> --- a/lib/ext2fs/mmp.c
> +++ b/lib/ext2fs/mmp.c
> @@ -194,7 +194,7 @@ static errcode_t ext2fs_mmp_reset(ext2_filsys fs)
> mmp_s->mmp_magic = EXT4_MMP_MAGIC;
> mmp_s->mmp_seq = EXT4_MMP_SEQ_CLEAN;
> mmp_s->mmp_time = 0;
> -#if _BSD_SOURCE || _XOPEN_SOURCE >= 500
> +#ifdef HAVE_GETHOSTNAME
> gethostname(mmp_s->mmp_nodename, sizeof(mmp_s->mmp_nodename));
> #else
> mmp_s->mmp_nodename[0] = '\0';
> @@ -269,6 +269,10 @@ out:
> #endif
> }
>
> +#ifndef min
> +#define min(x, y) ((x) < (y) ? (x) : (y))
> +#endif
> +
> /*
> * Make sure that the fs is not mounted or being fsck'ed while opening the fs.
> */
> @@ -316,7 +320,7 @@ errcode_t ext2fs_mmp_start(ext2_filsys fs)
> if (mmp_s->mmp_check_interval > mmp_check_interval)
> mmp_check_interval = mmp_s->mmp_check_interval;
>
> - sleep(2 * mmp_check_interval + 1);
> + sleep(min(mmp_check_interval * 2 + 1, mmp_check_interval + 60));
>
> retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf);
> if (retval)
> @@ -332,7 +336,7 @@ clean_seq:
> goto mmp_error;
>
> mmp_s->mmp_seq = seq = ext2fs_mmp_new_seq();
> -#if _BSD_SOURCE || _XOPEN_SOURCE >= 500
> +#ifdef HAVE_GETHOSTNAME
> gethostname(mmp_s->mmp_nodename, sizeof(mmp_s->mmp_nodename));
> #else
> strcpy(mmp_s->mmp_nodename, "unknown host");
> @@ -344,7 +348,7 @@ clean_seq:
> if (retval)
> goto mmp_error;
>
> - sleep(2 * mmp_check_interval + 1);
> + sleep(min(2 * mmp_check_interval + 1, mmp_check_interval + 60));
>
> retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf);
> if (retval)
> diff --git a/misc/Makefile.in b/misc/Makefile.in
> index efc0e0b..f500276 100644
> --- a/misc/Makefile.in
> +++ b/misc/Makefile.in
> @@ -39,7 +39,8 @@ USPROGS= mklost+found filefrag e2freefrag $(UUIDD_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) $(E4CRYPT_MAN) @FSCK_MAN@
> + $(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@ \
> + e2mmpstatus.8
> FMANPAGES= mke2fs.conf.5 ext4.5
>
> UPROGS= chattr lsattr @UUID_CMT@ uuidgen
> @@ -475,6 +476,10 @@ dumpe2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/dumpe2fs.8.in
> $(E) " SUBST $@"
> $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/dumpe2fs.8.in dumpe2fs.8
>
> +e2mmpstatus.8: $(DEP_SUBSTITUTE) $(srcdir)/e2mmpstatus.8.in
> + $(E) " SUBST $@"
> + $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2mmpstatus.8.in e2mmpstatus.8
> +
> badblocks.8: $(DEP_SUBSTITUTE) $(srcdir)/badblocks.8.in
> $(E) " SUBST $@"
> $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/badblocks.8.in badblocks.8
> @@ -546,6 +551,8 @@ install: all $(SMANPAGES) $(UMANPAGES) installdirs
> $(LN) $(LINK_INSTALL_FLAGS) mke2fs mkfs.$$i); \
> done
> $(Q) (cd $(DESTDIR)$(root_sbindir); \
> + $(LN) $(LINK_INSTALL_FLAGS) dumpe2fs e2mmpstatus)
> + $(Q) (cd $(DESTDIR)$(root_sbindir); \
> $(LN) $(LINK_INSTALL_FLAGS) tune2fs e2label)
> $(Q) if test -n "$(FINDFS_LINK)"; then \
> $(ES) " LINK $(root_sbindir)/findfs"; \
> @@ -661,7 +668,7 @@ uninstall:
> for i in $(UMANPAGES); do \
> $(RM) -f $(DESTDIR)$(man1dir)/$$i; \
> done
> - for i in $(FINDFS_LINK) e2label ; do \
> + for i in $(FINDFS_LINK) e2label e2mmpstatus ; do \
> $(RM) -f $(DESTDIR)$(root_sbindir)/$$i; \
> done
> for i in $(FMANPAGES); do \
> diff --git a/misc/dumpe2fs.8.in b/misc/dumpe2fs.8.in
> index da78d4f..ce3214f 100644
> --- a/misc/dumpe2fs.8.in
> +++ b/misc/dumpe2fs.8.in
> @@ -69,6 +69,17 @@ using
> .I device
> as the pathname to the image file.
> .TP
> +.B \-m
> +If the
> +.B mmp
> +feature is enabled on the filesystem, check if
> +.I device
> +is in use by another node, see
> +.BR e2mmpstatus (8)
> +for full details. If used together with the
> +.B \-i
> +option, only the MMP block information is printed.
> +.TP
> .B \-x
> print the detailed group information block numbers in hexadecimal format
> .TP
> @@ -76,8 +87,16 @@ print the detailed group information block numbers in hexadecimal format
> print the version number of
> .B dumpe2fs
> and exit.
> +.SH EXIT CODE
> +.B dumpe2fs
> +exits with a return code of 0 if the operation completed without errors.
> +It will exit with a non-zero return code if there are any errors, such
> +as problems reading a valid superblock, bad checksums, or if the device
> +is in use by another node and
> +.B -m
> +is specified.
> .SH BUGS
> -You need to know the physical filesystem structure to understand the
> +You may need to know the physical filesystem structure to understand the
> output.
> .SH AUTHOR
> .B dumpe2fs
> @@ -89,6 +108,7 @@ is part of the e2fsprogs package and is available from
> http://e2fsprogs.sourceforge.net.
> .SH SEE ALSO
> .BR e2fsck (8),
> +.BR e2mmpstatus (8),
> .BR mke2fs (8),
> .BR tune2fs (8).
> .BR ext4 (5)
> diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
> index 395ea9e..384ce92 100644
> --- a/misc/dumpe2fs.c
> +++ b/misc/dumpe2fs.c
> @@ -53,7 +53,7 @@ static int blocks64 = 0;
>
> static void usage(void)
> {
> - fprintf(stderr, _("Usage: %s [-bfghixV] [-o superblock=<num>] "
> + fprintf(stderr, _("Usage: %s [-bfghimxV] [-o superblock=<num>] "
> "[-o blocksize=<num>] device\n"), program_name);
> exit(1);
> }
> @@ -420,6 +420,79 @@ static void print_journal_information(ext2_filsys fs)
> e2p_list_journal_super(stdout, buf, fs->blocksize, 0);
> }
>
> +static int check_mmp(ext2_filsys fs)
> +{
> + int retval;
> +
> + /* This won't actually start MMP on the filesystem, since fs is opened
> + * readonly, but it will do the proper activity checking for us. */
> + retval = ext2fs_mmp_start(fs);
> + if (retval) {
> + com_err(program_name, retval, _("while trying to open %s"),
> + fs->device_name);
> + if (retval == EXT2_ET_MMP_FAILED ||
> + retval == EXT2_ET_MMP_FSCK_ON ||
> + retval == EXT2_ET_MMP_CSUM_INVALID ||
> + retval == EXT2_ET_MMP_UNKNOWN_SEQ) {
> + if (fs->mmp_buf) {
> + struct mmp_struct *mmp = fs->mmp_buf;
> + time_t mmp_time = mmp->mmp_time;
> +
> + fprintf(stderr,
> + "%s: MMP last updated by '%s' on %s",
> + program_name, mmp->mmp_nodename,
> + ctime(&mmp_time));
> + }
> + retval = 1;
> + } else {
> + retval = 2;
> + }
> + } else {
> + printf("%s: it is safe to mount '%s', MMP is clean\n",
> + program_name, fs->device_name);
> + }
> +
> + return retval;
> +}
> +
> +static void print_mmp_block(ext2_filsys fs)
> +{
> + struct mmp_struct *mmp;
> + time_t mmp_time;
> + errcode_t retval;
> +
> + if (fs->mmp_buf == NULL) {
> + retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf);
> + if (retval) {
> + com_err(program_name, retval,
> + _("failed to alloc MMP buffer\n"));
> + return;
> + }
> + }
> +
> + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf);
> + /* this is only dumping, not checking status, so OK to skip this */
> + if (retval == EXT2_ET_OP_NOT_SUPPORTED)
> + return;
> + if (retval) {
> + com_err(program_name, retval,
> + _("reading MMP block %llu from '%s'\n"),
> + fs->super->s_mmp_block, fs->device_name);
> + return;
> + }
> +
> + mmp = fs->mmp_buf;
> + mmp_time = mmp->mmp_time;
> + printf("MMP_block:\n");
> + printf(" mmp_magic: 0x%x\n", mmp->mmp_magic);
> + printf(" mmp_check_interval: %d\n", mmp->mmp_check_interval);
> + printf(" mmp_sequence: %#08x\n", mmp->mmp_seq);
> + printf(" mmp_update_date: %s", ctime(&mmp_time));
> + printf(" mmp_update_time: %lld\n", mmp->mmp_time);
> + printf(" mmp_node_name: %s\n", mmp->mmp_nodename);
> + printf(" mmp_device_name: %s\n", mmp->mmp_bdevname);
> +}
> +
> static void parse_extended_opts(const char *opts, blk64_t *superblock,
> int *blocksize)
> {
> @@ -500,11 +573,15 @@ static void parse_extended_opts(const char *opts, blk64_t *superblock,
> int main (int argc, char ** argv)
> {
> errcode_t retval;
> + errcode_t retval_csum = 0;
> + const char *error_csum = NULL;
> ext2_filsys fs;
> int print_badblocks = 0;
> blk64_t use_superblock = 0;
> int use_blocksize = 0;
> int image_dump = 0;
> + int mmp_check = 0;
> + int mmp_info = 0;
> int force = 0;
> int flags;
> int header_only = 0;
> @@ -519,12 +596,23 @@ int main (int argc, char ** argv)
> set_com_err_gettext(gettext);
> #endif
> add_error_table(&et_ext2_error_table);
> - fprintf (stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION,
> - E2FSPROGS_DATE);
> - if (argc && *argv)
> - program_name = *argv;
> + if (argc && *argv) {
> + if (strrchr(*argv, '/'))
> + program_name = strrchr(*argv, '/') + 1;
> + else
> + program_name = *argv;
> +
> + if (strstr(program_name, "mmpstatus") != NULL) {
> + mmp_check = 1;
> + header_only = 1;
> + }
> + }
>
> - while ((c = getopt(argc, argv, "bfghixVo:")) != EOF) {
> + if (!mmp_check)
> + fprintf(stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION,
> + E2FSPROGS_DATE);
> +
> + while ((c = getopt(argc, argv, "bfghimxVo:")) != EOF) {
> switch (c) {
> case 'b':
> print_badblocks++;
> @@ -539,7 +627,18 @@ int main (int argc, char ** argv)
> header_only++;
> break;
> case 'i':
> - image_dump++;
> + if (mmp_check)
> + mmp_info++;
> + else
> + image_dump++;
> + break;
> + case 'm':
> + mmp_check++;
> + header_only++;
> + if (image_dump) {
> + mmp_info = image_dump;
> + image_dump = 0;
> + }
That's fugly, I hate it with passion. The whole idea of making a decision
based on the binary name, changing the meaning of the parameters and on
top of that changing the meanin of "-i" in case we specify "-m" as
well, looks like a horrible mess to me.
Again, why do we need the mmpstatus alias ? why is dumpe2fs not enough ?
-Lukas
> break;
> case 'o':
> parse_extended_opts(optarg, &use_superblock,
> @@ -557,12 +656,12 @@ int main (int argc, char ** argv)
> usage();
> }
> }
> - if (optind != argc - 1) {
> + if (optind != argc - 1)
> usage();
> - exit(1);
> - }
> +
> device_name = argv[optind++];
> - flags = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS;
> + flags = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES |
> + EXT2_FLAG_64BITS;
> if (force)
> flags |= EXT2_FLAG_FORCE;
> if (image_dump)
> @@ -579,64 +678,87 @@ try_open_again:
> if (!retval)
> break;
> }
> - } else
> - retval = ext2fs_open (device_name, flags, use_superblock,
> - use_blocksize, unix_io_manager, &fs);
> - if (retval && !(flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
> - flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
> - goto try_open_again;
> + } else {
> + retval = ext2fs_open(device_name, flags, use_superblock,
> + use_blocksize, unix_io_manager, &fs);
> }
> - if (!retval && (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS))
> - printf("%s", _("\n*** Checksum errors detected in filesystem! Run e2fsck now!\n\n"));
> flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
> + if (retval && !retval_csum) {
> + retval_csum = retval;
> + error_csum = _("while trying to open %s");
> + goto try_open_again;
> + }
> if (retval) {
> - com_err (program_name, retval, _("while trying to open %s"),
> - device_name);
> + com_err(program_name, retval, _("while trying to open %s"),
> + device_name);
> printf("%s", _("Couldn't find valid filesystem superblock.\n"));
> if (retval == EXT2_ET_BAD_MAGIC)
> check_plausibility(device_name, CHECK_FS_EXIST, NULL);
> - exit (1);
> + goto out;
> }
> fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
> if (ext2fs_has_feature_64bit(fs->super))
> blocks64 = 1;
> - if (print_badblocks) {
> + if (mmp_check) {
> + if (ext2fs_has_feature_mmp(fs->super) &&
> + fs->super->s_mmp_block != 0) {
> + if (mmp_info) {
> + print_mmp_block(fs);
> + printf(" mmp_block_number: ");
> + print_number(fs->super->s_mmp_block);
> + printf("\n");
> + } else {
> + retval = check_mmp(fs);
> + }
> + if (!retval && retval_csum)
> + retval = 2;
> + } else {
> + fprintf(stderr, _("%s: MMP feature not enabled.\n"),
> + program_name);
> + retval = 2;
> + }
> + } else if (print_badblocks) {
> list_bad_blocks(fs, 1);
> } else {
> if (grp_only)
> goto just_descriptors;
> - list_super (fs->super);
> + list_super(fs->super);
> if (ext2fs_has_feature_journal_dev(fs->super)) {
> print_journal_information(fs);
> - ext2fs_close_free(&fs);
> - exit(0);
> +
> + goto out_close;
> }
> if (ext2fs_has_feature_journal(fs->super) &&
> (fs->super->s_journal_inum != 0))
> print_inline_journal_information(fs);
> + if (ext2fs_has_feature_mmp(fs->super) &&
> + fs->super->s_mmp_block != 0)
> + print_mmp_block(fs);
> list_bad_blocks(fs, 0);
> - if (header_only) {
> - ext2fs_close_free(&fs);
> - exit (0);
> - }
> + if (header_only)
> + goto out_close;
> +
> fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
> try_bitmaps_again:
> - retval = ext2fs_read_bitmaps (fs);
> - if (retval && !(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
> + retval = ext2fs_read_bitmaps(fs);
> + if (retval && !retval_csum) {
> fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
> + retval_csum = retval;
> + error_csum = _("while trying to read '%s' bitmaps\n");
> goto try_bitmaps_again;
> }
> - if (!retval && (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS))
> - printf("%s", _("\n*** Checksum errors detected in bitmaps! Run e2fsck now!\n\n"));
> just_descriptors:
> list_desc(fs, grp_only);
> - if (retval) {
> - printf(_("\n%s: %s: error reading bitmaps: %s\n"),
> - program_name, device_name,
> - error_message(retval));
> - }
> + }
> +out_close:
> + if (retval_csum) {
> + com_err(program_name, retval_csum, error_csum, device_name);
> + printf("%s", _("*** Run e2fsck now!\n\n"));
> + if (!retval)
> + retval = retval_csum;
> }
> ext2fs_close_free(&fs);
> remove_error_table(&et_ext2_error_table);
> - exit (0);
> +out:
> + return retval;
> }
> diff --git a/misc/e2mmpstatus.8.in b/misc/e2mmpstatus.8.in
> new file mode 100644
> index 0000000..f7d9557
> --- /dev/null
> +++ b/misc/e2mmpstatus.8.in
> @@ -0,0 +1,59 @@
> +.\" -*- nroff -*-
> +.\" This file may be copied under the terms of the GNU Public License.
> +.\"
> +.TH E2MMPSTATUS 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
> +.SH NAME
> +e2mmpstatus \- Check MMP status of an ext4 filesystem
> +.SH SYNOPSIS
> +.BR e2mmpstatus " [" \-i ]
> +.RI < filesystem >
> +.SH OPTIONS
> +.TP
> +.B \-i
> +prints out the MMP information rather than check it.
> +.SH DESCRIPTION
> +.B e2mmpstatus
> +is used to check Multiple-Mount Protection (MMP) status of an ext4
> +filesystem with the
> +.B mmp
> +feature enabled. The specified
> +.I filesystem
> +can be a device name (e.g.
> +.IR /dev/hdc1 ", " /dev/sdb2 ),
> +or an ext4 filesystem label or UUID, for example
> +.B UUID=8868abf6-88c5-4a83-98b8-bfc24057f7bd
> +or
> +.BR LABEL=root .
> +By default, the
> +.B e2mmpstatus
> +program checks whether it is safe to mount the filesystem without taking
> +the risk of mounting it more than once.
> +.PP
> +MMP (multiple-mount protection) is a feature that adds protection against
> +the filesystem being modified simultaneously by more than one node.
> +It is NOT safe to mount a filesystem when one of the following conditions
> +is true:
> +.br
> +\ 1. e2fsck is running on the filesystem.
> +.br
> +\ 2. the filesystem is in use by another node.
> +.br
> +\ 3. The MMP block is corrupted or cannot be read for some reason.
> +.br
> +The
> +.B e2mmpstatus
> +program might wait for some time to see whether the MMP block is being
> +updated by any node during this period. The time taken depends on how
> +frequently the MMP block is being written by the other node.
> +.SH EXIT CODE
> +The exit code returned by
> +.B e2mmpstatus
> +is 0 when it is safe to mount the filesystem, 1 when the MMP block shows
> +the filesystem is in use on another node and it is NOT safe to mount
> +the filesystem, and 2 if some other failure occurred that prevents the
> +check from properly detecting the current MMP status.
> +.SH SEE ALSO
> +.BR dumpe2fs (8),
> +.BR e2fsck (8),
> +.BR fstab (5),
> +.BR fsck (8),
> diff --git a/tests/f_mmp/script b/tests/f_mmp/script
> index 9ff16c9..07ae232 100644
> --- a/tests/f_mmp/script
> +++ b/tests/f_mmp/script
> @@ -43,6 +43,13 @@ rm -f $MARKFILE
> echo "kill debugfs abruptly (simulates e2fsck failure) ..." >> $test_name.log
> kill_debugfs
>
> +$E2MMPSTATUS $TMPFILE > $test_name.log 2>&1
> +status=$?
> +if [ "$status" != 1 ] ; then
> + echo "$E2MMPSTATUS with EXT2_MMP_SEQ_FSCK passed!" > $test_name.failed
> + echo "$test_name: $test_description: failed"
> + return 1
> +fi
>
> echo "e2fsck (should fail mmp_seq = EXT2_MMP_SEQ_FSCK) ..." >> $test_name.log
> $FSCK $FSCK_OPT $TMPFILE >> $test_name.log 2>&1
> diff --git a/tests/m_mmp/expect.1 b/tests/m_mmp/expect.1
> index a1452e6..9d8a5a3 100644
> --- a/tests/m_mmp/expect.1
> +++ b/tests/m_mmp/expect.1
> @@ -46,6 +46,14 @@ Inode size: 128
> Default directory hash: half_md4
> MMP block number: 1049
> MMP update interval: 5
> +MMP_block:
> + mmp_magic: 0x4d4d50
> + mmp_check_interval: 5
> + mmp_sequence: 0xff4d4d50
> + mmp_update_date: test date
> + mmp_update_time: test_time
> + mmp_node_name: test_node
> + mmp_device_name: test.img
>
>
> Group 0: (Blocks 0-32767)
> diff --git a/tests/m_mmp_bad_csum/expect b/tests/m_mmp_bad_csum/expect
> index e15e7b4..a0678ac 100644
> --- a/tests/m_mmp_bad_csum/expect
> +++ b/tests/m_mmp_bad_csum/expect
> @@ -1,4 +1,7 @@
> -Superblock MMP block checksum does not match MMP block. Fix? yes
> +dumpe2fs: MMP block checksum does not match while trying to open test.img
> +dumpe2fs: MMP last updated by 'test_node' on test date
> +Exit status is 1
> +Superblock MMP block checksum does not match. Fix? yes
>
> Pass 1: Checking inodes, blocks, and sizes
> Pass 2: Checking directory structure
> @@ -7,3 +10,14 @@ Pass 4: Checking reference counts
> Pass 5: Checking group summary information
> test_filesys: 11/128 files (0.0% non-contiguous), 19/512 blocks
> Exit status is 0
> +dumpe2fs: it is safe to mount 'test.img', MMP is clean
> +Exit status is 0
> +MMP_block:
> + mmp_magic: 0x4d4d50
> + mmp_check_interval: 5
> + mmp_sequence: 0xff4d4d50
> + mmp_update_date: test date
> + mmp_update_time: test_time
> + mmp_node_name: test_node
> + mmp_device_name: test.img
> + mmp_block_number: 8
> diff --git a/tests/m_mmp_bad_csum/script b/tests/m_mmp_bad_csum/script
> index 09e870c..4c8fe16 100644
> --- a/tests/m_mmp_bad_csum/script
> +++ b/tests/m_mmp_bad_csum/script
> @@ -12,8 +12,15 @@ gzip -dc < $test_dir/image.gz > $TMPFILE
>
> OUT=$test_name.log
> EXP=$test_dir/expect
> -$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed > $OUT
> +$E2MMPSTATUS $TMPFILE > $OUT 2>&1
> echo Exit status is $? >> $OUT
> +$FSCK -fy $TMPFILE >> $OUT 2>&1
> +echo Exit status is $? >> $OUT
> +$E2MMPSTATUS $TMPFILE >> $OUT 2>&1
> +echo Exit status is $? >> $OUT
> +$E2MMPSTATUS -i $TMPFILE >> $OUT 2>&1
> +sed -f $cmd_dir/filter.sed $OUT > $OUT.new
> +mv $OUT.new $OUT
>
> rm -f $TMPFILE
> cmp -s $OUT $EXP
> diff --git a/tests/m_mmp_bad_magic/expect b/tests/m_mmp_bad_magic/expect
> index b5dfb89..d5fa98c 100644
> --- a/tests/m_mmp_bad_magic/expect
> +++ b/tests/m_mmp_bad_magic/expect
> @@ -1,3 +1,5 @@
> +dumpe2fs: MMP: invalid magic number while trying to open test.img
> +Exit status is 2
> Superblock has invalid MMP magic. Fix? yes
>
> Pass 1: Checking inodes, blocks, and sizes
> @@ -7,3 +9,14 @@ Pass 4: Checking reference counts
> Pass 5: Checking group summary information
> test_filesys: 11/128 files (0.0% non-contiguous), 19/512 blocks
> Exit status is 0
> +dumpe2fs: it is safe to mount 'test.img', MMP is clean
> +Exit status is 0
> +MMP_block:
> + mmp_magic: 0x4d4d50
> + mmp_check_interval: 5
> + mmp_sequence: 0xff4d4d50
> + mmp_update_date: test date
> + mmp_update_time: test_time
> + mmp_node_name: test_node
> + mmp_device_name: test.img
> + mmp_block_number: 8
> diff --git a/tests/m_mmp_bad_magic/script b/tests/m_mmp_bad_magic/script
> index 09e870c..4c8fe16 100644
> --- a/tests/m_mmp_bad_magic/script
> +++ b/tests/m_mmp_bad_magic/script
> @@ -12,8 +12,15 @@ gzip -dc < $test_dir/image.gz > $TMPFILE
>
> OUT=$test_name.log
> EXP=$test_dir/expect
> -$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed > $OUT
> +$E2MMPSTATUS $TMPFILE > $OUT 2>&1
> echo Exit status is $? >> $OUT
> +$FSCK -fy $TMPFILE >> $OUT 2>&1
> +echo Exit status is $? >> $OUT
> +$E2MMPSTATUS $TMPFILE >> $OUT 2>&1
> +echo Exit status is $? >> $OUT
> +$E2MMPSTATUS -i $TMPFILE >> $OUT 2>&1
> +sed -f $cmd_dir/filter.sed $OUT > $OUT.new
> +mv $OUT.new $OUT
>
> rm -f $TMPFILE
> cmp -s $OUT $EXP
> diff --git a/tests/test_config b/tests/test_config
> index cf9c79c..2aee6ff 100644
> --- a/tests/test_config
> +++ b/tests/test_config
> @@ -25,6 +25,7 @@ RESIZE2FS_EXE="../resize/resize2fs"
> RESIZE2FS="$USE_VALGRIND $RESIZE2FS_EXE"
> E2UNDO_EXE="../misc/e2undo"
> E2UNDO="$USE_VALGRIND $E2UNDO_EXE"
> +E2MMPSTATUS="$USE_VALGRIND ../misc/dumpe2fs -m"
> TEST_REL=../tests/progs/test_rel
> TEST_ICOUNT=../tests/progs/test_icount
> CRCSUM=../tests/progs/crcsum
> --
> 1.8.0
>
Powered by blists - more mailing lists