lib/nvmf: Add nvmf_subsystem_get_qpairs RPC

Add an new RPC, nvmf_subsystem_get_qpairs to retrieve the list of
qpairs of an NVMe-oF subsystem.

This RPC will be usable to verify if NVMe ANA works.

Pause and resume the subsystem to access the qpairs safely.

One subtle issue remains. The JSON RPC returns success even if
resuming the subsystem fails. Write FIXME to address this.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I9d90a01b1117dee00d85b2e21b4f4d02d80db531
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4050
Community-CI: Broadcom CI
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Shuhei Matsumoto 2020-09-03 09:02:44 +09:00 committed by Tomasz Zawadzki
parent a9c0fdd77d
commit 83eb352b3c
4 changed files with 189 additions and 0 deletions

View File

@ -4723,6 +4723,63 @@ Example response:
}
~~~
## nvmf_subsystem_get_qpairs {#rpc_nvmf_subsystem_get_qpairs}
### Parameters
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
nqn | Required | string | Subsystem NQN
tgt_name | Optional | string | Parent NVMe-oF target name.
### Example
Example request:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"method": "nvmf_subsystem_get_qpairs",
"params": {
"nqn": "nqn.2016-06.io.spdk:cnode1"
}
}
~~~
Example response:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"cntlid": 1,
"qid": 0,
"state": "active",
"listen_address": {
"trtype": "RDMA",
"adrfam": "IPv4",
"traddr": "192.168.0.123",
"trsvcid": "4420"
}
},
{
"cntlid": 1,
"qid": 1,
"state": "active",
"listen_address": {
"trtype": "RDMA",
"adrfam": "IPv4",
"traddr": "192.168.0.123",
"trsvcid": "4420"
}
}
]
}
~~~
## nvmf_set_max_subsystems {#rpc_nvmf_set_max_subsystems}
Set the maximum allowed subsystems for the NVMe-oF target. This RPC may only be called

View File

@ -2107,6 +2107,49 @@ dump_nvmf_ctrlr(struct spdk_json_write_ctx *w, struct spdk_nvmf_ctrlr *ctrlr)
spdk_json_write_object_end(w);
}
static const char *
nvmf_qpair_state_str(enum spdk_nvmf_qpair_state state)
{
switch (state) {
case SPDK_NVMF_QPAIR_UNINITIALIZED:
return "uninitialized";
case SPDK_NVMF_QPAIR_ACTIVE:
return "active";
case SPDK_NVMF_QPAIR_DEACTIVATING:
return "deactivating";
case SPDK_NVMF_QPAIR_ERROR:
return "error";
default:
return NULL;
}
}
static void
dump_nvmf_qpair(struct spdk_json_write_ctx *w, struct spdk_nvmf_qpair *qpair)
{
const struct spdk_nvme_transport_id *trid = qpair->trid;
const char *adrfam;
spdk_json_write_object_begin(w);
spdk_json_write_named_uint32(w, "cntlid", qpair->ctrlr->cntlid);
spdk_json_write_named_uint32(w, "qid", qpair->qid);
spdk_json_write_named_string(w, "state", nvmf_qpair_state_str(qpair->state));
spdk_json_write_named_object_begin(w, "listen_address");
adrfam = spdk_nvme_transport_id_adrfam_str(trid->adrfam);
if (adrfam == NULL) {
adrfam = "unknown";
}
spdk_json_write_named_string(w, "trtype", trid->trstring);
spdk_json_write_named_string(w, "adrfam", adrfam);
spdk_json_write_named_string(w, "traddr", trid->traddr);
spdk_json_write_named_string(w, "trsvcid", trid->trsvcid);
spdk_json_write_object_end(w);
spdk_json_write_object_end(w);
}
struct rpc_subsystem_query_ctx {
char *nqn;
char *tgt_name;
@ -2154,6 +2197,58 @@ rpc_nvmf_get_controllers_paused(struct spdk_nvmf_subsystem *subsystem,
free_rpc_subsystem_query_ctx(ctx);
}
static void
rpc_nvmf_get_qpairs_done(struct spdk_io_channel_iter *i, int status)
{
struct rpc_subsystem_query_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
spdk_json_write_array_end(ctx->w);
spdk_jsonrpc_end_result(ctx->request, ctx->w);
if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) {
SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn);
/* FIXME: RPC should fail if resuming the subsystem failed. */
}
free_rpc_subsystem_query_ctx(ctx);
}
static void
rpc_nvmf_get_qpairs(struct spdk_io_channel_iter *i)
{
struct rpc_subsystem_query_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
struct spdk_io_channel *ch;
struct spdk_nvmf_poll_group *group;
struct spdk_nvmf_qpair *qpair;
ch = spdk_get_io_channel(ctx->subsystem->tgt);
group = spdk_io_channel_get_ctx(ch);
TAILQ_FOREACH(qpair, &group->qpairs, link) {
if (qpair->ctrlr->subsys == ctx->subsystem) {
dump_nvmf_qpair(ctx->w, qpair);
}
}
spdk_for_each_channel_continue(i, 0);
}
static void
rpc_nvmf_get_qpairs_paused(struct spdk_nvmf_subsystem *subsystem,
void *cb_arg, int status)
{
struct rpc_subsystem_query_ctx *ctx = cb_arg;
ctx->w = spdk_jsonrpc_begin_result(ctx->request);
spdk_json_write_array_begin(ctx->w);
spdk_for_each_channel(ctx->subsystem->tgt,
rpc_nvmf_get_qpairs,
ctx,
rpc_nvmf_get_qpairs_done);
}
static void
_rpc_nvmf_subsystem_query(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params,
@ -2218,3 +2313,11 @@ rpc_nvmf_subsystem_get_controllers(struct spdk_jsonrpc_request *request,
}
SPDK_RPC_REGISTER("nvmf_subsystem_get_controllers", rpc_nvmf_subsystem_get_controllers,
SPDK_RPC_RUNTIME);
static void
rpc_nvmf_subsystem_get_qpairs(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
_rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_qpairs_paused);
}
SPDK_RPC_REGISTER("nvmf_subsystem_get_qpairs", rpc_nvmf_subsystem_get_qpairs, SPDK_RPC_RUNTIME);

View File

@ -2001,6 +2001,17 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
p.set_defaults(func=nvmf_subsystem_get_controllers)
def nvmf_subsystem_get_qpairs(args):
print_dict(rpc.nvmf.nvmf_subsystem_get_qpairs(args.client,
nqn=args.nqn,
tgt_name=args.tgt_name))
p = subparsers.add_parser('nvmf_subsystem_get_qpairs',
help='Display queue pairs of an NVMe-oF subsystem.')
p.add_argument('nqn', help='NVMe-oF subsystem NQN')
p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str)
p.set_defaults(func=nvmf_subsystem_get_qpairs)
def nvmf_get_stats(args):
print_dict(rpc.nvmf.nvmf_get_stats(args.client, tgt_name=args.tgt_name))

View File

@ -487,6 +487,24 @@ def nvmf_subsystem_get_controllers(client, nqn, tgt_name=None):
return client.call('nvmf_subsystem_get_controllers', params)
def nvmf_subsystem_get_qpairs(client, nqn, tgt_name=None):
"""Get list of queue pairs of an NVMe-oF subsystem.
Args:
nqn: Subsystem NQN.
tgt_name: name of the parent NVMe-oF target (optional).
Returns:
List of queue pair objects of an NVMe-oF subsystem.
"""
params = {'nqn': nqn}
if tgt_name:
params['tgt_name'] = tgt_name
return client.call('nvmf_subsystem_get_qpairs', params)
def nvmf_get_stats(client, tgt_name=None):
"""Query NVMf statistics.