]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Grow - be careful about 'delayed' reshapes.
authorNeilBrown <neilb@suse.de>
Wed, 3 Oct 2012 04:41:31 +0000 (14:41 +1000)
committerNeilBrown <neilb@suse.de>
Wed, 3 Oct 2012 04:41:31 +0000 (14:41 +1000)
If multiple reshapes are activated on the same devices (different
partitions) then one might be forced to wait for the other to
complete.
As reshaping suspends access to small sections of the array
at time, this cause a region to be suspended for a long time,
which isn't good.

To try to detect this and don't start suspending until
the reshape is actually happening.

This is only effective on 3.7 and later as prior kernels
don't report when the delayed reshape can progress.  For
the earlier kernels, just give a warning.

Signed-off-by; NeilBrown <neilb@suse.de>

Grow.c

diff --git a/Grow.c b/Grow.c
index 20fe9078bf55cd78ce082bd48adcf697f5324ba6..6da939786b57edaf1ba0af0dd729931166462256 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -2087,6 +2087,7 @@ static int reshape_array(char *container, int fd, char *devname,
        char *msg;
        int orig_level = UnSet;
        int disks, odisks;
+       int delayed;
 
        struct mdu_array_info_s array;
        char *c;
@@ -2573,6 +2574,39 @@ started:
                break;
        }
 
+       /* If another array on the same devices is busy, the
+        * reshape will wait for them.  This would mean that
+        * the first section that we suspend will stay suspended
+        * for a long time.  So check on that possibility
+        * by looking for "DELAYED" in /proc/mdstat, and if found,
+        * wait a while
+        */
+       do {
+               struct mdstat_ent *mds, *m;
+               delayed = 0;
+               mds = mdstat_read(0, 0);
+               for (m = mds; m; m = mds->next)
+                       if (m->devnum == devname2devnum(sra->sys_name)) {
+                               if (m->resync &&
+                                   m->percent == RESYNC_DELAYED)
+                                       delayed = 1;
+                               if (m->resync == 0)
+                                       /* Haven't started the reshape thread
+                                        * yet, wait a bit
+                                        */
+                                       delayed = 2;
+                               break;
+                       }
+               free_mdstat(mds);
+               if (delayed == 1 && get_linux_version() < 3007000) {
+                       pr_err("Reshape is delayed, but cannot wait carefully with this kernel.\n"
+                              "       You might experience problems until other reshapes complete.\n");
+                       delayed = 0;
+               }
+               if (delayed)
+                       sleep(30 - (delayed-1) * 25);
+       } while (delayed);
+
        close(fd);
        if (check_env("MDADM_GROW_VERIFY"))
                fd = open(devname, O_RDONLY | O_DIRECT);