diff options
author | NeilBrown <neilb@suse.de> | 2014-12-14 20:57:01 -0500 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2015-02-05 17:32:56 -0500 |
commit | 23da422b1951cb8dbcb7c3090057cb6d5ceedf49 (patch) | |
tree | a8ee30585883d85d661faf1cb21aa0baddff62c7 /drivers/md | |
parent | 1b30e66f5acc6bf22fff49d4093cf17454f914b7 (diff) |
md: use mddev->lock to protect updates to resync_{min,max}.
There are interdependencies between these two sysfs attributes
and whether a resync is currently running.
Rather than depending on reconfig_mutex to ensure no races when
testing these interdependencies are met, use the spinlock.
This will allow the mutex to be remove from protecting this
code in a subsequent patch.
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/md.c | 58 | ||||
-rw-r--r-- | drivers/md/md.h | 2 |
2 files changed, 47 insertions, 13 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 0f9bc9a02a1b..0f00c1e2d829 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -4269,22 +4269,36 @@ static ssize_t | |||
4269 | min_sync_store(struct mddev *mddev, const char *buf, size_t len) | 4269 | min_sync_store(struct mddev *mddev, const char *buf, size_t len) |
4270 | { | 4270 | { |
4271 | unsigned long long min; | 4271 | unsigned long long min; |
4272 | int err; | ||
4273 | int chunk; | ||
4274 | |||
4272 | if (kstrtoull(buf, 10, &min)) | 4275 | if (kstrtoull(buf, 10, &min)) |
4273 | return -EINVAL; | 4276 | return -EINVAL; |
4277 | |||
4278 | spin_lock(&mddev->lock); | ||
4279 | err = -EINVAL; | ||
4274 | if (min > mddev->resync_max) | 4280 | if (min > mddev->resync_max) |
4275 | return -EINVAL; | 4281 | goto out_unlock; |
4282 | |||
4283 | err = -EBUSY; | ||
4276 | if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) | 4284 | if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) |
4277 | return -EBUSY; | 4285 | goto out_unlock; |
4278 | 4286 | ||
4279 | /* Must be a multiple of chunk_size */ | 4287 | /* Must be a multiple of chunk_size */ |
4280 | if (mddev->chunk_sectors) { | 4288 | chunk = mddev->chunk_sectors; |
4289 | if (chunk) { | ||
4281 | sector_t temp = min; | 4290 | sector_t temp = min; |
4282 | if (sector_div(temp, mddev->chunk_sectors)) | 4291 | |
4283 | return -EINVAL; | 4292 | err = -EINVAL; |
4293 | if (sector_div(temp, chunk)) | ||
4294 | goto out_unlock; | ||
4284 | } | 4295 | } |
4285 | mddev->resync_min = min; | 4296 | mddev->resync_min = min; |
4297 | err = 0; | ||
4286 | 4298 | ||
4287 | return len; | 4299 | out_unlock: |
4300 | spin_unlock(&mddev->lock); | ||
4301 | return err ?: len; | ||
4288 | } | 4302 | } |
4289 | 4303 | ||
4290 | static struct md_sysfs_entry md_min_sync = | 4304 | static struct md_sysfs_entry md_min_sync = |
@@ -4302,29 +4316,42 @@ max_sync_show(struct mddev *mddev, char *page) | |||
4302 | static ssize_t | 4316 | static ssize_t |
4303 | max_sync_store(struct mddev *mddev, const char *buf, size_t len) | 4317 | max_sync_store(struct mddev *mddev, const char *buf, size_t len) |
4304 | { | 4318 | { |
4319 | int err; | ||
4320 | spin_lock(&mddev->lock); | ||
4305 | if (strncmp(buf, "max", 3) == 0) | 4321 | if (strncmp(buf, "max", 3) == 0) |
4306 | mddev->resync_max = MaxSector; | 4322 | mddev->resync_max = MaxSector; |
4307 | else { | 4323 | else { |
4308 | unsigned long long max; | 4324 | unsigned long long max; |
4325 | int chunk; | ||
4326 | |||
4327 | err = -EINVAL; | ||
4309 | if (kstrtoull(buf, 10, &max)) | 4328 | if (kstrtoull(buf, 10, &max)) |
4310 | return -EINVAL; | 4329 | goto out_unlock; |
4311 | if (max < mddev->resync_min) | 4330 | if (max < mddev->resync_min) |
4312 | return -EINVAL; | 4331 | goto out_unlock; |
4332 | |||
4333 | err = -EBUSY; | ||
4313 | if (max < mddev->resync_max && | 4334 | if (max < mddev->resync_max && |
4314 | mddev->ro == 0 && | 4335 | mddev->ro == 0 && |
4315 | test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) | 4336 | test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) |
4316 | return -EBUSY; | 4337 | goto out_unlock; |
4317 | 4338 | ||
4318 | /* Must be a multiple of chunk_size */ | 4339 | /* Must be a multiple of chunk_size */ |
4319 | if (mddev->chunk_sectors) { | 4340 | chunk = mddev->chunk_sectors; |
4341 | if (chunk) { | ||
4320 | sector_t temp = max; | 4342 | sector_t temp = max; |
4321 | if (sector_div(temp, mddev->chunk_sectors)) | 4343 | |
4322 | return -EINVAL; | 4344 | err = -EINVAL; |
4345 | if (sector_div(temp, chunk)) | ||
4346 | goto out_unlock; | ||
4323 | } | 4347 | } |
4324 | mddev->resync_max = max; | 4348 | mddev->resync_max = max; |
4325 | } | 4349 | } |
4326 | wake_up(&mddev->recovery_wait); | 4350 | wake_up(&mddev->recovery_wait); |
4327 | return len; | 4351 | err = 0; |
4352 | out_unlock: | ||
4353 | spin_unlock(&mddev->lock); | ||
4354 | return err ?: len; | ||
4328 | } | 4355 | } |
4329 | 4356 | ||
4330 | static struct md_sysfs_entry md_max_sync = | 4357 | static struct md_sysfs_entry md_max_sync = |
@@ -7585,6 +7612,7 @@ void md_do_sync(struct md_thread *thread) | |||
7585 | skip: | 7612 | skip: |
7586 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | 7613 | set_bit(MD_CHANGE_DEVS, &mddev->flags); |
7587 | 7614 | ||
7615 | spin_lock(&mddev->lock); | ||
7588 | if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { | 7616 | if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { |
7589 | /* We completed so min/max setting can be forgotten if used. */ | 7617 | /* We completed so min/max setting can be forgotten if used. */ |
7590 | if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) | 7618 | if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) |
@@ -7593,6 +7621,8 @@ void md_do_sync(struct md_thread *thread) | |||
7593 | } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) | 7621 | } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) |
7594 | mddev->resync_min = mddev->curr_resync_completed; | 7622 | mddev->resync_min = mddev->curr_resync_completed; |
7595 | mddev->curr_resync = 0; | 7623 | mddev->curr_resync = 0; |
7624 | spin_unlock(&mddev->lock); | ||
7625 | |||
7596 | wake_up(&resync_wait); | 7626 | wake_up(&resync_wait); |
7597 | set_bit(MD_RECOVERY_DONE, &mddev->recovery); | 7627 | set_bit(MD_RECOVERY_DONE, &mddev->recovery); |
7598 | md_wakeup_thread(mddev->thread); | 7628 | md_wakeup_thread(mddev->thread); |
@@ -7793,7 +7823,9 @@ void md_check_recovery(struct mddev *mddev) | |||
7793 | * any transients in the value of "sync_action". | 7823 | * any transients in the value of "sync_action". |
7794 | */ | 7824 | */ |
7795 | mddev->curr_resync_completed = 0; | 7825 | mddev->curr_resync_completed = 0; |
7826 | spin_lock(&mddev->lock); | ||
7796 | set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); | 7827 | set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); |
7828 | spin_unlock(&mddev->lock); | ||
7797 | /* Clear some bits that don't mean anything, but | 7829 | /* Clear some bits that don't mean anything, but |
7798 | * might be left set | 7830 | * might be left set |
7799 | */ | 7831 | */ |
diff --git a/drivers/md/md.h b/drivers/md/md.h index b4fbd6a63fcf..6bf3faa951ec 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h | |||
@@ -394,6 +394,8 @@ struct mddev { | |||
394 | * pers (also protected by reconfig_mutex and pending IO). | 394 | * pers (also protected by reconfig_mutex and pending IO). |
395 | * clearing ->bitmap | 395 | * clearing ->bitmap |
396 | * clearing ->bitmap_info.file | 396 | * clearing ->bitmap_info.file |
397 | * changing ->resync_{min,max} | ||
398 | * setting MD_RECOVERY_RUNNING (which interacts with resync_{min,max}) | ||
397 | */ | 399 | */ |
398 | spinlock_t lock; | 400 | spinlock_t lock; |
399 | wait_queue_head_t sb_wait; /* for waiting on superblock updates */ | 401 | wait_queue_head_t sb_wait; /* for waiting on superblock updates */ |