From: Nilay Shroff <nilay@linux.ibm.com>
To: Sagi Grimberg <sagi@grimberg.me>,
Saravanan D <saravanand@crusoe.ai>,
linux-nvme@lists.infradead.org
Cc: kbusch@kernel.org, hch@lst.de, axboe@kernel.dk, dwagner@suse.de,
linux-kernel@vger.kernel.org, iyamahata@crusoe.ai,
kiyer@crusoe.ai, ganbalagane@crusoe.ai, sj@kernel.org
Subject: Re: [PATCH v3] nvme-tcp: allow setting per-queue io_cpu through sysfs
Date: Sat, 12 Sep 2026 17:09:27 +0530 [thread overview]
Message-ID: <1c62cb9b-8c8a-4272-8366-4c10e85ea01d@linux.ibm.com> (raw)
In-Reply-To: <13c160d0-0657-47ce-9a16-58d348267ab0@grimberg.me>
On 9/12/26 2:41 AM, Sagi Grimberg wrote:
>
>
> On 10/09/2026 0:14, Saravanan D wrote:
>> nvme_tcp_set_queue_io_cpu() picks each queue's io_cpu at connect time
>> as the least loaded CPU in the queue's blk-mq map group, and all socket
>> work runs there for the connection's lifetime. This decision falls
>> short when the host partitions its CPUs after connect time. On a 384
>> cpu multi tenant host with 128 queue controllers, blk-mq folds three
>> CPUs into every map group, some groups straddle two tenants' cpusets,
>> and 9% of nvme_tcp_io_work executions ran outside the submitting VM's
>> cpuset, seen by the neighbor as steal time.
>>
>> Expose each I/O queue's io_cpu as a writable sysfs attribute
>>
>> /sys/class/nvme/nvmeX/tcp_queues/<qid>/io_cpu
>>
>> so a control plane that owns CPU placement can set it directly instead
>> of relying on the driver's heuristic. A written value persists across
>> reconnects, marked by NVME_TCP_Q_IO_CPU_USER. Writing -1 clears the
>> mark and re-runs the connect time selection. Reading returns the CPU,
>> or -1 when the queue is unbound.
>
> No need for NVME_TCP_Q_IO_CPU_USER flag and restoring to the original connect time selection. -1 would mean WORK_CPU_UNBOUND. In fact lets allow this file to access "unbound" string (same as -1). I don't think we need to restore the connect time selection, the user who touches these settings is obviously interested to be in control.
>>
>> The store, the connect time selection and queue stop serialize their
>> accounting of nvme_tcp_cpu_queues under the queue lock.
>
> I think that the queue accounting is something we'd do anyways, regardless of how the
> queue is set. It just represents the io_cpu spread across cpu cores.
>
>>
>> Suggested-by: Sagi Grimberg <sagi@grimberg.me>
>> Link: https://lore.kernel.org/linux-nvme/220e9da3-f756-4a16-8de1-d4b171f15009@grimberg.me/
>> Assisted-by: Claude:claude-opus-4-8 [Claude Code]
>> Signed-off-by: Saravanan D <saravanand@crusoe.ai>
>> ---
>> Changes since v2 [1]:
>> - Replaced the io_cpu_adopt connect option and the submitter adoption
>> heuristic with a per queue writable sysfs attribute, following Sagi's
>> suggestion [2]. The control plane now sets each queue's io_cpu
>> directly, the assignment is kept across reconnects and writing -1
>> reverts to the connect time selection.
>> - Retitled from "nvme-tcp: pin io_cpu to submitter cpu".
>>
>> The per queue directories follow the blk-mq mq/<hctx> sysfs pattern.
>>
>> Tested on a 2 socket 384 cpu host with 128 queue controllers. Writing
>> a cpu number changed the queue's io_cpu to it. Writing an invalid
>> value was rejected. Writing -1 re-ran the connect time selection.
>> Pinned queues kept their io_cpu across a controller reset while
>> unpinned queues received a fresh pick.
>>
>> The multiple queues per hctx RFC [3] found the same need to steer the
>> socket work cpu, so this attribute may gain a second user.
>>
>> [1] https://lore.kernel.org/linux-nvme/20260820083634.71689-1-saravanand@crusoe.ai/
>> [2] https://lore.kernel.org/linux-nvme/1d56144d-6987-40c1-ac02-b15333db121e@grimberg.me/
>> [3] https://lore.kernel.org/linux-nvme/20260903152623.614951-1-kbusch@meta.com/
>>
>> Documentation/ABI/stable/sysfs-nvme | 12 +++
>> drivers/nvme/host/tcp.c | 153 +++++++++++++++++++++++++++-
>> 2 files changed, 162 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/ABI/stable/sysfs-nvme b/Documentation/ABI/stable/sysfs-nvme
>> index a2f5d0710db4..2bbb5a0b7c2e 100644
>> --- a/Documentation/ABI/stable/sysfs-nvme
>> +++ b/Documentation/ABI/stable/sysfs-nvme
>> @@ -451,3 +451,15 @@ Contact: Hannes Reinecke <hare@suse.de>
>> Description:
>> Shows the subsystem type. Possible values: "discovery",
>> "nvm", "reserved".
>> +
>> +What: /sys/class/nvme/nvmeX/tcp_queues/<qid>/io_cpu
>> +Date: September 2026
>> +KernelVersion: 7.4
>> +Contact: Saravanan D <saravanand@crusoe.ai>
>> +Description:
>> + (RW) The CPU that runs the socket work for I/O queue <qid>
>> + of an NVMe over TCP controller, selected by the driver at
>> + connect time. Writing a CPU number overrides the selection
>> + and persists across reconnects. Writing -1 reverts to the
>> + driver's selection. Reads show the current CPU, or -1 when
>> + the queue is unbound.
>> diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
>> index 921934028e0b..22ad1fdf4a12 100644
>> --- a/drivers/nvme/host/tcp.c
>> +++ b/drivers/nvme/host/tcp.c
>> @@ -93,6 +93,7 @@ enum nvme_tcp_queue_flags {
>> NVME_TCP_Q_LIVE = 1,
>> NVME_TCP_Q_POLLING = 2,
>> NVME_TCP_Q_IO_CPU_SET = 3,
>> + NVME_TCP_Q_IO_CPU_USER = 4,
>> };
>> enum nvme_tcp_recv_state {
>> @@ -102,6 +103,17 @@ enum nvme_tcp_recv_state {
>> };
>> struct nvme_tcp_ctrl;
>> +struct nvme_tcp_queue;
>> +
>> +/*
>> + * Allocated per registration and freed by its kobject release, so a
>> + * reconnect never reuses a kobject whose release is still pending.
>> + */
>> +struct nvme_tcp_queue_kobj {
>> + struct kobject kobj;
>> + struct nvme_tcp_queue *queue;
>> +};
>
> I am wandering if it is time to introduce the core nvme queue:
> struct nvme_queue {
> struct kobject kobj;
> unsigned int qid;
> u64 flags;
> };
>
> And have the transport queue embed it:
> struct nvme_tcp_queue {
> struct nvme_queue nvmeq;
> ....
> };
>
> I suspect it will allow for better abstractions.
>
> Thoughts? Keith, Christoph?
Yes, agreed. I think having a common queue structure would provide
a better abstraction here. However, struct nvme_queue is already
used by the PCI driver for its transport-specific queue representation.
Perhaps we could name common structure as struct nvme_queue_info.
Thanks,
--Nilay
prev parent reply other threads:[~2026-09-12 11:39 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-09 21:14 Saravanan D
2026-09-10 8:25 ` Nilay Shroff
2026-09-11 6:03 ` Saravanan D
2026-09-11 20:58 ` Sagi Grimberg
2026-09-11 21:11 ` Sagi Grimberg
2026-09-12 11:39 ` Nilay Shroff [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1c62cb9b-8c8a-4272-8366-4c10e85ea01d@linux.ibm.com \
--to=nilay@linux.ibm.com \
--cc=axboe@kernel.dk \
--cc=dwagner@suse.de \
--cc=ganbalagane@crusoe.ai \
--cc=hch@lst.de \
--cc=iyamahata@crusoe.ai \
--cc=kbusch@kernel.org \
--cc=kiyer@crusoe.ai \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=sagi@grimberg.me \
--cc=saravanand@crusoe.ai \
--cc=sj@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®