]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - sysfs.c
Move calls to SET_ARRAY_INFO to common helper.
[thirdparty/mdadm.git] / sysfs.c
diff --git a/sysfs.c b/sysfs.c
index 8979ec4e23c80fd1812fe6b4f277cc4ad325d923..727e25085471f59563bfa2210370c78b70a3461d 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -25,6 +25,7 @@
 
 #include       "mdadm.h"
 #include       <dirent.h>
+#include       <ctype.h>
 
 int load_sys(char *path, char *buf)
 {
@@ -73,6 +74,29 @@ int sysfs_open(int devnum, char *devname, char *attr)
        return fd;
 }
 
+void sysfs_init(struct mdinfo *mdi, int fd, int devnum)
+{
+       if (fd >= 0) {
+               struct stat stb;
+               mdu_version_t vers;
+               if (fstat(fd, &stb))
+                       return;
+               if (ioctl(fd, RAID_VERSION, &vers) != 0)
+                       return;
+               if (major(stb.st_rdev)==9)
+                       sprintf(mdi->sys_name, "md%d", (int)minor(stb.st_rdev));
+               else
+                       sprintf(mdi->sys_name, "md_d%d",
+                               (int)minor(stb.st_rdev)>>MdpMinorShift);
+       } else {
+               if (devnum >= 0)
+                       sprintf(mdi->sys_name, "md%d", devnum);
+               else
+                       sprintf(mdi->sys_name, "md_d%d",
+                               -1-devnum);
+       }
+}
+
 struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
 {
        /* Longest possible name in sysfs, mounted at /sys, is
@@ -92,26 +116,9 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
        sra = malloc(sizeof(*sra));
        if (sra == NULL)
                return sra;
-       sra->next = NULL;
+       memset(sra, 0, sizeof(*sra));
+       sysfs_init(sra, fd, devnum);
 
-       if (fd >= 0) {
-               struct stat stb;
-               mdu_version_t vers;
-               if (fstat(fd, &stb)) return NULL;
-               if (ioctl(fd, RAID_VERSION, &vers) != 0)
-                       return NULL;
-               if (major(stb.st_rdev)==9)
-                       sprintf(sra->sys_name, "md%d", (int)minor(stb.st_rdev));
-               else
-                       sprintf(sra->sys_name, "md_d%d",
-                               (int)minor(stb.st_rdev)>>MdpMinorShift);
-       } else {
-               if (devnum >= 0)
-                       sprintf(sra->sys_name, "md%d", devnum);
-               else
-                       sprintf(sra->sys_name, "md_d%d",
-                               -1-devnum);
-       }
        sprintf(fname, "/sys/block/%s/md/", sra->sys_name);
        base = fname + strlen(fname);
 
@@ -153,6 +160,12 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
                        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))
@@ -179,6 +192,35 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
                        goto abort;
                sra->mismatch_cnt = strtoul(buf, NULL, 0);
        }
+       if (options & GET_SAFEMODE) {
+               int scale = 1;
+               int dot = 0;
+               int i;
+               unsigned long msec;
+               size_t len;
+
+               strcpy(base, "safe_mode_delay");
+               if (load_sys(fname, buf))
+                       goto abort;
+
+               /* remove a period, and count digits after it */
+               len = strlen(buf);
+               for (i = 0; i < len; i++) {
+                       if (dot) {
+                               if (isdigit(buf[i])) {
+                                       buf[i-1] = buf[i];
+                                       scale *= 10;
+                               }
+                               buf[i] = 0;
+                       } else if (buf[i] == '.') {
+                               dot=1;
+                               buf[i] = 0;
+                       }
+               }
+               msec = strtoul(buf, NULL, 10);
+               msec = (msec * 1000) / scale;
+               sra->safe_mode_delay = msec;
+       }
 
        if (! (options & GET_DEVS))
                return sra;
@@ -202,14 +244,33 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
                dev = malloc(sizeof(*dev));
                if (!dev)
                        goto abort;
-               dev->next = sra->devs;
-               sra->devs = dev;
-               strcpy(dev->sys_name, de->d_name);
 
                /* Always get slot, major, minor */
                strcpy(dbase, "slot");
-               if (load_sys(fname, buf))
-                       goto abort;
+               if (load_sys(fname, buf)) {
+                       /* hmm... unable to read 'slot' maybe the device
+                        * is going away?
+                        */
+                       strcpy(dbase, "block");
+                       if (readlink(fname, buf, sizeof(buf)) < 0 &&
+                           errno != ENAMETOOLONG) {
+                               /* ...yup device is gone */
+                               free(dev);
+                               continue;
+                       } else {
+                               /* slot is unreadable but 'block' link
+                                * still intact... something bad is happening
+                                * so abort
+                                */
+                               free(dev);
+                               goto abort;
+                       }
+                       
+               }
+               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;
 
@@ -259,6 +320,31 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
        return NULL;
 }
 
+int sysfs_attr_match(const char *attr, const char *str)
+{
+       /* See if attr, read from a sysfs file, matches
+        * str.  They must either be the same, or attr can
+        * have a trailing newline or comma
+        */
+       while (*attr && *str && *attr == *str) {
+               attr++;
+               str++;
+       }
+
+       if (*str || (*attr && *attr != ',' && *attr != '\n'))
+               return 0;
+       return 1;
+}
+
+int sysfs_match_word(const char *word, char **list)
+{
+       int n;
+       for (n=0; list[n]; n++)
+               if (sysfs_attr_match(word, list[n]))
+                       break;
+       return n;
+}
+
 unsigned long long get_component_size(int fd)
 {
        /* Find out the component size of the array.
@@ -340,22 +426,47 @@ int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
        return 0;
 }
 
-int sysfs_set_array(struct mdinfo *sra,
-                   struct mdinfo *info)
+int sysfs_set_safemode(struct mdinfo *sra, unsigned long ms)
 {
-       int rv = 0;
-       sra->array = info->array;
+       unsigned long sec;
+       unsigned long msec;
+       char delay[30];
 
+       sec = ms / 1000;
+       msec = ms - (sec * 1000);
+
+       sprintf(delay, "%ld.%ld", sec, msec);
+       return sysfs_set_str(sra, NULL, "safe_mode_delay", delay);
+}
+
+int sysfs_set_array(struct mdinfo *info, int vers)
+{
+       int rv = 0;
+       char ver[100];
+
+       ver[0] = 0;
+       if (info->array.major_version == -1 &&
+           info->array.minor_version == -2) {
+               strcat(strcpy(ver, "external:"), info->text_version);
+
+               if ((vers % 100) < 2 ||
+                   sysfs_set_str(info, NULL, "metadata_version",
+                                 ver) < 0) {
+                       fprintf(stderr, Name ": This kernel does not "
+                               "support external metadata.\n");
+                       return 1;
+               }
+       }
        if (info->array.level < 0)
                return 0; /* FIXME */
-       rv |= sysfs_set_str(sra, NULL, "level",
+       rv |= sysfs_set_str(info, NULL, "level",
                            map_num(pers, info->array.level));
-       rv |= sysfs_set_num(sra, NULL, "raid_disks", info->array.raid_disks);
-       rv |= sysfs_set_num(sra, NULL, "chunk_size", info->array.chunk_size);
-       rv |= sysfs_set_num(sra, NULL, "layout", info->array.layout);
-       rv |= sysfs_set_num(sra, NULL, "component_size", info->component_size/2);
-       rv |= sysfs_set_num(sra, NULL, "resync_start", info->resync_start);
-       sra->array = info->array;
+       rv |= sysfs_set_num(info, NULL, "raid_disks", info->array.raid_disks);
+       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->array.level > 0)
+               rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start);
        return rv;
 }
 
@@ -363,7 +474,6 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd)
 {
        char dv[100];
        char nm[100];
-       struct mdinfo *sd2;
        char *dname;
        int rv;
 
@@ -389,15 +499,10 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd)
                rv |= sysfs_set_num(sra, sd, "slot", sd->disk.raid_disk);
 //             rv |= sysfs_set_str(sra, sd, "state", "in_sync");
        }
-       if (! rv) {
-               sd2 = malloc(sizeof(*sd2));
-               *sd2 = *sd;
-               sd2->next = sra->devs;
-               sra->devs = sd2;
-       }
        return rv;
 }
 
+#if 0
 int sysfs_disk_to_sg(int fd)
 {
        /* from an open block device, try find and open its corresponding
@@ -461,6 +566,7 @@ int sysfs_disk_to_sg(int fd)
 
        return -1;
 }
+#endif
 
 int sysfs_disk_to_scsi_id(int fd, __u32 *id)
 {