An open request for a mapped rbd image can arrive while removal of
that mapping is underway.  The control mutex and an open count is
protect a mapped device that's in use from being removed.  But it
is possible for the removal of the mapping to reach the point of no
return *after* a racing open has concluded it is OK to proceed.  The
result of this is not good.

Define and use a flag to indicate a mapping is getting removed to
avoid this problem.

This addresses http://tracker.newdream.net/issues/3427

Signed-off-by: Alex Elder <el...@inktank.com>
---
 drivers/block/rbd.c |   15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 9eb1631..760f7f7 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -264,6 +264,7 @@ struct rbd_device {

 enum rbd_dev_flags {
        rbd_dev_flag_exists,    /* mapped snapshot has not been deleted */
+       rbd_dev_flag_removing,  /* this mapping is being removed */
 };

 static DEFINE_MUTEX(ctl_mutex);          /* Serialize 
open/close/setup/teardown */
@@ -351,17 +352,22 @@ static int rbd_dev_v2_refresh(struct rbd_device
*rbd_dev, u64 *hver);
 static int rbd_open(struct block_device *bdev, fmode_t mode)
 {
        struct rbd_device *rbd_dev = bdev->bd_disk->private_data;
+       int ret = 0;

        if ((mode & FMODE_WRITE) && rbd_dev->mapping.read_only)
                return -EROFS;

        mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-       (void) get_device(&rbd_dev->dev);
-       set_device_ro(bdev, rbd_dev->mapping.read_only);
-       rbd_dev->open_count++;
+       if (!test_bit(rbd_dev_flag_removing, &rbd_dev->flags)) {
+               (void) get_device(&rbd_dev->dev);
+               set_device_ro(bdev, rbd_dev->mapping.read_only);
+               rbd_dev->open_count++;
+       } else {
+               ret = -ENOENT;
+       }
        mutex_unlock(&ctl_mutex);

-       return 0;
+       return ret;
 }

 static int rbd_release(struct gendisk *disk, fmode_t mode)
@@ -3796,6 +3802,7 @@ static ssize_t rbd_remove(struct bus_type *bus,
                ret = -EBUSY;
                goto done;
        }
+       set_bit(rbd_dev_flag_removing, &rbd_dev->flags);

        rbd_remove_all_snaps(rbd_dev);
        rbd_bus_del_dev(rbd_dev);
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to