diff options
author | Niels de Vos <ndevos@redhat.com> | 2015-07-21 18:50:12 +0200 |
---|---|---|
committer | Kaleb KEITHLEY <kkeithle@redhat.com> | 2015-08-05 04:53:12 -0700 |
commit | 64a5bf3749c67fcc00773a2716d0c7b61b0b4417 (patch) | |
tree | 4dd5a36c66ca70f726427480a1a87c44803027a1 /xlators/mount/fuse | |
parent | 28fc199d5dc92a69eb2b899bbea23548dc14a39b (diff) |
fuse: add "resolve-gids" mount option to overcome 32-groups limit
Add a --resolve-gids commandline option to the glusterfs binary. This
option gets set when executing "mount -t glusterfs -o resolve-gids ...".
This option is most useful in combination with the "acl" mount option.
POSIX ACL permission checking is done on the FUSE-client side to improve
performance (in addition to the checking on the bricks).
The fuse-bridge reads /proc/$PID/status by default, and this file
contains maximum 32 groups. Any local (client-side) permission checking
that requires more than the first 32 groups will fail.
By enabling the "resolve-gids" option, the fuse-bridge will call
getgrouplist() to retrieve all the groups from the user accessing the
mountpoint. This is comparable to how "nfs.server-aux-gids" works.
Note that when a user belongs to more than ~93 groups, the volume option
server.manage-gids needs to be enabled too. Without this option, the
RPC-layer will need to reduce the number of groups to make them fit in
the RPC-header.
Change-Id: I7ede90d0e41bcf55755cced5747fa0fb1699edb2
BUG: 1246275
Signed-off-by: Niels de Vos <ndevos@redhat.com>
Reviewed-on: http://review.gluster.org/11732
Tested-by: NetBSD Build System <jenkins@build.gluster.org>
Reviewed-by: Ravishankar N <ravishankar@redhat.com>
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: jiffin tony Thottan <jthottan@redhat.com>
Reviewed-by: Kaleb KEITHLEY <kkeithle@redhat.com>
Diffstat (limited to 'xlators/mount/fuse')
-rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.c | 6 | ||||
-rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.h | 3 | ||||
-rw-r--r-- | xlators/mount/fuse/src/fuse-helpers.c | 116 | ||||
-rwxr-xr-x | xlators/mount/fuse/utils/mount.glusterfs.in | 7 |
4 files changed, 93 insertions, 39 deletions
diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index b67a60a76b1..d6edcb360cd 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -5427,6 +5427,8 @@ init (xlator_t *this_xl) goto cleanup_exit; } + GF_OPTION_INIT("resolve-gids", priv->resolve_gids, bool, cleanup_exit); + /* default values seemed to work fine during testing */ GF_OPTION_INIT ("background-qlen", priv->background_qlen, int32, cleanup_exit); @@ -5665,6 +5667,10 @@ struct volume_options options[] = { .type = GF_OPTION_TYPE_INT, .default_value = "300" }, + { .key = {"resolve-gids"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "false" + }, { .key = {"acl"}, .type = GF_OPTION_TYPE_BOOL, .default_value = "false" diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h index a9705d6c654..850eeb60ea8 100644 --- a/xlators/mount/fuse/src/fuse-bridge.h +++ b/xlators/mount/fuse/src/fuse-bridge.h @@ -127,6 +127,9 @@ struct fuse_private { /* fini started, helps prevent multiple epoll worker threads * firing up the fini routine */ gf_boolean_t fini_invoked; + + /* resolve gid with getgrouplist() instead of /proc/%d/status */ + gf_boolean_t resolve_gids; }; typedef struct fuse_private fuse_private_t; diff --git a/xlators/mount/fuse/src/fuse-helpers.c b/xlators/mount/fuse/src/fuse-helpers.c index 1c888276eb5..22aa9b486d1 100644 --- a/xlators/mount/fuse/src/fuse-helpers.c +++ b/xlators/mount/fuse/src/fuse-helpers.c @@ -20,6 +20,8 @@ #elif defined(CTL_KERN) #include <sys/sysctl.h> #endif +#include <pwd.h> +#include <grp.h> #include "fuse-bridge.h" @@ -146,51 +148,87 @@ void frame_fill_groups (call_frame_t *frame) { #if defined(GF_LINUX_HOST_OS) - char filename[32]; - char line[4096]; - char *ptr = NULL; - FILE *fp = NULL; - int idx = 0; - long int id = 0; - char *saveptr = NULL; - char *endptr = NULL; - int ret = 0; - - ret = snprintf (filename, sizeof filename, "/proc/%d/status", - frame->root->pid); - if (ret >= sizeof filename) - goto out; + xlator_t *this = frame->this; + fuse_private_t *priv = this->private; + char filename[32]; + char line[4096]; + char *ptr = NULL; + FILE *fp = NULL; + int idx = 0; + long int id = 0; + char *saveptr = NULL; + char *endptr = NULL; + int ret = 0; + int ngroups = FUSE_MAX_AUX_GROUPS; + gid_t mygroups[GF_MAX_AUX_GROUPS]; + + if (priv->resolve_gids) { + struct passwd pwent; + char mystrs[1024]; + struct passwd *result; + + if (getpwuid_r (frame->root->uid, &pwent, mystrs, + sizeof(mystrs), &result) != 0) { + gf_log (this->name, GF_LOG_ERROR, "getpwuid_r(%u) " + "failed", frame->root->uid); + return; + } - fp = fopen (filename, "r"); - if (!fp) - goto out; + ngroups = GF_MAX_AUX_GROUPS; + if (getgrouplist (result->pw_name, frame->root->gid, mygroups, + &ngroups) == -1) { + gf_log (this->name, GF_LOG_ERROR, "could not map %s to " + "group list (ngroups %d, max %d)", + result->pw_name, ngroups, GF_MAX_AUX_GROUPS); + return; + } - if (call_stack_alloc_groups (frame->root, FUSE_MAX_AUX_GROUPS) != 0) - goto out; + if (call_stack_alloc_groups (frame->root, ngroups) != 0) + goto out; - while ((ptr = fgets (line, sizeof line, fp))) { - if (strncmp (ptr, "Groups:", 7) != 0) - continue; - - ptr = line + 8; - - for (ptr = strtok_r (ptr, " \t\r\n", &saveptr); - ptr; - ptr = strtok_r (NULL, " \t\r\n", &saveptr)) { - errno = 0; - id = strtol (ptr, &endptr, 0); - if (errno == ERANGE) - break; - if (!endptr || *endptr) - break; - frame->root->groups[idx++] = id; - if (idx == FUSE_MAX_AUX_GROUPS) - break; + /* Copy data to the frame. */ + for (idx = 0; idx < ngroups; ++idx) { + frame->root->groups[idx] = mygroups[idx]; } + frame->root->ngrps = ngroups; + } else { + ret = snprintf (filename, sizeof filename, "/proc/%d/status", + frame->root->pid); + if (ret >= sizeof filename) + goto out; - frame->root->ngrps = idx; - break; + fp = fopen (filename, "r"); + if (!fp) + goto out; + + if (call_stack_alloc_groups (frame->root, ngroups) != 0) + goto out; + + while ((ptr = fgets (line, sizeof line, fp))) { + if (strncmp (ptr, "Groups:", 7) != 0) + continue; + + ptr = line + 8; + + for (ptr = strtok_r (ptr, " \t\r\n", &saveptr); + ptr; + ptr = strtok_r (NULL, " \t\r\n", &saveptr)) { + errno = 0; + id = strtol (ptr, &endptr, 0); + if (errno == ERANGE) + break; + if (!endptr || *endptr) + break; + frame->root->groups[idx++] = id; + if (idx == FUSE_MAX_AUX_GROUPS) + break; + } + + frame->root->ngrps = idx; + break; + } } + out: if (fp) fclose (fp); diff --git a/xlators/mount/fuse/utils/mount.glusterfs.in b/xlators/mount/fuse/utils/mount.glusterfs.in index 82660328363..112dc0a225b 100755 --- a/xlators/mount/fuse/utils/mount.glusterfs.in +++ b/xlators/mount/fuse/utils/mount.glusterfs.in @@ -177,6 +177,10 @@ start_glusterfs () cmd_line=$(echo "$cmd_line --aux-gfid-mount"); fi + if [ -n "$resolve_gids" ]; then + cmd_line=$(echo "$cmd_line --resolve-gids"); + fi + if [ -n "$no_root_squash" ]; then cmd_line=$(echo "$cmd_line --no-root-squash"); fi @@ -501,6 +505,9 @@ without_options() aux_gfid_mount=1 fi ;; + "resolve-gids") + resolve_gids=1 + ;; # "mount -t glusterfs" sends this, but it's useless. "rw") ;; |