From b86c4b6541a0baa393712d2ebdec76b444c042a0 Mon Sep 17 00:00:00 2001 From: Tomasz Zawadzki Date: Wed, 7 Feb 2018 09:14:43 -0500 Subject: [PATCH] blob: persist super_blob id on blobstore immediately Before this patch super_blob id for blobstore was persisted only during spdk_bs_unload. If power fail occurred after creating and syncing blob, super_blob id was lost within blobstore. Lvol store metadata would be lost, if proper shutdown didn't occur in first SPDK instance run since creation of lvs. This fix changes setting super blob to be instantly persisted on disk in super block. Without affecting clean bit in super block. Change-Id: I578f1fc8717e2d7968ad506fa4dead7507a5e0b4 Signed-off-by: Tomasz Zawadzki Reviewed-on: https://review.gerrithub.io/398804 Reviewed-by: Maciej Szwed Reviewed-by: Shuhei Matsumoto Reviewed-by: Jim Harris Reviewed-by: Daniel Verkamp Tested-by: SPDK Automated Test System --- lib/blob/blobstore.c | 80 ++++++++++++++++++++++++++++- test/unit/lib/blob/blob.c/blob_ut.c | 13 ++++- 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/lib/blob/blobstore.c b/lib/blob/blobstore.c index 0de9698f04..44e08bafc9 100644 --- a/lib/blob/blobstore.c +++ b/lib/blob/blobstore.c @@ -3144,14 +3144,92 @@ spdk_bs_unload(struct spdk_blob_store *bs, spdk_bs_op_complete cb_fn, void *cb_a /* END spdk_bs_unload */ +/* START spdk_bs_set_super */ + +struct spdk_bs_set_super_ctx { + struct spdk_blob_store *bs; + struct spdk_bs_super_block *super; +}; + +static void +_spdk_bs_set_super_write_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno) +{ + struct spdk_bs_set_super_ctx *ctx = cb_arg; + + if (bserrno != 0) { + SPDK_ERRLOG("Unable to write to super block of blobstore\n"); + } + + spdk_dma_free(ctx->super); + + spdk_bs_sequence_finish(seq, bserrno); + + free(ctx); +} + +static void +_spdk_bs_set_super_read_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno) +{ + struct spdk_bs_set_super_ctx *ctx = cb_arg; + + if (bserrno != 0) { + SPDK_ERRLOG("Unable to read super block of blobstore\n"); + spdk_dma_free(ctx->super); + spdk_bs_sequence_finish(seq, bserrno); + free(ctx); + return; + } + + _spdk_bs_write_super(seq, ctx->bs, ctx->super, _spdk_bs_set_super_write_cpl, ctx); +} + void spdk_bs_set_super(struct spdk_blob_store *bs, spdk_blob_id blobid, spdk_bs_op_complete cb_fn, void *cb_arg) { + struct spdk_bs_cpl cpl; + spdk_bs_sequence_t *seq; + struct spdk_bs_set_super_ctx *ctx; + + SPDK_DEBUGLOG(SPDK_LOG_BLOB, "Setting super blob id on blobstore\n"); + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + cb_fn(cb_arg, -ENOMEM); + return; + } + + ctx->bs = bs; + + ctx->super = spdk_dma_zmalloc(sizeof(*ctx->super), 0x1000, NULL); + if (!ctx->super) { + free(ctx); + cb_fn(cb_arg, -ENOMEM); + return; + } + + cpl.type = SPDK_BS_CPL_TYPE_BS_BASIC; + cpl.u.bs_basic.cb_fn = cb_fn; + cpl.u.bs_basic.cb_arg = cb_arg; + + seq = spdk_bs_sequence_start(bs->md_channel, &cpl); + if (!seq) { + spdk_dma_free(ctx->super); + free(ctx); + cb_fn(cb_arg, -ENOMEM); + return; + } + bs->super_blob = blobid; - cb_fn(cb_arg, 0); + + /* Read super block */ + spdk_bs_sequence_read_dev(seq, ctx->super, _spdk_bs_page_to_lba(bs, 0), + _spdk_bs_byte_to_lba(bs, sizeof(*ctx->super)), + _spdk_bs_set_super_read_cpl, ctx); } +/* END spdk_bs_set_super */ + void spdk_bs_get_super(struct spdk_blob_store *bs, spdk_blob_op_with_id_complete cb_fn, void *cb_arg) diff --git a/test/unit/lib/blob/blob.c/blob_ut.c b/test/unit/lib/blob/blob.c/blob_ut.c index 423d74db0f..a047b3de3b 100644 --- a/test/unit/lib/blob/blob.c/blob_ut.c +++ b/test/unit/lib/blob/blob.c/blob_ut.c @@ -2063,13 +2063,13 @@ super_block_crc(void) } /* For blob dirty shutdown test case we do the following sub-test cases: - * 1 Initialize new blob store and create 1 blob with some xattrs, then we + * 1 Initialize new blob store and create 1 super blob with some xattrs, then we * dirty shutdown and reload the blob store and verify the xattrs. * 2 Resize the blob from 10 clusters to 20 clusters and then dirty shutdown, * reload the blob store and verify the clusters number. * 3 Create the second blob and then dirty shutdown, reload the blob store * and verify the second blob. - * 4 Delete the second blob and then dirty shutdown, reload teh blob store + * 4 Delete the second blob and then dirty shutdown, reload the blob store * and verify the second blob is invalid. * 5 Create the second blob again and also create the third blob, modify the * md of second blob which makes the md invalid, and then dirty shutdown, @@ -2122,6 +2122,10 @@ blob_dirty_shutdown(void) rc = spdk_blob_resize(blob, 10); CU_ASSERT(rc == 0); + /* Set the blob as the super blob */ + spdk_bs_set_super(g_bs, blobid1, blob_op_complete, NULL); + CU_ASSERT(g_bserrno == 0); + free_clusters = spdk_bs_free_cluster_count(g_bs); spdk_blob_close(blob, blob_op_complete, NULL); @@ -2138,6 +2142,11 @@ blob_dirty_shutdown(void) spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL); CU_ASSERT(g_bserrno == 0); + /* Get the super blob */ + spdk_bs_get_super(g_bs, blob_op_with_id_complete, NULL); + CU_ASSERT(g_bserrno == 0); + CU_ASSERT(blobid1 == g_blobid); + spdk_bs_open_blob(g_bs, blobid1, blob_op_with_handle_complete, NULL); CU_ASSERT(g_bserrno == 0); CU_ASSERT(g_blob != NULL);