Commit 9e2eb8cb authored by Amir More's avatar Amir More Committed by Jim Harris
Browse files

blobstore: Swap cluster maps on snapshot instead of copying



Previously, when creating a snapshot in blobstore the snapshot's cluster map
was copied from the "original" blob, with the original's map zeroed. These
operations are both O(num_clusters*cluster_size/page_size) while io
operations are frozen. This change replaces the linear operation with an
O(1) pointer swap at the critical moment that io is frozen, while
doing the zeroing before the freeze when preparing the snapshot to
minimize freeze time.

Change-Id: I1e468bc97623f5da161a8ddba1393c271acd3aed
Signed-off-by: default avatarAmir More <habeanf@gmail.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/451486


Reviewed-by: default avatarMaciej Szwed <maciej.szwed@intel.com>
Reviewed-by: default avatarDarek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent b70e6984
Loading
Loading
Loading
Loading
+24 −7
Original line number Diff line number Diff line
@@ -4344,13 +4344,25 @@ _spdk_bs_clone_snapshot_newblob_cleanup(void *cb_arg, int bserrno)

/* START spdk_bs_create_snapshot */

static void
_spdk_bs_snapshot_swap_cluster_maps(struct spdk_blob *blob1, struct spdk_blob *blob2)
{
	uint64_t *cluster_temp;

	cluster_temp = blob1->active.clusters;
	blob1->active.clusters = blob2->active.clusters;
	blob2->active.clusters = cluster_temp;
}

static void
_spdk_bs_snapshot_origblob_sync_cpl(void *cb_arg, int bserrno)
{
	struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
	struct spdk_blob *origblob = ctx->original.blob;
	struct spdk_blob *newblob = ctx->new.blob;

	if (bserrno != 0) {
		_spdk_bs_snapshot_swap_cluster_maps(newblob, origblob);
		_spdk_bs_clone_snapshot_newblob_cleanup(ctx, bserrno);
		return;
	}
@@ -4378,6 +4390,8 @@ _spdk_bs_snapshot_newblob_sync_cpl(void *cb_arg, int bserrno)
	struct spdk_blob *newblob = ctx->new.blob;

	if (bserrno != 0) {
		/* return cluster map back to original */
		_spdk_bs_snapshot_swap_cluster_maps(newblob, origblob);
		_spdk_bs_clone_snapshot_newblob_cleanup(ctx, bserrno);
		return;
	}
@@ -4385,6 +4399,8 @@ _spdk_bs_snapshot_newblob_sync_cpl(void *cb_arg, int bserrno)
	/* Set internal xattr for snapshot id */
	bserrno = _spdk_blob_set_xattr(origblob, BLOB_SNAPSHOT, &newblob->id, sizeof(spdk_blob_id), true);
	if (bserrno != 0) {
		/* return cluster map back to original */
		_spdk_bs_snapshot_swap_cluster_maps(newblob, origblob);
		_spdk_bs_clone_snapshot_newblob_cleanup(ctx, bserrno);
		return;
	}
@@ -4395,6 +4411,8 @@ _spdk_bs_snapshot_newblob_sync_cpl(void *cb_arg, int bserrno)
	/* Create new back_bs_dev for snapshot */
	origblob->back_bs_dev = spdk_bs_create_blob_bs_dev(newblob);
	if (origblob->back_bs_dev == NULL) {
		/* return cluster map back to original */
		_spdk_bs_snapshot_swap_cluster_maps(newblob, origblob);
		_spdk_bs_clone_snapshot_newblob_cleanup(ctx, -EINVAL);
		return;
	}
@@ -4404,10 +4422,6 @@ _spdk_bs_snapshot_newblob_sync_cpl(void *cb_arg, int bserrno)

	_spdk_bs_blob_list_add(newblob);

	/* Zero out origblob cluster map */
	memset(origblob->active.clusters, 0,
	       origblob->active.num_clusters * sizeof(origblob->active.clusters));

	/* sync clone metadata */
	spdk_blob_sync_md(origblob, _spdk_bs_snapshot_origblob_sync_cpl, ctx);
}
@@ -4444,9 +4458,8 @@ _spdk_bs_snapshot_freeze_cpl(void *cb_arg, int rc)
		}
	}

	/* Copy cluster map to snapshot */
	memcpy(newblob->active.clusters, origblob->active.clusters,
	       origblob->active.num_clusters * sizeof(origblob->active.clusters));
	/* swap cluster maps */
	_spdk_bs_snapshot_swap_cluster_maps(newblob, origblob);

	/* sync snapshot metadata */
	spdk_blob_sync_md(newblob, _spdk_bs_snapshot_newblob_sync_cpl, ctx);
@@ -4466,6 +4479,10 @@ _spdk_bs_snapshot_newblob_open_cpl(void *cb_arg, struct spdk_blob *_blob, int bs

	ctx->new.blob = newblob;

	/* Zero out newblob cluster map */
	memset(newblob->active.clusters, 0,
	       newblob->active.num_clusters * sizeof(newblob->active.clusters));

	_spdk_blob_freeze_io(origblob, _spdk_bs_snapshot_freeze_cpl, ctx);
}