summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/bugs/nfs/showmount-many-clients.t41
-rw-r--r--xlators/nfs/server/src/mount3.c84
2 files changed, 107 insertions, 18 deletions
diff --git a/tests/bugs/nfs/showmount-many-clients.t b/tests/bugs/nfs/showmount-many-clients.t
new file mode 100644
index 00000000000..f1b6859d528
--- /dev/null
+++ b/tests/bugs/nfs/showmount-many-clients.t
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# The nfs.rpc-auth-allow volume option is used to generate the list of clients
+# that are displayed as able to mount the export. The "group" in the export
+# should be a list of all clients, identified by "name". In previous versions,
+# the "name" was the copied string from nfs.rpc-auth-allow. This is not
+# correct, as the volume option should be parsed and split into different
+# groups.
+#
+# When the single string is passed, this testcase fails when the
+# nfs.rpc-auth-allow volume option is longer than 256 characters. By splitting
+# the groups into their own structures, this testcase passes.
+#
+
+. $(dirname $0)/../../include.rc
+. $(dirname $0)/../../nfs.rc
+. $(dirname $0)/../../volume.rc
+
+cleanup
+
+TEST glusterd
+TEST pidof glusterd
+
+TEST $CLI volume create $V0 $H0:$B0/brick1
+EXPECT 'Created' volinfo_field $V0 'Status'
+TEST $CLI volume set $V0 nfs.disable false
+
+CLIENTS=$(echo 127.0.0.{1..128} | tr ' ' ,)
+TEST $CLI volume set $V0 nfs.rpc-auth-allow ${CLIENTS}
+TEST $CLI volume set $V0 nfs.rpc-auth-reject all
+
+TEST $CLI volume start $V0;
+EXPECT 'Started' volinfo_field $V0 'Status'
+
+# glusterfs/nfs needs some time to start up in the background
+EXPECT_WITHIN $NFS_EXPORT_TIMEOUT 1 is_nfs_export_available
+
+# showmount should not timeout (no reply is sent on error)
+TEST showmount -e $H0
+
+cleanup
diff --git a/xlators/nfs/server/src/mount3.c b/xlators/nfs/server/src/mount3.c
index c10232e20e0..bf4ba0f25c7 100644
--- a/xlators/nfs/server/src/mount3.c
+++ b/xlators/nfs/server/src/mount3.c
@@ -2632,27 +2632,75 @@ mnt3_xlchildren_to_exports (rpcsvc_t *svc, struct mount3_state *ms)
}
strcpy (elist->ex_dir, ent->expname);
- addrstr = rpcsvc_volume_allowed (svc->options,
- ent->vol->name);
- elist->ex_groups = GF_CALLOC (1, sizeof (struct groupnode),
- gf_nfs_mt_groupnode);
- if (!elist->ex_groups) {
- gf_msg (GF_MNT, GF_LOG_ERROR, ENOMEM,
- NFS_MSG_NO_MEMORY, "Memory allocation failed");
- goto free_list;
- }
- /*This check has to be done after checking
- * elist->ex_groups allocation check to avoid resource leak;
- */
- if (addrstr)
- addrstr = gf_strdup (addrstr);
- else
+ addrstr = rpcsvc_volume_allowed (svc->options, ent->vol->name);
+ if (addrstr) {
+ /* create a groupnode per allowed client */
+ char *pos = NULL;
+ char *addr = NULL;
+ char *addrs = NULL;
+ struct groupnode *group = NULL;
+ struct groupnode *prev_group = NULL;
+
+ /* strtok_r() modifies the string, dup it */
+ addrs = gf_strdup (addrstr);
+ if (!addrs)
+ goto free_list;
+
+ while (1) {
+ /* only pass addrs on the 1st call */
+ addr = strtok_r (group ? NULL : addrs, ",",
+ &pos);
+ if (addr == NULL)
+ /* no mode clients */
+ break;
+
+ group = GF_CALLOC (1, sizeof (struct groupnode),
+ gf_nfs_mt_groupnode);
+ if (!group) {
+ gf_msg (GF_MNT, GF_LOG_ERROR, ENOMEM,
+ NFS_MSG_NO_MEMORY, "Memory "
+ "allocation failed");
+ GF_FREE (addrs);
+ goto free_list;
+ }
+
+ group->gr_name = gf_strdup (addr);
+ if (!group->gr_name) {
+ gf_msg (GF_MNT, GF_LOG_ERROR, ENOMEM,
+ NFS_MSG_NO_MEMORY, "Memory "
+ "allocation failed");
+ GF_FREE (group);
+ GF_FREE (addrs);
+ goto free_list;
+ }
+
+ /* chain the groups together */
+ if (!elist->ex_groups)
+ elist->ex_groups = group;
+ else
+ prev_group->gr_next = group;
+ prev_group = group;
+ }
+
+ GF_FREE (addrs);
+ } else {
+ elist->ex_groups = GF_CALLOC (1,
+ sizeof (struct groupnode),
+ gf_nfs_mt_groupnode);
+ if (!elist->ex_groups) {
+ gf_msg (GF_MNT, GF_LOG_ERROR, ENOMEM,
+ NFS_MSG_NO_MEMORY, "Memory allocation "
+ "failed");
+ goto free_list;
+ }
+
addrstr = gf_strdup ("No Access");
+ if (!addrstr)
+ goto free_list;
- if (!addrstr) {
- goto free_list;
+ elist->ex_groups->gr_name = addrstr;
}
- elist->ex_groups->gr_name = addrstr;
+
if (prev) {
prev->ex_next = elist;
prev = elist;