diff options
author | Alex Elder <elder@inktank.com> | 2013-05-31 18:40:44 -0400 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-07-03 18:32:41 -0400 |
commit | 82a442d239695a242c4d584464c9606322cd02aa (patch) | |
tree | 50ce1f9db9ecede73a92fc6ce1680e340495fee1 | |
parent | 751cc0e3cfabdda87c4c21519253c6751e97a8d4 (diff) |
rbd: protect against concurrent unmaps
Make sure two concurrent unmap operations on the same rbd device
won't collide, by only proceeding with the removal and cleanup of a
device if is not already underway.
Signed-off-by: Alex Elder <elder@inktank.com>
Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
-rw-r--r-- | drivers/block/rbd.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 9eead4879c90..305c740778c6 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -5137,6 +5137,7 @@ static ssize_t rbd_remove(struct bus_type *bus, | |||
5137 | struct list_head *tmp; | 5137 | struct list_head *tmp; |
5138 | int dev_id; | 5138 | int dev_id; |
5139 | unsigned long ul; | 5139 | unsigned long ul; |
5140 | bool already = false; | ||
5140 | int ret; | 5141 | int ret; |
5141 | 5142 | ||
5142 | ret = strict_strtoul(buf, 10, &ul); | 5143 | ret = strict_strtoul(buf, 10, &ul); |
@@ -5164,11 +5165,12 @@ static ssize_t rbd_remove(struct bus_type *bus, | |||
5164 | if (rbd_dev->open_count) | 5165 | if (rbd_dev->open_count) |
5165 | ret = -EBUSY; | 5166 | ret = -EBUSY; |
5166 | else | 5167 | else |
5167 | set_bit(RBD_DEV_FLAG_REMOVING, &rbd_dev->flags); | 5168 | already = test_and_set_bit(RBD_DEV_FLAG_REMOVING, |
5169 | &rbd_dev->flags); | ||
5168 | spin_unlock_irq(&rbd_dev->lock); | 5170 | spin_unlock_irq(&rbd_dev->lock); |
5169 | } | 5171 | } |
5170 | spin_unlock(&rbd_dev_list_lock); | 5172 | spin_unlock(&rbd_dev_list_lock); |
5171 | if (ret < 0) | 5173 | if (ret < 0 || already) |
5172 | goto done; | 5174 | goto done; |
5173 | 5175 | ||
5174 | rbd_bus_del_dev(rbd_dev); | 5176 | rbd_bus_del_dev(rbd_dev); |