diff --git a/app/nvmf_tgt/nvmf_rpc.c b/app/nvmf_tgt/nvmf_rpc.c index 289b3f581..50b770f04 100644 --- a/app/nvmf_tgt/nvmf_rpc.c +++ b/app/nvmf_tgt/nvmf_rpc.c @@ -280,13 +280,19 @@ static const struct spdk_json_object_decoder rpc_ns_params_decoders[] = { {"bdev_name", offsetof(struct spdk_nvmf_ns_params, bdev_name), spdk_json_decode_string}, }; +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(r->ns_params[i].bdev_name); + free_rpc_ns_params(&r->ns_params[i]); } } @@ -668,3 +674,125 @@ nvmf_rpc_subsystem_add_listener(struct spdk_jsonrpc_request *request, } } SPDK_RPC_REGISTER("nvmf_subsystem_add_listener", nvmf_rpc_subsystem_add_listener); + + +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_rpc_ns_params(&ctx->ns_params); + 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_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; + } + + ctx->ns_params.nsid = spdk_nvmf_subsystem_add_ns(subsystem, bdev, ctx->ns_params.nsid); + 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_tgt.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) diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 8e4b4f6d0..efffebcd2 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -384,3 +384,43 @@ Example response: "result": true } ~~~ + +## nvmf_subsystem_add_ns method {#rpc_nvmf_subsystem_add_ns} + +Add a namespace to a subsystem. The namespace ID is returned as the result. + +### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +nqn | Required | string | Subsystem NQN +namespace | Required | object | @ref rpc_construct_nvmf_subsystem_namespace object + +### Example + +Example request: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "method": "nvmf_subsystem_add_ns", + "params": { + "nqn": "nqn.2016-06.io.spdk:cnode1", + "namespace": { + "nsid": 3, + "bdev_name": "Nvme0n1" + } + } +} +~~~ + +Example response: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": 3 +} +~~~ diff --git a/scripts/rpc.py b/scripts/rpc.py index 48414948b..4f0454ca8 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -345,6 +345,12 @@ if __name__ == "__main__": p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number') p.set_defaults(func=rpc.nvmf.nvmf_subsystem_add_listener) + p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem') + p.add_argument('nqn', help='NVMe-oF subsystem NQN') + p.add_argument('bdev_name', help='The name of the bdev that will back this namespace') + p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int) + p.set_defaults(func=rpc.nvmf.nvmf_subsystem_add_ns) + # pmem p = subparsers.add_parser('create_pmem_pool', help='Create pmem pool') p.add_argument('pmem_file', help='Path to pmemblk pool file') diff --git a/scripts/rpc/nvmf.py b/scripts/rpc/nvmf.py index a859e1f43..9664d3376 100755 --- a/scripts/rpc/nvmf.py +++ b/scripts/rpc/nvmf.py @@ -58,6 +58,18 @@ def nvmf_subsystem_add_listener(args): args.client.call('nvmf_subsystem_add_listener', params) +def nvmf_subsystem_add_ns(args): + ns = {'bdev_name': args.bdev_name} + + if args.nsid: + ns['nsid'] = args.nsid + + params = {'nqn': args.nqn, + 'namespace': ns} + + args.client.call('nvmf_subsystem_add_ns', params) + + def delete_nvmf_subsystem(args): params = {'nqn': args.subsystem_nqn} args.client.call('delete_nvmf_subsystem', params) diff --git a/test/nvmf/discovery/discovery.sh b/test/nvmf/discovery/discovery.sh index 23e6e0b0e..66e0caaf4 100755 --- a/test/nvmf/discovery/discovery.sh +++ b/test/nvmf/discovery/discovery.sh @@ -40,7 +40,10 @@ bdevs="$bdevs $($rpc_py construct_null_bdev Null1 $NULL_BDEV_SIZE $NULL_BLOCK_SI modprobe -v nvme-rdma -$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" "" -a -s SPDK00000000000001 -n "$bdevs" +$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" "" -a -s SPDK00000000000001 +for bdev in $bdevs; do + $rpc_py nvmf_subsystem_add_ns nqn.2016-06.io.spdk:cnode1 $bdev +done nvme discover -t rdma -a $NVMF_FIRST_TARGET_IP -s $NVMF_PORT diff --git a/test/nvmf/rpc/rpc.sh b/test/nvmf/rpc/rpc.sh index 87a61ca61..81fb870c2 100755 --- a/test/nvmf/rpc/rpc.sh +++ b/test/nvmf/rpc/rpc.sh @@ -45,8 +45,8 @@ do j=0 for bdev in $bdevs; do let j=j+1 - $rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode$j '' '' -a -s SPDK00000000000001 -n "$bdev" - $rpc_py nvmf_subsystem_add_listener nqn.2016-06.io.spdk:cnode$j -t RDMA -a $NVMF_FIRST_TARGET_IP -s 4420 + $rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode$j '' '' -a -s SPDK00000000000001 + $rpc_py nvmf_subsystem_add_ns nqn.2016-06.io.spdk:cnode$j $bdev done n=$j