aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/block/rbd.c134
1 files changed, 86 insertions, 48 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 7915f3b03736..bec5a50c9890 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -4584,47 +4584,95 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
4584 &rbd_dev->header.features); 4584 &rbd_dev->header.features);
4585} 4585}
4586 4586
4587struct parent_image_info {
4588 u64 pool_id;
4589 const char *image_id;
4590 u64 snap_id;
4591
4592 u64 overlap;
4593};
4594
4595/*
4596 * The caller is responsible for @pii.
4597 */
4598static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
4599 struct page *req_page,
4600 struct page *reply_page,
4601 struct parent_image_info *pii)
4602{
4603 struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
4604 size_t reply_len = PAGE_SIZE;
4605 void *p, *end;
4606 int ret;
4607
4608 ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
4609 "rbd", "get_parent", CEPH_OSD_FLAG_READ,
4610 req_page, sizeof(u64), reply_page, &reply_len);
4611 if (ret)
4612 return ret;
4613
4614 p = page_address(reply_page);
4615 end = p + reply_len;
4616 ceph_decode_64_safe(&p, end, pii->pool_id, e_inval);
4617 pii->image_id = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL);
4618 if (IS_ERR(pii->image_id)) {
4619 ret = PTR_ERR(pii->image_id);
4620 pii->image_id = NULL;
4621 return ret;
4622 }
4623 ceph_decode_64_safe(&p, end, pii->snap_id, e_inval);
4624 ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
4625
4626 return 0;
4627
4628e_inval:
4629 return -EINVAL;
4630}
4631
4632static int get_parent_info(struct rbd_device *rbd_dev,
4633 struct parent_image_info *pii)
4634{
4635 struct page *req_page, *reply_page;
4636 void *p;
4637 int ret;
4638
4639 req_page = alloc_page(GFP_KERNEL);
4640 if (!req_page)
4641 return -ENOMEM;
4642
4643 reply_page = alloc_page(GFP_KERNEL);
4644 if (!reply_page) {
4645 __free_page(req_page);
4646 return -ENOMEM;
4647 }
4648
4649 p = page_address(req_page);
4650 ceph_encode_64(&p, rbd_dev->spec->snap_id);
4651 ret = __get_parent_info_legacy(rbd_dev, req_page, reply_page, pii);
4652
4653 __free_page(req_page);
4654 __free_page(reply_page);
4655 return ret;
4656}
4657
4587static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) 4658static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4588{ 4659{
4589 struct rbd_spec *parent_spec; 4660 struct rbd_spec *parent_spec;
4590 size_t size; 4661 struct parent_image_info pii = { 0 };
4591 void *reply_buf = NULL;
4592 __le64 snapid;
4593 void *p;
4594 void *end;
4595 u64 pool_id;
4596 char *image_id;
4597 u64 snap_id;
4598 u64 overlap;
4599 int ret; 4662 int ret;
4600 4663
4601 parent_spec = rbd_spec_alloc(); 4664 parent_spec = rbd_spec_alloc();
4602 if (!parent_spec) 4665 if (!parent_spec)
4603 return -ENOMEM; 4666 return -ENOMEM;
4604 4667
4605 size = sizeof (__le64) + /* pool_id */ 4668 ret = get_parent_info(rbd_dev, &pii);
4606 sizeof (__le32) + RBD_IMAGE_ID_LEN_MAX + /* image_id */ 4669 if (ret)
4607 sizeof (__le64) + /* snap_id */
4608 sizeof (__le64); /* overlap */
4609 reply_buf = kmalloc(size, GFP_KERNEL);
4610 if (!reply_buf) {
4611 ret = -ENOMEM;
4612 goto out_err; 4670 goto out_err;
4613 }
4614 4671
4615 snapid = cpu_to_le64(rbd_dev->spec->snap_id); 4672 dout("%s pool_id %llu image_id %s snap_id %llu overlap %llu\n",
4616 ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid, 4673 __func__, pii.pool_id, pii.image_id, pii.snap_id, pii.overlap);
4617 &rbd_dev->header_oloc, "get_parent",
4618 &snapid, sizeof(snapid), reply_buf, size);
4619 dout("%s: rbd_obj_method_sync returned %d\n", __func__, ret);
4620 if (ret < 0)
4621 goto out_err;
4622 4674
4623 p = reply_buf; 4675 if (pii.pool_id == CEPH_NOPOOL) {
4624 end = reply_buf + ret;
4625 ret = -ERANGE;
4626 ceph_decode_64_safe(&p, end, pool_id, out_err);
4627 if (pool_id == CEPH_NOPOOL) {
4628 /* 4676 /*
4629 * Either the parent never existed, or we have 4677 * Either the parent never existed, or we have
4630 * record of it but the image got flattened so it no 4678 * record of it but the image got flattened so it no
@@ -4647,19 +4695,11 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4647 /* The ceph file layout needs to fit pool id in 32 bits */ 4695 /* The ceph file layout needs to fit pool id in 32 bits */
4648 4696
4649 ret = -EIO; 4697 ret = -EIO;
4650 if (pool_id > (u64)U32_MAX) { 4698 if (pii.pool_id > (u64)U32_MAX) {
4651 rbd_warn(NULL, "parent pool id too large (%llu > %u)", 4699 rbd_warn(NULL, "parent pool id too large (%llu > %u)",
4652 (unsigned long long)pool_id, U32_MAX); 4700 (unsigned long long)pii.pool_id, U32_MAX);
4653 goto out_err;
4654 }
4655
4656 image_id = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL);
4657 if (IS_ERR(image_id)) {
4658 ret = PTR_ERR(image_id);
4659 goto out_err; 4701 goto out_err;
4660 } 4702 }
4661 ceph_decode_64_safe(&p, end, snap_id, out_err);
4662 ceph_decode_64_safe(&p, end, overlap, out_err);
4663 4703
4664 /* 4704 /*
4665 * The parent won't change (except when the clone is 4705 * The parent won't change (except when the clone is
@@ -4667,9 +4707,10 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4667 * record the parent spec we have not already done so. 4707 * record the parent spec we have not already done so.
4668 */ 4708 */
4669 if (!rbd_dev->parent_spec) { 4709 if (!rbd_dev->parent_spec) {
4670 parent_spec->pool_id = pool_id; 4710 parent_spec->pool_id = pii.pool_id;
4671 parent_spec->image_id = image_id; 4711 parent_spec->image_id = pii.image_id;
4672 parent_spec->snap_id = snap_id; 4712 pii.image_id = NULL;
4713 parent_spec->snap_id = pii.snap_id;
4673 4714
4674 /* TODO: support cloning across namespaces */ 4715 /* TODO: support cloning across namespaces */
4675 if (rbd_dev->spec->pool_ns) { 4716 if (rbd_dev->spec->pool_ns) {
@@ -4683,15 +4724,13 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4683 4724
4684 rbd_dev->parent_spec = parent_spec; 4725 rbd_dev->parent_spec = parent_spec;
4685 parent_spec = NULL; /* rbd_dev now owns this */ 4726 parent_spec = NULL; /* rbd_dev now owns this */
4686 } else {
4687 kfree(image_id);
4688 } 4727 }
4689 4728
4690 /* 4729 /*
4691 * We always update the parent overlap. If it's zero we issue 4730 * We always update the parent overlap. If it's zero we issue
4692 * a warning, as we will proceed as if there was no parent. 4731 * a warning, as we will proceed as if there was no parent.
4693 */ 4732 */
4694 if (!overlap) { 4733 if (!pii.overlap) {
4695 if (parent_spec) { 4734 if (parent_spec) {
4696 /* refresh, careful to warn just once */ 4735 /* refresh, careful to warn just once */
4697 if (rbd_dev->parent_overlap) 4736 if (rbd_dev->parent_overlap)
@@ -4702,14 +4741,13 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4702 rbd_warn(rbd_dev, "clone is standalone (overlap 0)"); 4741 rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
4703 } 4742 }
4704 } 4743 }
4705 rbd_dev->parent_overlap = overlap; 4744 rbd_dev->parent_overlap = pii.overlap;
4706 4745
4707out: 4746out:
4708 ret = 0; 4747 ret = 0;
4709out_err: 4748out_err:
4710 kfree(reply_buf); 4749 kfree(pii.image_id);
4711 rbd_spec_put(parent_spec); 4750 rbd_spec_put(parent_spec);
4712
4713 return ret; 4751 return ret;
4714} 4752}
4715 4753