summaryrefslogtreecommitdiff
path: root/debian/patches/0003-policy-support-devices-with-multiple-paths.patch
blob: a37763825469a9f1dbda917f007feca814bfd6ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
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