From 501a1511aeaaf8f7b50410ef7e64e06647aa8dfb Mon Sep 17 00:00:00 2001 From: felixdoerre Date: Thu, 21 May 2020 04:02:41 +0300 Subject: [PATCH] mount: use the mount syscall directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Felix Dörre #10294 --- cmd/mount_zfs/mount_zfs.c | 236 +----------- cmd/zfs/zfs_main.c | 3 - include/libzfs.h | 7 + include/libzfs_impl.h | 3 +- lib/libzfs/libzfs_mount.c | 2 +- lib/libzfs/os/freebsd/libzfs_zmount.c | 7 +- lib/libzfs/os/linux/libzfs_mount_os.c | 343 ++++++++++++++++-- man/man8/zfs.8 | 9 + .../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 a37dd6f53a16..87d2ccadcded 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 27f34b9fdc7e..c0ca8e8c22a1 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 551b6ae74200..d9f0d7259561 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 be11b1fc050e..91fa1efbbdac 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 4d4b497533ac..4123968b0dc6 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 8ff24f446bdc..c0951c314ded 100644 --- a/lib/libzfs/os/freebsd/libzfs_zmount.c +++ b/lib/libzfs/os/freebsd/libzfs_zmount.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include 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 c04eb21611e0..04252e42105d 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 eeefcda3cff1..47cf45a99ef7 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 779e2447de5e..b4819245e538 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 &