diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 44670a6b087..a00b18dfdfe 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -8792,6 +8792,120 @@ Example response: } ~~~ +### nvmf_subsystem_set_pause_timeout method {#rpc_nvmf_subsystem_set_pause_timeout} + +Set the pause timeout value for a subsystem. + +#### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +nqn | Required | string | Subsystem NQN +pause_timeout_sec | Required | number | Pause timeout in seconds +tgt_name | Optional | string | Parent NVMe-oF target name. + +#### Example + +Example request: + +~~json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "nvmf_subsystem_set_pause_timeout", + "params": { + "nqn": "nqn.2016-06.io.spdk:cnode1", + "pause_timeout_sec": 120 + } +} +~~ + +Example response: + +~~json +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~~ + +### nvmf_subsystem_pause_ext method {#rpc_nvmf_subsystem_pause_ext} + +Pause an NVMe-oF subsystem with the specified pause flags. + +#### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +nqn | Required | string | Subsystem NQN +nsid | Optional | number | Namespace ID. Defaults to 0. +flags | Optional | number | Pause operation flags. Defaults to 0. +tgt_name | Optional | string | Parent NVMe-oF target name. + +#### Example + +Example request: + +~json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "nvmf_subsystem_pause_ext", + "params": { + "nqn": "nqn.2016-06.io.spdk:cnode1", + "nsid": 1, + "flags": 0 + } +} +~ + +Example response: + +~json +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~ + +### nvmf_subsystem_resume_ext method {#rpc_nvmf_subsystem_resume_ext} + +Resume an NVMe-oF subsystem previously paused with `nvmf_subsystem_pause_ext`. + +#### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +nqn | Required | string | Subsystem NQN +tgt_name | Optional | string | Parent NVMe-oF target name. + +#### Example + +Example request: + +~json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "nvmf_subsystem_resume_ext", + "params": { + "nqn": "nqn.2016-06.io.spdk:cnode1" + } +} +~ + +Example response: + +~json +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~ + ### nvmf_subsystem_add_host method {#rpc_nvmf_subsystem_add_host} Add a host NQN to the list of allowed hosts. Adding an already allowed host will result in an diff --git a/doc/nvmf_tgt_pg.md b/doc/nvmf_tgt_pg.md index 51bfa85c595..21b65c1abe4 100644 --- a/doc/nvmf_tgt_pg.md +++ b/doc/nvmf_tgt_pg.md @@ -75,7 +75,8 @@ Subsystems begin in an inactive state and must be activated by calling spdk_nvmf_subsystem_start(). Subsystems may be modified at run time, but only when in the paused or inactive state. A running subsystem may be paused by calling spdk_nvmf_subsystem_pause() and resumed by calling -spdk_nvmf_subsystem_resume(). +spdk_nvmf_subsystem_resume(). Also nvmf_subsystem_pause_ext() and +nvmf_subsystem_resume_ext() is vendor specific method for pause and resume. Namespaces may be added to the subsystem by calling spdk_nvmf_subsystem_add_ns_ext() when the subsystem is inactive or paused. diff --git a/go/rpc/clientIntegration.go b/go/rpc/clientIntegration.go index 53b011722ac..483cba45090 100644 --- a/go/rpc/clientIntegration.go +++ b/go/rpc/clientIntegration.go @@ -46,7 +46,9 @@ func spdk_gorpc_call(jsonPtr *C.char, location *C.char) (*C.char, C.int) { log.Printf("error on client creation, err: %s", err.Error()) return nil, ConnectionError } - defer rpcClient.Close() + defer func() { + _ = rpcClient.Close() + }() method := jsonMap["method"].(string) params := jsonMap["params"].(map[string]any) diff --git a/include/spdk/nvmf.h b/include/spdk/nvmf.h index f1dcba9cf90..d79d0a2382a 100644 --- a/include/spdk/nvmf.h +++ b/include/spdk/nvmf.h @@ -27,6 +27,8 @@ extern "C" { #define SPDK_TLS_PSK_MAX_LEN 200 +#define SPDK_NVMF_SUBSYSTEM_PAUSE_KEEP_ADMINQ 0x1 + struct spdk_nvmf_tgt; struct spdk_nvmf_subsystem; struct spdk_nvmf_ctrlr; @@ -566,6 +568,21 @@ int spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem, spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg); +/** + * Vendor specific wrapper of subsystem pause + * we need to keep allow some admin commands during subsystem pause + */ +int spdk_nvmf_subsystem_pause_ext(struct spdk_nvmf_subsystem *subsystem, + uint32_t nsid, + uint32_t flags, + spdk_nvmf_subsystem_state_change_done cb_fn, + void *cb_arg); + +int spdk_nvmf_subsystem_set_pause_timeout(struct spdk_nvmf_subsystem *subsystem, + uint32_t timeout_sec); + +uint32_t spdk_nvmf_subsystem_get_pause_timeout(struct spdk_nvmf_subsystem *subsystem); + /** * Transition an NVMe-oF subsystem from Paused to Active state. * @@ -582,6 +599,13 @@ int spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem, spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg); +/** + * Vendor specific wrapper of subsystem resume + * We need to clear vendor specific flags during resume + */ +int spdk_nvmf_subsystem_resume_ext(struct spdk_nvmf_subsystem *subsystem, + spdk_nvmf_subsystem_state_change_done cb_fn, + void *cb_arg); /** * Search the target for a subsystem with the given NQN. * diff --git a/lib/nvmf/ctrlr.c b/lib/nvmf/ctrlr.c index 65d6bee8a2c..840d455a12f 100644 --- a/lib/nvmf/ctrlr.c +++ b/lib/nvmf/ctrlr.c @@ -4859,6 +4859,7 @@ nvmf_check_subsystem_active(struct spdk_nvmf_request *req) struct spdk_nvmf_subsystem_poll_group *sgroup = NULL; struct spdk_nvmf_subsystem_pg_ns_info *ns_info; uint32_t nsid; + struct spdk_nvmf_subsystem *subsystem; if (spdk_likely(qpair->ctrlr)) { sgroup = &qpair->group->sgroups[qpair->ctrlr->subsys->id]; @@ -4875,6 +4876,16 @@ nvmf_check_subsystem_active(struct spdk_nvmf_request *req) if (spdk_unlikely(req->cmd->nvmf_cmd.opcode == SPDK_NVME_OPC_FABRIC || nvmf_qpair_is_admin_queue(qpair))) { if (sgroup->state != SPDK_NVMF_SUBSYSTEM_ACTIVE) { + subsystem = qpair->ctrlr->subsys; + if (req->cmd->nvmf_cmd.opcode != SPDK_NVME_OPC_FABRIC && + (subsystem->pause_flags & SPDK_NVMF_SUBSYSTEM_PAUSE_KEEP_ADMINQ)) { + /* + * Vendor maintenance pause + * allow normal admin queue commands while data IO is paused + */ + sgroup->mgmt_io_outstanding++; + return true; + } /* The subsystem is not currently active. Queue this request. */ TAILQ_INSERT_TAIL(&sgroup->queued, req, link); return false; diff --git a/lib/nvmf/nvmf_internal.h b/lib/nvmf/nvmf_internal.h index f93c352b511..4fc38047039 100644 --- a/lib/nvmf/nvmf_internal.h +++ b/lib/nvmf/nvmf_internal.h @@ -26,7 +26,7 @@ /* The spec reserves cntlid values in the range FFF0h to FFFFh. */ #define NVMF_MIN_CNTLID 1 #define NVMF_MAX_CNTLID 0xFFEF - +#define SPDK_NVMF_DEFAULT_PAUSE_TIMEOUT_SEC 120 #define NVMF_DISC_KATO_IN_MS 120000 #define NVMF_KAS_TIME_UNIT_IN_MS 100 #define NVMF_DEFAULT_KAS 100 @@ -365,6 +365,10 @@ struct spdk_nvmf_subsystem { /* Subsystem event callback and its argument. */ spdk_nvmf_subsystem_event_cb event_cb_fn; void *event_cb_arg; + /* Vendor specific flags for maintainance work */ + uint32_t pause_flags; + struct spdk_poller *pause_timer; + uint32_t pause_timeout_sec; }; static int diff --git a/lib/nvmf/subsystem.c b/lib/nvmf/subsystem.c index 9d126897094..9b05e4fcc5d 100644 --- a/lib/nvmf/subsystem.c +++ b/lib/nvmf/subsystem.c @@ -29,6 +29,11 @@ #define MODEL_NUMBER_DEFAULT "SPDK bdev Controller" #define NVMF_SUBSYSTEM_DEFAULT_NAMESPACES 32 +struct spdk_nvmf_resume_ext_ctx { + spdk_nvmf_subsystem_state_change_done cb_fn; + void *cb_arg; +}; + /* * States for parsing valid domains in NQNs according to RFC 1034 */ @@ -265,6 +270,9 @@ spdk_nvmf_subsystem_create(struct spdk_nvmf_tgt *tgt, subsystem->next_cntlid = 1; subsystem->min_cntlid = NVMF_MIN_CNTLID; subsystem->max_cntlid = NVMF_MAX_CNTLID; + subsystem->pause_timeout_sec = SPDK_NVMF_DEFAULT_PAUSE_TIMEOUT_SEC; + subsystem->pause_flags = 0; + subsystem->pause_timer = NULL; snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", nqn); pthread_mutex_init(&subsystem->mutex, NULL); TAILQ_INIT(&subsystem->listeners); @@ -400,6 +408,11 @@ _nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem) return -EINPROGRESS; } + if (subsystem->pause_timer) { + spdk_poller_unregister(&subsystem->pause_timer); + subsystem->pause_timer = NULL; + } + ns = spdk_nvmf_subsystem_get_first_ns(subsystem); while (ns != NULL) { struct spdk_nvmf_ns *next_ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns); @@ -813,6 +826,51 @@ spdk_nvmf_subsystem_stop(struct spdk_nvmf_subsystem *subsystem, return nvmf_subsystem_state_change(subsystem, 0, SPDK_NVMF_SUBSYSTEM_INACTIVE, cb_fn, cb_arg); } +static +int +nvmf_subsys_pause_timer_cb(void *arg) +{ + struct spdk_nvmf_subsystem *subsystem = arg; + subsystem->pause_flags = 0; + if (subsystem->pause_timer) { + spdk_poller_unregister(&subsystem->pause_timer); + subsystem->pause_timer = NULL; + } + return SPDK_POLLER_BUSY; +} + +int +spdk_nvmf_subsystem_pause_ext(struct spdk_nvmf_subsystem *subsystem, + uint32_t nsid, + uint32_t flags, + spdk_nvmf_subsystem_state_change_done cb_fn, + void *cb_arg) +{ + subsystem->pause_flags = flags; + if (subsystem->pause_timer == NULL) { + subsystem->pause_timer = spdk_poller_register( + nvmf_subsys_pause_timer_cb, + subsystem, + subsystem->pause_timeout_sec * 1000000ULL + ); + } + return spdk_nvmf_subsystem_pause(subsystem, nsid, cb_fn, cb_arg); +} + +int +spdk_nvmf_subsystem_set_pause_timeout(struct spdk_nvmf_subsystem *subsystem, + uint32_t timeout_sec) +{ + subsystem->pause_timeout_sec = timeout_sec; + return 0; +} + +uint32_t +spdk_nvmf_subsystem_get_pause_timeout(struct spdk_nvmf_subsystem *subsystem) +{ + return subsystem->pause_timeout_sec; +} + int spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid, @@ -822,11 +880,54 @@ spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem, return nvmf_subsystem_state_change(subsystem, nsid, SPDK_NVMF_SUBSYSTEM_PAUSED, cb_fn, cb_arg); } +static void +nvmf_subsystem_resume_ext_done(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct spdk_nvmf_resume_ext_ctx *ctx = cb_arg; + + if (status == 0) { + subsystem->pause_flags = 0; + + if (subsystem->pause_timer != NULL) { + spdk_poller_unregister(&subsystem->pause_timer); + } + } + + ctx->cb_fn(subsystem, ctx->cb_arg, status); + free(ctx); +} + +int +spdk_nvmf_subsystem_resume_ext(struct spdk_nvmf_subsystem *subsystem, + spdk_nvmf_subsystem_state_change_done cb_fn, + void *cb_arg) +{ + struct spdk_nvmf_resume_ext_ctx *ctx; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + return -ENOMEM; + } + + ctx->cb_fn = cb_fn; + ctx->cb_arg = cb_arg; + + return spdk_nvmf_subsystem_resume(subsystem, + nvmf_subsystem_resume_ext_done, + ctx); +} + int spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem, spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg) { + subsystem->pause_flags = 0; + if (subsystem->pause_timer) { + spdk_poller_unregister(&subsystem->pause_timer); + subsystem->pause_timer = NULL; + } return nvmf_subsystem_state_change(subsystem, 0, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg); } diff --git a/module/event/subsystems/nvmf/nvmf_rpc.c b/module/event/subsystems/nvmf/nvmf_rpc.c index 56b77b5a5da..f36bee7ad19 100644 --- a/module/event/subsystems/nvmf/nvmf_rpc.c +++ b/module/event/subsystems/nvmf/nvmf_rpc.c @@ -6,6 +6,7 @@ #include "event_nvmf.h" +#include "spdk/string.h" #include "spdk/rpc.h" #include "spdk/util.h" #include "spdk/cpuset.h" @@ -14,6 +15,192 @@ static const struct spdk_json_object_decoder nvmf_rpc_subsystem_tgt_opts_decoder {"max_subsystems", 0, spdk_json_decode_uint32, true} }; +struct rpc_nvmf_subsystem_set_pause_timeout { + char *nqn; + uint32_t pause_timeout_sec; +}; + +static const struct spdk_json_object_decoder rpc_nvmf_subsystem_set_pause_timeout_decoders[] = { + {"nqn", offsetof(struct rpc_nvmf_subsystem_set_pause_timeout, nqn), spdk_json_decode_string}, + {"pause_timeout_sec", offsetof(struct rpc_nvmf_subsystem_set_pause_timeout, pause_timeout_sec), spdk_json_decode_uint32} +}; + +struct rpc_nvmf_subsystem_pause_ext { + char *nqn; + uint32_t nsid; + uint32_t flags; + char *tgt_name; +}; + +struct rpc_nvmf_subsystem_resume_ext { + char *nqn; + char *tgt_name; +}; + +static const struct spdk_json_object_decoder rpc_pause_ext_decoders[] = { + {"nqn", offsetof(struct rpc_nvmf_subsystem_pause_ext, nqn), spdk_json_decode_string}, + {"nsid", offsetof(struct rpc_nvmf_subsystem_pause_ext, nsid), spdk_json_decode_uint32}, + {"flags", offsetof(struct rpc_nvmf_subsystem_pause_ext, flags), spdk_json_decode_uint32}, + {"tgt_name", offsetof(struct rpc_nvmf_subsystem_pause_ext, tgt_name), spdk_json_decode_string, true}, +}; + +static const struct spdk_json_object_decoder rpc_resume_ext_decoders[] = { + {"nqn", offsetof(struct rpc_nvmf_subsystem_resume_ext, nqn), spdk_json_decode_string}, + {"tgt_name", offsetof(struct rpc_nvmf_subsystem_resume_ext, tgt_name), spdk_json_decode_string, true}, +}; + +static void +rpc_nvmf_subsystem_state_change_done(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct spdk_jsonrpc_request *request = cb_arg; + + if (status) { + spdk_jsonrpc_send_error_response(request, + SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Subsystem state change failed"); + return; + } + + spdk_jsonrpc_send_bool_response(request, true); +} + +static void +rpc_nvmf_subsystem_pause_ext(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_nvmf_subsystem_pause_ext req = {}; + struct spdk_nvmf_tgt *tgt; + struct spdk_nvmf_subsystem *subsystem; + int rc; + + rc = spdk_json_decode_object(params, + rpc_pause_ext_decoders, + SPDK_COUNTOF(rpc_pause_ext_decoders), + &req); + + if (rc) { + spdk_jsonrpc_send_error_response(request, + SPDK_JSONRPC_ERROR_PARSE_ERROR, + "Invalid parameters"); + return; + } + + tgt = spdk_nvmf_get_tgt(req.tgt_name); + subsystem = spdk_nvmf_tgt_find_subsystem(tgt, req.nqn); + + rc = spdk_nvmf_subsystem_pause_ext(subsystem, + req.nsid, + req.flags, + rpc_nvmf_subsystem_state_change_done, + request); + + if (rc) { + spdk_jsonrpc_send_error_response(request, + SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + spdk_strerror(-rc)); + } + + free(req.nqn); + free(req.tgt_name); +} + +static void +rpc_nvmf_subsystem_resume_ext(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_nvmf_subsystem_resume_ext req = {}; + struct spdk_nvmf_tgt *tgt; + struct spdk_nvmf_subsystem *subsystem; + int rc; + + rc = spdk_json_decode_object(params, + rpc_resume_ext_decoders, + SPDK_COUNTOF(rpc_resume_ext_decoders), + &req); + + if (rc) { + spdk_jsonrpc_send_error_response(request, + SPDK_JSONRPC_ERROR_PARSE_ERROR, + "Invalid parameters"); + return; + } + + tgt = spdk_nvmf_get_tgt(req.tgt_name); + + subsystem = spdk_nvmf_tgt_find_subsystem(tgt, req.nqn); + + if (subsystem == NULL) { + spdk_jsonrpc_send_error_response(request, + -SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Unable to find subsystem"); + goto cleanup; + } + + rc = spdk_nvmf_subsystem_resume_ext( + subsystem, + rpc_nvmf_subsystem_state_change_done, + request); + + if (rc) { + spdk_jsonrpc_send_error_response(request, + SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + spdk_strerror(-rc)); + } + +cleanup: + free(req.nqn); + free(req.tgt_name); +} + +SPDK_RPC_REGISTER("nvmf_subsystem_pause_ext", + rpc_nvmf_subsystem_pause_ext, + SPDK_RPC_RUNTIME) + +SPDK_RPC_REGISTER("nvmf_subsystem_resume_ext", + rpc_nvmf_subsystem_resume_ext, + SPDK_RPC_RUNTIME) + +static void +rpc_nvmf_subsystem_set_pause_timeout(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_nvmf_subsystem_set_pause_timeout req = {}; + struct spdk_nvmf_subsystem *subsystem; + int rc; + + if (spdk_json_decode_object(params, + rpc_nvmf_subsystem_set_pause_timeout_decoders, + SPDK_COUNTOF(rpc_nvmf_subsystem_set_pause_timeout_decoders), + &req)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + goto cleanup; + } + + subsystem = spdk_nvmf_tgt_find_subsystem(g_spdk_nvmf_tgt, req.nqn); + if (subsystem == NULL) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Invalid nqn"); + goto cleanup; + } + + rc = spdk_nvmf_subsystem_set_pause_timeout(subsystem, req.pause_timeout_sec); + if (rc != 0) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Failed to set timeout"); + goto cleanup; + } + + spdk_jsonrpc_send_bool_response(request, true); + +cleanup: + free(req.nqn); +} + +SPDK_RPC_REGISTER("nvmf_subsystem_set_pause_timeout", + rpc_nvmf_subsystem_set_pause_timeout, + SPDK_RPC_RUNTIME) + static void rpc_nvmf_set_max_subsystems(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) diff --git a/python/spdk/rpc/nvmf.py b/python/spdk/rpc/nvmf.py index c491a50f72f..249daeef10b 100644 --- a/python/spdk/rpc/nvmf.py +++ b/python/spdk/rpc/nvmf.py @@ -21,6 +21,43 @@ def nvmf_set_max_subsystems(client, return client.call('nvmf_set_max_subsystems', params) +def nvmf_subsystem_set_pause_timeout(client, nqn, pause_timeout_sec, tgt_name=None): + """Set NVMf subsystem pause timeout.""" + params = { + 'nqn': nqn, + 'pause_timeout_sec': pause_timeout_sec, + } + + if tgt_name: + params['tgt_name'] = tgt_name + + return client.call('nvmf_subsystem_set_pause_timeout', params) + + +def nvmf_subsystem_pause_ext(client, nqn, nsid=0, flags=0, tgt_name=None): + params = { + 'nqn': nqn, + 'nsid': nsid, + 'flags': flags, + } + + if tgt_name: + params['tgt_name'] = tgt_name + + return client.call('nvmf_subsystem_pause_ext', params) + + +def nvmf_subsystem_resume_ext(client, nqn, tgt_name=None): + params = { + 'nqn': nqn, + } + + if tgt_name: + params['tgt_name'] = tgt_name + + return client.call('nvmf_subsystem_resume_ext', params) + + def nvmf_set_config(client, passthru_identify_ctrlr=None, poll_groups_mask=None, diff --git a/scripts/rpc.py b/scripts/rpc.py index 2e50e232f55..affb9236e8c 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -2573,6 +2573,48 @@ def nvmf_set_max_subsystems(args): p.add_argument('-x', '--max-subsystems', help='Max number of NVMf subsystems', type=int, required=True) p.set_defaults(func=nvmf_set_max_subsystems) + def nvmf_subsystem_pause_ext(args): + rpc.nvmf.nvmf_subsystem_pause_ext( + args.client, + nqn=args.nqn, + nsid=args.nsid, + flags=args.flags) + + def nvmf_subsystem_resume_ext(args): + rpc.nvmf.nvmf_subsystem_resume_ext( + args.client, + nqn=args.nqn) + + p = subparsers.add_parser( + 'nvmf_subsystem_pause_ext', + help='Pause NVMf subsystem with vendor flags') + + p.add_argument('nqn', help='Subsystem NQN') + p.add_argument('nsid', type=int, help='Namespace ID') + p.add_argument('flags', type=int, help='Pause flags') + p.set_defaults(func=nvmf_subsystem_pause_ext) + + p = subparsers.add_parser( + 'nvmf_subsystem_resume_ext', + help='Resume NVMf subsystem') + + p.add_argument('nqn', help='Subsystem NQN') + p.set_defaults(func=nvmf_subsystem_resume_ext) + + def nvmf_subsystem_set_pause_timeout(args): + rpc.nvmf.nvmf_subsystem_set_pause_timeout( + args.client, + nqn=args.nqn, + pause_timeout_sec=args.pause_timeout_sec, + tgt_name=args.tgt_name) + + p = subparsers.add_parser('nvmf_subsystem_set_pause_timeout', + help='Set NVMf subsystem pause timeout') + p.add_argument('nqn', help='Subsystem NQN') + p.add_argument('pause_timeout_sec', help='Pause timeout in seconds', type=int) + p.add_argument('-t', '--tgt-name', help='Parent NVMe-oF target name') + p.set_defaults(func=nvmf_subsystem_set_pause_timeout) + def nvmf_set_config(args): rpc.nvmf.nvmf_set_config(args.client, passthru_identify_ctrlr=args.passthru_identify_ctrlr,