mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 22:02:02 +00:00
rbd: decouple parent info read-in from updating rbd_dev
Unlike header read-in, parent info read-in is already decoupled in get_parent_info(), but it's buried in rbd_dev_v2_parent_info() along with the processing logic. Separate the initial read-in and update read-in logic into rbd_dev_setup_parent() and rbd_dev_update_parent() respectively and have rbd_dev_v2_parent_info() just populate struct parent_image_info (i.e. what get_parent_info() did). Some existing QoI issues, like flatten of a standalone clone being disregarded on refresh, remain. Signed-off-by: Ilya Dryomov <idryomov@gmail.com> Reviewed-by: Dongsheng Yang <dongsheng.yang@easystack.cn>
This commit is contained in:
parent
510a7330c8
commit
c10311776f
1 changed files with 80 additions and 62 deletions
|
@ -5594,6 +5594,14 @@ struct parent_image_info {
|
||||||
u64 overlap;
|
u64 overlap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void rbd_parent_info_cleanup(struct parent_image_info *pii)
|
||||||
|
{
|
||||||
|
kfree(pii->pool_ns);
|
||||||
|
kfree(pii->image_id);
|
||||||
|
|
||||||
|
memset(pii, 0, sizeof(*pii));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The caller is responsible for @pii.
|
* The caller is responsible for @pii.
|
||||||
*/
|
*/
|
||||||
|
@ -5663,6 +5671,9 @@ static int __get_parent_info(struct rbd_device *rbd_dev,
|
||||||
if (pii->has_overlap)
|
if (pii->has_overlap)
|
||||||
ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
|
ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
|
||||||
|
|
||||||
|
dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
|
||||||
|
__func__, pii->pool_id, pii->pool_ns, pii->image_id, pii->snap_id,
|
||||||
|
pii->has_overlap, pii->overlap);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
e_inval:
|
e_inval:
|
||||||
|
@ -5701,14 +5712,17 @@ static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
|
||||||
pii->has_overlap = true;
|
pii->has_overlap = true;
|
||||||
ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
|
ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
|
||||||
|
|
||||||
|
dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
|
||||||
|
__func__, pii->pool_id, pii->pool_ns, pii->image_id, pii->snap_id,
|
||||||
|
pii->has_overlap, pii->overlap);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
e_inval:
|
e_inval:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_parent_info(struct rbd_device *rbd_dev,
|
static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev,
|
||||||
struct parent_image_info *pii)
|
struct parent_image_info *pii)
|
||||||
{
|
{
|
||||||
struct page *req_page, *reply_page;
|
struct page *req_page, *reply_page;
|
||||||
void *p;
|
void *p;
|
||||||
|
@ -5736,7 +5750,7 @@ static int get_parent_info(struct rbd_device *rbd_dev,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
|
static int rbd_dev_setup_parent(struct rbd_device *rbd_dev)
|
||||||
{
|
{
|
||||||
struct rbd_spec *parent_spec;
|
struct rbd_spec *parent_spec;
|
||||||
struct parent_image_info pii = { 0 };
|
struct parent_image_info pii = { 0 };
|
||||||
|
@ -5746,37 +5760,12 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
|
||||||
if (!parent_spec)
|
if (!parent_spec)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = get_parent_info(rbd_dev, &pii);
|
ret = rbd_dev_v2_parent_info(rbd_dev, &pii);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
||||||
dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
|
if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap)
|
||||||
__func__, pii.pool_id, pii.pool_ns, pii.image_id, pii.snap_id,
|
|
||||||
pii.has_overlap, pii.overlap);
|
|
||||||
|
|
||||||
if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap) {
|
|
||||||
/*
|
|
||||||
* Either the parent never existed, or we have
|
|
||||||
* record of it but the image got flattened so it no
|
|
||||||
* longer has a parent. When the parent of a
|
|
||||||
* layered image disappears we immediately set the
|
|
||||||
* overlap to 0. The effect of this is that all new
|
|
||||||
* requests will be treated as if the image had no
|
|
||||||
* parent.
|
|
||||||
*
|
|
||||||
* If !pii.has_overlap, the parent image spec is not
|
|
||||||
* applicable. It's there to avoid duplication in each
|
|
||||||
* snapshot record.
|
|
||||||
*/
|
|
||||||
if (rbd_dev->parent_overlap) {
|
|
||||||
rbd_dev->parent_overlap = 0;
|
|
||||||
rbd_dev_parent_put(rbd_dev);
|
|
||||||
pr_info("%s: clone image has been flattened\n",
|
|
||||||
rbd_dev->disk->disk_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
goto out; /* No parent? No problem. */
|
goto out; /* No parent? No problem. */
|
||||||
}
|
|
||||||
|
|
||||||
/* The ceph file layout needs to fit pool id in 32 bits */
|
/* The ceph file layout needs to fit pool id in 32 bits */
|
||||||
|
|
||||||
|
@ -5788,46 +5777,34 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The parent won't change (except when the clone is
|
* The parent won't change except when the clone is flattened,
|
||||||
* flattened, already handled that). So we only need to
|
* so we only need to record the parent image spec once.
|
||||||
* record the parent spec we have not already done so.
|
|
||||||
*/
|
*/
|
||||||
if (!rbd_dev->parent_spec) {
|
parent_spec->pool_id = pii.pool_id;
|
||||||
parent_spec->pool_id = pii.pool_id;
|
if (pii.pool_ns && *pii.pool_ns) {
|
||||||
if (pii.pool_ns && *pii.pool_ns) {
|
parent_spec->pool_ns = pii.pool_ns;
|
||||||
parent_spec->pool_ns = pii.pool_ns;
|
pii.pool_ns = NULL;
|
||||||
pii.pool_ns = NULL;
|
|
||||||
}
|
|
||||||
parent_spec->image_id = pii.image_id;
|
|
||||||
pii.image_id = NULL;
|
|
||||||
parent_spec->snap_id = pii.snap_id;
|
|
||||||
|
|
||||||
rbd_dev->parent_spec = parent_spec;
|
|
||||||
parent_spec = NULL; /* rbd_dev now owns this */
|
|
||||||
}
|
}
|
||||||
|
parent_spec->image_id = pii.image_id;
|
||||||
|
pii.image_id = NULL;
|
||||||
|
parent_spec->snap_id = pii.snap_id;
|
||||||
|
|
||||||
|
rbd_assert(!rbd_dev->parent_spec);
|
||||||
|
rbd_dev->parent_spec = parent_spec;
|
||||||
|
parent_spec = NULL; /* rbd_dev now owns this */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We always update the parent overlap. If it's zero we issue
|
* Record the parent overlap. If it's zero, issue a warning as
|
||||||
* a warning, as we will proceed as if there was no parent.
|
* we will proceed as if there is no parent.
|
||||||
*/
|
*/
|
||||||
if (!pii.overlap) {
|
if (!pii.overlap)
|
||||||
if (parent_spec) {
|
rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
|
||||||
/* refresh, careful to warn just once */
|
|
||||||
if (rbd_dev->parent_overlap)
|
|
||||||
rbd_warn(rbd_dev,
|
|
||||||
"clone now standalone (overlap became 0)");
|
|
||||||
} else {
|
|
||||||
/* initial probe */
|
|
||||||
rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rbd_dev->parent_overlap = pii.overlap;
|
rbd_dev->parent_overlap = pii.overlap;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out_err:
|
out_err:
|
||||||
kfree(pii.pool_ns);
|
rbd_parent_info_cleanup(&pii);
|
||||||
kfree(pii.image_id);
|
|
||||||
rbd_spec_put(parent_spec);
|
rbd_spec_put(parent_spec);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -6977,7 +6954,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rbd_dev->header.features & RBD_FEATURE_LAYERING) {
|
if (rbd_dev->header.features & RBD_FEATURE_LAYERING) {
|
||||||
ret = rbd_dev_v2_parent_info(rbd_dev);
|
ret = rbd_dev_setup_parent(rbd_dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_out_probe;
|
goto err_out_probe;
|
||||||
}
|
}
|
||||||
|
@ -7026,9 +7003,47 @@ static void rbd_dev_update_header(struct rbd_device *rbd_dev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rbd_dev_update_parent(struct rbd_device *rbd_dev,
|
||||||
|
struct parent_image_info *pii)
|
||||||
|
{
|
||||||
|
if (pii->pool_id == CEPH_NOPOOL || !pii->has_overlap) {
|
||||||
|
/*
|
||||||
|
* Either the parent never existed, or we have
|
||||||
|
* record of it but the image got flattened so it no
|
||||||
|
* longer has a parent. When the parent of a
|
||||||
|
* layered image disappears we immediately set the
|
||||||
|
* overlap to 0. The effect of this is that all new
|
||||||
|
* requests will be treated as if the image had no
|
||||||
|
* parent.
|
||||||
|
*
|
||||||
|
* If !pii.has_overlap, the parent image spec is not
|
||||||
|
* applicable. It's there to avoid duplication in each
|
||||||
|
* snapshot record.
|
||||||
|
*/
|
||||||
|
if (rbd_dev->parent_overlap) {
|
||||||
|
rbd_dev->parent_overlap = 0;
|
||||||
|
rbd_dev_parent_put(rbd_dev);
|
||||||
|
pr_info("%s: clone has been flattened\n",
|
||||||
|
rbd_dev->disk->disk_name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rbd_assert(rbd_dev->parent_spec);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the parent overlap. If it became zero, issue
|
||||||
|
* a warning as we will proceed as if there is no parent.
|
||||||
|
*/
|
||||||
|
if (!pii->overlap && rbd_dev->parent_overlap)
|
||||||
|
rbd_warn(rbd_dev,
|
||||||
|
"clone has become standalone (overlap 0)");
|
||||||
|
rbd_dev->parent_overlap = pii->overlap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int rbd_dev_refresh(struct rbd_device *rbd_dev)
|
static int rbd_dev_refresh(struct rbd_device *rbd_dev)
|
||||||
{
|
{
|
||||||
struct rbd_image_header header = { 0 };
|
struct rbd_image_header header = { 0 };
|
||||||
|
struct parent_image_info pii = { 0 };
|
||||||
u64 mapping_size;
|
u64 mapping_size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -7044,12 +7059,14 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
|
||||||
* mapped image getting flattened.
|
* mapped image getting flattened.
|
||||||
*/
|
*/
|
||||||
if (rbd_dev->parent) {
|
if (rbd_dev->parent) {
|
||||||
ret = rbd_dev_v2_parent_info(rbd_dev);
|
ret = rbd_dev_v2_parent_info(rbd_dev, &pii);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rbd_dev_update_header(rbd_dev, &header);
|
rbd_dev_update_header(rbd_dev, &header);
|
||||||
|
if (rbd_dev->parent)
|
||||||
|
rbd_dev_update_parent(rbd_dev, &pii);
|
||||||
|
|
||||||
rbd_assert(!rbd_is_snap(rbd_dev));
|
rbd_assert(!rbd_is_snap(rbd_dev));
|
||||||
rbd_dev->mapping.size = rbd_dev->header.image_size;
|
rbd_dev->mapping.size = rbd_dev->header.image_size;
|
||||||
|
@ -7059,6 +7076,7 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
|
||||||
if (!ret && mapping_size != rbd_dev->mapping.size)
|
if (!ret && mapping_size != rbd_dev->mapping.size)
|
||||||
rbd_dev_update_size(rbd_dev);
|
rbd_dev_update_size(rbd_dev);
|
||||||
|
|
||||||
|
rbd_parent_info_cleanup(&pii);
|
||||||
rbd_image_header_cleanup(&header);
|
rbd_image_header_cleanup(&header);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue