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

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