From 95b76c4dcc0eabf959462e9c8f9b99e2f798dcde Mon Sep 17 00:00:00 2001 From: Tomasz Zawadzki Date: Wed, 21 Oct 2020 09:55:57 -0400 Subject: [PATCH] test/external_code: replace copies of test apps with symbolic links The files for external_code tests were copies of the same files in SPDK. Intention of external_code tests is to verify that nothing breaks in regards to building process. The copies were getting out of sync with functional changes. So to address this: - hello_bdev app is now symlinked - vbdev_passthrough is copied from respective files - RPC and name of the module were changed to not conflict with the original passthrough module Signed-off-by: Tomasz Zawadzki Change-Id: Idb83b8a06dea7143505d2062b23bfb35c86e3274 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4804 Reviewed-by: Ben Walker Reviewed-by: Paul Luse Reviewed-by: Jim Harris Tested-by: SPDK CI Jenkins --- test/external_code/README.md | 2 +- test/external_code/hello_world/hello_bdev.c | 301 +----------------- test/external_code/passthru/vbdev_passthru.c | 250 ++++++++------- test/external_code/passthru/vbdev_passthru.h | 10 +- .../passthru/vbdev_passthru_rpc.c | 58 ++-- 5 files changed, 171 insertions(+), 450 deletions(-) mode change 100644 => 120000 test/external_code/hello_world/hello_bdev.c diff --git a/test/external_code/README.md b/test/external_code/README.md index 3db3218c0..edf43911e 100644 --- a/test/external_code/README.md +++ b/test/external_code/README.md @@ -12,6 +12,6 @@ repository and should be run as follows: sudo ./test_make.sh /path/to/spdk ~~~ -The application `hello_world` and bdev module `passthru_external` have been copied from their namesakes +The application `hello_bdev` is a symlink and bdev module `passthru_external` have been copied from their namesakes in the top level [SPDK github repository](https://github.com/spdk/spdk) and don't have any special functionality. diff --git a/test/external_code/hello_world/hello_bdev.c b/test/external_code/hello_world/hello_bdev.c deleted file mode 100644 index cd62571e8..000000000 --- a/test/external_code/hello_world/hello_bdev.c +++ /dev/null @@ -1,300 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright (c) Intel Corporation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "spdk/stdinc.h" -#include "spdk/thread.h" -#include "spdk/bdev.h" -#include "spdk/env.h" -#include "spdk/event.h" -#include "spdk/log.h" -#include "spdk/string.h" -#include "spdk/bdev_module.h" - -static char *g_bdev_name = "Malloc0"; - -/* - * We'll use this struct to gather housekeeping hello_context to pass between - * our events and callbacks. - */ -struct hello_context_t { - struct spdk_bdev *bdev; - struct spdk_bdev_desc *bdev_desc; - struct spdk_io_channel *bdev_io_channel; - char *buff; - char *bdev_name; - struct spdk_bdev_io_wait_entry bdev_io_wait; -}; - -/* - * Usage function for printing parameters that are specific to this application - */ -static void -hello_bdev_usage(void) -{ - printf(" -b name of the bdev to use\n"); -} - -/* - * This function is called to parse the parameters that are specific to this application - */ -static int hello_bdev_parse_arg(int ch, char *arg) -{ - switch (ch) { - case 'b': - g_bdev_name = arg; - break; - default: - return -EINVAL; - } - return 0; -} - -/* - * Callback function for read io completion. - */ -static void -read_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) -{ - struct hello_context_t *hello_context = cb_arg; - - if (success) { - SPDK_NOTICELOG("Read string from bdev : %s\n", hello_context->buff); - } else { - SPDK_ERRLOG("bdev io read error\n"); - } - - /* Complete the bdev io and close the channel */ - spdk_bdev_free_io(bdev_io); - spdk_put_io_channel(hello_context->bdev_io_channel); - spdk_bdev_close(hello_context->bdev_desc); - SPDK_NOTICELOG("Stopping app\n"); - spdk_app_stop(success ? 0 : -1); -} - -static void -hello_read(void *arg) -{ - struct hello_context_t *hello_context = arg; - int rc = 0; - uint32_t length = spdk_bdev_get_block_size(hello_context->bdev); - - SPDK_NOTICELOG("Reading io\n"); - rc = spdk_bdev_read(hello_context->bdev_desc, hello_context->bdev_io_channel, - hello_context->buff, 0, length, read_complete, hello_context); - - if (rc == -ENOMEM) { - SPDK_NOTICELOG("Queueing io\n"); - /* In case we cannot perform I/O now, queue I/O */ - hello_context->bdev_io_wait.bdev = hello_context->bdev; - hello_context->bdev_io_wait.cb_fn = hello_read; - hello_context->bdev_io_wait.cb_arg = hello_context; - spdk_bdev_queue_io_wait(hello_context->bdev, hello_context->bdev_io_channel, - &hello_context->bdev_io_wait); - } else if (rc) { - SPDK_ERRLOG("%s error while reading from bdev: %d\n", spdk_strerror(-rc), rc); - spdk_put_io_channel(hello_context->bdev_io_channel); - spdk_bdev_close(hello_context->bdev_desc); - spdk_app_stop(-1); - } -} - -/* - * Callback function for write io completion. - */ -static void -write_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) -{ - struct hello_context_t *hello_context = cb_arg; - uint32_t length; - - /* Complete the I/O */ - spdk_bdev_free_io(bdev_io); - - if (success) { - SPDK_NOTICELOG("bdev io write completed successfully\n"); - } else { - SPDK_ERRLOG("bdev io write error: %d\n", EIO); - spdk_put_io_channel(hello_context->bdev_io_channel); - spdk_bdev_close(hello_context->bdev_desc); - spdk_app_stop(-1); - return; - } - - /* Zero the buffer so that we can use it for reading */ - length = spdk_bdev_get_block_size(hello_context->bdev); - memset(hello_context->buff, 0, length); - - hello_read(hello_context); -} - -static void -hello_write(void *arg) -{ - struct hello_context_t *hello_context = arg; - int rc = 0; - uint32_t length = spdk_bdev_get_block_size(hello_context->bdev); - - SPDK_NOTICELOG("Writing to the bdev\n"); - rc = spdk_bdev_write(hello_context->bdev_desc, hello_context->bdev_io_channel, - hello_context->buff, 0, length, write_complete, hello_context); - - if (rc == -ENOMEM) { - SPDK_NOTICELOG("Queueing io\n"); - /* In case we cannot perform I/O now, queue I/O */ - hello_context->bdev_io_wait.bdev = hello_context->bdev; - hello_context->bdev_io_wait.cb_fn = hello_write; - hello_context->bdev_io_wait.cb_arg = hello_context; - spdk_bdev_queue_io_wait(hello_context->bdev, hello_context->bdev_io_channel, - &hello_context->bdev_io_wait); - } else if (rc) { - SPDK_ERRLOG("%s error while writing to bdev: %d\n", spdk_strerror(-rc), rc); - spdk_put_io_channel(hello_context->bdev_io_channel); - spdk_bdev_close(hello_context->bdev_desc); - spdk_app_stop(-1); - } -} - -/* - * Our initial event that kicks off everything from main(). - */ -static void -hello_start(void *arg1) -{ - struct hello_context_t *hello_context = arg1; - uint32_t blk_size, buf_align; - int rc = 0; - hello_context->bdev = NULL; - hello_context->bdev_desc = NULL; - - SPDK_NOTICELOG("Successfully started the application\n"); - - /* - * Get the bdev. There can be many bdevs configured in - * in the configuration file but this application will only - * use the one input by the user at runtime so we get it via its name. - */ - hello_context->bdev = spdk_bdev_get_by_name(hello_context->bdev_name); - if (hello_context->bdev == NULL) { - SPDK_ERRLOG("Could not find the bdev: %s\n", hello_context->bdev_name); - spdk_app_stop(-1); - return; - } - - /* - * Open the bdev by calling spdk_bdev_open() - * The function will return a descriptor - */ - SPDK_NOTICELOG("Opening the bdev %s\n", hello_context->bdev_name); - rc = spdk_bdev_open(hello_context->bdev, true, NULL, NULL, &hello_context->bdev_desc); - if (rc) { - SPDK_ERRLOG("Could not open bdev: %s\n", hello_context->bdev_name); - spdk_app_stop(-1); - return; - } - - SPDK_NOTICELOG("Opening io channel\n"); - /* Open I/O channel */ - hello_context->bdev_io_channel = spdk_bdev_get_io_channel(hello_context->bdev_desc); - if (hello_context->bdev_io_channel == NULL) { - SPDK_ERRLOG("Could not create bdev I/O channel!!\n"); - spdk_bdev_close(hello_context->bdev_desc); - spdk_app_stop(-1); - return; - } - - /* Allocate memory for the write buffer. - * Initialize the write buffer with the string "Hello World!" - */ - blk_size = spdk_bdev_get_block_size(hello_context->bdev); - buf_align = spdk_bdev_get_buf_align(hello_context->bdev); - hello_context->buff = spdk_dma_zmalloc(blk_size, buf_align, NULL); - if (!hello_context->buff) { - SPDK_ERRLOG("Failed to allocate buffer\n"); - spdk_put_io_channel(hello_context->bdev_io_channel); - spdk_bdev_close(hello_context->bdev_desc); - spdk_app_stop(-1); - return; - } - snprintf(hello_context->buff, blk_size, "%s", "Hello World!\n"); - - hello_write(hello_context); -} - -int -main(int argc, char **argv) -{ - struct spdk_app_opts opts = {}; - int rc = 0; - struct hello_context_t hello_context = {}; - - /* Set default values in opts structure. */ - spdk_app_opts_init(&opts); - opts.name = "hello_bdev"; - - /* - * The user can provide the config file and bdev name at run time. - * For example, to use Malloc0 in file bdev.json run with params - * ./hello_bdev --json bdev.json -b Malloc0 - * To use passthru bdev PT0 run with params - * ./hello_bdev --json bdev.json -b PT0 - * If the bdev name is not specified, - * then Malloc0 is used by default - */ - if ((rc = spdk_app_parse_args(argc, argv, &opts, "b:", NULL, hello_bdev_parse_arg, - hello_bdev_usage)) != SPDK_APP_PARSE_ARGS_SUCCESS) { - exit(rc); - } - if (opts.json_config_file == NULL) { - SPDK_ERRLOG("configfile must be specified using --json e.g. --json bdev.json\n"); - exit(1); - } - hello_context.bdev_name = g_bdev_name; - - /* - * spdk_app_start() will block running hello_start() until - * spdk_app_stop() is called by someone (not simply when - * hello_start() returns), or if an error occurs during - * spdk_app_start() before hello_start() runs. - */ - rc = spdk_app_start(&opts, hello_start, &hello_context); - if (rc) { - SPDK_ERRLOG("ERROR starting application\n"); - } - - /* When the app stops, free up memory that we allocated. */ - spdk_dma_free(hello_context.buff); - - /* Gracefully close out all of the SPDK subsystems. */ - spdk_app_fini(); - return rc; -} diff --git a/test/external_code/hello_world/hello_bdev.c b/test/external_code/hello_world/hello_bdev.c new file mode 120000 index 000000000..835809ce3 --- /dev/null +++ b/test/external_code/hello_world/hello_bdev.c @@ -0,0 +1 @@ +./../../../examples/bdev/hello_world/hello_bdev.c \ No newline at end of file diff --git a/test/external_code/passthru/vbdev_passthru.c b/test/external_code/passthru/vbdev_passthru.c index cecc8f701..63e5ed9f0 100644 --- a/test/external_code/passthru/vbdev_passthru.c +++ b/test/external_code/passthru/vbdev_passthru.c @@ -36,31 +36,36 @@ * down to a bdev (or bdevs) that its configured to attach to. */ +#include "spdk/stdinc.h" + #include "vbdev_passthru.h" +#include "spdk/rpc.h" #include "spdk/env.h" -#include "spdk/conf.h" #include "spdk/endian.h" +#include "spdk/string.h" #include "spdk/thread.h" +#include "spdk/util.h" + +#include "spdk/bdev_module.h" +#include "spdk/log.h" -static int vbdev_ext_passthru_init(void); -static void vbdev_ext_passthru_get_spdk_running_config(FILE *fp); -static int vbdev_ext_passthru_get_ctx_size(void); -static void vbdev_ext_passthru_examine(struct spdk_bdev *bdev); -static void vbdev_ext_passthru_finish(void); -static int vbdev_ext_passthru_config_json(struct spdk_json_write_ctx *w); +static int vbdev_passthru_init(void); +static int vbdev_passthru_get_ctx_size(void); +static void vbdev_passthru_examine(struct spdk_bdev *bdev); +static void vbdev_passthru_finish(void); +static int vbdev_passthru_config_json(struct spdk_json_write_ctx *w); -static struct spdk_bdev_module passthru_if_external = { +static struct spdk_bdev_module passthru_if = { .name = "passthru_external", - .module_init = vbdev_ext_passthru_init, - .config_text = vbdev_ext_passthru_get_spdk_running_config, - .get_ctx_size = vbdev_ext_passthru_get_ctx_size, - .examine_config = vbdev_ext_passthru_examine, - .module_fini = vbdev_ext_passthru_finish, - .config_json = vbdev_ext_passthru_config_json + .module_init = vbdev_passthru_init, + .get_ctx_size = vbdev_passthru_get_ctx_size, + .examine_config = vbdev_passthru_examine, + .module_fini = vbdev_passthru_finish, + .config_json = vbdev_passthru_config_json }; -SPDK_BDEV_MODULE_REGISTER(passthru, &passthru_if_external) +SPDK_BDEV_MODULE_REGISTER(ext_passthru, &passthru_if) /* List of pt_bdev names and their base bdevs via configuration file. * Used so we can parse the conf once at init and use this list in examine(). @@ -78,6 +83,7 @@ struct vbdev_passthru { struct spdk_bdev_desc *base_desc; /* its descriptor we get from open */ struct spdk_bdev pt_bdev; /* the PT virtual bdev */ TAILQ_ENTRY(vbdev_passthru) link; + struct spdk_thread *thread; /* thread where base device is opened */ }; static TAILQ_HEAD(, vbdev_passthru) g_pt_nodes = TAILQ_HEAD_INITIALIZER(g_pt_nodes); @@ -119,6 +125,15 @@ _device_unregister_cb(void *io_device) free(pt_node); } +/* Wrapper for the bdev close operation. */ +static void +_vbdev_passthru_destruct(void *ctx) +{ + struct spdk_bdev_desc *desc = ctx; + + spdk_bdev_close(desc); +} + /* Called after we've unregistered following a hot remove callback. * Our finish entry point will be called next. */ @@ -136,8 +151,12 @@ vbdev_passthru_destruct(void *ctx) /* Unclaim the underlying bdev. */ spdk_bdev_module_release_bdev(pt_node->base_bdev); - /* Close the underlying bdev. */ - spdk_bdev_close(pt_node->base_desc); + /* Close the underlying bdev on its same opened thread. */ + if (pt_node->thread && pt_node->thread != spdk_get_thread()) { + spdk_thread_send_msg(pt_node->thread, _vbdev_passthru_destruct, pt_node->base_desc); + } else { + spdk_bdev_close(pt_node->base_desc); + } /* Unregister the io_device. */ spdk_io_device_unregister(pt_node, _device_unregister_cb); @@ -165,12 +184,35 @@ _pt_complete_io(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) } /* Complete the original IO and then free the one that we created here - * as a result of issuing an IO via submit_reqeust. + * as a result of issuing an IO via submit_request. */ spdk_bdev_io_complete(orig_io, status); spdk_bdev_free_io(bdev_io); } +static void +_pt_complete_zcopy_io(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) +{ + struct spdk_bdev_io *orig_io = cb_arg; + int status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED; + struct passthru_bdev_io *io_ctx = (struct passthru_bdev_io *)orig_io->driver_ctx; + + /* We setup this value in the submission routine, just showing here that it is + * passed back to us. + */ + if (io_ctx->test != 0x5a) { + SPDK_ERRLOG("Error, original IO device_ctx is wrong! 0x%x\n", + io_ctx->test); + } + + /* Complete the original IO and then free the one that we created here + * as a result of issuing an IO via submit_request. + */ + spdk_bdev_io_set_buf(orig_io, bdev_io->u.bdev.iovs[0].iov_base, bdev_io->u.bdev.iovs[0].iov_len); + spdk_bdev_io_complete(orig_io, status); + spdk_bdev_free_io(bdev_io); +} + static void vbdev_passthru_resubmit_io(void *arg) { @@ -184,13 +226,15 @@ static void vbdev_passthru_queue_io(struct spdk_bdev_io *bdev_io) { struct passthru_bdev_io *io_ctx = (struct passthru_bdev_io *)bdev_io->driver_ctx; + struct pt_io_channel *pt_ch = spdk_io_channel_get_ctx(io_ctx->ch); int rc; io_ctx->bdev_io_wait.bdev = bdev_io->bdev; io_ctx->bdev_io_wait.cb_fn = vbdev_passthru_resubmit_io; io_ctx->bdev_io_wait.cb_arg = bdev_io; - rc = spdk_bdev_queue_io_wait(bdev_io->bdev, io_ctx->ch, &io_ctx->bdev_io_wait); + /* Queue the IO using the channel of the base device. */ + rc = spdk_bdev_queue_io_wait(bdev_io->bdev, pt_ch->base_ch, &io_ctx->bdev_io_wait); if (rc != 0) { SPDK_ERRLOG("Queue io failed in vbdev_passthru_queue_io, rc=%d.\n", rc); spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); @@ -244,7 +288,7 @@ pt_read_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, boo /* Called when someone above submits IO to this pt vbdev. We're simply passing it on here * via SPDK IO calls which in turn allocate another bdev IO and call our cpl callback provided - * below along with the original bdiv_io so that we can complete it once this IO completes. + * below along with the original bdev_io so that we can complete it once this IO completes. */ static void vbdev_passthru_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) @@ -302,6 +346,15 @@ vbdev_passthru_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *b rc = spdk_bdev_reset(pt_node->base_desc, pt_ch->base_ch, _pt_complete_io, bdev_io); break; + case SPDK_BDEV_IO_TYPE_ZCOPY: + rc = spdk_bdev_zcopy_start(pt_node->base_desc, pt_ch->base_ch, bdev_io->u.bdev.offset_blocks, + bdev_io->u.bdev.num_blocks, bdev_io->u.bdev.zcopy.populate, + _pt_complete_zcopy_io, bdev_io); + break; + case SPDK_BDEV_IO_TYPE_ABORT: + rc = spdk_bdev_abort(pt_node->base_desc, pt_ch->base_ch, bdev_io->u.abort.bio_to_abort, + _pt_complete_io, bdev_io); + break; default: SPDK_ERRLOG("passthru: unknown I/O type %d\n", bdev_io->type); spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); @@ -354,13 +407,13 @@ vbdev_passthru_get_io_channel(void *ctx) return pt_ch; } -/* This is the output for get_bdevs() for this vbdev */ +/* This is the output for bdev_get_bdevs() for this vbdev */ static int vbdev_passthru_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) { struct vbdev_passthru *pt_node = (struct vbdev_passthru *)ctx; - spdk_json_write_name(w, "passthru"); + spdk_json_write_name(w, "passthru_external"); spdk_json_write_object_begin(w); spdk_json_write_named_string(w, "name", spdk_bdev_get_name(&pt_node->pt_bdev)); spdk_json_write_named_string(w, "base_bdev_name", spdk_bdev_get_name(pt_node->base_bdev)); @@ -371,13 +424,13 @@ vbdev_passthru_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) /* This is used to generate JSON that can configure this module to its current state. */ static int -vbdev_ext_passthru_config_json(struct spdk_json_write_ctx *w) +vbdev_passthru_config_json(struct spdk_json_write_ctx *w) { struct vbdev_passthru *pt_node; TAILQ_FOREACH(pt_node, &g_pt_nodes, link) { spdk_json_write_object_begin(w); - spdk_json_write_named_string(w, "method", "construct_passthru_bdev"); + spdk_json_write_named_string(w, "method", "construct_ext_passthru_bdev"); spdk_json_write_named_object_begin(w, "params"); spdk_json_write_named_string(w, "base_bdev_name", spdk_bdev_get_name(pt_node->base_bdev)); spdk_json_write_named_string(w, "name", spdk_bdev_get_name(&pt_node->pt_bdev)); @@ -406,7 +459,7 @@ pt_bdev_ch_create_cb(void *io_device, void *ctx_buf) /* We provide this callback for the SPDK channel code to destroy a channel * created with our create callback. We just need to undo anything we did - * when we created. If this bdev used its own poller, we'd unregsiter it here. + * when we created. If this bdev used its own poller, we'd unregister it here. */ static void pt_bdev_ch_destroy_cb(void *io_device, void *ctx_buf) @@ -456,52 +509,16 @@ vbdev_passthru_insert_name(const char *bdev_name, const char *vbdev_name) return 0; } -/* On init, just parse config file and build list of pt vbdevs and bdev name pairs. */ +/* On init, just perform bdev module specific initialization. */ static int -vbdev_ext_passthru_init(void) +vbdev_passthru_init(void) { - struct spdk_conf_section *sp = NULL; - const char *conf_bdev_name = NULL; - const char *conf_vbdev_name = NULL; - struct bdev_names *name; - int i, rc; - - sp = spdk_conf_find_section(NULL, "Ext_Pt"); - if (sp == NULL) { - return 0; - } - - for (i = 0; ; i++) { - if (!spdk_conf_section_get_nval(sp, "PTE", i)) { - break; - } - - conf_bdev_name = spdk_conf_section_get_nmval(sp, "PTE", i, 0); - if (!conf_bdev_name) { - SPDK_ERRLOG("Passthru configuration missing bdev name\n"); - break; - } - - conf_vbdev_name = spdk_conf_section_get_nmval(sp, "PTE", i, 1); - if (!conf_vbdev_name) { - SPDK_ERRLOG("Passthru configuration missing pt_bdev name\n"); - break; - } - - rc = vbdev_passthru_insert_name(conf_bdev_name, conf_vbdev_name); - if (rc != 0) { - return rc; - } - } - TAILQ_FOREACH(name, &g_bdev_names, link) { - SPDK_NOTICELOG("conf parse matched: %s\n", name->bdev_name); - } return 0; } /* Called when the entire module is being torn down. */ static void -vbdev_ext_passthru_finish(void) +vbdev_passthru_finish(void) { struct bdev_names *name; @@ -518,27 +535,12 @@ vbdev_ext_passthru_finish(void) * much context we want per IO. */ static int -vbdev_ext_passthru_get_ctx_size(void) +vbdev_passthru_get_ctx_size(void) { return sizeof(struct passthru_bdev_io); } -/* Called when SPDK wants to save the current config of this vbdev module to - * a file. - */ -static void -vbdev_ext_passthru_get_spdk_running_config(FILE *fp) -{ - struct bdev_names *names = NULL; - - fprintf(fp, "\n[Ext_Pt]\n"); - TAILQ_FOREACH(names, &g_bdev_names, link) { - fprintf(fp, " PTE %s %s\n", names->bdev_name, names->vbdev_name); - } - fprintf(fp, "\n"); -} - -/* Where vbdev_ext_passthru_config_json() is used to generate per module JSON config data, this +/* Where vbdev_passthru_config_json() is used to generate per module JSON config data, this * function is called to output any per bdev specific methods. For the PT module, there are * none. */ @@ -558,12 +560,10 @@ static const struct spdk_bdev_fn_table vbdev_passthru_fn_table = { .write_config_json = vbdev_passthru_write_config_json, }; -/* Called when the underlying base bdev goes away. */ static void -vbdev_passthru_base_bdev_hotremove_cb(void *ctx) +vbdev_passthru_base_bdev_hotremove_cb(struct spdk_bdev *bdev_find) { struct vbdev_passthru *pt_node, *tmp; - struct spdk_bdev *bdev_find = ctx; TAILQ_FOREACH_SAFE(pt_node, &g_pt_nodes, link, tmp) { if (bdev_find == pt_node->base_bdev) { @@ -572,25 +572,41 @@ vbdev_passthru_base_bdev_hotremove_cb(void *ctx) } } +/* Called when the underlying base bdev triggers asynchronous event such as bdev removal. */ +static void +vbdev_passthru_base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, + void *event_ctx) +{ + switch (type) { + case SPDK_BDEV_EVENT_REMOVE: + vbdev_passthru_base_bdev_hotremove_cb(bdev); + break; + default: + SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type); + break; + } +} + /* Create and register the passthru vbdev if we find it in our list of bdev names. * This can be called either by the examine path or RPC method. */ static int -vbdev_passthru_register(struct spdk_bdev *bdev) +vbdev_passthru_register(const char *bdev_name) { struct bdev_names *name; struct vbdev_passthru *pt_node; + struct spdk_bdev *bdev; int rc = 0; /* Check our list of names from config versus this bdev and if * there's a match, create the pt_node & bdev accordingly. */ TAILQ_FOREACH(name, &g_bdev_names, link) { - if (strcmp(name->bdev_name, bdev->name) != 0) { + if (strcmp(name->bdev_name, bdev_name) != 0) { continue; } - SPDK_NOTICELOG("Match on %s\n", bdev->name); + SPDK_NOTICELOG("Match on %s\n", bdev_name); pt_node = calloc(1, sizeof(struct vbdev_passthru)); if (!pt_node) { rc = -ENOMEM; @@ -598,8 +614,6 @@ vbdev_passthru_register(struct spdk_bdev *bdev) break; } - /* The base bdev that we're attaching to. */ - pt_node->base_bdev = bdev; pt_node->pt_bdev.name = strdup(name->vbdev_name); if (!pt_node->pt_bdev.name) { rc = -ENOMEM; @@ -609,6 +623,22 @@ vbdev_passthru_register(struct spdk_bdev *bdev) } pt_node->pt_bdev.product_name = "passthru"; + /* The base bdev that we're attaching to. */ + rc = spdk_bdev_open_ext(bdev_name, true, vbdev_passthru_base_bdev_event_cb, + NULL, &pt_node->base_desc); + if (rc) { + if (rc != -ENODEV) { + SPDK_ERRLOG("could not open bdev %s\n", bdev_name); + } + free(pt_node->pt_bdev.name); + free(pt_node); + break; + } + SPDK_NOTICELOG("base bdev opened\n"); + + bdev = spdk_bdev_desc_get_bdev(pt_node->base_desc); + pt_node->base_bdev = bdev; + /* Copy some properties from the underlying base bdev. */ pt_node->pt_bdev.write_cache = bdev->write_cache; pt_node->pt_bdev.required_alignment = bdev->required_alignment; @@ -627,7 +657,7 @@ vbdev_passthru_register(struct spdk_bdev *bdev) */ pt_node->pt_bdev.ctxt = pt_node; pt_node->pt_bdev.fn_table = &vbdev_passthru_fn_table; - pt_node->pt_bdev.module = &passthru_if_external; + pt_node->pt_bdev.module = &passthru_if; TAILQ_INSERT_TAIL(&g_pt_nodes, pt_node, link); spdk_io_device_register(pt_node, pt_bdev_ch_create_cb, pt_bdev_ch_destroy_cb, @@ -635,21 +665,12 @@ vbdev_passthru_register(struct spdk_bdev *bdev) name->vbdev_name); SPDK_NOTICELOG("io_device created at: 0x%p\n", pt_node); - rc = spdk_bdev_open(bdev, true, vbdev_passthru_base_bdev_hotremove_cb, - bdev, &pt_node->base_desc); - if (rc) { - SPDK_ERRLOG("could not open bdev %s\n", spdk_bdev_get_name(bdev)); - TAILQ_REMOVE(&g_pt_nodes, pt_node, link); - spdk_io_device_unregister(pt_node, NULL); - free(pt_node->pt_bdev.name); - free(pt_node); - break; - } - SPDK_NOTICELOG("bdev opened\n"); + /* Save the thread where the base device is opened */ + pt_node->thread = spdk_get_thread(); rc = spdk_bdev_module_claim_bdev(bdev, pt_node->base_desc, pt_node->pt_bdev.module); if (rc) { - SPDK_ERRLOG("could not claim bdev %s\n", spdk_bdev_get_name(bdev)); + SPDK_ERRLOG("could not claim bdev %s\n", bdev_name); spdk_bdev_close(pt_node->base_desc); TAILQ_REMOVE(&g_pt_nodes, pt_node, link); spdk_io_device_unregister(pt_node, NULL); @@ -679,12 +700,11 @@ vbdev_passthru_register(struct spdk_bdev *bdev) /* Create the passthru disk from the given bdev and vbdev name. */ int -create_passthru_disk(const char *bdev_name, const char *vbdev_name) +bdev_passthru_create_disk(const char *bdev_name, const char *vbdev_name) { - struct spdk_bdev *bdev = NULL; - int rc = 0; + int rc; - /* Insert the bdev into our global name list even if it doesn't exist yet, + /* Insert the bdev name into our global name list even if it doesn't exist yet, * it may show up soon... */ rc = vbdev_passthru_insert_name(bdev_name, vbdev_name); @@ -692,24 +712,24 @@ create_passthru_disk(const char *bdev_name, const char *vbdev_name) return rc; } - bdev = spdk_bdev_get_by_name(bdev_name); - if (!bdev) { + rc = vbdev_passthru_register(bdev_name); + if (rc == -ENODEV) { /* This is not an error, we tracked the name above and it still * may show up later. */ SPDK_NOTICELOG("vbdev creation deferred pending base bdev arrival\n"); - return 0; + rc = 0; } - return vbdev_passthru_register(bdev); + return rc; } void -delete_passthru_disk(struct spdk_bdev *bdev, spdk_bdev_unregister_cb cb_fn, void *cb_arg) +bdev_passthru_delete_disk(struct spdk_bdev *bdev, spdk_bdev_unregister_cb cb_fn, void *cb_arg) { struct bdev_names *name; - if (!bdev || bdev->module != &passthru_if_external) { + if (!bdev || bdev->module != &passthru_if) { cb_fn(cb_arg, -ENODEV); return; } @@ -740,9 +760,9 @@ delete_passthru_disk(struct spdk_bdev *bdev, spdk_bdev_unregister_cb cb_fn, void * bdev, here's where we do it. */ static void -vbdev_ext_passthru_examine(struct spdk_bdev *bdev) +vbdev_passthru_examine(struct spdk_bdev *bdev) { - vbdev_passthru_register(bdev); + vbdev_passthru_register(bdev->name); - spdk_bdev_module_examine_done(&passthru_if_external); + spdk_bdev_module_examine_done(&passthru_if); } diff --git a/test/external_code/passthru/vbdev_passthru.h b/test/external_code/passthru/vbdev_passthru.h index db6ad8e8f..716e187c1 100644 --- a/test/external_code/passthru/vbdev_passthru.h +++ b/test/external_code/passthru/vbdev_passthru.h @@ -38,10 +38,6 @@ #include "spdk/bdev.h" #include "spdk/bdev_module.h" -#include "spdk/log.h" -#include "spdk/rpc.h" -#include "spdk/string.h" -#include "spdk/util.h" /** * Create new pass through bdev. @@ -50,7 +46,7 @@ * \param vbdev_name Name of the pass through bdev. * \return 0 on success, other on failure. */ -int create_passthru_disk(const char *bdev_name, const char *vbdev_name); +int bdev_passthru_create_disk(const char *bdev_name, const char *vbdev_name); /** * Delete passthru bdev. @@ -59,7 +55,7 @@ int create_passthru_disk(const char *bdev_name, const char *vbdev_name); * \param cb_fn Function to call after deletion. * \param cb_arg Argument to pass to cb_fn. */ -void delete_passthru_disk(struct spdk_bdev *bdev, spdk_bdev_unregister_cb cb_fn, - void *cb_arg); +void bdev_passthru_delete_disk(struct spdk_bdev *bdev, spdk_bdev_unregister_cb cb_fn, + void *cb_arg); #endif /* SPDK_VBDEV_PASSTHRU_H */ diff --git a/test/external_code/passthru/vbdev_passthru_rpc.c b/test/external_code/passthru/vbdev_passthru_rpc.c index a50be08ed..00b85a83b 100644 --- a/test/external_code/passthru/vbdev_passthru_rpc.c +++ b/test/external_code/passthru/vbdev_passthru_rpc.c @@ -32,48 +32,52 @@ */ #include "vbdev_passthru.h" +#include "spdk/rpc.h" +#include "spdk/util.h" +#include "spdk/string.h" +#include "spdk/log.h" /* Structure to hold the parameters for this RPC method. */ -struct rpc_construct_passthru { +struct rpc_bdev_passthru_create { char *base_bdev_name; char *name; }; /* Free the allocated memory resource after the RPC handling. */ static void -free_rpc_construct_passthru(struct rpc_construct_passthru *r) +free_rpc_bdev_passthru_create(struct rpc_bdev_passthru_create *r) { free(r->base_bdev_name); free(r->name); } /* Structure to decode the input parameters for this RPC method. */ -static const struct spdk_json_object_decoder rpc_construct_passthru_decoders[] = { - {"base_bdev_name", offsetof(struct rpc_construct_passthru, base_bdev_name), spdk_json_decode_string}, - {"name", offsetof(struct rpc_construct_passthru, name), spdk_json_decode_string}, +static const struct spdk_json_object_decoder rpc_bdev_passthru_create_decoders[] = { + {"base_bdev_name", offsetof(struct rpc_bdev_passthru_create, base_bdev_name), spdk_json_decode_string}, + {"name", offsetof(struct rpc_bdev_passthru_create, name), spdk_json_decode_string}, }; /* Decode the parameters for this RPC method and properly construct the passthru * device. Error status returned in the failed cases. */ static void -spdk_rpc_construct_passthru_bdev(struct spdk_jsonrpc_request *request, - const struct spdk_json_val *params) +rpc_bdev_passthru_create(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) { - struct rpc_construct_passthru req = {NULL}; + struct rpc_bdev_passthru_create req = {NULL}; struct spdk_json_write_ctx *w; int rc; - if (spdk_json_decode_object(params, rpc_construct_passthru_decoders, - SPDK_COUNTOF(rpc_construct_passthru_decoders), + if (spdk_json_decode_object(params, rpc_bdev_passthru_create_decoders, + SPDK_COUNTOF(rpc_bdev_passthru_create_decoders), &req)) { - SPDK_ERRLOG("spdk_json_decode_object failed\n"); + SPDK_DEBUGLOG(vbdev_passthru, "spdk_json_decode_object failed\n"); spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "spdk_json_decode_object failed"); goto cleanup; } - rc = create_passthru_disk(req.base_bdev_name, req.name); + rc = bdev_passthru_create_disk(req.base_bdev_name, req.name); if (rc != 0) { spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); goto cleanup; @@ -84,26 +88,26 @@ spdk_rpc_construct_passthru_bdev(struct spdk_jsonrpc_request *request, spdk_jsonrpc_end_result(request, w); cleanup: - free_rpc_construct_passthru(&req); + free_rpc_bdev_passthru_create(&req); } -SPDK_RPC_REGISTER("construct_ext_passthru_bdev", spdk_rpc_construct_passthru_bdev, SPDK_RPC_RUNTIME) +SPDK_RPC_REGISTER("construct_ext_passthru_bdev", rpc_bdev_passthru_create, SPDK_RPC_RUNTIME) -struct rpc_delete_passthru { +struct rpc_bdev_passthru_delete { char *name; }; static void -free_rpc_delete_passthru(struct rpc_delete_passthru *req) +free_rpc_bdev_passthru_delete(struct rpc_bdev_passthru_delete *req) { free(req->name); } -static const struct spdk_json_object_decoder rpc_delete_passthru_decoders[] = { - {"name", offsetof(struct rpc_delete_passthru, name), spdk_json_decode_string}, +static const struct spdk_json_object_decoder rpc_bdev_passthru_delete_decoders[] = { + {"name", offsetof(struct rpc_bdev_passthru_delete, name), spdk_json_decode_string}, }; static void -_spdk_rpc_delete_passthru_bdev_cb(void *cb_arg, int bdeverrno) +rpc_bdev_passthru_delete_cb(void *cb_arg, int bdeverrno) { struct spdk_jsonrpc_request *request = cb_arg; struct spdk_json_write_ctx *w; @@ -114,14 +118,14 @@ _spdk_rpc_delete_passthru_bdev_cb(void *cb_arg, int bdeverrno) } static void -spdk_rpc_delete_passthru_bdev(struct spdk_jsonrpc_request *request, - const struct spdk_json_val *params) +rpc_bdev_passthru_delete(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) { - struct rpc_delete_passthru req = {NULL}; + struct rpc_bdev_passthru_delete req = {NULL}; struct spdk_bdev *bdev; - if (spdk_json_decode_object(params, rpc_delete_passthru_decoders, - SPDK_COUNTOF(rpc_delete_passthru_decoders), + if (spdk_json_decode_object(params, rpc_bdev_passthru_delete_decoders, + SPDK_COUNTOF(rpc_bdev_passthru_delete_decoders), &req)) { spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "spdk_json_decode_object failed"); @@ -134,9 +138,9 @@ spdk_rpc_delete_passthru_bdev(struct spdk_jsonrpc_request *request, goto cleanup; } - delete_passthru_disk(bdev, _spdk_rpc_delete_passthru_bdev_cb, request); + bdev_passthru_delete_disk(bdev, rpc_bdev_passthru_delete_cb, request); cleanup: - free_rpc_delete_passthru(&req); + free_rpc_bdev_passthru_delete(&req); } -SPDK_RPC_REGISTER("delete_ext_passthru_bdev", spdk_rpc_delete_passthru_bdev, SPDK_RPC_RUNTIME) +SPDK_RPC_REGISTER("delete_ext_passthru_bdev", rpc_bdev_passthru_delete, SPDK_RPC_RUNTIME)