[PATCH v2 2/2] nvme-tcp: parallelize I/O queue allocation and startup

Sagi Grimberg sagi at grimberg.me
Sun Aug 30 15:00:52 PDT 2026



On 25/08/2026 1:56, Surabhi Gogte wrote:
> Similar to commit 2a8513091d2f ("nvme-rdma: parallelize I/O queue
> allocation and startup"), refactor nvme tcp I/O queue setup to use async
> API, combining allocation and startup into a single parallel operation
> per queue. This reduces connection and reconnection setup time when
> there are delays in establishing connections, which is especially
> important for high-core-count hosts.
>
> Key changes:
> - Use async API to facilitate parallel calls for io queue setup.
> - Add nvme_tcp_setup_ctx for propagating errors from async workers.
> - Remove nvme_tcp_start_io_queues() and __nvme_tcp_alloc_io_queues();
>    their logic is folded into nvme_tcp_setup_io_queues() and
>    nvme_tcp_configure_io_queues().
> - Allocate the io tag set before the queues so that the queue range is
>    known, and only set up the reconnect grow case if the queue count
>    actually increased.
> - Serialize the cpu scan and claim in nvme_tcp_set_queue_io_cpu() with a
>    spinlock, as concurrent callers would otherwise select the same cpu.
>    The per-cpu counters no longer need to be atomics.
> - Use init_net in nvme_tcp_alloc_queue() instead of the namespace of
>    current, which is no longer the connecting task once the allocation
>    runs from a worker. A controller is not guaranteed to be tied to a
>    namespace, as the reconnect and error recovery paths already run from
>    a workqueue in init_net.

Well, I think this is breaking 1be52169c3488ef98582ed553ab35cefa3978817

>
> Testing on a 64-core host with 64 IO-queues shows nvme-tcp connection
> time reduced from 61ms to 11ms.
>
> Signed-off-by: Surabhi Gogte <sgogte at purestorage.com>
> ---
>   drivers/nvme/host/tcp.c | 126 +++++++++++++++++++++++++---------------
>   1 file changed, 80 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
> index 354668ad29ac..30fe4c5abe0b 100644
> --- a/drivers/nvme/host/tcp.c
> +++ b/drivers/nvme/host/tcp.c
> @@ -7,6 +7,7 @@
>   #include <linux/module.h>
>   #include <linux/init.h>
>   #include <linux/slab.h>
> +#include <linux/async.h>
>   #include <linux/err.h>
>   #include <linux/crc32.h>
>   #include <linux/nvme-tcp.h>
> @@ -54,7 +55,8 @@ MODULE_PARM_DESC(tls_handshake_timeout,
>   		 "nvme TLS handshake timeout in seconds (default 10)");
>   #endif
>   
> -static atomic_t nvme_tcp_cpu_queues[NR_CPUS];
> +static int nvme_tcp_cpu_queues[NR_CPUS];
> +static DEFINE_SPINLOCK(nvme_tcp_cpu_queues_lock);
>   
>   enum nvme_tcp_send_state {
>   	NVME_TCP_SEND_CMD_PDU = 0,
> @@ -154,6 +156,12 @@ struct nvme_tcp_queue {
>   static DEFINE_MUTEX(nvme_tcp_ctrl_mutex);
>   static LIST_HEAD_GUARDED(nvme_tcp_ctrl_list, nvme_tcp_ctrl_mutex);
>   
> +struct nvme_tcp_setup_ctx {

nvme_tcp_queue_setup_ctx?

> +	struct nvme_ctrl	*ctrl;
> +	int			qid;
> +	int			*err;
> +};
> +
>   struct nvme_tcp_ctrl {
>   	/* read only in the hot path */
>   	struct nvme_tcp_queue	*queues;
> @@ -1718,9 +1726,10 @@ static void nvme_tcp_set_queue_io_cpu(struct nvme_tcp_queue *queue)
>   		goto out;
>   
>   	/* Search for the least used cpu from the mq_map */
> +	spin_lock(&nvme_tcp_cpu_queues_lock);
>   	io_cpu = WORK_CPU_UNBOUND;
>   	for_each_online_cpu(cpu) {
> -		int num_queues = atomic_read(&nvme_tcp_cpu_queues[cpu]);
> +		int num_queues = nvme_tcp_cpu_queues[cpu];
>   
>   		if (mq_map[cpu] != qid)
>   			continue;
> @@ -1731,9 +1740,10 @@ static void nvme_tcp_set_queue_io_cpu(struct nvme_tcp_queue *queue)
>   	}
>   	if (io_cpu != WORK_CPU_UNBOUND) {
>   		queue->io_cpu = io_cpu;
> -		atomic_inc(&nvme_tcp_cpu_queues[io_cpu]);
> +		nvme_tcp_cpu_queues[io_cpu]++;
>   		set_bit(NVME_TCP_Q_IO_CPU_SET, &queue->flags);
>   	}
> +	spin_unlock(&nvme_tcp_cpu_queues_lock);
>   out:
>   	dev_dbg(ctrl->ctrl.device, "queue %d: using cpu %d\n",
>   		qid, queue->io_cpu);
> @@ -1846,7 +1856,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,
>   		queue->cmnd_capsule_len = sizeof(struct nvme_command) +
>   						NVME_TCP_ADMIN_CCSZ;
>   
> -	ret = sock_create_kern(current->nsproxy->net_ns,
> +	ret = sock_create_kern(&init_net,

I don't think we can just change this...



More information about the Linux-nvme mailing list