summaryrefslogtreecommitdiff
path: root/debian/patches/0003-policy-support-devices-with-multiple-paths.patch
diff options
context:
space:
mode:
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.patch334
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
+