aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-12-14 20:57:01 -0500
committerNeilBrown <neilb@suse.de>2015-02-05 17:32:56 -0500
commit23da422b1951cb8dbcb7c3090057cb6d5ceedf49 (patch)
treea8ee30585883d85d661faf1cb21aa0baddff62c7 /drivers/md
parent1b30e66f5acc6bf22fff49d4093cf17454f914b7 (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.c58
-rw-r--r--drivers/md/md.h2
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
4269min_sync_store(struct mddev *mddev, const char *buf, size_t len) 4269min_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; 4299out_unlock:
4300 spin_unlock(&mddev->lock);
4301 return err ?: len;
4288} 4302}
4289 4303
4290static struct md_sysfs_entry md_min_sync = 4304static struct md_sysfs_entry md_min_sync =
@@ -4302,29 +4316,42 @@ max_sync_show(struct mddev *mddev, char *page)
4302static ssize_t 4316static ssize_t
4303max_sync_store(struct mddev *mddev, const char *buf, size_t len) 4317max_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;
4352out_unlock:
4353 spin_unlock(&mddev->lock);
4354 return err ?: len;
4328} 4355}
4329 4356
4330static struct md_sysfs_entry md_max_sync = 4357static 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 */