md: Just use RCU when checking for overlap between arrays.
authorNeilBrown <neilb@suse.de>
Mon, 29 Sep 2014 05:33:20 +0000 (15:33 +1000)
committerNeilBrown <neilb@suse.de>
Tue, 14 Oct 2014 02:08:28 +0000 (13:08 +1100)
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>
drivers/md/md.c

index d3a33a9..a7e9fae 100644 (file)
@@ -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.