aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/block/rbd.c235
-rw-r--r--fs/ceph/super.c16
2 files changed, 189 insertions, 62 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 7915f3b03736..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);
@@ -4584,47 +4586,177 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
4584 &rbd_dev->header.features); 4586 &rbd_dev->header.features);
4585} 4587}
4586 4588
4589struct parent_image_info {
4590 u64 pool_id;
4591 const char *pool_ns;
4592 const char *image_id;
4593 u64 snap_id;
4594
4595 bool has_overlap;
4596 u64 overlap;
4597};
4598
4599/*
4600 * The caller is responsible for @pii.
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 */
4677static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
4678 struct page *req_page,
4679 struct page *reply_page,
4680 struct parent_image_info *pii)
4681{
4682 struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
4683 size_t reply_len = PAGE_SIZE;
4684 void *p, *end;
4685 int ret;
4686
4687 ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
4688 "rbd", "get_parent", CEPH_OSD_FLAG_READ,
4689 req_page, sizeof(u64), reply_page, &reply_len);
4690 if (ret)
4691 return ret;
4692
4693 p = page_address(reply_page);
4694 end = p + reply_len;
4695 ceph_decode_64_safe(&p, end, pii->pool_id, e_inval);
4696 pii->image_id = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL);
4697 if (IS_ERR(pii->image_id)) {
4698 ret = PTR_ERR(pii->image_id);
4699 pii->image_id = NULL;
4700 return ret;
4701 }
4702 ceph_decode_64_safe(&p, end, pii->snap_id, e_inval);
4703 pii->has_overlap = true;
4704 ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
4705
4706 return 0;
4707
4708e_inval:
4709 return -EINVAL;
4710}
4711
4712static int get_parent_info(struct rbd_device *rbd_dev,
4713 struct parent_image_info *pii)
4714{
4715 struct page *req_page, *reply_page;
4716 void *p;
4717 int ret;
4718
4719 req_page = alloc_page(GFP_KERNEL);
4720 if (!req_page)
4721 return -ENOMEM;
4722
4723 reply_page = alloc_page(GFP_KERNEL);
4724 if (!reply_page) {
4725 __free_page(req_page);
4726 return -ENOMEM;
4727 }
4728
4729 p = page_address(req_page);
4730 ceph_encode_64(&p, rbd_dev->spec->snap_id);
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);
4735
4736 __free_page(req_page);
4737 __free_page(reply_page);
4738 return ret;
4739}
4740
4587static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) 4741static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4588{ 4742{
4589 struct rbd_spec *parent_spec; 4743 struct rbd_spec *parent_spec;
4590 size_t size; 4744 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; 4745 int ret;
4600 4746
4601 parent_spec = rbd_spec_alloc(); 4747 parent_spec = rbd_spec_alloc();
4602 if (!parent_spec) 4748 if (!parent_spec)
4603 return -ENOMEM; 4749 return -ENOMEM;
4604 4750
4605 size = sizeof (__le64) + /* pool_id */ 4751 ret = get_parent_info(rbd_dev, &pii);
4606 sizeof (__le32) + RBD_IMAGE_ID_LEN_MAX + /* image_id */ 4752 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; 4753 goto out_err;
4613 }
4614 4754
4615 snapid = cpu_to_le64(rbd_dev->spec->snap_id); 4755 dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
4616 ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid, 4756 __func__, pii.pool_id, pii.pool_ns, pii.image_id, pii.snap_id,
4617 &rbd_dev->header_oloc, "get_parent", 4757 pii.has_overlap, pii.overlap);
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 4758
4623 p = reply_buf; 4759 if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap) {
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 /* 4760 /*
4629 * Either the parent never existed, or we have 4761 * Either the parent never existed, or we have
4630 * record of it but the image got flattened so it no 4762 * record of it but the image got flattened so it no
@@ -4633,6 +4765,10 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4633 * overlap to 0. The effect of this is that all new 4765 * overlap to 0. The effect of this is that all new
4634 * requests will be treated as if the image had no 4766 * requests will be treated as if the image had no
4635 * 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.
4636 */ 4772 */
4637 if (rbd_dev->parent_overlap) { 4773 if (rbd_dev->parent_overlap) {
4638 rbd_dev->parent_overlap = 0; 4774 rbd_dev->parent_overlap = 0;
@@ -4647,51 +4783,36 @@ 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 */ 4783 /* The ceph file layout needs to fit pool id in 32 bits */
4648 4784
4649 ret = -EIO; 4785 ret = -EIO;
4650 if (pool_id > (u64)U32_MAX) { 4786 if (pii.pool_id > (u64)U32_MAX) {
4651 rbd_warn(NULL, "parent pool id too large (%llu > %u)", 4787 rbd_warn(NULL, "parent pool id too large (%llu > %u)",
4652 (unsigned long long)pool_id, U32_MAX); 4788 (unsigned long long)pii.pool_id, U32_MAX);
4653 goto out_err; 4789 goto out_err;
4654 } 4790 }
4655 4791
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;
4660 }
4661 ceph_decode_64_safe(&p, end, snap_id, out_err);
4662 ceph_decode_64_safe(&p, end, overlap, out_err);
4663
4664 /* 4792 /*
4665 * The parent won't change (except when the clone is 4793 * The parent won't change (except when the clone is
4666 * flattened, already handled that). So we only need to 4794 * flattened, already handled that). So we only need to
4667 * record the parent spec we have not already done so. 4795 * record the parent spec we have not already done so.
4668 */ 4796 */
4669 if (!rbd_dev->parent_spec) { 4797 if (!rbd_dev->parent_spec) {
4670 parent_spec->pool_id = pool_id; 4798 parent_spec->pool_id = pii.pool_id;
4671 parent_spec->image_id = image_id; 4799 if (pii.pool_ns && *pii.pool_ns) {
4672 parent_spec->snap_id = snap_id; 4800 parent_spec->pool_ns = pii.pool_ns;
4673 4801 pii.pool_ns = NULL;
4674 /* TODO: support cloning across namespaces */
4675 if (rbd_dev->spec->pool_ns) {
4676 parent_spec->pool_ns = kstrdup(rbd_dev->spec->pool_ns,
4677 GFP_KERNEL);
4678 if (!parent_spec->pool_ns) {
4679 ret = -ENOMEM;
4680 goto out_err;
4681 }
4682 } 4802 }
4803 parent_spec->image_id = pii.image_id;
4804 pii.image_id = NULL;
4805 parent_spec->snap_id = pii.snap_id;
4683 4806
4684 rbd_dev->parent_spec = parent_spec; 4807 rbd_dev->parent_spec = parent_spec;
4685 parent_spec = NULL; /* rbd_dev now owns this */ 4808 parent_spec = NULL; /* rbd_dev now owns this */
4686 } else {
4687 kfree(image_id);
4688 } 4809 }
4689 4810
4690 /* 4811 /*
4691 * We always update the parent overlap. If it's zero we issue 4812 * 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. 4813 * a warning, as we will proceed as if there was no parent.
4693 */ 4814 */
4694 if (!overlap) { 4815 if (!pii.overlap) {
4695 if (parent_spec) { 4816 if (parent_spec) {
4696 /* refresh, careful to warn just once */ 4817 /* refresh, careful to warn just once */
4697 if (rbd_dev->parent_overlap) 4818 if (rbd_dev->parent_overlap)
@@ -4702,14 +4823,14 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4702 rbd_warn(rbd_dev, "clone is standalone (overlap 0)"); 4823 rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
4703 } 4824 }
4704 } 4825 }
4705 rbd_dev->parent_overlap = overlap; 4826 rbd_dev->parent_overlap = pii.overlap;
4706 4827
4707out: 4828out:
4708 ret = 0; 4829 ret = 0;
4709out_err: 4830out_err:
4710 kfree(reply_buf); 4831 kfree(pii.pool_ns);
4832 kfree(pii.image_id);
4711 rbd_spec_put(parent_spec); 4833 rbd_spec_put(parent_spec);
4712
4713 return ret; 4834 return ret;
4714} 4835}
4715 4836
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index 43ca3b763875..eab1359d0553 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -602,6 +602,8 @@ static int extra_mon_dispatch(struct ceph_client *client, struct ceph_msg *msg)
602 602
603/* 603/*
604 * create a new fs client 604 * create a new fs client
605 *
606 * Success or not, this function consumes @fsopt and @opt.
605 */ 607 */
606static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, 608static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
607 struct ceph_options *opt) 609 struct ceph_options *opt)
@@ -609,17 +611,20 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
609 struct ceph_fs_client *fsc; 611 struct ceph_fs_client *fsc;
610 int page_count; 612 int page_count;
611 size_t size; 613 size_t size;
612 int err = -ENOMEM; 614 int err;
613 615
614 fsc = kzalloc(sizeof(*fsc), GFP_KERNEL); 616 fsc = kzalloc(sizeof(*fsc), GFP_KERNEL);
615 if (!fsc) 617 if (!fsc) {
616 return ERR_PTR(-ENOMEM); 618 err = -ENOMEM;
619 goto fail;
620 }
617 621
618 fsc->client = ceph_create_client(opt, fsc); 622 fsc->client = ceph_create_client(opt, fsc);
619 if (IS_ERR(fsc->client)) { 623 if (IS_ERR(fsc->client)) {
620 err = PTR_ERR(fsc->client); 624 err = PTR_ERR(fsc->client);
621 goto fail; 625 goto fail;
622 } 626 }
627 opt = NULL; /* fsc->client now owns this */
623 628
624 fsc->client->extra_mon_dispatch = extra_mon_dispatch; 629 fsc->client->extra_mon_dispatch = extra_mon_dispatch;
625 fsc->client->osdc.abort_on_full = true; 630 fsc->client->osdc.abort_on_full = true;
@@ -677,6 +682,9 @@ fail_client:
677 ceph_destroy_client(fsc->client); 682 ceph_destroy_client(fsc->client);
678fail: 683fail:
679 kfree(fsc); 684 kfree(fsc);
685 if (opt)
686 ceph_destroy_options(opt);
687 destroy_mount_options(fsopt);
680 return ERR_PTR(err); 688 return ERR_PTR(err);
681} 689}
682 690
@@ -1042,8 +1050,6 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
1042 fsc = create_fs_client(fsopt, opt); 1050 fsc = create_fs_client(fsopt, opt);
1043 if (IS_ERR(fsc)) { 1051 if (IS_ERR(fsc)) {
1044 res = ERR_CAST(fsc); 1052 res = ERR_CAST(fsc);
1045 destroy_mount_options(fsopt);
1046 ceph_destroy_options(opt);
1047 goto out_final; 1053 goto out_final;
1048 } 1054 }
1049 1055