]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Monitor.c
mdmon: fix wrong array state when disk fails during mdmon startup
[thirdparty/mdadm.git] / Monitor.c
index 0198a346c05801015508af21533b4546f770c79b..036103fb0f6bd94c2856a8eaed5c88b9e91d28b4 100644 (file)
--- a/Monitor.c
+++ b/Monitor.c
@@ -465,6 +465,8 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
        int last_disk;
        int new_array = 0;
        int retval;
+       int is_container = 0;
+       unsigned long redundancy_only_flags = 0;
 
        if (test)
                alert("TestMessage", dev, NULL, ainfo);
@@ -475,18 +477,39 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
        if (fd < 0)
                goto disappeared;
 
-       if (!md_array_active(fd))
+       if (st->devnm[0] == 0)
+               strcpy(st->devnm, fd2devnm(fd));
+
+       for (mse2 = mdstat; mse2; mse2 = mse2->next)
+               if (strcmp(mse2->devnm, st->devnm) == 0) {
+                       mse2->devnm[0] = 0; /* flag it as "used" */
+                       mse = mse2;
+               }
+
+       if (!mse) {
+               /* duplicated array in statelist
+                * or re-created after reading mdstat
+                */
+               st->err++;
+               goto out;
+       }
+
+       if (mse->level == NULL)
+               is_container = 1;
+
+       if (!is_container && !md_array_active(fd))
                goto disappeared;
 
        fcntl(fd, F_SETFD, FD_CLOEXEC);
        if (md_get_array_info(fd, &array) < 0)
                goto disappeared;
 
-       if (st->devnm[0] == 0)
-               strcpy(st->devnm, fd2devnm(fd));
+       if (!is_container && map_name(pers, mse->level) > 0)
+               redundancy_only_flags |= GET_MISMATCH;
+
+       sra = sysfs_read(-1, st->devnm, GET_LEVEL | GET_DISKS | GET_DEVS |
+                       GET_STATE | redundancy_only_flags);
 
-       sra = sysfs_read(-1, st->devnm, GET_LEVEL | GET_DISKS | GET_DEGRADED |
-                        GET_MISMATCH | GET_DEVS | GET_STATE);
        if (!sra)
                goto disappeared;
 
@@ -500,19 +523,6 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
                goto out;
        }
 
-       for (mse2 = mdstat; mse2; mse2 = mse2->next)
-               if (strcmp(mse2->devnm, st->devnm) == 0) {
-                       mse2->devnm[0] = 0; /* flag it as "used" */
-                       mse = mse2;
-               }
-
-       if (!mse) {
-               /* duplicated array in statelist
-                * or re-created after reading mdstat*/
-               st->err++;
-               close(fd);
-               goto out;
-       }
        /* this array is in /proc/mdstat */
        if (array.utime == 0)
                /* external arrays don't update utime, so
@@ -530,7 +540,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
        if (st->utime == array.utime && st->failed == sra->array.failed_disks &&
            st->working == sra->array.working_disks &&
            st->spare == sra->array.spare_disks &&
-           (mse == NULL  || (mse->percent == st->percent))) {
+           (mse == NULL || (mse->percent == st->percent))) {
                if ((st->active < st->raid) && st->spare == 0)
                        retval = 1;
                goto out;
@@ -547,7 +557,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
                alert("RebuildStarted", dev, NULL, ainfo);
        if (st->percent >= 0 && mse->percent >= 0 &&
            (mse->percent / increments) > (st->percent / increments)) {
-               char percentalert[15];
+               char percentalert[18];
                /*
                 * "RebuildNN" (10 chars) or "RebuildStarted" (15 chars)
                 */
@@ -653,7 +663,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
  out:
        if (sra)
                sysfs_free(sra);
-       if (fd > 0)
+       if (fd >= 0)
                close(fd);
        return retval;
 
@@ -672,7 +682,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
        char *name;
 
        for (mse = mdstat; mse; mse = mse->next)
-               if (mse->devnm[0] && (!mse->level  || /* retrieve containers */
+               if (mse->devnm[0] && (!mse->level || /* retrieve containers */
                                      (strcmp(mse->level, "raid0") != 0 &&
                                       strcmp(mse->level, "linear") != 0))) {
                        struct state *st = xcalloc(1, sizeof *st);
@@ -982,12 +992,21 @@ static void link_containers_with_subarrays(struct state *list)
 int Wait(char *dev)
 {
        char devnm[32];
+       dev_t rdev;
+       char *tmp;
        int rv = 1;
        int frozen_remaining = 3;
 
-       if (!stat_is_blkdev(dev, NULL))
+       if (!stat_is_blkdev(dev, &rdev))
+               return 2;
+
+       tmp = devid2devnm(rdev);
+       if (!tmp) {
+               pr_err("Cannot get md device name.\n");
                return 2;
-       strcpy(devnm, dev);
+       }
+
+       strcpy(devnm, tmp);
 
        while(1) {
                struct mdstat_ent *ms = mdstat_read(1, 0);
@@ -1039,7 +1058,7 @@ int Wait(char *dev)
 static char *clean_states[] = {
        "clear", "inactive", "readonly", "read-auto", "clean", NULL };
 
-int WaitClean(char *dev, int sock, int verbose)
+int WaitClean(char *dev, int verbose)
 {
        int fd;
        struct mdinfo *mdi;
@@ -1106,15 +1125,16 @@ int WaitClean(char *dev, int sock, int verbose)
                }
                if (rv < 0)
                        rv = 1;
-               else if (fping_monitor(sock) == 0 ||
-                        ping_monitor(mdi->text_version) == 0) {
+               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
+               } else {
                        rv = 1;
+                       pr_err("Error connecting monitor with %s\n", dev);
+               }
                if (rv && verbose)
                        pr_err("Error waiting for %s to be clean\n", dev);