aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-09-29 15:33:20 +1000
committerNeilBrown <neilb@suse.de>2014-10-14 13:08:28 +1100
commit8b1afc3d6751063d3f0cdefe55719b1cd2f7edcc (patch)
treecbf069807f783e75cb18f6ae42847d982ddac05c /drivers/md
parentmd: avoid potential long delay under pers_lock (diff)
downloadlinux-dev-8b1afc3d6751063d3f0cdefe55719b1cd2f7edcc.tar.xz
linux-dev-8b1afc3d6751063d3f0cdefe55719b1cd2f7edcc.zip
md: Just use RCU when checking for overlap between arrays.
We don't really need the full mddev_lock here, and having to drop it is messy. RCU is enough to protect these lists. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/md.c15
1 files changed, 7 insertions, 8 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index d3a33a95e527..a7e9fae6c639 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2963,20 +2963,20 @@ rdev_size_store(struct md_rdev *rdev, const char *buf, size_t len)
rdev->sectors = sectors;
if (sectors > oldsectors && my_mddev->external) {
- /* need to check that all other rdevs with the same ->bdev
- * do not overlap. We need to unlock the mddev to avoid
- * a deadlock. We have already changed rdev->sectors, and if
- * we have to change it back, we will have the lock again.
+ /* Need to check that all other rdevs with the same
+ * ->bdev do not overlap. 'rcu' is sufficient to walk
+ * the rdev lists safely.
+ * This check does not provide a hard guarantee, it
+ * just helps avoid dangerous mistakes.
*/
struct mddev *mddev;
int overlap = 0;
struct list_head *tmp;
- mddev_unlock(my_mddev);
+ rcu_read_lock();
for_each_mddev(mddev, tmp) {
struct md_rdev *rdev2;
- mddev_lock_nointr(mddev);
rdev_for_each(rdev2, mddev)
if (rdev->bdev == rdev2->bdev &&
rdev != rdev2 &&
@@ -2986,13 +2986,12 @@ rdev_size_store(struct md_rdev *rdev, const char *buf, size_t len)
overlap = 1;
break;
}
- mddev_unlock(mddev);
if (overlap) {
mddev_put(mddev);
break;
}
}
- mddev_lock_nointr(my_mddev);
+ rcu_read_unlock();
if (overlap) {
/* Someone else could have slipped in a size
* change here, but doing so is just silly.