Whamcloud - gitweb
LU-18210 utils: Fix issues with enhanced 'lfs check' 86/56286/3
authorChris Horn <chris.horn@hpe.com>
Fri, 6 Sep 2024 18:10:05 +0000 (12:10 -0600)
committerOleg Drokin <green@whamcloud.com>
Mon, 9 Dec 2024 06:09:52 +0000 (06:09 +0000)
lfs check takes an optional path argument that should restrict its
output to the targets that are related to the specified file system.
To determine which MGC should be shown the NID embedded in the OBD
name is compared against a NID that is parsed from the mount command
line. There are a few problems with this code:
1. The NID is parsed from the mount command by looking for a ':', but
   IPv6 NIDs can contain this character.
2. It doesn't handle case where multiple NIDs are listed on mount
   command separated by commas. e.g. "1@kfi,2@kfi:3@kfi,4@kfi:/lustre"
   will parse to "1@kfi,2@kfi" which is not a valid NID.
3. Even in the case where we have just two NIDs separated by ':', it
   assumes that the first one will be the one we are connected to.

To resolve these issues get_root_path_slow() will now store the entire
NID string used at mount time (after it has been processed by
convert_hostnames()) in the struct root_cache::nid. do_target_check()
will then iterate over each NID in the string using a new nidstrings
function, cfs_nidstr_find_delimiter(). This function contains logic
that was formerly in convert_hostnames(). This should ensure that
each MGS NID is checked.

convert_hostnames() is updated to use cfs_nidstr_find_delimiter() as
well.

Fixes: 6301419509 ("LU-17367 utils: improved hostname and IPv6 NID support")
Fixes: f5ca6853b8 ("LU-16076 utils: enhance 'lfs check' command")
Test-Parameters: testlist=sanityn env=ONLY=113,FORCE_LARGE_NID=true,LOAD_MODULES_REMOTE=true
Signed-off-by: Chris Horn <chris.horn@hpe.com>
Change-Id: I478c66d77a2b241b910324210475d61b3786c986
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/56286
Tested-by: Maloo <maloo@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Feng Lei <flei@whamcloud.com>
Reviewed-by: James Simmons <jsimmons@infradead.org>
Reviewed-by: Maximilian Dilger <mdilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
libcfs/libcfs/util/nidstrings.c
lnet/include/uapi/linux/lnet/nidstr.h
lustre/utils/liblustreapi.c
lustre/utils/liblustreapi_root.c
lustre/utils/mount_utils.c

index d892b8b..5f6d9c9 100644 (file)
@@ -36,6 +36,7 @@
 #define DEBUG_SUBSYSTEM S_LNET
 
 #include <assert.h>
+#include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdbool.h>
@@ -2172,3 +2173,45 @@ int cfs_expand_nidlist(struct list_head *nidlist, lnet_nid_t *lnet_nidlist,
        free(addrs);
        return max_nids - count;
 }
+
+/* returns pointer to the next delimiter in nidstr or if no delimiters are
+ * found then it returns a pointer to the termining NUL character
+ * A delimiter can be a comma, colon, or space.
+ */
+char *cfs_nidstr_find_delimiter(char *nidstr)
+{
+       char *delimiter = nidstr;
+       int hex_count = 0;
+       int hex_sections = 0;
+       bool is_ipv6 = true;
+
+       /* address parsing */
+       while (*delimiter != ',' && *delimiter != ' ' && *delimiter != '\0') {
+               /* Need to skip : in IPv6 / GUID NIDs. Lustre also uses
+                * ':' as a separator, which makes this complicated.
+                */
+               if (*delimiter == '@') {
+                       while (*delimiter != ':' && *delimiter != ',' &&
+                              *delimiter != ' ' && *delimiter != '\0')
+                               delimiter++;
+                       break;
+               }
+               /* IPv6 addresses are in 0-4 hex digit groups */
+               else if ((isxdigit(*delimiter) || *delimiter == ':') &&
+                        hex_count <= 4 && is_ipv6) {
+                       if (*delimiter == ':') {
+                               hex_sections++;
+                               hex_count = 0;
+                       } else {
+                               hex_count++;
+                       }
+               } else { /* NID is not IPv6 */
+                       is_ipv6 = false;
+                       if (*delimiter == ':')
+                               break;
+
+               }
+               delimiter++;
+       }
+       return delimiter;
+}
index f35a4b5..fe4c209 100644 (file)
@@ -117,5 +117,6 @@ int libcfs_ip_in_netmask(const __be32 *addr, size_t asize,
 int cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
                               char *max_nid, __kernel_size_t nidstr_length);
 void cfs_expr_list_free_list(struct list_head *list);
+char *cfs_nidstr_find_delimiter(char *buf);
 
 #endif /* _LNET_NIDSTRINGS_H */
index acc252e..60206f5 100644 (file)
@@ -7095,9 +7095,22 @@ static void do_target_check(char *obd_type_name, char *obd_name,
        struct check_target_filter *filter = args;
 
        if (filter != NULL) {
-               /* check nid if obd type is mgc */
+               /* check NIDs if obd type is mgc */
                if (strcmp(obd_type_name, "mgc") == 0) {
-                       if (strcmp(obd_name + 3, filter->nid) != 0)
+                       char *delimiter = filter->nid;
+                       char *nidstr = filter->nid;
+                       bool found = false;
+
+                       while (*nidstr && *delimiter) {
+                               delimiter = cfs_nidstr_find_delimiter(nidstr);
+                               if (!strncmp(obd_name + 3, nidstr,
+                                            delimiter - nidstr)) {
+                                       found = true;
+                                       break;
+                               }
+                               nidstr = delimiter + 1;
+                       }
+                       if (!found)
                                return;
                }
                /* check instance for other types of device (osc/mdc) */
index 23a2b4b..4bf8617 100644 (file)
@@ -265,7 +265,7 @@ static int get_root_path_slow(int want, char *fsname, int *outfd, char *path,
                strncpy(root_cached.mnt_dir, mnt.mnt_dir, mntlen);
                root_cached.mnt_dir[mntlen] = '\0';
                root_cached.dev = devmnt;
-               ptr_end = strchr(mnt.mnt_fsname, ':');
+               ptr_end = strstr(mnt.mnt_fsname, ":/");
                strncpy(root_cached.nid, mnt.mnt_fsname,
                        ptr_end - mnt.mnt_fsname);
                root_cached.nid[ptr_end - mnt.mnt_fsname] = '\0';
index 1c41f35..bdd4015 100644 (file)
@@ -954,9 +954,6 @@ char *convert_hostnames(char *buf, bool mount)
        char *delimiter = buf;
        int left = MAXNIDSTR;
        struct lnet_nid nid;
-       int hex_count = 0;
-       int hex_sections = 0;
-       bool is_ipv6 = true;
 
        converted = malloc(left);
        if (!converted) {
@@ -982,42 +979,8 @@ char *convert_hostnames(char *buf, bool mount)
        /* parse all NIDs */
        while ((left > 0) && (delimiter < end)) {
                int rc;
-               hex_count = 0;
-               hex_sections = 0;
-               is_ipv6 = true;
-
-               /* previous delimiter */
-               if (*delimiter == ',' || *delimiter == ':')
-                       delimiter++;
-
-               /* address parsing */
-               while (*delimiter != ',' && *delimiter != ' ' && *delimiter != '\0') {
-                       /* Need to skip : in IPv6 / GUID NIDs. Lustre also uses
-                        * ':' as a separator, which makes this complicated.
-                        */
-                       if (*delimiter == '@') {
-                               while (*delimiter != ':' && *delimiter != ','
-                                   && *delimiter != ' ' && *delimiter != '\0')
-                                       delimiter++;
-                               break;
-                       }
-                       /* IPv6 addresses are in 0-4 hex digit groups */
-                       else if ((isxdigit(*delimiter) || *delimiter == ':') &&
-                                hex_count <= 4 && is_ipv6) {
-                               if (*delimiter == ':') {
-                                       hex_sections++;
-                                       hex_count = 0;
-                               } else {
-                                       hex_count++;
-                               }
-                       } else { /* NID is not IPv6 */
-                               is_ipv6 = false;
-                               if (*delimiter == ':')
-                                       break;
 
-                       }
-                       delimiter++;
-               }
+               delimiter = cfs_nidstr_find_delimiter(buf);
                /* sets the position of the found delimiter to null
                 * temporarily so when we pass it into parse_nid
                 * or parse_net it only uses the found NID