diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/spdk/lib/event/subsystems | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/lib/event/subsystems')
23 files changed, 4455 insertions, 0 deletions
diff --git a/src/spdk/lib/event/subsystems/Makefile b/src/spdk/lib/event/subsystems/Makefile new file mode 100644 index 00000000..4a19160b --- /dev/null +++ b/src/spdk/lib/event/subsystems/Makefile @@ -0,0 +1,44 @@ +# +# 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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +DIRS-y += bdev copy iscsi nbd net nvmf scsi vhost + +.PHONY: all clean $(DIRS-y) + +all: $(DIRS-y) +clean: $(DIRS-y) + +include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk diff --git a/src/spdk/lib/event/subsystems/bdev/Makefile b/src/spdk/lib/event/subsystems/bdev/Makefile new file mode 100644 index 00000000..1747b759 --- /dev/null +++ b/src/spdk/lib/event/subsystems/bdev/Makefile @@ -0,0 +1,40 @@ +# +# 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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +C_SRCS = bdev.c bdev_rpc.c +LIBNAME = event_bdev + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/event/subsystems/bdev/bdev.c b/src/spdk/lib/event/subsystems/bdev/bdev.c new file mode 100644 index 00000000..5999d612 --- /dev/null +++ b/src/spdk/lib/event/subsystems/bdev/bdev.c @@ -0,0 +1,83 @@ +/*- + * 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/bdev.h" +#include "spdk/env.h" +#include "spdk/thread.h" + +#include "spdk_internal/event.h" +#include "spdk/env.h" + +static void +spdk_bdev_initialize_complete(void *cb_arg, int rc) +{ + spdk_subsystem_init_next(rc); +} + +static void +spdk_bdev_subsystem_initialize(void) +{ + spdk_bdev_initialize(spdk_bdev_initialize_complete, NULL); +} + +static void +spdk_bdev_subsystem_finish_done(void *cb_arg) +{ + spdk_subsystem_fini_next(); +} + +static void +spdk_bdev_subsystem_finish(void) +{ + spdk_bdev_finish(spdk_bdev_subsystem_finish_done, NULL); +} + +static void +_spdk_bdev_subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_event *done_ev) +{ + spdk_bdev_subsystem_config_json(w); + spdk_event_call(done_ev); +} + +static struct spdk_subsystem g_spdk_subsystem_bdev = { + .name = "bdev", + .init = spdk_bdev_subsystem_initialize, + .fini = spdk_bdev_subsystem_finish, + .config = spdk_bdev_config_text, + .write_config_json = _spdk_bdev_subsystem_config_json, +}; + +SPDK_SUBSYSTEM_REGISTER(g_spdk_subsystem_bdev); +SPDK_SUBSYSTEM_DEPEND(bdev, copy) diff --git a/src/spdk/lib/event/subsystems/bdev/bdev_rpc.c b/src/spdk/lib/event/subsystems/bdev/bdev_rpc.c new file mode 100644 index 00000000..69ead5f2 --- /dev/null +++ b/src/spdk/lib/event/subsystems/bdev/bdev_rpc.c @@ -0,0 +1,97 @@ +/*- + * 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/bdev.h" + +#include "spdk/rpc.h" +#include "spdk/util.h" +#include "spdk/string.h" + +#include "spdk_internal/log.h" + +struct spdk_rpc_set_bdev_opts { + uint32_t bdev_io_pool_size; + uint32_t bdev_io_cache_size; +}; + +static const struct spdk_json_object_decoder rpc_set_bdev_opts_decoders[] = { + {"bdev_io_pool_size", offsetof(struct spdk_rpc_set_bdev_opts, bdev_io_pool_size), spdk_json_decode_uint32, true}, + {"bdev_io_cache_size", offsetof(struct spdk_rpc_set_bdev_opts, bdev_io_cache_size), spdk_json_decode_uint32, true}, +}; + +static void +spdk_rpc_set_bdev_opts(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) +{ + struct spdk_rpc_set_bdev_opts rpc_opts; + struct spdk_bdev_opts bdev_opts; + struct spdk_json_write_ctx *w; + int rc; + + rpc_opts.bdev_io_pool_size = UINT32_MAX; + rpc_opts.bdev_io_cache_size = UINT32_MAX; + + if (params != NULL) { + if (spdk_json_decode_object(params, rpc_set_bdev_opts_decoders, + SPDK_COUNTOF(rpc_set_bdev_opts_decoders), &rpc_opts)) { + SPDK_ERRLOG("spdk_json_decode_object() failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + return; + } + } + + spdk_bdev_get_opts(&bdev_opts); + if (rpc_opts.bdev_io_pool_size != UINT32_MAX) { + bdev_opts.bdev_io_pool_size = rpc_opts.bdev_io_pool_size; + } + if (rpc_opts.bdev_io_cache_size != UINT32_MAX) { + bdev_opts.bdev_io_cache_size = rpc_opts.bdev_io_cache_size; + } + rc = spdk_bdev_set_opts(&bdev_opts); + + if (rc != 0) { + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Pool size %" PRIu32 " too small for cache size %" PRIu32, + bdev_opts.bdev_io_pool_size, bdev_opts.bdev_io_cache_size); + return; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} +SPDK_RPC_REGISTER("set_bdev_options", spdk_rpc_set_bdev_opts, SPDK_RPC_STARTUP) diff --git a/src/spdk/lib/event/subsystems/copy/Makefile b/src/spdk/lib/event/subsystems/copy/Makefile new file mode 100644 index 00000000..691eee2a --- /dev/null +++ b/src/spdk/lib/event/subsystems/copy/Makefile @@ -0,0 +1,40 @@ +# +# 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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +C_SRCS = copy.c +LIBNAME = event_copy + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/event/subsystems/copy/copy.c b/src/spdk/lib/event/subsystems/copy/copy.c new file mode 100644 index 00000000..9bc6e281 --- /dev/null +++ b/src/spdk/lib/event/subsystems/copy/copy.c @@ -0,0 +1,70 @@ +/*- + * 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/copy_engine.h" + +#include "spdk_internal/event.h" +#include "spdk/env.h" + +static void +spdk_copy_engine_subsystem_initialize(void) +{ + int rc; + + rc = spdk_copy_engine_initialize(); + + spdk_subsystem_init_next(rc); +} + +static void +spdk_copy_engine_subsystem_finish_done(void *cb_arg) +{ + spdk_subsystem_fini_next(); +} + +static void +spdk_copy_engine_subsystem_finish(void) +{ + spdk_copy_engine_finish(spdk_copy_engine_subsystem_finish_done, NULL); +} + +static struct spdk_subsystem g_spdk_subsystem_copy = { + .name = "copy", + .init = spdk_copy_engine_subsystem_initialize, + .fini = spdk_copy_engine_subsystem_finish, + .config = spdk_copy_engine_config_text, +}; + +SPDK_SUBSYSTEM_REGISTER(g_spdk_subsystem_copy); diff --git a/src/spdk/lib/event/subsystems/iscsi/Makefile b/src/spdk/lib/event/subsystems/iscsi/Makefile new file mode 100644 index 00000000..f57d9f9c --- /dev/null +++ b/src/spdk/lib/event/subsystems/iscsi/Makefile @@ -0,0 +1,41 @@ +# +# 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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +CFLAGS += -I$(SPDK_ROOT_DIR)/lib +C_SRCS = iscsi.c iscsi_rpc.c +LIBNAME = event_iscsi + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/event/subsystems/iscsi/iscsi.c b/src/spdk/lib/event/subsystems/iscsi/iscsi.c new file mode 100644 index 00000000..72750398 --- /dev/null +++ b/src/spdk/lib/event/subsystems/iscsi/iscsi.c @@ -0,0 +1,81 @@ +/*- + * 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 "iscsi/iscsi.h" + +#include "spdk_internal/event.h" + +static void +spdk_iscsi_subsystem_init_complete(void *cb_arg, int rc) +{ + spdk_subsystem_init_next(rc); +} + +static void +spdk_iscsi_subsystem_init(void) +{ + spdk_iscsi_init(spdk_iscsi_subsystem_init_complete, NULL); +} + +static void +spdk_iscsi_subsystem_fini_done(void *arg) +{ + spdk_subsystem_fini_next(); +} + +static void +spdk_iscsi_subsystem_fini(void) +{ + spdk_iscsi_fini(spdk_iscsi_subsystem_fini_done, NULL); +} + +static void +spdk_iscsi_subsystem_config_json(struct spdk_json_write_ctx *w, + struct spdk_event *done_ev) +{ + spdk_iscsi_config_json(w); + spdk_event_call(done_ev); +} + +static struct spdk_subsystem g_spdk_subsystem_iscsi = { + .name = "iscsi", + .init = spdk_iscsi_subsystem_init, + .fini = spdk_iscsi_subsystem_fini, + .config = spdk_iscsi_config_text, + .write_config_json = spdk_iscsi_subsystem_config_json, +}; + +SPDK_SUBSYSTEM_REGISTER(g_spdk_subsystem_iscsi); +SPDK_SUBSYSTEM_DEPEND(iscsi, scsi) diff --git a/src/spdk/lib/event/subsystems/iscsi/iscsi_rpc.c b/src/spdk/lib/event/subsystems/iscsi/iscsi_rpc.c new file mode 100644 index 00000000..fb96be07 --- /dev/null +++ b/src/spdk/lib/event/subsystems/iscsi/iscsi_rpc.c @@ -0,0 +1,119 @@ +/*- + * 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 "iscsi/iscsi.h" +#include "iscsi/conn.h" + +#include "spdk/rpc.h" +#include "spdk/util.h" +#include "spdk/event.h" + +#include "spdk_internal/log.h" + +static const struct spdk_json_object_decoder rpc_set_iscsi_opts_decoders[] = { + {"auth_file", offsetof(struct spdk_iscsi_opts, authfile), spdk_json_decode_string, true}, + {"node_base", offsetof(struct spdk_iscsi_opts, nodebase), spdk_json_decode_string, true}, + {"nop_timeout", offsetof(struct spdk_iscsi_opts, timeout), spdk_json_decode_int32, true}, + {"nop_in_interval", offsetof(struct spdk_iscsi_opts, nopininterval), spdk_json_decode_int32, true}, + {"no_discovery_auth", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true}, + {"req_discovery_auth", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true}, + {"req_discovery_auth_mutual", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true}, + {"discovery_auth_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true}, + {"disable_chap", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true}, + {"require_chap", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true}, + {"mutual_chap", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true}, + {"chap_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true}, + {"max_sessions", offsetof(struct spdk_iscsi_opts, MaxSessions), spdk_json_decode_uint32, true}, + {"max_queue_depth", offsetof(struct spdk_iscsi_opts, MaxQueueDepth), spdk_json_decode_uint32, true}, + {"max_connections_per_session", offsetof(struct spdk_iscsi_opts, MaxConnectionsPerSession), spdk_json_decode_uint32, true}, + {"default_time2wait", offsetof(struct spdk_iscsi_opts, DefaultTime2Wait), spdk_json_decode_uint32, true}, + {"default_time2retain", offsetof(struct spdk_iscsi_opts, DefaultTime2Retain), spdk_json_decode_uint32, true}, + {"first_burst_length", offsetof(struct spdk_iscsi_opts, FirstBurstLength), spdk_json_decode_uint32, true}, + {"immediate_data", offsetof(struct spdk_iscsi_opts, ImmediateData), spdk_json_decode_bool, true}, + {"error_recovery_level", offsetof(struct spdk_iscsi_opts, ErrorRecoveryLevel), spdk_json_decode_uint32, true}, + {"allow_duplicated_isid", offsetof(struct spdk_iscsi_opts, AllowDuplicateIsid), spdk_json_decode_bool, true}, + {"min_connections_per_core", offsetof(struct spdk_iscsi_opts, min_connections_per_core), spdk_json_decode_uint32, true}, +}; + +static void +spdk_rpc_iscsi_set_opts(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct spdk_iscsi_opts *opts; + struct spdk_json_write_ctx *w; + + if (g_spdk_iscsi_opts != NULL) { + SPDK_ERRLOG("this RPC must not be called more than once.\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Must not call more than once"); + return; + } + + opts = spdk_iscsi_opts_alloc(); + if (opts == NULL) { + SPDK_ERRLOG("spdk_iscsi_opts_alloc() failed.\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Out of memory"); + return; + } + + if (params != NULL) { + if (spdk_json_decode_object(params, rpc_set_iscsi_opts_decoders, + SPDK_COUNTOF(rpc_set_iscsi_opts_decoders), opts)) { + SPDK_ERRLOG("spdk_json_decode_object() failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + spdk_iscsi_opts_free(opts); + return; + } + } + + g_spdk_iscsi_opts = spdk_iscsi_opts_copy(opts); + spdk_iscsi_opts_free(opts); + + if (g_spdk_iscsi_opts == NULL) { + SPDK_ERRLOG("spdk_iscsi_opts_copy() failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Out of memory"); + return; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} +SPDK_RPC_REGISTER("set_iscsi_options", spdk_rpc_iscsi_set_opts, SPDK_RPC_STARTUP) diff --git a/src/spdk/lib/event/subsystems/nbd/Makefile b/src/spdk/lib/event/subsystems/nbd/Makefile new file mode 100644 index 00000000..92d99f15 --- /dev/null +++ b/src/spdk/lib/event/subsystems/nbd/Makefile @@ -0,0 +1,40 @@ +# +# 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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +C_SRCS = nbd.c +LIBNAME = event_nbd + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/event/subsystems/nbd/nbd.c b/src/spdk/lib/event/subsystems/nbd/nbd.c new file mode 100644 index 00000000..a943eb82 --- /dev/null +++ b/src/spdk/lib/event/subsystems/nbd/nbd.c @@ -0,0 +1,74 @@ +/*- + * 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/nbd.h" + +#include "spdk_internal/event.h" + +static void +spdk_nbd_subsystem_init(void) +{ + int rc; + + rc = spdk_nbd_init(); + + spdk_subsystem_init_next(rc); +} + +static void +spdk_nbd_subsystem_fini(void) +{ + spdk_nbd_fini(); + spdk_subsystem_fini_next(); +} + +static void +spdk_nbd_subsystem_write_config_json(struct spdk_json_write_ctx *w, + struct spdk_event *done_ev) +{ + spdk_nbd_write_config_json(w); + spdk_event_call(done_ev); +} + +static struct spdk_subsystem g_spdk_subsystem_nbd = { + .name = "nbd", + .init = spdk_nbd_subsystem_init, + .fini = spdk_nbd_subsystem_fini, + .config = NULL, + .write_config_json = spdk_nbd_subsystem_write_config_json, +}; + +SPDK_SUBSYSTEM_REGISTER(g_spdk_subsystem_nbd); +SPDK_SUBSYSTEM_DEPEND(nbd, bdev) diff --git a/src/spdk/lib/event/subsystems/net/Makefile b/src/spdk/lib/event/subsystems/net/Makefile new file mode 100644 index 00000000..cf81f07b --- /dev/null +++ b/src/spdk/lib/event/subsystems/net/Makefile @@ -0,0 +1,40 @@ +# +# 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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +C_SRCS = net.c +LIBNAME = event_net + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/event/subsystems/net/net.c b/src/spdk/lib/event/subsystems/net/net.c new file mode 100644 index 00000000..9355514f --- /dev/null +++ b/src/spdk/lib/event/subsystems/net/net.c @@ -0,0 +1,91 @@ +/*- + * 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/net.h" + +#include "spdk_internal/event.h" + +static void +spdk_interface_subsystem_init(void) +{ + int rc; + + rc = spdk_interface_init(); + + spdk_subsystem_init_next(rc); +} + +static void +spdk_interface_subsystem_destroy(void) +{ + spdk_interface_destroy(); + spdk_subsystem_fini_next(); +} + +static struct spdk_subsystem g_spdk_subsystem_interface = { + .name = "interface", + .init = spdk_interface_subsystem_init, + .fini = spdk_interface_subsystem_destroy, + .config = NULL, +}; + +SPDK_SUBSYSTEM_REGISTER(g_spdk_subsystem_interface); + +static void +spdk_net_subsystem_start(void) +{ + int rc; + + rc = spdk_net_framework_start(); + + spdk_subsystem_init_next(rc); +} + +static void +spdk_net_subsystem_fini(void) +{ + spdk_net_framework_fini(); + spdk_subsystem_fini_next(); +} + +static struct spdk_subsystem g_spdk_subsystem_net_framework = { + .name = "net_framework", + .init = spdk_net_subsystem_start, + .fini = spdk_net_subsystem_fini, + .config = NULL, +}; + +SPDK_SUBSYSTEM_REGISTER(g_spdk_subsystem_net_framework); +SPDK_SUBSYSTEM_DEPEND(net_framework, interface) diff --git a/src/spdk/lib/event/subsystems/nvmf/Makefile b/src/spdk/lib/event/subsystems/nvmf/Makefile new file mode 100644 index 00000000..eca62e25 --- /dev/null +++ b/src/spdk/lib/event/subsystems/nvmf/Makefile @@ -0,0 +1,40 @@ +# +# 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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +C_SRCS = conf.c nvmf_rpc.c nvmf_rpc_deprecated.c nvmf_tgt.c +LIBNAME = event_nvmf + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/event/subsystems/nvmf/conf.c b/src/spdk/lib/event/subsystems/nvmf/conf.c new file mode 100644 index 00000000..986e81c9 --- /dev/null +++ b/src/spdk/lib/event/subsystems/nvmf/conf.c @@ -0,0 +1,587 @@ +/*- + * 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 "event_nvmf.h" + +#include "spdk/conf.h" +#include "spdk/log.h" +#include "spdk/bdev.h" +#include "spdk/nvme.h" +#include "spdk/nvmf.h" +#include "spdk/string.h" +#include "spdk/util.h" + +#define SPDK_NVMF_MAX_NAMESPACES (1 << 14) + +struct spdk_nvmf_tgt_opts *g_spdk_nvmf_tgt_opts = NULL; +struct spdk_nvmf_tgt_conf *g_spdk_nvmf_tgt_conf = NULL; + +static int +spdk_add_nvmf_discovery_subsystem(void) +{ + struct spdk_nvmf_subsystem *subsystem; + + subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, SPDK_NVMF_DISCOVERY_NQN, + SPDK_NVMF_SUBTYPE_DISCOVERY, 0); + if (subsystem == NULL) { + SPDK_ERRLOG("Failed creating discovery nvmf library subsystem\n"); + return -1; + } + + spdk_nvmf_subsystem_set_allow_any_host(subsystem, true); + + return 0; +} + +static void +spdk_nvmf_read_config_file_tgt_opts(struct spdk_conf_section *sp, + struct spdk_nvmf_tgt_opts *opts) +{ + int max_queue_depth; + int max_queues_per_sess; + int in_capsule_data_size; + int max_io_size; + int io_unit_size; + + max_queue_depth = spdk_conf_section_get_intval(sp, "MaxQueueDepth"); + if (max_queue_depth >= 0) { + opts->max_queue_depth = max_queue_depth; + } + + max_queues_per_sess = spdk_conf_section_get_intval(sp, "MaxQueuesPerSession"); + if (max_queues_per_sess >= 0) { + opts->max_qpairs_per_ctrlr = max_queues_per_sess; + } + + in_capsule_data_size = spdk_conf_section_get_intval(sp, "InCapsuleDataSize"); + if (in_capsule_data_size >= 0) { + opts->in_capsule_data_size = in_capsule_data_size; + } + + max_io_size = spdk_conf_section_get_intval(sp, "MaxIOSize"); + if (max_io_size >= 0) { + opts->max_io_size = max_io_size; + } + + io_unit_size = spdk_conf_section_get_intval(sp, "IOUnitSize"); + if (io_unit_size >= 0) { + opts->io_unit_size = io_unit_size; + } +} + +static void +spdk_nvmf_read_config_file_tgt_conf(struct spdk_conf_section *sp, + struct spdk_nvmf_tgt_conf *conf) +{ + int acceptor_poll_rate; + + acceptor_poll_rate = spdk_conf_section_get_intval(sp, "AcceptorPollRate"); + if (acceptor_poll_rate >= 0) { + conf->acceptor_poll_rate = acceptor_poll_rate; + } +} + +static struct spdk_nvmf_tgt_opts * +spdk_nvmf_parse_tgt_opts(void) +{ + struct spdk_nvmf_tgt_opts *opts; + struct spdk_conf_section *sp; + + opts = calloc(1, sizeof(*opts)); + if (!opts) { + SPDK_ERRLOG("calloc() failed for target options\n"); + return NULL; + } + + spdk_nvmf_tgt_opts_init(opts); + + sp = spdk_conf_find_section(NULL, "Nvmf"); + if (sp != NULL) { + spdk_nvmf_read_config_file_tgt_opts(sp, opts); + } + + return opts; +} + +static struct spdk_nvmf_tgt_conf * +spdk_nvmf_parse_tgt_conf(void) +{ + struct spdk_nvmf_tgt_conf *conf; + struct spdk_conf_section *sp; + + conf = calloc(1, sizeof(*conf)); + if (!conf) { + SPDK_ERRLOG("calloc() failed for target conf\n"); + return NULL; + } + + conf->acceptor_poll_rate = ACCEPT_TIMEOUT_US; + conf->conn_sched = DEFAULT_CONN_SCHED; + + sp = spdk_conf_find_section(NULL, "Nvmf"); + if (sp != NULL) { + spdk_nvmf_read_config_file_tgt_conf(sp, conf); + } + + return conf; +} + +static int +spdk_nvmf_parse_nvmf_tgt(void) +{ + int rc; + + if (!g_spdk_nvmf_tgt_opts) { + g_spdk_nvmf_tgt_opts = spdk_nvmf_parse_tgt_opts(); + if (!g_spdk_nvmf_tgt_opts) { + SPDK_ERRLOG("spdk_nvmf_parse_tgt_opts() failed\n"); + return -1; + } + } + + if (!g_spdk_nvmf_tgt_conf) { + g_spdk_nvmf_tgt_conf = spdk_nvmf_parse_tgt_conf(); + if (!g_spdk_nvmf_tgt_conf) { + SPDK_ERRLOG("spdk_nvmf_parse_tgt_conf() failed\n"); + return -1; + } + } + + g_spdk_nvmf_tgt = spdk_nvmf_tgt_create(g_spdk_nvmf_tgt_opts); + + free(g_spdk_nvmf_tgt_opts); + g_spdk_nvmf_tgt_opts = NULL; + + if (!g_spdk_nvmf_tgt) { + SPDK_ERRLOG("spdk_nvmf_tgt_create() failed\n"); + return -1; + } + + rc = spdk_add_nvmf_discovery_subsystem(); + if (rc != 0) { + SPDK_ERRLOG("spdk_add_nvmf_discovery_subsystem failed\n"); + return rc; + } + + return 0; +} + +static void +spdk_nvmf_tgt_listen_done(void *cb_arg, int status) +{ + /* TODO: Config parsing should wait for this operation to finish. */ + + if (status) { + SPDK_ERRLOG("Failed to listen on transport address\n"); + } +} + +static int +spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) +{ + const char *nqn, *mode; + size_t i; + int ret; + int lcore; + bool allow_any_host; + const char *sn; + struct spdk_nvmf_subsystem *subsystem; + int num_ns; + + nqn = spdk_conf_section_get_val(sp, "NQN"); + if (nqn == NULL) { + SPDK_ERRLOG("Subsystem missing NQN\n"); + return -1; + } + + mode = spdk_conf_section_get_val(sp, "Mode"); + lcore = spdk_conf_section_get_intval(sp, "Core"); + num_ns = spdk_conf_section_get_intval(sp, "MaxNamespaces"); + + if (num_ns < 1) { + num_ns = 0; + } else if (num_ns > SPDK_NVMF_MAX_NAMESPACES) { + num_ns = SPDK_NVMF_MAX_NAMESPACES; + } + + /* Mode is no longer a valid parameter, but print out a nice + * message if it exists to inform users. + */ + if (mode) { + SPDK_NOTICELOG("Mode present in the [Subsystem] section of the config file.\n" + "Mode was removed as a valid parameter.\n"); + if (strcasecmp(mode, "Virtual") == 0) { + SPDK_NOTICELOG("Your mode value is 'Virtual' which is now the only possible mode.\n" + "Your configuration file will work as expected.\n"); + } else { + SPDK_NOTICELOG("Please remove Mode from your configuration file.\n"); + return -1; + } + } + + /* Core is no longer a valid parameter, but print out a nice + * message if it exists to inform users. + */ + if (lcore >= 0) { + SPDK_NOTICELOG("Core present in the [Subsystem] section of the config file.\n" + "Core was removed as an option. Subsystems can now run on all available cores.\n"); + SPDK_NOTICELOG("Please remove Core from your configuration file. Ignoring it and continuing.\n"); + } + + sn = spdk_conf_section_get_val(sp, "SN"); + if (sn == NULL) { + SPDK_ERRLOG("Subsystem %s: missing serial number\n", nqn); + return -1; + } + + subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, num_ns); + if (subsystem == NULL) { + goto done; + } + + if (spdk_nvmf_subsystem_set_sn(subsystem, sn)) { + SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", nqn, sn); + spdk_nvmf_subsystem_destroy(subsystem); + subsystem = NULL; + goto done; + } + + for (i = 0; ; i++) { + struct spdk_nvmf_ns_opts ns_opts; + struct spdk_bdev *bdev; + const char *bdev_name; + const char *uuid_str; + char *nsid_str; + + bdev_name = spdk_conf_section_get_nmval(sp, "Namespace", i, 0); + if (!bdev_name) { + break; + } + + bdev = spdk_bdev_get_by_name(bdev_name); + if (bdev == NULL) { + SPDK_ERRLOG("Could not find namespace bdev '%s'\n", bdev_name); + spdk_nvmf_subsystem_destroy(subsystem); + subsystem = NULL; + goto done; + } + + spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); + + nsid_str = spdk_conf_section_get_nmval(sp, "Namespace", i, 1); + if (nsid_str) { + char *end; + unsigned long nsid_ul = strtoul(nsid_str, &end, 0); + + if (*end != '\0' || nsid_ul == 0 || nsid_ul >= UINT32_MAX) { + SPDK_ERRLOG("Invalid NSID %s\n", nsid_str); + spdk_nvmf_subsystem_destroy(subsystem); + subsystem = NULL; + goto done; + } + + ns_opts.nsid = (uint32_t)nsid_ul; + } + + uuid_str = spdk_conf_section_get_nmval(sp, "Namespace", i, 2); + if (uuid_str) { + if (spdk_uuid_parse(&ns_opts.uuid, uuid_str)) { + SPDK_ERRLOG("Invalid UUID %s\n", uuid_str); + spdk_nvmf_subsystem_destroy(subsystem); + subsystem = NULL; + goto done; + } + } + + if (spdk_nvmf_subsystem_add_ns(subsystem, bdev, &ns_opts, sizeof(ns_opts)) == 0) { + SPDK_ERRLOG("Unable to add namespace\n"); + spdk_nvmf_subsystem_destroy(subsystem); + subsystem = NULL; + goto done; + } + + SPDK_INFOLOG(SPDK_LOG_NVMF, "Attaching block device %s to subsystem %s\n", + spdk_bdev_get_name(bdev), spdk_nvmf_subsystem_get_nqn(subsystem)); + } + + /* Parse Listen sections */ + for (i = 0; ; i++) { + struct spdk_nvme_transport_id trid = {0}; + const char *transport; + const char *address; + char *address_dup; + char *host; + char *port; + + transport = spdk_conf_section_get_nmval(sp, "Listen", i, 0); + if (!transport) { + break; + } + + if (spdk_nvme_transport_id_parse_trtype(&trid.trtype, transport)) { + SPDK_ERRLOG("Invalid listen address transport type '%s'\n", transport); + continue; + } + + address = spdk_conf_section_get_nmval(sp, "Listen", i, 1); + if (!address) { + break; + } + + address_dup = strdup(address); + if (!address_dup) { + break; + } + + ret = spdk_parse_ip_addr(address_dup, &host, &port); + if (ret < 0) { + SPDK_ERRLOG("Unable to parse listen address '%s'\n", address); + free(address_dup); + continue; + } + + if (strchr(host, ':')) { + trid.adrfam = SPDK_NVMF_ADRFAM_IPV6; + } else { + trid.adrfam = SPDK_NVMF_ADRFAM_IPV4; + } + + snprintf(trid.traddr, sizeof(trid.traddr), "%s", host); + if (port) { + snprintf(trid.trsvcid, sizeof(trid.trsvcid), "%s", port); + } + free(address_dup); + + spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &trid, spdk_nvmf_tgt_listen_done, NULL); + + spdk_nvmf_subsystem_add_listener(subsystem, &trid); + } + + /* Parse Host sections */ + for (i = 0; ; i++) { + const char *host = spdk_conf_section_get_nval(sp, "Host", i); + + if (!host) { + break; + } + + spdk_nvmf_subsystem_add_host(subsystem, host); + } + + allow_any_host = spdk_conf_section_get_boolval(sp, "AllowAnyHost", false); + spdk_nvmf_subsystem_set_allow_any_host(subsystem, allow_any_host); + +done: + return (subsystem != NULL); +} + +static int +spdk_nvmf_parse_subsystems(void) +{ + int rc = 0; + struct spdk_conf_section *sp; + + sp = spdk_conf_first_section(NULL); + while (sp != NULL) { + if (spdk_conf_section_match_prefix(sp, "Subsystem")) { + rc = spdk_nvmf_parse_subsystem(sp); + if (rc < 0) { + return -1; + } + } + sp = spdk_conf_next_section(sp); + } + return 0; +} + +struct spdk_nvmf_parse_transport_ctx { + struct spdk_conf_section *sp; + spdk_nvmf_parse_conf_done_fn cb_fn; +}; + +static void spdk_nvmf_parse_transport(struct spdk_nvmf_parse_transport_ctx *ctx); + +static void +spdk_nvmf_tgt_add_transport_done(void *cb_arg, int status) +{ + struct spdk_nvmf_parse_transport_ctx *ctx = cb_arg; + int rc; + + if (status < 0) { + SPDK_ERRLOG("Add transport to target failed (%d).\n", status); + ctx->cb_fn(status); + free(ctx); + return; + } + + /* find next transport */ + ctx->sp = spdk_conf_next_section(ctx->sp); + while (ctx->sp) { + if (spdk_conf_section_match_prefix(ctx->sp, "Transport")) { + spdk_nvmf_parse_transport(ctx); + return; + } + ctx->sp = spdk_conf_next_section(ctx->sp); + } + + /* done with transports, parse Subsystem sections */ + rc = spdk_nvmf_parse_subsystems(); + + ctx->cb_fn(rc); + free(ctx); +} + +static void +spdk_nvmf_parse_transport(struct spdk_nvmf_parse_transport_ctx *ctx) +{ + const char *type; + struct spdk_nvmf_transport_opts opts = { 0 }; + enum spdk_nvme_transport_type trtype; + struct spdk_nvmf_transport *transport; + int val; + + type = spdk_conf_section_get_val(ctx->sp, "Type"); + if (type == NULL) { + SPDK_ERRLOG("Transport missing Type\n"); + ctx->cb_fn(-1); + free(ctx); + return; + } + + if (spdk_nvme_transport_id_parse_trtype(&trtype, type)) { + SPDK_ERRLOG("Invalid transport type '%s'\n", type); + ctx->cb_fn(-1); + free(ctx); + return; + } + + if (spdk_nvmf_tgt_get_transport(g_spdk_nvmf_tgt, trtype)) { + SPDK_ERRLOG("Duplicate transport type '%s'\n", type); + ctx->cb_fn(-1); + free(ctx); + return; + } + + if (!spdk_nvmf_transport_opts_init(trtype, &opts)) { + ctx->cb_fn(-1); + free(ctx); + return; + } + + val = spdk_conf_section_get_intval(ctx->sp, "MaxQueueDepth"); + if (val >= 0) { + opts.max_queue_depth = val; + } + val = spdk_conf_section_get_intval(ctx->sp, "MaxQueuesPerSession"); + if (val >= 0) { + opts.max_qpairs_per_ctrlr = val; + } + val = spdk_conf_section_get_intval(ctx->sp, "InCapsuleDataSize"); + if (val >= 0) { + opts.in_capsule_data_size = val; + } + val = spdk_conf_section_get_intval(ctx->sp, "MaxIOSize"); + if (val >= 0) { + opts.max_io_size = val; + } + val = spdk_conf_section_get_intval(ctx->sp, "IOUnitSize"); + if (val >= 0) { + opts.io_unit_size = val; + } + val = spdk_conf_section_get_intval(ctx->sp, "MaxAQDepth"); + if (val >= 0) { + opts.max_aq_depth = val; + } + + transport = spdk_nvmf_transport_create(trtype, &opts); + if (transport) { + spdk_nvmf_tgt_add_transport(g_spdk_nvmf_tgt, transport, spdk_nvmf_tgt_add_transport_done, ctx); + } else { + ctx->cb_fn(-1); + free(ctx); + return; + } +} + +static int +spdk_nvmf_parse_transports(spdk_nvmf_parse_conf_done_fn cb_fn) +{ + struct spdk_nvmf_parse_transport_ctx *ctx; + + ctx = calloc(1, sizeof(struct spdk_nvmf_parse_transport_ctx)); + if (!ctx) { + SPDK_ERRLOG("Failed alloc of context memory for parse transports\n"); + return -ENOMEM; + } + + ctx->cb_fn = cb_fn; + ctx->sp = spdk_conf_first_section(NULL); + while (ctx->sp != NULL) { + if (spdk_conf_section_match_prefix(ctx->sp, "Transport")) { + spdk_nvmf_parse_transport(ctx); + return 0; + } + ctx->sp = spdk_conf_next_section(ctx->sp); + } + + /* if we get here, there are no transports defined in conf file */ + free(ctx); + cb_fn(spdk_nvmf_parse_subsystems()); + + return 0; +} + +int +spdk_nvmf_parse_conf(spdk_nvmf_parse_conf_done_fn cb_fn) +{ + int rc; + + if (cb_fn == NULL) { + SPDK_ERRLOG("Callback function is NULL\n"); + return -1; + } + + /* NVMf section */ + rc = spdk_nvmf_parse_nvmf_tgt(); + if (rc < 0) { + return rc; + } + + /* Transport sections */ + rc = spdk_nvmf_parse_transports(cb_fn); + if (rc < 0) { + return rc; + } + + return 0; +} diff --git a/src/spdk/lib/event/subsystems/nvmf/event_nvmf.h b/src/spdk/lib/event/subsystems/nvmf/event_nvmf.h new file mode 100644 index 00000000..50e5d755 --- /dev/null +++ b/src/spdk/lib/event/subsystems/nvmf/event_nvmf.h @@ -0,0 +1,67 @@ +/*- + * 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. + */ + +#ifndef NVMF_TGT_H +#define NVMF_TGT_H + +#include "spdk/stdinc.h" + +#include "spdk/nvmf.h" +#include "spdk/queue.h" + +#include "spdk_internal/event.h" +#include "spdk_internal/log.h" + +#define ACCEPT_TIMEOUT_US 10000 /* 10ms */ +#define DEFAULT_CONN_SCHED CONNECT_SCHED_ROUND_ROBIN + +enum spdk_nvmf_connect_sched { + CONNECT_SCHED_ROUND_ROBIN = 0, + CONNECT_SCHED_HOST_IP, +}; + +struct spdk_nvmf_tgt_conf { + uint32_t acceptor_poll_rate; + enum spdk_nvmf_connect_sched conn_sched; +}; + +extern struct spdk_nvmf_tgt_opts *g_spdk_nvmf_tgt_opts; +extern struct spdk_nvmf_tgt_conf *g_spdk_nvmf_tgt_conf; + +extern struct spdk_nvmf_tgt *g_spdk_nvmf_tgt; + +typedef void (*spdk_nvmf_parse_conf_done_fn)(int status); + +int spdk_nvmf_parse_conf(spdk_nvmf_parse_conf_done_fn cb_fn); + +#endif diff --git a/src/spdk/lib/event/subsystems/nvmf/nvmf_rpc.c b/src/spdk/lib/event/subsystems/nvmf/nvmf_rpc.c new file mode 100644 index 00000000..e4114afe --- /dev/null +++ b/src/spdk/lib/event/subsystems/nvmf/nvmf_rpc.c @@ -0,0 +1,1562 @@ +/*- + * 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 "event_nvmf.h" + +#include "spdk/bdev.h" +#include "spdk/log.h" +#include "spdk/rpc.h" +#include "spdk/env.h" +#include "spdk/nvme.h" +#include "spdk/nvmf.h" +#include "spdk/string.h" +#include "spdk/util.h" + +static int +json_write_hex_str(struct spdk_json_write_ctx *w, const void *data, size_t size) +{ + static const char hex_char[16] = "0123456789ABCDEF"; + const uint8_t *buf = data; + char *str, *out; + int rc; + + str = malloc(size * 2 + 1); + if (str == NULL) { + return -1; + } + + out = str; + while (size--) { + unsigned byte = *buf++; + + out[0] = hex_char[(byte >> 4) & 0xF]; + out[1] = hex_char[byte & 0xF]; + + out += 2; + } + *out = '\0'; + + rc = spdk_json_write_string(w, str); + free(str); + + return rc; +} + +static int +hex_nybble_to_num(char c) +{ + if (c >= '0' && c <= '9') { + return c - '0'; + } + + if (c >= 'a' && c <= 'f') { + return c - 'a' + 0xA; + } + + if (c >= 'A' && c <= 'F') { + return c - 'A' + 0xA; + } + + return -1; +} + +static int +hex_byte_to_num(const char *str) +{ + int hi, lo; + + hi = hex_nybble_to_num(str[0]); + if (hi < 0) { + return hi; + } + + lo = hex_nybble_to_num(str[1]); + if (lo < 0) { + return lo; + } + + return hi * 16 + lo; +} + +static int +decode_hex_string_be(const char *str, uint8_t *out, size_t size) +{ + size_t i; + + /* Decode a string in "ABCDEF012345" format to its binary representation */ + for (i = 0; i < size; i++) { + int num = hex_byte_to_num(str); + + if (num < 0) { + /* Invalid hex byte or end of string */ + return -1; + } + + out[i] = (uint8_t)num; + str += 2; + } + + if (i != size || *str != '\0') { + /* Length mismatch */ + return -1; + } + + return 0; +} + +static int +decode_ns_nguid(const struct spdk_json_val *val, void *out) +{ + char *str = NULL; + int rc; + + rc = spdk_json_decode_string(val, &str); + if (rc == 0) { + /* 16-byte NGUID */ + rc = decode_hex_string_be(str, out, 16); + } + + free(str); + return rc; +} + +static int +decode_ns_eui64(const struct spdk_json_val *val, void *out) +{ + char *str = NULL; + int rc; + + rc = spdk_json_decode_string(val, &str); + if (rc == 0) { + /* 8-byte EUI-64 */ + rc = decode_hex_string_be(str, out, 8); + } + + free(str); + return rc; +} + +static int +decode_ns_uuid(const struct spdk_json_val *val, void *out) +{ + char *str = NULL; + int rc; + + rc = spdk_json_decode_string(val, &str); + if (rc == 0) { + rc = spdk_uuid_parse(out, str); + } + + free(str); + return rc; +} + +static void +dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct spdk_nvmf_subsystem *subsystem) +{ + struct spdk_nvmf_host *host; + struct spdk_nvmf_listener *listener; + + spdk_json_write_object_begin(w); + + spdk_json_write_name(w, "nqn"); + spdk_json_write_string(w, spdk_nvmf_subsystem_get_nqn(subsystem)); + spdk_json_write_name(w, "subtype"); + if (spdk_nvmf_subsystem_get_type(subsystem) == SPDK_NVMF_SUBTYPE_NVME) { + spdk_json_write_string(w, "NVMe"); + } else { + spdk_json_write_string(w, "Discovery"); + } + + spdk_json_write_name(w, "listen_addresses"); + spdk_json_write_array_begin(w); + + for (listener = spdk_nvmf_subsystem_get_first_listener(subsystem); listener != NULL; + listener = spdk_nvmf_subsystem_get_next_listener(subsystem, listener)) { + const struct spdk_nvme_transport_id *trid; + const char *trtype; + const char *adrfam; + + trid = spdk_nvmf_listener_get_trid(listener); + + spdk_json_write_object_begin(w); + trtype = spdk_nvme_transport_id_trtype_str(trid->trtype); + if (trtype == NULL) { + trtype = "unknown"; + } + adrfam = spdk_nvme_transport_id_adrfam_str(trid->adrfam); + if (adrfam == NULL) { + adrfam = "unknown"; + } + /* NOTE: "transport" is kept for compatibility; new code should use "trtype" */ + spdk_json_write_name(w, "transport"); + spdk_json_write_string(w, trtype); + spdk_json_write_name(w, "trtype"); + spdk_json_write_string(w, trtype); + spdk_json_write_name(w, "adrfam"); + spdk_json_write_string(w, adrfam); + spdk_json_write_name(w, "traddr"); + spdk_json_write_string(w, trid->traddr); + spdk_json_write_name(w, "trsvcid"); + spdk_json_write_string(w, trid->trsvcid); + spdk_json_write_object_end(w); + } + spdk_json_write_array_end(w); + + spdk_json_write_name(w, "allow_any_host"); + spdk_json_write_bool(w, spdk_nvmf_subsystem_get_allow_any_host(subsystem)); + + spdk_json_write_name(w, "hosts"); + spdk_json_write_array_begin(w); + + for (host = spdk_nvmf_subsystem_get_first_host(subsystem); host != NULL; + host = spdk_nvmf_subsystem_get_next_host(subsystem, host)) { + spdk_json_write_object_begin(w); + spdk_json_write_name(w, "nqn"); + spdk_json_write_string(w, spdk_nvmf_host_get_nqn(host)); + spdk_json_write_object_end(w); + } + spdk_json_write_array_end(w); + + if (spdk_nvmf_subsystem_get_type(subsystem) == SPDK_NVMF_SUBTYPE_NVME) { + struct spdk_nvmf_ns *ns; + struct spdk_nvmf_ns_opts ns_opts; + uint32_t max_namespaces; + + spdk_json_write_name(w, "serial_number"); + spdk_json_write_string(w, spdk_nvmf_subsystem_get_sn(subsystem)); + + max_namespaces = spdk_nvmf_subsystem_get_max_namespaces(subsystem); + if (max_namespaces != 0) { + spdk_json_write_named_uint32(w, "max_namespaces", max_namespaces); + } + + spdk_json_write_name(w, "namespaces"); + spdk_json_write_array_begin(w); + for (ns = spdk_nvmf_subsystem_get_first_ns(subsystem); ns != NULL; + ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns)) { + spdk_nvmf_ns_get_opts(ns, &ns_opts, sizeof(ns_opts)); + spdk_json_write_object_begin(w); + spdk_json_write_name(w, "nsid"); + spdk_json_write_int32(w, spdk_nvmf_ns_get_id(ns)); + spdk_json_write_name(w, "bdev_name"); + spdk_json_write_string(w, spdk_bdev_get_name(spdk_nvmf_ns_get_bdev(ns))); + /* NOTE: "name" is kept for compatibility only - new code should use bdev_name. */ + spdk_json_write_name(w, "name"); + spdk_json_write_string(w, spdk_bdev_get_name(spdk_nvmf_ns_get_bdev(ns))); + + if (!spdk_mem_all_zero(ns_opts.nguid, sizeof(ns_opts.nguid))) { + spdk_json_write_name(w, "nguid"); + json_write_hex_str(w, ns_opts.nguid, sizeof(ns_opts.nguid)); + } + + if (!spdk_mem_all_zero(ns_opts.eui64, sizeof(ns_opts.eui64))) { + spdk_json_write_name(w, "eui64"); + json_write_hex_str(w, ns_opts.eui64, sizeof(ns_opts.eui64)); + } + + if (!spdk_mem_all_zero(&ns_opts.uuid, sizeof(ns_opts.uuid))) { + char uuid_str[SPDK_UUID_STRING_LEN]; + + spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &ns_opts.uuid); + spdk_json_write_name(w, "uuid"); + spdk_json_write_string(w, uuid_str); + } + + spdk_json_write_object_end(w); + } + spdk_json_write_array_end(w); + } + spdk_json_write_object_end(w); +} + +static void +spdk_rpc_get_nvmf_subsystems(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct spdk_json_write_ctx *w; + struct spdk_nvmf_subsystem *subsystem; + + if (params != NULL) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "get_nvmf_subsystems requires no parameters"); + return; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_array_begin(w); + subsystem = spdk_nvmf_subsystem_get_first(g_spdk_nvmf_tgt); + while (subsystem) { + dump_nvmf_subsystem(w, subsystem); + subsystem = spdk_nvmf_subsystem_get_next(subsystem); + } + spdk_json_write_array_end(w); + spdk_jsonrpc_end_result(request, w); +} +SPDK_RPC_REGISTER("get_nvmf_subsystems", spdk_rpc_get_nvmf_subsystems, SPDK_RPC_RUNTIME) + +struct rpc_subsystem_create { + char *nqn; + char *serial_number; + uint32_t max_namespaces; + bool allow_any_host; +}; + +static const struct spdk_json_object_decoder rpc_subsystem_create_decoders[] = { + {"nqn", offsetof(struct rpc_subsystem_create, nqn), spdk_json_decode_string}, + {"serial_number", offsetof(struct rpc_subsystem_create, serial_number), spdk_json_decode_string, true}, + {"max_namespaces", offsetof(struct rpc_subsystem_create, max_namespaces), spdk_json_decode_uint32, true}, + {"allow_any_host", offsetof(struct rpc_subsystem_create, allow_any_host), spdk_json_decode_bool, true}, +}; + +static void +spdk_rpc_nvmf_subsystem_started(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct spdk_jsonrpc_request *request = cb_arg; + struct spdk_json_write_ctx *w; + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} + +static void +spdk_rpc_nvmf_subsystem_create(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_subsystem_create *req; + struct spdk_nvmf_subsystem *subsystem; + + req = calloc(1, sizeof(*req)); + if (!req) { + goto invalid; + } + + if (spdk_json_decode_object(params, rpc_subsystem_create_decoders, + SPDK_COUNTOF(rpc_subsystem_create_decoders), + req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + goto invalid; + } + + subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, req->nqn, SPDK_NVMF_SUBTYPE_NVME, + req->max_namespaces); + if (!subsystem) { + goto invalid; + } + + if (req->serial_number) { + if (spdk_nvmf_subsystem_set_sn(subsystem, req->serial_number)) { + SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", req->nqn, req->serial_number); + goto invalid; + } + } + + spdk_nvmf_subsystem_set_allow_any_host(subsystem, req->allow_any_host); + + free(req->nqn); + free(req->serial_number); + free(req); + + spdk_nvmf_subsystem_start(subsystem, + spdk_rpc_nvmf_subsystem_started, + request); + + return; + +invalid: + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + if (req) { + free(req->nqn); + free(req->serial_number); + } + free(req); +} +SPDK_RPC_REGISTER("nvmf_subsystem_create", spdk_rpc_nvmf_subsystem_create, SPDK_RPC_RUNTIME) + +struct rpc_delete_subsystem { + char *nqn; +}; + +static void +free_rpc_delete_subsystem(struct rpc_delete_subsystem *r) +{ + free(r->nqn); +} + +static void +spdk_rpc_nvmf_subsystem_stopped(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct spdk_jsonrpc_request *request = cb_arg; + struct spdk_json_write_ctx *w; + + spdk_nvmf_subsystem_destroy(subsystem); + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} + +static const struct spdk_json_object_decoder rpc_delete_subsystem_decoders[] = { + {"nqn", offsetof(struct rpc_delete_subsystem, nqn), spdk_json_decode_string}, +}; + +static void +spdk_rpc_delete_nvmf_subsystem(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_delete_subsystem req = {}; + struct spdk_nvmf_subsystem *subsystem; + + if (spdk_json_decode_object(params, rpc_delete_subsystem_decoders, + SPDK_COUNTOF(rpc_delete_subsystem_decoders), + &req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + goto invalid; + } + + if (req.nqn == NULL) { + SPDK_ERRLOG("missing name param\n"); + goto invalid; + } + + subsystem = spdk_nvmf_tgt_find_subsystem(g_spdk_nvmf_tgt, req.nqn); + if (!subsystem) { + goto invalid; + } + + free_rpc_delete_subsystem(&req); + + spdk_nvmf_subsystem_stop(subsystem, + spdk_rpc_nvmf_subsystem_stopped, + request); + + return; + +invalid: + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + free_rpc_delete_subsystem(&req); +} +SPDK_RPC_REGISTER("delete_nvmf_subsystem", spdk_rpc_delete_nvmf_subsystem, SPDK_RPC_RUNTIME) + +struct rpc_listen_address { + char *transport; + char *adrfam; + char *traddr; + char *trsvcid; +}; + +#define RPC_MAX_LISTEN_ADDRESSES 255 +#define RPC_MAX_NAMESPACES 255 + +struct rpc_listen_addresses { + size_t num_listen_address; + struct rpc_listen_address addresses[RPC_MAX_LISTEN_ADDRESSES]; +}; + +static const struct spdk_json_object_decoder rpc_listen_address_decoders[] = { + /* NOTE: "transport" is kept for compatibility; new code should use "trtype" */ + {"transport", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true}, + {"trtype", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true}, + {"adrfam", offsetof(struct rpc_listen_address, adrfam), spdk_json_decode_string, true}, + {"traddr", offsetof(struct rpc_listen_address, traddr), spdk_json_decode_string}, + {"trsvcid", offsetof(struct rpc_listen_address, trsvcid), spdk_json_decode_string}, +}; + +static int +decode_rpc_listen_address(const struct spdk_json_val *val, void *out) +{ + struct rpc_listen_address *req = (struct rpc_listen_address *)out; + if (spdk_json_decode_object(val, rpc_listen_address_decoders, + SPDK_COUNTOF(rpc_listen_address_decoders), + req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + return -1; + } + return 0; +} + +static void +free_rpc_listen_address(struct rpc_listen_address *r) +{ + free(r->transport); + free(r->adrfam); + free(r->traddr); + free(r->trsvcid); +} + +enum nvmf_rpc_listen_op { + NVMF_RPC_LISTEN_ADD, + NVMF_RPC_LISTEN_REMOVE, +}; + +struct nvmf_rpc_listener_ctx { + char *nqn; + struct spdk_nvmf_subsystem *subsystem; + struct rpc_listen_address address; + + struct spdk_jsonrpc_request *request; + struct spdk_nvme_transport_id trid; + enum nvmf_rpc_listen_op op; + bool response_sent; +}; + +static const struct spdk_json_object_decoder nvmf_rpc_listener_decoder[] = { + {"nqn", offsetof(struct nvmf_rpc_listener_ctx, nqn), spdk_json_decode_string}, + {"listen_address", offsetof(struct nvmf_rpc_listener_ctx, address), decode_rpc_listen_address}, +}; + +static void +nvmf_rpc_listener_ctx_free(struct nvmf_rpc_listener_ctx *ctx) +{ + free(ctx->nqn); + free_rpc_listen_address(&ctx->address); + free(ctx); +} + +static void +nvmf_rpc_listen_resumed(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct nvmf_rpc_listener_ctx *ctx = cb_arg; + struct spdk_jsonrpc_request *request; + struct spdk_json_write_ctx *w; + + request = ctx->request; + if (ctx->response_sent) { + /* If an error occurred, the response has already been sent. */ + nvmf_rpc_listener_ctx_free(ctx); + return; + } + + nvmf_rpc_listener_ctx_free(ctx); + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} + +static void +nvmf_rpc_tgt_listen(void *cb_arg, int status) +{ + struct nvmf_rpc_listener_ctx *ctx = cb_arg; + + if (status) { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + ctx->response_sent = true; + } else { + if (spdk_nvmf_subsystem_add_listener(ctx->subsystem, &ctx->trid)) { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + ctx->response_sent = true; + } + } + + if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) { + if (!ctx->response_sent) { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + } + nvmf_rpc_listener_ctx_free(ctx); + /* Can't really do anything to recover here - subsystem will remain paused. */ + } +} + +static void +nvmf_rpc_listen_paused(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct nvmf_rpc_listener_ctx *ctx = cb_arg; + + if (ctx->op == NVMF_RPC_LISTEN_ADD) { + spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &ctx->trid, nvmf_rpc_tgt_listen, ctx); + return; + } else if (ctx->op == NVMF_RPC_LISTEN_REMOVE) { + if (spdk_nvmf_subsystem_remove_listener(subsystem, &ctx->trid)) { + SPDK_ERRLOG("Unable to remove listener.\n"); + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + ctx->response_sent = true; + } + } else { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + ctx->response_sent = true; + } + + if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_listen_resumed, ctx)) { + if (!ctx->response_sent) { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + } + nvmf_rpc_listener_ctx_free(ctx); + /* Can't really do anything to recover here - subsystem will remain paused. */ + } +} + +static int +rpc_listen_address_to_trid(const struct rpc_listen_address *address, + struct spdk_nvme_transport_id *trid) +{ + size_t len; + + memset(trid, 0, sizeof(*trid)); + + if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, address->transport)) { + SPDK_ERRLOG("Invalid transport type: %s\n", address->transport); + return -EINVAL; + } + + if (address->adrfam) { + if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, address->adrfam)) { + SPDK_ERRLOG("Invalid adrfam: %s\n", address->adrfam); + return -EINVAL; + } + } else { + trid->adrfam = SPDK_NVMF_ADRFAM_IPV4; + } + + len = strlen(address->traddr); + if (len > sizeof(trid->traddr) - 1) { + SPDK_ERRLOG("Transport address longer than %zu characters: %s\n", + sizeof(trid->traddr) - 1, address->traddr); + return -EINVAL; + } + memcpy(trid->traddr, address->traddr, len + 1); + + len = strlen(address->trsvcid); + if (len > sizeof(trid->trsvcid) - 1) { + SPDK_ERRLOG("Transport service id longer than %zu characters: %s\n", + sizeof(trid->trsvcid) - 1, address->trsvcid); + return -EINVAL; + } + memcpy(trid->trsvcid, address->trsvcid, len + 1); + + return 0; +} + +static void +nvmf_rpc_subsystem_add_listener(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct nvmf_rpc_listener_ctx *ctx; + struct spdk_nvmf_subsystem *subsystem; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); + return; + } + + ctx->request = request; + + if (spdk_json_decode_object(params, nvmf_rpc_listener_decoder, + SPDK_COUNTOF(nvmf_rpc_listener_decoder), + ctx)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_listener_ctx_free(ctx); + return; + } + + subsystem = spdk_nvmf_tgt_find_subsystem(g_spdk_nvmf_tgt, ctx->nqn); + if (!subsystem) { + SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_listener_ctx_free(ctx); + return; + } + + ctx->subsystem = subsystem; + + if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + nvmf_rpc_listener_ctx_free(ctx); + return; + } + + ctx->op = NVMF_RPC_LISTEN_ADD; + + if (spdk_nvmf_subsystem_pause(subsystem, nvmf_rpc_listen_paused, ctx)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + nvmf_rpc_listener_ctx_free(ctx); + return; + } +} +SPDK_RPC_REGISTER("nvmf_subsystem_add_listener", nvmf_rpc_subsystem_add_listener, SPDK_RPC_RUNTIME); + +static void +nvmf_rpc_subsystem_remove_listener(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct nvmf_rpc_listener_ctx *ctx; + struct spdk_nvmf_subsystem *subsystem; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); + return; + } + + ctx->request = request; + + if (spdk_json_decode_object(params, nvmf_rpc_listener_decoder, + SPDK_COUNTOF(nvmf_rpc_listener_decoder), + ctx)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_listener_ctx_free(ctx); + return; + } + + subsystem = spdk_nvmf_tgt_find_subsystem(g_spdk_nvmf_tgt, ctx->nqn); + if (!subsystem) { + SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_listener_ctx_free(ctx); + return; + } + + ctx->subsystem = subsystem; + + if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + nvmf_rpc_listener_ctx_free(ctx); + return; + } + + ctx->op = NVMF_RPC_LISTEN_REMOVE; + + if (spdk_nvmf_subsystem_pause(subsystem, nvmf_rpc_listen_paused, ctx)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + nvmf_rpc_listener_ctx_free(ctx); + return; + } + +} +SPDK_RPC_REGISTER("nvmf_subsystem_remove_listener", nvmf_rpc_subsystem_remove_listener, + SPDK_RPC_RUNTIME); + +struct spdk_nvmf_ns_params { + char *bdev_name; + uint32_t nsid; + char nguid[16]; + char eui64[8]; + struct spdk_uuid uuid; +}; + +struct rpc_namespaces { + size_t num_ns; + struct spdk_nvmf_ns_params ns_params[RPC_MAX_NAMESPACES]; +}; + + +static const struct spdk_json_object_decoder rpc_ns_params_decoders[] = { + {"nsid", offsetof(struct spdk_nvmf_ns_params, nsid), spdk_json_decode_uint32, true}, + {"bdev_name", offsetof(struct spdk_nvmf_ns_params, bdev_name), spdk_json_decode_string}, + {"nguid", offsetof(struct spdk_nvmf_ns_params, nguid), decode_ns_nguid, true}, + {"eui64", offsetof(struct spdk_nvmf_ns_params, eui64), decode_ns_eui64, true}, + {"uuid", offsetof(struct spdk_nvmf_ns_params, uuid), decode_ns_uuid, true}, +}; + +static int +decode_rpc_ns_params(const struct spdk_json_val *val, void *out) +{ + struct spdk_nvmf_ns_params *ns_params = out; + + return spdk_json_decode_object(val, rpc_ns_params_decoders, + SPDK_COUNTOF(rpc_ns_params_decoders), + ns_params); +} + +struct nvmf_rpc_ns_ctx { + char *nqn; + struct spdk_nvmf_ns_params ns_params; + + struct spdk_jsonrpc_request *request; + bool response_sent; +}; + +static const struct spdk_json_object_decoder nvmf_rpc_subsystem_ns_decoder[] = { + {"nqn", offsetof(struct nvmf_rpc_ns_ctx, nqn), spdk_json_decode_string}, + {"namespace", offsetof(struct nvmf_rpc_ns_ctx, ns_params), decode_rpc_ns_params}, +}; + +static void +nvmf_rpc_ns_ctx_free(struct nvmf_rpc_ns_ctx *ctx) +{ + free(ctx->nqn); + free(ctx->ns_params.bdev_name); + free(ctx); +} + +static void +nvmf_rpc_ns_resumed(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct nvmf_rpc_ns_ctx *ctx = cb_arg; + struct spdk_jsonrpc_request *request = ctx->request; + uint32_t nsid = ctx->ns_params.nsid; + bool response_sent = ctx->response_sent; + struct spdk_json_write_ctx *w; + + nvmf_rpc_ns_ctx_free(ctx); + + if (response_sent) { + return; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_uint32(w, nsid); + spdk_jsonrpc_end_result(request, w); +} + +static void +nvmf_rpc_ns_paused(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct nvmf_rpc_ns_ctx *ctx = cb_arg; + struct spdk_nvmf_ns_opts ns_opts; + struct spdk_bdev *bdev; + + bdev = spdk_bdev_get_by_name(ctx->ns_params.bdev_name); + if (!bdev) { + SPDK_ERRLOG("No bdev with name %s\n", ctx->ns_params.bdev_name); + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + ctx->response_sent = true; + goto resume; + } + + spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); + ns_opts.nsid = ctx->ns_params.nsid; + + SPDK_STATIC_ASSERT(sizeof(ns_opts.nguid) == sizeof(ctx->ns_params.nguid), "size mismatch"); + memcpy(ns_opts.nguid, ctx->ns_params.nguid, sizeof(ns_opts.nguid)); + + SPDK_STATIC_ASSERT(sizeof(ns_opts.eui64) == sizeof(ctx->ns_params.eui64), "size mismatch"); + memcpy(ns_opts.eui64, ctx->ns_params.eui64, sizeof(ns_opts.eui64)); + + if (!spdk_mem_all_zero(&ctx->ns_params.uuid, sizeof(ctx->ns_params.uuid))) { + ns_opts.uuid = ctx->ns_params.uuid; + } + + ctx->ns_params.nsid = spdk_nvmf_subsystem_add_ns(subsystem, bdev, &ns_opts, sizeof(ns_opts)); + if (ctx->ns_params.nsid == 0) { + SPDK_ERRLOG("Unable to add namespace\n"); + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + ctx->response_sent = true; + goto resume; + } + +resume: + if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_ns_resumed, ctx)) { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + nvmf_rpc_ns_ctx_free(ctx); + return; + } +} + +static void +nvmf_rpc_subsystem_add_ns(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct nvmf_rpc_ns_ctx *ctx; + struct spdk_nvmf_subsystem *subsystem; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); + return; + } + + if (spdk_json_decode_object(params, nvmf_rpc_subsystem_ns_decoder, + SPDK_COUNTOF(nvmf_rpc_subsystem_ns_decoder), + ctx)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_ns_ctx_free(ctx); + return; + } + + ctx->request = request; + ctx->response_sent = false; + + subsystem = spdk_nvmf_tgt_find_subsystem(g_spdk_nvmf_tgt, ctx->nqn); + if (!subsystem) { + SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_ns_ctx_free(ctx); + return; + } + + if (spdk_nvmf_subsystem_pause(subsystem, nvmf_rpc_ns_paused, ctx)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + nvmf_rpc_ns_ctx_free(ctx); + return; + } +} +SPDK_RPC_REGISTER("nvmf_subsystem_add_ns", nvmf_rpc_subsystem_add_ns, SPDK_RPC_RUNTIME) + +struct nvmf_rpc_remove_ns_ctx { + char *nqn; + uint32_t nsid; + + struct spdk_jsonrpc_request *request; + bool response_sent; +}; + +static const struct spdk_json_object_decoder nvmf_rpc_subsystem_remove_ns_decoder[] = { + {"nqn", offsetof(struct nvmf_rpc_remove_ns_ctx, nqn), spdk_json_decode_string}, + {"nsid", offsetof(struct nvmf_rpc_remove_ns_ctx, nsid), spdk_json_decode_uint32}, +}; + +static void +nvmf_rpc_remove_ns_ctx_free(struct nvmf_rpc_remove_ns_ctx *ctx) +{ + free(ctx->nqn); + free(ctx); +} + +static void +nvmf_rpc_remove_ns_resumed(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct nvmf_rpc_remove_ns_ctx *ctx = cb_arg; + struct spdk_jsonrpc_request *request = ctx->request; + bool response_sent = ctx->response_sent; + struct spdk_json_write_ctx *w; + + nvmf_rpc_remove_ns_ctx_free(ctx); + + if (response_sent) { + return; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} + +static void +nvmf_rpc_remove_ns_remove_done(struct spdk_nvmf_subsystem *subsystem, void *cb_arg, int status) +{ + struct nvmf_rpc_remove_ns_ctx *ctx; + + ctx = cb_arg; + + if (status != 0) { + SPDK_ERRLOG("Unable to remove namespace ID %u\n", ctx->nsid); + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + ctx->response_sent = true; + } + + if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_remove_ns_resumed, ctx)) { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + nvmf_rpc_remove_ns_ctx_free(ctx); + return; + } +} + +static void +nvmf_rpc_remove_ns_paused(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct nvmf_rpc_remove_ns_ctx *ctx = cb_arg; + int ret; + + ret = spdk_nvmf_subsystem_remove_ns(subsystem, ctx->nsid, nvmf_rpc_remove_ns_remove_done, ctx); + if (ret < 0) { + SPDK_ERRLOG("Unable to remove namespace ID %u\n", ctx->nsid); + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + ctx->response_sent = true; + spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_remove_ns_resumed, ctx); + } +} + +static void +nvmf_rpc_subsystem_remove_ns(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct nvmf_rpc_remove_ns_ctx *ctx; + struct spdk_nvmf_subsystem *subsystem; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); + return; + } + + if (spdk_json_decode_object(params, nvmf_rpc_subsystem_remove_ns_decoder, + SPDK_COUNTOF(nvmf_rpc_subsystem_remove_ns_decoder), + ctx)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_remove_ns_ctx_free(ctx); + return; + } + + ctx->request = request; + ctx->response_sent = false; + + subsystem = spdk_nvmf_tgt_find_subsystem(g_spdk_nvmf_tgt, ctx->nqn); + if (!subsystem) { + SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_remove_ns_ctx_free(ctx); + return; + } + + if (spdk_nvmf_subsystem_pause(subsystem, nvmf_rpc_remove_ns_paused, ctx)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + nvmf_rpc_remove_ns_ctx_free(ctx); + return; + } +} +SPDK_RPC_REGISTER("nvmf_subsystem_remove_ns", nvmf_rpc_subsystem_remove_ns, SPDK_RPC_RUNTIME) + +enum nvmf_rpc_host_op { + NVMF_RPC_HOST_ADD, + NVMF_RPC_HOST_REMOVE, + NVMF_RPC_HOST_ALLOW_ANY, +}; + +struct nvmf_rpc_host_ctx { + struct spdk_jsonrpc_request *request; + + char *nqn; + char *host; + + enum nvmf_rpc_host_op op; + + bool allow_any_host; + + bool response_sent; +}; + +static const struct spdk_json_object_decoder nvmf_rpc_subsystem_host_decoder[] = { + {"nqn", offsetof(struct nvmf_rpc_host_ctx, nqn), spdk_json_decode_string}, + {"host", offsetof(struct nvmf_rpc_host_ctx, host), spdk_json_decode_string}, +}; + +static void +nvmf_rpc_host_ctx_free(struct nvmf_rpc_host_ctx *ctx) +{ + free(ctx->nqn); + free(ctx->host); + free(ctx); +} + +static void +nvmf_rpc_host_resumed(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct nvmf_rpc_host_ctx *ctx = cb_arg; + struct spdk_jsonrpc_request *request; + struct spdk_json_write_ctx *w; + bool response_sent = ctx->response_sent; + + request = ctx->request; + nvmf_rpc_host_ctx_free(ctx); + + if (response_sent) { + return; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} + +static void +nvmf_rpc_host_paused(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct nvmf_rpc_host_ctx *ctx = cb_arg; + int rc = -1; + + switch (ctx->op) { + case NVMF_RPC_HOST_ADD: + rc = spdk_nvmf_subsystem_add_host(subsystem, ctx->host); + break; + case NVMF_RPC_HOST_REMOVE: + rc = spdk_nvmf_subsystem_remove_host(subsystem, ctx->host); + break; + case NVMF_RPC_HOST_ALLOW_ANY: + rc = spdk_nvmf_subsystem_set_allow_any_host(subsystem, ctx->allow_any_host); + break; + } + + if (rc != 0) { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + ctx->response_sent = true; + } + + if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_host_resumed, ctx)) { + if (!ctx->response_sent) { + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + } + nvmf_rpc_host_ctx_free(ctx); + return; + } +} + +static void +nvmf_rpc_subsystem_add_host(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct nvmf_rpc_host_ctx *ctx; + struct spdk_nvmf_subsystem *subsystem; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); + return; + } + + if (spdk_json_decode_object(params, nvmf_rpc_subsystem_host_decoder, + SPDK_COUNTOF(nvmf_rpc_subsystem_host_decoder), + ctx)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_host_ctx_free(ctx); + return; + } + + ctx->request = request; + ctx->op = NVMF_RPC_HOST_ADD; + ctx->response_sent = false; + + subsystem = spdk_nvmf_tgt_find_subsystem(g_spdk_nvmf_tgt, ctx->nqn); + if (!subsystem) { + SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_host_ctx_free(ctx); + return; + } + + if (spdk_nvmf_subsystem_pause(subsystem, nvmf_rpc_host_paused, ctx)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + nvmf_rpc_host_ctx_free(ctx); + return; + } +} +SPDK_RPC_REGISTER("nvmf_subsystem_add_host", nvmf_rpc_subsystem_add_host, SPDK_RPC_RUNTIME) + +static void +nvmf_rpc_subsystem_remove_host(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct nvmf_rpc_host_ctx *ctx; + struct spdk_nvmf_subsystem *subsystem; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); + return; + } + + if (spdk_json_decode_object(params, nvmf_rpc_subsystem_host_decoder, + SPDK_COUNTOF(nvmf_rpc_subsystem_host_decoder), + ctx)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_host_ctx_free(ctx); + return; + } + + ctx->request = request; + ctx->op = NVMF_RPC_HOST_REMOVE; + ctx->response_sent = false; + + subsystem = spdk_nvmf_tgt_find_subsystem(g_spdk_nvmf_tgt, ctx->nqn); + if (!subsystem) { + SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_host_ctx_free(ctx); + return; + } + + if (spdk_nvmf_subsystem_pause(subsystem, nvmf_rpc_host_paused, ctx)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + nvmf_rpc_host_ctx_free(ctx); + return; + } +} +SPDK_RPC_REGISTER("nvmf_subsystem_remove_host", nvmf_rpc_subsystem_remove_host, SPDK_RPC_RUNTIME) + + +static const struct spdk_json_object_decoder nvmf_rpc_subsystem_any_host_decoder[] = { + {"nqn", offsetof(struct nvmf_rpc_host_ctx, nqn), spdk_json_decode_string}, + {"allow_any_host", offsetof(struct nvmf_rpc_host_ctx, allow_any_host), spdk_json_decode_bool}, +}; + +static void +nvmf_rpc_subsystem_allow_any_host(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct nvmf_rpc_host_ctx *ctx; + struct spdk_nvmf_subsystem *subsystem; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); + return; + } + + if (spdk_json_decode_object(params, nvmf_rpc_subsystem_any_host_decoder, + SPDK_COUNTOF(nvmf_rpc_subsystem_any_host_decoder), + ctx)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_host_ctx_free(ctx); + return; + } + + ctx->request = request; + ctx->op = NVMF_RPC_HOST_ALLOW_ANY; + ctx->response_sent = false; + + subsystem = spdk_nvmf_tgt_find_subsystem(g_spdk_nvmf_tgt, ctx->nqn); + if (!subsystem) { + SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_host_ctx_free(ctx); + return; + } + + if (spdk_nvmf_subsystem_pause(subsystem, nvmf_rpc_host_paused, ctx)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); + nvmf_rpc_host_ctx_free(ctx); + return; + } +} +SPDK_RPC_REGISTER("nvmf_subsystem_allow_any_host", nvmf_rpc_subsystem_allow_any_host, + SPDK_RPC_RUNTIME) + +static const struct spdk_json_object_decoder nvmf_rpc_subsystem_tgt_opts_decoder[] = { + {"max_queue_depth", offsetof(struct spdk_nvmf_tgt_opts, max_queue_depth), spdk_json_decode_uint16, true}, + {"max_qpairs_per_ctrlr", offsetof(struct spdk_nvmf_tgt_opts, max_qpairs_per_ctrlr), spdk_json_decode_uint16, true}, + {"in_capsule_data_size", offsetof(struct spdk_nvmf_tgt_opts, in_capsule_data_size), spdk_json_decode_uint32, true}, + {"max_io_size", offsetof(struct spdk_nvmf_tgt_opts, max_io_size), spdk_json_decode_uint32, true}, + {"max_subsystems", offsetof(struct spdk_nvmf_tgt_opts, max_subsystems), spdk_json_decode_uint32, true}, + {"io_unit_size", offsetof(struct spdk_nvmf_tgt_opts, io_unit_size), spdk_json_decode_uint32, true}, +}; + +static void +nvmf_rpc_subsystem_set_tgt_opts(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct spdk_nvmf_tgt_opts *opts; + struct spdk_json_write_ctx *w; + + if (g_spdk_nvmf_tgt_opts != NULL) { + SPDK_ERRLOG("this RPC must not be called more than once.\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Must not call more than once"); + return; + } + + opts = calloc(1, sizeof(*opts)); + if (opts == NULL) { + SPDK_ERRLOG("malloc() failed for target options\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Out of memory"); + return; + } + + spdk_nvmf_tgt_opts_init(opts); + + if (params != NULL) { + if (spdk_json_decode_object(params, nvmf_rpc_subsystem_tgt_opts_decoder, + SPDK_COUNTOF(nvmf_rpc_subsystem_tgt_opts_decoder), opts)) { + free(opts); + SPDK_ERRLOG("spdk_json_decode_object() failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + return; + } + } + + g_spdk_nvmf_tgt_opts = opts; + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} +SPDK_RPC_REGISTER("set_nvmf_target_options", nvmf_rpc_subsystem_set_tgt_opts, SPDK_RPC_STARTUP) + +static int decode_conn_sched(const struct spdk_json_val *val, void *out) +{ + enum spdk_nvmf_connect_sched *sched = out; + + if (spdk_json_strequal(val, "roundrobin") == true) { + *sched = CONNECT_SCHED_ROUND_ROBIN; + } else if (spdk_json_strequal(val, "hostip") == true) { + *sched = CONNECT_SCHED_HOST_IP; + } else { + SPDK_ERRLOG("Invalid connection scheduling parameter\n"); + return -EINVAL; + } + + return 0; +} + +static const struct spdk_json_object_decoder nvmf_rpc_subsystem_tgt_conf_decoder[] = { + {"acceptor_poll_rate", offsetof(struct spdk_nvmf_tgt_conf, acceptor_poll_rate), spdk_json_decode_uint32, true}, + {"conn_sched", offsetof(struct spdk_nvmf_tgt_conf, conn_sched), decode_conn_sched, true}, +}; + +static void +nvmf_rpc_subsystem_set_tgt_conf(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct spdk_nvmf_tgt_conf *conf; + struct spdk_json_write_ctx *w; + + if (g_spdk_nvmf_tgt_conf != NULL) { + SPDK_ERRLOG("this RPC must not be called more than once.\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Must not call more than once"); + return; + } + + conf = calloc(1, sizeof(*conf)); + if (conf == NULL) { + SPDK_ERRLOG("calloc() failed for target config\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Out of memory"); + return; + } + + conf->acceptor_poll_rate = ACCEPT_TIMEOUT_US; + conf->conn_sched = DEFAULT_CONN_SCHED; + + if (params != NULL) { + if (spdk_json_decode_object(params, nvmf_rpc_subsystem_tgt_conf_decoder, + SPDK_COUNTOF(nvmf_rpc_subsystem_tgt_conf_decoder), conf)) { + free(conf); + SPDK_ERRLOG("spdk_json_decode_object() failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + return; + } + } + + g_spdk_nvmf_tgt_conf = conf; + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} +SPDK_RPC_REGISTER("set_nvmf_target_config", nvmf_rpc_subsystem_set_tgt_conf, SPDK_RPC_STARTUP) + +struct nvmf_rpc_create_transport_ctx { + char *trtype; + struct spdk_nvmf_transport_opts opts; + struct spdk_jsonrpc_request *request; +}; + +static const struct spdk_json_object_decoder nvmf_rpc_create_transport_decoder[] = { + { "trtype", offsetof(struct nvmf_rpc_create_transport_ctx, trtype), spdk_json_decode_string}, + { + "max_queue_depth", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_queue_depth), + spdk_json_decode_uint16, true + }, + { + "max_qpairs_per_ctrlr", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_qpairs_per_ctrlr), + spdk_json_decode_uint16, true + }, + { + "in_capsule_data_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.in_capsule_data_size), + spdk_json_decode_uint32, true + }, + { + "max_io_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_io_size), + spdk_json_decode_uint32, true + }, + { + "io_unit_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.io_unit_size), + spdk_json_decode_uint32, true + }, + { + "max_aq_depth", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_aq_depth), + spdk_json_decode_uint32, true + }, +}; + +static void +nvmf_rpc_create_transport_ctx_free(struct nvmf_rpc_create_transport_ctx *ctx) +{ + free(ctx->trtype); + free(ctx); +} + +static void +nvmf_rpc_tgt_add_transport_done(void *cb_arg, int status) +{ + struct nvmf_rpc_create_transport_ctx *ctx = cb_arg; + struct spdk_jsonrpc_request *request; + struct spdk_json_write_ctx *w; + + request = ctx->request; + nvmf_rpc_create_transport_ctx_free(ctx); + + if (status) { + SPDK_ERRLOG("Failed to add transport to tgt.(%d)\n", status); + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Failed to add transport to tgt.(%d)\n", + status); + return; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} + +static void +nvmf_rpc_create_transport(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct nvmf_rpc_create_transport_ctx *ctx; + enum spdk_nvme_transport_type trtype; + struct spdk_nvmf_transport *transport; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); + return; + } + + /* Decode parameters the first time to get the transport type */ + if (spdk_json_decode_object(params, nvmf_rpc_create_transport_decoder, + SPDK_COUNTOF(nvmf_rpc_create_transport_decoder), + ctx)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_create_transport_ctx_free(ctx); + return; + } + + if (spdk_nvme_transport_id_parse_trtype(&trtype, ctx->trtype)) { + SPDK_ERRLOG("Invalid transport type '%s'\n", ctx->trtype); + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid transport type '%s'\n", ctx->trtype); + nvmf_rpc_create_transport_ctx_free(ctx); + return; + } + + /* Initialize all the transport options (based on transport type) and decode the + * parameters again to update any options passed in rpc create transport call. + */ + spdk_nvmf_transport_opts_init(trtype, &ctx->opts); + if (spdk_json_decode_object(params, nvmf_rpc_create_transport_decoder, + SPDK_COUNTOF(nvmf_rpc_create_transport_decoder), + ctx)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + nvmf_rpc_create_transport_ctx_free(ctx); + return; + } + + if (spdk_nvmf_tgt_get_transport(g_spdk_nvmf_tgt, trtype)) { + SPDK_ERRLOG("Transport type '%s' already exists\n", ctx->trtype); + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Transport type '%s' already exists\n", ctx->trtype); + nvmf_rpc_create_transport_ctx_free(ctx); + return; + } + + transport = spdk_nvmf_transport_create(trtype, &ctx->opts); + + if (!transport) { + SPDK_ERRLOG("Transport type '%s' create failed\n", ctx->trtype); + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Transport type '%s' create failed\n", ctx->trtype); + nvmf_rpc_create_transport_ctx_free(ctx); + return; + } + + /* add transport to target */ + ctx->request = request; + spdk_nvmf_tgt_add_transport(g_spdk_nvmf_tgt, transport, nvmf_rpc_tgt_add_transport_done, ctx); +} + +SPDK_RPC_REGISTER("nvmf_create_transport", nvmf_rpc_create_transport, SPDK_RPC_RUNTIME) diff --git a/src/spdk/lib/event/subsystems/nvmf/nvmf_rpc_deprecated.c b/src/spdk/lib/event/subsystems/nvmf/nvmf_rpc_deprecated.c new file mode 100644 index 00000000..30e5d04c --- /dev/null +++ b/src/spdk/lib/event/subsystems/nvmf/nvmf_rpc_deprecated.c @@ -0,0 +1,620 @@ +/*- + * 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 "event_nvmf.h" + +#include "spdk/bdev.h" +#include "spdk/log.h" +#include "spdk/rpc.h" +#include "spdk/env.h" +#include "spdk/nvme.h" +#include "spdk/nvmf.h" +#include "spdk/string.h" +#include "spdk/util.h" + +static int +hex_nybble_to_num(char c) +{ + if (c >= '0' && c <= '9') { + return c - '0'; + } + + if (c >= 'a' && c <= 'f') { + return c - 'a' + 0xA; + } + + if (c >= 'A' && c <= 'F') { + return c - 'A' + 0xA; + } + + return -1; +} + +static int +hex_byte_to_num(const char *str) +{ + int hi, lo; + + hi = hex_nybble_to_num(str[0]); + if (hi < 0) { + return hi; + } + + lo = hex_nybble_to_num(str[1]); + if (lo < 0) { + return lo; + } + + return hi * 16 + lo; +} + +static int +decode_hex_string_be(const char *str, uint8_t *out, size_t size) +{ + size_t i; + + /* Decode a string in "ABCDEF012345" format to its binary representation */ + for (i = 0; i < size; i++) { + int num = hex_byte_to_num(str); + + if (num < 0) { + /* Invalid hex byte or end of string */ + return -1; + } + + out[i] = (uint8_t)num; + str += 2; + } + + if (i != size || *str != '\0') { + /* Length mismatch */ + return -1; + } + + return 0; +} + +static int +decode_ns_nguid(const struct spdk_json_val *val, void *out) +{ + char *str = NULL; + int rc; + + rc = spdk_json_decode_string(val, &str); + if (rc == 0) { + /* 16-byte NGUID */ + rc = decode_hex_string_be(str, out, 16); + } + + free(str); + return rc; +} + +static int +decode_ns_eui64(const struct spdk_json_val *val, void *out) +{ + char *str = NULL; + int rc; + + rc = spdk_json_decode_string(val, &str); + if (rc == 0) { + /* 8-byte EUI-64 */ + rc = decode_hex_string_be(str, out, 8); + } + + free(str); + return rc; +} + +static int +decode_ns_uuid(const struct spdk_json_val *val, void *out) +{ + char *str = NULL; + int rc; + + rc = spdk_json_decode_string(val, &str); + if (rc == 0) { + rc = spdk_uuid_parse(out, str); + } + + free(str); + return rc; +} + +struct rpc_listen_address { + char *transport; + char *adrfam; + char *traddr; + char *trsvcid; +}; + +#define RPC_MAX_LISTEN_ADDRESSES 255 +#define RPC_MAX_HOSTS 255 +#define RPC_MAX_NAMESPACES 255 + +struct rpc_listen_addresses { + size_t num_listen_address; + struct rpc_listen_address addresses[RPC_MAX_LISTEN_ADDRESSES]; +}; + +static const struct spdk_json_object_decoder rpc_listen_address_decoders[] = { + /* NOTE: "transport" is kept for compatibility; new code should use "trtype" */ + {"transport", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true}, + {"trtype", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true}, + {"adrfam", offsetof(struct rpc_listen_address, adrfam), spdk_json_decode_string, true}, + {"traddr", offsetof(struct rpc_listen_address, traddr), spdk_json_decode_string}, + {"trsvcid", offsetof(struct rpc_listen_address, trsvcid), spdk_json_decode_string}, +}; + +static int +decode_rpc_listen_address(const struct spdk_json_val *val, void *out) +{ + struct rpc_listen_address *req = (struct rpc_listen_address *)out; + if (spdk_json_decode_object(val, rpc_listen_address_decoders, + SPDK_COUNTOF(rpc_listen_address_decoders), + req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + return -1; + } + return 0; +} + +static void +free_rpc_listen_address(struct rpc_listen_address *r) +{ + free(r->transport); + free(r->adrfam); + free(r->traddr); + free(r->trsvcid); +} + +static int +rpc_listen_address_to_trid(const struct rpc_listen_address *address, + struct spdk_nvme_transport_id *trid) +{ + size_t len; + + memset(trid, 0, sizeof(*trid)); + + if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, address->transport)) { + SPDK_ERRLOG("Invalid transport type: %s\n", address->transport); + return -EINVAL; + } + + if (address->adrfam) { + if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, address->adrfam)) { + SPDK_ERRLOG("Invalid adrfam: %s\n", address->adrfam); + return -EINVAL; + } + } else { + trid->adrfam = SPDK_NVMF_ADRFAM_IPV4; + } + + len = strlen(address->traddr); + if (len > sizeof(trid->traddr) - 1) { + SPDK_ERRLOG("Transport address longer than %zu characters: %s\n", + sizeof(trid->traddr) - 1, address->traddr); + return -EINVAL; + } + memcpy(trid->traddr, address->traddr, len + 1); + + len = strlen(address->trsvcid); + if (len > sizeof(trid->trsvcid) - 1) { + SPDK_ERRLOG("Transport service id longer than %zu characters: %s\n", + sizeof(trid->trsvcid) - 1, address->trsvcid); + return -EINVAL; + } + memcpy(trid->trsvcid, address->trsvcid, len + 1); + + return 0; +} + +static int +decode_rpc_listen_addresses(const struct spdk_json_val *val, void *out) +{ + struct rpc_listen_addresses *listen_addresses = out; + return spdk_json_decode_array(val, decode_rpc_listen_address, &listen_addresses->addresses, + RPC_MAX_LISTEN_ADDRESSES, + &listen_addresses->num_listen_address, sizeof(struct rpc_listen_address)); +} + +struct rpc_hosts { + size_t num_hosts; + char *hosts[RPC_MAX_HOSTS]; +}; + +static int +decode_rpc_hosts(const struct spdk_json_val *val, void *out) +{ + struct rpc_hosts *rpc_hosts = out; + + return spdk_json_decode_array(val, spdk_json_decode_string, rpc_hosts->hosts, RPC_MAX_HOSTS, + &rpc_hosts->num_hosts, sizeof(char *)); +} + + +struct spdk_nvmf_ns_params { + char *bdev_name; + uint32_t nsid; + char nguid[16]; + char eui64[8]; + struct spdk_uuid uuid; +}; + +struct rpc_namespaces { + size_t num_ns; + struct spdk_nvmf_ns_params ns_params[RPC_MAX_NAMESPACES]; +}; + + +static const struct spdk_json_object_decoder rpc_ns_params_decoders[] = { + {"nsid", offsetof(struct spdk_nvmf_ns_params, nsid), spdk_json_decode_uint32, true}, + {"bdev_name", offsetof(struct spdk_nvmf_ns_params, bdev_name), spdk_json_decode_string}, + {"nguid", offsetof(struct spdk_nvmf_ns_params, nguid), decode_ns_nguid, true}, + {"eui64", offsetof(struct spdk_nvmf_ns_params, eui64), decode_ns_eui64, true}, + {"uuid", offsetof(struct spdk_nvmf_ns_params, uuid), decode_ns_uuid, true}, +}; + +static void +free_rpc_ns_params(struct spdk_nvmf_ns_params *ns_params) +{ + free(ns_params->bdev_name); +} + +static void +free_rpc_namespaces(struct rpc_namespaces *r) +{ + size_t i; + + for (i = 0; i < r->num_ns; i++) { + free_rpc_ns_params(&r->ns_params[i]); + } +} + +static int +decode_rpc_ns_params(const struct spdk_json_val *val, void *out) +{ + struct spdk_nvmf_ns_params *ns_params = out; + + return spdk_json_decode_object(val, rpc_ns_params_decoders, + SPDK_COUNTOF(rpc_ns_params_decoders), + ns_params); +} + +static int +decode_rpc_namespaces(const struct spdk_json_val *val, void *out) +{ + struct rpc_namespaces *namespaces = out; + char *names[RPC_MAX_NAMESPACES] = {0}; /* old format - array of strings (bdev names) */ + size_t i; + int rc; + + /* First try to decode namespaces as an array of objects (new format) */ + if (spdk_json_decode_array(val, decode_rpc_ns_params, namespaces->ns_params, + SPDK_COUNTOF(namespaces->ns_params), + &namespaces->num_ns, sizeof(*namespaces->ns_params)) == 0) { + return 0; + } + + /* If that fails, try to decode namespaces as an array of strings (old format) */ + free_rpc_namespaces(namespaces); + memset(namespaces, 0, sizeof(*namespaces)); + rc = spdk_json_decode_array(val, spdk_json_decode_string, names, + SPDK_COUNTOF(names), + &namespaces->num_ns, sizeof(char *)); + if (rc == 0) { + /* Decoded old format - copy to ns_params (new format) */ + for (i = 0; i < namespaces->num_ns; i++) { + namespaces->ns_params[i].bdev_name = names[i]; + } + return 0; + } + + /* Failed to decode - don't leave dangling string pointers around */ + for (i = 0; i < namespaces->num_ns; i++) { + free(names[i]); + } + + return rc; +} + +static void +free_rpc_listen_addresses(struct rpc_listen_addresses *r) +{ + size_t i; + + for (i = 0; i < r->num_listen_address; i++) { + free_rpc_listen_address(&r->addresses[i]); + } +} + +static void +free_rpc_hosts(struct rpc_hosts *r) +{ + size_t i; + + for (i = 0; i < r->num_hosts; i++) { + free(r->hosts[i]); + } +} + +struct rpc_subsystem { + int32_t core; + char *mode; + char *nqn; + struct rpc_listen_addresses listen_addresses; + struct rpc_hosts hosts; + bool allow_any_host; + char *pci_address; + char *serial_number; + struct rpc_namespaces namespaces; + uint32_t num_ns; +}; + +static void +free_rpc_subsystem(struct rpc_subsystem *req) +{ + if (req) { + free(req->mode); + free(req->nqn); + free(req->serial_number); + free_rpc_namespaces(&req->namespaces); + free_rpc_listen_addresses(&req->listen_addresses); + free_rpc_hosts(&req->hosts); + } + free(req); +} + +static void +spdk_rpc_nvmf_subsystem_started(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct spdk_jsonrpc_request *request = cb_arg; + struct spdk_json_write_ctx *w; + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} + +static const struct spdk_json_object_decoder rpc_subsystem_decoders[] = { + {"core", offsetof(struct rpc_subsystem, core), spdk_json_decode_int32, true}, + {"mode", offsetof(struct rpc_subsystem, mode), spdk_json_decode_string, true}, + {"nqn", offsetof(struct rpc_subsystem, nqn), spdk_json_decode_string}, + {"listen_addresses", offsetof(struct rpc_subsystem, listen_addresses), decode_rpc_listen_addresses, true}, + {"hosts", offsetof(struct rpc_subsystem, hosts), decode_rpc_hosts, true}, + {"allow_any_host", offsetof(struct rpc_subsystem, allow_any_host), spdk_json_decode_bool, true}, + {"serial_number", offsetof(struct rpc_subsystem, serial_number), spdk_json_decode_string, true}, + {"namespaces", offsetof(struct rpc_subsystem, namespaces), decode_rpc_namespaces, true}, + {"max_namespaces", offsetof(struct rpc_subsystem, num_ns), spdk_json_decode_uint32, true}, +}; + +struct subsystem_listen_ctx { + struct rpc_subsystem *req; + struct spdk_nvmf_subsystem *subsystem; + struct spdk_jsonrpc_request *request; + + uint32_t idx; +}; + +static void +spdk_rpc_construct_subsystem_listen_done(void *cb_arg, int status) +{ + struct subsystem_listen_ctx *ctx = cb_arg; + struct rpc_listen_address *addr; + struct spdk_nvme_transport_id trid = {0}; + + if (status) { + goto invalid; + } + + addr = &ctx->req->listen_addresses.addresses[ctx->idx]; + if (rpc_listen_address_to_trid(addr, &trid)) { + goto invalid; + } + + spdk_nvmf_subsystem_add_listener(ctx->subsystem, &trid); + + ctx->idx++; + + if (ctx->idx < ctx->req->listen_addresses.num_listen_address) { + addr = &ctx->req->listen_addresses.addresses[ctx->idx]; + + if (rpc_listen_address_to_trid(addr, &trid)) { + goto invalid; + } + + spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &trid, spdk_rpc_construct_subsystem_listen_done, ctx); + return; + } + + spdk_nvmf_subsystem_start(ctx->subsystem, + spdk_rpc_nvmf_subsystem_started, + ctx->request); + + free_rpc_subsystem(ctx->req); + free(ctx); + + return; + +invalid: + spdk_nvmf_subsystem_destroy(ctx->subsystem); + spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + free_rpc_subsystem(ctx->req); + free(ctx); +} + +static void +spdk_rpc_construct_nvmf_subsystem(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_subsystem *req; + struct spdk_nvmf_subsystem *subsystem; + size_t i; + + SPDK_WARNLOG("The construct_nvmf_subsystem RPC is deprecated. Use nvmf_subsystem_create instead.\n"); + + req = calloc(1, sizeof(*req)); + if (!req) { + goto invalid; + } + + req->core = -1; /* Explicitly set the core as the uninitialized value */ + + if (spdk_json_decode_object(params, rpc_subsystem_decoders, + SPDK_COUNTOF(rpc_subsystem_decoders), + req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + goto invalid; + } + + /* Mode is no longer a valid parameter, but print out a nice + * message if it exists to inform users. + */ + if (req->mode) { + SPDK_NOTICELOG("Mode present in the construct NVMe-oF subsystem RPC.\n" + "Mode was removed as a valid parameter.\n"); + if (strcasecmp(req->mode, "Virtual") == 0) { + SPDK_NOTICELOG("Your mode value is 'Virtual' which is now the only possible mode.\n" + "Your RPC will work as expected.\n"); + } else { + SPDK_NOTICELOG("Please remove 'mode' from the RPC.\n"); + goto invalid; + } + } + + /* Core is no longer a valid parameter, but print out a nice + * message if it exists to inform users. + */ + if (req->core != -1) { + SPDK_NOTICELOG("Core present in the construct NVMe-oF subsystem RPC.\n" + "Core was removed as an option. Subsystems can now run on all available cores.\n"); + SPDK_NOTICELOG("Ignoring it and continuing.\n"); + } + + subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, req->nqn, SPDK_NVMF_SUBTYPE_NVME, + req->num_ns); + if (!subsystem) { + goto invalid; + } + + if (spdk_nvmf_subsystem_set_sn(subsystem, req->serial_number)) { + SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", req->nqn, req->serial_number); + goto invalid; + } + + for (i = 0; i < req->hosts.num_hosts; i++) { + spdk_nvmf_subsystem_add_host(subsystem, req->hosts.hosts[i]); + } + + spdk_nvmf_subsystem_set_allow_any_host(subsystem, req->allow_any_host); + + for (i = 0; i < req->namespaces.num_ns; i++) { + struct spdk_nvmf_ns_params *ns_params = &req->namespaces.ns_params[i]; + struct spdk_bdev *bdev; + struct spdk_nvmf_ns_opts ns_opts; + + bdev = spdk_bdev_get_by_name(ns_params->bdev_name); + if (bdev == NULL) { + SPDK_ERRLOG("Could not find namespace bdev '%s'\n", ns_params->bdev_name); + spdk_nvmf_subsystem_destroy(subsystem); + goto invalid; + } + + spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); + ns_opts.nsid = ns_params->nsid; + + SPDK_STATIC_ASSERT(sizeof(ns_opts.nguid) == sizeof(ns_params->nguid), "size mismatch"); + memcpy(ns_opts.nguid, ns_params->nguid, sizeof(ns_opts.nguid)); + + SPDK_STATIC_ASSERT(sizeof(ns_opts.eui64) == sizeof(ns_params->eui64), "size mismatch"); + memcpy(ns_opts.eui64, ns_params->eui64, sizeof(ns_opts.eui64)); + + if (!spdk_mem_all_zero(&ns_params->uuid, sizeof(ns_params->uuid))) { + ns_opts.uuid = ns_params->uuid; + } + + if (spdk_nvmf_subsystem_add_ns(subsystem, bdev, &ns_opts, sizeof(ns_opts)) == 0) { + SPDK_ERRLOG("Unable to add namespace\n"); + spdk_nvmf_subsystem_destroy(subsystem); + goto invalid; + } + } + + if (req->listen_addresses.num_listen_address > 0) { + struct rpc_listen_address *addr; + struct spdk_nvme_transport_id trid = {0}; + struct subsystem_listen_ctx *ctx; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + spdk_nvmf_subsystem_destroy(subsystem); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "No Memory"); + free_rpc_subsystem(req); + return; + } + + ctx->req = req; + ctx->subsystem = subsystem; + ctx->request = request; + ctx->idx = 0; + + addr = &req->listen_addresses.addresses[0]; + + if (rpc_listen_address_to_trid(addr, &trid)) { + free(ctx); + goto invalid; + } + + spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &trid, spdk_rpc_construct_subsystem_listen_done, ctx); + return; + } + + free_rpc_subsystem(req); + + spdk_nvmf_subsystem_start(subsystem, + spdk_rpc_nvmf_subsystem_started, + request); + + return; + +invalid: + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + free_rpc_subsystem(req); +} +SPDK_RPC_REGISTER("construct_nvmf_subsystem", spdk_rpc_construct_nvmf_subsystem, SPDK_RPC_RUNTIME) diff --git a/src/spdk/lib/event/subsystems/nvmf/nvmf_tgt.c b/src/spdk/lib/event/subsystems/nvmf/nvmf_tgt.c new file mode 100644 index 00000000..bb35dcce --- /dev/null +++ b/src/spdk/lib/event/subsystems/nvmf/nvmf_tgt.c @@ -0,0 +1,503 @@ +/*- + * 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 "event_nvmf.h" + +#include "spdk/bdev.h" +#include "spdk/event.h" +#include "spdk/thread.h" +#include "spdk/log.h" +#include "spdk/nvme.h" +#include "spdk/util.h" + +enum nvmf_tgt_state { + NVMF_TGT_INIT_NONE = 0, + NVMF_TGT_INIT_PARSE_CONFIG, + NVMF_TGT_INIT_CREATE_POLL_GROUPS, + NVMF_TGT_INIT_START_SUBSYSTEMS, + NVMF_TGT_INIT_START_ACCEPTOR, + NVMF_TGT_RUNNING, + NVMF_TGT_FINI_STOP_SUBSYSTEMS, + NVMF_TGT_FINI_DESTROY_POLL_GROUPS, + NVMF_TGT_FINI_STOP_ACCEPTOR, + NVMF_TGT_FINI_FREE_RESOURCES, + NVMF_TGT_STOPPED, + NVMF_TGT_ERROR, +}; + +struct nvmf_tgt_poll_group { + struct spdk_nvmf_poll_group *group; +}; + +struct nvmf_tgt_host_trid { + struct spdk_nvme_transport_id host_trid; + uint32_t core; + uint32_t ref; + TAILQ_ENTRY(nvmf_tgt_host_trid) link; +}; + +/* List of host trids that are connected to the target */ +static TAILQ_HEAD(, nvmf_tgt_host_trid) g_nvmf_tgt_host_trids = + TAILQ_HEAD_INITIALIZER(g_nvmf_tgt_host_trids); + +struct spdk_nvmf_tgt *g_spdk_nvmf_tgt = NULL; + +static enum nvmf_tgt_state g_tgt_state; + +/* Round-Robin/IP-based tracking of cores for qpair assignment */ +static uint32_t g_tgt_core; + +static struct nvmf_tgt_poll_group *g_poll_groups = NULL; +static size_t g_num_poll_groups = 0; + +static struct spdk_poller *g_acceptor_poller = NULL; + +static void nvmf_tgt_advance_state(void); + +static void +_spdk_nvmf_shutdown_cb(void *arg1, void *arg2) +{ + /* Still in initialization state, defer shutdown operation */ + if (g_tgt_state < NVMF_TGT_RUNNING) { + spdk_event_call(spdk_event_allocate(spdk_env_get_current_core(), + _spdk_nvmf_shutdown_cb, NULL, NULL)); + return; + } else if (g_tgt_state > NVMF_TGT_RUNNING) { + /* Already in Shutdown status, ignore the signal */ + return; + } + + g_tgt_state = NVMF_TGT_FINI_STOP_SUBSYSTEMS; + nvmf_tgt_advance_state(); +} + +static void +spdk_nvmf_subsystem_fini(void) +{ + /* Always let the first core to handle the case */ + if (spdk_env_get_current_core() != spdk_env_get_first_core()) { + spdk_event_call(spdk_event_allocate(spdk_env_get_first_core(), + _spdk_nvmf_shutdown_cb, NULL, NULL)); + } else { + _spdk_nvmf_shutdown_cb(NULL, NULL); + } +} + +static void +nvmf_tgt_poll_group_add(void *arg1, void *arg2) +{ + struct spdk_nvmf_qpair *qpair = arg1; + struct nvmf_tgt_poll_group *pg = arg2; + + spdk_nvmf_poll_group_add(pg->group, qpair); +} + +/* Round robin selection of cores */ +static uint32_t +spdk_nvmf_get_core_rr(void) +{ + uint32_t core; + + core = g_tgt_core; + g_tgt_core = spdk_env_get_next_core(core); + if (g_tgt_core == UINT32_MAX) { + g_tgt_core = spdk_env_get_first_core(); + } + + return core; +} + +static void +nvmf_tgt_remove_host_trid(struct spdk_nvmf_qpair *qpair) +{ + struct spdk_nvme_transport_id trid_to_remove; + struct nvmf_tgt_host_trid *trid = NULL, *tmp_trid = NULL; + + if (g_spdk_nvmf_tgt_conf->conn_sched != CONNECT_SCHED_HOST_IP) { + return; + } + + if (spdk_nvmf_qpair_get_peer_trid(qpair, &trid_to_remove) != 0) { + return; + } + + TAILQ_FOREACH_SAFE(trid, &g_nvmf_tgt_host_trids, link, tmp_trid) { + if (trid && !strncmp(trid->host_trid.traddr, + trid_to_remove.traddr, SPDK_NVMF_TRADDR_MAX_LEN + 1)) { + trid->ref--; + if (trid->ref == 0) { + TAILQ_REMOVE(&g_nvmf_tgt_host_trids, trid, link); + free(trid); + } + + break; + } + } + + return; +} + +static uint32_t +nvmf_tgt_get_qpair_core(struct spdk_nvmf_qpair *qpair) +{ + struct spdk_nvme_transport_id trid; + struct nvmf_tgt_host_trid *tmp_trid = NULL, *new_trid = NULL; + int ret; + uint32_t core = 0; + + switch (g_spdk_nvmf_tgt_conf->conn_sched) { + case CONNECT_SCHED_HOST_IP: + ret = spdk_nvmf_qpair_get_peer_trid(qpair, &trid); + if (ret) { + SPDK_ERRLOG("Invalid host transport Id. Assigning to core %d\n", core); + break; + } + + TAILQ_FOREACH(tmp_trid, &g_nvmf_tgt_host_trids, link) { + if (tmp_trid && !strncmp(tmp_trid->host_trid.traddr, + trid.traddr, SPDK_NVMF_TRADDR_MAX_LEN + 1)) { + tmp_trid->ref++; + core = tmp_trid->core; + break; + } + } + if (!tmp_trid) { + new_trid = calloc(1, sizeof(*new_trid)); + if (!new_trid) { + SPDK_ERRLOG("Insufficient memory. Assigning to core %d\n", core); + break; + } + /* Get the next available core for the new host */ + core = spdk_nvmf_get_core_rr(); + new_trid->core = core; + memcpy(new_trid->host_trid.traddr, trid.traddr, + SPDK_NVMF_TRADDR_MAX_LEN + 1); + TAILQ_INSERT_TAIL(&g_nvmf_tgt_host_trids, new_trid, link); + } + break; + case CONNECT_SCHED_ROUND_ROBIN: + default: + core = spdk_nvmf_get_core_rr(); + break; + } + + return core; +} + +static void +new_qpair(struct spdk_nvmf_qpair *qpair) +{ + struct spdk_event *event; + struct nvmf_tgt_poll_group *pg; + uint32_t core; + uint32_t attempts; + + if (g_tgt_state != NVMF_TGT_RUNNING) { + spdk_nvmf_qpair_disconnect(qpair, NULL, NULL); + return; + } + + for (attempts = 0; attempts < g_num_poll_groups; attempts++) { + core = nvmf_tgt_get_qpair_core(qpair); + pg = &g_poll_groups[core]; + if (pg->group != NULL) { + break; + } else { + nvmf_tgt_remove_host_trid(qpair); + } + } + + if (attempts == g_num_poll_groups) { + SPDK_ERRLOG("No poll groups exist.\n"); + spdk_nvmf_qpair_disconnect(qpair, NULL, NULL); + return; + } + + event = spdk_event_allocate(core, nvmf_tgt_poll_group_add, qpair, pg); + spdk_event_call(event); +} + +static int +acceptor_poll(void *arg) +{ + struct spdk_nvmf_tgt *tgt = arg; + + spdk_nvmf_tgt_accept(tgt, new_qpair); + + return -1; +} + +static void +nvmf_tgt_destroy_poll_group_done(void *ctx) +{ + g_tgt_state = NVMF_TGT_FINI_STOP_ACCEPTOR; + nvmf_tgt_advance_state(); +} + +static void +nvmf_tgt_destroy_poll_group(void *ctx) +{ + struct nvmf_tgt_poll_group *pg; + + pg = &g_poll_groups[spdk_env_get_current_core()]; + + if (pg->group) { + spdk_nvmf_poll_group_destroy(pg->group); + pg->group = NULL; + } +} + +static void +nvmf_tgt_create_poll_group_done(void *ctx) +{ + g_tgt_state = NVMF_TGT_INIT_START_SUBSYSTEMS; + nvmf_tgt_advance_state(); +} + +static void +nvmf_tgt_create_poll_group(void *ctx) +{ + struct nvmf_tgt_poll_group *pg; + + pg = &g_poll_groups[spdk_env_get_current_core()]; + + pg->group = spdk_nvmf_poll_group_create(g_spdk_nvmf_tgt); +} + +static void +nvmf_tgt_subsystem_started(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + subsystem = spdk_nvmf_subsystem_get_next(subsystem); + + if (subsystem) { + spdk_nvmf_subsystem_start(subsystem, nvmf_tgt_subsystem_started, NULL); + return; + } + + g_tgt_state = NVMF_TGT_INIT_START_ACCEPTOR; + nvmf_tgt_advance_state(); +} + +static void +nvmf_tgt_subsystem_stopped(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + subsystem = spdk_nvmf_subsystem_get_next(subsystem); + + if (subsystem) { + spdk_nvmf_subsystem_stop(subsystem, nvmf_tgt_subsystem_stopped, NULL); + return; + } + + g_tgt_state = NVMF_TGT_FINI_DESTROY_POLL_GROUPS; + nvmf_tgt_advance_state(); +} + +static void +nvmf_tgt_destroy_done(void *ctx, int status) +{ + struct nvmf_tgt_host_trid *trid, *tmp_trid; + + g_tgt_state = NVMF_TGT_STOPPED; + + TAILQ_FOREACH_SAFE(trid, &g_nvmf_tgt_host_trids, link, tmp_trid) { + TAILQ_REMOVE(&g_nvmf_tgt_host_trids, trid, link); + free(trid); + } + + free(g_spdk_nvmf_tgt_conf); + g_spdk_nvmf_tgt_conf = NULL; + nvmf_tgt_advance_state(); +} + +static void +nvmf_tgt_parse_conf_done(int status) +{ + g_tgt_state = (status == 0) ? NVMF_TGT_INIT_CREATE_POLL_GROUPS : NVMF_TGT_ERROR; + nvmf_tgt_advance_state(); +} + +static void +nvmf_tgt_parse_conf_start(void *ctx) +{ + if (spdk_nvmf_parse_conf(nvmf_tgt_parse_conf_done)) { + SPDK_ERRLOG("spdk_nvmf_parse_conf() failed\n"); + g_tgt_state = NVMF_TGT_ERROR; + nvmf_tgt_advance_state(); + } +} + +static void +nvmf_tgt_advance_state(void) +{ + enum nvmf_tgt_state prev_state; + int rc = -1; + + do { + prev_state = g_tgt_state; + + switch (g_tgt_state) { + case NVMF_TGT_INIT_NONE: { + g_tgt_state = NVMF_TGT_INIT_PARSE_CONFIG; + + /* Find the maximum core number */ + g_num_poll_groups = spdk_env_get_last_core() + 1; + assert(g_num_poll_groups > 0); + + g_poll_groups = calloc(g_num_poll_groups, sizeof(*g_poll_groups)); + if (g_poll_groups == NULL) { + g_tgt_state = NVMF_TGT_ERROR; + rc = -ENOMEM; + break; + } + + g_tgt_core = spdk_env_get_first_core(); + break; + } + case NVMF_TGT_INIT_PARSE_CONFIG: + /* Send message to self to call parse conf func. + * Prevents it from possibly performing cb before getting + * out of this function, which causes problems. */ + spdk_thread_send_msg(spdk_get_thread(), nvmf_tgt_parse_conf_start, NULL); + break; + case NVMF_TGT_INIT_CREATE_POLL_GROUPS: + /* Send a message to each thread and create a poll group */ + spdk_for_each_thread(nvmf_tgt_create_poll_group, + NULL, + nvmf_tgt_create_poll_group_done); + break; + case NVMF_TGT_INIT_START_SUBSYSTEMS: { + struct spdk_nvmf_subsystem *subsystem; + + subsystem = spdk_nvmf_subsystem_get_first(g_spdk_nvmf_tgt); + + if (subsystem) { + spdk_nvmf_subsystem_start(subsystem, nvmf_tgt_subsystem_started, NULL); + } else { + g_tgt_state = NVMF_TGT_INIT_START_ACCEPTOR; + } + break; + } + case NVMF_TGT_INIT_START_ACCEPTOR: + g_acceptor_poller = spdk_poller_register(acceptor_poll, g_spdk_nvmf_tgt, + g_spdk_nvmf_tgt_conf->acceptor_poll_rate); + SPDK_INFOLOG(SPDK_LOG_NVMF, "Acceptor running\n"); + g_tgt_state = NVMF_TGT_RUNNING; + break; + case NVMF_TGT_RUNNING: + spdk_subsystem_init_next(0); + break; + case NVMF_TGT_FINI_STOP_SUBSYSTEMS: { + struct spdk_nvmf_subsystem *subsystem; + + subsystem = spdk_nvmf_subsystem_get_first(g_spdk_nvmf_tgt); + + if (subsystem) { + spdk_nvmf_subsystem_stop(subsystem, nvmf_tgt_subsystem_stopped, NULL); + } else { + g_tgt_state = NVMF_TGT_FINI_DESTROY_POLL_GROUPS; + } + break; + } + case NVMF_TGT_FINI_DESTROY_POLL_GROUPS: + /* Send a message to each thread and destroy the poll group */ + spdk_for_each_thread(nvmf_tgt_destroy_poll_group, + NULL, + nvmf_tgt_destroy_poll_group_done); + break; + case NVMF_TGT_FINI_STOP_ACCEPTOR: + spdk_poller_unregister(&g_acceptor_poller); + g_tgt_state = NVMF_TGT_FINI_FREE_RESOURCES; + break; + case NVMF_TGT_FINI_FREE_RESOURCES: + spdk_nvmf_tgt_destroy(g_spdk_nvmf_tgt, nvmf_tgt_destroy_done, NULL); + break; + case NVMF_TGT_STOPPED: + spdk_subsystem_fini_next(); + return; + case NVMF_TGT_ERROR: + spdk_subsystem_init_next(rc); + return; + } + + } while (g_tgt_state != prev_state); +} + +static void +spdk_nvmf_subsystem_init(void) +{ + g_tgt_state = NVMF_TGT_INIT_NONE; + nvmf_tgt_advance_state(); +} + +static char * +get_conn_sched_string(enum spdk_nvmf_connect_sched sched) +{ + if (sched == CONNECT_SCHED_HOST_IP) { + return "hostip"; + } else { + return "roundrobin"; + } +} + +static void +spdk_nvmf_subsystem_write_config_json(struct spdk_json_write_ctx *w, struct spdk_event *done_ev) +{ + spdk_json_write_array_begin(w); + + spdk_json_write_object_begin(w); + spdk_json_write_named_string(w, "method", "set_nvmf_target_config"); + + spdk_json_write_named_object_begin(w, "params"); + spdk_json_write_named_uint32(w, "acceptor_poll_rate", g_spdk_nvmf_tgt_conf->acceptor_poll_rate); + spdk_json_write_named_string(w, "conn_sched", + get_conn_sched_string(g_spdk_nvmf_tgt_conf->conn_sched)); + spdk_json_write_object_end(w); + spdk_json_write_object_end(w); + + spdk_nvmf_tgt_write_config_json(w, g_spdk_nvmf_tgt); + spdk_json_write_array_end(w); + + spdk_event_call(done_ev); +} + +static struct spdk_subsystem g_spdk_subsystem_nvmf = { + .name = "nvmf", + .init = spdk_nvmf_subsystem_init, + .fini = spdk_nvmf_subsystem_fini, + .write_config_json = spdk_nvmf_subsystem_write_config_json, +}; + +SPDK_SUBSYSTEM_REGISTER(g_spdk_subsystem_nvmf) +SPDK_SUBSYSTEM_DEPEND(nvmf, bdev) diff --git a/src/spdk/lib/event/subsystems/scsi/Makefile b/src/spdk/lib/event/subsystems/scsi/Makefile new file mode 100644 index 00000000..12bf15e3 --- /dev/null +++ b/src/spdk/lib/event/subsystems/scsi/Makefile @@ -0,0 +1,40 @@ +# +# 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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +C_SRCS = scsi.c +LIBNAME = event_scsi + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/event/subsystems/scsi/scsi.c b/src/spdk/lib/event/subsystems/scsi/scsi.c new file mode 100644 index 00000000..a37ebf61 --- /dev/null +++ b/src/spdk/lib/event/subsystems/scsi/scsi.c @@ -0,0 +1,65 @@ +/*- + * 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/scsi.h" + +#include "spdk_internal/event.h" + +static void +spdk_scsi_subsystem_init(void) +{ + int rc; + + rc = spdk_scsi_init(); + + spdk_subsystem_init_next(rc); +} + +static void +spdk_scsi_subsystem_fini(void) +{ + spdk_scsi_fini(); + spdk_subsystem_fini_next(); +} + +static struct spdk_subsystem g_spdk_subsystem_scsi = { + .name = "scsi", + .init = spdk_scsi_subsystem_init, + .fini = spdk_scsi_subsystem_fini, + .config = NULL, +}; + +SPDK_SUBSYSTEM_REGISTER(g_spdk_subsystem_scsi); +SPDK_SUBSYSTEM_DEPEND(scsi, bdev) diff --git a/src/spdk/lib/event/subsystems/vhost/Makefile b/src/spdk/lib/event/subsystems/vhost/Makefile new file mode 100644 index 00000000..2e0d61fe --- /dev/null +++ b/src/spdk/lib/event/subsystems/vhost/Makefile @@ -0,0 +1,40 @@ +# +# 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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +C_SRCS = vhost.c +LIBNAME = event_vhost + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/src/spdk/lib/event/subsystems/vhost/vhost.c b/src/spdk/lib/event/subsystems/vhost/vhost.c new file mode 100644 index 00000000..1fdbc6aa --- /dev/null +++ b/src/spdk/lib/event/subsystems/vhost/vhost.c @@ -0,0 +1,71 @@ +/*- + * 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/vhost.h" + +#include "spdk_internal/event.h" + +static void +spdk_vhost_subsystem_init(void) +{ + int rc = 0; + + rc = spdk_vhost_init(); + + spdk_subsystem_init_next(rc); +} + +static void +spdk_vhost_subsystem_fini_done(void) +{ + spdk_subsystem_fini_next(); +} + +static void +spdk_vhost_subsystem_fini(void) +{ + spdk_vhost_fini(spdk_vhost_subsystem_fini_done); +} + +static struct spdk_subsystem g_spdk_subsystem_vhost = { + .name = "vhost", + .init = spdk_vhost_subsystem_init, + .fini = spdk_vhost_subsystem_fini, + .config = NULL, + .write_config_json = spdk_vhost_config_json, +}; + +SPDK_SUBSYSTEM_REGISTER(g_spdk_subsystem_vhost); +SPDK_SUBSYSTEM_DEPEND(vhost, scsi) |