]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - mdstat.c
imsm: Remove --dump/--restore implementation
[thirdparty/mdadm.git] / mdstat.c
index 3bb74fa27410c48feb6a0cad285da1ce23388852..7e600d0cb03a7d072978226f5cd5cdab3a51f992 100644 (file)
--- a/mdstat.c
+++ b/mdstat.c
@@ -94,26 +94,26 @@ static void free_member_devnames(struct dev_member *m)
        }
 }
 
-static void add_member_devname(struct dev_member **m, char *name)
+static int add_member_devname(struct dev_member **m, char *name)
 {
        struct dev_member *new;
        char *t;
 
        if ((t = strchr(name, '[')) == NULL)
                /* not a device */
-               return;
+               return 0;
 
-       new = malloc(sizeof(*new));
+       new = xmalloc(sizeof(*new));
        new->name = strndup(name, t - name);
        new->next = *m;
        *m = new;
+       return 1;
 }
 
 void free_mdstat(struct mdstat_ent *ms)
 {
        while (ms) {
                struct mdstat_ent *t;
-               free(ms->dev);
                free(ms->level);
                free(ms->pattern);
                free(ms->metadata_version);
@@ -130,10 +130,19 @@ struct mdstat_ent *mdstat_read(int hold, int start)
        FILE *f;
        struct mdstat_ent *all, *rv, **end, **insert_here;
        char *line;
+       int fd;
 
        if (hold && mdstat_fd != -1) {
-               lseek(mdstat_fd, 0L, 0);
-               f = fdopen(dup(mdstat_fd), "r");
+               off_t offset = lseek(mdstat_fd, 0L, 0);
+               if (offset == (off_t)-1) {
+                       mdstat_close();
+                       return NULL;
+               }
+               fd = dup(mdstat_fd);
+               if (fd >= 0)
+                       f = fdopen(fd, "r");
+               else
+                       return NULL;
        } else
                f = fopen("/proc/mdstat", "r");
        if (f == NULL)
@@ -146,106 +155,109 @@ struct mdstat_ent *mdstat_read(int hold, int start)
        for (; (line = conf_line(f)) ; free_line(line)) {
                struct mdstat_ent *ent;
                char *w;
-               int devnum;
+               char devnm[32];
                int in_devs = 0;
-               char *ep;
 
-               if (strcmp(line, "Personalities")==0)
+               if (strcmp(line, "Personalities") == 0)
                        continue;
-               if (strcmp(line, "read_ahead")==0)
+               if (strcmp(line, "read_ahead") == 0)
                        continue;
-               if (strcmp(line, "unused")==0)
+               if (strcmp(line, "unused") == 0)
                        continue;
                insert_here = NULL;
                /* Better be an md line.. */
-               if (strncmp(line, "md", 2)!= 0)
-                       continue;
-               if (strncmp(line, "md_d", 4) == 0)
-                       devnum = -1-strtoul(line+4, &ep, 10);
-               else if (strncmp(line, "md", 2) == 0)
-                       devnum = strtoul(line+2, &ep, 10);
-               else
+               if (strncmp(line, "md", 2)!= 0 || strlen(line) >= 32 ||
+                   (line[2] != '_' && !isdigit(line[2])))
                        continue;
-               if (ep == NULL || *ep ) {
-                       /* fprintf(stderr, Name ": bad /proc/mdstat line starts: %s\n", line); */
-                       continue;
-               }
+               strcpy(devnm, line);
 
-               ent = malloc(sizeof(*ent));
-               if (!ent) {
-                       fprintf(stderr, Name ": malloc failed reading /proc/mdstat.\n");
-                       free_line(line);
-                       break;
-               }
-               ent->dev = ent->level = ent->pattern= NULL;
+               ent = xmalloc(sizeof(*ent));
+               ent->level = ent->pattern= NULL;
                ent->next = NULL;
-               ent->percent = -1;
+               ent->percent = RESYNC_NONE;
                ent->active = -1;
                ent->resync = 0;
                ent->metadata_version = NULL;
                ent->raid_disks = 0;
-               ent->chunk_size = 0;
                ent->devcnt = 0;
                ent->members = NULL;
 
-               ent->dev = strdup(line);
-               ent->devnum = devnum;
+               strcpy(ent->devnm, devnm);
 
                for (w=dl_next(line); w!= line ; w=dl_next(w)) {
                        int l = strlen(w);
                        char *eq;
-                       if (strcmp(w, "active")==0)
+                       if (strcmp(w, "active") == 0)
                                ent->active = 1;
-                       else if (strcmp(w, "inactive")==0) {
+                       else if (strcmp(w, "inactive") == 0) {
                                ent->active = 0;
                                in_devs = 1;
                        } else if (ent->active > 0 &&
                                 ent->level == NULL &&
                                 w[0] != '(' /*readonly*/) {
-                               ent->level = strdup(w);
+                               ent->level = xstrdup(w);
                                in_devs = 1;
-                       } else if (in_devs && strcmp(w, "blocks")==0)
+                       } else if (in_devs && strcmp(w, "blocks") == 0)
                                in_devs = 0;
                        else if (in_devs) {
-                               ent->devcnt++;
-                               add_member_devname(&ent->members, w);
-                               if (strncmp(w, "md", 2)==0) {
+                               char *ep = strchr(w, '[');
+                               ent->devcnt +=
+                                       add_member_devname(&ent->members, w);
+                               if (ep && strncmp(w, "md", 2) == 0) {
                                        /* This has an md device as a component.
                                         * If that device is already in the
                                         * list, make sure we insert before
                                         * there.
                                         */
                                        struct mdstat_ent **ih;
-                                       int dn2 = devname2devnum(w);
                                        ih = &all;
                                        while (ih != insert_here && *ih &&
-                                              (*ih)->devnum != dn2)
+                                              ((int)strlen((*ih)->devnm) !=
+                                               ep-w ||
+                                               strncmp((*ih)->devnm, w,
+                                                       ep-w) != 0))
                                                ih = & (*ih)->next;
                                        insert_here = ih;
                                }
                        } else if (strcmp(w, "super") == 0 &&
                                   dl_next(w) != line) {
                                w = dl_next(w);
-                               ent->metadata_version = strdup(w);
+                               ent->metadata_version = xstrdup(w);
                        } else if (w[0] == '[' && isdigit(w[1])) {
                                ent->raid_disks = atoi(w+1);
                        } else if (!ent->pattern &&
-                                w[0] == '[' &&
-                                (w[1] == 'U' || w[1] == '_')) {
-                               ent->pattern = strdup(w+1);
-                               if (ent->pattern[l-2]==']')
+                                  w[0] == '[' &&
+                                  (w[1] == 'U' || w[1] == '_')) {
+                               ent->pattern = xstrdup(w+1);
+                               if (ent->pattern[l-2] == ']')
                                        ent->pattern[l-2] = '\0';
-                       } else if (ent->percent == -1 &&
-                                  strncmp(w, "re", 2)== 0 &&
+                       } else if (ent->percent == RESYNC_NONE &&
+                                  strncmp(w, "re", 2) == 0 &&
                                   w[l-1] == '%' &&
-                                  (eq=strchr(w, '=')) != NULL ) {
+                                  (eq = strchr(w, '=')) != NULL ) {
                                ent->percent = atoi(eq+1);
-                               if (strncmp(w,"resync", 4)==0)
+                               if (strncmp(w,"resync", 6) == 0)
                                        ent->resync = 1;
-                       } else if (ent->percent == -1 &&
-                                  strncmp(w, "resync", 4)==0) {
-                               ent->resync = 1;
-                       } else if (ent->percent == -1 &&
+                               else if (strncmp(w, "reshape", 7) == 0)
+                                       ent->resync = 2;
+                               else
+                                       ent->resync = 0;
+                       } else if (ent->percent == RESYNC_NONE &&
+                                  (w[0] == 'r' || w[0] == 'c')) {
+                               if (strncmp(w, "resync", 6) == 0)
+                                       ent->resync = 1;
+                               if (strncmp(w, "reshape", 7) == 0)
+                                       ent->resync = 2;
+                               if (strncmp(w, "recovery", 8) == 0)
+                                       ent->resync = 0;
+                               if (strncmp(w, "check", 5) == 0)
+                                       ent->resync = 3;
+
+                               if (l > 8 && strcmp(w+l-8, "=DELAYED") == 0)
+                                       ent->percent = RESYNC_DELAYED;
+                               if (l > 8 && strcmp(w+l-8, "=PENDING") == 0)
+                                       ent->percent = RESYNC_PENDING;
+                       } else if (ent->percent == RESYNC_NONE &&
                                   w[0] >= '0' &&
                                   w[0] <= '9' &&
                                   w[l-1] == '%') {
@@ -277,10 +289,18 @@ struct mdstat_ent *mdstat_read(int hold, int start)
                        e->next = rv;
                        rv = e;
                }
-       } else rv = all;
+       } else
+               rv = all;
        return rv;
 }
 
+void mdstat_close(void)
+{
+       if (mdstat_fd >= 0)
+               close(mdstat_fd);
+       mdstat_fd = -1;
+}
+
 void mdstat_wait(int seconds)
 {
        fd_set fds;
@@ -329,13 +349,13 @@ void mdstat_wait_fd(int fd, const sigset_t *sigmask)
                NULL, sigmask);
 }
 
-int mddev_busy(int devnum)
+int mddev_busy(char *devnm)
 {
        struct mdstat_ent *mdstat = mdstat_read(0, 0);
        struct mdstat_ent *me;
 
        for (me = mdstat ; me ; me = me->next)
-               if (me->devnum == devnum)
+               if (strcmp(me->devnm, devnm) == 0)
                        break;
        free_mdstat(mdstat);
        return me != NULL;
@@ -367,3 +387,35 @@ struct mdstat_ent *mdstat_by_component(char *name)
        }
        return NULL;
 }
+
+struct mdstat_ent *mdstat_by_subdev(char *subdev, char *container)
+{
+       struct mdstat_ent *mdstat = mdstat_read(0, 0);
+       struct mdstat_ent *ent = NULL;
+
+       while (mdstat) {
+               /* metadata version must match:
+                *   external:[/-]%s/%s
+                * where first %s is 'container' and second %s is 'subdev'
+                */
+               if (ent)
+                       free_mdstat(ent);
+               ent = mdstat;
+               mdstat = mdstat->next;
+               ent->next = NULL;
+
+               if (ent->metadata_version == NULL ||
+                   strncmp(ent->metadata_version, "external:", 9) != 0)
+                       continue;
+
+               if (!metadata_container_matches(ent->metadata_version+9,
+                                              container) ||
+                   !metadata_subdev_matches(ent->metadata_version+9,
+                                            subdev))
+                       continue;
+
+               free_mdstat(mdstat);
+               return ent;
+       }
+       return NULL;
+}