dcavalca / rpms / mdadm

Forked from rpms/mdadm 3 years ago
Clone

Blame SOURCES/0003-policy-support-devices-with-multiple-paths.patch

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