]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Monitor.c
Merge branch 'master' in devel-3.0
[thirdparty/mdadm.git] / Monitor.c
index 54193f5c1fa51c1c1537164d167d83d774d4033f..af531294cc53c908ea7a1b88f7a1e0870c5c62bf 100644 (file)
--- a/Monitor.c
+++ b/Monitor.c
@@ -156,7 +156,7 @@ int Monitor(mddev_dev_t devlist,
                        return 1;
                }
                close(0);
-               open("/dev/null", 3);
+               open("/dev/null", O_RDWR);
                dup2(0,1);
                dup2(0,2);
                setsid();
@@ -165,7 +165,10 @@ int Monitor(mddev_dev_t devlist,
        if (devlist == NULL) {
                mddev_ident_t mdlist = conf_get_ident(NULL);
                for (; mdlist; mdlist=mdlist->next) {
-                       struct state *st = malloc(sizeof *st);
+                       struct state *st;
+                       if (mdlist->devname == NULL)
+                               continue;
+                       st = malloc(sizeof *st);
                        if (st == NULL)
                                continue;
                        st->devname = strdup(mdlist->devname);
@@ -431,6 +434,8 @@ int Monitor(mddev_dev_t devlist,
                                        st->spare_group = NULL;
                                        st->expected_spares = -1;
                                        statelist = st;
+                                       if (test)
+                                               alert("TestMessage", st->devname, NULL, mailaddr, mailfrom, alert_cmd, dosyslog);
                                        alert("NewArray", st->devname, NULL, mailaddr, mailfrom, alert_cmd, dosyslog);
                                        new_found = 1;
                                }
@@ -602,10 +607,7 @@ int Wait(char *dev)
                        strerror(errno));
                return 2;
        }
-       if (major(stb.st_rdev) == MD_MAJOR)
-               devnum = minor(stb.st_rdev);
-       else
-               devnum = -1-(minor(stb.st_rdev)/64);
+       devnum = stat2devnum(&stb);
 
        while(1) {
                struct mdstat_ent *ms = mdstat_read(1, 0);
@@ -616,11 +618,122 @@ int Wait(char *dev)
                                break;
 
                if (!e || e->percent < 0) {
+                       if (e && e->metadata_version &&
+                           strncmp(e->metadata_version, "external:", 9) == 0) {
+                               if (is_subarray(&e->metadata_version[9]))
+                                       ping_monitor(&e->metadata_version[9]);
+                               else
+                                       ping_monitor(devnum2devname(devnum));
+                       }
                        free_mdstat(ms);
                        return rv;
                }
-               free(ms);
+               free_mdstat(ms);
                rv = 0;
                mdstat_wait(5);
        }
 }
+
+static char *clean_states[] = {
+       "clear", "inactive", "readonly", "read-auto", "clean", NULL };
+
+int WaitClean(char *dev, int verbose)
+{
+       int fd;
+       struct mdinfo *mdi;
+       int rv = 1;
+       int devnum;
+
+       fd = open(dev, O_RDONLY); 
+       if (fd < 0) {
+               if (verbose)
+                       fprintf(stderr, Name ": Couldn't open %s: %s\n", dev, strerror(errno));
+               return 1;
+       }
+
+       devnum = fd2devnum(fd);
+       mdi = sysfs_read(fd, devnum, GET_VERSION|GET_LEVEL|GET_SAFEMODE);
+       if (!mdi) {
+               if (verbose)
+                       fprintf(stderr, Name ": Failed to read sysfs attributes for "
+                               "%s\n", dev);
+               close(fd);
+               return 0;
+       }
+
+       switch(mdi->array.level) {
+       case LEVEL_LINEAR:
+       case LEVEL_MULTIPATH:
+       case 0:
+               /* safemode delay is irrelevant for these levels */
+               rv = 0;
+               
+       }
+
+       /* for internal metadata the kernel handles the final clean
+        * transition, containers can never be dirty
+        */
+       if (!is_subarray(mdi->text_version))
+               rv = 0;
+
+       /* safemode disabled ? */
+       if (mdi->safe_mode_delay == 0)
+               rv = 0;
+
+       if (rv) {
+               int state_fd = sysfs_open(fd2devnum(fd), NULL, "array_state");
+               char buf[20];
+               fd_set fds;
+               struct timeval tm;
+
+               /* minimize the safe_mode_delay and prepare to wait up to 5s
+                * for writes to quiesce
+                */
+               sysfs_set_safemode(mdi, 1);
+               tm.tv_sec = 5;
+               tm.tv_usec = 0;
+
+               /* give mdmon a chance to checkpoint resync */
+               sysfs_set_str(mdi, NULL, "sync_action", "idle");
+
+               FD_ZERO(&fds);
+
+               /* wait for array_state to be clean */
+               while (1) {
+                       rv = read(state_fd, buf, sizeof(buf));
+                       if (rv < 0)
+                               break;
+                       if (sysfs_match_word(buf, clean_states) <= 4)
+                               break;
+                       FD_SET(state_fd, &fds);
+                       rv = select(state_fd + 1, &fds, NULL, NULL, &tm);
+                       if (rv < 0 && errno != EINTR)
+                               break;
+                       lseek(state_fd, 0, SEEK_SET);
+               }
+               if (rv < 0)
+                       rv = 1;
+               else if (ping_monitor(mdi->text_version) == 0) {
+                       /* we need to ping to close the window between array
+                        * state transitioning to clean and the metadata being
+                        * marked clean
+                        */
+                       rv = 0;
+               } else
+                       rv = 1;
+               if (rv && verbose)
+                       fprintf(stderr, Name ": Error waiting for %s to be clean\n",
+                               dev);
+
+               /* restore the original safe_mode_delay */
+               sysfs_set_safemode(mdi, mdi->safe_mode_delay);
+               close(state_fd);
+       }
+
+       sysfs_free(mdi);
+       close(fd);
+
+       return rv;
+}
+
+