X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=mdstat.c;h=bac374212e96444ceac9654b360fb9d99fb6a8fa;hb=aad6f216a1c667ddfbb9a4a4c379ff32f69f962f;hp=4d2f473eb09a5b4714dda91fad6c222609c866b2;hpb=ca4f89a3b76187dcd7ca897035a8e92ab67b252d;p=thirdparty%2Fmdadm.git diff --git a/mdstat.c b/mdstat.c index 4d2f473e..bac37421 100644 --- a/mdstat.c +++ b/mdstat.c @@ -83,14 +83,42 @@ #include #include +static void free_member_devnames(struct dev_member *m) +{ + while(m) { + struct dev_member *t = m; + + m = m->next; + free(t->name); + free(t); + } +} + +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 0; + + new = malloc(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; - if (ms->dev) free(ms->dev); - if (ms->level) free(ms->level); - if (ms->pattern) free(ms->pattern); - if (ms->metadata_version) free(ms->metadata_version); + free(ms->dev); + free(ms->level); + free(ms->pattern); + free(ms->metadata_version); + free_member_devnames(ms->members); t = ms; ms = ms->next; free(t); @@ -157,8 +185,8 @@ struct mdstat_ent *mdstat_read(int hold, int start) 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; @@ -168,9 +196,10 @@ struct mdstat_ent *mdstat_read(int hold, int start) char *eq; if (strcmp(w, "active")==0) ent->active = 1; - else if (strcmp(w, "inactive")==0) + else if (strcmp(w, "inactive")==0) { ent->active = 0; - else if (ent->active >=0 && + in_devs = 1; + } else if (ent->active > 0 && ent->level == NULL && w[0] != '(' /*readonly*/) { ent->level = strdup(w); @@ -178,7 +207,8 @@ struct mdstat_ent *mdstat_read(int hold, int start) } else if (in_devs && strcmp(w, "blocks")==0) in_devs = 0; else if (in_devs) { - ent->devcnt++; + ent->devcnt += + add_member_devname(&ent->members, w); if (strncmp(w, "md", 2)==0) { /* This has an md device as a component. * If that device is already in the @@ -210,11 +240,27 @@ struct mdstat_ent *mdstat_read(int hold, int start) w[l-1] == '%' && (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 (strncmp(w, "reshape", 7)==0) + ent->resync = 2; + else + ent->resync = 0; } else if (ent->percent == -1 && - strncmp(w, "resync", 4)==0) { - ent->resync = 1; + (w[0] == 'r' || w[0] == 'c')) { + if (strncmp(w, "resync", 4)==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")) + ent->percent = 0; + if (l > 8 && strcmp(w+l-8, "=PENDING")) + ent->percent = 0; } else if (ent->percent == -1 && w[0] >= '0' && w[0] <= '9' && @@ -269,12 +315,13 @@ void mdstat_wait(int seconds) void mdstat_wait_fd(int fd, const sigset_t *sigmask) { fd_set fds, rfds; - int maxfd = fd; + int maxfd = 0; FD_ZERO(&fds); FD_ZERO(&rfds); if (mdstat_fd >= 0) FD_SET(mdstat_fd, &fds); + if (fd >= 0) { struct stat stb; fstat(fd, &stb); @@ -286,6 +333,10 @@ void mdstat_wait_fd(int fd, const sigset_t *sigmask) FD_SET(fd, &fds); else FD_SET(fd, &rfds); + + if (fd > maxfd) + maxfd = fd; + } if (mdstat_fd > maxfd) maxfd = mdstat_fd; @@ -305,3 +356,63 @@ int mddev_busy(int devnum) free_mdstat(mdstat); return me != NULL; } + +struct mdstat_ent *mdstat_by_component(char *name) +{ + struct mdstat_ent *mdstat = mdstat_read(0, 0); + + while (mdstat) { + struct dev_member *m; + struct mdstat_ent *ent; + if (mdstat->metadata_version && + strncmp(mdstat->metadata_version, "external:", 9) == 0 && + is_subarray(mdstat->metadata_version+9)) + /* don't return subarrays, only containers */ + ; + else for (m = mdstat->members; m; m = m->next) { + if (strcmp(m->name, name) == 0) { + free_mdstat(mdstat->next); + mdstat->next = NULL; + return mdstat; + } + } + ent = mdstat; + mdstat = mdstat->next; + ent->next = NULL; + free_mdstat(ent); + } + return NULL; +} + +struct mdstat_ent *mdstat_by_subdev(char *subdev, int container) +{ + struct mdstat_ent *mdstat = mdstat_read(0, 0); + + while (mdstat) { + struct mdstat_ent *ent; + char *pos; + /* metadata version must match: + * external:[/-]md%d/%s + * where %d is 'container' and %s is 'subdev' + */ + if (mdstat->metadata_version && + strncmp(mdstat->metadata_version, "external:", 9) == 0 && + strchr("/-", mdstat->metadata_version[9]) != NULL && + strncmp(mdstat->metadata_version+10, "md", 2) == 0 && + strtoul(mdstat->metadata_version+11, &pos, 10) + == (unsigned)container && + pos > mdstat->metadata_version+11 && + *pos == '/' && + strcmp(pos+1, subdev) == 0 + ) { + free_mdstat(mdstat->next); + mdstat->next = NULL; + return mdstat; + } + ent = mdstat; + mdstat = mdstat->next; + ent->next = NULL; + free_mdstat(ent); + } + return NULL; +}