]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
mdadm: load default sysfs attributes after assemblation
authorMariusz Dabrowski <mariusz.dabrowski@intel.com>
Wed, 10 Jul 2019 11:38:53 +0000 (13:38 +0200)
committerJes Sorensen <jsorensen@fb.com>
Wed, 10 Jul 2019 20:12:09 +0000 (16:12 -0400)
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
Incremental.c
config.c
mdadm.conf.5
mdadm.h
sysfs.c

index 420c7b3943eabc4cca8611867f77dc67c5b5b953..b2e69144f1a26dc4db168a48ed0d99cd9bb1d78f 100644 (file)
@@ -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)
                               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);
                                        content->array.raid_disks);
-                       fprintf(stderr, "\n");
+                       else {
+                               fprintf(stderr, "\n");
+                               sysfs_rules_apply(mddev, content);
+                       }
                }
 
                if (st->ss->validate_container) {
                }
 
                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) {
                        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");
                        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");
                        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");
                        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)
                if (preexist)
                        fprintf(stderr, " (%d new)", working);
                if (expansion)
index d4d3c353560d8fb4946c8fad1b0840a0de82e0dd..98dbcd920f535a44f8764ee91f72fb4fcb6efea1 100644 (file)
@@ -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");
                        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));
                wait_for(chosen_name, mdfd);
                if (st->ss->external)
                        strcpy(devnm, fd2devnm(mdfd));
index e14eae0cdab31b62b034063fd32ead125bdccc41..7592b2d7aea94a623270fb1029aefd4d54539593 100644 (file)
--- 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,
 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",
 char *keywords[] = {
        [Devices]  = "devices",
        [Array]    = "array",
@@ -93,6 +94,7 @@ char *keywords[] = {
        [AutoMode] = "auto",
        [Policy]   = "policy",
        [PartPolicy]="part-policy",
        [AutoMode] = "auto",
        [Policy]   = "policy",
        [PartPolicy]="part-policy",
+       [Sysfs]    = "sysfs",
        [LTEnd]    = NULL
 };
 
        [LTEnd]    = NULL
 };
 
@@ -764,6 +766,9 @@ void conf_file(FILE *f)
                case PartPolicy:
                        policyline(line, rule_part);
                        break;
                case PartPolicy:
                        policyline(line, rule_part);
                        break;
+               case Sysfs:
+                       sysfsline(line);
+                       break;
                default:
                        pr_err("Unknown keyword %s\n", line);
                }
                default:
                        pr_err("Unknown keyword %s\n", line);
                }
index 47c962ab207125646f1cd7df5db25cacec23cf7a..27dbab18455d145790e502e101b1a02947ef7d13 100644 (file)
@@ -587,6 +587,26 @@ be based on the domain, but with
 appended, when N is the partition number for the partition that was
 found.
 
 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
 .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
 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),
 
 .SH SEE ALSO
 .BR mdadm (8),
diff --git a/mdadm.h b/mdadm.h
index 0fa9e1bd3080de51597ee26898f32f95f8aa3f72..c36d7fdb10f6fd45580e97670df0566df035078c 100644 (file)
--- 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 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
 #if __GNUC__ < 3
 struct stat64;
 #endif
diff --git a/sysfs.c b/sysfs.c
index 2dd9ab63b9ebfd382566866af965fd9ae648e163..c3137818974ed9eb4c031e5aa4a6f6d36c389cfb 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
 #include       "mdadm.h"
 #include       <dirent.h>
 #include       <ctype.h>
 #include       "mdadm.h"
 #include       <dirent.h>
 #include       <ctype.h>
+#include       "dlink.h"
 
 #define MAX_SYSFS_PATH_LEN     120
 
 
 #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);
 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;
 }
        }
        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;
+}