From 9e2eb8cb51a16839a54771eb842c4e3aa99b25d6 Mon Sep 17 00:00:00 2001 From: Amir More Date: Thu, 18 Apr 2019 19:49:59 +0300 Subject: [PATCH] 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: Amir More Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/451486 Reviewed-by: Maciej Szwed Reviewed-by: Darek Stojaczyk Reviewed-by: Ben Walker Reviewed-by: Jim Harris Tested-by: SPDK CI Jenkins --- lib/blob/blobstore.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/blob/blobstore.c b/lib/blob/blobstore.c index 7f1e8401c..44ef86333 100644 --- a/lib/blob/blobstore.c +++ b/lib/blob/blobstore.c @@ -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); }