Skip to content

Commit

Permalink
rbd: factor out get_parent_info()
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
idryomov committed Sep 6, 2018
1 parent 8aaff15 commit eb3b2d6
Showing 1 changed file with 86 additions and 48 deletions.
134 changes: 86 additions & 48 deletions drivers/block/rbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -4584,47 +4584,95 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
&rbd_dev->header.features);
}

struct parent_image_info {
u64 pool_id;
const char *image_id;
u64 snap_id;

u64 overlap;
};

/*
* The caller is responsible for @pii.
*/
static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
struct page *req_page,
struct page *reply_page,
struct parent_image_info *pii)
{
struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
size_t reply_len = PAGE_SIZE;
void *p, *end;
int ret;

ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
"rbd", "get_parent", CEPH_OSD_FLAG_READ,
req_page, sizeof(u64), reply_page, &reply_len);
if (ret)
return ret;

p = page_address(reply_page);
end = p + reply_len;
ceph_decode_64_safe(&p, end, pii->pool_id, e_inval);
pii->image_id = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL);
if (IS_ERR(pii->image_id)) {
ret = PTR_ERR(pii->image_id);
pii->image_id = NULL;
return ret;
}
ceph_decode_64_safe(&p, end, pii->snap_id, e_inval);
ceph_decode_64_safe(&p, end, pii->overlap, e_inval);

return 0;

e_inval:
return -EINVAL;
}

static int get_parent_info(struct rbd_device *rbd_dev,
struct parent_image_info *pii)
{
struct page *req_page, *reply_page;
void *p;
int ret;

req_page = alloc_page(GFP_KERNEL);
if (!req_page)
return -ENOMEM;

reply_page = alloc_page(GFP_KERNEL);
if (!reply_page) {
__free_page(req_page);
return -ENOMEM;
}

p = page_address(req_page);
ceph_encode_64(&p, rbd_dev->spec->snap_id);
ret = __get_parent_info_legacy(rbd_dev, req_page, reply_page, pii);

__free_page(req_page);
__free_page(reply_page);
return ret;
}

static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
{
struct rbd_spec *parent_spec;
size_t size;
void *reply_buf = NULL;
__le64 snapid;
void *p;
void *end;
u64 pool_id;
char *image_id;
u64 snap_id;
u64 overlap;
struct parent_image_info pii = { 0 };
int ret;

parent_spec = rbd_spec_alloc();
if (!parent_spec)
return -ENOMEM;

size = sizeof (__le64) + /* pool_id */
sizeof (__le32) + RBD_IMAGE_ID_LEN_MAX + /* image_id */
sizeof (__le64) + /* snap_id */
sizeof (__le64); /* overlap */
reply_buf = kmalloc(size, GFP_KERNEL);
if (!reply_buf) {
ret = -ENOMEM;
ret = get_parent_info(rbd_dev, &pii);
if (ret)
goto out_err;
}

snapid = cpu_to_le64(rbd_dev->spec->snap_id);
ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
&rbd_dev->header_oloc, "get_parent",
&snapid, sizeof(snapid), reply_buf, size);
dout("%s: rbd_obj_method_sync returned %d\n", __func__, ret);
if (ret < 0)
goto out_err;
dout("%s pool_id %llu image_id %s snap_id %llu overlap %llu\n",
__func__, pii.pool_id, pii.image_id, pii.snap_id, pii.overlap);

p = reply_buf;
end = reply_buf + ret;
ret = -ERANGE;
ceph_decode_64_safe(&p, end, pool_id, out_err);
if (pool_id == CEPH_NOPOOL) {
if (pii.pool_id == CEPH_NOPOOL) {
/*
* Either the parent never existed, or we have
* record of it but the image got flattened so it no
Expand All @@ -4647,29 +4695,22 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
/* The ceph file layout needs to fit pool id in 32 bits */

ret = -EIO;
if (pool_id > (u64)U32_MAX) {
if (pii.pool_id > (u64)U32_MAX) {
rbd_warn(NULL, "parent pool id too large (%llu > %u)",
(unsigned long long)pool_id, U32_MAX);
goto out_err;
}

image_id = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL);
if (IS_ERR(image_id)) {
ret = PTR_ERR(image_id);
(unsigned long long)pii.pool_id, U32_MAX);
goto out_err;
}
ceph_decode_64_safe(&p, end, snap_id, out_err);
ceph_decode_64_safe(&p, end, overlap, out_err);

/*
* The parent won't change (except when the clone is
* flattened, already handled that). So we only need to
* record the parent spec we have not already done so.
*/
if (!rbd_dev->parent_spec) {
parent_spec->pool_id = pool_id;
parent_spec->image_id = image_id;
parent_spec->snap_id = snap_id;
parent_spec->pool_id = pii.pool_id;
parent_spec->image_id = pii.image_id;
pii.image_id = NULL;
parent_spec->snap_id = pii.snap_id;

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

rbd_dev->parent_spec = parent_spec;
parent_spec = NULL; /* rbd_dev now owns this */
} else {
kfree(image_id);
}

/*
* We always update the parent overlap. If it's zero we issue
* a warning, as we will proceed as if there was no parent.
*/
if (!overlap) {
if (!pii.overlap) {
if (parent_spec) {
/* refresh, careful to warn just once */
if (rbd_dev->parent_overlap)
Expand All @@ -4702,14 +4741,13 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
}
}
rbd_dev->parent_overlap = overlap;
rbd_dev->parent_overlap = pii.overlap;

out:
ret = 0;
out_err:
kfree(reply_buf);
kfree(pii.image_id);
rbd_spec_put(parent_spec);

return ret;
}

Expand Down

0 comments on commit eb3b2d6

Please sign in to comment.