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 | 6791875e2e5393845b9c781d2998481089735134 (patch) | |
tree | a89ef0e3fbd3de6ff0bfe6bf3496f281853ab08c /drivers/md | |
parent | 5c47daf6e76f657d961a96d89f6419fde8eda557 (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.c | 346 | ||||
-rw-r--r-- | drivers/md/raid5.c | 134 |
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 | |||
3256 | level_store(struct mddev *mddev, const char *buf, size_t len) | 3256 | level_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; | ||
3452 | out_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 | } |
3486 | static struct md_sysfs_entry md_layout = | 3503 | static 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 | |||
3504 | raid_disks_store(struct mddev *mddev, const char *buf, size_t len) | 3521 | raid_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; | 3554 | out_unlock: |
3555 | mddev_unlock(mddev); | ||
3556 | return err ? err : len; | ||
3533 | } | 3557 | } |
3534 | static struct md_sysfs_entry md_raid_disks = | 3558 | static 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) | |||
3548 | static ssize_t | 3572 | static ssize_t |
3549 | chunk_size_store(struct mddev *mddev, const char *buf, size_t len) | 3573 | chunk_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 | } |
3576 | static struct md_sysfs_entry md_chunk_size = | 3604 | static 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) | |||
3587 | static ssize_t | 3615 | static ssize_t |
3588 | resync_start_store(struct mddev *mddev, const char *buf, size_t len) | 3616 | resync_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 | } |
3605 | static struct md_sysfs_entry md_resync_start = | 3640 | static 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); | |||
3698 | static ssize_t | 3733 | static ssize_t |
3699 | array_state_store(struct mddev *mddev, const char *buf, size_t len) | 3734 | array_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 | } |
3787 | static struct md_sysfs_entry md_array_state = | 3853 | static 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 */ |
3897 | out: | 3973 | out: |
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; |
4098 | out_unlock: | ||
4099 | mddev_unlock(mddev); | ||
4100 | return err ?: len; | ||
4008 | } | 4101 | } |
4009 | 4102 | ||
4010 | static struct md_sysfs_entry md_metadata = | 4103 | static 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; |
4473 | unlock: | ||
4474 | mddev_unlock(mddev); | ||
4475 | return err ?: len; | ||
4367 | } | 4476 | } |
4368 | static struct md_sysfs_entry md_suspend_lo = | 4477 | static 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; |
4515 | unlock: | ||
4516 | mddev_unlock(mddev); | ||
4517 | return err ?: len; | ||
4400 | } | 4518 | } |
4401 | static struct md_sysfs_entry md_suspend_hi = | 4519 | static 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; |
4557 | unlock: | ||
4558 | mddev_unlock(mddev); | ||
4559 | return err ?: len; | ||
4433 | } | 4560 | } |
4434 | 4561 | ||
4435 | static struct md_sysfs_entry md_reshape_position = | 4562 | static struct md_sysfs_entry md_reshape_position = |
@@ -4447,6 +4574,8 @@ static ssize_t | |||
4447 | reshape_direction_store(struct mddev *mddev, const char *buf, size_t len) | 4574 | reshape_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 | ||
4471 | static struct md_sysfs_entry md_reshape_direction = | 4603 | static struct md_sysfs_entry md_reshape_direction = |
@@ -4486,6 +4618,11 @@ static ssize_t | |||
4486 | array_size_store(struct mddev *mddev, const char *buf, size_t len) | 4618 | array_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, §ors) < 0) | 4635 | if (strict_blocks_to_sectors(buf, §ors) < 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 | ||
4514 | static struct md_sysfs_entry md_array_size = | 4654 | static 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); | |||
5400 | static ssize_t | 5400 | static ssize_t |
5401 | raid5_store_stripe_cache_size(struct mddev *mddev, const char *page, size_t len) | 5401 | raid5_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 | ||
5420 | static struct md_sysfs_entry | 5424 | static struct md_sysfs_entry |
@@ -5438,19 +5442,27 @@ raid5_show_preread_threshold(struct mddev *mddev, char *page) | |||
5438 | static ssize_t | 5442 | static ssize_t |
5439 | raid5_store_preread_threshold(struct mddev *mddev, const char *page, size_t len) | 5443 | raid5_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 | ||
5456 | static struct md_sysfs_entry | 5468 | static struct md_sysfs_entry |
@@ -5475,29 +5487,35 @@ raid5_show_skip_copy(struct mddev *mddev, char *page) | |||
5475 | static ssize_t | 5487 | static ssize_t |
5476 | raid5_store_skip_copy(struct mddev *mddev, const char *page, size_t len) | 5488 | raid5_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 | ||
5503 | static struct md_sysfs_entry | 5521 | static struct md_sysfs_entry |
@@ -5538,7 +5556,7 @@ static int alloc_thread_groups(struct r5conf *conf, int cnt, | |||
5538 | static ssize_t | 5556 | static ssize_t |
5539 | raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len) | 5557 | raid5_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 | ||
5586 | static struct md_sysfs_entry | 5604 | static struct md_sysfs_entry |