mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-25 18:59:33 +03:00
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 <behlendorf1@llnl.gov> Signed-off-by: Felix Dörre <felix@dogcraft.de> #10294
This commit is contained in:
parent
57434abae6
commit
501a1511ae
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
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};
|
||||
|
||||
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 (ENXIO); /* Generic error */
|
||||
/* 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] = {
|
||||
|
@ -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
|
||||
|
@ -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 &
|
||||
|
Loading…
Reference in New Issue
Block a user