]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - sysfs.c
imsm: set generation number when reading superblock
[thirdparty/mdadm.git] / sysfs.c
diff --git a/sysfs.c b/sysfs.c
index 8379ca83075dfec584c4408b35ad3f3a68d68521..84c7348526c995929a2d7f07b68ee801d3363529 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -27,6 +27,8 @@
 #include       <dirent.h>
 #include       <ctype.h>
 
+#define MAX_SYSFS_PATH_LEN     120
+
 int load_sys(char *path, char *buf, int len)
 {
        int fd = open(path, O_RDONLY);
@@ -50,8 +52,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,15 +63,15 @@ 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);
@@ -259,7 +263,7 @@ 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");
@@ -392,14 +396,17 @@ 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 (fstat(fd, &stb))
+               return 0;
        if (major(stb.st_rdev) != (unsigned)get_mdp_major())
-               sprintf(fname, "/sys/block/md%d/md/component_size",
+               snprintf(fname, MAX_SYSFS_PATH_LEN,
+                       "/sys/block/md%d/md/component_size",
                        (int)minor(stb.st_rdev));
        else
-               sprintf(fname, "/sys/block/md_d%d/md/component_size",
+               snprintf(fname, MAX_SYSFS_PATH_LEN,
+                       "/sys/block/md_d%d/md/component_size",
                        (int)minor(stb.st_rdev)>>MdpMinorShift);
        fd = open(fname, O_RDONLY);
        if (fd < 0)
@@ -415,11 +422,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)
@@ -452,11 +459,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)
@@ -473,10 +480,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;
@@ -485,10 +492,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)
@@ -686,6 +693,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);
@@ -717,6 +725,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;
 }