]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - sysfs.c
mdadm: check value returned by snprintf against errors
[thirdparty/mdadm.git] / sysfs.c
diff --git a/sysfs.c b/sysfs.c
index 260034327e3ae852f0683722b052d102b6bb460e..2995713d644d572a447cacdddb1b5b2e043f98a5 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
 #include       "mdadm.h"
 #include       <dirent.h>
 #include       <ctype.h>
-
-int load_sys(char *path, char *buf)
+#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);
        int n;
        if (fd < 0)
                return -1;
-       n = read(fd, buf, 1024);
+       n = read(fd, buf, len);
        close(fd);
-       if (n <0 || n >= 1024)
+       if (n <0 || n >= len)
                return -1;
        buf[n] = 0;
        if (n && buf[n-1] == '\n')
@@ -50,8 +65,10 @@ void sysfs_free(struct mdinfo *sra)
                while (sra->devs) {
                        struct mdinfo *d = sra->devs;
                        sra->devs = d->next;
+                       free(d->bb.entries);
                        free(d);
                }
+               free(sra->bb.entries);
                free(sra);
                sra = sra2;
        }
@@ -59,39 +76,51 @@ void sysfs_free(struct mdinfo *sra)
 
 int sysfs_open(char *devnm, char *devname, char *attr)
 {
-       char fname[50];
+       char fname[MAX_SYSFS_PATH_LEN];
        int fd;
 
-       sprintf(fname, "/sys/block/%s/md/", devnm);
+       snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/", devnm);
        if (devname) {
-               strcat(fname, devname);
-               strcat(fname, "/");
+               strncat(fname, devname, MAX_SYSFS_PATH_LEN - strlen(fname));
+               strncat(fname, "/", MAX_SYSFS_PATH_LEN - strlen(fname));
        }
-       strcat(fname, attr);
+       strncat(fname, attr, MAX_SYSFS_PATH_LEN - strlen(fname));
        fd = open(fname, O_RDWR);
        if (fd < 0 && errno == EACCES)
                fd = open(fname, O_RDONLY);
        return fd;
 }
 
-void sysfs_init_dev(struct mdinfo *mdi, unsigned long devid)
+void sysfs_init_dev(struct mdinfo *mdi, dev_t devid)
 {
        snprintf(mdi->sys_name,
                 sizeof(mdi->sys_name), "dev-%s", devid2kname(devid));
 }
 
-void sysfs_init(struct mdinfo *mdi, int fd, char *devnm)
+int sysfs_init(struct mdinfo *mdi, int fd, char *devnm)
 {
+       struct stat stb;
+       char fname[MAX_SYSFS_PATH_LEN];
+       int retval = -ENODEV;
+
        mdi->sys_name[0] = 0;
-       if (fd >= 0) {
-               mdu_version_t vers;
-               if (ioctl(fd, RAID_VERSION, &vers) != 0)
-                       return;
+       if (fd >= 0)
                devnm = fd2devnm(fd);
-       }
+
        if (devnm == NULL)
-               return;
+               goto out;
+
+       snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md", devnm);
+
+       if (stat(fname, &stb))
+               goto out;
+       if (!S_ISDIR(stb.st_mode))
+               goto out;
        strcpy(mdi->sys_name, devnm);
+
+       retval = 0;
+out:
+       return retval;
 }
 
 struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
@@ -106,8 +135,7 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
        struct dirent *de;
 
        sra = xcalloc(1, sizeof(*sra));
-       sysfs_init(sra, fd, devnm);
-       if (sra->sys_name[0] == 0) {
+       if (sysfs_init(sra, fd, devnm)) {
                free(sra);
                return NULL;
        }
@@ -118,7 +146,7 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
        sra->devs = NULL;
        if (options & GET_VERSION) {
                strcpy(base, "metadata_version");
-               if (load_sys(fname, buf))
+               if (load_sys(fname, buf, sizeof(buf)))
                        goto abort;
                if (strncmp(buf, "none", 4) == 0) {
                        sra->array.major_version =
@@ -137,31 +165,25 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
        }
        if (options & GET_LEVEL) {
                strcpy(base, "level");
-               if (load_sys(fname, buf))
+               if (load_sys(fname, buf, sizeof(buf)))
                        goto abort;
                sra->array.level = map_name(pers, buf);
        }
        if (options & GET_LAYOUT) {
                strcpy(base, "layout");
-               if (load_sys(fname, buf))
+               if (load_sys(fname, buf, sizeof(buf)))
                        goto abort;
                sra->array.layout = strtoul(buf, NULL, 0);
        }
-       if (options & GET_DISKS) {
+       if (options & (GET_DISKS|GET_STATE)) {
                strcpy(base, "raid_disks");
-               if (load_sys(fname, buf))
+               if (load_sys(fname, buf, sizeof(buf)))
                        goto abort;
                sra->array.raid_disks = strtoul(buf, NULL, 0);
        }
-       if (options & GET_DEGRADED) {
-               strcpy(base, "degraded");
-               if (load_sys(fname, buf))
-                       goto abort;
-               sra->array.failed_disks = strtoul(buf, NULL, 0);
-       }
        if (options & GET_COMPONENT) {
                strcpy(base, "component_size");
-               if (load_sys(fname, buf))
+               if (load_sys(fname, buf, sizeof(buf)))
                        goto abort;
                sra->component_size = strtoull(buf, NULL, 0);
                /* sysfs reports "K", but we want sectors */
@@ -169,13 +191,13 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
        }
        if (options & GET_CHUNK) {
                strcpy(base, "chunk_size");
-               if (load_sys(fname, buf))
+               if (load_sys(fname, buf, sizeof(buf)))
                        goto abort;
                sra->array.chunk_size = strtoul(buf, NULL, 0);
        }
        if (options & GET_CACHE) {
                strcpy(base, "stripe_cache_size");
-               if (load_sys(fname, buf))
+               if (load_sys(fname, buf, sizeof(buf)))
                        /* Probably level doesn't support it */
                        sra->cache_size = 0;
                else
@@ -183,7 +205,7 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
        }
        if (options & GET_MISMATCH) {
                strcpy(base, "mismatch_cnt");
-               if (load_sys(fname, buf))
+               if (load_sys(fname, buf, sizeof(buf)))
                        goto abort;
                sra->mismatch_cnt = strtoul(buf, NULL, 0);
        }
@@ -195,7 +217,7 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
                size_t len;
 
                strcpy(base, "safe_mode_delay");
-               if (load_sys(fname, buf))
+               if (load_sys(fname, buf, sizeof(buf)))
                        goto abort;
 
                /* remove a period, and count digits after it */
@@ -218,7 +240,7 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
        }
        if (options & GET_BITMAP_LOCATION) {
                strcpy(base, "bitmap/location");
-               if (load_sys(fname, buf))
+               if (load_sys(fname, buf, sizeof(buf)))
                        goto abort;
                if (strncmp(buf, "file", 4) == 0)
                        sra->bitmap_offset = 1;
@@ -232,10 +254,19 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
 
        if (options & GET_ARRAY_STATE) {
                strcpy(base, "array_state");
-               if (load_sys(fname, sra->sysfs_array_state))
+               if (load_sys(fname, buf, sizeof(buf)))
                        goto abort;
-       } else
-               sra->sysfs_array_state[0] = 0;
+               sra->array_state = map_name(sysfs_array_states, buf);
+       }
+
+       if (options & GET_CONSISTENCY_POLICY) {
+               strcpy(base, "consistency_policy");
+               if (load_sys(fname, buf, sizeof(buf)))
+                       sra->consistency_policy = CONSISTENCY_POLICY_UNKNOWN;
+               else
+                       sra->consistency_policy = map_name(consistency_policies,
+                                                          buf);
+       }
 
        if (! (options & GET_DEVS))
                return sra;
@@ -246,6 +277,9 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
        if (!dir)
                goto abort;
        sra->array.spare_disks = 0;
+       sra->array.active_disks = 0;
+       sra->array.failed_disks = 0;
+       sra->array.working_disks = 0;
 
        devp = &sra->devs;
        sra->devs = NULL;
@@ -258,11 +292,11 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
                dbase = base + strlen(base);
                *dbase++ = '/';
 
-               dev = xmalloc(sizeof(*dev));
+               dev = xcalloc(1, sizeof(*dev));
 
                /* Always get slot, major, minor */
                strcpy(dbase, "slot");
-               if (load_sys(fname, buf)) {
+               if (load_sys(fname, buf, sizeof(buf))) {
                        /* hmm... unable to read 'slot' maybe the device
                         * is going away?
                         */
@@ -286,23 +320,28 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
                dev->disk.raid_disk = strtoul(buf, &ep, 10);
                if (*ep) dev->disk.raid_disk = -1;
 
+               sra->array.nr_disks++;
                strcpy(dbase, "block/dev");
-               if (load_sys(fname, buf)) {
+               if (load_sys(fname, buf, sizeof(buf))) {
                        /* assume this is a stale reference to a hot
                         * removed device
                         */
-                       free(dev);
-                       continue;
+                       if (!(options & GET_DEVS_ALL)) {
+                               free(dev);
+                               continue;
+                       }
+               } else {
+                       sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
                }
-               sra->array.nr_disks++;
-               sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
 
-               /* special case check for block devices that can go 'offline' */
-               strcpy(dbase, "block/device/state");
-               if (load_sys(fname, buf) == 0 &&
-                   strncmp(buf, "offline", 7) == 0) {
-                       free(dev);
-                       continue;
+               if (!(options & GET_DEVS_ALL)) {
+                       /* special case check for block devices that can go 'offline' */
+                       strcpy(dbase, "block/device/state");
+                       if (load_sys(fname, buf, sizeof(buf)) == 0 &&
+                           strncmp(buf, "offline", 7) == 0) {
+                               free(dev);
+                               continue;
+                       }
                }
 
                /* finally add this disk to the array */
@@ -312,40 +351,50 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
 
                if (options & GET_OFFSET) {
                        strcpy(dbase, "offset");
-                       if (load_sys(fname, buf))
+                       if (load_sys(fname, buf, sizeof(buf)))
                                goto abort;
                        dev->data_offset = strtoull(buf, NULL, 0);
                        strcpy(dbase, "new_offset");
-                       if (load_sys(fname, buf) == 0)
+                       if (load_sys(fname, buf, sizeof(buf)) == 0)
                                dev->new_data_offset = strtoull(buf, NULL, 0);
                        else
                                dev->new_data_offset = dev->data_offset;
                }
                if (options & GET_SIZE) {
                        strcpy(dbase, "size");
-                       if (load_sys(fname, buf))
+                       if (load_sys(fname, buf, sizeof(buf)))
                                goto abort;
                        dev->component_size = strtoull(buf, NULL, 0) * 2;
                }
                if (options & GET_STATE) {
                        dev->disk.state = 0;
                        strcpy(dbase, "state");
-                       if (load_sys(fname, buf))
+                       if (load_sys(fname, buf, sizeof(buf)))
                                goto abort;
-                       if (strstr(buf, "in_sync"))
-                               dev->disk.state |= (1<<MD_DISK_SYNC);
                        if (strstr(buf, "faulty"))
                                dev->disk.state |= (1<<MD_DISK_FAULTY);
-                       if (dev->disk.state == 0)
-                               sra->array.spare_disks++;
+                       else {
+                               sra->array.working_disks++;
+                               if (strstr(buf, "in_sync")) {
+                                       dev->disk.state |= (1<<MD_DISK_SYNC);
+                                       sra->array.active_disks++;
+                               }
+                               if (dev->disk.state == 0)
+                                       sra->array.spare_disks++;
+                       }
                }
                if (options & GET_ERROR) {
                        strcpy(buf, "errors");
-                       if (load_sys(fname, buf))
+                       if (load_sys(fname, buf, sizeof(buf)))
                                goto abort;
                        dev->errors = strtoul(buf, NULL, 0);
                }
        }
+
+       if ((options & GET_STATE) && sra->array.raid_disks)
+               sra->array.failed_disks = sra->array.raid_disks -
+                       sra->array.active_disks - sra->array.spare_disks;
+
        closedir(dir);
        return sra;
 
@@ -391,15 +440,12 @@ unsigned long long get_component_size(int fd)
         * This returns in units of sectors.
         */
        struct stat stb;
-       char fname[50];
+       char fname[MAX_SYSFS_PATH_LEN];
        int n;
-       if (fstat(fd, &stb)) return 0;
-       if (major(stb.st_rdev) != (unsigned)get_mdp_major())
-               sprintf(fname, "/sys/block/md%d/md/component_size",
-                       (int)minor(stb.st_rdev));
-       else
-               sprintf(fname, "/sys/block/md_d%d/md/component_size",
-                       (int)minor(stb.st_rdev)>>MdpMinorShift);
+       if (fstat(fd, &stb))
+               return 0;
+       snprintf(fname, MAX_SYSFS_PATH_LEN,
+                "/sys/block/%s/md/component_size", stat2devnm(&stb));
        fd = open(fname, O_RDONLY);
        if (fd < 0)
                return 0;
@@ -414,11 +460,11 @@ unsigned long long get_component_size(int fd)
 int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
                  char *name, char *val)
 {
-       char fname[50];
+       char fname[MAX_SYSFS_PATH_LEN];
        unsigned int n;
        int fd;
 
-       sprintf(fname, "/sys/block/%s/md/%s/%s",
+       snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/%s/%s",
                sra->sys_name, dev?dev->sys_name:"", name);
        fd = open(fname, O_WRONLY);
        if (fd < 0)
@@ -451,11 +497,11 @@ int sysfs_set_num_signed(struct mdinfo *sra, struct mdinfo *dev,
 
 int sysfs_uevent(struct mdinfo *sra, char *event)
 {
-       char fname[50];
+       char fname[MAX_SYSFS_PATH_LEN];
        int n;
        int fd;
 
-       sprintf(fname, "/sys/block/%s/uevent",
+       snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/uevent",
                sra->sys_name);
        fd = open(fname, O_WRONLY);
        if (fd < 0)
@@ -472,10 +518,10 @@ int sysfs_uevent(struct mdinfo *sra, char *event)
 
 int sysfs_attribute_available(struct mdinfo *sra, struct mdinfo *dev, char *name)
 {
-       char fname[50];
+       char fname[MAX_SYSFS_PATH_LEN];
        struct stat st;
 
-       sprintf(fname, "/sys/block/%s/md/%s/%s",
+       snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/%s/%s",
                sra->sys_name, dev?dev->sys_name:"", name);
 
        return stat(fname, &st) == 0;
@@ -484,10 +530,10 @@ int sysfs_attribute_available(struct mdinfo *sra, struct mdinfo *dev, char *name
 int sysfs_get_fd(struct mdinfo *sra, struct mdinfo *dev,
                       char *name)
 {
-       char fname[50];
+       char fname[MAX_SYSFS_PATH_LEN];
        int fd;
 
-       sprintf(fname, "/sys/block/%s/md/%s/%s",
+       snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/%s/%s",
                sra->sys_name, dev?dev->sys_name:"", name);
        fd = open(fname, O_RDWR);
        if (fd < 0)
@@ -676,6 +722,16 @@ int sysfs_set_array(struct mdinfo *info, int vers)
                 * once the reshape completes.
                 */
        }
+
+       if (info->consistency_policy == CONSISTENCY_POLICY_PPL) {
+               if (sysfs_set_str(info, NULL, "consistency_policy",
+                                 map_num(consistency_policies,
+                                         info->consistency_policy))) {
+                       pr_err("This kernel does not support PPL. Falling back to consistency-policy=resync.\n");
+                       info->consistency_policy = CONSISTENCY_POLICY_RESYNC;
+               }
+       }
+
        return rv;
 }
 
@@ -685,6 +741,7 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
        char nm[PATH_MAX];
        char *dname;
        int rv;
+       int i;
 
        sprintf(dv, "%d:%d", sd->disk.major, sd->disk.minor);
        rv = sysfs_set_str(sra, NULL, "new_dev", dv);
@@ -706,6 +763,10 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
        rv = sysfs_set_num(sra, sd, "offset", sd->data_offset);
        rv |= sysfs_set_num(sra, sd, "size", (sd->component_size+1) / 2);
        if (sra->array.level != LEVEL_CONTAINER) {
+               if (sra->consistency_policy == CONSISTENCY_POLICY_PPL) {
+                       rv |= sysfs_set_num(sra, sd, "ppl_sector", sd->ppl_sector);
+                       rv |= sysfs_set_num(sra, sd, "ppl_size", sd->ppl_size);
+               }
                if (sd->recovery_start == MaxSector)
                        /* This can correctly fail if array isn't started,
                         * yet, so just ignore status for now.
@@ -716,6 +777,28 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
                if (resume)
                        sysfs_set_num(sra, sd, "recovery_start", sd->recovery_start);
        }
+       if (sd->bb.supported) {
+               if (sysfs_set_str(sra, sd, "state", "external_bbl")) {
+                       /*
+                        * backward compatibility - if kernel doesn't support
+                        * bad blocks for external metadata, let it continue
+                        * as long as there are none known so far
+                        */
+                       if (sd->bb.count) {
+                               pr_err("The kernel has no support for bad blocks in external metadata\n");
+                               return -1;
+                       }
+               }
+
+               for (i = 0; i < sd->bb.count; i++) {
+                       char s[30];
+                       const struct md_bb_entry *entry = &sd->bb.entries[i];
+
+                       snprintf(s, sizeof(s) - 1, "%llu %d\n", entry->sector,
+                                entry->length);
+                       rv |= sysfs_set_str(sra, sd, "bad_blocks", s);
+               }
+       }
        return rv;
 }
 
@@ -929,3 +1012,156 @@ 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];
+       int result;
+
+       if (sra == NULL || ent == NULL)
+               return -1;
+
+       result = snprintf(dname, MAX_SYSFS_PATH_LEN,
+                         "/sys/block/%s/md/", sra->sys_name);
+       if (result < 0 || result >= MAX_SYSFS_PATH_LEN)
+               return -1;
+
+       result = snprintf(fname, MAX_SYSFS_PATH_LEN,
+                         "%s/%s", dname, ent->name);
+       if (result < 0 || result >= MAX_SYSFS_PATH_LEN)
+               return -1;
+
+       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;
+}