[PATCH v5 2/2] nvme-tcp: allow setting per-queue io_cpu through sysfs

sashiko-bot at kernel.org sashiko-bot at kernel.org
Sat Oct 17 18:15:14 PDT 2026


Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] nvme-tcp: sysfs io_cpu exposed before nvme_tcp_set_queue_io_cpu() runs
--

commit e947efa489c70b4e98e2f6a3345b13b02a0aef83
Author: Saravanan D <saravanand at crusoe.ai>

nvme-tcp: allow setting per-queue io_cpu through sysfs

This commit exposes per-queue io_cpu and managed sysfs attributes under
/sys/class/nvme/nvmeX/queues/<qid>/ so userspace can view and override
the CPU placement for NVMe-TCP I/O queue socket work.

Link: https://lore.kernel.org/linux-nvme/13c160d0-0657-47ce-9a16-58d348267ab0@grimberg.me/

> diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
> index ec678ed07af8d..699997c0e8e24 100644
> --- a/drivers/nvme/host/tcp.c
> +++ b/drivers/nvme/host/tcp.c
[ ... ]
> @@ -1917,7 +2038,11 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,
>  
>  	queue->sock->sk->sk_allocation = GFP_ATOMIC;
>  	queue->sock->sk->sk_use_task_frag = false;
> -	queue->io_cpu = WORK_CPU_UNBOUND;
> +	/* no store races here, the lock is for the write helper */
> +	spin_lock(&nvme_tcp_cpu_queues_lock);
> +	if (!test_bit(NVME_TCP_Q_IO_CPU_USER, &queue->flags))
> +		nvme_tcp_queue_change_io_cpu(queue, WORK_CPU_UNBOUND);
> +	spin_unlock(&nvme_tcp_cpu_queues_lock);
>  	queue->request = NULL;
>  	queue->data_remaining = 0;
>  	queue->ddgst_remaining = 0;
> @@ -1985,6 +2110,9 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,
>  
>  	set_bit(NVME_TCP_Q_ALLOCATED, &queue->flags);
>  
> +	if (qid)
> +		nvme_tcp_add_queue_sysfs(queue);
> +
>  	return 0;

[Severity: Medium]
In nvme_tcp_setup_queue_async(), nvme_tcp_alloc_queue() runs before
nvme_tcp_start_queue(), where nvme_tcp_set_queue_io_cpu() is called:

nvme_tcp_setup_queue_async()
  nvme_tcp_alloc_queue()
    if (!test_bit(NVME_TCP_Q_IO_CPU_USER, &queue->flags))
      nvme_tcp_queue_change_io_cpu(queue, WORK_CPU_UNBOUND);
    ...
    nvme_tcp_add_queue_sysfs(queue);
  nvme_tcp_start_queue()
    if (idx) {
      nvme_tcp_set_queue_io_cpu(queue);
      ret = nvmf_connect_io_queue(nctrl, idx);
    }

Because nvme_tcp_add_queue_sysfs() publishes the sysfs attributes in
nvme_tcp_alloc_queue() before nvme_tcp_set_queue_io_cpu() runs in
nvme_tcp_start_queue(), can a userspace control plane reading io_cpu and
managed as soon as the queue directory appears observe io_cpu as -1
(unbound) with managed=1 even when wq_unbound is false?

Also, during parallel reconnects in nvme_tcp_setup_io_queues(), a queue
with NVME_TCP_Q_IO_CPU_USER set does not re-increment
nvme_tcp_cpu_queues[io_cpu] until it reaches nvme_tcp_set_queue_io_cpu()
after completing the blocking TCP, TLS, and ICReq handshakes in
nvme_tcp_alloc_queue(). If a driver-managed queue finishes its handshake
first, could nvme_tcp_set_queue_io_cpu() pick a CPU without accounting for
the user-assigned queue's load?

Would it make sense to either call nvme_tcp_set_queue_io_cpu() before
nvme_tcp_add_queue_sysfs() in nvme_tcp_alloc_queue(), or defer
nvme_tcp_add_queue_sysfs() until after nvme_tcp_set_queue_io_cpu() has
run?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261018010059.83120-1-saravanand@crusoe.ai?part=2



More information about the Linux-nvme mailing list