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

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

rbd: decouple header read-in from updating rbd_dev->header



commit 510a7330c82a7754d5df0117a8589e8a539067c7 upstream.

Make rbd_dev_header_info() populate a passed struct rbd_image_header
instead of rbd_dev->header and introduce rbd_dev_update_header() for
updating mutable fields in rbd_dev->header upon refresh.  The initial
read-in of both mutable and immutable fields in rbd_dev_image_probe()
passes in rbd_dev->header so no update step is required there.

rbd_init_layout() is now called directly from rbd_dev_image_probe()
instead of individually in format 1 and format 2 implementations.

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: _rbd_dev_v2_snap_features()
 doesn't have read_only param]
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 32a59639
Loading
Loading
Loading
Loading
+114 −91
Original line number Diff line number Diff line
@@ -626,7 +626,8 @@ void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...)
static void rbd_dev_remove_parent(struct rbd_device *rbd_dev);

static int rbd_dev_refresh(struct rbd_device *rbd_dev);
static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev);
static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev,
				     struct rbd_image_header *header);
static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev,
					u64 snap_id);
static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
@@ -1096,15 +1097,24 @@ static void rbd_init_layout(struct rbd_device *rbd_dev)
	RCU_INIT_POINTER(rbd_dev->layout.pool_ns, NULL);
}

static void rbd_image_header_cleanup(struct rbd_image_header *header)
{
	kfree(header->object_prefix);
	ceph_put_snap_context(header->snapc);
	kfree(header->snap_sizes);
	kfree(header->snap_names);

	memset(header, 0, sizeof(*header));
}

/*
 * Fill an rbd image header with information from the given format 1
 * on-disk header.
 */
static int rbd_header_from_disk(struct rbd_device *rbd_dev,
				 struct rbd_image_header_ondisk *ondisk)
static int rbd_header_from_disk(struct rbd_image_header *header,
				struct rbd_image_header_ondisk *ondisk,
				bool first_time)
{
	struct rbd_image_header *header = &rbd_dev->header;
	bool first_time = header->object_prefix == NULL;
	struct ceph_snap_context *snapc;
	char *object_prefix = NULL;
	char *snap_names = NULL;
@@ -1171,11 +1181,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev,
	if (first_time) {
		header->object_prefix = object_prefix;
		header->obj_order = ondisk->options.order;
		rbd_init_layout(rbd_dev);
	} else {
		ceph_put_snap_context(header->snapc);
		kfree(header->snap_names);
		kfree(header->snap_sizes);
	}

	/* The remaining fields always get updated (when we refresh) */
@@ -4981,7 +4986,9 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
 * return, the rbd_dev->header field will contain up-to-date
 * information about the image.
 */
static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev)
static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev,
				  struct rbd_image_header *header,
				  bool first_time)
{
	struct rbd_image_header_ondisk *ondisk = NULL;
	u32 snap_count = 0;
@@ -5029,7 +5036,7 @@ static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev)
		snap_count = le32_to_cpu(ondisk->snap_count);
	} while (snap_count != want_count);

	ret = rbd_header_from_disk(rbd_dev, ondisk);
	ret = rbd_header_from_disk(header, ondisk, first_time);
out:
	kfree(ondisk);

@@ -5642,17 +5649,12 @@ static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
	return 0;
}

static int rbd_dev_v2_image_size(struct rbd_device *rbd_dev)
{
	return _rbd_dev_v2_snap_size(rbd_dev, CEPH_NOSNAP,
					&rbd_dev->header.obj_order,
					&rbd_dev->header.image_size);
}

static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev)
static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev,
				    char **pobject_prefix)
{
	size_t size;
	void *reply_buf;
	char *object_prefix;
	int ret;
	void *p;

@@ -5670,16 +5672,16 @@ static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev)
		goto out;

	p = reply_buf;
	rbd_dev->header.object_prefix = ceph_extract_encoded_string(&p,
						p + ret, NULL, GFP_NOIO);
	object_prefix = ceph_extract_encoded_string(&p, p + ret, NULL,
						    GFP_NOIO);
	if (IS_ERR(object_prefix)) {
		ret = PTR_ERR(object_prefix);
		goto out;
	}
	ret = 0;

	if (IS_ERR(rbd_dev->header.object_prefix)) {
		ret = PTR_ERR(rbd_dev->header.object_prefix);
		rbd_dev->header.object_prefix = NULL;
	} else {
		dout("  object_prefix = %s\n", rbd_dev->header.object_prefix);
	}
	*pobject_prefix = object_prefix;
	dout("  object_prefix = %s\n", object_prefix);
out:
	kfree(reply_buf);

@@ -5724,12 +5726,6 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
	return 0;
}

static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
{
	return _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP,
						&rbd_dev->header.features);
}

/*
 * These are generic image flags, but since they are used only for
 * object map, store them in rbd_dev->object_map_flags.
@@ -6004,14 +6000,14 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
	return ret;
}

static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev)
static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev,
				    u64 *stripe_unit, u64 *stripe_count)
{
	struct {
		__le64 stripe_unit;
		__le64 stripe_count;
	} __attribute__ ((packed)) striping_info_buf = { 0 };
	size_t size = sizeof (striping_info_buf);
	void *p;
	int ret;

	ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
@@ -6023,27 +6019,33 @@ static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev)
	if (ret < size)
		return -ERANGE;

	p = &striping_info_buf;
	rbd_dev->header.stripe_unit = ceph_decode_64(&p);
	rbd_dev->header.stripe_count = ceph_decode_64(&p);
	*stripe_unit = le64_to_cpu(striping_info_buf.stripe_unit);
	*stripe_count = le64_to_cpu(striping_info_buf.stripe_count);
	dout("  stripe_unit = %llu stripe_count = %llu\n", *stripe_unit,
	     *stripe_count);

	return 0;
}

static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev)
static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev, s64 *data_pool_id)
{
	__le64 data_pool_id;
	__le64 data_pool_buf;
	int ret;

	ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
				  &rbd_dev->header_oloc, "get_data_pool",
				  NULL, 0, &data_pool_id, sizeof(data_pool_id));
				  NULL, 0, &data_pool_buf,
				  sizeof(data_pool_buf));
	dout("%s: rbd_obj_method_sync returned %d\n", __func__, ret);
	if (ret < 0)
		return ret;
	if (ret < sizeof(data_pool_id))
	if (ret < sizeof(data_pool_buf))
		return -EBADMSG;

	rbd_dev->header.data_pool_id = le64_to_cpu(data_pool_id);
	WARN_ON(rbd_dev->header.data_pool_id == CEPH_NOPOOL);
	*data_pool_id = le64_to_cpu(data_pool_buf);
	dout("  data_pool_id = %lld\n", *data_pool_id);
	WARN_ON(*data_pool_id == CEPH_NOPOOL);

	return 0;
}

@@ -6235,7 +6237,8 @@ static int rbd_spec_fill_names(struct rbd_device *rbd_dev)
	return ret;
}

static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)
static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev,
				   struct ceph_snap_context **psnapc)
{
	size_t size;
	int ret;
@@ -6296,9 +6299,7 @@ static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)
	for (i = 0; i < snap_count; i++)
		snapc->snaps[i] = ceph_decode_64(&p);

	ceph_put_snap_context(rbd_dev->header.snapc);
	rbd_dev->header.snapc = snapc;

	*psnapc = snapc;
	dout("  snap context seq = %llu, snap_count = %u\n",
		(unsigned long long)seq, (unsigned int)snap_count);
out:
@@ -6347,38 +6348,42 @@ static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev,
	return snap_name;
}

static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev,
				  struct rbd_image_header *header,
				  bool first_time)
{
	bool first_time = rbd_dev->header.object_prefix == NULL;
	int ret;

	ret = rbd_dev_v2_image_size(rbd_dev);
	ret = _rbd_dev_v2_snap_size(rbd_dev, CEPH_NOSNAP,
				    first_time ? &header->obj_order : NULL,
				    &header->image_size);
	if (ret)
		return ret;

	if (first_time) {
		ret = rbd_dev_v2_header_onetime(rbd_dev);
		ret = rbd_dev_v2_header_onetime(rbd_dev, header);
		if (ret)
			return ret;
	}

	ret = rbd_dev_v2_snap_context(rbd_dev);
	if (ret && first_time) {
		kfree(rbd_dev->header.object_prefix);
		rbd_dev->header.object_prefix = NULL;
	}

	ret = rbd_dev_v2_snap_context(rbd_dev, &header->snapc);
	if (ret)
		return ret;

	return 0;
}

static int rbd_dev_header_info(struct rbd_device *rbd_dev)
static int rbd_dev_header_info(struct rbd_device *rbd_dev,
			       struct rbd_image_header *header,
			       bool first_time)
{
	rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
	rbd_assert(!header->object_prefix && !header->snapc);

	if (rbd_dev->image_format == 1)
		return rbd_dev_v1_header_info(rbd_dev);
		return rbd_dev_v1_header_info(rbd_dev, header, first_time);

	return rbd_dev_v2_header_info(rbd_dev);
	return rbd_dev_v2_header_info(rbd_dev, header, first_time);
}

/*
@@ -6728,60 +6733,49 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev)
 */
static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
{
	struct rbd_image_header	*header;

	rbd_dev_parent_put(rbd_dev);
	rbd_object_map_free(rbd_dev);
	rbd_dev_mapping_clear(rbd_dev);

	/* Free dynamic fields from the header, then zero it out */

	header = &rbd_dev->header;
	ceph_put_snap_context(header->snapc);
	kfree(header->snap_sizes);
	kfree(header->snap_names);
	kfree(header->object_prefix);
	memset(header, 0, sizeof (*header));
	rbd_image_header_cleanup(&rbd_dev->header);
}

static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev)
static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev,
				     struct rbd_image_header *header)
{
	int ret;

	ret = rbd_dev_v2_object_prefix(rbd_dev);
	ret = rbd_dev_v2_object_prefix(rbd_dev, &header->object_prefix);
	if (ret)
		goto out_err;
		return ret;

	/*
	 * Get the and check features for the image.  Currently the
	 * features are assumed to never change.
	 */
	ret = rbd_dev_v2_features(rbd_dev);
	ret = _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP,
					&header->features);
	if (ret)
		goto out_err;
		return ret;

	/* If the image supports fancy striping, get its parameters */

	if (rbd_dev->header.features & RBD_FEATURE_STRIPINGV2) {
		ret = rbd_dev_v2_striping_info(rbd_dev);
		if (ret < 0)
			goto out_err;
	if (header->features & RBD_FEATURE_STRIPINGV2) {
		ret = rbd_dev_v2_striping_info(rbd_dev, &header->stripe_unit,
					       &header->stripe_count);
		if (ret)
			return ret;
	}

	if (rbd_dev->header.features & RBD_FEATURE_DATA_POOL) {
		ret = rbd_dev_v2_data_pool(rbd_dev);
	if (header->features & RBD_FEATURE_DATA_POOL) {
		ret = rbd_dev_v2_data_pool(rbd_dev, &header->data_pool_id);
		if (ret)
			goto out_err;
			return ret;
	}

	rbd_init_layout(rbd_dev);
	return 0;

out_err:
	rbd_dev->header.features = 0;
	kfree(rbd_dev->header.object_prefix);
	rbd_dev->header.object_prefix = NULL;
	return ret;
}

/*
@@ -6959,10 +6953,12 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
	if (!depth)
		down_write(&rbd_dev->header_rwsem);

	ret = rbd_dev_header_info(rbd_dev);
	ret = rbd_dev_header_info(rbd_dev, &rbd_dev->header, true);
	if (ret)
		goto err_out_probe;

	rbd_init_layout(rbd_dev);

	/*
	 * If this image is the one being mapped, we have pool name and
	 * id, image name and id, and snap name - need to fill snap id.
@@ -7022,15 +7018,39 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
	return ret;
}

static void rbd_dev_update_header(struct rbd_device *rbd_dev,
				  struct rbd_image_header *header)
{
	rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
	rbd_assert(rbd_dev->header.object_prefix); /* !first_time */

	rbd_dev->header.image_size = header->image_size;

	ceph_put_snap_context(rbd_dev->header.snapc);
	rbd_dev->header.snapc = header->snapc;
	header->snapc = NULL;

	if (rbd_dev->image_format == 1) {
		kfree(rbd_dev->header.snap_names);
		rbd_dev->header.snap_names = header->snap_names;
		header->snap_names = NULL;

		kfree(rbd_dev->header.snap_sizes);
		rbd_dev->header.snap_sizes = header->snap_sizes;
		header->snap_sizes = NULL;
	}
}

static int rbd_dev_refresh(struct rbd_device *rbd_dev)
{
	struct rbd_image_header	header = { 0 };
	u64 mapping_size;
	int ret;

	down_write(&rbd_dev->header_rwsem);
	mapping_size = rbd_dev->mapping.size;

	ret = rbd_dev_header_info(rbd_dev);
	ret = rbd_dev_header_info(rbd_dev, &header, false);
	if (ret)
		goto out;

@@ -7044,6 +7064,8 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
			goto out;
	}

	rbd_dev_update_header(rbd_dev, &header);

	if (rbd_dev->spec->snap_id == CEPH_NOSNAP) {
		rbd_dev->mapping.size = rbd_dev->header.image_size;
	} else {
@@ -7056,6 +7078,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_image_header_cleanup(&header);
	return ret;
}