aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-10-10 22:37:33 -0400
committerNeilBrown <neilb@suse.de>2012-10-10 22:37:33 -0400
commit1ca69c4bc4b1ef889861db39f325901eadbf9497 (patch)
treea4c83843fc630c42853e1a5ecc51dff5ab3ef54f /drivers
parent4ed8731d8e6bd2a88a30697fbf4f7e6e979a6c46 (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.c85
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
677static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev) 677static 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
688static 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
699static 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
688static struct md_personality *find_pers(int level, char *clevel) 710static 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)
6232static int set_disk_faulty(struct mddev *mddev, dev_t dev) 6258static 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;