Skip to content

Commit

Permalink
Change /etc/mtab to /proc/self/mounts
Browse files Browse the repository at this point in the history
Misleading error message "The /dev/zfs device is missing and must be created.", if /etc/mtab is missing.

Signed-off-by: Eric Desrochers <eric.desrochers@canonical.com>
  • Loading branch information
Eric Desrochers authored and Eric Desrochers committed Aug 30, 2016
1 parent 9907cc1 commit 71e4989
Show file tree
Hide file tree
Showing 14 changed files with 37 additions and 105 deletions.
66 changes: 0 additions & 66 deletions cmd/mount_zfs/mount_zfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,66 +283,6 @@ parse_dataset(char *dataset)
return (dataset);
}

/*
* Update the mtab_* code to use the libmount library when it is commonly
* available otherwise fallback to legacy mode. The mount(8) utility will
* manage the lock file for us to prevent racing updates to /etc/mtab.
*/
static int
mtab_is_writeable(void)
{
struct stat st;
int error, fd;

error = lstat(MNTTAB, &st);
if (error || S_ISLNK(st.st_mode))
return (0);

fd = open(MNTTAB, O_RDWR | O_CREAT, 0644);
if (fd < 0)
return (0);

close(fd);
return (1);
}

static int
mtab_update(char *dataset, char *mntpoint, char *type, char *mntopts)
{
struct mntent mnt;
FILE *fp;
int error;

mnt.mnt_fsname = dataset;
mnt.mnt_dir = mntpoint;
mnt.mnt_type = type;
mnt.mnt_opts = mntopts ? mntopts : "";
mnt.mnt_freq = 0;
mnt.mnt_passno = 0;

fp = setmntent(MNTTAB, "a+");
if (!fp) {
(void) fprintf(stderr, gettext(
"filesystem '%s' was mounted, but %s "
"could not be opened due to error %d\n"),
dataset, MNTTAB, errno);
return (MOUNT_FILEIO);
}

error = addmntent(fp, &mnt);
if (error) {
(void) fprintf(stderr, gettext(
"filesystem '%s' was mounted, but %s "
"could not be updated due to error %d\n"),
dataset, MNTTAB, errno);
return (MOUNT_FILEIO);
}

(void) endmntent(fp);

return (MOUNT_SUCCESS);
}

static void
append_mntopt(const char *name, const char *val, char *mntopts,
char *mtabopt, boolean_t quote)
Expand Down Expand Up @@ -615,11 +555,5 @@ main(int argc, char **argv)
}
}

if (!nomtab && mtab_is_writeable()) {
error = mtab_update(dataset, mntpoint, MNTTYPE_ZFS, mtabopt);
if (error)
return (error);
}

return (MOUNT_SUCCESS);
}
23 changes: 12 additions & 11 deletions cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6116,9 +6116,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 */
Expand Down Expand Up @@ -6198,8 +6199,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)
Expand All @@ -6212,7 +6213,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.
Expand Down Expand Up @@ -6243,8 +6244,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));
Expand Down Expand Up @@ -6355,9 +6356,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
Expand Down
2 changes: 1 addition & 1 deletion cmd/zinject/translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 /proc/self/mounts\n");
return (-1);
}

Expand Down
2 changes: 1 addition & 1 deletion config/user-commands.m4
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,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)
])

Expand Down
7 changes: 3 additions & 4 deletions contrib/initramfs/scripts/zfs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion etc/init.d/zfs-functions.in
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ read_mtab()
# Set the variable.
eval export MTAB_$mntpnt=\"$fs\"
fi
done < /proc/mounts
done < /proc/self/mounts
}

in_mtab()
Expand Down
4 changes: 2 additions & 2 deletions etc/init.d/zfs-mount.in
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ chkroot() {
if [ "$2" = "/" ]; then
return 0
fi
done < /etc/mtab
done < /proc/self/mounts

return 1
}
Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion include/sys/mntent.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
#define MOUNT_SYSERR 0x02 /* System error (ENOMEM, etc) */
#define MOUNT_SOFTWARE 0x04 /* Internal mount bug */
#define MOUNT_USER 0x08 /* Interrupted by user (EINTR) */
#define MOUNT_FILEIO 0x10 /* Error updating/locking /etc/mtab */
#define MOUNT_FAIL 0x20 /* Mount failed */
#define MOUNT_SOMEOK 0x40 /* At least on mount succeeded */
#define MOUNT_BUSY 0x80 /* Mount failed due to EBUSY */
Expand Down
2 changes: 1 addition & 1 deletion lib/libspl/include/sys/mnttab.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
11 changes: 6 additions & 5 deletions lib/libzfs/libzfs_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -1911,9 +1911,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,
Expand Down Expand Up @@ -1984,8 +1984,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)) {
Expand Down
12 changes: 5 additions & 7 deletions lib/libzfs/libzfs_mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,9 @@ zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,

/*
* The filesystem is mounted by invoking the system mount utility rather
* than by the system call mount(2). This ensures that the /etc/mtab
* than by the system call mount(2). This ensures that the /proc/self/mounts
* file is correctly locked for the update. Performing our own locking
* and /etc/mtab update requires making an unsafe assumption about how
* and /proc/self/mounts update requires making an unsafe assumption about how
* the mount utility performs its locking. Unfortunately, this also means
* in the case of a mount failure we do not have the exact errno. We must
* make due with return value from the mount process.
Expand Down Expand Up @@ -289,8 +289,6 @@ do_mount(const char *src, const char *mntpt, char *opts)
/* Return only the most critical mount error */
rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE);
if (rc) {
if (rc & MOUNT_FILEIO)
return (EIO);
if (rc & MOUNT_USER)
return (EINTR);
if (rc & MOUNT_SOFTWARE)
Expand Down Expand Up @@ -348,7 +346,7 @@ zfs_add_option(zfs_handle_t *zhp, char *options, int len,

/*
* zfs_prop_get_int() to 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);

Expand Down Expand Up @@ -1182,8 +1180,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)
Expand Down
2 changes: 1 addition & 1 deletion scripts/zfs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fi

if [ ${UNLOAD} ]; then
kill_zed
umount -t zfs -a
umount -t zfs -a -n
stack_check
unload_modules
else
Expand Down
2 changes: 1 addition & 1 deletion scripts/ziltest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ CHECKSUM_BEFORE=$(sha256sum -b "$PAYLOAD")
#
# TX_WRITE (small file with ordering)
#
cp /etc/mtab $ROOT/small_file
cp /proc/self/mounts $ROOT/small_file
cp /etc/profile $ROOT/small_file

#
Expand Down
6 changes: 3 additions & 3 deletions tests/zfs-tests/tests/functional/cli_root/zfs/zfs_003_neg.ksh
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@

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

for file in $ZFS_DEV $MNTTAB; do
for file in $ZFS_DEV; do
if [[ -e $file ]]; then
$MV $file ${file}.bak
fi
Expand All @@ -55,4 +55,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."

0 comments on commit 71e4989

Please sign in to comment.