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 <rlaager@wiktel.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Eric Desrochers <eric.desrochers@canonical.com>
Closes #4680 
Closes #5029
This commit is contained in:
slashdd 2016-09-20 13:07:58 -04:00 committed by Brian Behlendorf
parent 25e2ab16be
commit 792517389f
13 changed files with 53 additions and 43 deletions

View File

@ -294,11 +294,11 @@ mtab_is_writeable(void)
struct stat st; struct stat st;
int error, fd; int error, fd;
error = lstat(MNTTAB, &st); error = lstat("/etc/mtab", &st);
if (error || S_ISLNK(st.st_mode)) if (error || S_ISLNK(st.st_mode))
return (0); return (0);
fd = open(MNTTAB, O_RDWR | O_CREAT, 0644); fd = open("/etc/mtab", O_RDWR | O_CREAT, 0644);
if (fd < 0) if (fd < 0)
return (0); return (0);
@ -320,21 +320,21 @@ mtab_update(char *dataset, char *mntpoint, char *type, char *mntopts)
mnt.mnt_freq = 0; mnt.mnt_freq = 0;
mnt.mnt_passno = 0; mnt.mnt_passno = 0;
fp = setmntent(MNTTAB, "a+"); fp = setmntent("/etc/mtab", "a+");
if (!fp) { if (!fp) {
(void) fprintf(stderr, gettext( (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"), "could not be opened due to error %d\n"),
dataset, MNTTAB, errno); dataset, errno);
return (MOUNT_FILEIO); return (MOUNT_FILEIO);
} }
error = addmntent(fp, &mnt); error = addmntent(fp, &mnt);
if (error) { if (error) {
(void) fprintf(stderr, gettext( (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"), "could not be updated due to error %d\n"),
dataset, MNTTAB, errno); dataset, errno);
return (MOUNT_FILEIO); return (MOUNT_FILEIO);
} }

View File

@ -6146,9 +6146,10 @@ share_mount(int op, int argc, char **argv)
} }
/* /*
* When mount is given no arguments, go through /etc/mtab and * When mount is given no arguments, go through
* display any active ZFS mounts. We hide any snapshots, since * /proc/self/mounts and display any active ZFS mounts.
* they are controlled automatically. * We hide any snapshots, since they are controlled
* automatically.
*/ */
/* Reopen MNTTAB to prevent reading stale data from open file */ /* 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 * 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, * absolute path, find the entry /proc/self/mounts, verify that its a
* and unmount it appropriately. * ZFS filesystems, and unmount it appropriately.
*/ */
static int static int
unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) 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; 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. ".." * specific path, which can be fooled by non-standard paths (i.e. ".."
* or "//"), we stat() the path and search for the corresponding * or "//"), we stat() the path and search for the corresponding
* (major,minor) device pair. * (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); "currently mounted\n"), cmdname, path);
return (1); return (1);
} }
(void) fprintf(stderr, gettext("warning: %s not in mtab\n"), (void) fprintf(stderr, gettext("warning: %s not in"
path); "/proc/self/mounts\n"), path);
if ((ret = umount2(path, flags)) != 0) if ((ret = umount2(path, flags)) != 0)
(void) fprintf(stderr, gettext("%s: %s\n"), path, (void) fprintf(stderr, gettext("%s: %s\n"), path,
strerror(errno)); 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 * We could make use of zfs_for_each() to walk all datasets in
* the system, but this would be very inefficient, especially * the system, but this would be very inefficient, especially
* since we would have to linearly search /etc/mtab for each * since we would have to linearly search /proc/self/mounts for
* one. Instead, do one pass through /etc/mtab looking for * each one. Instead, do one pass through /proc/self/mounts
* zfs entries and call zfs_unmount() for each one. * looking for zfs entries and call zfs_unmount() for each one.
* *
* Things get a little tricky if the administrator has created * Things get a little tricky if the administrator has created
* mountpoints beneath other ZFS filesystems. In this case, we * mountpoints beneath other ZFS filesystems. In this case, we

View File

@ -120,7 +120,7 @@ parse_pathname(const char *inpath, char *dataset, char *relpath,
#else #else
if ((fp = fopen(MNTTAB, "r")) == NULL) { if ((fp = fopen(MNTTAB, "r")) == NULL) {
#endif #endif
(void) fprintf(stderr, "cannot open /etc/mtab\n"); (void) fprintf(stderr, "cannot open %s\n", MNTTAB);
return (-1); return (-1);
} }

View File

@ -127,7 +127,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_LINUX], [
PAGESIZE=$($GETCONF PAGESIZE) PAGESIZE=$($GETCONF PAGESIZE)
AC_SUBST(PAGESIZE) AC_SUBST(PAGESIZE)
MNTTAB=/etc/mtab MNTTAB=/proc/self/mounts
AC_SUBST(MNTTAB) AC_SUBST(MNTTAB)
]) ])

View File

@ -288,9 +288,8 @@ load_module_initrd()
wait_for_dev wait_for_dev
fi fi
# zpool import refuse to import without a valid mtab # zpool import refuse to import without a valid /proc/self/mounts
[ ! -f /proc/mounts ] && mount proc /proc [ ! -f /proc/self/mounts ] && mount proc /proc
[ ! -f /etc/mtab ] && cat /proc/mounts > /etc/mtab
# Load the module # Load the module
load_module "zfs" || return 1 load_module "zfs" || return 1
@ -919,7 +918,7 @@ mountroot()
# #
# but the MOUNTPOINT prefix is preserved on descendent filesystem # but the MOUNTPOINT prefix is preserved on descendent filesystem
# after the pivot into the regular root, which later breaks things # 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 # * Mount additional filesystems required
# Such as /usr, /var, /usr/local etc. # Such as /usr, /var, /usr/local etc.

View File

@ -368,7 +368,7 @@ read_mtab()
# Set the variable. # Set the variable.
eval export MTAB_$mntpnt=\"$fs\" eval export MTAB_$mntpnt=\"$fs\"
fi fi
done < /proc/mounts done < /proc/self/mounts
} }
in_mtab() in_mtab()

View File

@ -39,7 +39,7 @@ chkroot() {
if [ "$2" = "/" ]; then if [ "$2" = "/" ]; then
return 0 return 0
fi fi
done < /etc/mtab done < /proc/self/mounts
return 1 return 1
} }
@ -178,7 +178,7 @@ do_start()
check_module_loaded "zfs" || exit 0 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. # This should be handled by rc.sysinit but lets be paranoid.
if ! chkroot if ! chkroot
then then

View File

@ -38,7 +38,7 @@
#undef MNTTAB #undef MNTTAB
#endif /* MNTTAB */ #endif /* MNTTAB */
#define MNTTAB "/etc/mtab" #define MNTTAB "/proc/self/mounts"
#define MNT_LINE_MAX 4096 #define MNT_LINE_MAX 4096
#define MNT_TOOLONG 1 /* entry exceeds MNT_LINE_MAX */ #define MNT_TOOLONG 1 /* entry exceeds MNT_LINE_MAX */

View File

@ -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. * zfs_prop_get_int() are built using this interface.
* *
* Certain properties can be overridden using 'mount -o'. In this case, scan * Certain properties can be overridden using 'mount -o'. In this case, scan
* the contents of the /etc/mtab entry, searching for the appropriate options. * the contents of the /proc/self/mounts entry, searching for the
* If they differ from the on-disk values, report the current values and mark * appropriate options. If they differ from the on-disk values, report the
* the source "temporary". * current values and mark the source "temporary".
*/ */
static int static int
get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, 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 * Because looking up the mount options is potentially expensive
* (iterating over all of /etc/mtab), we defer its calculation until * (iterating over all of /proc/self/mounts), we defer its
* we're looking up a property which requires its presence. * calculation until we're looking up a property which requires
* its presence.
*/ */
if (!zhp->zfs_mntcheck && if (!zhp->zfs_mntcheck &&
(mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) { (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {

View File

@ -347,8 +347,8 @@ zfs_add_option(zfs_handle_t *zhp, char *options, int len,
return (0); return (0);
/* /*
* zfs_prop_get_int() to not used to ensure our mount options * zfs_prop_get_int() is not used to ensure our mount options
* are not influenced by the current /etc/mtab contents. * are not influenced by the current /proc/self/mounts contents.
*/ */
value = getprop_uint64(zhp, prop, &source); 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 * 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, * 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 * 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 * arbitrarily (on I/O error, for example). Instead, we walk /proc/self/mounts
* gather all the filesystems that are currently mounted. * and gather all the filesystems that are currently mounted.
*/ */
int int
zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)

View File

@ -67,9 +67,9 @@ libzfs_error_init(int error)
"loaded.\nTry running '/sbin/modprobe zfs' as root " "loaded.\nTry running '/sbin/modprobe zfs' as root "
"to load them.\n")); "to load them.\n"));
case ENOENT: case ENOENT:
return (dgettext(TEXT_DOMAIN, "The /dev/zfs device is " return (dgettext(TEXT_DOMAIN, "/dev/zfs and /proc/self/mounts "
"missing and must be created.\nTry running 'udevadm " "are required.\nTry running 'udevadm trigger' and 'mount "
"trigger' as root to create it.\n")); "-t proc proc /proc' as root.\n"));
case ENOEXEC: case ENOEXEC:
return (dgettext(TEXT_DOMAIN, "The ZFS modules cannot be " return (dgettext(TEXT_DOMAIN, "The ZFS modules cannot be "
"auto-loaded.\nTry running '/sbin/modprobe zfs' as " "auto-loaded.\nTry running '/sbin/modprobe zfs' as "

View File

@ -185,7 +185,11 @@ CHECKSUM_BEFORE=$(sha256sum -b "$PAYLOAD")
# #
# TX_WRITE (small file with ordering) # 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 cp /etc/profile $ROOT/small_file
# #

View File

@ -40,11 +40,16 @@
verify_runnable "global" 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 #verify zfs failed if ZFS_DEV cannot be opened
ZFS_DEV=/dev/zfs 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 for file in $ZFS_DEV $MNTTAB; do
if [[ -e $file ]]; then if [[ -e $file ]]; then
$MV $file ${file}.bak $MV $file ${file}.bak
@ -55,4 +60,4 @@ for file in $ZFS_DEV $MNTTAB; do
$MV ${file}.bak $file $MV ${file}.bak $file
done done
log_pass "zfs fails with unexpected scenarios as expected." log_pass "zfs fails with unexpected scenario as expected."