diff options
author | Csaba Henk <csaba@redhat.com> | 2017-01-03 15:26:30 +0100 |
---|---|---|
committer | Kaleb KEITHLEY <kkeithle@redhat.com> | 2017-04-27 17:38:48 +0000 |
commit | e624e7fe38a784363c57108c73487d83a7bda562 (patch) | |
tree | 65013ea9801d44f89095f69c519b997214ae5f67 | |
parent | ec7a0c7eefacc68532bdc909f05a01eca8b3139d (diff) |
fuse: clean up mount flag processing
In general, when one invokes a mount helper program -- basically
anything that mounts something based on its command line, so thinking of
mount(8), mount.<fs-type> or fusermount, but also of FUSE servers in
general, including glusterfs -- the command line arguments that are to
affect mount(2) are mapped to a bitmask called the mount flags, which is
passed to mount(2), so that the kernel can interpret the flag bits and
adjusts properties of the mount accordingly.
There is a traditional syntax for this mechanism as implemented in
mount(8): one passes "-ocomma,separated,mount,options" and the
individual option name strings are mapped to flag bits in mount(8).
FUSE further explores this idea and typically the FUSE server command
lines allow further option names to be used in the "-ooption,name,list"
which are then separated from the kernel sanctioned option names (to
which we'll refer as "system mount options") and are passed to a
platform specific lower level fuse mount helper interface.
The separation of system mount option names and FUSE specific option
names is also platform specific, so the general mount interface
function, which in case of glusterfs is gf_fuse_mount(), should abstract
this away.
Therefore we change the signature of this function from
int gf_fuse_mount (const char *mountpoint, char *fsname,
unsigned long mountflags, char *mnt_param,
pid_t *mtab_pid, int status_fd);
to
int gf_fuse_mount (const char *mountpoint, char *fsname,
char *mnt_param, pid_t *mtab_pid,
int status_fd);
and deal with flag extraction in platform specific mount code. Note that
the sole purpose of the mountflags argument was to indicate read-only
mounting. The other system mount option names were expected to reside in
the comma-separated mnt_param string, but they were not properly
processed (see the referred BUG). With the new gf_fuse_mount signature
read-only mounting is to be indicated as a "ro" component in mnt_param.
- For Darwin, which has a dedicated, separate gf_fuse_mount
implementation, gf_fuse_mount was ignoring mountflags, so only the
signature had to to be adjusted. However, as bonus, we gain read-only
support for Darwin, which was missing so far, given that it was
indicated via the ignored mountflags. Darwin's low level mount helper
relies on the "ro" component of the option string, which agrees with
the new calling convention of gf_fuse_mount.
- On Linux, system mount option name handling (apart from the
distinguished read-only option) used to have the inadvertent side
effect of adding "nosuid,nodev" as indicated in BUG; since
Ia89d975d1e27fcfa5ab2036ba546aa8fa0d2d1b0 this side effect is removed,
but system mount option name handling was left broken (passing system
mount options other than "ro" fails to mount).
- On other platforms, system mount option name handling is broken
(expect for the distinguished read-only option).
As of this change, in the general (non-Darwin) implementation of
gf_fuse_mount we take care of proper separation of system mount names
and their conversion to mount flags. For Linux, we adopt the conversion
table from FUSE upstream. For other systems we just provide a best
effort to support those system mount options which are understood across
all Unices (nosuid,nodev,noatime,noexec,ro). (This can be improved later
to provide proper plaform support.)
BUG: 1297182
Change-Id: I5d10b5df46feba7a02bf5bf1018db69e6b52260a
Signed-off-by: Csaba Henk <csaba@redhat.com>
Reviewed-on: https://review.gluster.org/16313
Smoke: Gluster Build System <jenkins@build.gluster.org>
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
Reviewed-by: Amar Tumballi <amarts@redhat.com>
Tested-by: Amar Tumballi <amarts@redhat.com>
-rw-r--r-- | contrib/fuse-include/fuse-mount.h | 3 | ||||
-rw-r--r-- | contrib/fuse-lib/mount-gluster-compat.h | 42 | ||||
-rw-r--r-- | contrib/fuse-lib/mount.c | 119 | ||||
-rw-r--r-- | contrib/macfuse/mount_darwin.c | 3 | ||||
-rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.c | 9 |
5 files changed, 151 insertions, 25 deletions
diff --git a/contrib/fuse-include/fuse-mount.h b/contrib/fuse-include/fuse-mount.h index 9358ac810e1..7a3756d92b8 100644 --- a/contrib/fuse-include/fuse-mount.h +++ b/contrib/fuse-include/fuse-mount.h @@ -8,6 +8,5 @@ */ void gf_fuse_unmount (const char *mountpoint, int fd); -int gf_fuse_mount (const char *mountpoint, char *fsname, - unsigned long mountflags, char *mnt_param, +int gf_fuse_mount (const char *mountpoint, char *fsname, char *mnt_param, pid_t *mtab_pid, int status_fd); diff --git a/contrib/fuse-lib/mount-gluster-compat.h b/contrib/fuse-lib/mount-gluster-compat.h index 562f089dd1f..a16103e0fbb 100644 --- a/contrib/fuse-lib/mount-gluster-compat.h +++ b/contrib/fuse-lib/mount-gluster-compat.h @@ -30,17 +30,59 @@ #include <sys/wait.h> #include <sys/mount.h> +#ifdef GF_LINUX_HOST_OS +typedef unsigned long mount_flag_t; +#endif + #if defined(__NetBSD__) #include <perfuse.h> #define umount2(dir, flags) unmount(dir, ((flags) != 0) ? MNT_FORCE : 0) #define MS_RDONLY MNT_RDONLY +#define MS_NOSUID MNT_NOSUID +#define MS_NODEV MNT_NODEV +#define MS_NOATIME MNT_NOATIME +#define MS_NOEXEC MNT_NOEXEC +typedef int mount_flag_t; #endif #if defined(GF_DARWIN_HOST_OS) || defined(__FreeBSD__) #include <sys/param.h> #include <sys/mount.h> #define umount2(dir, flags) unmount(dir, ((flags) != 0) ? MNT_FORCE : 0) +#endif + +#if defined(__FreeBSD__) #define MS_RDONLY MNT_RDONLY +#define MS_NOSUID MNT_NOSUID +/* "nodev"/MNT_NODEV was removed from FreBSD, as it became unneeded because "As + * of FreeBSD 6.0 device nodes may be created in regular file systems but such + * nodes cannot be used to access devices." (See + * https://freebsd.org/cgi/man.cgi?query=mknod&sektion=8 . + * Also see: + * - https://github.com/freebsd/freebsd/commit/266790a + * - https://github.com/freebsd/freebsd/commit/a5e716d + * - 700008 in + * https://www.freebsd.org/doc/en/books/porters-handbook/versions-7.html .) + */ +#if __FreeBSD_version < 700008 +#define MS_NODEV MNT_NODEV +#else +#define MS_NODEV 0 +#endif +#define MS_NOATIME MNT_NOATIME +#define MS_NOEXEC MNT_NOEXEC +#if __FreeBSD_version < 1000715 +typedef int mount_flag_t; +#else +/* __FreeBSD_version was not bumped for this type change. Anyway, see + * https://github.com/freebsd/freebsd/commit/e8d76f8 + * and respective __FreeBSD_version: + * https://github.com/freebsd/freebsd/blob/e8d76f8/sys/sys/param.h#L61 . + * We use the subsequent value, 1000715, to switch. (Also see: + * https://www.freebsd.org/doc/en/books/porters-handbook/versions-10.html .) + */ +typedef long long mount_flag_t; +#endif #endif #ifdef GF_LINUX_HOST_OS diff --git a/contrib/fuse-lib/mount.c b/contrib/fuse-lib/mount.c index bfe28d3a26a..1dfd2a71c05 100644 --- a/contrib/fuse-lib/mount.c +++ b/contrib/fuse-lib/mount.c @@ -106,8 +106,7 @@ escape (char *s) static int fuse_mount_fusermount (const char *mountpoint, char *fsname, - unsigned long mountflags, char *mnt_param, - int fd) + char *mnt_param, int fd) { int pid = -1; int res = 0; @@ -130,8 +129,7 @@ fuse_mount_fusermount (const char *mountpoint, char *fsname, return -1; } ret = asprintf (&fm_mnt_params, - "%s%s,fsname=%s,nonempty,subtype=glusterfs", - (mountflags & MS_RDONLY) ? "ro," : "", + "%s,fsname=%s,nonempty,subtype=glusterfs", mnt_param, efsname); FREE (efsname); if (ret == -1) { @@ -224,19 +222,112 @@ build_iovec_argf(struct iovec **iov, int *iovlen, const char *name, } #endif /* __FreeBSD__ */ +struct mount_flags { + const char *opt; + mount_flag_t flag; + int on; +} mount_flags[] = { + /* We provide best effort cross platform support for mount flags by + * defining the ones which are commonly used in Unix-like OS-es. + */ + {"ro", MS_RDONLY, 1}, + {"nosuid", MS_NOSUID, 1}, + {"nodev", MS_NODEV, 1}, + {"noatime", MS_NOATIME, 1}, + {"noexec", MS_NOEXEC, 1}, +#ifdef GF_LINUX_HOST_OS + {"rw", MS_RDONLY, 0}, + {"suid", MS_NOSUID, 0}, + {"dev", MS_NODEV, 0}, + {"exec", MS_NOEXEC, 0}, + {"async", MS_SYNCHRONOUS, 0}, + {"sync", MS_SYNCHRONOUS, 1}, + {"atime", MS_NOATIME, 0}, + {"dirsync", MS_DIRSYNC, 1}, +#endif + {NULL, 0, 0} +}; + +static int +mount_param_to_flag (char *mnt_param, mount_flag_t *mntflags, + char **mnt_param_new) +{ + int i = 0; + int j = 0; + char *p = NULL; + gf_boolean_t found = _gf_false; + struct mount_flags *flag = NULL; + + /* Allocate a buffer that will hold the mount parameters remaining + * after the ones corresponding to mount flags are processed and + * removed.The length of the original params are a good upper bound + * of the size needed. + */ + *mnt_param_new = CALLOC (1, strlen (mnt_param) + 1); + if (!*mnt_param_new) + return -1; + p = *mnt_param_new; + + while (mnt_param[j]) { + if (j > 0) + i = j+1; + j = i; + + /* Seek the delimiters. */ + while (mnt_param[j] != ',' && mnt_param[j] != '\0') + j++; + + found = _gf_false; + for (flag = mount_flags; flag->opt; flag++) { + /* Compare the mount flag name to the param + * name at hand (from i to j in mnt_param). + */ + if (strlen (flag->opt) == j - i && + memcmp (flag->opt, mnt_param + i, j - i) == 0) { + /* If there is a match, adjust mntflags + * accordingly and break. + */ + if (flag->on) { + *mntflags |= flag->flag; + } else { + *mntflags &= ~flag->flag; + } + found = _gf_true; + break; + } + } + /* If the param did't match any flag name, retain it (ie. copy + * over to the new param buffer). + */ + if (!found) { + if (p != *mnt_param_new) + *p++ = ','; + memcpy (p, mnt_param + i, j - i); + p += j - i; + } + } + + return 0; +} + static int fuse_mount_sys (const char *mountpoint, char *fsname, - unsigned long mountflags, char *mnt_param, int fd) + char *mnt_param, int fd) { int ret = -1; unsigned mounted = 0; char *mnt_param_mnt = NULL; char *fstype = "fuse.glusterfs"; char *source = fsname; - - ret = asprintf (&mnt_param_mnt, - "%s,fd=%i,rootmode=%o,user_id=%i,group_id=%i", - mnt_param, fd, S_IFDIR, getuid (), getgid ()); + mount_flag_t mountflags = 0; + char *mnt_param_new = NULL; + + ret = mount_param_to_flag (mnt_param, &mountflags, &mnt_param_new); + if (ret == 0) + ret = asprintf (&mnt_param_mnt, + "%s,fd=%i,rootmode=%o,user_id=%i,group_id=%i", + mnt_param_new, fd, S_IFDIR, getuid (), + getgid ()); if (ret == -1) { GFFUSE_LOGERR ("Out of memory"); @@ -295,7 +386,7 @@ fuse_mount_sys (const char *mountpoint, char *fsname, ret = asprintf (&mnt_param_mtab, "%s%s", mountflags & MS_RDONLY ? "ro," : "", - mnt_param); + mnt_param_new); if (ret == -1) GFFUSE_LOGERR ("Out of memory"); else { @@ -320,6 +411,7 @@ out: umount2 (mountpoint, 2); /* lazy umount */ } FREE (mnt_param_mnt); + FREE (mnt_param_new); if (source != fsname) FREE (source); @@ -328,8 +420,7 @@ out: int gf_fuse_mount (const char *mountpoint, char *fsname, - unsigned long mountflags, char *mnt_param, - pid_t *mnt_pid, int status_fd) + char *mnt_param, pid_t *mnt_pid, int status_fd) { int fd = -1; pid_t pid = -1; @@ -356,8 +447,7 @@ gf_fuse_mount (const char *mountpoint, char *fsname, exit (pid == -1 ? 1 : 0); } - ret = fuse_mount_sys (mountpoint, fsname, mountflags, mnt_param, - fd); + ret = fuse_mount_sys (mountpoint, fsname, mnt_param, fd); if (ret == -1) { gf_log ("glusterfs-fuse", GF_LOG_INFO, "direct mount failed (%s) errno %d", @@ -368,7 +458,6 @@ gf_fuse_mount (const char *mountpoint, char *fsname, "retry to mount via fusermount"); ret = fuse_mount_fusermount (mountpoint, fsname, - mountflags, mnt_param, fd); } } diff --git a/contrib/macfuse/mount_darwin.c b/contrib/macfuse/mount_darwin.c index 10eff204bc6..f4ecacad86a 100644 --- a/contrib/macfuse/mount_darwin.c +++ b/contrib/macfuse/mount_darwin.c @@ -42,8 +42,7 @@ gf_log ("glusterfs-fuse", GF_LOG_ERROR, ## __VA_ARGS__) int -gf_fuse_mount (const char *mountpoint, char *fsname, - unsigned long mountflags, char *mnt_param, +gf_fuse_mount (const char *mountpoint, char *fsname, char *mnt_param, pid_t *mnt_pid, int status_fd) /* Not used on OS X */ { int fd = 0; diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index 6e5cd63a818..7056b6fd164 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -10,7 +10,6 @@ #include <sys/wait.h> #include "fuse-bridge.h" -#include "mount-gluster-compat.h" #include "glusterfs.h" #include "byte-order.h" #include "compat-errno.h" @@ -5481,7 +5480,6 @@ init (xlator_t *this_xl) glusterfs_ctx_t *ctx = NULL; gf_boolean_t sync_to_mount = _gf_false; gf_boolean_t fopen_keep_cache = _gf_false; - unsigned long mntflags = 0; char *mnt_args = NULL; eh_t *event = NULL; @@ -5717,10 +5715,9 @@ init (xlator_t *this_xl) goto cleanup_exit; } - if (priv->read_only) - mntflags |= MS_RDONLY; - gf_asprintf (&mnt_args, "%s%s%sallow_other,max_read=131072", + gf_asprintf (&mnt_args, "%s%s%s%sallow_other,max_read=131072", priv->acl ? "" : "default_permissions,", + priv->read_only ? "ro," : "", priv->fuse_mountopts ? priv->fuse_mountopts : "", priv->fuse_mountopts ? "," : ""); if (!mnt_args) @@ -5732,7 +5729,7 @@ init (xlator_t *this_xl) goto cleanup_exit; } - priv->fd = gf_fuse_mount (priv->mount_point, fsname, mntflags, mnt_args, + priv->fd = gf_fuse_mount (priv->mount_point, fsname, mnt_args, sync_to_mount ? &ctx->mnt_pid : NULL, priv->status_pipe[1]); if (priv->fd == -1) |