From a4a73fec9c54c07653cffae6dfc96b4f17129381 Mon Sep 17 00:00:00 2001 From: Mike Gerdts Date: Fri, 7 Oct 2022 16:49:19 -0500 Subject: [PATCH] blob: pass bs context with esnap_bs_dev_create When a blobstore consumer creates or loads a blobstore, it should be able to set a per-blobstore context pointer that will be passed back to the consumer via bs->esnap_bs_dev_create(). Signed-off-by: Mike Gerdts Change-Id: I59c0ebe21eaf65c3d79a4ac3469715283f56313a Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14970 Reviewed-by: Jim Harris Tested-by: SPDK CI Jenkins Community-CI: Mellanox Build Bot Reviewed-by: Ben Walker --- include/spdk/blob.h | 14 +++++++++++--- lib/blob/blobstore.c | 7 +++++-- lib/blob/blobstore.h | 1 + test/unit/lib/blob/blob.c/blob_ut.c | 24 ++++++++++++++++++++++++ test/unit/lib/blob/blob.c/esnap_dev.c | 17 ++++++++++++++++- 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/include/spdk/blob.h b/include/spdk/blob.h index 923fb89de..d3f21e5f8 100644 --- a/include/spdk/blob.h +++ b/include/spdk/blob.h @@ -132,6 +132,8 @@ typedef void (*spdk_blob_op_with_bs_dev)(void *cb_arg, struct spdk_bs_dev *bs_de * callback registered with the blobstore to create the external snapshot device. The blobstore * consumer must set this while loading the blobstore if it intends to support external snapshots. * + * \param bs_ctx Context provided by the blobstore consumer via esnap_ctx member of struct + * spdk_bs_opts. * \param blob The blob that needs its external snapshot device. * \param esnap_id A copy of the esnap_id passed via blob_opts when creating the esnap clone. * \param id_size The size in bytes of the data referenced by esnap_id. @@ -139,8 +141,9 @@ typedef void (*spdk_blob_op_with_bs_dev)(void *cb_arg, struct spdk_bs_dev *bs_de * * \return 0 on success, else a negative errno. */ -typedef int (*spdk_bs_esnap_dev_create)(struct spdk_blob *blob, const void *esnap_id, - uint32_t id_size, struct spdk_bs_dev **bs_dev); +typedef int (*spdk_bs_esnap_dev_create)(void *bs_ctx, struct spdk_blob *blob, + const void *esnap_id, uint32_t id_size, + struct spdk_bs_dev **bs_dev); struct spdk_bs_dev_cb_args { spdk_bs_dev_cpl cb_fn; @@ -287,8 +290,13 @@ struct spdk_bs_opts { * External snapshot creation callback to register with the blobstore. */ spdk_bs_esnap_dev_create esnap_bs_dev_create; + + /** + * Context to pass with esnap_bs_dev_create. + */ + void *esnap_ctx; } __attribute__((packed)); -SPDK_STATIC_ASSERT(sizeof(struct spdk_bs_opts) == 80, "Incorrect size"); +SPDK_STATIC_ASSERT(sizeof(struct spdk_bs_opts) == 88, "Incorrect size"); /** * Initialize a spdk_bs_opts structure to the default blobstore option values. diff --git a/lib/blob/blobstore.c b/lib/blob/blobstore.c index 962ef8d55..bfa4e523b 100644 --- a/lib/blob/blobstore.c +++ b/lib/blob/blobstore.c @@ -1370,7 +1370,7 @@ blob_load_esnap(struct spdk_blob *blob) SPDK_INFOLOG(blob, "Creating external snapshot device\n"); - rc = bs->esnap_bs_dev_create(blob, esnap_id, (uint32_t)id_len, &bs_dev); + rc = bs->esnap_bs_dev_create(bs->esnap_ctx, blob, esnap_id, (uint32_t)id_len, &bs_dev); if (rc != 0) { SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": failed to load back_bs_dev " "with error %d\n", blob->id, rc); @@ -3471,6 +3471,7 @@ spdk_bs_opts_init(struct spdk_bs_opts *opts, size_t opts_size) SET_FIELD(iter_cb_arg, NULL); SET_FIELD(force_recover, false); SET_FIELD(esnap_bs_dev_create, NULL); + SET_FIELD(esnap_ctx, NULL); #undef FIELD_OK #undef SET_FIELD @@ -3599,6 +3600,7 @@ bs_alloc(struct spdk_bs_dev *dev, struct spdk_bs_opts *opts, struct spdk_blob_st bs->super_blob = SPDK_BLOBID_INVALID; memcpy(&bs->bstype, &opts->bstype, sizeof(opts->bstype)); bs->esnap_bs_dev_create = opts->esnap_bs_dev_create; + bs->esnap_ctx = opts->esnap_ctx; /* The metadata is assumed to be at least 1 page */ bs->used_md_pages = spdk_bit_array_create(1); @@ -4676,12 +4678,13 @@ bs_opts_copy(struct spdk_bs_opts *src, struct spdk_bs_opts *dst) SET_FIELD(iter_cb_arg); SET_FIELD(force_recover); SET_FIELD(esnap_bs_dev_create); + SET_FIELD(esnap_ctx); dst->opts_size = src->opts_size; /* You should not remove this statement, but need to update the assert statement * if you add a new field, and also add a corresponding SET_FIELD statement */ - SPDK_STATIC_ASSERT(sizeof(struct spdk_bs_opts) == 80, "Incorrect size"); + SPDK_STATIC_ASSERT(sizeof(struct spdk_bs_opts) == 88, "Incorrect size"); #undef FIELD_OK #undef SET_FIELD diff --git a/lib/blob/blobstore.h b/lib/blob/blobstore.h index 5c09edee4..8923c5eef 100644 --- a/lib/blob/blobstore.h +++ b/lib/blob/blobstore.h @@ -188,6 +188,7 @@ struct spdk_blob_store { bool clean; spdk_bs_esnap_dev_create esnap_bs_dev_create; + void *esnap_ctx; }; struct spdk_bs_channel { diff --git a/test/unit/lib/blob/blob.c/blob_ut.c b/test/unit/lib/blob/blob.c/blob_ut.c index 4f56ae136..d412e7872 100644 --- a/test/unit/lib/blob/blob.c/blob_ut.c +++ b/test/unit/lib/blob/blob.c/blob_ut.c @@ -7421,6 +7421,7 @@ blob_esnap_create(void) uint64_t esnap_num_blocks; uint32_t sz; spdk_blob_id blobid; + uint32_t bs_ctx_count; cluster_sz = spdk_bs_get_cluster_size(bs); block_sz = spdk_bs_get_io_unit_size(bs); @@ -7498,6 +7499,29 @@ blob_esnap_create(void) poll_threads(); CU_ASSERT(g_bserrno != 0); CU_ASSERT(g_blob == NULL); + + /* Reload the blobstore with ctx set and verify it is passed to the esnap create callback */ + bs_ctx_count = 0; + spdk_bs_opts_init(&bs_opts, sizeof(bs_opts)); + bs_opts.esnap_bs_dev_create = ut_esnap_create_with_count; + bs_opts.esnap_ctx = &bs_ctx_count; + ut_bs_reload(&bs, &bs_opts); + /* Loading the blobstore triggers the esnap to be loaded */ + CU_ASSERT(bs_ctx_count == 1); + spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL); + poll_threads(); + CU_ASSERT(g_bserrno == 0); + CU_ASSERT(g_blob != NULL); + /* Opening the blob also triggers the esnap to be loaded */ + CU_ASSERT(bs_ctx_count == 2); + blob = g_blob; + SPDK_CU_ASSERT_FATAL(blob_is_esnap_clone(blob)); + sz = spdk_blob_get_num_clusters(blob); + CU_ASSERT(sz == esnap_num_clusters + 1); + spdk_blob_close(blob, blob_op_complete, NULL); + poll_threads(); + CU_ASSERT(g_bserrno == 0); + g_blob = NULL; } static void diff --git a/test/unit/lib/blob/blob.c/esnap_dev.c b/test/unit/lib/blob/blob.c/esnap_dev.c index 555679109..355edc604 100644 --- a/test/unit/lib/blob/blob.c/esnap_dev.c +++ b/test/unit/lib/blob/blob.c/esnap_dev.c @@ -92,11 +92,14 @@ ut_esnap_dev_alloc(const struct ut_esnap_opts *opts) } static int -ut_esnap_create(struct spdk_blob *blob, const void *id, uint32_t id_len, +ut_esnap_create(void *bs_ctx, struct spdk_blob *blob, const void *id, uint32_t id_len, struct spdk_bs_dev **bs_devp) { struct spdk_bs_dev *bs_dev = NULL; + /* With any blobstore that will use bs_ctx, wrap this function and pass NULL as bs_ctx. */ + CU_ASSERT(bs_ctx == NULL); + SPDK_CU_ASSERT_FATAL(id != NULL); SPDK_CU_ASSERT_FATAL(sizeof(struct ut_esnap_opts) == id_len); @@ -106,3 +109,15 @@ ut_esnap_create(struct spdk_blob *blob, const void *id, uint32_t id_len, *bs_devp = bs_dev; return 0; } + +static int +ut_esnap_create_with_count(void *bs_ctx, struct spdk_blob *blob, + const void *id, uint32_t id_len, struct spdk_bs_dev **bs_devp) +{ + uint32_t *bs_ctx_count = bs_ctx; + + SPDK_CU_ASSERT_FATAL(bs_ctx != NULL); + + (*bs_ctx_count)++; + return ut_esnap_create(NULL, blob, id, id_len, bs_devp); +}