Blame SOURCES/0030-mdadm-load-default-sysfs-attributes-after-assemblati.patch

5d5466
From b06815989179e0f153e44e4336290e655edce9a1 Mon Sep 17 00:00:00 2001
5d5466
From: Mariusz Dabrowski <mariusz.dabrowski@intel.com>
5d5466
Date: Wed, 10 Jul 2019 13:38:53 +0200
5d5466
Subject: [RHEL7.8 PATCH V2 30/47] mdadm: load default sysfs attributes after
5d5466
 assemblation
5d5466
5d5466
Added new type of line to mdadm.conf which allows to specify values of
5d5466
sysfs attributes for MD devices that should be loaded after the array is
5d5466
assembled. Each line is interpreted as list of structures containing
5d5466
sysname of MD device (md126 etc.) and list of sysfs attributes and their
5d5466
values.
5d5466
5d5466
Signed-off-by: Mariusz Dabrowski <mariusz.dabrowski@intel.com>
5d5466
Signed-off-by: Krzysztof Smolinski <krzysztof.smolinski@intel.com>
5d5466
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
5d5466
---
5d5466
 Assemble.c    |  12 +++--
5d5466
 Incremental.c |   1 +
5d5466
 config.c      |   7 ++-
5d5466
 mdadm.conf.5  |  25 ++++++++++
5d5466
 mdadm.h       |   3 ++
5d5466
 sysfs.c       | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5d5466
 6 files changed, 202 insertions(+), 4 deletions(-)
5d5466
5d5466
diff --git a/Assemble.c b/Assemble.c
5d5466
index 420c7b3..b2e6914 100644
5d5466
--- a/Assemble.c
5d5466
+++ b/Assemble.c
5d5466
@@ -1063,9 +1063,12 @@ static int start_array(int mdfd,
5d5466
 			       mddev, okcnt + sparecnt + journalcnt,
5d5466
 			       okcnt + sparecnt + journalcnt == 1 ? "" : "s");
5d5466
 			if (okcnt < (unsigned)content->array.raid_disks)
5d5466
-				fprintf(stderr, " (out of %d)",
5d5466
+				fprintf(stderr, " (out of %d)\n",
5d5466
 					content->array.raid_disks);
5d5466
-			fprintf(stderr, "\n");
5d5466
+			else {
5d5466
+				fprintf(stderr, "\n");
5d5466
+				sysfs_rules_apply(mddev, content);
5d5466
+			}
5d5466
 		}
5d5466
 
5d5466
 		if (st->ss->validate_container) {
5d5466
@@ -1139,6 +1142,7 @@ static int start_array(int mdfd,
5d5466
 			rv = ioctl(mdfd, RUN_ARRAY, NULL);
5d5466
 		reopen_mddev(mdfd); /* drop O_EXCL */
5d5466
 		if (rv == 0) {
5d5466
+			sysfs_rules_apply(mddev, content);
5d5466
 			if (c->verbose >= 0) {
5d5466
 				pr_err("%s has been started with %d drive%s",
5d5466
 				       mddev, okcnt, okcnt==1?"":"s");
5d5466
@@ -2130,10 +2134,12 @@ int assemble_container_content(struct supertype *st, int mdfd,
5d5466
 			pr_err("array %s now has %d device%s",
5d5466
 			       chosen_name, working + preexist,
5d5466
 			       working + preexist == 1 ? "":"s");
5d5466
-		else
5d5466
+		else {
5d5466
+			sysfs_rules_apply(chosen_name, content);
5d5466
 			pr_err("Started %s with %d device%s",
5d5466
 			       chosen_name, working + preexist,
5d5466
 			       working + preexist == 1 ? "":"s");
5d5466
+		}
5d5466
 		if (preexist)
5d5466
 			fprintf(stderr, " (%d new)", working);
5d5466
 		if (expansion)
5d5466
diff --git a/Incremental.c b/Incremental.c
5d5466
index d4d3c35..98dbcd9 100644
5d5466
--- a/Incremental.c
5d5466
+++ b/Incremental.c
5d5466
@@ -480,6 +480,7 @@ int Incremental(struct mddev_dev *devlist, struct context *c,
5d5466
 			pr_err("container %s now has %d device%s\n",
5d5466
 			       chosen_name, info.array.working_disks,
5d5466
 			       info.array.working_disks == 1?"":"s");
5d5466
+		sysfs_rules_apply(chosen_name, &info;;
5d5466
 		wait_for(chosen_name, mdfd);
5d5466
 		if (st->ss->external)
5d5466
 			strcpy(devnm, fd2devnm(mdfd));
5d5466
diff --git a/config.c b/config.c
5d5466
index e14eae0..7592b2d 100644
5d5466
--- a/config.c
5d5466
+++ b/config.c
5d5466
@@ -80,7 +80,8 @@ char DefaultAltConfFile[] = CONFFILE2;
5d5466
 char DefaultAltConfDir[] = CONFFILE2 ".d";
5d5466
 
5d5466
 enum linetype { Devices, Array, Mailaddr, Mailfrom, Program, CreateDev,
5d5466
-		Homehost, HomeCluster, AutoMode, Policy, PartPolicy, LTEnd };
5d5466
+		Homehost, HomeCluster, AutoMode, Policy, PartPolicy, Sysfs,
5d5466
+		LTEnd };
5d5466
 char *keywords[] = {
5d5466
 	[Devices]  = "devices",
5d5466
 	[Array]    = "array",
5d5466
@@ -93,6 +94,7 @@ char *keywords[] = {
5d5466
 	[AutoMode] = "auto",
5d5466
 	[Policy]   = "policy",
5d5466
 	[PartPolicy]="part-policy",
5d5466
+	[Sysfs]    = "sysfs",
5d5466
 	[LTEnd]    = NULL
5d5466
 };
5d5466
 
5d5466
@@ -764,6 +766,9 @@ void conf_file(FILE *f)
5d5466
 		case PartPolicy:
5d5466
 			policyline(line, rule_part);
5d5466
 			break;
5d5466
+		case Sysfs:
5d5466
+			sysfsline(line);
5d5466
+			break;
5d5466
 		default:
5d5466
 			pr_err("Unknown keyword %s\n", line);
5d5466
 		}
5d5466
diff --git a/mdadm.conf.5 b/mdadm.conf.5
5d5466
index 47c962a..27dbab1 100644
5d5466
--- a/mdadm.conf.5
5d5466
+++ b/mdadm.conf.5
5d5466
@@ -587,6 +587,26 @@ be based on the domain, but with
5d5466
 appended, when N is the partition number for the partition that was
5d5466
 found.
5d5466
 
5d5466
+.TP
5d5466
+.B SYSFS
5d5466
+The SYSFS line lists custom values of MD device's sysfs attributes which will be
5d5466
+stored in sysfs after the array is assembled. Multiple lines are allowed and each
5d5466
+line has to contain the uuid or the name of the device to which it relates.
5d5466
+.RS 4
5d5466
+.TP
5d5466
+.B uuid=
5d5466
+hexadecimal identifier of MD device. This has to match the uuid stored in the
5d5466
+superblock.
5d5466
+.TP
5d5466
+.B name=
5d5466
+name of the MD device as was given to
5d5466
+.I mdadm
5d5466
+when the array was created. It will be ignored if
5d5466
+.B uuid
5d5466
+is not empty.
5d5466
+.TP
5d5466
+.RS 7
5d5466
+
5d5466
 .SH EXAMPLE
5d5466
 DEVICE /dev/sd[bcdjkl]1
5d5466
 .br
5d5466
@@ -657,6 +677,11 @@ CREATE group=system mode=0640 auto=part\-8
5d5466
 HOMEHOST <system>
5d5466
 .br
5d5466
 AUTO +1.x homehost \-all
5d5466
+.br
5d5466
+SYSFS name=/dev/md/raid5 group_thread_cnt=4 sync_speed_max=1000000
5d5466
+.br
5d5466
+SYSFS uuid=bead5eb6:31c17a27:da120ba2:7dfda40d group_thread_cnt=4
5d5466
+sync_speed_max=1000000
5d5466
 
5d5466
 .SH SEE ALSO
5d5466
 .BR mdadm (8),
5d5466
diff --git a/mdadm.h b/mdadm.h
5d5466
index 0fa9e1b..c36d7fd 100644
5d5466
--- a/mdadm.h
5d5466
+++ b/mdadm.h
5d5466
@@ -1322,6 +1322,9 @@ void domain_add(struct domainlist **domp, char *domain);
5d5466
 extern void policy_save_path(char *id_path, struct map_ent *array);
5d5466
 extern int policy_check_path(struct mdinfo *disk, struct map_ent *array);
5d5466
 
5d5466
+extern void sysfs_rules_apply(char *devnm, struct mdinfo *dev);
5d5466
+extern void sysfsline(char *line);
5d5466
+
5d5466
 #if __GNUC__ < 3
5d5466
 struct stat64;
5d5466
 #endif
5d5466
diff --git a/sysfs.c b/sysfs.c
5d5466
index 2dd9ab6..c313781 100644
5d5466
--- a/sysfs.c
5d5466
+++ b/sysfs.c
5d5466
@@ -26,9 +26,22 @@
5d5466
 #include	"mdadm.h"
5d5466
 #include	<dirent.h>
5d5466
 #include	<ctype.h>
5d5466
+#include	"dlink.h"
5d5466
 
5d5466
 #define MAX_SYSFS_PATH_LEN	120
5d5466
 
5d5466
+struct dev_sysfs_rule {
5d5466
+	struct dev_sysfs_rule *next;
5d5466
+	char *devname;
5d5466
+	int uuid[4];
5d5466
+	int uuid_set;
5d5466
+	struct sysfs_entry {
5d5466
+		struct sysfs_entry *next;
5d5466
+		char *name;
5d5466
+		char *value;
5d5466
+	} *entry;
5d5466
+};
5d5466
+
5d5466
 int load_sys(char *path, char *buf, int len)
5d5466
 {
5d5466
 	int fd = open(path, O_RDONLY);
5d5466
@@ -999,3 +1012,148 @@ int sysfs_wait(int fd, int *msec)
5d5466
 	}
5d5466
 	return n;
5d5466
 }
5d5466
+
5d5466
+int sysfs_rules_apply_check(const struct mdinfo *sra,
5d5466
+			    const struct sysfs_entry *ent)
5d5466
+{
5d5466
+	/* Check whether parameter is regular file,
5d5466
+	 * exists and is under specified directory.
5d5466
+	 */
5d5466
+	char fname[MAX_SYSFS_PATH_LEN];
5d5466
+	char dname[MAX_SYSFS_PATH_LEN];
5d5466
+	char resolved_path[PATH_MAX];
5d5466
+	char resolved_dir[PATH_MAX];
5d5466
+
5d5466
+	if (sra == NULL || ent == NULL)
5d5466
+		return -1;
5d5466
+
5d5466
+	snprintf(dname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/", sra->sys_name);
5d5466
+	snprintf(fname, MAX_SYSFS_PATH_LEN, "%s/%s", dname, ent->name);
5d5466
+
5d5466
+	if (realpath(fname, resolved_path) == NULL ||
5d5466
+	    realpath(dname, resolved_dir) == NULL)
5d5466
+		return -1;
5d5466
+
5d5466
+	if (strncmp(resolved_dir, resolved_path,
5d5466
+		    strnlen(resolved_dir, PATH_MAX)) != 0)
5d5466
+		return -1;
5d5466
+
5d5466
+	return 0;
5d5466
+}
5d5466
+
5d5466
+static struct dev_sysfs_rule *sysfs_rules;
5d5466
+
5d5466
+void sysfs_rules_apply(char *devnm, struct mdinfo *dev)
5d5466
+{
5d5466
+	struct dev_sysfs_rule *rules = sysfs_rules;
5d5466
+
5d5466
+	while (rules) {
5d5466
+		struct sysfs_entry *ent = rules->entry;
5d5466
+		int match  = 0;
5d5466
+
5d5466
+		if (!rules->uuid_set) {
5d5466
+			if (rules->devname)
5d5466
+				match = strcmp(devnm, rules->devname) == 0;
5d5466
+		} else {
5d5466
+			match = memcmp(dev->uuid, rules->uuid,
5d5466
+				       sizeof(int[4])) == 0;
5d5466
+		}
5d5466
+
5d5466
+		while (match && ent) {
5d5466
+			if (sysfs_rules_apply_check(dev, ent) < 0)
5d5466
+				pr_err("SYSFS: failed to write '%s' to '%s'\n",
5d5466
+					ent->value, ent->name);
5d5466
+			else
5d5466
+				sysfs_set_str(dev, NULL, ent->name, ent->value);
5d5466
+			ent = ent->next;
5d5466
+		}
5d5466
+		rules = rules->next;
5d5466
+	}
5d5466
+}
5d5466
+
5d5466
+static void sysfs_rule_free(struct dev_sysfs_rule *rule)
5d5466
+{
5d5466
+	struct sysfs_entry *entry;
5d5466
+
5d5466
+	while (rule) {
5d5466
+		struct dev_sysfs_rule *tmp = rule->next;
5d5466
+
5d5466
+		entry = rule->entry;
5d5466
+		while (entry) {
5d5466
+			struct sysfs_entry *tmp = entry->next;
5d5466
+
5d5466
+			free(entry->name);
5d5466
+			free(entry->value);
5d5466
+			free(entry);
5d5466
+			entry = tmp;
5d5466
+		}
5d5466
+
5d5466
+		if (rule->devname)
5d5466
+			free(rule->devname);
5d5466
+		free(rule);
5d5466
+		rule = tmp;
5d5466
+	}
5d5466
+}
5d5466
+
5d5466
+void sysfsline(char *line)
5d5466
+{
5d5466
+	struct dev_sysfs_rule *sr;
5d5466
+	char *w;
5d5466
+
5d5466
+	sr = xcalloc(1, sizeof(*sr));
5d5466
+	for (w = dl_next(line); w != line ; w = dl_next(w)) {
5d5466
+		if (strncasecmp(w, "name=", 5) == 0) {
5d5466
+			char *devname = w + 5;
5d5466
+
5d5466
+			if (strncmp(devname, "/dev/md/", 8) == 0) {
5d5466
+				if (sr->devname)
5d5466
+					pr_err("Only give one device per SYSFS line: %s\n",
5d5466
+						devname);
5d5466
+				else
5d5466
+					sr->devname = xstrdup(devname);
5d5466
+			} else {
5d5466
+				pr_err("%s is an invalid name for an md device - ignored.\n",
5d5466
+				       devname);
5d5466
+			}
5d5466
+		} else if (strncasecmp(w, "uuid=", 5) == 0) {
5d5466
+			char *uuid = w + 5;
5d5466
+
5d5466
+			if (sr->uuid_set) {
5d5466
+				pr_err("Only give one uuid per SYSFS line: %s\n",
5d5466
+					uuid);
5d5466
+			} else {
5d5466
+				if (parse_uuid(w + 5, sr->uuid) &&
5d5466
+				    memcmp(sr->uuid, uuid_zero,
5d5466
+					   sizeof(int[4])) != 0)
5d5466
+					sr->uuid_set = 1;
5d5466
+				else
5d5466
+					pr_err("Invalid uuid: %s\n", uuid);
5d5466
+			}
5d5466
+		} else {
5d5466
+			struct sysfs_entry *prop;
5d5466
+
5d5466
+			char *sep = strchr(w, '=');
5d5466
+
5d5466
+			if (sep == NULL || *(sep + 1) == 0) {
5d5466
+				pr_err("Cannot parse \"%s\" - ignoring.\n", w);
5d5466
+				continue;
5d5466
+			}
5d5466
+
5d5466
+			prop = xmalloc(sizeof(*prop));
5d5466
+			prop->value = xstrdup(sep + 1);
5d5466
+			*sep = 0;
5d5466
+			prop->name = xstrdup(w);
5d5466
+			prop->next = sr->entry;
5d5466
+			sr->entry = prop;
5d5466
+		}
5d5466
+	}
5d5466
+
5d5466
+	if (!sr->devname && !sr->uuid_set) {
5d5466
+		pr_err("Device name not found in sysfs config entry - ignoring.\n");
5d5466
+		sysfs_rule_free(sr);
5d5466
+		return;
5d5466
+	}
5d5466
+
5d5466
+	sr->next = sysfs_rules;
5d5466
+	sysfs_rules = sr;
5d5466
+}
5d5466
-- 
5d5466
2.7.5
5d5466