aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2013-05-06 18:40:33 -0400
committerAlex Elder <elder@inktank.com>2013-05-13 16:06:45 -0400
commit392a9dad7e777296fe79d97a6b3acd735ad2eb5f (patch)
tree3007be625c9d59c38184bce538c20bf233441b06 /drivers/block
parenta2acd00e7964dbb1668a5956c9d0a4bdeb838c4a (diff)
rbd: detect when clone image is flattened
A format 2 clone image can be the subject of a "flatten" operation, during which all of its data gets "copied up" from its parent image, leaving the image fully populated. Once this is complete, the clone's association with the parent is abolished. Since this can occur when a clone is mapped, we need to detect when it has occurred and handle it accordingly. We know an image has been flattened when we know it at one time had a parent, but we have learned (via a "get_parent" object class method call) it no longer has one. There might be in-flight requests at the point we learn an image has been flattened, so we can't simply clean up parent data structures right away. Instead, we'll drop the initial parent reference when the parent has disappeared (rather than when the image gets destroyed), which will allow the last in-flight reference to clean things up when it's complete. We leverage the fact that a zero parent overlap renders an image effectively unlayered. We set the overlap to 0 at the point we detect the clone image has flattened, which allows the unlayered behavior to take effect immediately, while keeping other parent structures in place until in-flight requests to complete. This and the next few patches resolve: http://tracker.ceph.com/issues/3763 Signed-off-by: Alex Elder <elder@inktank.com> Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/rbd.c30
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