blobstore: New API call to destroy blobstore [1/3]

Currently exposed API allows to load/unload and to
initialize blobstore on a device.

A spdk_bs_destroy() call is added in order to reach
functional parity with spdk_bs_init(). It was not
possible to remove blobstore from device from within
SPDK previously.

spdk_bs_destroy() takes blobstore pointer as argument
(instead of bs_dev), because blobstore has to be already
loaded to destroy it.

Signed-off-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Change-Id: I2c493a4407868fcf08fd1766a19fc8463f634ef5
Reviewed-on: https://review.gerrithub.io/382019
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Tomasz Zawadzki 2017-10-20 14:52:19 +02:00 committed by Jim Harris
parent 63fce5595b
commit 2df9f03c47
4 changed files with 125 additions and 0 deletions

View File

@ -76,6 +76,9 @@ makes it explicit that the default is being used.
### Blobstore
spdk_bs_destroy() was added to allow destroying blobstore on device
with an initialized blobstore.
spdk_bs_io_readv_blob() and spdk_bs_io_writev_blob() were added to enable
scattered payloads.

View File

@ -163,6 +163,13 @@ void spdk_bs_load(struct spdk_bs_dev *dev, struct spdk_bs_opts *opts,
void spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *opts,
spdk_bs_op_with_handle_complete cb_fn, void *cb_arg);
/* Destroy a blob store by unmapping super block and destroying in-memory structures.
* If unmap_device is set to true, entire device will be unmapped. Otherwise only
* super block will be unmapped.
*/
void spdk_bs_destroy(struct spdk_blob_store *bs, bool unmap_device, spdk_bs_op_complete cb_fn,
void *cb_arg);
/* Flush all volatile data to disk and destroy in-memory structures. */
void spdk_bs_unload(struct spdk_blob_store *bs, spdk_bs_op_complete cb_fn, void *cb_arg);

View File

@ -2183,6 +2183,84 @@ spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o,
/* END spdk_bs_init */
/* START spdk_bs_destroy */
static void
_spdk_bs_destroy_trim_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
{
struct spdk_bs_init_ctx *ctx = cb_arg;
struct spdk_blob_store *bs = ctx->bs;
/*
* We need to defer calling spdk_bs_call_cpl() until after
* dev destruction, so tuck these away for later use.
*/
bs->unload_err = bserrno;
memcpy(&bs->unload_cpl, &seq->cpl, sizeof(struct spdk_bs_cpl));
seq->cpl.type = SPDK_BS_CPL_TYPE_NONE;
spdk_bs_sequence_finish(seq, bserrno);
_spdk_bs_free(bs);
spdk_dma_free(ctx->super);
free(ctx);
}
void
spdk_bs_destroy(struct spdk_blob_store *bs, bool unmap_device, spdk_bs_op_complete cb_fn,
void *cb_arg)
{
struct spdk_bs_cpl cpl;
spdk_bs_sequence_t *seq;
struct spdk_bs_init_ctx *ctx;
SPDK_DEBUGLOG(SPDK_TRACE_BLOB, "Destroying blobstore\n");
if (!TAILQ_EMPTY(&bs->blobs)) {
SPDK_ERRLOG("Blobstore still has open blobs\n");
cb_fn(cb_arg, -EBUSY);
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;
ctx = calloc(1, sizeof(*ctx));
if (!ctx) {
cb_fn(cb_arg, -ENOMEM);
return;
}
ctx->super = spdk_dma_zmalloc(sizeof(*ctx->super), 0x1000, NULL);
if (!ctx->super) {
free(ctx);
cb_fn(cb_arg, -ENOMEM);
return;
}
ctx->bs = bs;
seq = spdk_bs_sequence_start(bs->md_target.md_channel, &cpl);
if (!seq) {
spdk_dma_free(ctx->super);
free(ctx);
cb_fn(cb_arg, -ENOMEM);
return;
}
if (unmap_device) {
/* TRIM the entire device */
spdk_bs_sequence_unmap(seq, 0, bs->dev->blockcnt, _spdk_bs_destroy_trim_cpl, ctx);
} else {
/* Write zeroes to the super block */
spdk_bs_sequence_write(seq, ctx->super, _spdk_bs_page_to_lba(bs, 0), _spdk_bs_byte_to_lba(bs,
sizeof(*ctx->super)), _spdk_bs_destroy_trim_cpl, ctx);
}
}
/* END spdk_bs_destroy */
/* START spdk_bs_unload */
static void

View File

@ -1263,6 +1263,42 @@ bs_resize_md(void)
g_bs = NULL;
}
static void
bs_destroy(void)
{
struct spdk_bs_dev *dev;
struct spdk_bs_opts opts;
g_scheduler_delay = true;
_bs_flush_scheduler();
CU_ASSERT(TAILQ_EMPTY(&g_scheduled_ops));
/* Initialize a new blob store */
dev = init_dev();
spdk_bs_opts_init(&opts);
spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
CU_ASSERT(g_bserrno == 0);
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
/* Destroy the blob store */
g_bserrno = -1;
spdk_bs_destroy(g_bs, 0, bs_op_complete, NULL);
/* Callback is called after device is destroyed in next scheduler run. */
_bs_flush_scheduler();
CU_ASSERT(TAILQ_EMPTY(&g_scheduled_ops));
CU_ASSERT(g_bserrno == 0);
/* Loading an non-existent blob store should fail. */
g_bserrno = -1;
g_bs = NULL;
dev = init_dev();
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
CU_ASSERT(g_bserrno != 0);
g_scheduler_delay = false;
}
/* Try to hit all of the corner cases associated with serializing
* a blob to disk
*/
@ -1768,6 +1804,7 @@ int main(int argc, char **argv)
CU_add_test(suite, "bs_unload", bs_unload) == NULL ||
CU_add_test(suite, "bs_cluster_sz", bs_cluster_sz) == NULL ||
CU_add_test(suite, "bs_resize_md", bs_resize_md) == NULL ||
CU_add_test(suite, "bs_destroy", bs_destroy) == NULL ||
CU_add_test(suite, "bs_type", bs_type) == NULL ||
CU_add_test(suite, "bs_super_block", bs_super_block) == NULL ||
CU_add_test(suite, "blob_serialize", blob_serialize) == NULL ||