* mdstat - parse /proc/mdstat file. Part of:
* mdadm - manage Linux "md" devices aka RAID arrays.
*
- * Copyright (C) 2002-2006 Neil Brown <neilb@suse.de>
+ * Copyright (C) 2002-2009 Neil Brown <neilb@suse.de>
*
*
* This program is free software; you can redistribute it and/or modify
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Neil Brown
- * Email: <neilb@cse.unsw.edu.au>
- * Paper: Neil Brown
- * School of Computer Science and Engineering
- * The University of New South Wales
- * Sydney, 2052
- * Australia
+ * Email: <neilb@suse.de>
*/
/*
#include <sys/select.h>
#include <ctype.h>
+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);
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");
+ fd = dup(mdstat_fd);
+ if (fd >= 0)
+ f = fdopen(fd, "r");
+ else
+ return NULL;
} else
f = fopen("/proc/mdstat", "r");
if (f == NULL)
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;
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);
} 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
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") == 0)
+ ent->percent = PROCESS_DELAYED;
+ if (l > 8 && strcmp(w+l-8, "=PENDING") == 0)
+ ent->percent = PROCESS_PENDING;
} else if (ent->percent == -1 &&
w[0] >= '0' &&
w[0] <= '9' &&
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)
- FD_SET(fd, &rfds);
+
+ if (fd >= 0) {
+ struct stat stb;
+ fstat(fd, &stb);
+ if ((stb.st_mode & S_IFMT) == S_IFREG)
+ /* Must be a /proc or /sys fd, so expect
+ * POLLPRI
+ * i.e. an 'exceptional' event.
+ */
+ FD_SET(fd, &fds);
+ else
+ FD_SET(fd, &rfds);
+
+ if (fd > maxfd)
+ maxfd = fd;
+
+ }
if (mdstat_fd > maxfd)
maxfd = mdstat_fd;
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+12, &pos, 10)
+ == (unsigned)container &&
+ pos > mdstat->metadata_version+12 &&
+ *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;
+}