diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 03636d799837..91469de4e62e 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4791,6 +4791,16 @@ Kernel parameters Example: nvme.quirks=7710:2267:bogus_nid,^identify_cns-9900:7711:broken_msi + nvme_tcp.tls_handshake_timeout= + [NVME] NVMe/TCP host TLS handshake timeout in seconds. + Valid values range from 0 to the smaller of + UINT_MAX / 1000 and MAX_JIFFY_OFFSET / HZ. Default: 10 + + nvmet_tcp.tls_handshake_timeout= + [NVME] NVMe/TCP target TLS handshake timeout in seconds. + Valid values range from 0 to the smaller of + UINT_MAX / 1000 and MAX_JIFFY_OFFSET / HZ. Default: 10 + ohci1394_dma=early [HW,EARLY] enable debugging via the ohci1394 driver. See Documentation/core-api/debugging-via-ohci1394.rst for more info. diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c index cbb38935fa22..85f005a5efd0 100644 --- a/drivers/nvme/host/auth.c +++ b/drivers/nvme/host/auth.c @@ -85,10 +85,12 @@ static int nvme_auth_submit(struct nvme_ctrl *ctrl, int qid, qid == 0 ? NVME_QID_ANY : qid, flags); if (ret > 0) dev_warn(ctrl->device, - "qid %d auth_send failed with status %d\n", qid, ret); + "qid %d auth_%s failed with status %d\n", + qid, auth_send ? "send" : "receive", ret); else if (ret < 0) dev_err(ctrl->device, - "qid %d auth_send failed with error %d\n", qid, ret); + "qid %d auth_%s failed with error %d\n", + qid, auth_send ? "send" : "receive", ret); return ret; } diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 59f823dfbbcc..3d7ad86c1955 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -1125,16 +1125,27 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, void nvmf_set_io_queues(struct nvmf_ctrl_options *opts, u32 nr_io_queues, u32 io_queues[HCTX_MAX_TYPES]) { - if (opts->nr_write_queues && opts->nr_io_queues < nr_io_queues) { + /* + * Each queue type is mapped to the CPUs separately, so a type with + * more queues than online CPUs has hardware contexts without an online + * CPU. Use the same limits as nvmf_nr_io_queues. + */ + u32 nr_io = min(opts->nr_io_queues, num_online_cpus()); + u32 nr_write = min(opts->nr_write_queues, num_online_cpus()); + u32 nr_poll = min(opts->nr_poll_queues, num_online_cpus()); + + memset(io_queues, 0, sizeof(*io_queues) * HCTX_MAX_TYPES); + + if (nr_write && nr_io < nr_io_queues) { /* * separate read/write queues * hand out dedicated default queues only after we have * sufficient read queues. */ - io_queues[HCTX_TYPE_READ] = opts->nr_io_queues; + io_queues[HCTX_TYPE_READ] = nr_io; nr_io_queues -= io_queues[HCTX_TYPE_READ]; io_queues[HCTX_TYPE_DEFAULT] = - min(opts->nr_write_queues, nr_io_queues); + min(nr_write, nr_io_queues); nr_io_queues -= io_queues[HCTX_TYPE_DEFAULT]; } else { /* @@ -1143,14 +1154,14 @@ void nvmf_set_io_queues(struct nvmf_ctrl_options *opts, u32 nr_io_queues, * sufficient queue count to have dedicated default queues. */ io_queues[HCTX_TYPE_DEFAULT] = - min(opts->nr_io_queues, nr_io_queues); + min(nr_io, nr_io_queues); nr_io_queues -= io_queues[HCTX_TYPE_DEFAULT]; } - if (opts->nr_poll_queues && nr_io_queues) { + if (nr_poll && nr_io_queues) { /* map dedicated poll queues only if we have queues left */ io_queues[HCTX_TYPE_POLL] = - min(opts->nr_poll_queues, nr_io_queues); + min(nr_poll, nr_io_queues); } } EXPORT_SYMBOL_GPL(nvmf_set_io_queues); @@ -1188,6 +1199,13 @@ void nvmf_map_queues(struct blk_mq_tag_set *set, struct nvme_ctrl *ctrl, io_queues[HCTX_TYPE_DEFAULT] + io_queues[HCTX_TYPE_READ]; blk_mq_map_queues(&set->map[HCTX_TYPE_POLL]); + } else { + /* + * blk_mq_alloc_tag_set sets nr_queues of all maps to + * nr_hw_queues. Clear the poll map, otherwise the queue claims + * poll support and polled I/O ends up on hctx 0. + */ + set->map[HCTX_TYPE_POLL].nr_queues = 0; } dev_info(ctrl->device, diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 3a4030bcfab7..0b9ff50d26ff 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -3778,6 +3778,9 @@ static ssize_t nvme_fc_nvme_discovery_store(struct device *dev, restart: list_for_each_entry(lport, &nvme_fc_lport_list, port_list) { list_for_each_entry(rport, &lport->endp_list, endp_list) { + /* skip rports already queued for discovery */ + if (!list_empty(&rport->disc_list)) + continue; if (!nvme_fc_lport_get(lport)) continue; if (!nvme_fc_rport_get(rport)) { @@ -3799,9 +3802,7 @@ static ssize_t nvme_fc_nvme_discovery_store(struct device *dev, "failures\n"); goto process_local_list; } - if (list_empty(&rport->disc_list)) - list_add_tail(&rport->disc_list, - &local_disc_list); + list_add_tail(&rport->disc_list, &local_disc_list); } } diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index b1c512ab8c4d..8a90639789c9 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -232,7 +232,7 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp) return err; } -static char quirks_param[128]; +static char quirks_param[256]; static const struct kernel_param_ops quirks_param_ops = { .set = quirks_param_set, .get = param_get_string, @@ -243,7 +243,7 @@ static struct kparam_string quirks_param_string = { .string = quirks_param, }; -module_param_cb(quirks, &quirks_param_ops, &quirks_param_string, 0444); +device_param_cb(quirks, &quirks_param_ops, &quirks_param_string, 0444); MODULE_PARM_DESC(quirks, "Enable/disable NVMe quirks by specifying " "quirks=VID:DID:quirk_names"); diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 5b9b540693b5..07216890f75c 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -313,7 +313,7 @@ static int nvme_rdma_init_request(struct blk_mq_tag_set *set, return -ENOMEM; /* metadata nvme_rdma_sgl struct is located after command's data SGL */ - if (queue->pi_support) + if (queue_idx && ctrl->ctrl.max_integrity_segments) req->metadata_sgl = (void *)nvme_req(rq) + sizeof(struct nvme_rdma_request) + NVME_RDMA_DATA_SGL_SIZE; diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 7190eb10c248..bc46e5f3eaa7 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -6,6 +6,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include +#include #include #include #include @@ -48,13 +49,34 @@ MODULE_PARM_DESC(wq_unbound, "Use unbound workqueue for nvme-tcp IO context (def /* * TLS handshake timeout */ -static int tls_handshake_timeout = 10; +static unsigned int tls_handshake_timeout = 10; #ifdef CONFIG_NVME_TCP_TLS -module_param(tls_handshake_timeout, int, 0644); +static int tls_handshake_timeout_set(const char *val, + const struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, 0, + min_t(unsigned long, UINT_MAX / MSEC_PER_SEC, + MAX_JIFFY_OFFSET / HZ)); +} + +static const struct kernel_param_ops tls_handshake_timeout_ops = { + .set = tls_handshake_timeout_set, + .get = param_get_uint, +}; + +module_param_cb(tls_handshake_timeout, &tls_handshake_timeout_ops, + &tls_handshake_timeout, 0644); +__MODULE_PARM_TYPE(tls_handshake_timeout, "uint"); MODULE_PARM_DESC(tls_handshake_timeout, "nvme TLS handshake timeout in seconds (default 10)"); #endif +/* read a TLS control record in chunks of this size */ +#define NVME_TCP_TLS_REC_CHUNK 256 + +/* TLS records read while waiting for the ICResp, the ICResp included */ +#define NVME_TCP_ICRESP_MAX_RECORDS 8 + static int nvme_tcp_cpu_queues[NR_CPUS]; static DEFINE_SPINLOCK(nvme_tcp_cpu_queues_lock); @@ -97,6 +119,9 @@ enum nvme_tcp_queue_flags { NVME_TCP_Q_IO_CPU_SET = 3, }; +#define NVME_TCP_OPT_NR_QUEUES(opts) ((opts)->nr_io_queues + \ + (opts)->nr_write_queues + (opts)->nr_poll_queues + 1) + enum nvme_tcp_recv_state { NVME_TCP_RECV_PDU = 0, NVME_TCP_RECV_DATA, @@ -1430,6 +1455,19 @@ static int nvme_tcp_try_recv(struct nvme_tcp_queue *queue) lock_sock(sk); queue->nr_cqe = 0; consumed = sock->ops->read_sock(sk, &rd_desc, nvme_tcp_recv_skb); + /* + * nvme_tcp_recv_skb() handles its own errors, so a queue that is + * still enabled failed inside read_sock(). Handle it before + * release_sock() processes the backlog. + */ + if (unlikely(consumed < 0 && consumed != -EAGAIN && + queue->rd_enabled)) { + dev_err(queue->ctrl->ctrl.device, + "queue %d: receive failed: %d\n", + nvme_tcp_queue_id(queue), consumed); + queue->rd_enabled = false; + nvme_tcp_error_recovery(&queue->ctrl->ctrl); + } release_sock(sk); return consumed == -EAGAIN ? 0 : consumed; } @@ -1442,9 +1480,11 @@ static void nvme_tcp_io_work(struct work_struct *w) do { bool pending = false; + bool got_send_mutex = false; int result; if (mutex_trylock(&queue->send_mutex)) { + got_send_mutex = true; result = nvme_tcp_try_send(queue); mutex_unlock(&queue->send_mutex); if (result > 0) @@ -1459,8 +1499,13 @@ static void nvme_tcp_io_work(struct work_struct *w) else if (unlikely(result < 0)) return; - /* did we get some space after spending time in recv? */ - if (nvme_tcp_queue_has_pending(queue) && + /* + * did we get some space after spending time in recv? + * Only check this if we could take send_mutex. Otherwise + * the task holding it sends the requests and queues io_work + * again after it releases the mutex. + */ + if (got_send_mutex && nvme_tcp_queue_has_pending(queue) && sk_stream_is_writeable(queue->sock->sk)) pending = true; @@ -1523,23 +1568,159 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid) * nvme_reset_ctrl_work(), queue teardown is immediately followed by * re-allocation. fput() defers socket cleanup to delayed_fput_work * in workqueue context, which can race with new queue setup. + * + * Clear queue->sock under the queue lock so that a sysfs reader in + * nvme_tcp_get_address() either observes the NVME_TCP_Q_LIVE bit + * cleared or a still valid socket. The queue lock itself is owned + * by the controller and only destroyed when the controller is + * freed, so readers blocked on it cannot race its teardown. */ + mutex_lock(&queue->queue_lock); __fput_sync(queue->sock->file); queue->sock = NULL; + mutex_unlock(&queue->queue_lock); memalloc_noio_restore(noio_flag); kfree(queue->pdu); - mutex_destroy(&queue->send_mutex); - mutex_destroy(&queue->queue_lock); - mutex_destroy(&queue->pf_cache_lock); +} + +static int nvme_tcp_recv_tls_alert(struct nvme_tcp_queue *queue, + struct msghdr *msg, int len) +{ + struct sock *sk = queue->sock->sk; + u8 level, description; + + if (len < 2) { + dev_err(queue->ctrl->ctrl.device, + "queue %d: truncated TLS alert\n", + nvme_tcp_queue_id(queue)); + return -ENOTCONN; + } + + /* tls_alert_recv() reads through the iterator */ + iov_iter_revert(&msg->msg_iter, len); + tls_alert_recv(sk, msg, &level, &description); + + if (level == TLS_ALERT_LEVEL_FATAL) { + dev_err(queue->ctrl->ctrl.device, + "queue %d: fatal TLS alert %u\n", + nvme_tcp_queue_id(queue), description); + return -ENOTCONN; + } + + /* a peer shutting down normally is not worth a warning */ + if (description == TLS_ALERT_DESC_CLOSE_NOTIFY) + dev_dbg(queue->ctrl->ctrl.device, + "queue %d: TLS close_notify\n", + nvme_tcp_queue_id(queue)); + else + dev_warn(queue->ctrl->ctrl.device, + "queue %d: TLS alert %u\n", + nvme_tcp_queue_id(queue), description); + + return 0; +} + +/* + * Discard a TLS record that arrived in place of the ICResp. A peer may send + * a NewSessionTicket as soon as the handshake completes. + * + * Returns 0 when the record was discarded and the ICResp can be read, or a + * negative errno if the connection cannot continue. + */ +static int nvme_tcp_skip_tls_record(struct nvme_tcp_queue *queue, + struct msghdr *msg, u8 ctype, int len) +{ + u8 buf[NVME_TCP_TLS_REC_CHUNK]; + int ret; + + switch (ctype) { + case TLS_RECORD_TYPE_HANDSHAKE: + break; + case TLS_RECORD_TYPE_ALERT: + ret = nvme_tcp_recv_tls_alert(queue, msg, len); + return ret ? : -ENOTCONN; + default: + pr_err("queue %d: unhandled TLS record %u\n", + nvme_tcp_queue_id(queue), ctype); + return -ENOTCONN; + } + + /* the ICResp is in a later record, drain this one first */ + while (!(msg->msg_flags & MSG_EOR)) { + struct kvec iov = { + .iov_base = buf, + .iov_len = sizeof(buf), + }; + char cbuf[CMSG_LEN(sizeof(char))] = {}; + /* kTLS fails a control record read without a cmsg buffer */ + struct msghdr drain = { + .msg_control = cbuf, + .msg_controllen = sizeof(cbuf), + }; + + ret = kernel_recvmsg(queue->sock, &drain, &iov, 1, sizeof(buf), + 0); + if (ret <= 0) { + pr_warn("queue %d: failed to drain TLS record: %d\n", + nvme_tcp_queue_id(queue), ret); + return ret ? : -ECONNRESET; + } + msg->msg_flags = drain.msg_flags; + } + + return 0; +} + +/* + * Receive the ICResp. Over TLS, skip the records that a peer may send + * ahead of it. + * + * Returns the length received, or a negative errno. + */ +static int nvme_tcp_recv_icresp(struct nvme_tcp_queue *queue, + struct nvme_tcp_icresp_pdu *icresp) +{ + char cbuf[CMSG_LEN(sizeof(char))]; + struct msghdr msg; + struct kvec iov; + u8 ctype; + int i, ret; + + for (i = 0; i < NVME_TCP_ICRESP_MAX_RECORDS; i++) { + memset(&msg, 0, sizeof(msg)); + memset(cbuf, 0, sizeof(cbuf)); + iov.iov_base = icresp; + iov.iov_len = sizeof(*icresp); + if (nvme_tcp_queue_tls(queue)) { + msg.msg_control = cbuf; + msg.msg_controllen = sizeof(cbuf); + } + msg.msg_flags = MSG_WAITALL; + ret = kernel_recvmsg(queue->sock, &msg, &iov, 1, + iov.iov_len, msg.msg_flags); + if (ret <= 0 || !nvme_tcp_queue_tls(queue)) + return ret; + + ctype = tls_get_record_type(queue->sock->sk, + (struct cmsghdr *)cbuf); + if (ctype == TLS_RECORD_TYPE_DATA) + return ret; + + ret = nvme_tcp_skip_tls_record(queue, &msg, ctype, ret); + if (ret < 0) + return ret; + } + + pr_err("queue %d: too many TLS records before the ICResp\n", + nvme_tcp_queue_id(queue)); + return -EPROTO; } static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue) { struct nvme_tcp_icreq_pdu *icreq; struct nvme_tcp_icresp_pdu *icresp; - char cbuf[CMSG_LEN(sizeof(char))] = {}; - u8 ctype; struct msghdr msg = {}; struct kvec iov; bool ctrl_hdgst, ctrl_ddgst; @@ -1577,16 +1758,7 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue) goto free_icresp; } - memset(&msg, 0, sizeof(msg)); - iov.iov_base = icresp; - iov.iov_len = sizeof(*icresp); - if (nvme_tcp_queue_tls(queue)) { - msg.msg_control = cbuf; - msg.msg_controllen = sizeof(cbuf); - } - msg.msg_flags = MSG_WAITALL; - ret = kernel_recvmsg(queue->sock, &msg, &iov, 1, - iov.iov_len, msg.msg_flags); + ret = nvme_tcp_recv_icresp(queue, icresp); if (ret >= 0 && ret < sizeof(*icresp)) ret = -ECONNRESET; if (ret < 0) { @@ -1594,16 +1766,6 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue) nvme_tcp_queue_id(queue), ret); goto free_icresp; } - ret = -ENOTCONN; - if (nvme_tcp_queue_tls(queue)) { - ctype = tls_get_record_type(queue->sock->sk, - (struct cmsghdr *)cbuf); - if (ctype != TLS_RECORD_TYPE_DATA) { - pr_err("queue %d: unhandled TLS record %d\n", - nvme_tcp_queue_id(queue), ctype); - goto free_icresp; - } - } ret = -EINVAL; if (icresp->hdr.type != nvme_tcp_icresp) { pr_err("queue %d: bad type returned %d\n", @@ -1795,8 +1957,10 @@ static int nvme_tcp_start_tls(struct nvme_ctrl *nctrl, { int qid = nvme_tcp_queue_id(queue); int ret; + long wait_ret; struct tls_handshake_args args; - unsigned long tmo = tls_handshake_timeout * HZ; + unsigned int timeout = READ_ONCE(tls_handshake_timeout); + unsigned long tmo = (unsigned long)timeout * HZ; key_serial_t keyring = nvme_keyring_id(); dev_dbg(nctrl->device, "queue %d: start TLS with key %x\n", @@ -1810,7 +1974,7 @@ static int nvme_tcp_start_tls(struct nvme_ctrl *nctrl, if (nctrl->opts->keyring) keyring = key_serial(nctrl->opts->keyring); args.ta_keyring = keyring; - args.ta_timeout_ms = tls_handshake_timeout * 1000; + args.ta_timeout_ms = timeout * MSEC_PER_SEC; queue->tls_err = -EOPNOTSUPP; init_completion(&queue->tls_complete); ret = tls_client_hello_psk(&args, GFP_KERNEL); @@ -1819,10 +1983,10 @@ static int nvme_tcp_start_tls(struct nvme_ctrl *nctrl, qid, ret); return ret; } - ret = wait_for_completion_interruptible_timeout(&queue->tls_complete, tmo); - if (ret <= 0) { - if (ret == 0) - ret = -ETIMEDOUT; + wait_ret = wait_for_completion_interruptible_timeout(&queue->tls_complete, + tmo); + if (wait_ret <= 0) { + ret = wait_ret < 0 ? -ERESTARTSYS : -ETIMEDOUT; dev_err(nctrl->device, "queue %d: TLS handshake failed, error %d\n", @@ -1842,6 +2006,28 @@ static int nvme_tcp_start_tls(struct nvme_ctrl *nctrl, return ret; } +static void nvme_tcp_init_queue(struct nvme_tcp_ctrl *ctrl, int qid) +{ + struct nvme_tcp_queue *queue = &ctrl->queues[qid]; + + queue->ctrl = ctrl; + mutex_init(&queue->queue_lock); + mutex_init(&queue->send_mutex); + mutex_init(&queue->pf_cache_lock); + INIT_WORK(&queue->io_work, nvme_tcp_io_work); + queue->hdr_digest = ctrl->ctrl.opts->hdr_digest; + queue->data_digest = ctrl->ctrl.opts->data_digest; +} + +static void nvme_tcp_exit_queue(struct nvme_tcp_ctrl *ctrl, int qid) +{ + struct nvme_tcp_queue *queue = &ctrl->queues[qid]; + + mutex_destroy(&queue->queue_lock); + mutex_destroy(&queue->send_mutex); + mutex_destroy(&queue->pf_cache_lock); +} + static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, key_serial_t pskid) { @@ -1850,13 +2036,8 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, int ret, rcv_pdu_size; struct file *sock_file; - mutex_init(&queue->queue_lock); - queue->ctrl = ctrl; init_llist_head(&queue->req_list); INIT_LIST_HEAD(&queue->send_list); - mutex_init(&queue->send_mutex); - INIT_WORK(&queue->io_work, nvme_tcp_io_work); - mutex_init(&queue->pf_cache_lock); if (qid > 0) queue->cmnd_capsule_len = nctrl->ioccsz * 16; @@ -1870,14 +2051,12 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, if (ret) { dev_err(nctrl->device, "failed to create socket: %d\n", ret); - goto err_destroy_mutex; + return ret; } sock_file = sock_alloc_file(queue->sock, O_CLOEXEC, NULL); - if (IS_ERR(sock_file)) { - ret = PTR_ERR(sock_file); - goto err_destroy_mutex; - } + if (IS_ERR(sock_file)) + return PTR_ERR(sock_file); sk_net_refcnt_upgrade(queue->sock->sk); @@ -1939,9 +2118,6 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, } } - queue->hdr_digest = nctrl->opts->hdr_digest; - queue->data_digest = nctrl->opts->data_digest; - rcv_pdu_size = sizeof(struct nvme_tcp_rsp_pdu) + nvme_tcp_hdgst_len(queue); queue->pdu = kmalloc(rcv_pdu_size, GFP_KERNEL); @@ -1986,10 +2162,6 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, /* Use sync variant - see nvme_tcp_free_queue() for explanation */ __fput_sync(queue->sock->file); queue->sock = NULL; -err_destroy_mutex: - mutex_destroy(&queue->send_mutex); - mutex_destroy(&queue->queue_lock); - mutex_destroy(&queue->pf_cache_lock); return ret; } @@ -2676,6 +2848,9 @@ static void nvme_tcp_stop_ctrl(struct nvme_ctrl *ctrl) static void nvme_tcp_free_ctrl(struct nvme_ctrl *nctrl) { struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); + /* the same count used to size and initialize the queue array */ + unsigned int nr_queues = NVME_TCP_OPT_NR_QUEUES(nctrl->opts); + unsigned int i; if (list_empty_careful(&ctrl->list)) goto free_ctrl; @@ -2687,6 +2862,8 @@ static void nvme_tcp_free_ctrl(struct nvme_ctrl *nctrl) nvmf_free_options(nctrl->opts); free_ctrl: put_net(ctrl->net); + for (i = 0; i < nr_queues; i++) + nvme_tcp_exit_queue(ctrl, i); kfree(ctrl->queues); kfree(ctrl); } @@ -2939,17 +3116,18 @@ static int nvme_tcp_get_address(struct nvme_ctrl *ctrl, char *buf, int size) len = nvmf_get_address(ctrl, buf, size); - if (!test_bit(NVME_TCP_Q_LIVE, &queue->flags)) - return len; - mutex_lock(&queue->queue_lock); - ret = kernel_getsockname(queue->sock, (struct sockaddr *)&src_addr); - if (ret > 0) { - if (len > 0) - len--; /* strip trailing newline */ - len += scnprintf(buf + len, size - len, "%ssrc_addr=%pISc\n", - (len) ? "," : "", &src_addr); + if (test_bit(NVME_TCP_Q_LIVE, &queue->flags)) { + ret = kernel_getsockname(queue->sock, + (struct sockaddr *)&src_addr); + if (ret > 0) { + if (len > 0) + len--; /* strip trailing newline */ + len += scnprintf(buf + len, size - len, + "%ssrc_addr=%pISc\n", + (len) ? "," : "", &src_addr); + } } mutex_unlock(&queue->queue_lock); @@ -3015,7 +3193,7 @@ static struct nvme_tcp_ctrl *nvme_tcp_alloc_ctrl(struct device *dev, struct nvmf_ctrl_options *opts) { struct nvme_tcp_ctrl *ctrl; - int ret; + int ret, i; ctrl = kzalloc_obj(*ctrl); if (!ctrl) @@ -3026,8 +3204,7 @@ static struct nvme_tcp_ctrl *nvme_tcp_alloc_ctrl(struct device *dev, */ context_unsafe(INIT_LIST_HEAD(&ctrl->list)); ctrl->ctrl.opts = opts; - ctrl->ctrl.queue_count = opts->nr_io_queues + opts->nr_write_queues + - opts->nr_poll_queues + 1; + ctrl->ctrl.queue_count = NVME_TCP_OPT_NR_QUEUES(opts); ctrl->ctrl.sqsize = opts->queue_size - 1; ctrl->ctrl.kato = opts->kato; @@ -3085,8 +3262,10 @@ static struct nvme_tcp_ctrl *nvme_tcp_alloc_ctrl(struct device *dev, goto out_free_ctrl; } - ctrl->net = get_net(current->nsproxy->net_ns); + for (i = 0; i < ctrl->ctrl.queue_count; i++) + nvme_tcp_init_queue(ctrl, i); + ctrl->net = get_net(current->nsproxy->net_ns); ret = nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_tcp_ctrl_ops, 0); if (ret) goto out_kfree_queues; diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c index 1680e5e6839c..574025730834 100644 --- a/drivers/nvme/target/auth.c +++ b/drivers/nvme/target/auth.c @@ -237,6 +237,7 @@ void nvmet_auth_sq_free(struct nvmet_sq *sq) sq->dhchap_c2 = NULL; kfree(sq->dhchap_skey); sq->dhchap_skey = NULL; + sq->dhchap_skey_len = 0; } void nvmet_auth_sq_destroy(struct nvmet_sq *sq) diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index 8aea64d279c4..b3a5242d06f9 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -387,10 +387,15 @@ static ssize_t nvmet_addr_trtype_store(struct config_item *item, const char *page, size_t count) { struct nvmet_port *port = to_nvmet_port(item); + ssize_t ret = count; int i; - if (nvmet_is_port_enabled(port, __func__)) - return -EACCES; + down_write(&nvmet_config_sem); + + if (nvmet_is_port_enabled(port, __func__)) { + ret = -EACCES; + goto out; + } for (i = 0; i < ARRAY_SIZE(nvmet_transport); i++) { if (sysfs_streq(page, nvmet_transport[i].name)) @@ -398,7 +403,8 @@ static ssize_t nvmet_addr_trtype_store(struct config_item *item, } pr_err("Invalid value '%s' for trtype\n", page); - return -EINVAL; + ret = -EINVAL; + goto out; found: memset(&port->disc_addr.tsas, 0, NVMF_TSAS_SIZE); @@ -407,7 +413,9 @@ static ssize_t nvmet_addr_trtype_store(struct config_item *item, nvmet_port_init_tsas_rdma(port); else if (port->disc_addr.trtype == NVMF_TRTYPE_TCP) nvmet_port_init_tsas_tcp(port, NVMF_TCP_SECTYPE_NONE); - return count; +out: + up_write(&nvmet_config_sem); + return ret; } CONFIGFS_ATTR(nvmet_, addr_trtype); @@ -1783,8 +1791,10 @@ static ssize_t nvmet_subsys_attr_qid_max_store(struct config_item *item, subsys->max_qid = qid_max; /* Force reconnect */ + mutex_lock(&subsys->lock); list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) ctrl->ops->delete_ctrl(ctrl); + mutex_unlock(&subsys->lock); up_write(&nvmet_config_sem); return cnt; @@ -2104,7 +2114,9 @@ static void nvmet_port_release(struct config_item *item) /* Let inflight controllers teardown complete */ flush_workqueue(nvmet_wq); + down_write(&nvmet_config_sem); list_del(&port->global_entry); + up_write(&nvmet_config_sem); key_put(port->keyring); kfree(port); @@ -2165,8 +2177,6 @@ static struct config_group *nvmet_ports_make(struct config_group *group, port->ana_state[i] = NVME_ANA_INACCESSIBLE; } - list_add(&port->global_entry, &nvmet_ports_list); - INIT_LIST_HEAD(&port->entry); INIT_LIST_HEAD(&port->subsystems); INIT_LIST_HEAD(&port->referrals); @@ -2200,6 +2210,10 @@ static struct config_group *nvmet_ports_make(struct config_group *group, configfs_add_default_group(&port->ana_default_group.group, &port->ana_groups_group); + down_write(&nvmet_config_sem); + list_add(&port->global_entry, &nvmet_ports_list); + up_write(&nvmet_config_sem); + return &port->group; } diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 8353950f346f..a8171b88035c 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -393,11 +393,13 @@ void nvmet_disable_port(struct nvmet_port *port) lockdep_assert_held(&nvmet_config_sem); - port->enabled = false; - port->tr_ops = NULL; + if (!port->enabled) + return; - ops = nvmet_transports[port->disc_addr.trtype]; + ops = port->tr_ops; + port->enabled = false; ops->remove_port(port); + port->tr_ops = NULL; module_put(ops->owner); } @@ -1101,6 +1103,9 @@ static u32 nvmet_io_cmd_transfer_len(struct nvmet_req *req) case nvme_cmd_dsm: return nvmet_dsm_len(req); case nvme_cmd_zone_mgmt_recv: + /* The handler rejects a NUMD whose byte count would wrap. */ + if (le32_to_cpu(req->cmd->zmr.numd) >= U32_MAX / 4) + return 0; return (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2; default: return 0; @@ -1362,7 +1367,7 @@ int nvmet_req_alloc_sgls(struct nvmet_req *req) return 0; out_free: - sgl_free(req->sg); + nvmet_req_free_sgls(req); out: return -ENOMEM; } @@ -1823,6 +1828,9 @@ ssize_t nvmet_ctrl_host_traddr(struct nvmet_ctrl *ctrl, { if (!ctrl->ops->host_traddr) return -EOPNOTSUPP; + /* They all take the address from the admin queue */ + if (!ctrl->sqs[0]) + return -ENOTCONN; return ctrl->ops->host_traddr(ctrl, traddr, traddr_len); } diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c index 1fe21f2672f1..70136f6c22e8 100644 --- a/drivers/nvme/target/fabrics-cmd-auth.c +++ b/drivers/nvme/target/fabrics-cmd-auth.c @@ -330,6 +330,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req) /* Restart negotiation */ pr_debug("%s: ctrl %d qid %d reset negotiation\n", __func__, ctrl->cntlid, req->sq->qid); + nvmet_auth_sq_free(req->sq); if (!req->sq->qid) { dhchap_status = nvmet_setup_auth(ctrl, req->sq, true); @@ -344,8 +345,9 @@ void nvmet_execute_auth_send(struct nvmet_req *req) } req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE; - } else if (data->auth_id != req->sq->dhchap_step) + } else { goto done_failure1; + } /* Validate negotiation parameters */ dhchap_status = nvmet_auth_negotiate(req, d, tl); if (dhchap_status == 0) @@ -605,10 +607,11 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) switch (req->sq->dhchap_step) { case NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE: if (nvmet_auth_challenge(req, d, al) < 0) { - pr_warn("ctrl %d qid %d: challenge error (%d)\n", - ctrl->cntlid, req->sq->qid, status); + pr_warn("ctrl %d qid %d: challenge error\n", + ctrl->cntlid, req->sq->qid); status = NVME_SC_INTERNAL; - break; + kfree(d); + goto done; } req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_REPLY; break; diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c index b451029ab8f4..fc626c2fd2c9 100644 --- a/drivers/nvme/target/fabrics-cmd.c +++ b/drivers/nvme/target/fabrics-cmd.c @@ -186,8 +186,7 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req) pr_warn("queue size zero!\n"); req->error_loc = offsetof(struct nvmf_connect_command, sqsize); req->cqe->result.u32 = IPO_IATTR_CONNECT_SQE(sqsize); - ret = NVME_SC_CONNECT_INVALID_PARAM | NVME_STATUS_DNR; - goto err; + return NVME_SC_CONNECT_INVALID_PARAM | NVME_STATUS_DNR; } if (ctrl->sqs[qid] != NULL) { diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index eecdffefa24f..2b7dc3f03912 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -1708,7 +1708,7 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, be16_to_cpu(rqst->assoc_cmd.sqsize)); if (!queue) { ret = VERR_QUEUE_ALLOC_FAIL; - nvmet_fc_tgt_a_put(iod->assoc); + nvmet_fc_schedule_delete_assoc(iod->assoc); } } } @@ -1799,9 +1799,6 @@ nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, be16_to_cpu(rqst->connect_cmd.sqsize)); if (!queue) ret = VERR_QUEUE_ALLOC_FAIL; - - /* release get taken in nvmet_fc_find_target_assoc */ - nvmet_fc_tgt_a_put(iod->assoc); } } @@ -1815,6 +1812,8 @@ nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, FCNVME_RJT_RC_INV_ASSOC : FCNVME_RJT_RC_LOGIC, FCNVME_RJT_EXP_NONE, 0); + if (iod->assoc) + nvmet_fc_tgt_a_put(iod->assoc); return; } @@ -1836,6 +1835,9 @@ nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, acc->connectid.connection_id = cpu_to_be64(nvmet_fc_makeconnid(iod->assoc, be16_to_cpu(rqst->connect_cmd.qid))); + + /* release get taken in nvmet_fc_find_target_assoc */ + nvmet_fc_tgt_a_put(iod->assoc); } /* @@ -2487,11 +2489,11 @@ __nvmet_fc_fcp_nvme_cmd_done(struct nvmet_fc_tgtport *tgtport, } else { /* - * try to push the data even if the SQE status is non-zero. - * There may be a status where data still was intended to - * be moved + * A failed command may not have filled its read buffer, so + * only push data for success, as the tcp and rdma targets do. */ - if ((fod->io_dir == NVMET_FCP_READ) && (fod->data_sg_cnt)) { + if (fod->io_dir == NVMET_FCP_READ && fod->data_sg_cnt && + !cqe->status) { /* push the data over before sending rsp */ nvmet_fc_transfer_fcp_data(tgtport, fod, NVMET_FCOP_READDATA); diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c index f2d9e8901df4..72618dced191 100644 --- a/drivers/nvme/target/io-cmd-bdev.c +++ b/drivers/nvme/target/io-cmd-bdev.c @@ -316,7 +316,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) &prot_miter); if (unlikely(rc)) { bio_io_error(bio); - return; + goto out_plug; } } @@ -336,11 +336,12 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) rc = nvmet_bdev_alloc_bip(req, bio, &prot_miter); if (unlikely(rc)) { bio_io_error(bio); - return; + goto out_plug; } } submit_bio(bio); +out_plug: blk_finish_plug(&plug); } @@ -389,7 +390,8 @@ static void nvmet_bdev_execute_discard(struct nvmet_req *req) if (status) break; - nr_sects = le32_to_cpu(range.nlb) << (ns->blksize_shift - 9); + nr_sects = (sector_t)le32_to_cpu(range.nlb) << + (ns->blksize_shift - 9); __blkdev_issue_discard(ns->bdev, nvmet_lba_to_sect(ns, range.slba), nr_sects, GFP_KERNEL, &bio); diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c index fcb1f8186fdd..e579a307798b 100644 --- a/drivers/nvme/target/loop.c +++ b/drivers/nvme/target/loop.c @@ -221,8 +221,6 @@ static int nvme_loop_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, struct nvme_loop_ctrl *ctrl = to_loop_ctrl(data); struct nvme_loop_queue *queue = &ctrl->queues[hctx_idx + 1]; - BUG_ON(hctx_idx >= ctrl->ctrl.queue_count); - /* * flush_end_io() can be called recursively for us, so use our own * lock class key for avoiding lockdep possible recursive locking, diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 9cec19e6f485..d7804bf91aaa 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -959,7 +959,8 @@ static inline void nvmet_req_bio_put(struct nvmet_req *req, struct bio *bio) #ifdef CONFIG_NVME_TARGET_TCP_TLS static inline key_serial_t nvmet_queue_tls_keyid(struct nvmet_sq *sq) { - return sq->tls_key ? key_serial(sq->tls_key) : 0; + /* A PCI endpoint controller is created without a queue */ + return sq && sq->tls_key ? key_serial(sq->tls_key) : 0; } static inline void nvmet_sq_put_tls_key(struct nvmet_sq *sq) { diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c index c683450df422..a8df176c1a57 100644 --- a/drivers/nvme/target/pci-epf.c +++ b/drivers/nvme/target/pci-epf.c @@ -1073,10 +1073,22 @@ static int nvmet_pci_epf_iod_parse_sgl_segments(struct nvmet_pci_epf_ctrl *ctrl, return 0; } +static u64 nvmet_pci_epf_iod_data_segs_len(struct nvmet_pci_epf_iod *iod) +{ + u64 len = 0; + int i; + + for (i = 0; i < iod->nr_data_segs; i++) + len += iod->data_segs[i].length; + + return len; +} + static int nvmet_pci_epf_iod_parse_sgls(struct nvmet_pci_epf_iod *iod) { struct nvmet_pci_epf_ctrl *ctrl = iod->ctrl; struct nvme_sgl_desc *sgl = &iod->cmd.common.dptr.sgl; + int ret; if (sgl->type == (NVME_SGL_FMT_DATA_DESC << 4)) { /* Single data descriptor case. */ @@ -1084,10 +1096,23 @@ static int nvmet_pci_epf_iod_parse_sgls(struct nvmet_pci_epf_iod *iod) iod->data_segs = &iod->data_seg; iod->data_seg.pci_addr = le64_to_cpu(sgl->addr); iod->data_seg.length = le32_to_cpu(sgl->length); - return 0; + } else { + ret = nvmet_pci_epf_iod_parse_sgl_segments(ctrl, iod); + if (ret) + return ret; } - return nvmet_pci_epf_iod_parse_sgl_segments(ctrl, iod); + /* + * The command executes on data_len bytes, but each segment is + * allocated and transferred in full, so they must describe exactly + * data_len bytes. + */ + if (nvmet_pci_epf_iod_data_segs_len(iod) != iod->data_len) { + iod->status = NVME_SC_SGL_INVALID_DATA | NVME_STATUS_DNR; + return -EINVAL; + } + + return 0; } static int nvmet_pci_epf_alloc_iod_data_buf(struct nvmet_pci_epf_iod *iod) @@ -1152,7 +1177,6 @@ static void nvmet_pci_epf_complete_iod(struct nvmet_pci_epf_iod *iod) unsigned long flags; /* Print an error message for failed commands, except AENs. */ - iod->status = le16_to_cpu(iod->cqe.status) >> 1; if (iod->status && iod->cmd.common.opcode != nvme_admin_async_event) dev_err(iod->ctrl->dev, "CQ[%d]: Command %s (0x%x) status 0x%0x\n", diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index ffa1e172c259..b9e39d1657d2 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -513,7 +513,9 @@ static int nvmet_rdma_post_recv(struct nvmet_rdma_device *ndev, static void nvmet_rdma_process_wr_wait_list(struct nvmet_rdma_queue *queue) { - spin_lock(&queue->rsp_wr_wait_lock); + unsigned long flags; + + spin_lock_irqsave(&queue->rsp_wr_wait_lock, flags); while (!list_empty(&queue->rsp_wr_wait_list)) { struct nvmet_rdma_rsp *rsp; bool ret; @@ -522,16 +524,16 @@ static void nvmet_rdma_process_wr_wait_list(struct nvmet_rdma_queue *queue) struct nvmet_rdma_rsp, wait_list); list_del(&rsp->wait_list); - spin_unlock(&queue->rsp_wr_wait_lock); + spin_unlock_irqrestore(&queue->rsp_wr_wait_lock, flags); ret = nvmet_rdma_execute_command(rsp); - spin_lock(&queue->rsp_wr_wait_lock); + spin_lock_irqsave(&queue->rsp_wr_wait_lock, flags); if (!ret) { list_add(&rsp->wait_list, &queue->rsp_wr_wait_list); break; } } - spin_unlock(&queue->rsp_wr_wait_lock); + spin_unlock_irqrestore(&queue->rsp_wr_wait_lock, flags); } static u16 nvmet_rdma_check_pi_status(struct ib_mr *sig_mr) @@ -801,7 +803,10 @@ static void nvmet_rdma_write_data_done(struct ib_cq *cq, struct ib_wc *wc) if (unlikely(wc->status != IB_WC_SUCCESS)) { nvmet_rdma_rw_ctx_destroy(rsp); - nvmet_req_uninit(&rsp->req); + /* + * Unlike in nvmet_rdma_read_data_done(), the request has been + * completed and its references are put: no nvmet_req_uninit(). + */ nvmet_rdma_release_rsp(rsp); if (wc->status != IB_WC_WR_FLUSH_ERR) { pr_info("RDMA WRITE for CQE failed with status %s (%d).\n", @@ -864,7 +869,8 @@ static u16 nvmet_rdma_map_sgl_inline(struct nvmet_rdma_rsp *rsp) return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; } - if (off + len > rsp->queue->dev->inline_data_size) { + if (off > (u64)rsp->queue->dev->inline_data_size || + len > (u64)rsp->queue->dev->inline_data_size - off) { pr_err("invalid inline data offset!\n"); return NVME_SC_SGL_INVALID_OFFSET | NVME_STATUS_DNR; } @@ -976,6 +982,7 @@ static bool nvmet_rdma_execute_command(struct nvmet_rdma_rsp *rsp) static void nvmet_rdma_handle_command(struct nvmet_rdma_queue *queue, struct nvmet_rdma_rsp *cmd) { + unsigned long flags; u16 status; ib_dma_sync_single_for_cpu(queue->dev->device, @@ -993,9 +1000,9 @@ static void nvmet_rdma_handle_command(struct nvmet_rdma_queue *queue, goto out_err; if (unlikely(!nvmet_rdma_execute_command(cmd))) { - spin_lock(&queue->rsp_wr_wait_lock); + spin_lock_irqsave(&queue->rsp_wr_wait_lock, flags); list_add_tail(&cmd->wait_list, &queue->rsp_wr_wait_list); - spin_unlock(&queue->rsp_wr_wait_lock); + spin_unlock_irqrestore(&queue->rsp_wr_wait_lock, flags); } return; @@ -1412,7 +1419,7 @@ nvmet_rdma_parse_cm_connect_req(struct rdma_conn_param *conn, struct nvme_rdma_cm_req *req; req = (struct nvme_rdma_cm_req *)conn->private_data; - if (!req || conn->private_data_len == 0) + if (!req || conn->private_data_len < sizeof(*req)) return NVME_RDMA_CM_INVALID_LEN; if (le16_to_cpu(req->recfmt) != NVME_RDMA_CM_FMT_1_0) @@ -2150,6 +2157,12 @@ static void __exit nvmet_rdma_exit(void) { nvmet_unregister_transport(&nvmet_rdma_ops); ib_unregister_client(&nvmet_rdma_ib_client); + /* + * nvmet_rdma_remove_one() does not flush for a device that has left + * device_list, and the release work that took it off still has to + * return from nvmet_rdma_free_dev(). + */ + flush_workqueue(nvmet_wq); WARN_ON_ONCE(!list_empty(&nvmet_rdma_queue_list)); ida_destroy(&nvmet_rdma_queue_ida); } diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index c38ea3501ea5..8092ce4914b6 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -6,6 +6,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include +#include #include #include #include @@ -76,8 +77,24 @@ MODULE_PARM_DESC(idle_poll_period_usecs, /* * TLS handshake timeout */ -static int tls_handshake_timeout = 10; -module_param(tls_handshake_timeout, int, 0644); +static unsigned int tls_handshake_timeout = 10; + +static int tls_handshake_timeout_set(const char *val, + const struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, 0, + min_t(unsigned long, UINT_MAX / MSEC_PER_SEC, + MAX_JIFFY_OFFSET / HZ)); +} + +static const struct kernel_param_ops tls_handshake_timeout_ops = { + .set = tls_handshake_timeout_set, + .get = param_get_uint, +}; + +module_param_cb(tls_handshake_timeout, &tls_handshake_timeout_ops, + &tls_handshake_timeout, 0644); +__MODULE_PARM_TYPE(tls_handshake_timeout, "uint"); MODULE_PARM_DESC(tls_handshake_timeout, "nvme TLS handshake timeout in seconds (default 10)"); #endif @@ -149,6 +166,7 @@ enum nvmet_tcp_queue_state { struct nvmet_tcp_queue { struct socket *sock; struct nvmet_tcp_port *port; + struct nvmet_port *nport; struct work_struct io_work; struct nvmet_cq nvme_cq; struct nvmet_sq nvme_sq; @@ -1495,7 +1513,7 @@ static int nvmet_tcp_alloc_cmd(struct nvmet_tcp_queue *queue, u8 hdgst = nvmet_tcp_hdgst_len(queue); c->queue = queue; - c->req.port = queue->port->nport; + c->req.port = queue->nport; c->cmd_pdu = page_frag_alloc(&queue->pf_cache, sizeof(*c->cmd_pdu) + hdgst, GFP_KERNEL | __GFP_ZERO); @@ -1904,6 +1922,7 @@ static int nvmet_tcp_tls_handshake(struct nvmet_tcp_queue *queue) { int ret = -EOPNOTSUPP; struct tls_handshake_args args; + unsigned int timeout = READ_ONCE(tls_handshake_timeout); if (queue->state != NVMET_TCP_Q_TLS_HANDSHAKE) { pr_warn("cannot start TLS in state %d\n", queue->state); @@ -1917,7 +1936,7 @@ static int nvmet_tcp_tls_handshake(struct nvmet_tcp_queue *queue) args.ta_done = nvmet_tcp_tls_handshake_done; args.ta_data = queue; args.ta_keyring = key_serial(queue->port->nport->keyring); - args.ta_timeout_ms = tls_handshake_timeout * 1000; + args.ta_timeout_ms = timeout * MSEC_PER_SEC; ret = tls_server_hello_psk(&args, GFP_KERNEL); if (ret) { @@ -1925,7 +1944,7 @@ static int nvmet_tcp_tls_handshake(struct nvmet_tcp_queue *queue) pr_err("failed to start TLS, err=%d\n", ret); } else { queue_delayed_work(nvmet_wq, &queue->tls_handshake_tmo_work, - tls_handshake_timeout * HZ); + (unsigned long)timeout * HZ); } return ret; } @@ -1951,6 +1970,8 @@ static void nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port, kref_init(&queue->kref); queue->sock = newsock; queue->port = port; + /* The port may be gone when the commands are allocated */ + queue->nport = port->nport; queue->nr_cmds = 0; spin_lock_init(&queue->state_lock); if (queue->port->nport->disc_addr.tsas.tcp.sectype == @@ -2173,6 +2194,8 @@ static void nvmet_tcp_remove_port(struct nvmet_port *nport) port->sock->sk->sk_data_ready = port->data_ready; port->sock->sk->sk_user_data = NULL; write_unlock_bh(&port->sock->sk->sk_callback_lock); + /* The accept work goes on for as long as there is something to accept */ + kernel_sock_shutdown(port->sock, SHUT_RDWR); cancel_work_sync(&port->accept_work); /* * Destroy the remaining queues, which are not belong to any diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c index 78d82b6ff121..92f5c1435582 100644 --- a/drivers/nvme/target/zns.c +++ b/drivers/nvme/target/zns.c @@ -322,9 +322,17 @@ static void nvmet_bdev_zone_zmgmt_recv_work(struct work_struct *w) void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req) { - u32 out_bufsize = (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2; + u32 numd = le32_to_cpu(req->cmd->zmr.numd); - if (!nvmet_check_transfer_len(req, out_bufsize)) + /* From U32_MAX / 4 up, (numd + 1) << 2 wraps here and in the work. */ + if (numd >= U32_MAX / 4) { + req->error_loc = offsetof(struct nvme_zone_mgmt_recv_cmd, numd); + nvmet_req_complete(req, + NVME_SC_INVALID_FIELD | NVME_STATUS_DNR); + return; + } + + if (!nvmet_check_transfer_len(req, (numd + 1) << 2)) return; INIT_WORK(&req->z.zmgmt_work, nvmet_bdev_zone_zmgmt_recv_work);