Whamcloud - gitweb
LU-5690 mount: fix lmd_parse() to handle commas in expr_list 36/17036/6
authorJian Yu <jian.yu@intel.com>
Fri, 20 Nov 2015 19:13:18 +0000 (11:13 -0800)
committerOleg Drokin <oleg.drokin@intel.com>
Sun, 13 Dec 2015 20:57:23 +0000 (20:57 +0000)
The lmd_parse() function parses mount options with comma as
delimiter without considering commas in expr_list as follows
is a valid LNET nid range syntax:

<expr_list>  :== '[' <range_expr> [ ',' <range_expr>] ']'

This patch fixes the above issue by using cfs_parse_nidlist()
to parse nid range list instead of using class_parse_nid_quiet()
to parse only one nid.

Signed-off-by: Jian Yu <jian.yu@intel.com>
Change-Id: I8ba6ee6eb31b4bb078a83d9db213cfca27b0fe66
Reviewed-on: http://review.whamcloud.com/17036
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Niu Yawei <yawei.niu@intel.com>
Reviewed-by: Bob Glossman <bob.glossman@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
lustre/obdclass/obd_mount.c
lustre/tests/conf-sanity.sh

index 880f7b8..c8b0338 100644 (file)
@@ -1039,6 +1039,89 @@ static int lmd_parse_mgs(struct lustre_mount_data *lmd, char **ptr)
        return 0;
 }
 
+/**
+ * Find the first comma delimiter from the specified \a buf and make \a *endh
+ * point to the string starting with the comma. The commas in expression list
+ * [...] will be skipped.
+ *
+ * \param[in] buf      a comma-separated string
+ * \param[in] endh     a pointer to a pointer that will point to the string
+ *                     starting with the comma
+ *
+ * \retval 0           if comma delimiter is found
+ * \retval 1           if comma delimiter is not found
+ */
+static int lmd_find_comma(char *buf, char **endh)
+{
+       char *c = buf;
+       int   skip = 0;
+
+       if (buf == NULL)
+               return 1;
+
+       while (*c != '\0') {
+               if (*c == '[')
+                       skip++;
+               else if (*c == ']')
+                       skip--;
+
+               if (*c == ',' && skip == 0) {
+                       if (endh != NULL)
+                               *endh = c;
+                       return 0;
+               }
+
+               c++;
+       }
+
+       return 1;
+}
+
+/**
+ * Find the first valid string delimited by comma from the specified \a buf
+ # and parse it to see whether it's a valid nid list. If yes, \a *endh will
+ * point to the next string starting with the comma.
+ *
+ * \param[in] buf      a comma-separated string
+ * \param[in] endh     a pointer to a pointer that will point to the string
+ *                     starting with the comma
+ *
+ * \retval 0           if the string is a valid nid list
+ * \retval 1           if the string is not a valid nid list
+ */
+static int lmd_parse_nidlist(char *buf, char **endh)
+{
+       struct list_head nidlist;
+       char            *endp = buf;
+       char             tmp;
+       int              rc = 0;
+
+       if (buf == NULL)
+               return 1;
+       while (*buf == ',' || *buf == ':')
+               buf++;
+       if (*buf == ' ' || *buf == '/' || *buf == '\0')
+               return 1;
+
+       if (lmd_find_comma(buf, &endp) != 0)
+               endp = buf + strlen(buf);
+
+       tmp = *endp;
+       *endp = '\0';
+
+       INIT_LIST_HEAD(&nidlist);
+       if (cfs_parse_nidlist(buf, strlen(buf), &nidlist) <= 0)
+               rc = 1;
+       cfs_free_nidlist(&nidlist);
+
+       *endp = tmp;
+       if (rc != 0)
+               return rc;
+       if (endh != NULL)
+               *endh = endp;
+       return 0;
+}
+
 /** Parse mount line options
  * e.g. mount -v -t lustre -o abort_recov uml1:uml2:/lustre-client /mnt/lustre
  * dev is passed as device=uml1:/lustre by mount.lustre
@@ -1155,16 +1238,14 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
                        clear++;
                } else if (strncmp(s1, "param=", 6) == 0) {
                        size_t length, params_length;
-                       char *tail = strchr(s1 + 6, ',');
-                       if (tail == NULL) {
+                       char  *tail = s1;
+                       if (lmd_find_comma(s1 + 6, &tail) != 0)
                                length = strlen(s1);
-                       } else {
-                               lnet_nid_t nid;
-                               char      *param_str = tail + 1;
-                               int        supplementary = 1;
-
-                               while (class_parse_nid_quiet(param_str, &nid,
-                                                            &param_str) == 0) {
+                       else {
+                               char *param_str = tail + 1;
+                               int   supplementary = 1;
+                               while (lmd_parse_nidlist(param_str,
+                                                        &param_str) == 0) {
                                        supplementary = 0;
                                }
                                length = param_str - s1 - supplementary;
index 30eb1ff..c3a4881 100644 (file)
@@ -2872,7 +2872,7 @@ test_42() { #bug 14693
 }
 run_test 42 "allow client/server mount/unmount with invalid config param"
 
-test_43() {
+test_43a() {
        [[ $(lustre_version_code mgs) -ge $(version_code 2.5.58) ]] ||
                { skip "Need MDS version at least 2.5.58" && return 0; }
        [ $UID -ne 0 -o $RUNAS_ID -eq 0 ] && skip_env "run as root"
@@ -3020,8 +3020,43 @@ test_43() {
        touch $DIR/$tdir-rootdir/tfile-2 ||
                error "$ST: root create permission is denied"
        echo "$ST: root create permission is granted - ok"
+       cleanup || error "cleanup failed with $?"
+}
+run_test 43a "check root_squash and nosquash_nids"
+
+test_43b() { # LU-5690
+       [[ $(lustre_version_code mgs) -ge $(version_code 2.7.62) ]] ||
+               { skip "Need MGS version 2.7.62+"; return; }
+
+       if [[ -z "$fs2mds_DEV" ]]; then
+               is_blkdev $SINGLEMDS $(mdsdevname ${SINGLEMDS//mds/}) &&
+               skip_env "mixed loopback and real device not working" && return
+       fi
+
+       local fs2mdsdev=$(mdsdevname 1_2)
+       local fs2mdsvdev=$(mdsvdevname 1_2)
+
+       # temporarily use fs2mds as fs2mgs
+       local fs2mgs=fs2mds
+       local fs2mgsdev=$fs2mdsdev
+       local fs2mgsvdev=$fs2mdsvdev
+
+       local fsname=test1234
+
+       load_module llite/lustre
+       local client_ip=$(host_nids_address $HOSTNAME $NETTYPE)
+       local host=${client_ip//*./}
+       local net=${client_ip/%$host/}
+       local nosquash_nids=$(h2$NETTYPE $net[$host,$host,$host])
+
+       add $fs2mgs $(mkfs_opts mgs $fs2mgsdev) --fsname=$fsname \
+               --param mdt.root_squash=$RUNAS_ID:$RUNAS_ID \
+               --param mdt.nosquash_nids=$nosquash_nids \
+               --reformat $fs2mgsdev $fs2mgsvdev || error "add fs2mgs failed"
+       start $fs2mgs $fs2mgsdev $MGS_MOUNT_OPTS  || error "start fs2mgs failed"
+       stop $fs2mgs -f || error "stop fs2mgs failed"
 }
-run_test 43 "check root_squash and nosquash_nids"
+run_test 43b "parse nosquash_nids with commas in expr_list"
 
 umount_client $MOUNT
 cleanup_nocli