From c0f3805153a41cdcc2b1454560224e24eaa5c2e2 Mon Sep 17 00:00:00 2001 From: Jim Harris Date: Thu, 20 Dec 2018 02:45:42 -0700 Subject: [PATCH] reduce: add spdk_reduce_vol_destroy This will remove the metadata from the associated backing device and delete the pm_file associated with the reduce volume. Signed-off-by: Jim Harris Change-Id: I30ffd68e5ba69b31ee1be85418c5b8c592d82e70 Reviewed-on: https://review.gerrithub.io/c/437995 Chandler-Test-Pool: SPDK Automated Test System Tested-by: SPDK CI Jenkins Reviewed-by: Shuhei Matsumoto Reviewed-by: wuzhouhui Reviewed-by: Changpeng Liu --- include/spdk/reduce.h | 16 +++++ lib/reduce/reduce.c | 88 +++++++++++++++++++++++ test/unit/lib/reduce/reduce.c/Makefile | 1 + test/unit/lib/reduce/reduce.c/reduce_ut.c | 69 +++++++++++++++++- 4 files changed, 173 insertions(+), 1 deletion(-) diff --git a/include/spdk/reduce.h b/include/spdk/reduce.h index 53934ff1a5..a3db770556 100644 --- a/include/spdk/reduce.h +++ b/include/spdk/reduce.h @@ -158,6 +158,22 @@ void spdk_reduce_vol_unload(struct spdk_reduce_vol *vol, spdk_reduce_vol_op_complete cb_fn, void *cb_arg); +/** + * Destroy an existing libreduce compressed volume. + * + * This will zero the metadata region on the backing device and delete the associated + * pm metadata file. If the backing device does not contain a compressed volume, the + * cb_fn will be called with error status without modifying the backing device nor + * deleting a pm file. + * + * \param backing_dev Structure describing the backing device containing the compressed volume. + * \param cb_fn Callback function to signal completion of the destruction process. + * \param cb_arg Argument to pass to the callback function. + */ +void spdk_reduce_vol_destroy(struct spdk_reduce_backing_dev *backing_dev, + spdk_reduce_vol_op_complete cb_fn, + void *cb_arg); + /** * Read data from a libreduce compressed volume. * diff --git a/lib/reduce/reduce.c b/lib/reduce/reduce.c index 65598a00ae..959faed0dc 100644 --- a/lib/reduce/reduce.c +++ b/lib/reduce/reduce.c @@ -704,6 +704,94 @@ spdk_reduce_vol_unload(struct spdk_reduce_vol *vol, cb_fn(cb_arg, 0); } +struct reduce_destroy_ctx { + spdk_reduce_vol_op_complete cb_fn; + void *cb_arg; + struct spdk_reduce_vol *vol; + struct spdk_reduce_vol_superblock *super; + struct iovec iov; + struct spdk_reduce_vol_cb_args backing_cb_args; + int reduce_errno; + char pm_path[REDUCE_PATH_MAX]; +}; + +static void +destroy_unload_cpl(void *cb_arg, int reduce_errno) +{ + struct reduce_destroy_ctx *destroy_ctx = cb_arg; + + if (destroy_ctx->reduce_errno == 0) { + if (unlink(destroy_ctx->pm_path)) { + SPDK_ERRLOG("%s could not be unlinked: %s\n", + destroy_ctx->pm_path, strerror(errno)); + } + } + + /* Even if the unload somehow failed, we still pass the destroy_ctx + * reduce_errno since that indicates whether or not the volume was + * actually destroyed. + */ + destroy_ctx->cb_fn(destroy_ctx->cb_arg, destroy_ctx->reduce_errno); + spdk_dma_free(destroy_ctx->super); + free(destroy_ctx); +} + +static void +_destroy_zero_super_cpl(void *cb_arg, int reduce_errno) +{ + struct reduce_destroy_ctx *destroy_ctx = cb_arg; + struct spdk_reduce_vol *vol = destroy_ctx->vol; + + destroy_ctx->reduce_errno = reduce_errno; + spdk_reduce_vol_unload(vol, destroy_unload_cpl, destroy_ctx); +} + +static void +destroy_load_cb(void *cb_arg, struct spdk_reduce_vol *vol, int reduce_errno) +{ + struct reduce_destroy_ctx *destroy_ctx = cb_arg; + + if (reduce_errno != 0) { + destroy_ctx->cb_fn(destroy_ctx->cb_arg, reduce_errno); + spdk_dma_free(destroy_ctx->super); + free(destroy_ctx); + return; + } + + destroy_ctx->vol = vol; + memcpy(destroy_ctx->pm_path, vol->pm_file.path, sizeof(destroy_ctx->pm_path)); + destroy_ctx->iov.iov_base = destroy_ctx->super; + destroy_ctx->iov.iov_len = sizeof(*destroy_ctx->super); + destroy_ctx->backing_cb_args.cb_fn = _destroy_zero_super_cpl; + destroy_ctx->backing_cb_args.cb_arg = destroy_ctx; + vol->backing_dev->writev(vol->backing_dev, &destroy_ctx->iov, 1, 0, + sizeof(*destroy_ctx->super) / vol->backing_dev->blocklen, + &destroy_ctx->backing_cb_args); +} + +void +spdk_reduce_vol_destroy(struct spdk_reduce_backing_dev *backing_dev, + spdk_reduce_vol_op_complete cb_fn, void *cb_arg) +{ + struct reduce_destroy_ctx *destroy_ctx; + + destroy_ctx = calloc(1, sizeof(*destroy_ctx)); + if (destroy_ctx == NULL) { + cb_fn(cb_arg, -ENOMEM); + return; + } + + destroy_ctx->super = spdk_dma_zmalloc(sizeof(*destroy_ctx->super), 64, NULL); + if (destroy_ctx->super == NULL) { + free(destroy_ctx); + cb_fn(cb_arg, -ENOMEM); + return; + } + destroy_ctx->cb_fn = cb_fn; + destroy_ctx->cb_arg = cb_arg; + spdk_reduce_vol_load(backing_dev, destroy_load_cb, destroy_ctx); +} + static bool _request_spans_chunk_boundary(struct spdk_reduce_vol *vol, uint64_t offset, uint64_t length) { diff --git a/test/unit/lib/reduce/reduce.c/Makefile b/test/unit/lib/reduce/reduce.c/Makefile index f8e6df6da2..500171e740 100644 --- a/test/unit/lib/reduce/reduce.c/Makefile +++ b/test/unit/lib/reduce/reduce.c/Makefile @@ -35,5 +35,6 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk TEST_FILE = reduce_ut.c +LDFLAGS += -Wl,--wrap,unlink include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/test/unit/lib/reduce/reduce.c/reduce_ut.c b/test/unit/lib/reduce/reduce.c/reduce_ut.c index ef965260ba..a172bfd460 100644 --- a/test/unit/lib/reduce/reduce.c/reduce_ut.c +++ b/test/unit/lib/reduce/reduce.c/reduce_ut.c @@ -152,6 +152,19 @@ persistent_pm_buf_destroy(void) g_persistent_pm_buf_len = 0; } +int __wrap_unlink(const char *path); + +int +__wrap_unlink(const char *path) +{ + if (strcmp(g_path, path) != 0) { + return ENOENT; + } + + persistent_pm_buf_destroy(); + return 0; +} + static void init_cb(void *cb_arg, struct spdk_reduce_vol *vol, int reduce_errno) { @@ -676,6 +689,59 @@ read_write(void) _read_write(4096); } +static void +destroy_cb(void *ctx, int reduce_errno) +{ + g_reduce_errno = reduce_errno; +} + +static void +destroy(void) +{ + struct spdk_reduce_vol_params params = {}; + struct spdk_reduce_backing_dev backing_dev = {}; + + params.chunk_size = 16 * 1024; + params.backing_io_unit_size = 512; + params.logical_block_size = 512; + spdk_uuid_generate(¶ms.uuid); + + backing_dev_init(&backing_dev, ¶ms, 512); + + g_vol = NULL; + g_reduce_errno = -1; + spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL); + CU_ASSERT(g_reduce_errno == 0); + SPDK_CU_ASSERT_FATAL(g_vol != NULL); + + g_reduce_errno = -1; + spdk_reduce_vol_unload(g_vol, unload_cb, NULL); + CU_ASSERT(g_reduce_errno == 0); + + g_vol = NULL; + g_reduce_errno = -1; + spdk_reduce_vol_load(&backing_dev, load_cb, NULL); + CU_ASSERT(g_reduce_errno == 0); + SPDK_CU_ASSERT_FATAL(g_vol != NULL); + + g_reduce_errno = -1; + spdk_reduce_vol_unload(g_vol, unload_cb, NULL); + CU_ASSERT(g_reduce_errno == 0); + + g_reduce_errno = -1; + MOCK_CLEAR(spdk_dma_zmalloc); + MOCK_CLEAR(spdk_malloc); + MOCK_CLEAR(spdk_zmalloc); + spdk_reduce_vol_destroy(&backing_dev, destroy_cb, NULL); + CU_ASSERT(g_reduce_errno == 0); + + g_reduce_errno = 0; + spdk_reduce_vol_load(&backing_dev, load_cb, NULL); + CU_ASSERT(g_reduce_errno == -EILSEQ); + + backing_dev_destroy(&backing_dev); +} + int main(int argc, char **argv) { @@ -700,7 +766,8 @@ main(int argc, char **argv) CU_add_test(suite, "init_backing_dev", init_backing_dev) == NULL || CU_add_test(suite, "load", load) == NULL || CU_add_test(suite, "write_maps", write_maps) == NULL || - CU_add_test(suite, "read_write", read_write) == NULL + CU_add_test(suite, "read_write", read_write) == NULL || + CU_add_test(suite, "destroy", destroy) == NULL ) { CU_cleanup_registry(); return CU_get_error();