aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/rbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/rbd.c')
-rw-r--r--drivers/block/rbd.c25
1 files changed, 7 insertions, 18 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 3ec85dfce124..8a86b62466f7 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -2098,32 +2098,26 @@ static void rbd_dev_parent_put(struct rbd_device *rbd_dev)
2098 * If an image has a non-zero parent overlap, get a reference to its 2098 * If an image has a non-zero parent overlap, get a reference to its
2099 * parent. 2099 * parent.
2100 * 2100 *
2101 * We must get the reference before checking for the overlap to
2102 * coordinate properly with zeroing the parent overlap in
2103 * rbd_dev_v2_parent_info() when an image gets flattened. We
2104 * drop it again if there is no overlap.
2105 *
2106 * Returns true if the rbd device has a parent with a non-zero 2101 * Returns true if the rbd device has a parent with a non-zero
2107 * overlap and a reference for it was successfully taken, or 2102 * overlap and a reference for it was successfully taken, or
2108 * false otherwise. 2103 * false otherwise.
2109 */ 2104 */
2110static bool rbd_dev_parent_get(struct rbd_device *rbd_dev) 2105static bool rbd_dev_parent_get(struct rbd_device *rbd_dev)
2111{ 2106{
2112 int counter; 2107 int counter = 0;
2113 2108
2114 if (!rbd_dev->parent_spec) 2109 if (!rbd_dev->parent_spec)
2115 return false; 2110 return false;
2116 2111
2117 counter = atomic_inc_return_safe(&rbd_dev->parent_ref); 2112 down_read(&rbd_dev->header_rwsem);
2118 if (counter > 0 && rbd_dev->parent_overlap) 2113 if (rbd_dev->parent_overlap)
2119 return true; 2114 counter = atomic_inc_return_safe(&rbd_dev->parent_ref);
2120 2115 up_read(&rbd_dev->header_rwsem);
2121 /* Image was flattened, but parent is not yet torn down */
2122 2116
2123 if (counter < 0) 2117 if (counter < 0)
2124 rbd_warn(rbd_dev, "parent reference overflow"); 2118 rbd_warn(rbd_dev, "parent reference overflow");
2125 2119
2126 return false; 2120 return counter > 0;
2127} 2121}
2128 2122
2129/* 2123/*
@@ -4239,7 +4233,6 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4239 */ 4233 */
4240 if (rbd_dev->parent_overlap) { 4234 if (rbd_dev->parent_overlap) {
4241 rbd_dev->parent_overlap = 0; 4235 rbd_dev->parent_overlap = 0;
4242 smp_mb();
4243 rbd_dev_parent_put(rbd_dev); 4236 rbd_dev_parent_put(rbd_dev);
4244 pr_info("%s: clone image has been flattened\n", 4237 pr_info("%s: clone image has been flattened\n",
4245 rbd_dev->disk->disk_name); 4238 rbd_dev->disk->disk_name);
@@ -4285,7 +4278,6 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4285 * treat it specially. 4278 * treat it specially.
4286 */ 4279 */
4287 rbd_dev->parent_overlap = overlap; 4280 rbd_dev->parent_overlap = overlap;
4288 smp_mb();
4289 if (!overlap) { 4281 if (!overlap) {
4290 4282
4291 /* A null parent_spec indicates it's the initial probe */ 4283 /* A null parent_spec indicates it's the initial probe */
@@ -5114,10 +5106,7 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
5114{ 5106{
5115 struct rbd_image_header *header; 5107 struct rbd_image_header *header;
5116 5108
5117 /* Drop parent reference unless it's already been done (or none) */ 5109 rbd_dev_parent_put(rbd_dev);
5118
5119 if (rbd_dev->parent_overlap)
5120 rbd_dev_parent_put(rbd_dev);
5121 5110
5122 /* Free dynamic fields from the header, then zero it out */ 5111 /* Free dynamic fields from the header, then zero it out */
5123 5112