diff options
-rw-r--r-- | drivers/block/rbd.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 8b6091b6d5cb..9717e20f3477 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -1929,6 +1929,11 @@ static void rbd_dev_parent_put(struct rbd_device *rbd_dev) | |||
1929 | * If an image has a non-zero parent overlap, get a reference to its | 1929 | * If an image has a non-zero parent overlap, get a reference to its |
1930 | * parent. | 1930 | * parent. |
1931 | * | 1931 | * |
1932 | * We must get the reference before checking for the overlap to | ||
1933 | * coordinate properly with zeroing the parent overlap in | ||
1934 | * rbd_dev_v2_parent_info() when an image gets flattened. We | ||
1935 | * drop it again if there is no overlap. | ||
1936 | * | ||
1932 | * Returns true if the rbd device has a parent with a non-zero | 1937 | * Returns true if the rbd device has a parent with a non-zero |
1933 | * overlap and a reference for it was successfully taken, or | 1938 | * overlap and a reference for it was successfully taken, or |
1934 | * false otherwise. | 1939 | * false otherwise. |
@@ -3782,8 +3787,26 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) | |||
3782 | end = reply_buf + ret; | 3787 | end = reply_buf + ret; |
3783 | ret = -ERANGE; | 3788 | ret = -ERANGE; |
3784 | ceph_decode_64_safe(&p, end, pool_id, out_err); | 3789 | ceph_decode_64_safe(&p, end, pool_id, out_err); |
3785 | if (pool_id == CEPH_NOPOOL) | 3790 | if (pool_id == CEPH_NOPOOL) { |
3791 | /* | ||
3792 | * Either the parent never existed, or we have | ||
3793 | * record of it but the image got flattened so it no | ||
3794 | * longer has a parent. When the parent of a | ||
3795 | * layered image disappears we immediately set the | ||
3796 | * overlap to 0. The effect of this is that all new | ||
3797 | * requests will be treated as if the image had no | ||
3798 | * parent. | ||
3799 | */ | ||
3800 | if (rbd_dev->parent_overlap) { | ||
3801 | rbd_dev->parent_overlap = 0; | ||
3802 | smp_mb(); | ||
3803 | rbd_dev_parent_put(rbd_dev); | ||
3804 | pr_info("%s: clone image has been flattened\n", | ||
3805 | rbd_dev->disk->disk_name); | ||
3806 | } | ||
3807 | |||
3786 | goto out; /* No parent? No problem. */ | 3808 | goto out; /* No parent? No problem. */ |
3809 | } | ||
3787 | 3810 | ||
3788 | /* The ceph file layout needs to fit pool id in 32 bits */ | 3811 | /* The ceph file layout needs to fit pool id in 32 bits */ |
3789 | 3812 | ||
@@ -4633,7 +4656,10 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev) | |||
4633 | { | 4656 | { |
4634 | struct rbd_image_header *header; | 4657 | struct rbd_image_header *header; |
4635 | 4658 | ||
4636 | rbd_dev_parent_put(rbd_dev); | 4659 | /* Drop parent reference unless it's already been done (or none) */ |
4660 | |||
4661 | if (rbd_dev->parent_overlap) | ||
4662 | rbd_dev_parent_put(rbd_dev); | ||
4637 | 4663 | ||
4638 | /* Free dynamic fields from the header, then zero it out */ | 4664 | /* Free dynamic fields from the header, then zero it out */ |
4639 | 4665 | ||