diff --git a/app/nvmf_tgt/nvmf_rpc.c b/app/nvmf_tgt/nvmf_rpc.c index 3a78115e0..fc6f4ade4 100644 --- a/app/nvmf_tgt/nvmf_rpc.c +++ b/app/nvmf_tgt/nvmf_rpc.c @@ -980,6 +980,113 @@ nvmf_rpc_subsystem_add_ns(struct spdk_jsonrpc_request *request, } SPDK_RPC_REGISTER("nvmf_subsystem_add_ns", nvmf_rpc_subsystem_add_ns) +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_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); + 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; + } + + 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_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_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_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) + enum nvmf_rpc_host_op { NVMF_RPC_HOST_ADD, NVMF_RPC_HOST_REMOVE, diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 5e060abaa..c83d1d64c 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -423,6 +423,42 @@ Example response: } ~~~ +## nvmf_subsystem_remove_ns method {#rpc_nvmf_subsystem_remove_ns} + +Remove a namespace to a subsystem. + +### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +nqn | Required | string | Subsystem NQN +nsid | Required | number | Namespace ID + +### Example + +Example request: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "method": "nvmf_subsystem_remove_ns", + "params": { + "nqn": "nqn.2016-06.io.spdk:cnode1", + "nsid": 1 + } +} +~~~ + +Example response: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} + ## nvmf_subsystem_add_host method {#rpc_nvmf_subsystem_add_host} Add a host NQN to the whitelist of allowed hosts. diff --git a/scripts/rpc.py b/scripts/rpc.py index 9c5799408..f53a3ad59 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -378,6 +378,11 @@ if __name__ == "__main__": p.add_argument('-e', '--eui64', help='Namespace EUI-64 identifier (optional)') p.set_defaults(func=rpc.nvmf.nvmf_subsystem_add_ns) + p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem') + p.add_argument('nqn', help='NVMe-oF subsystem NQN') + p.add_argument('nsid', help='The requested NSID', type=int) + p.set_defaults(func=rpc.nvmf.nvmf_subsystem_remove_ns) + p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem') p.add_argument('nqn', help='NVMe-oF subsystem NQN') p.add_argument('host', help='Host NQN to allow') diff --git a/scripts/rpc/nvmf.py b/scripts/rpc/nvmf.py index e105f652f..5b26c1c45 100755 --- a/scripts/rpc/nvmf.py +++ b/scripts/rpc/nvmf.py @@ -76,6 +76,14 @@ def nvmf_subsystem_add_ns(args): args.client.call('nvmf_subsystem_add_ns', params) +def nvmf_subsystem_remove_ns(args): + + params = {'nqn': args.nqn, + 'nsid': args.nsid} + + args.client.call('nvmf_subsystem_remove_ns', params) + + def nvmf_subsystem_add_host(args): params = {'nqn': args.nqn, 'host': args.host} diff --git a/test/nvmf/rpc/rpc.sh b/test/nvmf/rpc/rpc.sh index 1242b7930..fc7e53769 100755 --- a/test/nvmf/rpc/rpc.sh +++ b/test/nvmf/rpc/rpc.sh @@ -82,6 +82,12 @@ do $rpc_py nvmf_subsystem_allow_any_host nqn.2016-06.io.spdk:cnode$j done + j=0 + for bdev in $bdevs; do + let j=j+1 + $rpc_py nvmf_subsystem_remove_ns nqn.2016-06.io.spdk:cnode$j $j + done + n=$j for j in `seq 1 $n` do