summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2013-07-02 16:18:21 +1000
committerNeilBrown <neilb@suse.de>2013-07-02 16:18:21 +1000
commit5509dc44d8f23d8501212b3d1f33dd35354b018b (patch)
tree838e914923969e6a45ada66ca45975f7d5c9f5ef
parentefb3994e4829f35e74b422e61c37eba79561fd4c (diff)
Stop: improve synchronising of reshape with whole stripes.
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>
-rw-r--r--Manage.c40
1 files changed, 30 insertions, 10 deletions
diff --git a/Manage.c b/Manage.c
index ed3f61d7..c8592583 100644
--- 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)