]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - mdstat.c
Grow: avoid overflow of chunk sizes.
[thirdparty/mdadm.git] / mdstat.c
index a8f7ce7576eb1d017acfe962a1dea48084cde5d2..4a9f370060f36839792dfcd708bf3a23fed72c49 100644 (file)
--- a/mdstat.c
+++ b/mdstat.c
@@ -2,7 +2,7 @@
  * 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>
  */
 
 /*
@@ -86,6 +81,7 @@
 #include       "mdadm.h"
 #include       "dlink.h"
 #include       <sys/select.h>
+#include       <ctype.h>
 
 void free_mdstat(struct mdstat_ent *ms)
 {
@@ -94,6 +90,7 @@ void free_mdstat(struct mdstat_ent *ms)
                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);
                t = ms;
                ms = ms->next;
                free(t);
@@ -158,6 +155,10 @@ struct mdstat_ent *mdstat_read(int hold, int start)
                ent->percent = -1;
                ent->active = -1;
                ent->resync = 0;
+               ent->metadata_version = NULL;
+               ent->raid_disks = 0;
+               ent->chunk_size = 0;
+               ent->devcnt = 0;
 
                ent->dev = strdup(line);
                ent->devnum = devnum;
@@ -176,22 +177,28 @@ struct mdstat_ent *mdstat_read(int hold, int start)
                                in_devs = 1;
                        } else if (in_devs && strcmp(w, "blocks")==0)
                                in_devs = 0;
-                       else if (in_devs && 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;
-                               if (strncmp(w, "md_d", 4)==0)
-                                       dn2 = -1-strtoul(w+4, &ep, 10);
-                               else
-                                       dn2 = strtoul(w+2, &ep, 10);
-                               ih = &all;
-                               while (ih != insert_here && *ih &&
-                                      (*ih)->devnum != dn2)
-                                       ih = & (*ih)->next;
-                               insert_here = ih;
+                       else if (in_devs) {
+                               ent->devcnt++;
+                               if (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)
+                                               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);
+                       } else if (w[0] == '[' && isdigit(w[1])) {
+                               ent->raid_disks = atoi(w+1);
                        } else if (!ent->pattern &&
                                 w[0] == '[' &&
                                 (w[1] == 'U' || w[1] == '_')) {
@@ -248,12 +255,48 @@ void mdstat_wait(int seconds)
 {
        fd_set fds;
        struct timeval tm;
+       int maxfd = 0;
        FD_ZERO(&fds);
-       if (mdstat_fd >= 0)
+       if (mdstat_fd >= 0) {
                FD_SET(mdstat_fd, &fds);
+               maxfd = mdstat_fd;
+       }
        tm.tv_sec = seconds;
        tm.tv_usec = 0;
-       select(mdstat_fd >2 ? mdstat_fd+1:3, NULL, NULL, &fds, &tm);
+       select(maxfd + 1, NULL, NULL, &fds, &tm);
+}
+
+void mdstat_wait_fd(int fd, const sigset_t *sigmask)
+{
+       fd_set fds, rfds;
+       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);
+               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;
+
+       pselect(maxfd + 1, &rfds, NULL, &fds,
+               NULL, sigmask);
 }
 
 int mddev_busy(int devnum)