]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Assemble.c
Grow: remove excess drives when converting to RAID0.
[thirdparty/mdadm.git] / Assemble.c
index 7e8cdb4de8ee75a16cfedb2a7b06dded4159ba13..383b149e739d42a5ae20f8c2d2485ddf80f3548c 100644 (file)
@@ -690,11 +690,12 @@ static int load_devices(struct devs *devices, char *devmap,
                devices[devcnt].i = *content;
                devices[devcnt].i.disk.major = major(stb.st_rdev);
                devices[devcnt].i.disk.minor = minor(stb.st_rdev);
-               if (most_recent < devcnt) {
-                       if (devices[devcnt].i.events
-                           > devices[most_recent].i.events)
+
+               if (devices[devcnt].i.events
+                   > devices[most_recent].i.events &&
+                   devices[devcnt].i.disk.state == 6)
                                most_recent = devcnt;
-               }
+
                if (content->array.level == LEVEL_MULTIPATH)
                        /* with multipath, the raid_disk from the superblock is meaningless */
                        i = devcnt;
@@ -882,7 +883,9 @@ static int start_array(int mdfd,
                       unsigned int rebuilding_cnt,
                       struct context *c,
                       int clean, char *avail,
-                      int start_partial_ok
+                      int start_partial_ok,
+                      int err_ok,
+                      int was_forced
        )
 {
        int rv;
@@ -890,7 +893,7 @@ static int start_array(int mdfd,
        unsigned int req_cnt;
 
        rv = set_array_info(mdfd, st, content);
-       if (rv) {
+       if (rv && !err_ok) {
                pr_err("failed to set array info for %s: %s\n",
                       mddev, strerror(errno));
                return 1;
@@ -1063,6 +1066,17 @@ static int start_array(int mdfd,
                                        }
                                }
                        }
+                       printf("l=%d o=%d r=%d w=%d\n",content->array.level,
+                              okcnt, content->array.raid_disks, was_forced);
+                       if (content->array.level == 6 &&
+                           okcnt + 1 == (unsigned)content->array.raid_disks &&
+                           was_forced) {
+                               struct mdinfo *sra = sysfs_read(mdfd, NULL, 0);
+                               if (sra)
+                                       sysfs_set_str(sra, NULL,
+                                                     "sync_action", "repair");
+                               sysfs_free(sra);
+                       }
                        return 0;
                }
                pr_err("failed to RUN_ARRAY %s: %s\n",
@@ -1189,6 +1203,7 @@ int Assemble(struct supertype *st, char *mddev,
        int devcnt;
        unsigned int okcnt, sparecnt, rebuilding_cnt, replcnt;
        int i;
+       int was_forced = 0;
        int most_recent = 0;
        int chosen_drive;
        int change = 0;
@@ -1248,7 +1263,7 @@ try_again:
                                  inargv, auto_assem);
        if (num_devs < 0)
                return 1;
-       
+
        if (!st || !st->sb || !content)
                return 2;
 
@@ -1456,8 +1471,15 @@ try_again:
                        best[i] = -1;
                        continue;
                }
+               /* Require event counter to be same as, or just less than,
+                * most recent.  If it is bigger, it must be a stray spare and
+                * should be ignored.
+                */
                if (devices[j].i.events+event_margin >=
-                   devices[most_recent].i.events) {
+                   devices[most_recent].i.events &&
+                   devices[j].i.events <=
+                   devices[most_recent].i.events
+                       ) {
                        devices[j].uptodate = 1;
                        if (i < content->array.raid_disks * 2) {
                                if (devices[j].i.recovery_start == MaxSector ||
@@ -1477,10 +1499,13 @@ try_again:
                }
        }
        free(devmap);
-       if (c->force)
-               okcnt += force_array(content, devices, best, bestcnt,
-                                    avail, most_recent, st, c);
-
+       if (c->force) {
+               int force_ok = force_array(content, devices, best, bestcnt,
+                                          avail, most_recent, st, c);
+               okcnt += force_ok;
+               if (force_ok)
+                       was_forced = 1;
+       }
        /* Now we want to look at the superblock which the kernel will base things on
         * and compare the devices that we think are working with the devices that the
         * superblock thinks are working.
@@ -1576,6 +1601,7 @@ try_again:
                change += st->ss->update_super(st, content, "force-array",
                                               devices[chosen_drive].devname, c->verbose,
                                               0, NULL);
+               was_forced = 1;
                clean = 1;
        }
 
@@ -1618,6 +1644,7 @@ try_again:
                        pr_err(":%s has an active reshape - checking "
                               "if critical section needs to be restored\n",
                               chosen_name);
+               enable_fds(bestcnt/2);
                for (i = 0; i < bestcnt/2; i++) {
                        int j = best[i*2];
                        if (j >= 0) {
@@ -1680,7 +1707,9 @@ try_again:
                         chosen_drive, devices, okcnt, sparecnt,
                         rebuilding_cnt,
                         c,
-                        clean, avail, start_partial_ok);
+                        clean, avail, start_partial_ok,
+                        pre_exist != NULL,
+                        was_forced);
        if (rv == 1 && !pre_exist)
                ioctl(mdfd, STOP_ARRAY, NULL);
        free(devices);
@@ -1871,4 +1900,3 @@ int assemble_container_content(struct supertype *st, int mdfd,
        }
 }
 #endif
-