diff options
Diffstat (limited to 'debian/patches/0003-policy-support-devices-with-multiple-paths.patch')
-rw-r--r-- | debian/patches/0003-policy-support-devices-with-multiple-paths.patch | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/debian/patches/0003-policy-support-devices-with-multiple-paths.patch b/debian/patches/0003-policy-support-devices-with-multiple-paths.patch new file mode 100644 index 00000000..a3776382 --- /dev/null +++ b/debian/patches/0003-policy-support-devices-with-multiple-paths.patch @@ -0,0 +1,334 @@ +From cd72f9d114da206baa01fd56ff2d8ffcc08f3239 Mon Sep 17 00:00:00 2001 +From: NeilBrown <neilb@suse.com> +Date: Fri, 9 Nov 2018 17:12:33 +1100 +Subject: [PATCH 03/11] policy: support devices with multiple paths. + +As new releases of Linux some time change the name of +a path, some distros keep "legacy" names as well. This +is useful, but confuses mdadm which assumes each device has +precisely one path. + +So change this assumption: allow a disk to have several +paths, and allow any to match when looking for a policy +which matches a disk. + +Reported-and-tested-by: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com> +Signed-off-by: NeilBrown <neilb@suse.com> +Signed-off-by: Jes Sorensen <jsorensen@fb.com> +--- + Incremental.c | 5 +- + mdadm.h | 2 +- + policy.c | 163 ++++++++++++++++++++++++++++---------------------- + 3 files changed, 95 insertions(+), 75 deletions(-) + +diff --git a/Incremental.c b/Incremental.c +index a4ff7d4b..d4d3c353 100644 +--- a/Incremental.c ++++ b/Incremental.c +@@ -1080,6 +1080,7 @@ static int partition_try_spare(char *devname, int *dfdp, struct dev_policy *pol, + struct supertype *st2 = NULL; + char *devname = NULL; + unsigned long long devsectors; ++ char *pathlist[2]; + + if (de->d_ino == 0 || de->d_name[0] == '.' || + (de->d_type != DT_LNK && de->d_type != DT_UNKNOWN)) +@@ -1094,7 +1095,9 @@ static int partition_try_spare(char *devname, int *dfdp, struct dev_policy *pol, + /* This is a partition - skip it */ + goto next; + +- pol2 = path_policy(de->d_name, type_disk); ++ pathlist[0] = de->d_name; ++ pathlist[1] = NULL; ++ pol2 = path_policy(pathlist, type_disk); + + domain_merge(&domlist, pol2, st ? st->ss->name : NULL); + if (domain_test(domlist, pol, st ? st->ss->name : NULL) != 1) +diff --git a/mdadm.h b/mdadm.h +index 387e681a..705bd9b5 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1247,7 +1247,7 @@ extern void policyline(char *line, char *type); + extern void policy_add(char *type, ...); + extern void policy_free(void); + +-extern struct dev_policy *path_policy(char *path, char *type); ++extern struct dev_policy *path_policy(char **paths, char *type); + extern struct dev_policy *disk_policy(struct mdinfo *disk); + extern struct dev_policy *devid_policy(int devid); + extern void dev_policy_free(struct dev_policy *p); +diff --git a/policy.c b/policy.c +index 258f3931..fa67d559 100644 +--- a/policy.c ++++ b/policy.c +@@ -189,15 +189,17 @@ struct dev_policy *pol_find(struct dev_policy *pol, char *name) + return pol; + } + +-static char *disk_path(struct mdinfo *disk) ++static char **disk_paths(struct mdinfo *disk) + { + struct stat stb; + int prefix_len; + DIR *by_path; + char symlink[PATH_MAX] = "/dev/disk/by-path/"; +- char nm[PATH_MAX]; ++ char **paths; ++ int cnt = 0; + struct dirent *ent; +- int rv; ++ ++ paths = xmalloc(sizeof(*paths) * (cnt+1)); + + by_path = opendir(symlink); + if (by_path) { +@@ -214,22 +216,13 @@ static char *disk_path(struct mdinfo *disk) + continue; + if (stb.st_rdev != makedev(disk->disk.major, disk->disk.minor)) + continue; +- closedir(by_path); +- return xstrdup(ent->d_name); ++ paths[cnt++] = xstrdup(ent->d_name); ++ paths = xrealloc(paths, sizeof(*paths) * (cnt+1)); + } + closedir(by_path); + } +- /* A NULL path isn't really acceptable - use the devname.. */ +- sprintf(symlink, "/sys/dev/block/%d:%d", disk->disk.major, disk->disk.minor); +- rv = readlink(symlink, nm, sizeof(nm)-1); +- if (rv > 0) { +- char *dname; +- nm[rv] = 0; +- dname = strrchr(nm, '/'); +- if (dname) +- return xstrdup(dname + 1); +- } +- return xstrdup("unknown"); ++ paths[cnt] = NULL; ++ return paths; + } + + char type_part[] = "part"; +@@ -246,18 +239,53 @@ static char *disk_type(struct mdinfo *disk) + return type_disk; + } + +-static int pol_match(struct rule *rule, char *path, char *type) ++static int path_has_part(char *path, char **part) ++{ ++ /* check if path ends with "-partNN" and ++ * if it does, place a pointer to "-pathNN" ++ * in 'part'. ++ */ ++ int l; ++ if (!path) ++ return 0; ++ l = strlen(path); ++ while (l > 1 && isdigit(path[l-1])) ++ l--; ++ if (l < 5 || strncmp(path+l-5, "-part", 5) != 0) ++ return 0; ++ *part = path+l-5; ++ return 1; ++} ++ ++static int pol_match(struct rule *rule, char **paths, char *type, char **part) + { +- /* check if this rule matches on path and type */ ++ /* Check if this rule matches on any path and type. ++ * If 'part' is not NULL, then 'path' must end in -partN, which ++ * we ignore for matching, and return in *part on success. ++ */ + int pathok = 0; /* 0 == no path, 1 == match, -1 == no match yet */ + int typeok = 0; + +- while (rule) { ++ for (; rule; rule = rule->next) { + if (rule->name == rule_path) { ++ char *p; ++ int i; + if (pathok == 0) + pathok = -1; +- if (path && fnmatch(rule->value, path, 0) == 0) +- pathok = 1; ++ if (!paths) ++ continue; ++ for (i = 0; paths[i]; i++) { ++ if (part) { ++ if (!path_has_part(paths[i], &p)) ++ continue; ++ *p = '\0'; ++ *part = p+1; ++ } ++ if (fnmatch(rule->value, paths[i], 0) == 0) ++ pathok = 1; ++ if (part) ++ *p = '-'; ++ } + } + if (rule->name == rule_type) { + if (typeok == 0) +@@ -265,7 +293,6 @@ static int pol_match(struct rule *rule, char *path, char *type) + if (type && strcmp(rule->value, type) == 0) + typeok = 1; + } +- rule = rule->next; + } + return pathok >= 0 && typeok >= 0; + } +@@ -286,24 +313,6 @@ static void pol_merge(struct dev_policy **pol, struct rule *rule) + pol_new(pol, r->name, r->value, metadata); + } + +-static int path_has_part(char *path, char **part) +-{ +- /* check if path ends with "-partNN" and +- * if it does, place a pointer to "-pathNN" +- * in 'part'. +- */ +- int l; +- if (!path) +- return 0; +- l = strlen(path); +- while (l > 1 && isdigit(path[l-1])) +- l--; +- if (l < 5 || strncmp(path+l-5, "-part", 5) != 0) +- return 0; +- *part = path+l-5; +- return 1; +-} +- + static void pol_merge_part(struct dev_policy **pol, struct rule *rule, char *part) + { + /* copy any name assignments from rule into pol, appending +@@ -352,7 +361,7 @@ static int config_rules_has_path = 0; + * path_policy() gathers policy information for the + * disk described in the given a 'path' and a 'type'. + */ +-struct dev_policy *path_policy(char *path, char *type) ++struct dev_policy *path_policy(char **paths, char *type) + { + struct pol_rule *rules; + struct dev_policy *pol = NULL; +@@ -361,27 +370,24 @@ struct dev_policy *path_policy(char *path, char *type) + rules = config_rules; + + while (rules) { +- char *part; ++ char *part = NULL; + if (rules->type == rule_policy) +- if (pol_match(rules->rule, path, type)) ++ if (pol_match(rules->rule, paths, type, NULL)) + pol_merge(&pol, rules->rule); + if (rules->type == rule_part && strcmp(type, type_part) == 0) +- if (path_has_part(path, &part)) { +- *part = 0; +- if (pol_match(rules->rule, path, type_disk)) +- pol_merge_part(&pol, rules->rule, part+1); +- *part = '-'; +- } ++ if (pol_match(rules->rule, paths, type_disk, &part)) ++ pol_merge_part(&pol, rules->rule, part); + rules = rules->next; + } + + /* Now add any metadata-specific internal knowledge + * about this path + */ +- for (i=0; path && superlist[i]; i++) ++ for (i=0; paths[0] && superlist[i]; i++) + if (superlist[i]->get_disk_controller_domain) { + const char *d = +- superlist[i]->get_disk_controller_domain(path); ++ superlist[i]->get_disk_controller_domain( ++ paths[0]); + if (d) + pol_new(&pol, pol_domain, d, superlist[i]->name); + } +@@ -400,22 +406,34 @@ void pol_add(struct dev_policy **pol, + pol_dedup(*pol); + } + ++static void free_paths(char **paths) ++{ ++ int i; ++ ++ if (!paths) ++ return; ++ ++ for (i = 0; paths[i]; i++) ++ free(paths[i]); ++ free(paths); ++} ++ + /* + * disk_policy() gathers policy information for the + * disk described in the given mdinfo (disk.{major,minor}). + */ + struct dev_policy *disk_policy(struct mdinfo *disk) + { +- char *path = NULL; ++ char **paths = NULL; + char *type = disk_type(disk); + struct dev_policy *pol = NULL; + + if (config_rules_has_path) +- path = disk_path(disk); ++ paths = disk_paths(disk); + +- pol = path_policy(path, type); ++ pol = path_policy(paths, type); + +- free(path); ++ free_paths(paths); + return pol; + } + +@@ -756,27 +774,26 @@ int policy_check_path(struct mdinfo *disk, struct map_ent *array) + { + char path[PATH_MAX]; + FILE *f = NULL; +- char *id_path = disk_path(disk); +- int rv; ++ char **id_paths = disk_paths(disk); ++ int i; ++ int rv = 0; + +- if (!id_path) +- return 0; ++ for (i = 0; id_paths[i]; i++) { ++ snprintf(path, PATH_MAX, FAILED_SLOTS_DIR "/%s", id_paths[i]); ++ f = fopen(path, "r"); ++ if (!f) ++ continue; + +- snprintf(path, PATH_MAX, FAILED_SLOTS_DIR "/%s", id_path); +- f = fopen(path, "r"); +- if (!f) { +- free(id_path); +- return 0; ++ rv = fscanf(f, " %s %x:%x:%x:%x\n", ++ array->metadata, ++ array->uuid, ++ array->uuid+1, ++ array->uuid+2, ++ array->uuid+3); ++ fclose(f); ++ break; + } +- +- rv = fscanf(f, " %s %x:%x:%x:%x\n", +- array->metadata, +- array->uuid, +- array->uuid+1, +- array->uuid+2, +- array->uuid+3); +- fclose(f); +- free(id_path); ++ free_paths(id_paths); + return rv == 5; + } + +-- +2.19.1 + |