]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - sysfs.c
Monitor: handle v.quick removal of devices better.
[thirdparty/mdadm.git] / sysfs.c
diff --git a/sysfs.c b/sysfs.c
index c3bbbe32b1fca1ff0a4a6a02a339aafa20cd3632..a7dfcc2966b5eca585d504338a267fc521ad6486 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -90,23 +90,14 @@ void sysfs_init(struct mdinfo *mdi, int fd, int devnum)
        }
        if (devnum == NoMdDev)
                return;
-       if (devnum >= 0)
-               sprintf(mdi->sys_name, "md%d", devnum);
-       else
-               sprintf(mdi->sys_name, "md_d%d",
-                       -1-devnum);
+       fmt_devname(mdi->sys_name, devnum);
 }
 
 
 struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
 {
-       /* Longest possible name in sysfs, mounted at /sys, is
-        *  /sys/block/md_dXXX/md/dev-XXXXX/block/dev
-        *  /sys/block/md_dXXX/md/metadata_version
-        * which is about 41 characters.  50 should do for now
-        */
-       char fname[50];
-       char buf[1024];
+       char fname[PATH_MAX];
+       char buf[PATH_MAX];
        char *base;
        char *dbase;
        struct mdinfo *sra;
@@ -200,7 +191,7 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
        if (options & GET_SAFEMODE) {
                int scale = 1;
                int dot = 0;
-               int i;
+               unsigned i;
                unsigned long msec;
                size_t len;
 
@@ -278,22 +269,20 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
 
                strcpy(dbase, "block/dev");
                if (load_sys(fname, buf)) {
+                       /* assume this is a stale reference to a hot
+                        * removed device
+                        */
                        free(dev);
-                       if (options & SKIP_GONE_DEVS)
-                               continue;
-                       else
-                               goto abort;
+                       continue;
                }
                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;
-                       }
+               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 */
@@ -379,7 +368,7 @@ unsigned long long get_component_size(int fd)
        char fname[50];
        int n;
        if (fstat(fd, &stb)) return 0;
-       if (major(stb.st_rdev) != get_mdp_major())
+       if (major(stb.st_rdev) != (unsigned)get_mdp_major())
                sprintf(fname, "/sys/block/md%d/md/component_size",
                        (int)minor(stb.st_rdev));
        else
@@ -400,7 +389,7 @@ int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
                  char *name, char *val)
 {
        char fname[50];
-       int n;
+       unsigned int n;
        int fd;
 
        sprintf(fname, "/sys/block/%s/md/%s/%s",
@@ -442,6 +431,17 @@ int sysfs_uevent(struct mdinfo *sra, char *event)
        return 0;
 }      
 
+int sysfs_attribute_available(struct mdinfo *sra, struct mdinfo *dev, char *name)
+{
+       char fname[50];
+       struct stat st;
+
+       sprintf(fname, "/sys/block/%s/md/%s/%s",
+               sra->sys_name, dev?dev->sys_name:"", name);
+
+       return stat(fname, &st) == 0;
+}
+
 int sysfs_get_fd(struct mdinfo *sra, struct mdinfo *dev,
                       char *name)
 {
@@ -569,13 +569,25 @@ int sysfs_set_array(struct mdinfo *info, int vers)
 
        if (info->array.level > 0)
                rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start);
+
+       if (info->reshape_active) {
+               rv |= sysfs_set_num(info, NULL, "reshape_position",
+                                   info->reshape_progress);
+               rv |= sysfs_set_num(info, NULL, "chunk_size", info->new_chunk);
+               rv |= sysfs_set_num(info, NULL, "layout", info->new_layout);
+               rv |= sysfs_set_num(info, NULL, "raid_disks",
+                                   info->array.raid_disks + info->delta_disks);
+               /* We don't set 'new_level' here.  That can only happen
+                * once the reshape completes.
+                */
+       }
        return rv;
 }
 
 int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
 {
-       char dv[100];
-       char nm[100];
+       char dv[PATH_MAX];
+       char nm[PATH_MAX];
        char *dname;
        int rv;
 
@@ -610,7 +622,8 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
                         * yet, so just ignore status for now.
                         */
                        sysfs_set_str(sra, sd, "state", "insync");
-               rv |= sysfs_set_num(sra, sd, "slot", sd->disk.raid_disk);
+               if (sd->disk.raid_disk >= 0)
+                       rv |= sysfs_set_num(sra, sd, "slot", sd->disk.raid_disk);
                if (resume)
                        sysfs_set_num(sra, sd, "recovery_start", sd->recovery_start);
        }
@@ -695,7 +708,7 @@ int sysfs_disk_to_scsi_id(int fd, __u32 *id)
        if (fstat(fd, &st))
                return 1;
 
-       snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device",
+       snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device/scsi_device",
                 major(st.st_rdev), minor(st.st_rdev));
 
        dir = opendir(path);
@@ -704,8 +717,7 @@ int sysfs_disk_to_scsi_id(int fd, __u32 *id)
 
        de = readdir(dir);
        while (de) {
-               if (strncmp("scsi_disk:", de->d_name,
-                           strlen("scsi_disk:")) == 0)
+               if (strchr(de->d_name, ':'))
                        break;
                de = readdir(dir);
        }
@@ -714,21 +726,20 @@ int sysfs_disk_to_scsi_id(int fd, __u32 *id)
        if (!de)
                return 1;
 
-       c1 = strchr(de->d_name, ':');
-       c1++;
+       c1 = de->d_name;
        c2 = strchr(c1, ':');
        *c2 = '\0';
        *id = strtol(c1, NULL, 10) << 24; /* host */
        c1 = c2 + 1;
        c2 = strchr(c1, ':');
        *c2 = '\0';
-       *id |= strtol(c1, NULL, 10) << 16; /* channel */
+       *id |= strtol(c1, NULL, 10) << 16; /* bus */
        c1 = c2 + 1;
        c2 = strchr(c1, ':');
        *c2 = '\0';
-       *id |= strtol(c1, NULL, 10) << 8; /* lun */
+       *id |= strtol(c1, NULL, 10) << 8; /* target */
        c1 = c2 + 1;
-       *id |= strtol(c1, NULL, 10); /* id */
+       *id |= strtol(c1, NULL, 10); /* lun */
 
        return 0;
 }
@@ -796,6 +807,28 @@ int sysfs_unique_holder(int devnum, long rdev)
                return found;
 }
 
+int sysfs_freeze_array(struct mdinfo *sra)
+{
+       /* Try to freeze resync/rebuild on this array/container.
+        * Return -1 if the array is busy,
+        * return -2 container cannot be frozen,
+        * return 0 if this kernel doesn't support 'frozen'
+        * return 1 if it worked.
+        */
+       char buf[20];
+
+       if (!sysfs_attribute_available(sra, NULL, "sync_action"))
+               return 1; /* no sync_action == frozen */
+       if (sysfs_get_str(sra, NULL, "sync_action", buf, 20) <= 0)
+               return 0;
+       if (strcmp(buf, "idle\n") != 0 &&
+           strcmp(buf, "frozen\n") != 0)
+               return -1;
+       if (sysfs_set_str(sra, NULL, "sync_action", "frozen") < 0)
+               return 0;
+       return 1;
+}
+
 #ifndef MDASSEMBLE
 
 static char *clean_states[] = {
@@ -857,9 +890,6 @@ int WaitClean(char *dev, int sock, int verbose)
                tm.tv_sec = 5;
                tm.tv_usec = 0;
 
-               /* give mdmon a chance to checkpoint resync */
-               sysfs_set_str(mdi, NULL, "sync_action", "idle");
-
                FD_ZERO(&fds);
 
                /* wait for array_state to be clean */