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

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