diff options
author | NeilBrown <neilb@suse.de> | 2015-07-06 05:33:20 +0200 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2015-07-06 05:33:20 +0200 |
commit | 30ddba7de56f598f2ebb5a8a36c7ee8282a54dbd (patch) | |
tree | a9f299f178d33ffff30e41e33bf2e45e3968735c /Manage.c | |
parent | Monitor: don't Wait forever on a 'frozen' array. (diff) | |
download | mdadm-30ddba7de56f598f2ebb5a8a36c7ee8282a54dbd.tar.xz mdadm-30ddba7de56f598f2ebb5a8a36c7ee8282a54dbd.zip |
Manage/stop: guard against 'completed' being too large.
A race can allow 'completed' to read as 2^63-1, which takes
a long time to count up to.
So guard against that possibility.
Signed-off-by: NeilBrown <neilb@suse.com>
Diffstat (limited to 'Manage.c')
-rw-r--r-- | Manage.c | 6 |
1 files changed, 5 insertions, 1 deletions
@@ -400,6 +400,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) delay = 3000; scfd = sysfs_open(mdi->sys_name, NULL, "sync_completed"); while (scfd >= 0 && delay > 0 && old_sync_max > 0) { + unsigned long long max_completed; sysfs_get_ll(mdi, NULL, "reshape_position", &curr); sysfs_fd_get_str(scfd, buf, sizeof(buf)); if (strncmp(buf, "none", 4) == 0) { @@ -413,7 +414,10 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) break; } - if (sysfs_fd_get_ll(scfd, &completed) == 0 && + if (sysfs_fd_get_two(scfd, &completed, + &max_completed) == 2 && + /* 'completed' sometimes reads as max-uulong */ + completed < max_completed && (completed > sync_max || (completed == sync_max && curr != position))) { while (completed > sync_max) { |