Commit 1ca69c4b authored by NeilBrown's avatar NeilBrown

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: default avatarNeilBrown <neilb@suse.de>
parent 4ed8731d
...@@ -674,7 +674,18 @@ static struct md_rdev * find_rdev_nr(struct mddev *mddev, int nr) ...@@ -674,7 +674,18 @@ static struct md_rdev * find_rdev_nr(struct mddev *mddev, int nr)
return NULL; return NULL;
} }
static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev) static struct md_rdev *find_rdev_nr_rcu(struct mddev *mddev, int nr)
{
struct md_rdev *rdev;
rdev_for_each_rcu(rdev, mddev)
if (rdev->desc_nr == nr)
return rdev;
return NULL;
}
static struct md_rdev *find_rdev(struct mddev *mddev, dev_t dev)
{ {
struct md_rdev *rdev; struct md_rdev *rdev;
...@@ -685,6 +696,17 @@ static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev) ...@@ -685,6 +696,17 @@ static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev)
return NULL; return NULL;
} }
static struct md_rdev *find_rdev_rcu(struct mddev *mddev, dev_t dev)
{
struct md_rdev *rdev;
rdev_for_each_rcu(rdev, mddev)
if (rdev->bdev->bd_dev == dev)
return rdev;
return NULL;
}
static struct md_personality *find_pers(int level, char *clevel) static struct md_personality *find_pers(int level, char *clevel)
{ {
struct md_personality *pers; struct md_personality *pers;
...@@ -5509,8 +5531,9 @@ static int get_array_info(struct mddev * mddev, void __user * arg) ...@@ -5509,8 +5531,9 @@ static int get_array_info(struct mddev * mddev, void __user * arg)
int nr,working,insync,failed,spare; int nr,working,insync,failed,spare;
struct md_rdev *rdev; struct md_rdev *rdev;
nr=working=insync=failed=spare=0; nr = working = insync = failed = spare = 0;
rdev_for_each(rdev, mddev) { rcu_read_lock();
rdev_for_each_rcu(rdev, mddev) {
nr++; nr++;
if (test_bit(Faulty, &rdev->flags)) if (test_bit(Faulty, &rdev->flags))
failed++; failed++;
...@@ -5522,6 +5545,7 @@ static int get_array_info(struct mddev * mddev, void __user * arg) ...@@ -5522,6 +5545,7 @@ static int get_array_info(struct mddev * mddev, void __user * arg)
spare++; spare++;
} }
} }
rcu_read_unlock();
info.major_version = mddev->major_version; info.major_version = mddev->major_version;
info.minor_version = mddev->minor_version; info.minor_version = mddev->minor_version;
...@@ -5605,7 +5629,8 @@ static int get_disk_info(struct mddev * mddev, void __user * arg) ...@@ -5605,7 +5629,8 @@ static int get_disk_info(struct mddev * mddev, void __user * arg)
if (copy_from_user(&info, arg, sizeof(info))) if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT; return -EFAULT;
rdev = find_rdev_nr(mddev, info.number); rcu_read_lock();
rdev = find_rdev_nr_rcu(mddev, info.number);
if (rdev) { if (rdev) {
info.major = MAJOR(rdev->bdev->bd_dev); info.major = MAJOR(rdev->bdev->bd_dev);
info.minor = MINOR(rdev->bdev->bd_dev); info.minor = MINOR(rdev->bdev->bd_dev);
...@@ -5624,6 +5649,7 @@ static int get_disk_info(struct mddev * mddev, void __user * arg) ...@@ -5624,6 +5649,7 @@ static int get_disk_info(struct mddev * mddev, void __user * arg)
info.raid_disk = -1; info.raid_disk = -1;
info.state = (1<<MD_DISK_REMOVED); info.state = (1<<MD_DISK_REMOVED);
} }
rcu_read_unlock();
if (copy_to_user(arg, &info, sizeof(info))) if (copy_to_user(arg, &info, sizeof(info)))
return -EFAULT; return -EFAULT;
...@@ -6232,18 +6258,22 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) ...@@ -6232,18 +6258,22 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
static int set_disk_faulty(struct mddev *mddev, dev_t dev) static int set_disk_faulty(struct mddev *mddev, dev_t dev)
{ {
struct md_rdev *rdev; struct md_rdev *rdev;
int err = 0;
if (mddev->pers == NULL) if (mddev->pers == NULL)
return -ENODEV; return -ENODEV;
rdev = find_rdev(mddev, dev); rcu_read_lock();
rdev = find_rdev_rcu(mddev, dev);
if (!rdev) if (!rdev)
return -ENODEV; err = -ENODEV;
else {
md_error(mddev, rdev); md_error(mddev, rdev);
if (!test_bit(Faulty, &rdev->flags)) if (!test_bit(Faulty, &rdev->flags))
return -EBUSY; err = -EBUSY;
return 0; }
rcu_read_unlock();
return err;
} }
/* /*
...@@ -6315,6 +6345,27 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -6315,6 +6345,27 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
goto abort; goto abort;
} }
/* Some actions do not requires the mutex */
switch (cmd) {
case GET_ARRAY_INFO:
if (!mddev->raid_disks && !mddev->external)
err = -ENODEV;
else
err = get_array_info(mddev, argp);
goto abort;
case GET_DISK_INFO:
if (!mddev->raid_disks && !mddev->external)
err = -ENODEV;
else
err = get_disk_info(mddev, argp);
goto abort;
case SET_DISK_FAULTY:
err = set_disk_faulty(mddev, new_decode_dev(arg));
goto abort;
}
err = mddev_lock(mddev); err = mddev_lock(mddev);
if (err) { if (err) {
printk(KERN_INFO printk(KERN_INFO
...@@ -6387,18 +6438,10 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -6387,18 +6438,10 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
*/ */
switch (cmd) switch (cmd)
{ {
case GET_ARRAY_INFO:
err = get_array_info(mddev, argp);
goto done_unlock;
case GET_BITMAP_FILE: case GET_BITMAP_FILE:
err = get_bitmap_file(mddev, argp); err = get_bitmap_file(mddev, argp);
goto done_unlock; goto done_unlock;
case GET_DISK_INFO:
err = get_disk_info(mddev, argp);
goto done_unlock;
case RESTART_ARRAY_RW: case RESTART_ARRAY_RW:
err = restart_array(mddev); err = restart_array(mddev);
goto done_unlock; goto done_unlock;
...@@ -6480,10 +6523,6 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -6480,10 +6523,6 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
err = hot_add_disk(mddev, new_decode_dev(arg)); err = hot_add_disk(mddev, new_decode_dev(arg));
goto done_unlock; goto done_unlock;
case SET_DISK_FAULTY:
err = set_disk_faulty(mddev, new_decode_dev(arg));
goto done_unlock;
case RUN_ARRAY: case RUN_ARRAY:
err = do_md_run(mddev); err = do_md_run(mddev);
goto done_unlock; goto done_unlock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment