diff --git a/CHANGELOG.md b/CHANGELOG.md index a75237f57..34ca68fb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,11 @@ An `opts_size` element was added in the `spdk_blob_opts` structure to solve the ABI compatiblity issue between different SPDK version. And also add `opts_size` parameter in `spdk_blob_opts_init` function. +An `opts_size` element was added in the `spdk_blob_open_opts` structure to solve the +ABI compatiblity issue between different SPDK version. And also add `opts_size` +parameter in `spdk_blob_open_opts_init` function. + + ### event The pci_whitelist and pci_blacklist members of struct spdk_app_opts have been diff --git a/include/spdk/blob.h b/include/spdk/blob.h index f9e686bb2..d3a9599e6 100644 --- a/include/spdk/blob.h +++ b/include/spdk/blob.h @@ -614,14 +614,23 @@ void spdk_bs_blob_decouple_parent(struct spdk_blob_store *bs, struct spdk_io_cha struct spdk_blob_open_opts { enum blob_clear_method clear_method; + + /** + * The size of spdk_blob_open_opts according to the caller of this library is used for ABI + * compatibility. The library uses this field to know how many fields in this + * structure are valid. And the library will populate any remaining fields with default values. + * New added fields should be put at the end of the struct. + */ + size_t opts_size; }; /** * Initialize a spdk_blob_open_opts structure to the default blob option values. * * \param opts spdk_blob_open_opts structure to initialize. + * \param opts_size It mus be the size of struct spdk_blob_open_opts. */ -void spdk_blob_open_opts_init(struct spdk_blob_open_opts *opts); +void spdk_blob_open_opts_init(struct spdk_blob_open_opts *opts, size_t opts_size); /** * Open a blob from the given blobstore. diff --git a/lib/blob/blobstore.c b/lib/blob/blobstore.c index f5d3d8b98..08483fcf2 100644 --- a/lib/blob/blobstore.c +++ b/lib/blob/blobstore.c @@ -241,9 +241,33 @@ spdk_blob_opts_init(struct spdk_blob_opts *opts, size_t opts_size) } void -spdk_blob_open_opts_init(struct spdk_blob_open_opts *opts) +spdk_blob_open_opts_init(struct spdk_blob_open_opts *opts, size_t opts_size) { - opts->clear_method = BLOB_CLEAR_WITH_DEFAULT; + if (!opts) { + SPDK_ERRLOG("opts should not be NULL\n"); + return; + } + + if (!opts_size) { + SPDK_ERRLOG("opts_size should not be zero value\n"); + return; + } + + memset(opts, 0, opts_size); + opts->opts_size = opts_size; + +#define FIELD_OK(field) \ + offsetof(struct spdk_blob_open_opts, field) + sizeof(opts->field) <= opts_size + +#define SET_FIELD(field, value) \ + if (FIELD_OK(field)) { \ + opts->field = value; \ + } \ + + SET_FIELD(clear_method, BLOB_CLEAR_WITH_DEFAULT); + +#undef FIELD_OK +#undef SET_FILED } static struct spdk_blob * @@ -6821,6 +6845,29 @@ bs_open_blob_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno) bs_sequence_finish(seq, bserrno); } +static inline void +blob_open_opts_copy(const struct spdk_blob_open_opts *src, struct spdk_blob_open_opts *dst) +{ +#define FIELD_OK(field) \ + offsetof(struct spdk_blob_opts, field) + sizeof(src->field) <= src->opts_size + +#define SET_FIELD(field) \ + if (FIELD_OK(field)) { \ + dst->field = src->field; \ + } \ + + SET_FIELD(clear_method); + + 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_blob_open_opts) == 16, "Incorrect size"); + +#undef FIELD_OK +#undef SET_FIELD +} + static void bs_open_blob(struct spdk_blob_store *bs, spdk_blob_id blobid, @@ -6830,7 +6877,7 @@ bs_open_blob(struct spdk_blob_store *bs, { struct spdk_blob *blob; struct spdk_bs_cpl cpl; - struct spdk_blob_open_opts opts_default; + struct spdk_blob_open_opts opts_local; spdk_bs_sequence_t *seq; uint32_t page_num; @@ -6857,12 +6904,12 @@ bs_open_blob(struct spdk_blob_store *bs, return; } - if (!opts) { - spdk_blob_open_opts_init(&opts_default); - opts = &opts_default; + spdk_blob_open_opts_init(&opts_local, sizeof(opts_local)); + if (opts) { + blob_open_opts_copy(opts, &opts_local); } - blob->clear_method = opts->clear_method; + blob->clear_method = opts_local.clear_method; cpl.type = SPDK_BS_CPL_TYPE_BLOB_HANDLE; cpl.u.blob_handle.cb_fn = cb_fn; diff --git a/lib/lvol/lvol.c b/lib/lvol/lvol.c index f1c6b1469..905527559 100644 --- a/lib/lvol/lvol.c +++ b/lib/lvol/lvol.c @@ -143,7 +143,7 @@ spdk_lvol_open(struct spdk_lvol *lvol, spdk_lvol_op_with_handle_complete cb_fn, req->cb_arg = cb_arg; req->lvol = lvol; - spdk_blob_open_opts_init(&opts); + spdk_blob_open_opts_init(&opts, sizeof(opts)); opts.clear_method = lvol->clear_method; spdk_bs_open_blob_ext(lvol->lvol_store->blobstore, lvol->blob_id, &opts, lvol_open_cb, req); @@ -960,7 +960,7 @@ lvol_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno) return; } - spdk_blob_open_opts_init(&opts); + spdk_blob_open_opts_init(&opts, sizeof(opts)); opts.clear_method = req->lvol->clear_method; bs = req->lvol->lvol_store->blobstore; diff --git a/test/unit/lib/lvol/lvol.c/lvol_ut.c b/test/unit/lib/lvol/lvol.c/lvol_ut.c index d12e49aac..d8f16df4b 100644 --- a/test/unit/lib/lvol/lvol.c/lvol_ut.c +++ b/test/unit/lib/lvol/lvol.c/lvol_ut.c @@ -411,8 +411,9 @@ spdk_blob_opts_init(struct spdk_blob_opts *opts, size_t opts_size) } void -spdk_blob_open_opts_init(struct spdk_blob_open_opts *opts) +spdk_blob_open_opts_init(struct spdk_blob_open_opts *opts, size_t opts_size) { + opts->opts_size = opts_size; opts->clear_method = BLOB_CLEAR_WITH_DEFAULT; }