|
@@ -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)
|
|
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)
|
|
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;
|
|
|
|
- rdev_for_each(rdev, mddev) {
|
|
|
|
|
|
+ nr = working = insync = failed = spare = 0;
|
|
|
|
+ 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)
|
|
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)
|
|
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)
|
|
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)
|
|
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;
|
|
|
|
-
|
|
|
|
- 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;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -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,
|
|
*/
|
|
*/
|
|
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,
|
|
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;
|