]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - sysfs.c
RebuildMap: handle missing disks
[thirdparty/mdadm.git] / sysfs.c
diff --git a/sysfs.c b/sysfs.c
index 00f42ea65722704c14b32e3e888b2a950ea09e83..48d1f54264818097c22ba8322d03e4703e2c19dd 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -81,6 +81,7 @@ int sysfs_open(int devnum, char *devname, char *attr)
 
 void sysfs_init(struct mdinfo *mdi, int fd, int devnum)
 {
+       mdi->sys_name[0] = 0;
        if (fd >= 0) {
                mdu_version_t vers;
                if (ioctl(fd, RAID_VERSION, &vers) != 0)
@@ -118,6 +119,10 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
                return sra;
        memset(sra, 0, sizeof(*sra));
        sysfs_init(sra, fd, devnum);
+       if (sra->sys_name[0] == 0) {
+               free(sra);
+               return NULL;
+       }
 
        sprintf(fname, "/sys/block/%s/md/", sra->sys_name);
        base = fname + strlen(fname);
@@ -267,18 +272,34 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
                        }
                        
                }
-               dev->next = sra->devs;
-               sra->devs = dev;
-
                strcpy(dev->sys_name, de->d_name);
                dev->disk.raid_disk = strtoul(buf, &ep, 10);
                if (*ep) dev->disk.raid_disk = -1;
 
                strcpy(dbase, "block/dev");
-               if (load_sys(fname, buf))
-                       goto abort;
+               if (load_sys(fname, buf)) {
+                       free(dev);
+                       if (options & SKIP_GONE_DEVS)
+                               continue;
+                       else
+                               goto abort;
+               }
                sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
 
+               /* special case check for block devices that can go 'offline' */
+               if (options & SKIP_GONE_DEVS) {
+                       strcpy(dbase, "block/device/state");
+                       if (load_sys(fname, buf) == 0 &&
+                           strncmp(buf, "offline", 7) == 0) {
+                               free(dev);
+                               continue;
+                       }
+               }
+
+               /* finally add this disk to the array */
+               dev->next = sra->devs;
+               sra->devs = dev;
+
                if (options & GET_OFFSET) {
                        strcpy(dbase, "offset");
                        if (load_sys(fname, buf))
@@ -405,6 +426,22 @@ int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev,
        return sysfs_set_str(sra, dev, name, valstr);
 }
 
+int sysfs_uevent(struct mdinfo *sra, char *event)
+{
+       char fname[50];
+       int n;
+       int fd;
+
+       sprintf(fname, "/sys/block/%s/uevent",
+               sra->sys_name);
+       fd = open(fname, O_WRONLY);
+       if (fd < 0)
+               return -1;
+       n = write(fd, event, strlen(event));
+       close(fd);
+       return 0;
+}      
+
 int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
                       char *name, unsigned long long *val)
 {
@@ -469,6 +506,20 @@ int sysfs_set_array(struct mdinfo *info, int vers)
        rv |= sysfs_set_num(info, NULL, "chunk_size", info->array.chunk_size);
        rv |= sysfs_set_num(info, NULL, "layout", info->array.layout);
        rv |= sysfs_set_num(info, NULL, "component_size", info->component_size/2);
+       if (info->custom_array_size) {
+               int rc;
+
+               rc = sysfs_set_num(info, NULL, "array_size",
+                                  info->custom_array_size/2);
+               if (rc && errno == ENOENT) {
+                       fprintf(stderr, Name ": This kernel does not "
+                               "have the md/array_size attribute, "
+                               "the array may be larger than expected\n");
+                       rc = 0;
+               }
+               rv |= rc;
+       }
+
        if (info->array.level > 0)
                rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start);
        return rv;