Skip to content

Commit

Permalink
md: avoid taking the mutex on some ioctls.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
neilbrown committed Oct 11, 2012
1 parent 4ed8731 commit 1ca69c4
Showing 1 changed file with 62 additions and 23 deletions.
85 changes: 62 additions & 23 deletions drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,18 @@ static struct md_rdev * find_rdev_nr(struct mddev *mddev, int nr)
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;

Expand All @@ -685,6 +696,17 @@ static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev)
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)
{
struct md_personality *pers;
Expand Down Expand Up @@ -5509,8 +5531,9 @@ static int get_array_info(struct mddev * mddev, void __user * arg)
int nr,working,insync,failed,spare;
struct md_rdev *rdev;

nr=working=insync=failed=spare=0;
rdev_for_each(rdev, mddev) {
nr = working = insync = failed = spare = 0;
rcu_read_lock();
rdev_for_each_rcu(rdev, mddev) {
nr++;
if (test_bit(Faulty, &rdev->flags))
failed++;
Expand All @@ -5522,6 +5545,7 @@ static int get_array_info(struct mddev * mddev, void __user * arg)
spare++;
}
}
rcu_read_unlock();

info.major_version = mddev->major_version;
info.minor_version = mddev->minor_version;
Expand Down Expand Up @@ -5605,7 +5629,8 @@ static int get_disk_info(struct mddev * mddev, void __user * arg)
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;

rdev = find_rdev_nr(mddev, info.number);
rcu_read_lock();
rdev = find_rdev_nr_rcu(mddev, info.number);
if (rdev) {
info.major = MAJOR(rdev->bdev->bd_dev);
info.minor = MINOR(rdev->bdev->bd_dev);
Expand All @@ -5624,6 +5649,7 @@ static int get_disk_info(struct mddev * mddev, void __user * arg)
info.raid_disk = -1;
info.state = (1<<MD_DISK_REMOVED);
}
rcu_read_unlock();

if (copy_to_user(arg, &info, sizeof(info)))
return -EFAULT;
Expand Down Expand Up @@ -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)
{
struct md_rdev *rdev;
int err = 0;

if (mddev->pers == NULL)
return -ENODEV;

rdev = find_rdev(mddev, dev);
rcu_read_lock();
rdev = find_rdev_rcu(mddev, dev);
if (!rdev)
return -ENODEV;

md_error(mddev, rdev);
if (!test_bit(Faulty, &rdev->flags))
return -EBUSY;
return 0;
err = -ENODEV;
else {
md_error(mddev, rdev);
if (!test_bit(Faulty, &rdev->flags))
err = -EBUSY;
}
rcu_read_unlock();
return err;
}

/*
Expand Down Expand Up @@ -6315,6 +6345,27 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
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);
if (err) {
printk(KERN_INFO
Expand Down Expand Up @@ -6387,18 +6438,10 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
*/
switch (cmd)
{
case GET_ARRAY_INFO:
err = get_array_info(mddev, argp);
goto done_unlock;

case GET_BITMAP_FILE:
err = get_bitmap_file(mddev, argp);
goto done_unlock;

case GET_DISK_INFO:
err = get_disk_info(mddev, argp);
goto done_unlock;

case RESTART_ARRAY_RW:
err = restart_array(mddev);
goto done_unlock;
Expand Down Expand Up @@ -6480,10 +6523,6 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
err = hot_add_disk(mddev, new_decode_dev(arg));
goto done_unlock;

case SET_DISK_FAULTY:
err = set_disk_faulty(mddev, new_decode_dev(arg));
goto done_unlock;

case RUN_ARRAY:
err = do_md_run(mddev);
goto done_unlock;
Expand Down

0 comments on commit 1ca69c4

Please sign in to comment.