summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.com>2015-07-17 04:06:02 +0200
committerNeilBrown <neilb@suse.com>2015-08-31 19:37:33 +0200
commitc5e19d906a658f27fa858b09a95d9551b1a69bd0 (patch)
tree4f24e56a076c2d544fbda272a85ba25e8d1e0242 /drivers
parentmd: set MD_RECOVERY_RECOVER when starting a degraded array. (diff)
downloadlinux-c5e19d906a658f27fa858b09a95d9551b1a69bd0.tar.xz
linux-c5e19d906a658f27fa858b09a95d9551b1a69bd0.zip
md: be careful when testing resync_max against curr_resync_completed.
While it generally shouldn't happen, it is not impossible for curr_resync_completed to exceed resync_max. This can particularly happen when reshaping RAID5 - the current status isn't copied to curr_resync_completed promptly, so when it is, it can exceed resync_max. This happens when the reshape is 'frozen', resync_max is set low, and reshape is re-enabled. Taking a difference between two unsigned numbers is always dangerous anyway, so add a test to behave correctly if curr_resync_completed > resync_max Signed-off-by: NeilBrown <neilb@suse.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/md.c3
-rw-r--r--drivers/md/raid5.c3
2 files changed, 4 insertions, 2 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5b62a3d49e12..b326cd26b027 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7834,7 +7834,8 @@ void md_do_sync(struct md_thread *thread)
> (max_sectors >> 4)) ||
time_after_eq(jiffies, update_time + UPDATE_FREQUENCY) ||
(j - mddev->curr_resync_completed)*2
- >= mddev->resync_max - mddev->curr_resync_completed
+ >= mddev->resync_max - mddev->curr_resync_completed ||
+ mddev->curr_resync_completed > mddev->resync_max
)) {
/* time to update curr_resync_completed */
wait_event(mddev->recovery_wait,
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 19bbdbe1a52f..1c27aa10f89c 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5542,7 +5542,8 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
sector_nr += reshape_sectors;
retn = reshape_sectors;
finish:
- if ((sector_nr - mddev->curr_resync_completed) * 2
+ if (mddev->curr_resync_completed > mddev->resync_max ||
+ (sector_nr - mddev->curr_resync_completed) * 2
>= mddev->resync_max - mddev->curr_resync_completed) {
/* Cannot proceed until we've updated the superblock... */
wait_event(conf->wait_for_overlap,