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
commit6791875e2e5393845b9c781d2998481089735134 (patch)
treea89ef0e3fbd3de6ff0bfe6bf3496f281853ab08c /drivers/md
parent5c47daf6e76f657d961a96d89f6419fde8eda557 (diff)
md: make reconfig_mutex optional for writes to md sysfs files.
Rather than using mddev_lock() to take the reconfig_mutex when writing to any md sysfs file, we only take mddev_lock() in the particular _store() functions that require it. Admittedly this is most, but it isn't all. This also allows us to remove special-case handling for new_dev_store (in md_attr_store). Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/md.c346
-rw-r--r--drivers/md/raid5.c134
2 files changed, 316 insertions, 164 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index ea839d811f64..c8d2bac4e28b 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3256,26 +3256,32 @@ static ssize_t
3256level_store(struct mddev *mddev, const char *buf, size_t len) 3256level_store(struct mddev *mddev, const char *buf, size_t len)
3257{ 3257{
3258 char clevel[16]; 3258 char clevel[16];
3259 ssize_t rv = len; 3259 ssize_t rv;
3260 size_t slen = len;
3260 struct md_personality *pers, *oldpers; 3261 struct md_personality *pers, *oldpers;
3261 long level; 3262 long level;
3262 void *priv, *oldpriv; 3263 void *priv, *oldpriv;
3263 struct md_rdev *rdev; 3264 struct md_rdev *rdev;
3264 3265
3266 if (slen == 0 || slen >= sizeof(clevel))
3267 return -EINVAL;
3268
3269 rv = mddev_lock(mddev);
3270 if (rv)
3271 return rv;
3272
3265 if (mddev->pers == NULL) { 3273 if (mddev->pers == NULL) {
3266 if (len == 0) 3274 strncpy(mddev->clevel, buf, slen);
3267 return 0; 3275 if (mddev->clevel[slen-1] == '\n')
3268 if (len >= sizeof(mddev->clevel)) 3276 slen--;
3269 return -ENOSPC; 3277 mddev->clevel[slen] = 0;
3270 strncpy(mddev->clevel, buf, len);
3271 if (mddev->clevel[len-1] == '\n')
3272 len--;
3273 mddev->clevel[len] = 0;
3274 mddev->level = LEVEL_NONE; 3278 mddev->level = LEVEL_NONE;
3275 return rv; 3279 rv = len;
3280 goto out_unlock;
3276 } 3281 }
3282 rv = -EROFS;
3277 if (mddev->ro) 3283 if (mddev->ro)
3278 return -EROFS; 3284 goto out_unlock;
3279 3285
3280 /* request to change the personality. Need to ensure: 3286 /* request to change the personality. Need to ensure:
3281 * - array is not engaged in resync/recovery/reshape 3287 * - array is not engaged in resync/recovery/reshape
@@ -3283,25 +3289,25 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
3283 * - new personality will access other array. 3289 * - new personality will access other array.
3284 */ 3290 */
3285 3291
3292 rv = -EBUSY;
3286 if (mddev->sync_thread || 3293 if (mddev->sync_thread ||
3287 test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || 3294 test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
3288 mddev->reshape_position != MaxSector || 3295 mddev->reshape_position != MaxSector ||
3289 mddev->sysfs_active) 3296 mddev->sysfs_active)
3290 return -EBUSY; 3297 goto out_unlock;
3291 3298
3299 rv = -EINVAL;
3292 if (!mddev->pers->quiesce) { 3300 if (!mddev->pers->quiesce) {
3293 printk(KERN_WARNING "md: %s: %s does not support online personality change\n", 3301 printk(KERN_WARNING "md: %s: %s does not support online personality change\n",
3294 mdname(mddev), mddev->pers->name); 3302 mdname(mddev), mddev->pers->name);
3295 return -EINVAL; 3303 goto out_unlock;
3296 } 3304 }
3297 3305
3298 /* Now find the new personality */ 3306 /* Now find the new personality */
3299 if (len == 0 || len >= sizeof(clevel)) 3307 strncpy(clevel, buf, slen);
3300 return -EINVAL; 3308 if (clevel[slen-1] == '\n')
3301 strncpy(clevel, buf, len); 3309 slen--;
3302 if (clevel[len-1] == '\n') 3310 clevel[slen] = 0;
3303 len--;
3304 clevel[len] = 0;
3305 if (kstrtol(clevel, 10, &level)) 3311 if (kstrtol(clevel, 10, &level))
3306 level = LEVEL_NONE; 3312 level = LEVEL_NONE;
3307 3313
@@ -3312,20 +3318,23 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
3312 if (!pers || !try_module_get(pers->owner)) { 3318 if (!pers || !try_module_get(pers->owner)) {
3313 spin_unlock(&pers_lock); 3319 spin_unlock(&pers_lock);
3314 printk(KERN_WARNING "md: personality %s not loaded\n", clevel); 3320 printk(KERN_WARNING "md: personality %s not loaded\n", clevel);
3315 return -EINVAL; 3321 rv = -EINVAL;
3322 goto out_unlock;
3316 } 3323 }
3317 spin_unlock(&pers_lock); 3324 spin_unlock(&pers_lock);
3318 3325
3319 if (pers == mddev->pers) { 3326 if (pers == mddev->pers) {
3320 /* Nothing to do! */ 3327 /* Nothing to do! */
3321 module_put(pers->owner); 3328 module_put(pers->owner);
3322 return rv; 3329 rv = len;
3330 goto out_unlock;
3323 } 3331 }
3324 if (!pers->takeover) { 3332 if (!pers->takeover) {
3325 module_put(pers->owner); 3333 module_put(pers->owner);
3326 printk(KERN_WARNING "md: %s: %s does not support personality takeover\n", 3334 printk(KERN_WARNING "md: %s: %s does not support personality takeover\n",
3327 mdname(mddev), clevel); 3335 mdname(mddev), clevel);
3328 return -EINVAL; 3336 rv = -EINVAL;
3337 goto out_unlock;
3329 } 3338 }
3330 3339
3331 rdev_for_each(rdev, mddev) 3340 rdev_for_each(rdev, mddev)
@@ -3345,7 +3354,8 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
3345 module_put(pers->owner); 3354 module_put(pers->owner);
3346 printk(KERN_WARNING "md: %s: %s would not accept array\n", 3355 printk(KERN_WARNING "md: %s: %s would not accept array\n",
3347 mdname(mddev), clevel); 3356 mdname(mddev), clevel);
3348 return PTR_ERR(priv); 3357 rv = PTR_ERR(priv);
3358 goto out_unlock;
3349 } 3359 }
3350 3360
3351 /* Looks like we have a winner */ 3361 /* Looks like we have a winner */
@@ -3438,6 +3448,9 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
3438 md_update_sb(mddev, 1); 3448 md_update_sb(mddev, 1);
3439 sysfs_notify(&mddev->kobj, NULL, "level"); 3449 sysfs_notify(&mddev->kobj, NULL, "level");
3440 md_new_event(mddev); 3450 md_new_event(mddev);
3451 rv = len;
3452out_unlock:
3453 mddev_unlock(mddev);
3441 return rv; 3454 return rv;
3442} 3455}
3443 3456
@@ -3460,28 +3473,32 @@ layout_store(struct mddev *mddev, const char *buf, size_t len)
3460{ 3473{
3461 char *e; 3474 char *e;
3462 unsigned long n = simple_strtoul(buf, &e, 10); 3475 unsigned long n = simple_strtoul(buf, &e, 10);
3476 int err;
3463 3477
3464 if (!*buf || (*e && *e != '\n')) 3478 if (!*buf || (*e && *e != '\n'))
3465 return -EINVAL; 3479 return -EINVAL;
3480 err = mddev_lock(mddev);
3481 if (err)
3482 return err;
3466 3483
3467 if (mddev->pers) { 3484 if (mddev->pers) {
3468 int err;
3469 if (mddev->pers->check_reshape == NULL) 3485 if (mddev->pers->check_reshape == NULL)
3470 return -EBUSY; 3486 err = -EBUSY;
3471 if (mddev->ro) 3487 else if (mddev->ro)
3472 return -EROFS; 3488 err = -EROFS;
3473 mddev->new_layout = n; 3489 else {
3474 err = mddev->pers->check_reshape(mddev); 3490 mddev->new_layout = n;
3475 if (err) { 3491 err = mddev->pers->check_reshape(mddev);
3476 mddev->new_layout = mddev->layout; 3492 if (err)
3477 return err; 3493 mddev->new_layout = mddev->layout;
3478 } 3494 }
3479 } else { 3495 } else {
3480 mddev->new_layout = n; 3496 mddev->new_layout = n;
3481 if (mddev->reshape_position == MaxSector) 3497 if (mddev->reshape_position == MaxSector)
3482 mddev->layout = n; 3498 mddev->layout = n;
3483 } 3499 }
3484 return len; 3500 mddev_unlock(mddev);
3501 return err ?: len;
3485} 3502}
3486static struct md_sysfs_entry md_layout = 3503static struct md_sysfs_entry md_layout =
3487__ATTR(layout, S_IRUGO|S_IWUSR, layout_show, layout_store); 3504__ATTR(layout, S_IRUGO|S_IWUSR, layout_show, layout_store);
@@ -3504,32 +3521,39 @@ static ssize_t
3504raid_disks_store(struct mddev *mddev, const char *buf, size_t len) 3521raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
3505{ 3522{
3506 char *e; 3523 char *e;
3507 int rv = 0; 3524 int err;
3508 unsigned long n = simple_strtoul(buf, &e, 10); 3525 unsigned long n = simple_strtoul(buf, &e, 10);
3509 3526
3510 if (!*buf || (*e && *e != '\n')) 3527 if (!*buf || (*e && *e != '\n'))
3511 return -EINVAL; 3528 return -EINVAL;
3512 3529
3530 err = mddev_lock(mddev);
3531 if (err)
3532 return err;
3513 if (mddev->pers) 3533 if (mddev->pers)
3514 rv = update_raid_disks(mddev, n); 3534 err = update_raid_disks(mddev, n);
3515 else if (mddev->reshape_position != MaxSector) { 3535 else if (mddev->reshape_position != MaxSector) {
3516 struct md_rdev *rdev; 3536 struct md_rdev *rdev;
3517 int olddisks = mddev->raid_disks - mddev->delta_disks; 3537 int olddisks = mddev->raid_disks - mddev->delta_disks;
3518 3538
3539 err = -EINVAL;
3519 rdev_for_each(rdev, mddev) { 3540 rdev_for_each(rdev, mddev) {
3520 if (olddisks < n && 3541 if (olddisks < n &&
3521 rdev->data_offset < rdev->new_data_offset) 3542 rdev->data_offset < rdev->new_data_offset)
3522 return -EINVAL; 3543 goto out_unlock;
3523 if (olddisks > n && 3544 if (olddisks > n &&
3524 rdev->data_offset > rdev->new_data_offset) 3545 rdev->data_offset > rdev->new_data_offset)
3525 return -EINVAL; 3546 goto out_unlock;
3526 } 3547 }
3548 err = 0;
3527 mddev->delta_disks = n - olddisks; 3549 mddev->delta_disks = n - olddisks;
3528 mddev->raid_disks = n; 3550 mddev->raid_disks = n;
3529 mddev->reshape_backwards = (mddev->delta_disks < 0); 3551 mddev->reshape_backwards = (mddev->delta_disks < 0);
3530 } else 3552 } else
3531 mddev->raid_disks = n; 3553 mddev->raid_disks = n;
3532 return rv ? rv : len; 3554out_unlock:
3555 mddev_unlock(mddev);
3556 return err ? err : len;
3533} 3557}
3534static struct md_sysfs_entry md_raid_disks = 3558static struct md_sysfs_entry md_raid_disks =
3535__ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store); 3559__ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);
@@ -3548,30 +3572,34 @@ chunk_size_show(struct mddev *mddev, char *page)
3548static ssize_t 3572static ssize_t
3549chunk_size_store(struct mddev *mddev, const char *buf, size_t len) 3573chunk_size_store(struct mddev *mddev, const char *buf, size_t len)
3550{ 3574{
3575 int err;
3551 char *e; 3576 char *e;
3552 unsigned long n = simple_strtoul(buf, &e, 10); 3577 unsigned long n = simple_strtoul(buf, &e, 10);
3553 3578
3554 if (!*buf || (*e && *e != '\n')) 3579 if (!*buf || (*e && *e != '\n'))
3555 return -EINVAL; 3580 return -EINVAL;
3556 3581
3582 err = mddev_lock(mddev);
3583 if (err)
3584 return err;
3557 if (mddev->pers) { 3585 if (mddev->pers) {
3558 int err;
3559 if (mddev->pers->check_reshape == NULL) 3586 if (mddev->pers->check_reshape == NULL)
3560 return -EBUSY; 3587 err = -EBUSY;
3561 if (mddev->ro) 3588 else if (mddev->ro)
3562 return -EROFS; 3589 err = -EROFS;
3563 mddev->new_chunk_sectors = n >> 9; 3590 else {
3564 err = mddev->pers->check_reshape(mddev); 3591 mddev->new_chunk_sectors = n >> 9;
3565 if (err) { 3592 err = mddev->pers->check_reshape(mddev);
3566 mddev->new_chunk_sectors = mddev->chunk_sectors; 3593 if (err)
3567 return err; 3594 mddev->new_chunk_sectors = mddev->chunk_sectors;
3568 } 3595 }
3569 } else { 3596 } else {
3570 mddev->new_chunk_sectors = n >> 9; 3597 mddev->new_chunk_sectors = n >> 9;
3571 if (mddev->reshape_position == MaxSector) 3598 if (mddev->reshape_position == MaxSector)
3572 mddev->chunk_sectors = n >> 9; 3599 mddev->chunk_sectors = n >> 9;
3573 } 3600 }
3574 return len; 3601 mddev_unlock(mddev);
3602 return err ?: len;
3575} 3603}
3576static struct md_sysfs_entry md_chunk_size = 3604static struct md_sysfs_entry md_chunk_size =
3577__ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store); 3605__ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store);
@@ -3587,20 +3615,27 @@ resync_start_show(struct mddev *mddev, char *page)
3587static ssize_t 3615static ssize_t
3588resync_start_store(struct mddev *mddev, const char *buf, size_t len) 3616resync_start_store(struct mddev *mddev, const char *buf, size_t len)
3589{ 3617{
3618 int err;
3590 char *e; 3619 char *e;
3591 unsigned long long n = simple_strtoull(buf, &e, 10); 3620 unsigned long long n = simple_strtoull(buf, &e, 10);
3592 3621
3622 err = mddev_lock(mddev);
3623 if (err)
3624 return err;
3593 if (mddev->pers && !test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) 3625 if (mddev->pers && !test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
3594 return -EBUSY; 3626 err = -EBUSY;
3595 if (cmd_match(buf, "none")) 3627 else if (cmd_match(buf, "none"))
3596 n = MaxSector; 3628 n = MaxSector;
3597 else if (!*buf || (*e && *e != '\n')) 3629 else if (!*buf || (*e && *e != '\n'))
3598 return -EINVAL; 3630 err = -EINVAL;
3599 3631
3600 mddev->recovery_cp = n; 3632 if (!err) {
3601 if (mddev->pers) 3633 mddev->recovery_cp = n;
3602 set_bit(MD_CHANGE_CLEAN, &mddev->flags); 3634 if (mddev->pers)
3603 return len; 3635 set_bit(MD_CHANGE_CLEAN, &mddev->flags);
3636 }
3637 mddev_unlock(mddev);
3638 return err ?: len;
3604} 3639}
3605static struct md_sysfs_entry md_resync_start = 3640static struct md_sysfs_entry md_resync_start =
3606__ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store); 3641__ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store);
@@ -3698,8 +3733,39 @@ static int restart_array(struct mddev *mddev);
3698static ssize_t 3733static ssize_t
3699array_state_store(struct mddev *mddev, const char *buf, size_t len) 3734array_state_store(struct mddev *mddev, const char *buf, size_t len)
3700{ 3735{
3701 int err = -EINVAL; 3736 int err;
3702 enum array_state st = match_word(buf, array_states); 3737 enum array_state st = match_word(buf, array_states);
3738
3739 if (mddev->pers && (st == active || st == clean) && mddev->ro != 1) {
3740 /* don't take reconfig_mutex when toggling between
3741 * clean and active
3742 */
3743 spin_lock(&mddev->lock);
3744 if (st == active) {
3745 restart_array(mddev);
3746 clear_bit(MD_CHANGE_PENDING, &mddev->flags);
3747 wake_up(&mddev->sb_wait);
3748 err = 0;
3749 } else /* st == clean */ {
3750 restart_array(mddev);
3751 if (atomic_read(&mddev->writes_pending) == 0) {
3752 if (mddev->in_sync == 0) {
3753 mddev->in_sync = 1;
3754 if (mddev->safemode == 1)
3755 mddev->safemode = 0;
3756 set_bit(MD_CHANGE_CLEAN, &mddev->flags);
3757 }
3758 err = 0;
3759 } else
3760 err = -EBUSY;
3761 }
3762 spin_unlock(&mddev->lock);
3763 return err;
3764 }
3765 err = mddev_lock(mddev);
3766 if (err)
3767 return err;
3768 err = -EINVAL;
3703 switch(st) { 3769 switch(st) {
3704 case bad_word: 3770 case bad_word:
3705 break; 3771 break;
@@ -3775,14 +3841,14 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
3775 /* these cannot be set */ 3841 /* these cannot be set */
3776 break; 3842 break;
3777 } 3843 }
3778 if (err) 3844
3779 return err; 3845 if (!err) {
3780 else {
3781 if (mddev->hold_active == UNTIL_IOCTL) 3846 if (mddev->hold_active == UNTIL_IOCTL)
3782 mddev->hold_active = 0; 3847 mddev->hold_active = 0;
3783 sysfs_notify_dirent_safe(mddev->sysfs_state); 3848 sysfs_notify_dirent_safe(mddev->sysfs_state);
3784 return len;
3785 } 3849 }
3850 mddev_unlock(mddev);
3851 return err ?: len;
3786} 3852}
3787static struct md_sysfs_entry md_array_state = 3853static struct md_sysfs_entry md_array_state =
3788__ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store); 3854__ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
@@ -3843,6 +3909,11 @@ new_dev_store(struct mddev *mddev, const char *buf, size_t len)
3843 minor != MINOR(dev)) 3909 minor != MINOR(dev))
3844 return -EOVERFLOW; 3910 return -EOVERFLOW;
3845 3911
3912 flush_workqueue(md_misc_wq);
3913
3914 err = mddev_lock(mddev);
3915 if (err)
3916 return err;
3846 if (mddev->persistent) { 3917 if (mddev->persistent) {
3847 rdev = md_import_device(dev, mddev->major_version, 3918 rdev = md_import_device(dev, mddev->major_version,
3848 mddev->minor_version); 3919 mddev->minor_version);
@@ -3866,6 +3937,7 @@ new_dev_store(struct mddev *mddev, const char *buf, size_t len)
3866 out: 3937 out:
3867 if (err) 3938 if (err)
3868 export_rdev(rdev); 3939 export_rdev(rdev);
3940 mddev_unlock(mddev);
3869 return err ? err : len; 3941 return err ? err : len;
3870} 3942}
3871 3943
@@ -3877,7 +3949,11 @@ bitmap_store(struct mddev *mddev, const char *buf, size_t len)
3877{ 3949{
3878 char *end; 3950 char *end;
3879 unsigned long chunk, end_chunk; 3951 unsigned long chunk, end_chunk;
3952 int err;
3880 3953
3954 err = mddev_lock(mddev);
3955 if (err)
3956 return err;
3881 if (!mddev->bitmap) 3957 if (!mddev->bitmap)
3882 goto out; 3958 goto out;
3883 /* buf should be <chunk> <chunk> ... or <chunk>-<chunk> ... (range) */ 3959 /* buf should be <chunk> <chunk> ... or <chunk>-<chunk> ... (range) */
@@ -3895,6 +3971,7 @@ bitmap_store(struct mddev *mddev, const char *buf, size_t len)
3895 } 3971 }
3896 bitmap_unplug(mddev->bitmap); /* flush the bits to disk */ 3972 bitmap_unplug(mddev->bitmap); /* flush the bits to disk */
3897out: 3973out:
3974 mddev_unlock(mddev);
3898 return len; 3975 return len;
3899} 3976}
3900 3977
@@ -3922,6 +3999,9 @@ size_store(struct mddev *mddev, const char *buf, size_t len)
3922 3999
3923 if (err < 0) 4000 if (err < 0)
3924 return err; 4001 return err;
4002 err = mddev_lock(mddev);
4003 if (err)
4004 return err;
3925 if (mddev->pers) { 4005 if (mddev->pers) {
3926 err = update_size(mddev, sectors); 4006 err = update_size(mddev, sectors);
3927 md_update_sb(mddev, 1); 4007 md_update_sb(mddev, 1);
@@ -3932,6 +4012,7 @@ size_store(struct mddev *mddev, const char *buf, size_t len)
3932 else 4012 else
3933 err = -ENOSPC; 4013 err = -ENOSPC;
3934 } 4014 }
4015 mddev_unlock(mddev);
3935 return err ? err : len; 4016 return err ? err : len;
3936} 4017}
3937 4018
@@ -3961,21 +4042,28 @@ metadata_store(struct mddev *mddev, const char *buf, size_t len)
3961{ 4042{
3962 int major, minor; 4043 int major, minor;
3963 char *e; 4044 char *e;
4045 int err;
3964 /* Changing the details of 'external' metadata is 4046 /* Changing the details of 'external' metadata is
3965 * always permitted. Otherwise there must be 4047 * always permitted. Otherwise there must be
3966 * no devices attached to the array. 4048 * no devices attached to the array.
3967 */ 4049 */
4050
4051 err = mddev_lock(mddev);
4052 if (err)
4053 return err;
4054 err = -EBUSY;
3968 if (mddev->external && strncmp(buf, "external:", 9) == 0) 4055 if (mddev->external && strncmp(buf, "external:", 9) == 0)
3969 ; 4056 ;
3970 else if (!list_empty(&mddev->disks)) 4057 else if (!list_empty(&mddev->disks))
3971 return -EBUSY; 4058 goto out_unlock;
3972 4059
4060 err = 0;
3973 if (cmd_match(buf, "none")) { 4061 if (cmd_match(buf, "none")) {
3974 mddev->persistent = 0; 4062 mddev->persistent = 0;
3975 mddev->external = 0; 4063 mddev->external = 0;
3976 mddev->major_version = 0; 4064 mddev->major_version = 0;
3977 mddev->minor_version = 90; 4065 mddev->minor_version = 90;
3978 return len; 4066 goto out_unlock;
3979 } 4067 }
3980 if (strncmp(buf, "external:", 9) == 0) { 4068 if (strncmp(buf, "external:", 9) == 0) {
3981 size_t namelen = len-9; 4069 size_t namelen = len-9;
@@ -3989,22 +4077,27 @@ metadata_store(struct mddev *mddev, const char *buf, size_t len)
3989 mddev->external = 1; 4077 mddev->external = 1;
3990 mddev->major_version = 0; 4078 mddev->major_version = 0;
3991 mddev->minor_version = 90; 4079 mddev->minor_version = 90;
3992 return len; 4080 goto out_unlock;
3993 } 4081 }
3994 major = simple_strtoul(buf, &e, 10); 4082 major = simple_strtoul(buf, &e, 10);
4083 err = -EINVAL;
3995 if (e==buf || *e != '.') 4084 if (e==buf || *e != '.')
3996 return -EINVAL; 4085 goto out_unlock;
3997 buf = e+1; 4086 buf = e+1;
3998 minor = simple_strtoul(buf, &e, 10); 4087 minor = simple_strtoul(buf, &e, 10);
3999 if (e==buf || (*e && *e != '\n') ) 4088 if (e==buf || (*e && *e != '\n') )
4000 return -EINVAL; 4089 goto out_unlock;
4090 err = -ENOENT;
4001 if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL) 4091 if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL)
4002 return -ENOENT; 4092 goto out_unlock;
4003 mddev->major_version = major; 4093 mddev->major_version = major;
4004 mddev->minor_version = minor; 4094 mddev->minor_version = minor;
4005 mddev->persistent = 1; 4095 mddev->persistent = 1;
4006 mddev->external = 0; 4096 mddev->external = 0;
4007 return len; 4097 err = 0;
4098out_unlock:
4099 mddev_unlock(mddev);
4100 return err ?: len;
4008} 4101}
4009 4102
4010static struct md_sysfs_entry md_metadata = 4103static struct md_sysfs_entry md_metadata =
@@ -4049,7 +4142,10 @@ action_store(struct mddev *mddev, const char *page, size_t len)
4049 flush_workqueue(md_misc_wq); 4142 flush_workqueue(md_misc_wq);
4050 if (mddev->sync_thread) { 4143 if (mddev->sync_thread) {
4051 set_bit(MD_RECOVERY_INTR, &mddev->recovery); 4144 set_bit(MD_RECOVERY_INTR, &mddev->recovery);
4052 md_reap_sync_thread(mddev); 4145 if (mddev_lock(mddev) == 0) {
4146 md_reap_sync_thread(mddev);
4147 mddev_unlock(mddev);
4148 }
4053 } 4149 }
4054 } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || 4150 } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
4055 test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) 4151 test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
@@ -4063,7 +4159,11 @@ action_store(struct mddev *mddev, const char *page, size_t len)
4063 int err; 4159 int err;
4064 if (mddev->pers->start_reshape == NULL) 4160 if (mddev->pers->start_reshape == NULL)
4065 return -EINVAL; 4161 return -EINVAL;
4066 err = mddev->pers->start_reshape(mddev); 4162 err = mddev_lock(mddev);
4163 if (!err) {
4164 err = mddev->pers->start_reshape(mddev);
4165 mddev_unlock(mddev);
4166 }
4067 if (err) 4167 if (err)
4068 return err; 4168 return err;
4069 sysfs_notify(&mddev->kobj, NULL, "degraded"); 4169 sysfs_notify(&mddev->kobj, NULL, "degraded");
@@ -4346,14 +4446,20 @@ suspend_lo_store(struct mddev *mddev, const char *buf, size_t len)
4346{ 4446{
4347 char *e; 4447 char *e;
4348 unsigned long long new = simple_strtoull(buf, &e, 10); 4448 unsigned long long new = simple_strtoull(buf, &e, 10);
4349 unsigned long long old = mddev->suspend_lo; 4449 unsigned long long old;
4450 int err;
4350 4451
4351 if (mddev->pers == NULL ||
4352 mddev->pers->quiesce == NULL)
4353 return -EINVAL;
4354 if (buf == e || (*e && *e != '\n')) 4452 if (buf == e || (*e && *e != '\n'))
4355 return -EINVAL; 4453 return -EINVAL;
4356 4454
4455 err = mddev_lock(mddev);
4456 if (err)
4457 return err;
4458 err = -EINVAL;
4459 if (mddev->pers == NULL ||
4460 mddev->pers->quiesce == NULL)
4461 goto unlock;
4462 old = mddev->suspend_lo;
4357 mddev->suspend_lo = new; 4463 mddev->suspend_lo = new;
4358 if (new >= old) 4464 if (new >= old)
4359 /* Shrinking suspended region */ 4465 /* Shrinking suspended region */
@@ -4363,7 +4469,10 @@ suspend_lo_store(struct mddev *mddev, const char *buf, size_t len)
4363 mddev->pers->quiesce(mddev, 1); 4469 mddev->pers->quiesce(mddev, 1);
4364 mddev->pers->quiesce(mddev, 0); 4470 mddev->pers->quiesce(mddev, 0);
4365 } 4471 }
4366 return len; 4472 err = 0;
4473unlock:
4474 mddev_unlock(mddev);
4475 return err ?: len;
4367} 4476}
4368static struct md_sysfs_entry md_suspend_lo = 4477static struct md_sysfs_entry md_suspend_lo =
4369__ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store); 4478__ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store);
@@ -4379,14 +4488,20 @@ suspend_hi_store(struct mddev *mddev, const char *buf, size_t len)
4379{ 4488{
4380 char *e; 4489 char *e;
4381 unsigned long long new = simple_strtoull(buf, &e, 10); 4490 unsigned long long new = simple_strtoull(buf, &e, 10);
4382 unsigned long long old = mddev->suspend_hi; 4491 unsigned long long old;
4492 int err;
4383 4493
4384 if (mddev->pers == NULL ||
4385 mddev->pers->quiesce == NULL)
4386 return -EINVAL;
4387 if (buf == e || (*e && *e != '\n')) 4494 if (buf == e || (*e && *e != '\n'))
4388 return -EINVAL; 4495 return -EINVAL;
4389 4496
4497 err = mddev_lock(mddev);
4498 if (err)
4499 return err;
4500 err = -EINVAL;
4501 if (mddev->pers == NULL ||
4502 mddev->pers->quiesce == NULL)
4503 goto unlock;
4504 old = mddev->suspend_hi;
4390 mddev->suspend_hi = new; 4505 mddev->suspend_hi = new;
4391 if (new <= old) 4506 if (new <= old)
4392 /* Shrinking suspended region */ 4507 /* Shrinking suspended region */
@@ -4396,7 +4511,10 @@ suspend_hi_store(struct mddev *mddev, const char *buf, size_t len)
4396 mddev->pers->quiesce(mddev, 1); 4511 mddev->pers->quiesce(mddev, 1);
4397 mddev->pers->quiesce(mddev, 0); 4512 mddev->pers->quiesce(mddev, 0);
4398 } 4513 }
4399 return len; 4514 err = 0;
4515unlock:
4516 mddev_unlock(mddev);
4517 return err ?: len;
4400} 4518}
4401static struct md_sysfs_entry md_suspend_hi = 4519static struct md_sysfs_entry md_suspend_hi =
4402__ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store); 4520__ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
@@ -4416,11 +4534,17 @@ reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
4416{ 4534{
4417 struct md_rdev *rdev; 4535 struct md_rdev *rdev;
4418 char *e; 4536 char *e;
4537 int err;
4419 unsigned long long new = simple_strtoull(buf, &e, 10); 4538 unsigned long long new = simple_strtoull(buf, &e, 10);
4420 if (mddev->pers) 4539
4421 return -EBUSY;
4422 if (buf == e || (*e && *e != '\n')) 4540 if (buf == e || (*e && *e != '\n'))
4423 return -EINVAL; 4541 return -EINVAL;
4542 err = mddev_lock(mddev);
4543 if (err)
4544 return err;
4545 err = -EBUSY;
4546 if (mddev->pers)
4547 goto unlock;
4424 mddev->reshape_position = new; 4548 mddev->reshape_position = new;
4425 mddev->delta_disks = 0; 4549 mddev->delta_disks = 0;
4426 mddev->reshape_backwards = 0; 4550 mddev->reshape_backwards = 0;
@@ -4429,7 +4553,10 @@ reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
4429 mddev->new_chunk_sectors = mddev->chunk_sectors; 4553 mddev->new_chunk_sectors = mddev->chunk_sectors;
4430 rdev_for_each(rdev, mddev) 4554 rdev_for_each(rdev, mddev)
4431 rdev->new_data_offset = rdev->data_offset; 4555 rdev->new_data_offset = rdev->data_offset;
4432 return len; 4556 err = 0;
4557unlock:
4558 mddev_unlock(mddev);
4559 return err ?: len;
4433} 4560}
4434 4561
4435static struct md_sysfs_entry md_reshape_position = 4562static struct md_sysfs_entry md_reshape_position =
@@ -4447,6 +4574,8 @@ static ssize_t
4447reshape_direction_store(struct mddev *mddev, const char *buf, size_t len) 4574reshape_direction_store(struct mddev *mddev, const char *buf, size_t len)
4448{ 4575{
4449 int backwards = 0; 4576 int backwards = 0;
4577 int err;
4578
4450 if (cmd_match(buf, "forwards")) 4579 if (cmd_match(buf, "forwards"))
4451 backwards = 0; 4580 backwards = 0;
4452 else if (cmd_match(buf, "backwards")) 4581 else if (cmd_match(buf, "backwards"))
@@ -4456,16 +4585,19 @@ reshape_direction_store(struct mddev *mddev, const char *buf, size_t len)
4456 if (mddev->reshape_backwards == backwards) 4585 if (mddev->reshape_backwards == backwards)
4457 return len; 4586 return len;
4458 4587
4588 err = mddev_lock(mddev);
4589 if (err)
4590 return err;
4459 /* check if we are allowed to change */ 4591 /* check if we are allowed to change */
4460 if (mddev->delta_disks) 4592 if (mddev->delta_disks)
4461 return -EBUSY; 4593 err = -EBUSY;
4462 4594 else if (mddev->persistent &&
4463 if (mddev->persistent &&
4464 mddev->major_version == 0) 4595 mddev->major_version == 0)
4465 return -EINVAL; 4596 err = -EINVAL;
4466 4597 else
4467 mddev->reshape_backwards = backwards; 4598 mddev->reshape_backwards = backwards;
4468 return len; 4599 mddev_unlock(mddev);
4600 return err ?: len;
4469} 4601}
4470 4602
4471static struct md_sysfs_entry md_reshape_direction = 4603static struct md_sysfs_entry md_reshape_direction =
@@ -4486,6 +4618,11 @@ static ssize_t
4486array_size_store(struct mddev *mddev, const char *buf, size_t len) 4618array_size_store(struct mddev *mddev, const char *buf, size_t len)
4487{ 4619{
4488 sector_t sectors; 4620 sector_t sectors;
4621 int err;
4622
4623 err = mddev_lock(mddev);
4624 if (err)
4625 return err;
4489 4626
4490 if (strncmp(buf, "default", 7) == 0) { 4627 if (strncmp(buf, "default", 7) == 0) {
4491 if (mddev->pers) 4628 if (mddev->pers)
@@ -4496,19 +4633,22 @@ array_size_store(struct mddev *mddev, const char *buf, size_t len)
4496 mddev->external_size = 0; 4633 mddev->external_size = 0;
4497 } else { 4634 } else {
4498 if (strict_blocks_to_sectors(buf, &sectors) < 0) 4635 if (strict_blocks_to_sectors(buf, &sectors) < 0)
4499 return -EINVAL; 4636 err = -EINVAL;
4500 if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors) 4637 else if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors)
4501 return -E2BIG; 4638 err = -E2BIG;
4502 4639 else
4503 mddev->external_size = 1; 4640 mddev->external_size = 1;
4504 } 4641 }
4505 4642
4506 mddev->array_sectors = sectors; 4643 if (!err) {
4507 if (mddev->pers) { 4644 mddev->array_sectors = sectors;
4508 set_capacity(mddev->gendisk, mddev->array_sectors); 4645 if (mddev->pers) {
4509 revalidate_disk(mddev->gendisk); 4646 set_capacity(mddev->gendisk, mddev->array_sectors);
4647 revalidate_disk(mddev->gendisk);
4648 }
4510 } 4649 }
4511 return len; 4650 mddev_unlock(mddev);
4651 return err ?: len;
4512} 4652}
4513 4653
4514static struct md_sysfs_entry md_array_size = 4654static struct md_sysfs_entry md_array_size =
@@ -4596,13 +4736,7 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
4596 } 4736 }
4597 mddev_get(mddev); 4737 mddev_get(mddev);
4598 spin_unlock(&all_mddevs_lock); 4738 spin_unlock(&all_mddevs_lock);
4599 if (entry->store == new_dev_store) 4739 rv = entry->store(mddev, page, length);
4600 flush_workqueue(md_misc_wq);
4601 rv = mddev_lock(mddev);
4602 if (!rv) {
4603 rv = entry->store(mddev, page, length);
4604 mddev_unlock(mddev);
4605 }
4606 mddev_put(mddev); 4740 mddev_put(mddev);
4607 return rv; 4741 return rv;
4608} 4742}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index d5b80174b3b3..aa76865b804b 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5400,21 +5400,25 @@ EXPORT_SYMBOL(raid5_set_cache_size);
5400static ssize_t 5400static ssize_t
5401raid5_store_stripe_cache_size(struct mddev *mddev, const char *page, size_t len) 5401raid5_store_stripe_cache_size(struct mddev *mddev, const char *page, size_t len)
5402{ 5402{
5403 struct r5conf *conf = mddev->private; 5403 struct r5conf *conf;
5404 unsigned long new; 5404 unsigned long new;
5405 int err; 5405 int err;
5406 5406
5407 if (len >= PAGE_SIZE) 5407 if (len >= PAGE_SIZE)
5408 return -EINVAL; 5408 return -EINVAL;
5409 if (!conf)
5410 return -ENODEV;
5411
5412 if (kstrtoul(page, 10, &new)) 5409 if (kstrtoul(page, 10, &new))
5413 return -EINVAL; 5410 return -EINVAL;
5414 err = raid5_set_cache_size(mddev, new); 5411 err = mddev_lock(mddev);
5415 if (err) 5412 if (err)
5416 return err; 5413 return err;
5417 return len; 5414 conf = mddev->private;
5415 if (!conf)
5416 err = -ENODEV;
5417 else
5418 err = raid5_set_cache_size(mddev, new);
5419 mddev_unlock(mddev);
5420
5421 return err ?: len;
5418} 5422}
5419 5423
5420static struct md_sysfs_entry 5424static struct md_sysfs_entry
@@ -5438,19 +5442,27 @@ raid5_show_preread_threshold(struct mddev *mddev, char *page)
5438static ssize_t 5442static ssize_t
5439raid5_store_preread_threshold(struct mddev *mddev, const char *page, size_t len) 5443raid5_store_preread_threshold(struct mddev *mddev, const char *page, size_t len)
5440{ 5444{
5441 struct r5conf *conf = mddev->private; 5445 struct r5conf *conf;
5442 unsigned long new; 5446 unsigned long new;
5447 int err;
5448
5443 if (len >= PAGE_SIZE) 5449 if (len >= PAGE_SIZE)
5444 return -EINVAL; 5450 return -EINVAL;
5445 if (!conf)
5446 return -ENODEV;
5447
5448 if (kstrtoul(page, 10, &new)) 5451 if (kstrtoul(page, 10, &new))
5449 return -EINVAL; 5452 return -EINVAL;
5450 if (new > conf->max_nr_stripes) 5453
5451 return -EINVAL; 5454 err = mddev_lock(mddev);
5452 conf->bypass_threshold = new; 5455 if (err)
5453 return len; 5456 return err;
5457 conf = mddev->private;
5458 if (!conf)
5459 err = -ENODEV;
5460 else if (new > conf->max_nr_stripes)
5461 err = -EINVAL;
5462 else
5463 conf->bypass_threshold = new;
5464 mddev_unlock(mddev);
5465 return err ?: len;
5454} 5466}
5455 5467
5456static struct md_sysfs_entry 5468static struct md_sysfs_entry
@@ -5475,29 +5487,35 @@ raid5_show_skip_copy(struct mddev *mddev, char *page)
5475static ssize_t 5487static ssize_t
5476raid5_store_skip_copy(struct mddev *mddev, const char *page, size_t len) 5488raid5_store_skip_copy(struct mddev *mddev, const char *page, size_t len)
5477{ 5489{
5478 struct r5conf *conf = mddev->private; 5490 struct r5conf *conf;
5479 unsigned long new; 5491 unsigned long new;
5492 int err;
5493
5480 if (len >= PAGE_SIZE) 5494 if (len >= PAGE_SIZE)
5481 return -EINVAL; 5495 return -EINVAL;
5482 if (!conf)
5483 return -ENODEV;
5484
5485 if (kstrtoul(page, 10, &new)) 5496 if (kstrtoul(page, 10, &new))
5486 return -EINVAL; 5497 return -EINVAL;
5487 new = !!new; 5498 new = !!new;
5488 if (new == conf->skip_copy)
5489 return len;
5490 5499
5491 mddev_suspend(mddev); 5500 err = mddev_lock(mddev);
5492 conf->skip_copy = new; 5501 if (err)
5493 if (new) 5502 return err;
5494 mddev->queue->backing_dev_info.capabilities |= 5503 conf = mddev->private;
5495 BDI_CAP_STABLE_WRITES; 5504 if (!conf)
5496 else 5505 err = -ENODEV;
5497 mddev->queue->backing_dev_info.capabilities &= 5506 else if (new != conf->skip_copy) {
5498 ~BDI_CAP_STABLE_WRITES; 5507 mddev_suspend(mddev);
5499 mddev_resume(mddev); 5508 conf->skip_copy = new;
5500 return len; 5509 if (new)
5510 mddev->queue->backing_dev_info.capabilities |=
5511 BDI_CAP_STABLE_WRITES;
5512 else
5513 mddev->queue->backing_dev_info.capabilities &=
5514 ~BDI_CAP_STABLE_WRITES;
5515 mddev_resume(mddev);
5516 }
5517 mddev_unlock(mddev);
5518 return err ?: len;
5501} 5519}
5502 5520
5503static struct md_sysfs_entry 5521static struct md_sysfs_entry
@@ -5538,7 +5556,7 @@ static int alloc_thread_groups(struct r5conf *conf, int cnt,
5538static ssize_t 5556static ssize_t
5539raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len) 5557raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len)
5540{ 5558{
5541 struct r5conf *conf = mddev->private; 5559 struct r5conf *conf;
5542 unsigned long new; 5560 unsigned long new;
5543 int err; 5561 int err;
5544 struct r5worker_group *new_groups, *old_groups; 5562 struct r5worker_group *new_groups, *old_groups;
@@ -5546,41 +5564,41 @@ raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len)
5546 5564
5547 if (len >= PAGE_SIZE) 5565 if (len >= PAGE_SIZE)
5548 return -EINVAL; 5566 return -EINVAL;
5549 if (!conf)
5550 return -ENODEV;
5551
5552 if (kstrtoul(page, 10, &new)) 5567 if (kstrtoul(page, 10, &new))
5553 return -EINVAL; 5568 return -EINVAL;
5554 5569
5555 if (new == conf->worker_cnt_per_group) 5570 err = mddev_lock(mddev);
5556 return len; 5571 if (err)
5557 5572 return err;
5558 mddev_suspend(mddev); 5573 conf = mddev->private;
5574 if (!conf)
5575 err = -ENODEV;
5576 else if (new != conf->worker_cnt_per_group) {
5577 mddev_suspend(mddev);
5559 5578
5560 old_groups = conf->worker_groups; 5579 old_groups = conf->worker_groups;
5561 if (old_groups) 5580 if (old_groups)
5562 flush_workqueue(raid5_wq); 5581 flush_workqueue(raid5_wq);
5563 5582
5564 err = alloc_thread_groups(conf, new, 5583 err = alloc_thread_groups(conf, new,
5565 &group_cnt, &worker_cnt_per_group, 5584 &group_cnt, &worker_cnt_per_group,
5566 &new_groups); 5585 &new_groups);
5567 if (!err) { 5586 if (!err) {
5568 spin_lock_irq(&conf->device_lock); 5587 spin_lock_irq(&conf->device_lock);
5569 conf->group_cnt = group_cnt; 5588 conf->group_cnt = group_cnt;
5570 conf->worker_cnt_per_group = worker_cnt_per_group; 5589 conf->worker_cnt_per_group = worker_cnt_per_group;
5571 conf->worker_groups = new_groups; 5590 conf->worker_groups = new_groups;
5572 spin_unlock_irq(&conf->device_lock); 5591 spin_unlock_irq(&conf->device_lock);
5573 5592
5574 if (old_groups) 5593 if (old_groups)
5575 kfree(old_groups[0].workers); 5594 kfree(old_groups[0].workers);
5576 kfree(old_groups); 5595 kfree(old_groups);
5596 }
5597 mddev_resume(mddev);
5577 } 5598 }
5599 mddev_unlock(mddev);
5578 5600
5579 mddev_resume(mddev); 5601 return err ?: len;
5580
5581 if (err)
5582 return err;
5583 return len;
5584} 5602}
5585 5603
5586static struct md_sysfs_entry 5604static struct md_sysfs_entry