diff options
author | felixdoerre <[email protected]> | 2020-05-21 04:02:41 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2020-05-20 18:02:41 -0700 |
commit | 501a1511aeaaf8f7b50410ef7e64e06647aa8dfb (patch) | |
tree | 605dbad078ed66f976f1799831093bc08a67cd9c | |
parent | 57434abae6af23cf0b0b360882762dfae7fee555 (diff) |
mount: use the mount syscall directly
Allow zfs datasets to be mounted on Linux without relying on the
invocation of an external processes. This is the same behavior
which is implemented for FreeBSD.
Use of the libmount library was originally considered because it
provides functionality to properly lock and update the /etc/mtab
file. However, these days /etc/mtab is typically a symlink to
/proc/self/mounts so there's nothing to updated. Therefore, we
call mount(2) directly and avoid any additional dependencies.
If required the legacy behavior can be enabled by setting the
ZFS_MOUNT_HELPER environment variable. This may be needed in
environments where SELinux in enabled and the zfs binary does
not have mount permission.
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Felix Dörre <[email protected]>
#10294
-rw-r--r-- | cmd/mount_zfs/mount_zfs.c | 236 | ||||
-rw-r--r-- | cmd/zfs/zfs_main.c | 3 | ||||
-rw-r--r-- | include/libzfs.h | 7 | ||||
-rw-r--r-- | include/libzfs_impl.h | 3 | ||||
-rw-r--r-- | lib/libzfs/libzfs_mount.c | 2 | ||||
-rw-r--r-- | lib/libzfs/os/freebsd/libzfs_zmount.c | 7 | ||||
-rw-r--r-- | lib/libzfs/os/linux/libzfs_mount_os.c | 343 | ||||
-rw-r--r-- | man/man8/zfs.8 | 9 | ||||
-rw-r--r-- | tests/zfs-tests/tests/functional/rsend/rsend.kshlib | 2 |
9 files changed, 335 insertions, 277 deletions
diff --git a/cmd/mount_zfs/mount_zfs.c b/cmd/mount_zfs/mount_zfs.c index a37dd6f53..87d2ccadc 100644 --- a/cmd/mount_zfs/mount_zfs.c +++ b/cmd/mount_zfs/mount_zfs.c @@ -42,185 +42,6 @@ libzfs_handle_t *g_zfs; -typedef struct option_map { - const char *name; - unsigned long mntmask; - unsigned long zfsmask; -} option_map_t; - -static const option_map_t option_map[] = { - /* Canonicalized filesystem independent options from mount(8) */ - { MNTOPT_NOAUTO, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_DEFAULTS, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_NODEVICES, MS_NODEV, ZS_COMMENT }, - { MNTOPT_DIRSYNC, MS_DIRSYNC, ZS_COMMENT }, - { MNTOPT_NOEXEC, MS_NOEXEC, ZS_COMMENT }, - { MNTOPT_GROUP, MS_GROUP, ZS_COMMENT }, - { MNTOPT_NETDEV, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_NOFAIL, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_NOSUID, MS_NOSUID, ZS_COMMENT }, - { MNTOPT_OWNER, MS_OWNER, ZS_COMMENT }, - { MNTOPT_REMOUNT, MS_REMOUNT, ZS_COMMENT }, - { MNTOPT_RO, MS_RDONLY, ZS_COMMENT }, - { MNTOPT_RW, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_SYNC, MS_SYNCHRONOUS, ZS_COMMENT }, - { MNTOPT_USER, MS_USERS, ZS_COMMENT }, - { MNTOPT_USERS, MS_USERS, ZS_COMMENT }, - /* acl flags passed with util-linux-2.24 mount command */ - { MNTOPT_ACL, MS_POSIXACL, ZS_COMMENT }, - { MNTOPT_NOACL, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_POSIXACL, MS_POSIXACL, ZS_COMMENT }, -#ifdef MS_NOATIME - { MNTOPT_NOATIME, MS_NOATIME, ZS_COMMENT }, -#endif -#ifdef MS_NODIRATIME - { MNTOPT_NODIRATIME, MS_NODIRATIME, ZS_COMMENT }, -#endif -#ifdef MS_RELATIME - { MNTOPT_RELATIME, MS_RELATIME, ZS_COMMENT }, -#endif -#ifdef MS_STRICTATIME - { MNTOPT_STRICTATIME, MS_STRICTATIME, ZS_COMMENT }, -#endif -#ifdef MS_LAZYTIME - { MNTOPT_LAZYTIME, MS_LAZYTIME, ZS_COMMENT }, -#endif - { MNTOPT_CONTEXT, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_FSCONTEXT, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_DEFCONTEXT, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_ROOTCONTEXT, MS_COMMENT, ZS_COMMENT }, -#ifdef MS_I_VERSION - { MNTOPT_IVERSION, MS_I_VERSION, ZS_COMMENT }, -#endif -#ifdef MS_MANDLOCK - { MNTOPT_NBMAND, MS_MANDLOCK, ZS_COMMENT }, -#endif - /* Valid options not found in mount(8) */ - { MNTOPT_BIND, MS_BIND, ZS_COMMENT }, -#ifdef MS_REC - { MNTOPT_RBIND, MS_BIND|MS_REC, ZS_COMMENT }, -#endif - { MNTOPT_COMMENT, MS_COMMENT, ZS_COMMENT }, -#ifdef MS_NOSUB - { MNTOPT_NOSUB, MS_NOSUB, ZS_COMMENT }, -#endif -#ifdef MS_SILENT - { MNTOPT_QUIET, MS_SILENT, ZS_COMMENT }, -#endif - /* Custom zfs options */ - { MNTOPT_XATTR, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_NOXATTR, MS_COMMENT, ZS_COMMENT }, - { MNTOPT_ZFSUTIL, MS_COMMENT, ZS_ZFSUTIL }, - { NULL, 0, 0 } }; - -/* - * Break the mount option in to a name/value pair. The name is - * validated against the option map and mount flags set accordingly. - */ -static int -parse_option(char *mntopt, unsigned long *mntflags, - unsigned long *zfsflags, int sloppy) -{ - const option_map_t *opt; - char *ptr, *name, *value = NULL; - int error = 0; - - name = strdup(mntopt); - if (name == NULL) - return (ENOMEM); - - for (ptr = name; ptr && *ptr; ptr++) { - if (*ptr == '=') { - *ptr = '\0'; - value = ptr+1; - VERIFY3P(value, !=, NULL); - break; - } - } - - for (opt = option_map; opt->name != NULL; opt++) { - if (strncmp(name, opt->name, strlen(name)) == 0) { - *mntflags |= opt->mntmask; - *zfsflags |= opt->zfsmask; - error = 0; - goto out; - } - } - - if (!sloppy) - error = ENOENT; -out: - /* If required further process on the value may be done here */ - free(name); - return (error); -} - -/* - * Translate the mount option string in to MS_* mount flags for the - * kernel vfs. When sloppy is non-zero unknown options will be ignored - * otherwise they are considered fatal are copied in to badopt. - */ -static int -parse_options(char *mntopts, unsigned long *mntflags, unsigned long *zfsflags, - int sloppy, char *badopt, char *mtabopt) -{ - int error = 0, quote = 0, flag = 0, count = 0; - char *ptr, *opt, *opts; - - opts = strdup(mntopts); - if (opts == NULL) - return (ENOMEM); - - *mntflags = 0; - opt = NULL; - - /* - * Scan through all mount options which must be comma delimited. - * We must be careful to notice regions which are double quoted - * and skip commas in these regions. Each option is then checked - * to determine if it is a known option. - */ - for (ptr = opts; ptr && !flag; ptr++) { - if (opt == NULL) - opt = ptr; - - if (*ptr == '"') - quote = !quote; - - if (quote) - continue; - - if (*ptr == '\0') - flag = 1; - - if ((*ptr == ',') || (*ptr == '\0')) { - *ptr = '\0'; - - error = parse_option(opt, mntflags, zfsflags, sloppy); - if (error) { - strcpy(badopt, opt); - goto out; - - } - - if (!(*mntflags & MS_REMOUNT) && - !(*zfsflags & ZS_ZFSUTIL)) { - if (count > 0) - strlcat(mtabopt, ",", MNT_LINE_MAX); - - strlcat(mtabopt, opt, MNT_LINE_MAX); - count++; - } - - opt = NULL; - } - } - -out: - free(opts); - return (error); -} - /* * Return the pool/dataset to mount given the name passed to mount. This * is expected to be of the form pool/dataset, however may also refer to @@ -345,34 +166,6 @@ mtab_update(char *dataset, char *mntpoint, char *type, char *mntopts) return (MOUNT_SUCCESS); } -static void -append_mntopt(const char *name, const char *val, char *mntopts, - char *mtabopt, boolean_t quote) -{ - char tmp[MNT_LINE_MAX]; - - snprintf(tmp, MNT_LINE_MAX, quote ? ",%s=\"%s\"" : ",%s=%s", name, val); - - if (mntopts) - strlcat(mntopts, tmp, MNT_LINE_MAX); - - if (mtabopt) - strlcat(mtabopt, tmp, MNT_LINE_MAX); -} - -static void -zfs_selinux_setcontext(zfs_handle_t *zhp, zfs_prop_t zpt, const char *name, - char *mntopts, char *mtabopt) -{ - char context[ZFS_MAXPROPLEN]; - - if (zfs_prop_get(zhp, zpt, context, sizeof (context), - NULL, NULL, 0, B_FALSE) == 0) { - if (strcmp(context, "none") != 0) - append_mntopt(name, context, mntopts, mtabopt, B_TRUE); - } -} - int main(int argc, char **argv) { @@ -449,7 +242,7 @@ main(int argc, char **argv) } /* validate mount options and set mntflags */ - error = parse_options(mntopts, &mntflags, &zfsflags, sloppy, + error = zfs_parse_mount_options(mntopts, &mntflags, &zfsflags, sloppy, badopt, mtabopt); if (error) { switch (error) { @@ -502,32 +295,7 @@ main(int argc, char **argv) return (MOUNT_USAGE); } - /* - * Checks to see if the ZFS_PROP_SELINUX_CONTEXT exists - * if it does, create a tmp variable in case it's needed - * checks to see if the selinux context is set to the default - * if it is, allow the setting of the other context properties - * this is needed because the 'context' property overrides others - * if it is not the default, set the 'context' property - */ - if (zfs_prop_get(zhp, ZFS_PROP_SELINUX_CONTEXT, prop, sizeof (prop), - NULL, NULL, 0, B_FALSE) == 0) { - if (strcmp(prop, "none") == 0) { - zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_FSCONTEXT, - MNTOPT_FSCONTEXT, mntopts, mtabopt); - zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_DEFCONTEXT, - MNTOPT_DEFCONTEXT, mntopts, mtabopt); - zfs_selinux_setcontext(zhp, - ZFS_PROP_SELINUX_ROOTCONTEXT, MNTOPT_ROOTCONTEXT, - mntopts, mtabopt); - } else { - append_mntopt(MNTOPT_CONTEXT, prop, - mntopts, mtabopt, B_TRUE); - } - } - - /* A hint used to determine an auto-mounted snapshot mount point */ - append_mntopt(MNTOPT_MNTPOINT, mntpoint, mntopts, NULL, B_FALSE); + zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt); /* treat all snapshots as legacy mount points */ if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 27f34b9fd..c0ca8e8c2 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -7319,9 +7319,6 @@ unshare_unmount(int op, int argc, char **argv) const char *mntarg = NULL; uu_avl_remove(tree, node); -#ifndef __FreeBSD__ - mntarg = node->un_zhp->zfs_name; -#endif switch (op) { case OP_SHARE: if (zfs_unshareall_bytype(node->un_zhp, diff --git a/include/libzfs.h b/include/libzfs.h index 551b6ae74..d9f0d7259 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -803,6 +803,13 @@ extern int zfs_mount_at(zfs_handle_t *, const char *, int, const char *); extern int zfs_unmount(zfs_handle_t *, const char *, int); extern int zfs_unmountall(zfs_handle_t *, int); +#if defined(__linux__) +extern int zfs_parse_mount_options(char *mntopts, unsigned long *mntflags, + unsigned long *zfsflags, int sloppy, char *badopt, char *mtabopt); +extern void zfs_adjust_mount_options(zfs_handle_t *zhp, const char *mntpoint, + char *mntopts, char *mtabopt); +#endif + /* * Share support functions. */ diff --git a/include/libzfs_impl.h b/include/libzfs_impl.h index be11b1fc0..91fa1efbb 100644 --- a/include/libzfs_impl.h +++ b/include/libzfs_impl.h @@ -246,7 +246,8 @@ typedef struct differ_info { extern proto_table_t proto_table[PROTO_END]; -extern int do_mount(const char *src, const char *mntpt, char *opts, int flags); +extern int do_mount(zfs_handle_t *zhp, const char *mntpt, char *opts, + int flags); extern int do_unmount(const char *mntpt, int flags); extern int zfs_mount_delegation_check(void); extern int zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto); diff --git a/lib/libzfs/libzfs_mount.c b/lib/libzfs/libzfs_mount.c index 4d4b49753..4123968b0 100644 --- a/lib/libzfs/libzfs_mount.c +++ b/lib/libzfs/libzfs_mount.c @@ -500,7 +500,7 @@ zfs_mount_at(zfs_handle_t *zhp, const char *options, int flags, } /* perform the mount */ - rc = do_mount(zfs_get_name(zhp), mountpoint, mntopts, flags); + rc = do_mount(zhp, mountpoint, mntopts, flags); if (rc) { /* * Generic errors are nasty, but there are just way too many diff --git a/lib/libzfs/os/freebsd/libzfs_zmount.c b/lib/libzfs/os/freebsd/libzfs_zmount.c index 8ff24f446..c0951c314 100644 --- a/lib/libzfs/os/freebsd/libzfs_zmount.c +++ b/lib/libzfs/os/freebsd/libzfs_zmount.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include <sys/mnttab.h> #include <sys/errno.h> +#include <libzfs.h> static void build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val, @@ -115,11 +116,11 @@ do_mount_(const char *spec, const char *dir, int mflag, char *fstype, } int -do_mount(const char *src, const char *mntpt, char *opts, int flags) +do_mount(zfs_handle_t *zhp, const char *mntpt, char *opts, int flags) { - return (do_mount_(src, mntpt, flags, MNTTYPE_ZFS, NULL, 0, opts, - sizeof (mntpt))); + return (do_mount_(zfs_get_name(zhp), mntpt, flags, MNTTYPE_ZFS, NULL, 0, + opts, sizeof (mntpt))); } int diff --git a/lib/libzfs/os/linux/libzfs_mount_os.c b/lib/libzfs/os/linux/libzfs_mount_os.c index c04eb2161..04252e421 100644 --- a/lib/libzfs/os/linux/libzfs_mount_os.c +++ b/lib/libzfs/os/linux/libzfs_mount_os.c @@ -282,7 +282,268 @@ is_shared_impl(libzfs_handle_t *hdl, const char *mountpoint, return (SHARED_NOT_SHARED); } + +#define ZS_COMMENT 0x00000000 /* comment */ +#define ZS_ZFSUTIL 0x00000001 /* caller is zfs(8) */ + +typedef struct option_map { + const char *name; + unsigned long mntmask; + unsigned long zfsmask; +} option_map_t; + +static const option_map_t option_map[] = { + /* Canonicalized filesystem independent options from mount(8) */ + { MNTOPT_NOAUTO, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_DEFAULTS, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_NODEVICES, MS_NODEV, ZS_COMMENT }, + { MNTOPT_DEVICES, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_DIRSYNC, MS_DIRSYNC, ZS_COMMENT }, + { MNTOPT_NOEXEC, MS_NOEXEC, ZS_COMMENT }, + { MNTOPT_EXEC, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_GROUP, MS_GROUP, ZS_COMMENT }, + { MNTOPT_NETDEV, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_NOFAIL, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_NOSUID, MS_NOSUID, ZS_COMMENT }, + { MNTOPT_SUID, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_OWNER, MS_OWNER, ZS_COMMENT }, + { MNTOPT_REMOUNT, MS_REMOUNT, ZS_COMMENT }, + { MNTOPT_RO, MS_RDONLY, ZS_COMMENT }, + { MNTOPT_RW, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_SYNC, MS_SYNCHRONOUS, ZS_COMMENT }, + { MNTOPT_USER, MS_USERS, ZS_COMMENT }, + { MNTOPT_USERS, MS_USERS, ZS_COMMENT }, + /* acl flags passed with util-linux-2.24 mount command */ + { MNTOPT_ACL, MS_POSIXACL, ZS_COMMENT }, + { MNTOPT_NOACL, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_POSIXACL, MS_POSIXACL, ZS_COMMENT }, +#ifdef MS_NOATIME + { MNTOPT_NOATIME, MS_NOATIME, ZS_COMMENT }, + { MNTOPT_ATIME, MS_COMMENT, ZS_COMMENT }, +#endif +#ifdef MS_NODIRATIME + { MNTOPT_NODIRATIME, MS_NODIRATIME, ZS_COMMENT }, + { MNTOPT_DIRATIME, MS_COMMENT, ZS_COMMENT }, +#endif +#ifdef MS_RELATIME + { MNTOPT_RELATIME, MS_RELATIME, ZS_COMMENT }, + { MNTOPT_NORELATIME, MS_COMMENT, ZS_COMMENT }, +#endif +#ifdef MS_STRICTATIME + { MNTOPT_STRICTATIME, MS_STRICTATIME, ZS_COMMENT }, + { MNTOPT_NOSTRICTATIME, MS_COMMENT, ZS_COMMENT }, +#endif +#ifdef MS_LAZYTIME + { MNTOPT_LAZYTIME, MS_LAZYTIME, ZS_COMMENT }, +#endif + { MNTOPT_CONTEXT, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_FSCONTEXT, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_DEFCONTEXT, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_ROOTCONTEXT, MS_COMMENT, ZS_COMMENT }, +#ifdef MS_I_VERSION + { MNTOPT_IVERSION, MS_I_VERSION, ZS_COMMENT }, +#endif +#ifdef MS_MANDLOCK + { MNTOPT_NBMAND, MS_MANDLOCK, ZS_COMMENT }, + { MNTOPT_NONBMAND, MS_COMMENT, ZS_COMMENT }, +#endif + /* Valid options not found in mount(8) */ + { MNTOPT_BIND, MS_BIND, ZS_COMMENT }, +#ifdef MS_REC + { MNTOPT_RBIND, MS_BIND|MS_REC, ZS_COMMENT }, +#endif + { MNTOPT_COMMENT, MS_COMMENT, ZS_COMMENT }, +#ifdef MS_NOSUB + { MNTOPT_NOSUB, MS_NOSUB, ZS_COMMENT }, +#endif +#ifdef MS_SILENT + { MNTOPT_QUIET, MS_SILENT, ZS_COMMENT }, +#endif + /* Custom zfs options */ + { MNTOPT_XATTR, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_NOXATTR, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_ZFSUTIL, MS_COMMENT, ZS_ZFSUTIL }, + { NULL, 0, 0 } }; + /* + * Break the mount option in to a name/value pair. The name is + * validated against the option map and mount flags set accordingly. + */ +static int +parse_option(char *mntopt, unsigned long *mntflags, + unsigned long *zfsflags, int sloppy) +{ + const option_map_t *opt; + char *ptr, *name, *value = NULL; + int error = 0; + + name = strdup(mntopt); + if (name == NULL) + return (ENOMEM); + + for (ptr = name; ptr && *ptr; ptr++) { + if (*ptr == '=') { + *ptr = '\0'; + value = ptr+1; + VERIFY3P(value, !=, NULL); + break; + } + } + + for (opt = option_map; opt->name != NULL; opt++) { + if (strncmp(name, opt->name, strlen(name)) == 0) { + *mntflags |= opt->mntmask; + *zfsflags |= opt->zfsmask; + error = 0; + goto out; + } + } + + if (!sloppy) + error = ENOENT; +out: + /* If required further process on the value may be done here */ + free(name); + return (error); +} + +/* + * Translate the mount option string in to MS_* mount flags for the + * kernel vfs. When sloppy is non-zero unknown options will be ignored + * otherwise they are considered fatal are copied in to badopt. + */ +int +zfs_parse_mount_options(char *mntopts, unsigned long *mntflags, + unsigned long *zfsflags, int sloppy, char *badopt, char *mtabopt) +{ + int error = 0, quote = 0, flag = 0, count = 0; + char *ptr, *opt, *opts; + + opts = strdup(mntopts); + if (opts == NULL) + return (ENOMEM); + + *mntflags = 0; + opt = NULL; + + /* + * Scan through all mount options which must be comma delimited. + * We must be careful to notice regions which are double quoted + * and skip commas in these regions. Each option is then checked + * to determine if it is a known option. + */ + for (ptr = opts; ptr && !flag; ptr++) { + if (opt == NULL) + opt = ptr; + + if (*ptr == '"') + quote = !quote; + + if (quote) + continue; + + if (*ptr == '\0') + flag = 1; + + if ((*ptr == ',') || (*ptr == '\0')) { + *ptr = '\0'; + + error = parse_option(opt, mntflags, zfsflags, sloppy); + if (error) { + strcpy(badopt, opt); + goto out; + + } + + if (!(*mntflags & MS_REMOUNT) && + !(*zfsflags & ZS_ZFSUTIL) && + mtabopt != NULL) { + if (count > 0) + strlcat(mtabopt, ",", MNT_LINE_MAX); + + strlcat(mtabopt, opt, MNT_LINE_MAX); + count++; + } + + opt = NULL; + } + } + +out: + free(opts); + return (error); +} + +static void +append_mntopt(const char *name, const char *val, char *mntopts, + char *mtabopt, boolean_t quote) +{ + char tmp[MNT_LINE_MAX]; + + snprintf(tmp, MNT_LINE_MAX, quote ? ",%s=\"%s\"" : ",%s=%s", name, val); + + if (mntopts) + strlcat(mntopts, tmp, MNT_LINE_MAX); + + if (mtabopt) + strlcat(mtabopt, tmp, MNT_LINE_MAX); +} + +static void +zfs_selinux_setcontext(zfs_handle_t *zhp, zfs_prop_t zpt, const char *name, + char *mntopts, char *mtabopt) +{ + char context[ZFS_MAXPROPLEN]; + + if (zfs_prop_get(zhp, zpt, context, sizeof (context), + NULL, NULL, 0, B_FALSE) == 0) { + if (strcmp(context, "none") != 0) + append_mntopt(name, context, mntopts, mtabopt, B_TRUE); + } +} + +void +zfs_adjust_mount_options(zfs_handle_t *zhp, const char *mntpoint, + char *mntopts, char *mtabopt) +{ + char prop[ZFS_MAXPROPLEN]; + + /* + * Checks to see if the ZFS_PROP_SELINUX_CONTEXT exists + * if it does, create a tmp variable in case it's needed + * checks to see if the selinux context is set to the default + * if it is, allow the setting of the other context properties + * this is needed because the 'context' property overrides others + * if it is not the default, set the 'context' property + */ + if (zfs_prop_get(zhp, ZFS_PROP_SELINUX_CONTEXT, prop, sizeof (prop), + NULL, NULL, 0, B_FALSE) == 0) { + if (strcmp(prop, "none") == 0) { + zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_FSCONTEXT, + MNTOPT_FSCONTEXT, mntopts, mtabopt); + zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_DEFCONTEXT, + MNTOPT_DEFCONTEXT, mntopts, mtabopt); + zfs_selinux_setcontext(zhp, + ZFS_PROP_SELINUX_ROOTCONTEXT, MNTOPT_ROOTCONTEXT, + mntopts, mtabopt); + } else { + append_mntopt(MNTOPT_CONTEXT, prop, + mntopts, mtabopt, B_TRUE); + } + } + + /* A hint used to determine an auto-mounted snapshot mount point */ + append_mntopt(MNTOPT_MNTPOINT, mntpoint, mntopts, NULL, B_FALSE); +} + +/* + * By default the filesystem by preparing the mount options (i.e. parsing + * some flags from the "opts" parameter into the "flags" parameter) and then + * directly calling the system call mount(2). We don't need the mount utility + * or update /etc/mtab, because this is a symlink on all modern systems. + * + * If the environment variable ZFS_MOUNT_HELPER is set, we fall back to the + * previous behavior: * The filesystem is mounted by invoking the system mount utility rather * than by the system call mount(2). This ensures that the /etc/mtab * file is correctly locked for the update. Performing our own locking @@ -290,52 +551,66 @@ is_shared_impl(libzfs_handle_t *hdl, const char *mountpoint, * 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. - * - * In the long term a shared library called libmount is under development - * which provides a common API to address the locking and errno issues. - * Once the standard mount utility has been updated to use this library - * we can add an autoconf check to conditionally use it. - * - * http://www.kernel.org/pub/linux/utils/util-linux/libmount-docs/index.html */ int -do_mount(const char *src, const char *mntpt, char *opts, int flags) +do_mount(zfs_handle_t *zhp, const char *mntpt, char *opts, int flags) { - char *argv[9] = { - "/bin/mount", - "--no-canonicalize", - "-t", MNTTYPE_ZFS, - "-o", opts, - (char *)src, - (char *)mntpt, - (char *)NULL }; - int rc; + const char *src = zfs_get_name(zhp); + int error = 0; - /* 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) - return (EPIPE); - if (rc & MOUNT_BUSY) - return (EBUSY); - if (rc & MOUNT_SYSERR) - return (EAGAIN); - if (rc & MOUNT_USAGE) - return (EINVAL); + if (!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) { + char badopt[MNT_LINE_MAX] = {0}; + unsigned long mntflags = flags, zfsflags; + char myopts[MNT_LINE_MAX] = {0}; - return (ENXIO); /* Generic error */ + if (zfs_parse_mount_options(opts, &mntflags, + &zfsflags, 0, badopt, NULL)) { + return (EINVAL); + } + strlcat(myopts, opts, MNT_LINE_MAX); + zfs_adjust_mount_options(zhp, mntpt, myopts, NULL); + error = mount(src, mntpt, MNTTYPE_ZFS, mntflags, myopts); + } else { + char *argv[9] = { + "/bin/mount", + "--no-canonicalize", + "-t", MNTTYPE_ZFS, + "-o", opts, + (char *)src, + (char *)mntpt, + (char *)NULL }; + + /* Return only the most critical mount error */ + error = libzfs_run_process(argv[0], argv, + STDOUT_VERBOSE|STDERR_VERBOSE); + if (error) { + if (error & MOUNT_FILEIO) { + error = EIO; + } else if (error & MOUNT_USER) { + error = EINTR; + } else if (error & MOUNT_SOFTWARE) { + error = EPIPE; + } else if (error & MOUNT_BUSY) { + error = EBUSY; + } else if (error & MOUNT_SYSERR) { + error = EAGAIN; + } else if (error & MOUNT_USAGE) { + error = EINVAL; + } else + error = ENXIO; /* Generic error */ + } } - return (0); + return (error); } int do_unmount(const char *mntpt, int flags) { + if (!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) { + return (umount2(mntpt, flags)); + } + char force_opt[] = "-f"; char lazy_opt[] = "-l"; char *argv[7] = { diff --git a/man/man8/zfs.8 b/man/man8/zfs.8 index eeefcda3c..47cf45a99 100644 --- a/man/man8/zfs.8 +++ b/man/man8/zfs.8 @@ -710,6 +710,15 @@ Do note that any changes done with the .Xr net 8 command will be undone if the share is ever unshared (such as at a reboot etc). .El +.Sh ENVIRONMENT VARIABLES +.Bl -tag -width "ZFS_MOUNT_HELPER" +.It Ev ZFS_MOUNT_HELPER +Cause +.Nm zfs mount +to use +.Em /bin/mount +to mount zfs datasets. This option is provided for backwards compatibility with older zfs versions. +.El .Sh INTERFACE STABILITY .Sy Committed . .Sh SEE ALSO diff --git a/tests/zfs-tests/tests/functional/rsend/rsend.kshlib b/tests/zfs-tests/tests/functional/rsend/rsend.kshlib index 779e2447d..b4819245e 100644 --- a/tests/zfs-tests/tests/functional/rsend/rsend.kshlib +++ b/tests/zfs-tests/tests/functional/rsend/rsend.kshlib @@ -675,7 +675,7 @@ function test_fs_setup datasetexists $recvfs && log_must_busy zfs destroy -r $recvpool datasetexists $streamfs && log_must_busy zfs destroy -r $streamfs - if $(datasetexists $sendfs || zfs create -o compress=lz4 $sendfs); then + if datasetexists $sendfs || zfs create -o compress=lz4 $sendfs; then mk_files 1000 256 0 $sendfs & mk_files 1000 131072 0 $sendfs & mk_files 100 1048576 0 $sendfs & |