dcavalca / rpms / mdadm

Forked from rpms/mdadm 3 years ago
Clone

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

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