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