diff options
author | NeilBrown <neilb@suse.de> | 2014-09-29 15:33:20 +1000 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2014-10-14 13:08:28 +1100 |
commit | 8b1afc3d6751063d3f0cdefe55719b1cd2f7edcc (patch) | |
tree | cbf069807f783e75cb18f6ae42847d982ddac05c /drivers/md | |
parent | 50bd3774058137e687b41da8b31fdd3544f7d901 (diff) |
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.c | 15 |
1 files changed, 7 insertions, 8 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index d3a33a95e52..a7e9fae6c63 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. |