diff options
| author | NeilBrown <neilb@suse.de> | 2012-10-10 22:37:33 -0400 |
|---|---|---|
| committer | NeilBrown <neilb@suse.de> | 2012-10-10 22:37:33 -0400 |
| commit | 1ca69c4bc4b1ef889861db39f325901eadbf9497 (patch) | |
| tree | a4c83843fc630c42853e1a5ecc51dff5ab3ef54f /drivers | |
| parent | 4ed8731d8e6bd2a88a30697fbf4f7e6e979a6c46 (diff) | |
md: avoid taking the mutex on some ioctls.
Some ioctls don't need to take the mutex and doing so can cause
a delay as it is held during super-block update.
So move those ioctls out of the mutex and rely on rcu locking
to ensure we don't access stale data.
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/md/md.c | 85 |
1 files changed, 62 insertions, 23 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 8e842b326ebd..feab588adb50 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
| @@ -674,7 +674,18 @@ static struct md_rdev * find_rdev_nr(struct mddev *mddev, int nr) | |||
| 674 | return NULL; | 674 | return NULL; |
| 675 | } | 675 | } |
| 676 | 676 | ||
| 677 | static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev) | 677 | static struct md_rdev *find_rdev_nr_rcu(struct mddev *mddev, int nr) |
| 678 | { | ||
| 679 | struct md_rdev *rdev; | ||
| 680 | |||
| 681 | rdev_for_each_rcu(rdev, mddev) | ||
| 682 | if (rdev->desc_nr == nr) | ||
| 683 | return rdev; | ||
| 684 | |||
| 685 | return NULL; | ||
| 686 | } | ||
| 687 | |||
| 688 | static struct md_rdev *find_rdev(struct mddev *mddev, dev_t dev) | ||
| 678 | { | 689 | { |
| 679 | struct md_rdev *rdev; | 690 | struct md_rdev *rdev; |
| 680 | 691 | ||
| @@ -685,6 +696,17 @@ static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev) | |||
| 685 | return NULL; | 696 | return NULL; |
| 686 | } | 697 | } |
| 687 | 698 | ||
| 699 | static struct md_rdev *find_rdev_rcu(struct mddev *mddev, dev_t dev) | ||
| 700 | { | ||
| 701 | struct md_rdev *rdev; | ||
| 702 | |||
| 703 | rdev_for_each_rcu(rdev, mddev) | ||
| 704 | if (rdev->bdev->bd_dev == dev) | ||
| 705 | return rdev; | ||
| 706 | |||
| 707 | return NULL; | ||
| 708 | } | ||
| 709 | |||
| 688 | static struct md_personality *find_pers(int level, char *clevel) | 710 | static struct md_personality *find_pers(int level, char *clevel) |
| 689 | { | 711 | { |
| 690 | struct md_personality *pers; | 712 | struct md_personality *pers; |
| @@ -5509,8 +5531,9 @@ static int get_array_info(struct mddev * mddev, void __user * arg) | |||
| 5509 | int nr,working,insync,failed,spare; | 5531 | int nr,working,insync,failed,spare; |
| 5510 | struct md_rdev *rdev; | 5532 | struct md_rdev *rdev; |
| 5511 | 5533 | ||
| 5512 | nr=working=insync=failed=spare=0; | 5534 | nr = working = insync = failed = spare = 0; |
| 5513 | rdev_for_each(rdev, mddev) { | 5535 | rcu_read_lock(); |
| 5536 | rdev_for_each_rcu(rdev, mddev) { | ||
| 5514 | nr++; | 5537 | nr++; |
| 5515 | if (test_bit(Faulty, &rdev->flags)) | 5538 | if (test_bit(Faulty, &rdev->flags)) |
| 5516 | failed++; | 5539 | failed++; |
| @@ -5522,6 +5545,7 @@ static int get_array_info(struct mddev * mddev, void __user * arg) | |||
| 5522 | spare++; | 5545 | spare++; |
| 5523 | } | 5546 | } |
| 5524 | } | 5547 | } |
| 5548 | rcu_read_unlock(); | ||
| 5525 | 5549 | ||
| 5526 | info.major_version = mddev->major_version; | 5550 | info.major_version = mddev->major_version; |
| 5527 | info.minor_version = mddev->minor_version; | 5551 | info.minor_version = mddev->minor_version; |
| @@ -5605,7 +5629,8 @@ static int get_disk_info(struct mddev * mddev, void __user * arg) | |||
| 5605 | if (copy_from_user(&info, arg, sizeof(info))) | 5629 | if (copy_from_user(&info, arg, sizeof(info))) |
| 5606 | return -EFAULT; | 5630 | return -EFAULT; |
| 5607 | 5631 | ||
| 5608 | rdev = find_rdev_nr(mddev, info.number); | 5632 | rcu_read_lock(); |
| 5633 | rdev = find_rdev_nr_rcu(mddev, info.number); | ||
| 5609 | if (rdev) { | 5634 | if (rdev) { |
| 5610 | info.major = MAJOR(rdev->bdev->bd_dev); | 5635 | info.major = MAJOR(rdev->bdev->bd_dev); |
| 5611 | info.minor = MINOR(rdev->bdev->bd_dev); | 5636 | info.minor = MINOR(rdev->bdev->bd_dev); |
| @@ -5624,6 +5649,7 @@ static int get_disk_info(struct mddev * mddev, void __user * arg) | |||
| 5624 | info.raid_disk = -1; | 5649 | info.raid_disk = -1; |
| 5625 | info.state = (1<<MD_DISK_REMOVED); | 5650 | info.state = (1<<MD_DISK_REMOVED); |
| 5626 | } | 5651 | } |
| 5652 | rcu_read_unlock(); | ||
| 5627 | 5653 | ||
| 5628 | if (copy_to_user(arg, &info, sizeof(info))) | 5654 | if (copy_to_user(arg, &info, sizeof(info))) |
| 5629 | return -EFAULT; | 5655 | return -EFAULT; |
| @@ -6232,18 +6258,22 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) | |||
| 6232 | static int set_disk_faulty(struct mddev *mddev, dev_t dev) | 6258 | static int set_disk_faulty(struct mddev *mddev, dev_t dev) |
| 6233 | { | 6259 | { |
| 6234 | struct md_rdev *rdev; | 6260 | struct md_rdev *rdev; |
| 6261 | int err = 0; | ||
| 6235 | 6262 | ||
| 6236 | if (mddev->pers == NULL) | 6263 | if (mddev->pers == NULL) |
| 6237 | return -ENODEV; | 6264 | return -ENODEV; |
| 6238 | 6265 | ||
| 6239 | rdev = find_rdev(mddev, dev); | 6266 | rcu_read_lock(); |
| 6267 | rdev = find_rdev_rcu(mddev, dev); | ||
| 6240 | if (!rdev) | 6268 | if (!rdev) |
| 6241 | return -ENODEV; | 6269 | err = -ENODEV; |
| 6242 | 6270 | else { | |
| 6243 | md_error(mddev, rdev); | 6271 | md_error(mddev, rdev); |
| 6244 | if (!test_bit(Faulty, &rdev->flags)) | 6272 | if (!test_bit(Faulty, &rdev->flags)) |
| 6245 | return -EBUSY; | 6273 | err = -EBUSY; |
| 6246 | return 0; | 6274 | } |
| 6275 | rcu_read_unlock(); | ||
| 6276 | return err; | ||
| 6247 | } | 6277 | } |
| 6248 | 6278 | ||
| 6249 | /* | 6279 | /* |
| @@ -6315,6 +6345,27 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, | |||
| 6315 | goto abort; | 6345 | goto abort; |
| 6316 | } | 6346 | } |
| 6317 | 6347 | ||
| 6348 | /* Some actions do not requires the mutex */ | ||
| 6349 | switch (cmd) { | ||
| 6350 | case GET_ARRAY_INFO: | ||
| 6351 | if (!mddev->raid_disks && !mddev->external) | ||
| 6352 | err = -ENODEV; | ||
| 6353 | else | ||
| 6354 | err = get_array_info(mddev, argp); | ||
| 6355 | goto abort; | ||
| 6356 | |||
| 6357 | case GET_DISK_INFO: | ||
| 6358 | if (!mddev->raid_disks && !mddev->external) | ||
| 6359 | err = -ENODEV; | ||
| 6360 | else | ||
| 6361 | err = get_disk_info(mddev, argp); | ||
| 6362 | goto abort; | ||
| 6363 | |||
| 6364 | case SET_DISK_FAULTY: | ||
| 6365 | err = set_disk_faulty(mddev, new_decode_dev(arg)); | ||
| 6366 | goto abort; | ||
| 6367 | } | ||
| 6368 | |||
| 6318 | err = mddev_lock(mddev); | 6369 | err = mddev_lock(mddev); |
| 6319 | if (err) { | 6370 | if (err) { |
| 6320 | printk(KERN_INFO | 6371 | printk(KERN_INFO |
| @@ -6387,18 +6438,10 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, | |||
| 6387 | */ | 6438 | */ |
| 6388 | switch (cmd) | 6439 | switch (cmd) |
| 6389 | { | 6440 | { |
| 6390 | case GET_ARRAY_INFO: | ||
| 6391 | err = get_array_info(mddev, argp); | ||
| 6392 | goto done_unlock; | ||
| 6393 | |||
| 6394 | case GET_BITMAP_FILE: | 6441 | case GET_BITMAP_FILE: |
| 6395 | err = get_bitmap_file(mddev, argp); | 6442 | err = get_bitmap_file(mddev, argp); |
| 6396 | goto done_unlock; | 6443 | goto done_unlock; |
| 6397 | 6444 | ||
| 6398 | case GET_DISK_INFO: | ||
| 6399 | err = get_disk_info(mddev, argp); | ||
| 6400 | goto done_unlock; | ||
| 6401 | |||
| 6402 | case RESTART_ARRAY_RW: | 6445 | case RESTART_ARRAY_RW: |
| 6403 | err = restart_array(mddev); | 6446 | err = restart_array(mddev); |
| 6404 | goto done_unlock; | 6447 | goto done_unlock; |
| @@ -6480,10 +6523,6 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, | |||
| 6480 | err = hot_add_disk(mddev, new_decode_dev(arg)); | 6523 | err = hot_add_disk(mddev, new_decode_dev(arg)); |
| 6481 | goto done_unlock; | 6524 | goto done_unlock; |
| 6482 | 6525 | ||
| 6483 | case SET_DISK_FAULTY: | ||
| 6484 | err = set_disk_faulty(mddev, new_decode_dev(arg)); | ||
| 6485 | goto done_unlock; | ||
| 6486 | |||
| 6487 | case RUN_ARRAY: | 6526 | case RUN_ARRAY: |
| 6488 | err = do_md_run(mddev); | 6527 | err = do_md_run(mddev); |
| 6489 | goto done_unlock; | 6528 | goto done_unlock; |
