]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Stop: improve synchronising of reshape with whole stripes.
authorNeilBrown <neilb@suse.de>
Tue, 2 Jul 2013 06:18:21 +0000 (16:18 +1000)
committerNeilBrown <neilb@suse.de>
Tue, 2 Jul 2013 06:18:21 +0000 (16:18 +1000)
It is possible for 'sync_completed' to be further ahead than
we deduced from 'reshape_position'.  However we cannot read it while
the array is frozen, so it is hard to know.

Once that array is unfrozen, check and if sync_completed is ahead of
'sync_max',  push 'sync_max' well ahead if 'sync_completed' so it
will all synchronise up properly.

Signed-off-by: NeilBrown <neilb@suse.de>
Manage.c

index ed3f61d768a9e7f7e8119ba39c86d0e528be4d7e..c8592583ed9a6c3750e6540284776de6632e5652 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -357,6 +357,8 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
                unsigned long long chunk1, chunk2;
                unsigned long long rddiv, chunkdiv;
                unsigned long long sectors;
+               unsigned long long sync_max, old_sync_max;
+               unsigned long long completed;
                int backwards = 0;
                int delay;
                int scfd;
@@ -383,28 +385,46 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
                        size &= ~(chunk1-1);
                        size &= ~(chunk2-1);
                        /* rd1 must be smaller */
-                       size *= rd1;
-                       position = size - position;
-                       position = (position/sectors + 2) * sectors;
-                       sysfs_set_num(mdi, NULL, "sync_max", position/rd1);
-                       position = size - position;
+                       position = (position / sectors - 1) * sectors;
+                       sync_max = size - position/rd1;
                } else {
-                       position = (position/sectors + 2) * sectors;
-                       sysfs_set_num(mdi, NULL, "sync_max", position/rd1);
+                       position = (position / sectors + 2) * sectors;
+                       sync_max = position/rd1;
                }
+               if (sysfs_get_ll(mdi, NULL, "sync_max", &old_sync_max) < 0)
+                       old_sync_max = mdi->component_size;
+               /* Must not advance sync_max as that could confuse
+                * the reshape monitor */
+               if (sync_max < old_sync_max)
+                       sysfs_set_num(mdi, NULL, "sync_max", sync_max);
                sysfs_set_str(mdi, NULL, "sync_action", "idle");
 
                /* That should have set things going again.  Now we
-                * wait a little while (5 seconds) for sync_completed
+                * wait a little while (1 second max) for sync_completed
                 * to reach the target.
                 */
-               delay = 500;
+               delay = 1000;
                scfd = sysfs_open(mdi->sys_name, NULL, "sync_completed");
                while (scfd >= 0 && delay > 0) {
+                       sysfs_get_ll(mdi, NULL, "reshape_position", &curr);
                        sysfs_fd_get_str(scfd, buf, sizeof(buf));
                        if (strncmp(buf, "none", 4) == 0)
                                break;
-                       sysfs_get_ll(mdi, NULL, "reshape_position", &curr);
+
+                       if (sysfs_fd_get_ll(scfd, &completed) == 0 &&
+                           (completed > sync_max ||
+                            (completed == sync_max && curr != position))) {
+                               while (completed > sync_max) {
+                                       sync_max += sectors / rd1;
+                                       if (backwards)
+                                               position -= sectors;
+                                       else
+                                               position += sectors;
+                               }
+                               if (sync_max < old_sync_max)
+                                       sysfs_set_num(mdi, NULL, "sync_max", sync_max);
+                       }
+
                        if (!backwards && curr >= position)
                                break;
                        if (backwards && curr <= position)