From 792517389fad5c495a2738b61c2e9c65dedaaa9a Mon Sep 17 00:00:00 2001 From: slashdd Date: Tue, 20 Sep 2016 13:07:58 -0400 Subject: [PATCH] Change /etc/mtab to /proc/self/mounts Fix misleading error message: "The /dev/zfs device is missing and must be created.", if /etc/mtab is missing. Reviewed-by: Richard Laager Reviewed-by: Brian Behlendorf Signed-off-by: Eric Desrochers Closes #4680 Closes #5029 --- cmd/mount_zfs/mount_zfs.c | 14 +++++------ cmd/zfs/zfs_main.c | 23 ++++++++++--------- cmd/zinject/translate.c | 2 +- config/user-commands.m4 | 2 +- contrib/initramfs/scripts/zfs | 7 +++--- etc/init.d/zfs-functions.in | 2 +- etc/init.d/zfs-mount.in | 4 ++-- lib/libspl/include/sys/mnttab.h | 2 +- lib/libzfs/libzfs_dataset.c | 11 +++++---- lib/libzfs/libzfs_mount.c | 8 +++---- lib/libzfs/libzfs_util.c | 6 ++--- scripts/ziltest.sh | 6 ++++- .../functional/cli_root/zfs/zfs_003_neg.ksh | 9 ++++++-- 13 files changed, 53 insertions(+), 43 deletions(-) diff --git a/cmd/mount_zfs/mount_zfs.c b/cmd/mount_zfs/mount_zfs.c index b78c91c7c..f6631a527 100644 --- a/cmd/mount_zfs/mount_zfs.c +++ b/cmd/mount_zfs/mount_zfs.c @@ -294,11 +294,11 @@ mtab_is_writeable(void) struct stat st; int error, fd; - error = lstat(MNTTAB, &st); + error = lstat("/etc/mtab", &st); if (error || S_ISLNK(st.st_mode)) return (0); - fd = open(MNTTAB, O_RDWR | O_CREAT, 0644); + fd = open("/etc/mtab", O_RDWR | O_CREAT, 0644); if (fd < 0) return (0); @@ -320,21 +320,21 @@ mtab_update(char *dataset, char *mntpoint, char *type, char *mntopts) mnt.mnt_freq = 0; mnt.mnt_passno = 0; - fp = setmntent(MNTTAB, "a+"); + fp = setmntent("/etc/mtab", "a+"); if (!fp) { (void) fprintf(stderr, gettext( - "filesystem '%s' was mounted, but %s " + "filesystem '%s' was mounted, but /etc/mtab " "could not be opened due to error %d\n"), - dataset, MNTTAB, errno); + dataset, errno); return (MOUNT_FILEIO); } error = addmntent(fp, &mnt); if (error) { (void) fprintf(stderr, gettext( - "filesystem '%s' was mounted, but %s " + "filesystem '%s' was mounted, but /etc/mtab " "could not be updated due to error %d\n"), - dataset, MNTTAB, errno); + dataset, errno); return (MOUNT_FILEIO); } diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index dd165da0e..cca52dbe7 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -6146,9 +6146,10 @@ share_mount(int op, int argc, char **argv) } /* - * When mount is given no arguments, go through /etc/mtab and - * display any active ZFS mounts. We hide any snapshots, since - * they are controlled automatically. + * When mount is given no arguments, go through + * /proc/self/mounts and display any active ZFS mounts. + * We hide any snapshots, since they are controlled + * automatically. */ /* Reopen MNTTAB to prevent reading stale data from open file */ @@ -6228,8 +6229,8 @@ unshare_unmount_compare(const void *larg, const void *rarg, void *unused) /* * Convenience routine used by zfs_do_umount() and manual_unmount(). Given an - * absolute path, find the entry /etc/mtab, verify that its a ZFS filesystem, - * and unmount it appropriately. + * absolute path, find the entry /proc/self/mounts, verify that its a + * ZFS filesystems, and unmount it appropriately. */ static int unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) @@ -6242,7 +6243,7 @@ unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) ino_t path_inode; /* - * Search for the path in /etc/mtab. Rather than looking for the + * Search for the path in /proc/self/mounts. Rather than looking for the * specific path, which can be fooled by non-standard paths (i.e. ".." * or "//"), we stat() the path and search for the corresponding * (major,minor) device pair. @@ -6273,8 +6274,8 @@ unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) "currently mounted\n"), cmdname, path); return (1); } - (void) fprintf(stderr, gettext("warning: %s not in mtab\n"), - path); + (void) fprintf(stderr, gettext("warning: %s not in" + "/proc/self/mounts\n"), path); if ((ret = umount2(path, flags)) != 0) (void) fprintf(stderr, gettext("%s: %s\n"), path, strerror(errno)); @@ -6385,9 +6386,9 @@ unshare_unmount(int op, int argc, char **argv) /* * We could make use of zfs_for_each() to walk all datasets in * the system, but this would be very inefficient, especially - * since we would have to linearly search /etc/mtab for each - * one. Instead, do one pass through /etc/mtab looking for - * zfs entries and call zfs_unmount() for each one. + * since we would have to linearly search /proc/self/mounts for + * each one. Instead, do one pass through /proc/self/mounts + * looking for zfs entries and call zfs_unmount() for each one. * * Things get a little tricky if the administrator has created * mountpoints beneath other ZFS filesystems. In this case, we diff --git a/cmd/zinject/translate.c b/cmd/zinject/translate.c index 5cc9d9fdc..adace72ff 100644 --- a/cmd/zinject/translate.c +++ b/cmd/zinject/translate.c @@ -120,7 +120,7 @@ parse_pathname(const char *inpath, char *dataset, char *relpath, #else if ((fp = fopen(MNTTAB, "r")) == NULL) { #endif - (void) fprintf(stderr, "cannot open /etc/mtab\n"); + (void) fprintf(stderr, "cannot open %s\n", MNTTAB); return (-1); } diff --git a/config/user-commands.m4 b/config/user-commands.m4 index 58633b4a0..6e9c3d103 100644 --- a/config/user-commands.m4 +++ b/config/user-commands.m4 @@ -127,7 +127,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_LINUX], [ PAGESIZE=$($GETCONF PAGESIZE) AC_SUBST(PAGESIZE) - MNTTAB=/etc/mtab + MNTTAB=/proc/self/mounts AC_SUBST(MNTTAB) ]) diff --git a/contrib/initramfs/scripts/zfs b/contrib/initramfs/scripts/zfs index 6a78a46d2..250dc5717 100644 --- a/contrib/initramfs/scripts/zfs +++ b/contrib/initramfs/scripts/zfs @@ -288,9 +288,8 @@ load_module_initrd() wait_for_dev fi - # zpool import refuse to import without a valid mtab - [ ! -f /proc/mounts ] && mount proc /proc - [ ! -f /etc/mtab ] && cat /proc/mounts > /etc/mtab + # zpool import refuse to import without a valid /proc/self/mounts + [ ! -f /proc/self/mounts ] && mount proc /proc # Load the module load_module "zfs" || return 1 @@ -919,7 +918,7 @@ mountroot() # # but the MOUNTPOINT prefix is preserved on descendent filesystem # after the pivot into the regular root, which later breaks things - # like `zfs mount -a` and the /etc/mtab refresh. + # like `zfs mount -a` and the /proc/self/mounts refresh. # # * Mount additional filesystems required # Such as /usr, /var, /usr/local etc. diff --git a/etc/init.d/zfs-functions.in b/etc/init.d/zfs-functions.in index acfdf9926..97f2ea039 100644 --- a/etc/init.d/zfs-functions.in +++ b/etc/init.d/zfs-functions.in @@ -368,7 +368,7 @@ read_mtab() # Set the variable. eval export MTAB_$mntpnt=\"$fs\" fi - done < /proc/mounts + done < /proc/self/mounts } in_mtab() diff --git a/etc/init.d/zfs-mount.in b/etc/init.d/zfs-mount.in index 34db057c8..2722a31e4 100755 --- a/etc/init.d/zfs-mount.in +++ b/etc/init.d/zfs-mount.in @@ -39,7 +39,7 @@ chkroot() { if [ "$2" = "/" ]; then return 0 fi - done < /etc/mtab + done < /proc/self/mounts return 1 } @@ -178,7 +178,7 @@ do_start() check_module_loaded "zfs" || exit 0 - # Ensure / exists in /etc/mtab, if not update mtab accordingly. + # Ensure / exists in /proc/self/mounts. # This should be handled by rc.sysinit but lets be paranoid. if ! chkroot then diff --git a/lib/libspl/include/sys/mnttab.h b/lib/libspl/include/sys/mnttab.h index 21d89658c..026a8fa7b 100644 --- a/lib/libspl/include/sys/mnttab.h +++ b/lib/libspl/include/sys/mnttab.h @@ -38,7 +38,7 @@ #undef MNTTAB #endif /* MNTTAB */ -#define MNTTAB "/etc/mtab" +#define MNTTAB "/proc/self/mounts" #define MNT_LINE_MAX 4096 #define MNT_TOOLONG 1 /* entry exceeds MNT_LINE_MAX */ diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 3ac31ad1d..84fe71734 100755 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -1908,9 +1908,9 @@ zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) * zfs_prop_get_int() are built using this interface. * * Certain properties can be overridden using 'mount -o'. In this case, scan - * the contents of the /etc/mtab entry, searching for the appropriate options. - * If they differ from the on-disk values, report the current values and mark - * the source "temporary". + * the contents of the /proc/self/mounts entry, searching for the + * appropriate options. If they differ from the on-disk values, report the + * current values and mark the source "temporary". */ static int get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, @@ -1981,8 +1981,9 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, /* * Because looking up the mount options is potentially expensive - * (iterating over all of /etc/mtab), we defer its calculation until - * we're looking up a property which requires its presence. + * (iterating over all of /proc/self/mounts), we defer its + * calculation until we're looking up a property which requires + * its presence. */ if (!zhp->zfs_mntcheck && (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { diff --git a/lib/libzfs/libzfs_mount.c b/lib/libzfs/libzfs_mount.c index 8c7f32638..44781679d 100644 --- a/lib/libzfs/libzfs_mount.c +++ b/lib/libzfs/libzfs_mount.c @@ -347,8 +347,8 @@ zfs_add_option(zfs_handle_t *zhp, char *options, int len, return (0); /* - * zfs_prop_get_int() to not used to ensure our mount options - * are not influenced by the current /etc/mtab contents. + * zfs_prop_get_int() is not used to ensure our mount options + * are not influenced by the current /proc/self/mounts contents. */ value = getprop_uint64(zhp, prop, &source); @@ -1184,8 +1184,8 @@ mountpoint_compare(const void *a, const void *b) * Unshare and unmount all datasets within the given pool. We don't want to * rely on traversing the DSL to discover the filesystems within the pool, * because this may be expensive (if not all of them are mounted), and can fail - * arbitrarily (on I/O error, for example). Instead, we walk /etc/mtab and - * gather all the filesystems that are currently mounted. + * arbitrarily (on I/O error, for example). Instead, we walk /proc/self/mounts + * and gather all the filesystems that are currently mounted. */ int zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index 3c388a3a0..4988e8115 100755 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -67,9 +67,9 @@ libzfs_error_init(int error) "loaded.\nTry running '/sbin/modprobe zfs' as root " "to load them.\n")); case ENOENT: - return (dgettext(TEXT_DOMAIN, "The /dev/zfs device is " - "missing and must be created.\nTry running 'udevadm " - "trigger' as root to create it.\n")); + return (dgettext(TEXT_DOMAIN, "/dev/zfs and /proc/self/mounts " + "are required.\nTry running 'udevadm trigger' and 'mount " + "-t proc proc /proc' as root.\n")); case ENOEXEC: return (dgettext(TEXT_DOMAIN, "The ZFS modules cannot be " "auto-loaded.\nTry running '/sbin/modprobe zfs' as " diff --git a/scripts/ziltest.sh b/scripts/ziltest.sh index 62cf09e88..bb816293f 100755 --- a/scripts/ziltest.sh +++ b/scripts/ziltest.sh @@ -185,7 +185,11 @@ CHECKSUM_BEFORE=$(sha256sum -b "$PAYLOAD") # # TX_WRITE (small file with ordering) # -cp /etc/mtab $ROOT/small_file +if is_linux; then + cp /proc/self/mounts $ROOT/small_file +else + cp /etc/mtab $ROOT/small_file +fi cp /etc/profile $ROOT/small_file # diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_003_neg.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_003_neg.ksh index d094d1a7d..63c735f31 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_003_neg.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_003_neg.ksh @@ -40,11 +40,16 @@ verify_runnable "global" -log_assert "zfs fails with unexpected scenarios." +log_assert "zfs fails with unexpected scenario." #verify zfs failed if ZFS_DEV cannot be opened ZFS_DEV=/dev/zfs +if is_linux; then + # On Linux, we use /proc/self/mounts, which cannot be moved. + MNTTAB= +fi + for file in $ZFS_DEV $MNTTAB; do if [[ -e $file ]]; then $MV $file ${file}.bak @@ -55,4 +60,4 @@ for file in $ZFS_DEV $MNTTAB; do $MV ${file}.bak $file done -log_pass "zfs fails with unexpected scenarios as expected." +log_pass "zfs fails with unexpected scenario as expected."