diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 96055a7d1..d626736f0 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -3227,6 +3227,9 @@ traddr | Required | string | NVMe-oF target address: ip adrfam | Optional | string | NVMe-oF target adrfam: ipv4, ipv6 trsvcid | Optional | string | NVMe-oF target trsvcid: port number hostnqn | Optional | string | NVMe-oF target hostnqn +ctrlr_loss_timeout_sec | Optional | number | Time to wait until ctrlr is reconnected before deleting ctrlr. -1 means infinite reconnects. 0 means no reconnect. +reconnect_delay_sec | Optional | number | Time to delay a reconnect trial. 0 means no reconnect. +fast_io_fail_timeout_sec | Optional | number | Time to wait until ctrlr is reconnected before failing I/O to ctrlr. 0 means no such timeout. #### Example diff --git a/module/bdev/nvme/bdev_nvme.c b/module/bdev/nvme/bdev_nvme.c index b1ac6377b..9c5c94303 100644 --- a/module/bdev/nvme/bdev_nvme.c +++ b/module/bdev/nvme/bdev_nvme.c @@ -4332,6 +4332,7 @@ struct discovery_ctx { struct discovery_entry_ctx *entry_ctx_in_use; struct spdk_poller *poller; struct spdk_nvme_ctrlr_opts drv_opts; + struct nvme_ctrlr_opts bdev_opts; struct spdk_nvmf_discovery_log_page *log_page; TAILQ_ENTRY(discovery_ctx) tailq; TAILQ_HEAD(, discovery_entry_ctx) nvm_entry_ctxs; @@ -4568,7 +4569,7 @@ discovery_log_page_cb(void *cb_arg, int rc, const struct spdk_nvme_cpl *cpl, snprintf(new_ctx->drv_opts.hostnqn, sizeof(new_ctx->drv_opts.hostnqn), "%s", ctx->hostnqn); rc = bdev_nvme_create(&new_ctx->trid, new_ctx->name, NULL, 0, discovery_attach_controller_done, new_ctx, - &new_ctx->drv_opts, NULL, true); + &new_ctx->drv_opts, &ctx->bdev_opts, true); if (rc == 0) { TAILQ_INSERT_TAIL(&ctx->nvm_entry_ctxs, new_ctx, tailq); ctx->attach_in_progress++; @@ -4716,7 +4717,8 @@ start_discovery_poller(void *arg) int bdev_nvme_start_discovery(struct spdk_nvme_transport_id *trid, const char *base_name, - struct spdk_nvme_ctrlr_opts *drv_opts) + struct spdk_nvme_ctrlr_opts *drv_opts, + struct nvme_ctrlr_opts *bdev_opts) { struct discovery_ctx *ctx; struct discovery_entry_ctx *discovery_entry_ctx; @@ -4732,6 +4734,7 @@ bdev_nvme_start_discovery(struct spdk_nvme_transport_id *trid, return -ENOMEM; } memcpy(&ctx->drv_opts, drv_opts, sizeof(*drv_opts)); + memcpy(&ctx->bdev_opts, bdev_opts, sizeof(*bdev_opts)); ctx->calling_thread = spdk_get_thread(); TAILQ_INIT(&ctx->nvm_entry_ctxs); TAILQ_INIT(&ctx->discovery_entry_ctxs); diff --git a/module/bdev/nvme/bdev_nvme.h b/module/bdev/nvme/bdev_nvme.h index 21b36248a..bb3920ff7 100644 --- a/module/bdev/nvme/bdev_nvme.h +++ b/module/bdev/nvme/bdev_nvme.h @@ -282,7 +282,7 @@ int bdev_nvme_create(struct spdk_nvme_transport_id *trid, bool multipath); int bdev_nvme_start_discovery(struct spdk_nvme_transport_id *trid, const char *base_name, - struct spdk_nvme_ctrlr_opts *drv_opts); + struct spdk_nvme_ctrlr_opts *drv_opts, struct nvme_ctrlr_opts *bdev_opts); int bdev_nvme_stop_discovery(const char *name, spdk_bdev_nvme_stop_discovery_fn cb_fn, void *cb_ctx); diff --git a/module/bdev/nvme/bdev_nvme_rpc.c b/module/bdev/nvme/bdev_nvme_rpc.c index 150d7988b..ad37d7889 100644 --- a/module/bdev/nvme/bdev_nvme_rpc.c +++ b/module/bdev/nvme/bdev_nvme_rpc.c @@ -1607,6 +1607,7 @@ struct rpc_bdev_nvme_start_discovery { char *trsvcid; char *hostnqn; struct spdk_nvme_ctrlr_opts opts; + struct nvme_ctrlr_opts bdev_opts; }; static void @@ -1627,6 +1628,9 @@ static const struct spdk_json_object_decoder rpc_bdev_nvme_start_discovery_decod {"adrfam", offsetof(struct rpc_bdev_nvme_start_discovery, adrfam), spdk_json_decode_string, true}, {"trsvcid", offsetof(struct rpc_bdev_nvme_start_discovery, trsvcid), spdk_json_decode_string, true}, {"hostnqn", offsetof(struct rpc_bdev_nvme_start_discovery, hostnqn), spdk_json_decode_string, true}, + {"ctrlr_loss_timeout_sec", offsetof(struct rpc_bdev_nvme_start_discovery, bdev_opts.ctrlr_loss_timeout_sec), spdk_json_decode_int32, true}, + {"reconnect_delay_sec", offsetof(struct rpc_bdev_nvme_start_discovery, bdev_opts.reconnect_delay_sec), spdk_json_decode_uint32, true}, + {"fast_io_fail_timeout_sec", offsetof(struct rpc_bdev_nvme_start_discovery, bdev_opts.fast_io_fail_timeout_sec), spdk_json_decode_uint32, true}, }; struct rpc_bdev_nvme_start_discovery_ctx { @@ -1712,7 +1716,7 @@ rpc_bdev_nvme_start_discovery(struct spdk_jsonrpc_request *request, } ctx->request = request; - rc = bdev_nvme_start_discovery(&trid, ctx->req.name, &ctx->req.opts); + rc = bdev_nvme_start_discovery(&trid, ctx->req.name, &ctx->req.opts, &ctx->req.bdev_opts); if (rc == 0) { spdk_jsonrpc_send_bool_response(ctx->request, true); } else { diff --git a/scripts/rpc.py b/scripts/rpc.py index 6ce5d0e73..36dfac1eb 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -693,7 +693,10 @@ if __name__ == "__main__": traddr=args.traddr, adrfam=args.adrfam, trsvcid=args.trsvcid, - hostnqn=args.hostnqn) + hostnqn=args.hostnqn, + ctrlr_loss_timeout_sec=args.ctrlr_loss_timeout_sec, + reconnect_delay_sec=args.reconnect_delay_sec, + fast_io_fail_timeout_sec=args.fast_io_fail_timeout_sec) p = subparsers.add_parser('bdev_nvme_start_discovery', help='Start automatic discovery') p.add_argument('-b', '--name', help="Name of the NVMe controller prefix for each bdev name", required=True) @@ -706,6 +709,26 @@ if __name__ == "__main__": p.add_argument('-s', '--trsvcid', help='NVMe-oF target trsvcid: e.g., a port number') p.add_argument('-q', '--hostnqn', help='NVMe-oF host subnqn') + p.add_argument('-l', '--ctrlr-loss-timeout-sec', + help="""Time to wait until ctrlr is reconnected before deleting ctrlr. + -1 means infinite reconnect retries. 0 means no reconnect retry. + If reconnect_delay_sec is zero, ctrlr_loss_timeout_sec has to be zero. + If reconnect_delay_sec is non-zero, ctrlr_loss_timeout_sec has to be -1 or not less than + reconnect_delay_sec.""", + type=int) + p.add_argument('-o', '--reconnect-delay-sec', + help="""Time to delay a reconnect retry. + If ctrlr_loss_timeout_sec is zero, reconnect_delay_sec has to be zero. + If ctrlr_loss_timeout_sec is -1, reconnect_delay_sec has to be non-zero. + If ctrlr_loss_timeout_sec is not -1 or zero, reconnect_delay_sec has to be non-zero and + less than ctrlr_loss_timeout_sec.""", + type=int) + p.add_argument('-u', '--fast-io-fail-timeout-sec', + help="""Time to wait until ctrlr is reconnected before failing I/O to ctrlr. + 0 means no such timeout. + If fast_io_fail_timeout_sec is not zero, it has to be not less than reconnect_delay_sec and + less than ctrlr_loss_timeout_sec if ctrlr_loss_timeout_sec is not -1.""", + type=int) p.set_defaults(func=bdev_nvme_start_discovery) def bdev_nvme_stop_discovery(args): diff --git a/scripts/rpc/bdev.py b/scripts/rpc/bdev.py index 3717f17c7..faf24e840 100644 --- a/scripts/rpc/bdev.py +++ b/scripts/rpc/bdev.py @@ -724,7 +724,8 @@ def bdev_nvme_reset_controller(client, name): def bdev_nvme_start_discovery(client, name, trtype, traddr, adrfam=None, trsvcid=None, - hostnqn=None): + hostnqn=None, ctrlr_loss_timeout_sec=None, reconnect_delay_sec=None, + fast_io_fail_timeout_sec=None): """Start discovery with the specified discovery subsystem Args: @@ -734,6 +735,20 @@ def bdev_nvme_start_discovery(client, name, trtype, traddr, adrfam=None, trsvcid adrfam: address family ("IPv4", "IPv6", "IB", or "FC") trsvcid: transport service ID (port number for IP-based addresses) hostnqn: NQN to connect from (optional) + ctrlr_loss_timeout_sec: Time to wait until ctrlr is reconnected before deleting ctrlr. + -1 means infinite reconnect retries. 0 means no reconnect retry. + If reconnect_delay_sec is zero, ctrlr_loss_timeout_sec has to be zero. + If reconnect_delay_sec is non-zero, ctrlr_loss_timeout_sec has to be -1 or not less than reconnect_delay_sec. + (optional) + reconnect_delay_sec: Time to delay a reconnect retry. + If ctrlr_loss_timeout_sec is zero, reconnect_delay_sec has to be zero. + If ctrlr_loss_timeout_sec is -1, reconnect_delay_sec has to be non-zero. + If ctrlr_loss_timeout_sec is not -1 or zero, reconnect_sec has to be non-zero and less than ctrlr_loss_timeout_sec. + (optional) + fail_io_fast_timeout_sec: Time to wait until ctrlr is reconnected before failing I/O to ctrlr. + 0 means no such timeout. + If fast_io_fail_timeout_sec is not zero, it has to be not less than reconnect_delay_sec and less than + ctrlr_loss_timeout_sec if ctrlr_loss_timeout_sec is not -1. (optional) """ params = {'name': name, 'trtype': trtype, @@ -748,6 +763,15 @@ def bdev_nvme_start_discovery(client, name, trtype, traddr, adrfam=None, trsvcid if trsvcid: params['trsvcid'] = trsvcid + if ctrlr_loss_timeout_sec is not None: + params['ctrlr_loss_timeout_sec'] = ctrlr_loss_timeout_sec + + if reconnect_delay_sec is not None: + params['reconnect_delay_sec'] = reconnect_delay_sec + + if fast_io_fail_timeout_sec is not None: + params['fast_io_fail_timeout_sec'] = fast_io_fail_timeout_sec + return client.call('bdev_nvme_start_discovery', params)