diff options
| -rw-r--r-- | drivers/block/rbd.c | 134 |
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 | ||
| 4587 | struct 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 | */ | ||
| 4598 | static 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 | |||
| 4628 | e_inval: | ||
| 4629 | return -EINVAL; | ||
| 4630 | } | ||
| 4631 | |||
| 4632 | static 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 | |||
| 4587 | static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) | 4658 | static 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 | ||
| 4707 | out: | 4746 | out: |
| 4708 | ret = 0; | 4747 | ret = 0; |
| 4709 | out_err: | 4748 | out_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 | ||
