aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/rbd.c111
1 files changed, 97 insertions, 14 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index bec5a50c9890..73ed5f3a862d 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -4207,11 +4207,13 @@ static ssize_t rbd_parent_show(struct device *dev,
4207 4207
4208 count += sprintf(&buf[count], "%s" 4208 count += sprintf(&buf[count], "%s"
4209 "pool_id %llu\npool_name %s\n" 4209 "pool_id %llu\npool_name %s\n"
4210 "pool_ns %s\n"
4210 "image_id %s\nimage_name %s\n" 4211 "image_id %s\nimage_name %s\n"
4211 "snap_id %llu\nsnap_name %s\n" 4212 "snap_id %llu\nsnap_name %s\n"
4212 "overlap %llu\n", 4213 "overlap %llu\n",
4213 !count ? "" : "\n", /* first? */ 4214 !count ? "" : "\n", /* first? */
4214 spec->pool_id, spec->pool_name, 4215 spec->pool_id, spec->pool_name,
4216 spec->pool_ns ?: "",
4215 spec->image_id, spec->image_name ?: "(unknown)", 4217 spec->image_id, spec->image_name ?: "(unknown)",
4216 spec->snap_id, spec->snap_name, 4218 spec->snap_id, spec->snap_name,
4217 rbd_dev->parent_overlap); 4219 rbd_dev->parent_overlap);
@@ -4586,15 +4588,92 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
4586 4588
4587struct parent_image_info { 4589struct parent_image_info {
4588 u64 pool_id; 4590 u64 pool_id;
4591 const char *pool_ns;
4589 const char *image_id; 4592 const char *image_id;
4590 u64 snap_id; 4593 u64 snap_id;
4591 4594
4595 bool has_overlap;
4592 u64 overlap; 4596 u64 overlap;
4593}; 4597};
4594 4598
4595/* 4599/*
4596 * The caller is responsible for @pii. 4600 * The caller is responsible for @pii.
4597 */ 4601 */
4602static int decode_parent_image_spec(void **p, void *end,
4603 struct parent_image_info *pii)
4604{
4605 u8 struct_v;
4606 u32 struct_len;
4607 int ret;
4608
4609 ret = ceph_start_decoding(p, end, 1, "ParentImageSpec",
4610 &struct_v, &struct_len);
4611 if (ret)
4612 return ret;
4613
4614 ceph_decode_64_safe(p, end, pii->pool_id, e_inval);
4615 pii->pool_ns = ceph_extract_encoded_string(p, end, NULL, GFP_KERNEL);
4616 if (IS_ERR(pii->pool_ns)) {
4617 ret = PTR_ERR(pii->pool_ns);
4618 pii->pool_ns = NULL;
4619 return ret;
4620 }
4621 pii->image_id = ceph_extract_encoded_string(p, end, NULL, GFP_KERNEL);
4622 if (IS_ERR(pii->image_id)) {
4623 ret = PTR_ERR(pii->image_id);
4624 pii->image_id = NULL;
4625 return ret;
4626 }
4627 ceph_decode_64_safe(p, end, pii->snap_id, e_inval);
4628 return 0;
4629
4630e_inval:
4631 return -EINVAL;
4632}
4633
4634static int __get_parent_info(struct rbd_device *rbd_dev,
4635 struct page *req_page,
4636 struct page *reply_page,
4637 struct parent_image_info *pii)
4638{
4639 struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
4640 size_t reply_len = PAGE_SIZE;
4641 void *p, *end;
4642 int ret;
4643
4644 ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
4645 "rbd", "parent_get", CEPH_OSD_FLAG_READ,
4646 req_page, sizeof(u64), reply_page, &reply_len);
4647 if (ret)
4648 return ret == -EOPNOTSUPP ? 1 : ret;
4649
4650 p = page_address(reply_page);
4651 end = p + reply_len;
4652 ret = decode_parent_image_spec(&p, end, pii);
4653 if (ret)
4654 return ret;
4655
4656 ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
4657 "rbd", "parent_overlap_get", CEPH_OSD_FLAG_READ,
4658 req_page, sizeof(u64), reply_page, &reply_len);
4659 if (ret)
4660 return ret;
4661
4662 p = page_address(reply_page);
4663 end = p + reply_len;
4664 ceph_decode_8_safe(&p, end, pii->has_overlap, e_inval);
4665 if (pii->has_overlap)
4666 ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
4667
4668 return 0;
4669
4670e_inval:
4671 return -EINVAL;
4672}
4673
4674/*
4675 * The caller is responsible for @pii.
4676 */
4598static int __get_parent_info_legacy(struct rbd_device *rbd_dev, 4677static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
4599 struct page *req_page, 4678 struct page *req_page,
4600 struct page *reply_page, 4679 struct page *reply_page,
@@ -4621,6 +4700,7 @@ static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
4621 return ret; 4700 return ret;
4622 } 4701 }
4623 ceph_decode_64_safe(&p, end, pii->snap_id, e_inval); 4702 ceph_decode_64_safe(&p, end, pii->snap_id, e_inval);
4703 pii->has_overlap = true;
4624 ceph_decode_64_safe(&p, end, pii->overlap, e_inval); 4704 ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
4625 4705
4626 return 0; 4706 return 0;
@@ -4648,7 +4728,10 @@ static int get_parent_info(struct rbd_device *rbd_dev,
4648 4728
4649 p = page_address(req_page); 4729 p = page_address(req_page);
4650 ceph_encode_64(&p, rbd_dev->spec->snap_id); 4730 ceph_encode_64(&p, rbd_dev->spec->snap_id);
4651 ret = __get_parent_info_legacy(rbd_dev, req_page, reply_page, pii); 4731 ret = __get_parent_info(rbd_dev, req_page, reply_page, pii);
4732 if (ret > 0)
4733 ret = __get_parent_info_legacy(rbd_dev, req_page, reply_page,
4734 pii);
4652 4735
4653 __free_page(req_page); 4736 __free_page(req_page);
4654 __free_page(reply_page); 4737 __free_page(reply_page);
@@ -4669,10 +4752,11 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4669 if (ret) 4752 if (ret)
4670 goto out_err; 4753 goto out_err;
4671 4754
4672 dout("%s pool_id %llu image_id %s snap_id %llu overlap %llu\n", 4755 dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
4673 __func__, pii.pool_id, pii.image_id, pii.snap_id, pii.overlap); 4756 __func__, pii.pool_id, pii.pool_ns, pii.image_id, pii.snap_id,
4757 pii.has_overlap, pii.overlap);
4674 4758
4675 if (pii.pool_id == CEPH_NOPOOL) { 4759 if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap) {
4676 /* 4760 /*
4677 * Either the parent never existed, or we have 4761 * Either the parent never existed, or we have
4678 * record of it but the image got flattened so it no 4762 * record of it but the image got flattened so it no
@@ -4681,6 +4765,10 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4681 * overlap to 0. The effect of this is that all new 4765 * overlap to 0. The effect of this is that all new
4682 * requests will be treated as if the image had no 4766 * requests will be treated as if the image had no
4683 * parent. 4767 * parent.
4768 *
4769 * If !pii.has_overlap, the parent image spec is not
4770 * applicable. It's there to avoid duplication in each
4771 * snapshot record.
4684 */ 4772 */
4685 if (rbd_dev->parent_overlap) { 4773 if (rbd_dev->parent_overlap) {
4686 rbd_dev->parent_overlap = 0; 4774 rbd_dev->parent_overlap = 0;
@@ -4708,20 +4796,14 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4708 */ 4796 */
4709 if (!rbd_dev->parent_spec) { 4797 if (!rbd_dev->parent_spec) {
4710 parent_spec->pool_id = pii.pool_id; 4798 parent_spec->pool_id = pii.pool_id;
4799 if (pii.pool_ns && *pii.pool_ns) {
4800 parent_spec->pool_ns = pii.pool_ns;
4801 pii.pool_ns = NULL;
4802 }
4711 parent_spec->image_id = pii.image_id; 4803 parent_spec->image_id = pii.image_id;
4712 pii.image_id = NULL; 4804 pii.image_id = NULL;
4713 parent_spec->snap_id = pii.snap_id; 4805 parent_spec->snap_id = pii.snap_id;
4714 4806
4715 /* TODO: support cloning across namespaces */
4716 if (rbd_dev->spec->pool_ns) {
4717 parent_spec->pool_ns = kstrdup(rbd_dev->spec->pool_ns,
4718 GFP_KERNEL);
4719 if (!parent_spec->pool_ns) {
4720 ret = -ENOMEM;
4721 goto out_err;
4722 }
4723 }
4724
4725 rbd_dev->parent_spec = parent_spec; 4807 rbd_dev->parent_spec = parent_spec;
4726 parent_spec = NULL; /* rbd_dev now owns this */ 4808 parent_spec = NULL; /* rbd_dev now owns this */
4727 } 4809 }
@@ -4746,6 +4828,7 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4746out: 4828out:
4747 ret = 0; 4829 ret = 0;
4748out_err: 4830out_err:
4831 kfree(pii.pool_ns);
4749 kfree(pii.image_id); 4832 kfree(pii.image_id);
4750 rbd_spec_put(parent_spec); 4833 rbd_spec_put(parent_spec);
4751 return ret; 4834 return ret;