Skip to content

Commit eb3b2d6

Browse files
committed
rbd: factor out get_parent_info()
In preparation for the new parent_get and parent_overlap_get class methods, factor out the fetching and decoding of parent data. As a side effect, we now decode all four fields in the "no parent" case. Signed-off-by: Ilya Dryomov <[email protected]> Reviewed-by: Jason Dillaman <[email protected]>
1 parent 8aaff15 commit eb3b2d6

File tree

1 file changed

+86
-48
lines changed

1 file changed

+86
-48
lines changed

drivers/block/rbd.c

Lines changed: 86 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4584,47 +4584,95 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
45844584
&rbd_dev->header.features);
45854585
}
45864586

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+
45874658
static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
45884659
{
45894660
struct rbd_spec *parent_spec;
4590-
size_t size;
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;
4661+
struct parent_image_info pii = { 0 };
45994662
int ret;
46004663

46014664
parent_spec = rbd_spec_alloc();
46024665
if (!parent_spec)
46034666
return -ENOMEM;
46044667

4605-
size = sizeof (__le64) + /* pool_id */
4606-
sizeof (__le32) + RBD_IMAGE_ID_LEN_MAX + /* image_id */
4607-
sizeof (__le64) + /* snap_id */
4608-
sizeof (__le64); /* overlap */
4609-
reply_buf = kmalloc(size, GFP_KERNEL);
4610-
if (!reply_buf) {
4611-
ret = -ENOMEM;
4668+
ret = get_parent_info(rbd_dev, &pii);
4669+
if (ret)
46124670
goto out_err;
4613-
}
46144671

4615-
snapid = cpu_to_le64(rbd_dev->spec->snap_id);
4616-
ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
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;
4672+
dout("%s pool_id %llu image_id %s snap_id %llu overlap %llu\n",
4673+
__func__, pii.pool_id, pii.image_id, pii.snap_id, pii.overlap);
46224674

4623-
p = reply_buf;
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) {
4675+
if (pii.pool_id == CEPH_NOPOOL) {
46284676
/*
46294677
* Either the parent never existed, or we have
46304678
* record of it but the image got flattened so it no
@@ -4647,29 +4695,22 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
46474695
/* The ceph file layout needs to fit pool id in 32 bits */
46484696

46494697
ret = -EIO;
4650-
if (pool_id > (u64)U32_MAX) {
4698+
if (pii.pool_id > (u64)U32_MAX) {
46514699
rbd_warn(NULL, "parent pool id too large (%llu > %u)",
4652-
(unsigned long long)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);
4700+
(unsigned long long)pii.pool_id, U32_MAX);
46594701
goto out_err;
46604702
}
4661-
ceph_decode_64_safe(&p, end, snap_id, out_err);
4662-
ceph_decode_64_safe(&p, end, overlap, out_err);
46634703

46644704
/*
46654705
* The parent won't change (except when the clone is
46664706
* flattened, already handled that). So we only need to
46674707
* record the parent spec we have not already done so.
46684708
*/
46694709
if (!rbd_dev->parent_spec) {
4670-
parent_spec->pool_id = pool_id;
4671-
parent_spec->image_id = image_id;
4672-
parent_spec->snap_id = snap_id;
4710+
parent_spec->pool_id = pii.pool_id;
4711+
parent_spec->image_id = pii.image_id;
4712+
pii.image_id = NULL;
4713+
parent_spec->snap_id = pii.snap_id;
46734714

46744715
/* TODO: support cloning across namespaces */
46754716
if (rbd_dev->spec->pool_ns) {
@@ -4683,15 +4724,13 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
46834724

46844725
rbd_dev->parent_spec = parent_spec;
46854726
parent_spec = NULL; /* rbd_dev now owns this */
4686-
} else {
4687-
kfree(image_id);
46884727
}
46894728

46904729
/*
46914730
* We always update the parent overlap. If it's zero we issue
46924731
* a warning, as we will proceed as if there was no parent.
46934732
*/
4694-
if (!overlap) {
4733+
if (!pii.overlap) {
46954734
if (parent_spec) {
46964735
/* refresh, careful to warn just once */
46974736
if (rbd_dev->parent_overlap)
@@ -4702,14 +4741,13 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
47024741
rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
47034742
}
47044743
}
4705-
rbd_dev->parent_overlap = overlap;
4744+
rbd_dev->parent_overlap = pii.overlap;
47064745

47074746
out:
47084747
ret = 0;
47094748
out_err:
4710-
kfree(reply_buf);
4749+
kfree(pii.image_id);
47114750
rbd_spec_put(parent_spec);
4712-
47134751
return ret;
47144752
}
47154753

0 commit comments

Comments
 (0)