Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc2a3044 authored by Ilya Dryomov's avatar Ilya Dryomov Committed by Greg Kroah-Hartman
Browse files

rbd: decouple parent info read-in from updating rbd_dev



commit c10311776f0a8ddea2276df96e255625b07045a8 upstream.

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: default avatarIlya Dryomov <idryomov@gmail.com>
Reviewed-by: default avatarDongsheng Yang <dongsheng.yang@easystack.cn>
[idryomov@gmail.com: backport to 5.4: context]
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 2e0114ed
Loading
Loading
Loading
Loading
+80 −62
Original line number Diff line number Diff line
@@ -5762,6 +5762,14 @@ struct parent_image_info {
	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.
 */
@@ -5831,6 +5839,9 @@ static int __get_parent_info(struct rbd_device *rbd_dev,
	if (pii->has_overlap)
		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;

e_inval:
@@ -5869,13 +5880,16 @@ static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
	pii->has_overlap = true;
	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;

e_inval:
	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 page *req_page, *reply_page;
@@ -5904,7 +5918,7 @@ static int get_parent_info(struct rbd_device *rbd_dev,
	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 parent_image_info pii = { 0 };
@@ -5914,37 +5928,12 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
	if (!parent_spec)
		return -ENOMEM;

	ret = get_parent_info(rbd_dev, &pii);
	ret = rbd_dev_v2_parent_info(rbd_dev, &pii);
	if (ret)
		goto out_err;

	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);

	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);
		}

	if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap)
		goto out;	/* No parent?  No problem. */
	}

	/* The ceph file layout needs to fit pool id in 32 bits */

@@ -5956,11 +5945,9 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
	}

	/*
	 * 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.
	 * The parent won't change except when the clone is flattened,
	 * so we only need to record the parent image spec once.
	 */
	if (!rbd_dev->parent_spec) {
	parent_spec->pool_id = pii.pool_id;
	if (pii.pool_ns && *pii.pool_ns) {
		parent_spec->pool_ns = pii.pool_ns;
@@ -5970,32 +5957,22 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
	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
	 * a warning, as we will proceed as if there was no parent.
	 * Record the parent overlap.  If it's zero, issue a warning as
	 * we will proceed as if there is no parent.
	 */
	if (!pii.overlap) {
		if (parent_spec) {
			/* refresh, careful to warn just once */
			if (rbd_dev->parent_overlap)
				rbd_warn(rbd_dev,
				    "clone now standalone (overlap became 0)");
		} else {
			/* initial probe */
	if (!pii.overlap)
		rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
		}
	}
	rbd_dev->parent_overlap = pii.overlap;

out:
	ret = 0;
out_err:
	kfree(pii.pool_ns);
	kfree(pii.image_id);
	rbd_parent_info_cleanup(&pii);
	rbd_spec_put(parent_spec);
	return ret;
}
@@ -6992,7 +6969,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
	}

	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)
			goto err_out_probe;
	}
@@ -7041,9 +7018,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)
{
	struct rbd_image_header	header = { 0 };
	struct parent_image_info pii = { 0 };
	u64 mapping_size;
	int ret;

@@ -7059,12 +7074,14 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
	 * mapped image getting flattened.
	 */
	if (rbd_dev->parent) {
		ret = rbd_dev_v2_parent_info(rbd_dev);
		ret = rbd_dev_v2_parent_info(rbd_dev, &pii);
		if (ret)
			goto out;
	}

	rbd_dev_update_header(rbd_dev, &header);
	if (rbd_dev->parent)
		rbd_dev_update_parent(rbd_dev, &pii);

	if (rbd_dev->spec->snap_id == CEPH_NOSNAP) {
		rbd_dev->mapping.size = rbd_dev->header.image_size;
@@ -7078,6 +7095,7 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
	if (!ret && mapping_size != rbd_dev->mapping.size)
		rbd_dev_update_size(rbd_dev);

	rbd_parent_info_cleanup(&pii);
	rbd_image_header_cleanup(&header);
	return ret;
}