]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - sysfs.c
Grow: pass INVALID_SECTORS to reshape_array, not 0.
[thirdparty/mdadm.git] / sysfs.c
diff --git a/sysfs.c b/sysfs.c
index 6bc28651fd4f8f81c582eb4d5e98b4de80cdc90a..13558c5fd0516e1c4a19f355a77f5df62b57e924 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -88,7 +88,6 @@ void sysfs_init(struct mdinfo *mdi, int fd, char *devnm)
        strcpy(mdi->sys_name, devnm);
 }
 
-
 struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
 {
        char fname[PATH_MAX];
@@ -96,7 +95,7 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
        char *base;
        char *dbase;
        struct mdinfo *sra;
-       struct mdinfo *dev;
+       struct mdinfo *dev, **devp;
        DIR *dir = NULL;
        struct dirent *de;
 
@@ -235,6 +234,8 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
                goto abort;
        sra->array.spare_disks = 0;
 
+       devp = &sra->devs;
+       sra->devs = NULL;
        while ((de = readdir(dir)) != NULL) {
                char *ep;
                if (de->d_ino == 0 ||
@@ -266,7 +267,7 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
                                free(dev);
                                goto abort;
                        }
-                       
+
                }
                strcpy(dev->sys_name, de->d_name);
                dev->disk.raid_disk = strtoul(buf, &ep, 10);
@@ -292,8 +293,9 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
                }
 
                /* finally add this disk to the array */
-               dev->next = sra->devs;
-               sra->devs = dev;
+               *devp = dev;
+               devp = & dev->next;
+               dev->next = NULL;
 
                if (options & GET_OFFSET) {
                        strcpy(dbase, "offset");
@@ -453,7 +455,7 @@ int sysfs_uevent(struct mdinfo *sra, char *event)
                return -1;
        }
        return 0;
-}      
+}
 
 int sysfs_attribute_available(struct mdinfo *sra, struct mdinfo *dev, char *name)
 {
@@ -511,6 +513,49 @@ int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
        return n;
 }
 
+int sysfs_fd_get_two(int fd, unsigned long long *v1, unsigned long long *v2)
+{
+       /* two numbers in this sysfs file, either
+        *  NNN (NNN)
+        * or
+        *  NNN / NNN
+        */
+       char buf[80];
+       int n;
+       char *ep, *ep2;
+
+       lseek(fd, 0, 0);
+       n = read(fd, buf, sizeof(buf));
+       if (n <= 0)
+               return -2;
+       buf[n] = 0;
+       *v1 = strtoull(buf, &ep, 0);
+       if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
+               return -1;
+       while (*ep == ' ' || *ep == '/' || *ep == '(')
+               ep++;
+       *v2 = strtoull(ep, &ep2, 0);
+       if (ep2 == ep || (*ep2 != 0 && *ep2 != '\n' && *ep2 != ' ' && *ep2 != ')')) {
+               *v2 = *v1;
+               return 1;
+       }
+       return 2;
+}
+
+int sysfs_get_two(struct mdinfo *sra, struct mdinfo *dev,
+                 char *name, unsigned long long *v1, unsigned long long *v2)
+{
+       int n;
+       int fd;
+
+       fd = sysfs_get_fd(sra, dev, name);
+       if (fd < 0)
+               return -1;
+       n = sysfs_fd_get_two(fd, v1, v2);
+       close(fd);
+       return n;
+}
+
 int sysfs_fd_get_str(int fd, char *val, int size)
 {
        int n;
@@ -768,7 +813,6 @@ int sysfs_disk_to_scsi_id(int fd, __u32 *id)
        return 0;
 }
 
-
 int sysfs_unique_holder(char *devnm, long rdev)
 {
        /* Check that devnm is a holder of rdev,
@@ -837,9 +881,41 @@ int sysfs_freeze_array(struct mdinfo *sra)
        if (strcmp(buf, "frozen\n") == 0)
                /* Already frozen */
                return 0;
-       if (strcmp(buf, "idle\n") != 0)
+       if (strcmp(buf, "idle\n") != 0 && strcmp(buf, "recover\n") != 0)
                return -1;
        if (sysfs_set_str(sra, NULL, "sync_action", "frozen") < 0)
                return 0;
        return 1;
 }
+
+int sysfs_wait(int fd, int *msec)
+{
+       /* Wait up to '*msec' for fd to have an exception condition.
+        * if msec == NULL, wait indefinitely.
+        */
+       fd_set fds;
+       int n;
+       FD_ZERO(&fds);
+       FD_SET(fd, &fds);
+       if (msec == NULL)
+               n = select(fd+1, NULL, NULL, &fds, NULL);
+       else if (*msec < 0)
+               n = 0;
+       else {
+               struct timeval start, end, tv;
+               gettimeofday(&start, NULL);
+               if (*msec < 1000) {
+                       tv.tv_sec = 0;
+                       tv.tv_usec = (*msec)*1000;
+               } else {
+                       tv.tv_sec = (*msec)/1000;
+                       tv.tv_usec = 0;
+               }
+               n = select(fd+1, NULL, NULL, &fds, &tv);
+               gettimeofday(&end, NULL);
+               end.tv_sec -= start.tv_sec;
+               *msec -= (end.tv_sec * 1000 + end.tv_usec/1000
+                         - start.tv_usec/1000) + 1;
+       }
+       return n;
+}