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; |