nvmf: Correct the error path of transport creation.

An error might occur after succesful transport creation
when the new transport is added to nvmf poll groups, e.g.
in nvmf_transport_poll_group_create. In that case
transport is not detroyed and poll groups are not fully
functional. To correct this behaviour, destroy transport if
spdk_nvmf_tgt_add_transport fails. Also update nvmf_tgt
initialization step to check that all poll groups were
created.

Change-Id: I116e6944729d846c1755c2844c77825f65db8c12
Signed-off-by: Alexey Marchuk <alexeymar@mellanox.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9255
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Jacek Kalwas <jacek.kalwas@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
This commit is contained in:
Alexey Marchuk 2021-08-23 12:53:03 +03:00 committed by Tomasz Zawadzki
parent d409971b79
commit fb4398ef4b
4 changed files with 42 additions and 14 deletions

View File

@ -116,6 +116,7 @@ nvmf_tgt_create_poll_group(void *io_device, void *ctx_buf)
struct spdk_nvmf_transport *transport;
struct spdk_thread *thread = spdk_get_thread();
uint32_t sid;
int rc;
SPDK_DTRACE_PROBE1(nvmf_create_poll_group, spdk_thread_get_id(thread));
@ -123,7 +124,10 @@ nvmf_tgt_create_poll_group(void *io_device, void *ctx_buf)
TAILQ_INIT(&group->qpairs);
TAILQ_FOREACH(transport, &tgt->transports, link) {
nvmf_poll_group_add_transport(group, transport);
rc = nvmf_poll_group_add_transport(group, transport);
if (rc != 0) {
return rc;
}
}
group->num_sgroups = tgt->max_subsystems;
@ -714,6 +718,9 @@ _nvmf_tgt_add_transport_done(struct spdk_io_channel_iter *i, int status)
{
struct spdk_nvmf_tgt_add_transport_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
if (status) {
TAILQ_REMOVE(&ctx->tgt->transports, ctx->transport, link);
}
ctx->cb_fn(ctx->cb_arg, status);
free(ctx);

View File

@ -1787,6 +1787,8 @@ struct nvmf_rpc_create_transport_ctx {
char *tgt_name;
struct spdk_nvmf_transport_opts opts;
struct spdk_jsonrpc_request *request;
struct spdk_nvmf_transport *transport;
int status;
};
/**
@ -1889,24 +1891,30 @@ nvmf_rpc_create_transport_ctx_free(struct nvmf_rpc_create_transport_ctx *ctx)
free(ctx);
}
static void
nvmf_rpc_transport_destroy_done_cb(void *cb_arg)
{
struct nvmf_rpc_create_transport_ctx *ctx = cb_arg;
spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Failed to add transport to tgt.(%d)", ctx->status);
nvmf_rpc_create_transport_ctx_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;
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)",
status);
ctx->status = status;
spdk_nvmf_transport_destroy(ctx->transport, nvmf_rpc_transport_destroy_done_cb, ctx);
return;
}
spdk_jsonrpc_send_bool_response(request, true);
spdk_jsonrpc_send_bool_response(ctx->request, true);
nvmf_rpc_create_transport_ctx_free(ctx);
}
static void
@ -1915,7 +1923,6 @@ rpc_nvmf_create_transport(struct spdk_jsonrpc_request *request,
{
struct nvmf_rpc_create_transport_ctx *ctx;
enum spdk_nvme_transport_type trtype;
struct spdk_nvmf_transport *transport;
struct spdk_nvmf_tgt *tgt;
ctx = calloc(1, sizeof(*ctx));
@ -1985,9 +1992,9 @@ rpc_nvmf_create_transport(struct spdk_jsonrpc_request *request,
/* Transport can parse additional params themselves */
ctx->opts.transport_specific = params;
transport = spdk_nvmf_transport_create(ctx->trtype, &ctx->opts);
ctx->transport = spdk_nvmf_transport_create(ctx->trtype, &ctx->opts);
if (!transport) {
if (!ctx->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", ctx->trtype);
@ -1997,7 +2004,7 @@ rpc_nvmf_create_transport(struct spdk_jsonrpc_request *request,
/* add transport to target */
ctx->request = request;
spdk_nvmf_tgt_add_transport(tgt, transport, nvmf_rpc_tgt_add_transport_done, ctx);
spdk_nvmf_tgt_add_transport(tgt, ctx->transport, nvmf_rpc_tgt_add_transport_done, ctx);
}
SPDK_RPC_REGISTER("nvmf_create_transport", rpc_nvmf_create_transport, SPDK_RPC_RUNTIME)

View File

@ -3,6 +3,7 @@
*
* Copyright (c) Intel Corporation.
* All rights reserved.
* Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -166,12 +167,22 @@ nvmf_tgt_create_poll_group_done(void *ctx)
{
struct nvmf_tgt_poll_group *pg = ctx;
assert(pg);
if (!pg->group) {
SPDK_ERRLOG("Failed to create nvmf poll group\n");
/* Change the state to error but wait for completions from all other threads */
g_tgt_state = NVMF_TGT_ERROR;
}
TAILQ_INSERT_TAIL(&g_poll_groups, pg, link);
assert(g_num_poll_groups < nvmf_get_cpuset_count());
if (++g_num_poll_groups == nvmf_get_cpuset_count()) {
g_tgt_state = NVMF_TGT_INIT_START_SUBSYSTEMS;
if (g_tgt_state != NVMF_TGT_ERROR) {
g_tgt_state = NVMF_TGT_INIT_START_SUBSYSTEMS;
}
nvmf_tgt_advance_state();
}
}

View File

@ -169,6 +169,7 @@ test_nvmf_tgt_create_poll_group(void)
struct spdk_nvmf_ns ns = {};
struct spdk_bdev bdev = {};
struct spdk_io_channel ch = {};
struct spdk_nvmf_transport_poll_group transport_pg = {};
thread = spdk_thread_create(NULL, NULL);
SPDK_CU_ASSERT_FATAL(thread != NULL);
@ -202,7 +203,9 @@ test_nvmf_tgt_create_poll_group(void)
transport.tgt = &tgt;
TAILQ_INSERT_TAIL(&tgt.transports, &transport, link);
MOCK_SET(nvmf_transport_poll_group_create, &transport_pg);
rc = nvmf_tgt_create_poll_group((void *)&tgt, (void *)&group);
MOCK_SET(nvmf_transport_poll_group_create, NULL);
CU_ASSERT(rc == 0);
CU_ASSERT(group.num_sgroups == 1);
CU_ASSERT(group.sgroups != NULL);