* Re: [PATCH net v1] vhost_net: fix sleeping with preempt-disabled in vhost_net_busy_poll()
From: Michael S. Tsirkin @ 2026-04-22 6:05 UTC (permalink / raw)
To: Kohei Enju
Cc: Jason Wang, Eugenio Pérez, kvm, virtualization, netdev,
syzbot+6985cb8e543ea90ba8ee
In-Reply-To: <20260422023026.81960-1-kohei@enjuk.jp>
On Wed, Apr 22, 2026 at 02:30:24AM +0000, Kohei Enju wrote:
> syzbot reported "sleeping function called from invalid context" in
> vhost_net_busy_poll().
>
> Commit 030881372460 ("vhost_net: basic polling support") introduced a
> busy-poll loop and preempt_{disable,enable}() around it, where each
> iteration calls a sleepable function inside the loop.
>
> The purpose of disabling preemption was to keep local_clock()-based
> timeout accounting on a single CPU, rather than as a requirement of
> busy-poll itself:
>
> https://lore.kernel.org/netdev/1448435489-5949-4-git-send-email-jasowang@redhat.com/T/#u
>
> Changes from RFC V1:
> ...
> - Disable preemption during busy looping to make sure local_clock()
> was correctly used.
>
> >From this perspective, migrate_disable() is sufficient here, so replace
> preempt_disable() with migrate_disable(), avoiding sleepable accesses
> from a preempt-disabled context.
>
> Fixes: 030881372460 ("vhost_net: basic polling support")
> Tested-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com
> Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/
> Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
> ---
> drivers/vhost/net.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index 80965181920c..c6536cad9c4f 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -560,7 +560,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
> busyloop_timeout = poll_rx ? rvq->busyloop_timeout:
> tvq->busyloop_timeout;
>
> - preempt_disable();
> + migrate_disable();
> endtime = busy_clock() + busyloop_timeout;
>
> while (vhost_can_busy_poll(endtime)) {
> @@ -577,7 +577,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
> cpu_relax();
> }
>
> - preempt_enable();
> + migrate_enable();
>
> if (poll_rx || sock_has_rx_data(sock))
> vhost_net_busy_poll_try_queue(net, vq);
> --
> 2.51.0
^ permalink raw reply
* Re: [PATCH 1/2] powerpc: Add a typos.toml file
From: Shrikanth Hegde @ 2026-04-22 6:33 UTC (permalink / raw)
To: Link Mauve, linuxppc-dev
Cc: Krzysztof Kozlowski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Herbert Xu, David S. Miller,
Juergen Gross, Ajay Kaher, Alexey Makhalov,
Broadcom internal kernel review list, Geoff Levand,
Mahesh J Salgaonkar, Oliver O'Halloran, Anatolij Gustschin,
Breno Leitão, Nayna Jain, Paulo Flabiano Smorigo,
Eric Biggers, Jason A. Donenfeld, Ard Biesheuvel, Thorsten Blum,
Thomas Huth, Jason Gunthorpe, David Hildenbrand, Alistair Popple,
Ritesh Harjani (IBM), Donet Tom, Andrew Morton,
Björn Töpel, Will Deacon, Lorenzo Stoakes (Oracle),
Paul Moore, Nam Cao, Alexander Gordeev, Sourabh Jain,
Hari Bathini, Srikar Dronamraju, Jiri Bohac,
Mike Rapoport (Microsoft), Jiri Slaby (SUSE), Greg Kroah-Hartman,
Andy Shevchenko, Ilpo Järvinen, Kees Cook, Stephen Rothwell,
Xichao Zhao, Gautam Menghani, Peter Zijlstra, K Prateek Nayak,
Guangshuo Li, Li Chen, Aboorva Devarajan, Petr Mladek, Feng Tang,
Nysal Jan K.A., Aditya Gupta, Sayali Patil, Rohan McLure,
Pasha Tatashin, Yeoreum Yun, Kevin Brodsky,
Matthew Wilcox (Oracle), Andrew Donnellan, Vishal Moola (Oracle),
Thomas Weißschuh, Athira Rajeev, Kajol Jain, Thomas Gleixner,
Chen Ni, Haren Myneni, Jonathan Greental, Ingo Molnar,
Yury Norov (NVIDIA), Gaurav Batra, Nilay Shroff, Vivian Wang,
Adrian Barnaś, Rafael J. Wysocki (Intel), Thierry Reding,
Yury Norov, Mukesh Kumar Chaurasiya (IBM), Ruben Wauters,
linux-kernel, devicetree, linux-crypto, kvm, virtualization, x86
In-Reply-To: <215f12d6-62c1-4837-9f78-ef270684950c@kernel.org>
On 4/21/26 5:56 PM, Krzysztof Kozlowski wrote:
> On 21/04/2026 14:14, Link Mauve wrote:
>> This file is used by the typos tool[1] to determine which words to fix,
>> which ones not to fix, and what the target word should be.
>>
>> [1] https://github.com/crate-ci/typos
>>
>> Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
>
> This typos.toml file does not belong to the kernel, IMO, but that's up
> to PowerPC folks.
>
Right, Also there is nothing specific to arch/powerpc here.
IMO, This file should be part of the tool's repo. Not part of
arch/powerpc kernel tree.
^ permalink raw reply
* Re: [PATCH RFC v3 10/19] mm: remove arch vma_alloc_zeroed_movable_folio overrides
From: Geert Uytterhoeven @ 2026-04-22 6:54 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: linux-kernel, Andrew Morton, David Hildenbrand, Vlastimil Babka,
Brendan Jackman, Michal Hocko, Suren Baghdasaryan, Jason Wang,
Andrea Arcangeli, Gregory Price, linux-mm, virtualization,
Richard Henderson, Matt Turner, Magnus Lindholm, Greg Ungerer,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
linux-alpha, linux-m68k, linux-s390
In-Reply-To: <006f9142e591ba8c340c3b354aee76aec5c285b9.1776808210.git.mst@redhat.com>
On Wed, 22 Apr 2026 at 00:01, Michael S. Tsirkin <mst@redhat.com> wrote:
> Now that the generic vma_alloc_zeroed_movable_folio() uses
> __GFP_ZERO, the arch-specific macros on alpha, m68k, s390, and
> x86 that did the same thing are redundant. Remove them.
>
> arm64 is not affected: it has a real function override that
> handles MTE tag zeroing, not just __GFP_ZERO.
>
> Suggested-by: David Hildenbrand <david@kernel.org>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> arch/m68k/include/asm/page_no.h | 3 ---
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> # m68k
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH 1/2] powerpc: Add a typos.toml file
From: Andy Shevchenko @ 2026-04-22 7:13 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Link Mauve, linuxppc-dev, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Herbert Xu, David S. Miller,
Juergen Gross, Ajay Kaher, Alexey Makhalov,
Broadcom internal kernel review list, Geoff Levand,
Mahesh J Salgaonkar, Oliver O'Halloran, Anatolij Gustschin,
Breno Leitão, Nayna Jain, Paulo Flabiano Smorigo,
Eric Biggers, Jason A. Donenfeld, Ard Biesheuvel, Thorsten Blum,
Thomas Huth, Jason Gunthorpe, David Hildenbrand, Alistair Popple,
Ritesh Harjani (IBM), Donet Tom, Andrew Morton,
Björn Töpel, Will Deacon, Lorenzo Stoakes (Oracle),
Paul Moore, Nam Cao, Alexander Gordeev, Sourabh Jain,
Hari Bathini, Srikar Dronamraju, Shrikanth Hegde, Jiri Bohac,
Mike Rapoport (Microsoft), Jiri Slaby (SUSE), Greg Kroah-Hartman,
Ilpo Järvinen, Kees Cook, Stephen Rothwell, Xichao Zhao,
Gautam Menghani, Peter Zijlstra, K Prateek Nayak, Guangshuo Li,
Li Chen, Aboorva Devarajan, Petr Mladek, Feng Tang,
Nysal Jan K.A., Aditya Gupta, Sayali Patil, Rohan McLure,
Pasha Tatashin, Yeoreum Yun, Kevin Brodsky,
Matthew Wilcox (Oracle), Andrew Donnellan, Vishal Moola (Oracle),
Thomas Weißschuh, Athira Rajeev, Kajol Jain, Thomas Gleixner,
Chen Ni, Haren Myneni, Jonathan Greental, Ingo Molnar,
Yury Norov (NVIDIA), Gaurav Batra, Nilay Shroff, Vivian Wang,
Adrian Barnaś, Rafael J. Wysocki (Intel), Thierry Reding,
Yury Norov, Mukesh Kumar Chaurasiya (IBM), Ruben Wauters,
linux-kernel, devicetree, linux-crypto, kvm, virtualization, x86
In-Reply-To: <215f12d6-62c1-4837-9f78-ef270684950c@kernel.org>
On Tue, Apr 21, 2026 at 02:26:35PM +0200, Krzysztof Kozlowski wrote:
> On 21/04/2026 14:14, Link Mauve wrote:
> > This file is used by the typos tool[1] to determine which words to fix,
> > which ones not to fix, and what the target word should be.
It's a little too many people in Cc list...
> > [1] https://github.com/crate-ci/typos
You may do it as Link tag in a form of
Link: $URL [1]
> > Signed-off-by: Link Mauve <linkmauve@linkmauve.fr>
>
> This typos.toml file does not belong to the kernel, IMO, but that's up
> to PowerPC folks.
In kernel we use codespell. If we want to have another tool to welcome, we
need to setup infrastructure in parallel, so it will be `make` option with
the fixed name and choose the tool based on availability, et cetera.
> My note here is: please use your real, full name. See submitting patches.
+1.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH net] hv_sock: Return -EIO for malformed/short packets
From: Stefano Garzarella @ 2026-04-22 9:40 UTC (permalink / raw)
To: Dexuan Cui
Cc: kys, haiyangz, wei.liu, longli, davem, edumazet, kuba, pabeni,
horms, niuxuewei.nxw, linux-hyperv, virtualization, netdev,
linux-kernel, stable
In-Reply-To: <20260421174931.1152238-1-decui@microsoft.com>
On Tue, Apr 21, 2026 at 10:49:31AM -0700, Dexuan Cui wrote:
>Commit f63152958994 fixes a regression, however it fails to report an
>error for malformed/short packets -- normally we should never see such
>packets, but let's report an error for them just in case.
>
>Fixes: f63152958994 ("hv_sock: Report EOF instead of -EIO for FIN")
>Cc: stable@vger.kernel.org
>Signed-off-by: Dexuan Cui <decui@microsoft.com>
>---
>
>Commit f63152958994 is currently only in net.git's master branch.
>
> net/vmw_vsock/hyperv_transport.c | 29 +++++++++++++++++++----------
> 1 file changed, 19 insertions(+), 10 deletions(-)
>
>diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c
>index 76e78c83fdbc..8faaa14bccda 100644
>--- a/net/vmw_vsock/hyperv_transport.c
>+++ b/net/vmw_vsock/hyperv_transport.c
>@@ -704,18 +704,27 @@ static s64 hvs_stream_has_data(struct vsock_sock *vsk)
> if (hvs->recv_desc) {
> /* Here hvs->recv_data_len is 0, so hvs->recv_desc must
> * be NULL unless it points to the 0-byte-payload FIN
>- * packet: see hvs_update_recv_data().
>+ * packet or a malformed/short packet: see
>+ * hvs_update_recv_data().
> *
>- * Here all the payload has been dequeued, but
>- * hvs_channel_readable_payload() still returns 1,
>- * because the VMBus ringbuffer's read_index is not
>- * updated for the FIN packet: hvs_stream_dequeue() ->
>- * hv_pkt_iter_next() updates the cached priv_read_index
>- * but has no opportunity to update the read_index in
>- * hv_pkt_iter_close() as hvs_stream_has_data() returns
>- * 0 for the FIN packet, so it won't get dequeued.
>+ * If hvs->recv_desc points to the FIN packet, here all
>+ * the payload has been dequeued and the peer_shutdown
>+ * flag is set, but hvs_channel_readable_payload() still
>+ * returns 1, because the VMBus ringbuffer's read_index
>+ * is not updated for the FIN packet:
>+ * hvs_stream_dequeue() -> hv_pkt_iter_next() updates
>+ * the cached priv_read_index but has no opportunity to
>+ * update the read_index in hv_pkt_iter_close() as
>+ * hvs_stream_has_data() returns 0 for the FIN packet,
>+ * so it won't get dequeued.
>+ *
>+ * In case hvs->recv_desc points to a malformed/short
>+ * packet, return -EIO.
> */
>- return 0;
>+ if (hvs->vsk->peer_shutdown & SEND_SHUTDOWN)
We can access `vsk` directly, I mean `vsk->peer_shutdown`.
>+ return 0;
>+ else
nit: we usually avoid the `else` if the other branch returns early, and
maybe have the error returned first, so it's more clear when reading the
comment on top. I mean something like this:
if (!(vsk->peer_shutdown & SEND_SHUTDOWN))
return -EIO;
return 0;
BTW, not a strong opinion on that.
The rest, LGTM!
Thanks,
Stefano
^ permalink raw reply
* [RFC PATCH v3 0/4] virtio: add noirq system sleep PM callbacks for virtio-mmio
From: Sungho Bae @ 2026-04-22 13:10 UTC (permalink / raw)
To: mst, jasowang
Cc: xuanzhuo, eperezma, virtualization, linux-kernel, Sungho Bae
From: Sungho Bae <baver.bae@lge.com>
Hi all,
Some virtio-mmio based devices, such as virtio-clock or virtio-regulator,
must become operational before other devices have their regular PM restore
callbacks invoked, because those other devices depend on them.
Generally, PM framework provides the three phases (freeze, freeze_late,
freeze_noirq) for the system sleep sequence, and the corresponding resume
phases. But, virtio core only supports the normal freeze/restore phase,
so virtio drivers have no way to participate in the noirq phase, which runs
with IRQs disabled and is guaranteed to run before any normal-phase restore
callbacks.
This series adds the infrastructure and the virtio-mmio transport
wiring so that virtio drivers can implement freeze_noirq/restore_noirq
callbacks.
Design overview
===============
The noirq phase runs with device IRQ handlers disabled and must avoid
sleepable operations. The main constraints addressed are:
- might_sleep() in virtio_add_status() and virtio_features_ok().
- virtio_synchronize_cbs() in virtio_reset_device() (IRQs are already
quiesced).
- spin_lock_irq() in virtio_config_core_enable() (not safe to call
with interrupts already disabled).
- Memory allocation during vq setup (virtqueue_reinit_vring() reuses
existing buffers instead).
The series provides noirq-safe variants for each of these, plus a new
config_ops->reset_vqs() callback that lets the transport reprogram
queue registers without freeing/reallocating vring memory.
When a driver implements restore_noirq, the device bring-up (reset ->
ACKNOWLEDGE -> DRIVER -> finalize_features -> FEATURES_OK) happens in
the noirq phase. The subsequent normal-phase virtio_device_restore()
detects this and skips the redundant re-initialization.
Patch breakdown
===============
Patch 1 is a preparatory refactoring with no functional change.
Patches 2-3 add the core infrastructure. Patch 4 wires it up for
virtio-mmio.
1. virtio: separate PM restore and reset_done paths
Splits virtio_device_restore_priv() into independent
virtio_device_restore() and virtio_device_reset_done() paths,
using a shared virtio_device_reinit() helper. This is a pure
refactoring to make the restore path independently extensible
without complicating the boolean dispatch.
2. virtio_ring: export virtqueue_reinit_vring() for noirq restore
Adds a thin exported wrapper around the existing static
virtqueue_reset_split()/virtqueue_reset_packed() helpers, which
reset vring indices and descriptor state in place without any
memory allocation. This makes them usable from the transport's
reset_vqs() callback in noirq context.
3. virtio: add noirq system sleep PM infrastructure
Adds noirq-safe helpers (virtio_add_status_noirq,
virtio_features_ok_noirq, virtio_reset_device_noirq,
virtio_config_core_enable_noirq, virtio_device_ready_noirq) and
the freeze_noirq/restore_noirq driver callbacks plus the
config_ops->reset_vqs() transport hook. Modifies
virtio_device_restore() to skip bring-up when restore_noirq
already ran.
4. virtio-mmio: wire up noirq system sleep PM callbacks
Implements vm_reset_vqs() which iterates existing virtqueues,
reinitializes the vring state via virtqueue_reinit_vring(), and
reprograms the MMIO queue registers. Adds
virtio_mmio_freeze_noirq/virtio_mmio_restore_noirq and registers
them via SET_NOIRQ_SYSTEM_SLEEP_PM_OPS().
Testing
=======
Build-tested with arm64 cross-compilation.
(make ARCH=arm64 M=drivers/virtio)
Runtime-tested on an internal virtio-mmio platform with virtio-clock,
confirming that the clock device works well before other devices' normal
restore() callbacks run.
Questions for reviewers
=======================
- virtio_config_core_enable_noirq() is currently a separate helper
that duplicates the spin_lock logic, but it only differs from
virtio_config_core_enable() by the locking context.
Would it be better to merge them into a single function with irqsafe
locking, or is the current separate-helper approach acceptable?
- Should reset_vqs be a mandatory callback when restore_noirq is
used, or should the core silently skip vq re-initialization when
the vq list is empty (current behavior)?
- Some functions, such as get_status() and set_status(), are also used
in the noirq restore path. Therefore, it is assumed that drivers using
noirq callbacks have implemented these functions usable in the noirq
context.
Is the current implementation acceptable? Or is it necessary to create a
flag to indicate the driver supports them in the noirq context, or
have a separate noirq callback?
Changes
=======
v3:
virtio: separate PM restore and reset_done paths
- Refined restore flow to explicitly handle the no-driver case after
reinit, improving clarity and avoiding unnecessary driver-path
assumptions.
virtio_ring: export virtqueue_reinit_vring() for noirq restore
- Hardened virtqueue_reinit_vring() with stronger safety notes and
a runtime WARN_ON check to catch reinit with unexpected free-list
state.
virtio: add noirq system sleep PM infrastructure
- Added explicit noirq restore completion tracking noirq_restore_done
and updated PM sequencing to use it, plus early freeze_noirq
validation for missing reset_vqs support.
virtio-mmio: wire up noirq system sleep PM callbacks
- Updated virtio-mmio restore path to skip legacy GUEST_PAGE_SIZE
rewrite when noirq restore already completed.
v2:
virtio-mmio: wire up noirq system sleep PM callbacks
- The code that was duplicated in vm_setup_vq() and vm_reset_vqs() has
been moved to vm_active_vq() function.
Sungho Bae (4):
virtio: separate PM restore and reset_done paths
virtio_ring: export virtqueue_reinit_vring() for noirq restore
virtio: add noirq system sleep PM infrastructure
virtio-mmio: wire up noirq system sleep PM callbacks
drivers/virtio/virtio.c | 252 ++++++++++++++++++++++++++++++----
drivers/virtio/virtio_mmio.c | 133 ++++++++++++------
drivers/virtio/virtio_ring.c | 30 ++++
include/linux/virtio.h | 10 ++
include/linux/virtio_config.h | 29 ++++
include/linux/virtio_ring.h | 3 +
6 files changed, 391 insertions(+), 66 deletions(-)
--
2.43.0
^ permalink raw reply
* [RFC PATCH v3 1/4] virtio: separate PM restore and reset_done paths
From: Sungho Bae @ 2026-04-22 13:10 UTC (permalink / raw)
To: mst, jasowang
Cc: xuanzhuo, eperezma, virtualization, linux-kernel, Sungho Bae
In-Reply-To: <20260422131014.956-1-baver.bae@gmail.com>
From: Sungho Bae <baver.bae@lge.com>
Refactor virtio_device_restore_priv() by extracting the common device
re-initialization sequence into virtio_device_reinit(). This helper
performs the full bring-up sequence: reset, status acknowledgment,
feature finalization, and feature negotiation.
virtio_device_restore() and virtio_device_reset_done() now each call
virtio_device_reinit() directly instead of going through a boolean-
dispatched wrapper. This makes each path independently readable and
extensible without further complicating the dispatch logic.
A follow-up series will add noirq PM callbacks that only affect the
restore path; having the two paths separated avoids adding more
conditionals to a shared function.
No functional change.
Signed-off-by: Sungho Bae <baver.bae@lge.com>
---
drivers/virtio/virtio.c | 81 +++++++++++++++++++++++++----------------
1 file changed, 50 insertions(+), 31 deletions(-)
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index 5bdc6b82b30b..98f1875f8df1 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -588,7 +588,7 @@ void unregister_virtio_device(struct virtio_device *dev)
}
EXPORT_SYMBOL_GPL(unregister_virtio_device);
-static int virtio_device_restore_priv(struct virtio_device *dev, bool restore)
+static int virtio_device_reinit(struct virtio_device *dev)
{
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
int ret;
@@ -613,35 +613,9 @@ static int virtio_device_restore_priv(struct virtio_device *dev, bool restore)
ret = dev->config->finalize_features(dev);
if (ret)
- goto err;
-
- ret = virtio_features_ok(dev);
- if (ret)
- goto err;
-
- if (restore) {
- if (drv->restore) {
- ret = drv->restore(dev);
- if (ret)
- goto err;
- }
- } else {
- ret = drv->reset_done(dev);
- if (ret)
- goto err;
- }
-
- /* If restore didn't do it, mark device DRIVER_OK ourselves. */
- if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK))
- virtio_device_ready(dev);
-
- virtio_config_core_enable(dev);
-
- return 0;
+ return ret;
-err:
- virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
- return ret;
+ return virtio_features_ok(dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -668,7 +642,33 @@ EXPORT_SYMBOL_GPL(virtio_device_freeze);
int virtio_device_restore(struct virtio_device *dev)
{
- return virtio_device_restore_priv(dev, true);
+ struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
+ int ret;
+
+ ret = virtio_device_reinit(dev);
+ if (ret)
+ goto err;
+
+ if (!drv)
+ return 0;
+
+ if (drv->restore) {
+ ret = drv->restore(dev);
+ if (ret)
+ goto err;
+ }
+
+ /* If restore didn't do it, mark device DRIVER_OK ourselves. */
+ if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK))
+ virtio_device_ready(dev);
+
+ virtio_config_core_enable(dev);
+
+ return 0;
+
+err:
+ virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
+ return ret;
}
EXPORT_SYMBOL_GPL(virtio_device_restore);
#endif
@@ -698,11 +698,30 @@ EXPORT_SYMBOL_GPL(virtio_device_reset_prepare);
int virtio_device_reset_done(struct virtio_device *dev)
{
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
+ int ret;
if (!drv || !drv->reset_done)
return -EOPNOTSUPP;
- return virtio_device_restore_priv(dev, false);
+ ret = virtio_device_reinit(dev);
+ if (ret)
+ goto err;
+
+ ret = drv->reset_done(dev);
+ if (ret)
+ goto err;
+
+ /* If reset_done didn't do it, mark device DRIVER_OK ourselves. */
+ if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK))
+ virtio_device_ready(dev);
+
+ virtio_config_core_enable(dev);
+
+ return 0;
+
+err:
+ virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
+ return ret;
}
EXPORT_SYMBOL_GPL(virtio_device_reset_done);
--
2.43.0
^ permalink raw reply related
* [RFC PATCH v3 2/4] virtio_ring: export virtqueue_reinit_vring() for noirq restore
From: Sungho Bae @ 2026-04-22 13:10 UTC (permalink / raw)
To: mst, jasowang
Cc: xuanzhuo, eperezma, virtualization, linux-kernel, Sungho Bae
In-Reply-To: <20260422131014.956-1-baver.bae@gmail.com>
From: Sungho Bae <baver.bae@lge.com>
After a device reset in noirq context the existing vrings must be
re-initialized without any memory allocation, because GFP_KERNEL is
not available.
The internal helpers virtqueue_reset_split() and
virtqueue_reset_packed() already reset vring indices and descriptor
state in place. Add a thin exported wrapper, virtqueue_reinit_vring(),
that dispatches to the appropriate helper based on the ring layout.
This will be used by a subsequent patch that adds noirq system-sleep
PM callbacks for virtio-mmio.
Signed-off-by: Sungho Bae <baver.bae@lge.com>
---
drivers/virtio/virtio_ring.c | 30 ++++++++++++++++++++++++++++++
include/linux/virtio_ring.h | 3 +++
2 files changed, 33 insertions(+)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index fbca7ce1c6bf..528157b1211d 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -3936,5 +3936,35 @@ void virtqueue_map_sync_single_range_for_device(const struct virtqueue *_vq,
}
EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_device);
+/**
+ * virtqueue_reinit_vring - reinitialize vring state without reallocation
+ * @_vq: the virtqueue
+ *
+ * Reset the avail/used indices and descriptor state of an existing
+ * virtqueue so it can be reused after a device reset. No memory is
+ * allocated or freed, making this safe for use in noirq context.
+ *
+ * The caller must ensure that all in-flight buffers have been completed
+ * or detached before invoking this function. Calling it with outstanding
+ * descriptors will corrupt the free-list state because num_free is
+ * unconditionally restored to the ring's maximum capacity while the
+ * desc_extra next-chain and free_head reflect only the partial free list
+ * that existed at reset time.
+ */
+void virtqueue_reinit_vring(struct virtqueue *_vq)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+ unsigned int num = virtqueue_is_packed(vq) ?
+ vq->packed.vring.num : vq->split.vring.num;
+
+ WARN_ON(vq->vq.num_free != num);
+
+ if (virtqueue_is_packed(vq))
+ virtqueue_reset_packed(vq);
+ else
+ virtqueue_reset_split(vq);
+}
+EXPORT_SYMBOL_GPL(virtqueue_reinit_vring);
+
MODULE_DESCRIPTION("Virtio ring implementation");
MODULE_LICENSE("GPL");
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
index c97a12c1cda3..26c7c9d0a151 100644
--- a/include/linux/virtio_ring.h
+++ b/include/linux/virtio_ring.h
@@ -118,6 +118,9 @@ void vring_del_virtqueue(struct virtqueue *vq);
/* Filter out transport-specific feature bits. */
void vring_transport_features(struct virtio_device *vdev);
+/* Reinitialize a virtqueue without reallocation (safe in noirq context) */
+void virtqueue_reinit_vring(struct virtqueue *_vq);
+
irqreturn_t vring_interrupt(int irq, void *_vq);
u32 vring_notification_data(struct virtqueue *_vq);
--
2.43.0
^ permalink raw reply related
* [RFC PATCH v3 3/4] virtio: add noirq system sleep PM infrastructure
From: Sungho Bae @ 2026-04-22 13:10 UTC (permalink / raw)
To: mst, jasowang
Cc: xuanzhuo, eperezma, virtualization, linux-kernel, Sungho Bae
In-Reply-To: <20260422131014.956-1-baver.bae@gmail.com>
From: Sungho Bae <baver.bae@lge.com>
Some virtio-mmio devices, such as virtio-clock or virtio-regulator,
must become operational before the regular PM restore callback runs
because other devices may depend on them.
Add the core infrastructure needed to support noirq system-sleep PM
callbacks for virtio transports:
- virtio_add_status_noirq(): status helper without might_sleep().
- virtio_features_ok_noirq(): feature negotiation without might_sleep().
- virtio_reset_device_noirq(): device reset that skips
virtio_synchronize_cbs() (IRQ handlers are already quiesced in the
noirq phase).
- virtio_device_reinit_noirq(): full noirq bring-up sequence using the
above helpers.
- virtio_config_core_enable_noirq(): config enable with irqsave
locking.
- virtio_device_ready_noirq(): marks DRIVER_OK without
virtio_synchronize_cbs().
Add freeze_noirq/restore_noirq callbacks to struct virtio_driver and
provide matching helper wrappers in the virtio core:
- virtio_device_freeze_noirq(): forwards to drv->freeze_noirq().
- virtio_device_restore_noirq(): runs the noirq bring-up sequence,
resets existing vrings via the new config_ops->reset_vqs() hook,
then calls drv->restore_noirq().
Modify virtio_device_restore() so that when a driver provides
restore_noirq, the normal-phase restore skips the re-initialization
that was already done in the noirq phase.
Signed-off-by: Sungho Bae <baver.bae@lge.com>
---
drivers/virtio/virtio.c | 193 ++++++++++++++++++++++++++++++++--
include/linux/virtio.h | 10 ++
include/linux/virtio_config.h | 29 +++++
3 files changed, 226 insertions(+), 6 deletions(-)
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index 98f1875f8df1..124ada693f5f 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -193,6 +193,17 @@ static void virtio_config_core_enable(struct virtio_device *dev)
spin_unlock_irq(&dev->config_lock);
}
+static void virtio_config_core_enable_noirq(struct virtio_device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->config_lock, flags);
+ dev->config_core_enabled = true;
+ if (dev->config_change_pending)
+ __virtio_config_changed(dev);
+ spin_unlock_irqrestore(&dev->config_lock, flags);
+}
+
void virtio_add_status(struct virtio_device *dev, unsigned int status)
{
might_sleep();
@@ -200,6 +211,20 @@ void virtio_add_status(struct virtio_device *dev, unsigned int status)
}
EXPORT_SYMBOL_GPL(virtio_add_status);
+/*
+ * Same as virtio_add_status() but without the might_sleep() assertion,
+ * so it is safe to call from noirq context.
+ *
+ * This assumes that the device's get_status and set_status operations are
+ * also noirq-safe. Therefore, the device must garantee that get_status and
+ * set_status can be called from noirq context.
+ */
+void virtio_add_status_noirq(struct virtio_device *dev, unsigned int status)
+{
+ dev->config->set_status(dev, dev->config->get_status(dev) | status);
+}
+EXPORT_SYMBOL_GPL(virtio_add_status_noirq);
+
/* Do some validation, then set FEATURES_OK */
static int virtio_features_ok(struct virtio_device *dev)
{
@@ -234,6 +259,38 @@ static int virtio_features_ok(struct virtio_device *dev)
return 0;
}
+/* noirq-safe variant: no might_sleep(), uses virtio_add_status_noirq() */
+static int virtio_features_ok_noirq(struct virtio_device *dev)
+{
+ unsigned int status;
+
+ if (virtio_check_mem_acc_cb(dev)) {
+ if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) {
+ dev_warn(&dev->dev,
+ "device must provide VIRTIO_F_VERSION_1\n");
+ return -ENODEV;
+ }
+
+ if (!virtio_has_feature(dev, VIRTIO_F_ACCESS_PLATFORM)) {
+ dev_warn(&dev->dev,
+ "device must provide VIRTIO_F_ACCESS_PLATFORM\n");
+ return -ENODEV;
+ }
+ }
+
+ if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1))
+ return 0;
+
+ virtio_add_status_noirq(dev, VIRTIO_CONFIG_S_FEATURES_OK);
+ status = dev->config->get_status(dev);
+ if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) {
+ dev_err(&dev->dev, "virtio: device refuses features: %x\n",
+ status);
+ return -ENODEV;
+ }
+ return 0;
+}
+
/**
* virtio_reset_device - quiesce device for removal
* @dev: the device to reset
@@ -267,6 +324,24 @@ void virtio_reset_device(struct virtio_device *dev)
}
EXPORT_SYMBOL_GPL(virtio_reset_device);
+/**
+ * virtio_reset_device_noirq - noirq-safe variant of virtio_reset_device()
+ * @dev: the device to reset
+ */
+void virtio_reset_device_noirq(struct virtio_device *dev)
+{
+#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
+ /*
+ * The noirq stage runs with device IRQ handlers disabled, so
+ * virtio_synchronize_cbs() must not be called here.
+ */
+ virtio_break_device(dev);
+#endif
+
+ dev->config->reset(dev);
+}
+EXPORT_SYMBOL_GPL(virtio_reset_device_noirq);
+
static int virtio_dev_probe(struct device *_d)
{
int err, i;
@@ -539,6 +614,7 @@ int register_virtio_device(struct virtio_device *dev)
dev->config_driver_disabled = false;
dev->config_core_enabled = false;
dev->config_change_pending = false;
+ dev->noirq_restore_done = false;
INIT_LIST_HEAD(&dev->vqs);
spin_lock_init(&dev->vqs_list_lock);
@@ -618,6 +694,41 @@ static int virtio_device_reinit(struct virtio_device *dev)
return virtio_features_ok(dev);
}
+/* noirq-safe variant of virtio_device_reinit() */
+static int virtio_device_reinit_noirq(struct virtio_device *dev)
+{
+ struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
+ int ret;
+
+ /*
+ * We always start by resetting the device, in case a previous
+ * driver messed it up.
+ */
+ virtio_reset_device_noirq(dev);
+
+ /* Acknowledge that we've seen the device. */
+ virtio_add_status_noirq(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
+
+ /*
+ * Maybe driver failed before freeze.
+ * Restore the failed status, for debugging.
+ */
+ if (dev->failed)
+ virtio_add_status_noirq(dev, VIRTIO_CONFIG_S_FAILED);
+
+ if (!drv)
+ return 0;
+
+ /* We have a driver! */
+ virtio_add_status_noirq(dev, VIRTIO_CONFIG_S_DRIVER);
+
+ ret = dev->config->finalize_features(dev);
+ if (ret)
+ return ret;
+
+ return virtio_features_ok_noirq(dev);
+}
+
#ifdef CONFIG_PM_SLEEP
int virtio_device_freeze(struct virtio_device *dev)
{
@@ -627,6 +738,7 @@ int virtio_device_freeze(struct virtio_device *dev)
virtio_config_core_disable(dev);
dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
+ dev->noirq_restore_done = false;
if (drv && drv->freeze) {
ret = drv->freeze(dev);
@@ -645,12 +757,17 @@ int virtio_device_restore(struct virtio_device *dev)
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
int ret;
- ret = virtio_device_reinit(dev);
- if (ret)
- goto err;
-
- if (!drv)
- return 0;
+ /*
+ * If this device was already brought up in the noirq phase,
+ * skip the re-initialization here.
+ */
+ if (!drv || !dev->noirq_restore_done) {
+ ret = virtio_device_reinit(dev);
+ if (ret)
+ goto err;
+ if (!drv)
+ return 0;
+ }
if (drv->restore) {
ret = drv->restore(dev);
@@ -671,6 +788,70 @@ int virtio_device_restore(struct virtio_device *dev)
return ret;
}
EXPORT_SYMBOL_GPL(virtio_device_restore);
+
+int virtio_device_freeze_noirq(struct virtio_device *dev)
+{
+ struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
+
+ if (drv && drv->freeze_noirq) {
+ /*
+ * If the driver provides restore_noirq and has active vqs,
+ * the transport must support reset_vqs to restore them.
+ * Fail here so the PM core can abort the transition
+ * gracefully, rather than hitting -EOPNOTSUPP on resume.
+ */
+ if (drv->restore_noirq && !list_empty(&dev->vqs) &&
+ !dev->config->reset_vqs)
+ return -EOPNOTSUPP;
+
+ return drv->freeze_noirq(dev);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_device_freeze_noirq);
+
+int virtio_device_restore_noirq(struct virtio_device *dev)
+{
+ struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
+ int ret;
+
+ if (!drv || !drv->restore_noirq)
+ return 0;
+
+ ret = virtio_device_reinit_noirq(dev);
+ if (ret)
+ goto err;
+
+ if (!list_empty(&dev->vqs)) {
+ if (!dev->config->reset_vqs) {
+ ret = -EOPNOTSUPP;
+ goto err;
+ }
+
+ ret = dev->config->reset_vqs(dev);
+ if (ret)
+ goto err;
+ }
+
+ ret = drv->restore_noirq(dev);
+ if (ret)
+ goto err;
+
+ /* Mark that noirq restore has completed. */
+ dev->noirq_restore_done = true;
+
+ /* If restore_noirq set DRIVER_OK, enable config now. */
+ if (dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)
+ virtio_config_core_enable_noirq(dev);
+
+ return 0;
+
+err:
+ virtio_add_status_noirq(dev, VIRTIO_CONFIG_S_FAILED);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(virtio_device_restore_noirq);
#endif
int virtio_device_reset_prepare(struct virtio_device *dev)
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 3bbc4cb6a672..ab66a3799310 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -151,6 +151,7 @@ struct virtio_admin_cmd {
* @config_driver_disabled: configuration change reporting disabled by
* a driver
* @config_change_pending: configuration change reported while disabled
+ * @noirq_restore_done: set if the noirq restore phase completed successfully
* @config_lock: protects configuration change reporting
* @vqs_list_lock: protects @vqs.
* @dev: underlying device.
@@ -171,6 +172,7 @@ struct virtio_device {
bool config_core_enabled;
bool config_driver_disabled;
bool config_change_pending;
+ bool noirq_restore_done;
spinlock_t config_lock;
spinlock_t vqs_list_lock;
struct device dev;
@@ -209,8 +211,12 @@ void virtio_config_driver_enable(struct virtio_device *dev);
#ifdef CONFIG_PM_SLEEP
int virtio_device_freeze(struct virtio_device *dev);
int virtio_device_restore(struct virtio_device *dev);
+int virtio_device_freeze_noirq(struct virtio_device *dev);
+int virtio_device_restore_noirq(struct virtio_device *dev);
#endif
void virtio_reset_device(struct virtio_device *dev);
+void virtio_reset_device_noirq(struct virtio_device *dev);
+void virtio_add_status_noirq(struct virtio_device *dev, unsigned int status);
int virtio_device_reset_prepare(struct virtio_device *dev);
int virtio_device_reset_done(struct virtio_device *dev);
@@ -237,6 +243,8 @@ size_t virtio_max_dma_size(const struct virtio_device *vdev);
* changes; may be called in interrupt context.
* @freeze: optional function to call during suspend/hibernation.
* @restore: optional function to call on resume.
+ * @freeze_noirq: optional function to call during noirq suspend/hibernation.
+ * @restore_noirq: optional function to call on noirq resume.
* @reset_prepare: optional function to call when a transport specific reset
* occurs.
* @reset_done: optional function to call after transport specific reset
@@ -258,6 +266,8 @@ struct virtio_driver {
void (*config_changed)(struct virtio_device *dev);
int (*freeze)(struct virtio_device *dev);
int (*restore)(struct virtio_device *dev);
+ int (*freeze_noirq)(struct virtio_device *dev);
+ int (*restore_noirq)(struct virtio_device *dev);
int (*reset_prepare)(struct virtio_device *dev);
int (*reset_done)(struct virtio_device *dev);
void (*shutdown)(struct virtio_device *dev);
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index 69f84ea85d71..496897bc417e 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -70,6 +70,9 @@ struct virtqueue_info {
* vqs_info: array of virtqueue info structures
* Returns 0 on success or error status
* @del_vqs: free virtqueues found by find_vqs().
+ * @reset_vqs: reinitialize existing virtqueues without allocating or
+ * freeing them (optional). Used during noirq restore.
+ * Returns 0 on success or error status.
* @synchronize_cbs: synchronize with the virtqueue callbacks (optional)
* The function guarantees that all memory operations on the
* queue before it are visible to the vring_interrupt() that is
@@ -123,6 +126,7 @@ struct virtio_config_ops {
struct virtqueue_info vqs_info[],
struct irq_affinity *desc);
void (*del_vqs)(struct virtio_device *);
+ int (*reset_vqs)(struct virtio_device *vdev);
void (*synchronize_cbs)(struct virtio_device *);
u64 (*get_features)(struct virtio_device *vdev);
void (*get_extended_features)(struct virtio_device *vdev,
@@ -371,6 +375,31 @@ void virtio_device_ready(struct virtio_device *dev)
dev->config->set_status(dev, status | VIRTIO_CONFIG_S_DRIVER_OK);
}
+/**
+ * virtio_device_ready_noirq - noirq-safe variant of virtio_device_ready()
+ * @dev: the virtio device
+ *
+ * This assumes that the device's get_status and set_status operations are
+ * noirq-safe.
+ */
+static inline
+void virtio_device_ready_noirq(struct virtio_device *dev)
+{
+ unsigned int status = dev->config->get_status(dev);
+
+ WARN_ON(status & VIRTIO_CONFIG_S_DRIVER_OK);
+
+#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
+ /*
+ * The noirq stage runs with device IRQ handlers disabled, so
+ * virtio_synchronize_cbs() must not be called here.
+ */
+ __virtio_unbreak_device(dev);
+#endif
+
+ dev->config->set_status(dev, status | VIRTIO_CONFIG_S_DRIVER_OK);
+}
+
static inline
const char *virtio_bus_name(struct virtio_device *vdev)
{
--
2.43.0
^ permalink raw reply related
* [RFC PATCH v3 4/4] virtio-mmio: wire up noirq system sleep PM callbacks
From: Sungho Bae @ 2026-04-22 13:10 UTC (permalink / raw)
To: mst, jasowang
Cc: xuanzhuo, eperezma, virtualization, linux-kernel, Sungho Bae
In-Reply-To: <20260422131014.956-1-baver.bae@gmail.com>
From: Sungho Bae <baver.bae@lge.com>
Implement the transport side of noirq system-sleep PM for virtio-mmio:
- vm_reset_vqs(): iterate all virtqueues, call virtqueue_reinit_vring()
to reset the vring state in place, then reprogram the MMIO queue
registers (QUEUE_SEL, QUEUE_NUM, descriptor/avail/used addresses,
QUEUE_READY) so the device can use the same rings immediately after
restore. No memory is allocated or freed.
- virtio_mmio_freeze_noirq() / virtio_mmio_restore_noirq(): thin
wrappers that forward to the virtio core noirq helpers. The
restore_noirq path also writes GUEST_PAGE_SIZE for legacy (v1)
devices, matching the existing restore callback.
- Wire vm_reset_vqs into virtio_mmio_config_ops and register the
noirq callbacks via SET_NOIRQ_SYSTEM_SLEEP_PM_OPS().
With this in place, a virtio-mmio driver can implement freeze_noirq /
restore_noirq to participate in the noirq PM phase, enabling use cases
such as virtio-clock or virtio-regulator that must be operational
before other devices are restored.
Signed-off-by: Sungho Bae <baver.bae@lge.com>
---
drivers/virtio/virtio_mmio.c | 133 ++++++++++++++++++++++++-----------
1 file changed, 93 insertions(+), 40 deletions(-)
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index 595c2274fbb5..583da43013e7 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -336,6 +336,75 @@ static void vm_del_vqs(struct virtio_device *vdev)
free_irq(platform_get_irq(vm_dev->pdev, 0), vm_dev);
}
+static int vm_active_vq(struct virtio_device *vdev, struct virtqueue *vq)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+ int q_num = virtqueue_get_vring_size(vq);
+
+ writel(q_num, vm_dev->base + VIRTIO_MMIO_QUEUE_NUM);
+ if (vm_dev->version == 1) {
+ u64 q_pfn = virtqueue_get_desc_addr(vq) >> PAGE_SHIFT;
+
+ /*
+ * virtio-mmio v1 uses a 32bit QUEUE PFN. If we have something
+ * that doesn't fit in 32bit, fail the setup rather than
+ * pretending to be successful.
+ */
+ if (q_pfn >> 32) {
+ dev_err(&vdev->dev,
+ "platform bug: legacy virtio-mmio must not be used with RAM above 0x%llxGB\n",
+ 0x1ULL << (32 + PAGE_SHIFT - 30));
+ return -E2BIG;
+ }
+
+ writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN);
+ writel(q_pfn, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
+ } else {
+ u64 addr;
+
+ addr = virtqueue_get_desc_addr(vq);
+ writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_LOW);
+ writel((u32)(addr >> 32),
+ vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_HIGH);
+
+ addr = virtqueue_get_avail_addr(vq);
+ writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW);
+ writel((u32)(addr >> 32),
+ vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH);
+
+ addr = virtqueue_get_used_addr(vq);
+ writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_USED_LOW);
+ writel((u32)(addr >> 32),
+ vm_dev->base + VIRTIO_MMIO_QUEUE_USED_HIGH);
+
+ writel(1, vm_dev->base + VIRTIO_MMIO_QUEUE_READY);
+ }
+
+ return 0;
+}
+
+static int vm_reset_vqs(struct virtio_device *vdev)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+ struct virtqueue *vq;
+ int err;
+
+ virtio_device_for_each_vq(vdev, vq) {
+ /* Re-initialize vring state */
+ virtqueue_reinit_vring(vq);
+
+ /* Select the queue we're interested in */
+ writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL);
+
+ /* Activate the queue */
+ err = vm_active_vq(vdev, vq);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
static void vm_synchronize_cbs(struct virtio_device *vdev)
{
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
@@ -388,45 +457,9 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
vq->num_max = num;
/* Activate the queue */
- writel(virtqueue_get_vring_size(vq), vm_dev->base + VIRTIO_MMIO_QUEUE_NUM);
- if (vm_dev->version == 1) {
- u64 q_pfn = virtqueue_get_desc_addr(vq) >> PAGE_SHIFT;
-
- /*
- * virtio-mmio v1 uses a 32bit QUEUE PFN. If we have something
- * that doesn't fit in 32bit, fail the setup rather than
- * pretending to be successful.
- */
- if (q_pfn >> 32) {
- dev_err(&vdev->dev,
- "platform bug: legacy virtio-mmio must not be used with RAM above 0x%llxGB\n",
- 0x1ULL << (32 + PAGE_SHIFT - 30));
- err = -E2BIG;
- goto error_bad_pfn;
- }
-
- writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN);
- writel(q_pfn, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
- } else {
- u64 addr;
-
- addr = virtqueue_get_desc_addr(vq);
- writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_LOW);
- writel((u32)(addr >> 32),
- vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_HIGH);
-
- addr = virtqueue_get_avail_addr(vq);
- writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW);
- writel((u32)(addr >> 32),
- vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH);
-
- addr = virtqueue_get_used_addr(vq);
- writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_USED_LOW);
- writel((u32)(addr >> 32),
- vm_dev->base + VIRTIO_MMIO_QUEUE_USED_HIGH);
-
- writel(1, vm_dev->base + VIRTIO_MMIO_QUEUE_READY);
- }
+ err = vm_active_vq(vdev, vq);
+ if (err < 0)
+ goto error_bad_pfn;
return vq;
@@ -528,6 +561,7 @@ static const struct virtio_config_ops virtio_mmio_config_ops = {
.reset = vm_reset,
.find_vqs = vm_find_vqs,
.del_vqs = vm_del_vqs,
+ .reset_vqs = vm_reset_vqs,
.get_features = vm_get_features,
.finalize_features = vm_finalize_features,
.bus_name = vm_bus_name,
@@ -547,14 +581,33 @@ static int virtio_mmio_restore(struct device *dev)
{
struct virtio_mmio_device *vm_dev = dev_get_drvdata(dev);
- if (vm_dev->version == 1)
+ if (vm_dev->version == 1 && !vm_dev->vdev.noirq_restore_done)
writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
return virtio_device_restore(&vm_dev->vdev);
}
+static int virtio_mmio_freeze_noirq(struct device *dev)
+{
+ struct virtio_mmio_device *vm_dev = dev_get_drvdata(dev);
+
+ return virtio_device_freeze_noirq(&vm_dev->vdev);
+}
+
+static int virtio_mmio_restore_noirq(struct device *dev)
+{
+ struct virtio_mmio_device *vm_dev = dev_get_drvdata(dev);
+
+ if (vm_dev->version == 1)
+ writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
+
+ return virtio_device_restore_noirq(&vm_dev->vdev);
+}
+
static const struct dev_pm_ops virtio_mmio_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(virtio_mmio_freeze, virtio_mmio_restore)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(virtio_mmio_freeze_noirq,
+ virtio_mmio_restore_noirq)
};
#endif
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 3/4] scsi: Support scsi_devices without a device wide limit
From: Hannes Reinecke @ 2026-04-22 13:15 UTC (permalink / raw)
To: Mike Christie, martin.petersen, linux-scsi, james.bottomley,
virtualization, mst, pbonzini, stefanha, eperezma
In-Reply-To: <20260417230751.117836-4-michael.christie@oracle.com>
On 4/18/26 00:57, Mike Christie wrote:
> For virtio-scsi, we export a wide variety of non-scsi devices like
> NVMe (local and RDMA/TCP based) drives and block based devices using
> ublk. And then it's common to have multiple high perf devices im a LVM
> volume. The problem for these setups, is we can easily hit the 4096
> scsi_device queue depth limit so we end up throttling IO in the guest
> when the real device can handle more IO.
>
> In these situations we don't have a device wide limit that maps to
> cmd_per_lun. We have per hw queue limits or on the host we are doing
> more dynamic throttling. To allow for these types of devices, this
> patch allows drivers to set SCSI_UNLIMITED_CMD_PER_LUN for the
> cmd_per_lun. When set, we will then only be limited by the per hw
> queue limits.
>
> Signed-off-by: Mike Christie <michael.christie@oracle.com>
> ---
> drivers/scsi/hosts.c | 5 +++--
> drivers/scsi/scsi_scan.c | 25 ++++++++++++++-----------
> include/scsi/scsi_host.h | 4 ++++
> 3 files changed, 21 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
> index e047747d4ecf..c93c59e847c5 100644
> --- a/drivers/scsi/hosts.c
> +++ b/drivers/scsi/hosts.c
> @@ -238,8 +238,9 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
> }
>
> /* Use min_t(int, ...) in case shost->can_queue exceeds SHRT_MAX */
> - shost->cmd_per_lun = min_t(int, shost->cmd_per_lun,
> - shost->can_queue);
> + if (shost->cmd_per_lun != SCSI_UNLIMITED_CMD_PER_LUN)
> + shost->cmd_per_lun = min_t(int, shost->cmd_per_lun,
> + shost->can_queue);
>
> error = scsi_init_sense_cache(shost);
> if (error)
> diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
> index 7b11bc7de0e3..ecc3638c1909 100644
> --- a/drivers/scsi/scsi_scan.c
> +++ b/drivers/scsi/scsi_scan.c
> @@ -352,18 +352,20 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
> if (scsi_device_is_pseudo_dev(sdev))
> return sdev;
>
> - depth = sdev->host->cmd_per_lun ?: 1;
> + if (sdev->host->cmd_per_lun != SCSI_UNLIMITED_CMD_PER_LUN) {
> + depth = sdev->host->cmd_per_lun ?: 1;
>
Why don't we use a simple flag in the host (or host template) to
indicate that cmd_per_lun should be ignored?
I'm not in favour of using magic values for a setting which
otherwise is a limit.
Look to dev_loss_tmo as a bad example ...
Cheers,
Hannes
--
Dr. Hannes Reinecke Kernel Storage Architect
hare@suse.de +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich
^ permalink raw reply
* Re: [PATCH v3 0/2] Bluetooth: virtio_bt: harden rx against untrusted backend
From: patchwork-bot+bluetooth @ 2026-04-22 16:00 UTC (permalink / raw)
To: Michael Bommarito
Cc: marcel, luiz.dentz, linux-bluetooth, linux-kernel, soenke.huster,
mst, virtualization
In-Reply-To: <20260421170845.3469513-1-michael.bommarito@gmail.com>
Hello:
This series was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Tue, 21 Apr 2026 13:08:43 -0400 you wrote:
> Respin of the virtio_bt rx hardening patch, split per Luiz's
> request on the v2 thread:
>
> https://lore.kernel.org/linux-bluetooth/20260421151659.3326690-1-michael.bommarito@gmail.com/
>
> v2 bundled two independent hazards in one commit and the commit
> message got convoluted trying to explain them together. This v3
> keeps each hazard in its own patch so the rationale for each is
> self-contained.
>
> [...]
Here is the summary with links:
- [v3,1/2] Bluetooth: virtio_bt: clamp rx length before skb_put
https://git.kernel.org/bluetooth/bluetooth-next/c/041f524fb455
- [v3,2/2] Bluetooth: virtio_bt: validate rx pkt_type header length
https://git.kernel.org/bluetooth/bluetooth-next/c/d677b827eea1
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH v11 03/13] lib/group_cpus: Add group_mask_cpus_evenly()
From: Aaron Tomlin @ 2026-04-22 17:47 UTC (permalink / raw)
To: Marco Crivellari
Cc: James.Bottomley, MPT-FusionLinux.pdl, aacraid, akpm, axboe,
bigeasy, chandrakanth.patil, chenridong, chjohnst, frederic, hare,
hch, jinpu.wang, juri.lelli, kashyap.desai, kbusch, kch,
linux-block, linux-kernel, linux-nvme, linux-scsi, liyihang9,
longman, martin.petersen, maz, megaraidlinux.pdl, ming.lei, mingo,
mpi3mr-linuxdrv.pdl, mproche, mst, neelx, nick.lange, peterz,
ranjan.kumar, ruanjinjie, sagi, sathya.prakash, sean,
shivasharan.srikanteshwara, sreekanth.reddy, steve,
suganath-prabu.subramani, sumit.saxena, tglx, tom.leiming,
vincent.guittot, virtualization, wagi, yphbchou0911
In-Reply-To: <20260420131152.243488-1-marco.crivellari@suse.com>
[-- Attachment #1: Type: text/plain, Size: 1093 bytes --]
On Mon, Apr 20, 2026 at 03:11:52PM +0200, Marco Crivellari wrote:
> Without it, I guess the kmalloc() in `group_mask_cpus_evenly()` will
> return ZERO_SIZE_PTR:
Hi Marco,
Thank you for reviewing the patch.
You are correct. If numgrps is 0, __do_kmalloc_node() will
return ZERO_SIZE_PTR.
> Should this check be added or it is not needed? Or maybe rely on `ZERO_OR_NULL_PTR()` ?
- File: mm/slub.c
5275 static __always_inline
5276 void *__do_kmalloc_node(size_t size, kmem_buckets *b, gfp_t flags, int node,
5277 unsigned long caller)
5278 {
5279 struct kmem_cache *s;
5280 void *ret;
:
5289 if (unlikely(!size))
5290 return ZERO_SIZE_PTR;
:
5298 }
Regarding your suggestion: rather than relying on ZERO_OR_NULL_PTR() after
the fact, I think it is much cleaner to just add the early exit at the very
beginning of the function, exactly as group_cpus_evenly() does. It avoids
the allocator path entirely.
Kind regards,
--
Aaron Tomlin
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH 0/4] scsi: Support devices that don't have a cmd_per_lun limit
From: Mike Christie @ 2026-04-22 18:05 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: martin.petersen, linux-scsi, james.bottomley, virtualization, mst,
pbonzini, eperezma
In-Reply-To: <20260420173352.GB405461@fedora>
On 4/20/26 12:33 PM, Stefan Hajnoczi wrote:
> On Fri, Apr 17, 2026 at 05:57:20PM -0500, Mike Christie wrote:
>> The following patches were made over Linus's and Martin's 7.1 trees.
>> They fix an issue where for virtio-scsi we export a lot of non-scsi
>> devices but are getting throttled by the cmd_per_lun_limit too early.
>> For example we export 1 or more NVMe or block devices and would like
>> to just pass command to them in way where virtio-scsi's hw queue
>> limits match the physical hardware. Or in some cases we are doing
>> cgroup based throttling on the host side, and we don't want the guest
>> to block IO when the host knows we have extra bandwidth.
>>
>> The patches add a new cmd_per_lun value so drivers can indicate
>> when to avoid tracking queueing at the device wide level. They
>> then rely on just the block layer hw queue limits. And the patches
>> convert virtio-scsi. They also fix some can_queue related issues
>> discovered while testing/reviewing.
>
> Hi Mike,
> Is there a difference between setting cmd_per_lun to U32_MAX with your
> patches versus setting cmd_per_lun to the virtqueue size without your
> patches (this can already be done today without code changes in the
> driver)?
The problem today is that cmd_per_lun doesn't take into account the
multiqueue queues (virtqueues in virtio) so we have a low limit of 1024
commands total. On a 32-128 vCPU VM we can easily hit that as there's
lots of IO submission threads spread over lots of those CPUs. CPUs are
then mapped to block mq queues which are mapped to virtqueues so we are
hitting them hard.
That 1024 value comes from QEMU which limits virtqueue_size to 1024.
We could increase that to 4096 or 32K or whatever. The problem is that
we would then be wasting a lot of memory as we would be allocating lots
of really large virtqueues that would go underutilized (we are submitting
10s of thousands of total IOs but not to just a single queue).
So a possibly good balance between not having to use a magic number
(U32_MAX) plus having to update the spec would be to:
1. Fix up scsi-ml and virtio-scsi so they allow cmd_per_lun to be
greater than can_queue (virtqueue_size for virtio-scsi).
2. Increase the scsi-ml cap cmd_per_lun cap from 4096 to S16_MAX
(scsi-ml uses a short for cmd_per_lun).
The only drawback to this would be that for each scsi_device we track
running IO with a sbitmap. For my cases, we don't need it, so it would
be a waste of memory. For a S16_MAX worth of commands I think it would
be 128K wasted so not too bad for us as we don't have lots of these
types of high perf devices per VM.
^ permalink raw reply
* Re: [PATCH 3/4] scsi: Support scsi_devices without a device wide limit
From: Mike Christie @ 2026-04-22 18:06 UTC (permalink / raw)
To: Hannes Reinecke, martin.petersen, linux-scsi, james.bottomley,
virtualization, mst, pbonzini, stefanha, eperezma
In-Reply-To: <448302b1-3950-4e6d-ae8b-337cad09f3fe@suse.de>
On 4/22/26 8:15 AM, Hannes Reinecke wrote:
> On 4/18/26 00:57, Mike Christie wrote:
>> For virtio-scsi, we export a wide variety of non-scsi devices like
>> NVMe (local and RDMA/TCP based) drives and block based devices using
>> ublk. And then it's common to have multiple high perf devices im a LVM
>> volume. The problem for these setups, is we can easily hit the 4096
>> scsi_device queue depth limit so we end up throttling IO in the guest
>> when the real device can handle more IO.
>>
>> In these situations we don't have a device wide limit that maps to
>> cmd_per_lun. We have per hw queue limits or on the host we are doing
>> more dynamic throttling. To allow for these types of devices, this
>> patch allows drivers to set SCSI_UNLIMITED_CMD_PER_LUN for the
>> cmd_per_lun. When set, we will then only be limited by the per hw
>> queue limits.
>>
>> Signed-off-by: Mike Christie <michael.christie@oracle.com>
>> ---
>> drivers/scsi/hosts.c | 5 +++--
>> drivers/scsi/scsi_scan.c | 25 ++++++++++++++-----------
>> include/scsi/scsi_host.h | 4 ++++
>> 3 files changed, 21 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
>> index e047747d4ecf..c93c59e847c5 100644
>> --- a/drivers/scsi/hosts.c
>> +++ b/drivers/scsi/hosts.c
>> @@ -238,8 +238,9 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
>> }
>> /* Use min_t(int, ...) in case shost->can_queue exceeds SHRT_MAX */
>> - shost->cmd_per_lun = min_t(int, shost->cmd_per_lun,
>> - shost->can_queue);
>> + if (shost->cmd_per_lun != SCSI_UNLIMITED_CMD_PER_LUN)
>> + shost->cmd_per_lun = min_t(int, shost->cmd_per_lun,
>> + shost->can_queue);
>> error = scsi_init_sense_cache(shost);
>> if (error)
>> diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
>> index 7b11bc7de0e3..ecc3638c1909 100644
>> --- a/drivers/scsi/scsi_scan.c
>> +++ b/drivers/scsi/scsi_scan.c
>> @@ -352,18 +352,20 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
>> if (scsi_device_is_pseudo_dev(sdev))
>> return sdev;
>> - depth = sdev->host->cmd_per_lun ?: 1;
>> + if (sdev->host->cmd_per_lun != SCSI_UNLIMITED_CMD_PER_LUN) {
>> + depth = sdev->host->cmd_per_lun ?: 1;
>>
> Why don't we use a simple flag in the host (or host template) to
> indicate that cmd_per_lun should be ignored?
That's fine with me. I don't need it per scsi_device, but had thought
someone might. We can always change it later to a scsi_device flag if
it comes up.
> I'm not in favour of using magic values for a setting which
> otherwise is a limit.
> Look to dev_loss_tmo as a bad example ...
>
> Cheers,
>
> Hannes
^ permalink raw reply
* RE: [EXTERNAL] Re: [PATCH net] hv_sock: Return -EIO for malformed/short packets
From: Dexuan Cui @ 2026-04-22 18:14 UTC (permalink / raw)
To: Stefano Garzarella
Cc: KY Srinivasan, Haiyang Zhang, wei.liu@kernel.org, Long Li,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, horms@kernel.org, niuxuewei.nxw@antgroup.com,
linux-hyperv@vger.kernel.org, virtualization@lists.linux.dev,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
In-Reply-To: <aeiEsYqcKumplu5P@sgarzare-redhat>
> From: Stefano Garzarella <sgarzare@redhat.com>
> Sent: Wednesday, April 22, 2026 2:40 AM
> ...
> >+ if (hvs->vsk->peer_shutdown & SEND_SHUTDOWN)
>
> We can access `vsk` directly, I mean `vsk->peer_shutdown`.
>
> >+ return 0;
> >+ else
>
> nit: we usually avoid the `else` if the other branch returns early, and
> maybe have the error returned first, so it's more clear when reading the
> comment on top. I mean something like this:
>
> if (!(vsk->peer_shutdown & SEND_SHUTDOWN))
> return -EIO;
>
> return 0;
>
> BTW, not a strong opinion on that.
>
> The rest, LGTM!
>
> Thanks,
> Stefano
Thank you Stefano! I'll post v2 later today.
^ permalink raw reply
* [PATCH v12 00/13] blk: honor isolcpus configuration
From: Aaron Tomlin @ 2026-04-22 18:52 UTC (permalink / raw)
To: axboe, kbusch, hch, sagi, mst
Cc: atomlin, aacraid, James.Bottomley, martin.petersen, liyihang9,
kashyap.desai, sumit.saxena, shivasharan.srikanteshwara,
chandrakanth.patil, sathya.prakash, sreekanth.reddy,
suganath-prabu.subramani, ranjan.kumar, jinpu.wang, tglx, mingo,
peterz, juri.lelli, vincent.guittot, akpm, maz, ruanjinjie,
bigeasy, yphbchou0911, wagi, frederic, longman, chenridong, hare,
kch, ming.lei, tom.leiming, steve, sean, chjohnst, neelx, mproche,
nick.lange, marco.crivellari, linux-block, linux-kernel,
virtualization, linux-nvme, linux-scsi, megaraidlinux.pdl,
mpi3mr-linuxdrv.pdl, MPT-FusionLinux.pdl
Hi,
I have decided to drive this series forward on behalf of Daniel Wagner, the
original author. The series has been rebased on v7.0-12635-g6596a02b2078.
Building upon prior iterations, this series introduces critical
architectural refinements to the mapping and affinity spreading algorithms
to guarantee thread safety and resilience against concurrent CPU-hotplug
operations. Previously, the block layer relied on a shared global static
mask (i.e., blk_hk_online_mask), which proved vulnerable to race conditions
during rapid hotplug events. This vulnerability was highlighted by the
kernel test robot, which encountered a NULL pointer dereference during
rcutorture (cpuhotplug) stress testing due to concurrent mask modification.
To resolve this, the architecture has been fundamentally hardened. The
global static state has been eradicated. Instead, the IRQ affinity core now
employs a newly introduced irq_spread_hk_filter(), which safely intersects
the natively calculated affinity mask with the HK_TYPE_IO_QUEUE mask.
Crucially, this is achieved using a local, hotplug-safe snapshot via
data_race(cpu_online_mask). This approach circumvents the hotplug lock
deadlocks previously identified by Thomas Gleixner, while explicitly
avoiding CONFIG_CPUMASK_OFFSTACK stack bloat hazards on high-core-count
systems. A robust fallback mechanism guarantees that should an interrupt
vector be assigned exclusively to isolated cores, it is safely re-routed to
the system's online housekeeping CPUs.
Following rigorous testing of multiple queue maps (such as NVMe poll
queues) alongside isolated CPUs, the tenth iteration resolved a critical
page fault regression. The multi-queue mapping logic has been corrected to
strictly maintain absolute hardware queue indices, ensuring faultless queue
initialisation and preventing out-of-bounds memory access.
Furthermore, following feedback from Ming Lei, the administrative
documentation for isolcpus=io_queue has undergone a comprehensive overhaul
to reflect this architectural reality. Previous iterations lacked the
required technical precision regarding subsystem impact. The expanded
kernel-parameters.txt now explicitly details that this parameter applies
strictly to managed IRQs. It thoroughly documents how the block layer
intercepts multiqueue allocation to match the housekeeping mask, actively
preventing MSI-X vector exhaustion on massive topologies and forcing queue
sharing. Most importantly, it cements the structural guarantee: while an
application on an isolated CPU may freely submit I/O, the hardware
completion interrupt is strictly and safely offloaded to a housekeeping
core.
Please let me know your thoughts.
Changes since v12:
- Removed duplicate paragraph from the commit message in patch 11
(Marco Crivellari)
- Ensure ZERO_SIZE_PTR is not returned by group_mask_cpus_evenly()
(Marco Crivellari)
- Linked to v11: https://lore.kernel.org/lkml/20260416192942.1243421-1-atomlin@atomlin.com/
Changes since v11:
- Completely rewrote the isolcpus=io_queue documentation in
Documentation/admin-guide/kernel-parameters.txt to clarify its exclusive
application to managed IRQs, queue allocation limits, vector exhaustion
prevention, and hardware interrupt routing (Ming Lei)
- Fixed a stack frame bloat issue by avoiding the on-stack declaration of
struct cpumask (Waiman Long)
- Linked to v10: https://lore.kernel.org/linux-nvme/20260401222312.772334-1-atomlin@atomlin.com/
Changes since v10:
- Fixed a page fault regression encountered when initialising secondary
queue maps (e.g., NVMe poll queues). Restored the qmap->queue_offset to
the mq_map assignment to ensure CPUs are strictly mapped to absolute
hardware indices (Keith Busch)
- Corrected the active_hctx tracker to utilise relative queue indices,
preventing out-of-bounds mask assignments
- Fixed the blk_mq_validate() sanity check to properly evaluate absolute
queue indices against the offset-adjusted loop index
- Corrected typographical errors within block/blk-mq-cpumap.c
(Keith Busch)
- Clarified the commit message regarding the removal of the !SMP fallback
code, explicitly noting that the core scheduler now mandates SMP
unconditionally (Sebastian Andrzej Siewior)
- Added missing "Signed-off-by:" tags to properly record the patch series
chain of custody
- Linked to v9: https://lore.kernel.org/lkml/20260330221047.630206-1-atomlin@atomlin.com/
Changes since v9:
- Added "Reviewed-by:" tags
- Introduced irq_spread_hk_filter() to safely restrict managed IRQ
affinity to housekeeping CPUs (Thomas Gleixner)
- Removed the unsafe global static variable blk_hk_online_mask from
blk-mq-cpumap.c and blk-mq.c. blk_mq_online_queue_affinity() now returns
a stable pointer, delegating safe intersection to the callers to prevent
concurrent modification races (Thomas Gleixner, Hannes Reinecke)
- Resolved BUG: kernel NULL pointer dereference in __blk_mq_all_tag_iter
reported by the kernel test robot during cpuhotplug rcutorture stress
testing
- Linked to v8: https://lore.kernel.org/lkml/20250905-isolcpus-io-queues-v8-0-885984c5daca@kernel.org/
Changes since v8:
- Added commit 524f5eea4bbe ("lib/group_cpus: remove !SMP code")
- Merged the new mapping logic directly into the existing function to
avoid special casing
- Refined the group_mask_cpus_evenly() implementation with the following
updates:
- Corrected the function name typo (changed group_masks_cpus_evenly to
group_mask_cpus_evenly)
- Updated the documentation comment to accurately reflect the function's
behavior
- Renamed the cpu_mask argument to mask for consistency
- Added a new patch for aacraid to include the missing number of queues
calculation
- Restricted updates to only affect SCSI drivers that support
PCI_IRQ_AFFINITY and do not utilize nvme-fabrics
- Removed the __free cleanup attribute usage for cpumask_var_t allocations
due to compatibility issues
- Updated the documentation to explicitly highlight the limitations
surrounding CPU offlining
- Collected accumulated Reviewed-by and Acked-by tags
- Linked to v7: https://patch.msgid.link/20250702-isolcpus-io-queues-v7-0-557aa7eacce4@kernel.org
Changes since v7:
- Sent out the first part of the series independently:
https://lore.kernel.org/all/20250617-isolcpus-queue-counters-v1-0-13923686b54b@kernel.org/
- Added comprehensive kernel command-line documentation
- Added validation logic to ensure the resulting CPU-to-queue mapping is
fully operational
- Rewrote the isolcpus mapping code to properly account for active
hardware contexts (hctx)
- Introduced blk_mq_map_hk_irq_queues, which utilizes the mask retrieved
from irq_get_affinity()
- Refactored blk_mq_map_hk_queues to require the caller to explicitly test
for HK_TYPE_MANAGED_IRQ
- Linked to v6: https://patch.msgid.link/20250424-isolcpus-io-queues-v6-0-9a53a870ca1f@kernel.org
Changes since v6:
- Reintroduced the io_queue type for the isolcpus kernel parameter
- Prevented the offlining of a housekeeping CPU if an isolated CPU is
still present, upgrading this behavior from a simple warning to a hard
restriction
- Linked to v5: https://lore.kernel.org/r/20250110-isolcpus-io-queues-v5-0-0e4f118680b0@kernel.org
Changes since v5:
- Rebased the series onto the latest for-6.14/block branch.
- Updated the documentation regarding the managed_irq parameters
- Reworded the commit message for "blk-mq: issue warning when offlining
hctx with online isolcpus" for better clarity
- Split the input and output parameters in the patch "lib/group_cpus: let
group_cpu_evenly return number of groups"
- Dropped the patch "sched/isolation: document HK_TYPE housekeeping
option"
- Linked to v4: https://lore.kernel.org/r/20241217-isolcpus-io-queues-v4-0-5d355fbb1e14@kernel.org
Changes since v4:
- Added the patch "blk-mq: issue warning when offlining hctx with online
isolcpus"
- Fixed the check in group_cpus_evenly(); the condition now properly uses
housekeeping_enabled() instead of cpumask_weight(), as the latter always
returns a valid mask
- Dropped the Fixes: tag from "lib/group_cpus.c: honor housekeeping config
when grouping CPUs"
- Fixed an overlong line warning in the patch "scsi: use block layer
helpers to calculate num of queues"
- Dropped the patch "sched/isolation: Add io_queue housekeeping option" in
favor of simply documenting the housekeeping hk_type enum
- Added the patch "lib/group_cpus: let group_cpu_evenly return number of
groups"
- Collected accumulated Reviewed-by and Acked-by tags
- Split the patchset by moving foundational changes into a separate
preparation series:
https://lore.kernel.org/linux-nvme/20241202-refactor-blk-affinity-helpers-v6-0-27211e9c2cd5@kernel.org/
- Linked to v3: https://lore.kernel.org/r/20240806-isolcpus-io-queues-v3-0-da0eecfeaf8b@suse.de
Changes since v3:
- Integrated patches from Ming Lei
(https://lore.kernel.org/all/20210709081005.421340-1-ming.lei@redhat.com/):
"virtio: add APIs for retrieving vq affinity" and "blk-mq: introduce
blk_mq_dev_map_queues"
- Replaced all instances of blk_mq_pci_map_queues and
blk_mq_virtio_map_queues with the new unified blk_mq_dev_map_queues
- Updated and expanded the helper functions used for calculating the
number of queues
- Added the CPU-to-hctx mapping function specifically to support the
isolcpus=io_queue parameter
- Documented the hk_type enum and the newly introduced isolcpus=io_queue
parameter
- Added the patch "scsi: pm8001: do not overwrite PCI queue mapping"
- Linked to v2: https://lore.kernel.org/r/20240627-isolcpus-io-queues-v2-0-26a32e3c4f75@suse.de
Changes since v2:
- Updated the feature documentation for clarity and completeness
- Split the blk/nvme-pci patch into smaller, logical commits
- Dropped the HK_TYPE_IO_QUEUE macro in favor of reusing
HK_TYPE_MANAGED_IRQ
- Linked to v1: https://lore.kernel.org/r/20240621-isolcpus-io-queues-v1-0-8b169bf41083@suse.de
Aaron Tomlin (1):
genirq/affinity: Restrict managed IRQ affinity to housekeeping CPUs
Daniel Wagner (12):
scsi: aacraid: use block layer helpers to calculate num of queues
lib/group_cpus: remove dead !SMP code
lib/group_cpus: Add group_mask_cpus_evenly()
genirq/affinity: Add cpumask to struct irq_affinity
blk-mq: add blk_mq_{online|possible}_queue_affinity
nvme-pci: use block layer helpers to constrain queue affinity
scsi: Use block layer helpers to constrain queue affinity
virtio: blk/scsi: use block layer helpers to constrain queue affinity
isolation: Introduce io_queue isolcpus type
blk-mq: use hk cpus only when isolcpus=io_queue is enabled
blk-mq: prevent offlining hk CPUs with associated online isolated CPUs
docs: add io_queue flag to isolcpus
.../admin-guide/kernel-parameters.txt | 30 ++-
block/blk-mq-cpumap.c | 192 ++++++++++++++++--
block/blk-mq.c | 42 ++++
drivers/block/virtio_blk.c | 4 +-
drivers/nvme/host/pci.c | 1 +
drivers/scsi/aacraid/comminit.c | 3 +-
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 1 +
drivers/scsi/megaraid/megaraid_sas_base.c | 5 +-
drivers/scsi/mpi3mr/mpi3mr_fw.c | 6 +-
drivers/scsi/mpt3sas/mpt3sas_base.c | 5 +-
drivers/scsi/pm8001/pm8001_init.c | 1 +
drivers/scsi/virtio_scsi.c | 5 +-
include/linux/blk-mq.h | 2 +
include/linux/group_cpus.h | 3 +
include/linux/interrupt.h | 16 +-
include/linux/sched/isolation.h | 1 +
kernel/irq/affinity.c | 38 +++-
kernel/sched/isolation.c | 7 +
lib/group_cpus.c | 66 ++++--
19 files changed, 381 insertions(+), 47 deletions(-)
base-commit: 6596a02b207886e9e00bb0161c7fd59fea53c081
--
2.51.0
^ permalink raw reply
* [PATCH v12 01/13] scsi: aacraid: use block layer helpers to calculate num of queues
From: Aaron Tomlin @ 2026-04-22 18:52 UTC (permalink / raw)
To: axboe, kbusch, hch, sagi, mst
Cc: atomlin, aacraid, James.Bottomley, martin.petersen, liyihang9,
kashyap.desai, sumit.saxena, shivasharan.srikanteshwara,
chandrakanth.patil, sathya.prakash, sreekanth.reddy,
suganath-prabu.subramani, ranjan.kumar, jinpu.wang, tglx, mingo,
peterz, juri.lelli, vincent.guittot, akpm, maz, ruanjinjie,
bigeasy, yphbchou0911, wagi, frederic, longman, chenridong, hare,
kch, ming.lei, tom.leiming, steve, sean, chjohnst, neelx, mproche,
nick.lange, marco.crivellari, linux-block, linux-kernel,
virtualization, linux-nvme, linux-scsi, megaraidlinux.pdl,
mpi3mr-linuxdrv.pdl, MPT-FusionLinux.pdl
In-Reply-To: <20260422185215.100929-1-atomlin@atomlin.com>
From: Daniel Wagner <wagi@kernel.org>
The calculation of the upper limit for queues does not depend solely on
the number of online CPUs; for example, the isolcpus kernel
command-line option must also be considered.
To account for this, the block layer provides a helper function to
retrieve the maximum number of queues. Use it to set an appropriate
upper queue number limit.
Fixes: 94970cfb5f10 ("scsi: use block layer helpers to calculate num of queues")
Signed-off-by: Daniel Wagner <wagi@kernel.org>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
drivers/scsi/aacraid/comminit.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 9bd3f5b868bc..ec165b57182d 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -469,8 +469,7 @@ void aac_define_int_mode(struct aac_dev *dev)
}
/* Don't bother allocating more MSI-X vectors than cpus */
- msi_count = min(dev->max_msix,
- (unsigned int)num_online_cpus());
+ msi_count = blk_mq_num_online_queues(dev->max_msix);
dev->max_msix = msi_count;
--
2.51.0
^ permalink raw reply related
* [PATCH v12 02/13] lib/group_cpus: remove dead !SMP code
From: Aaron Tomlin @ 2026-04-22 18:52 UTC (permalink / raw)
To: axboe, kbusch, hch, sagi, mst
Cc: atomlin, aacraid, James.Bottomley, martin.petersen, liyihang9,
kashyap.desai, sumit.saxena, shivasharan.srikanteshwara,
chandrakanth.patil, sathya.prakash, sreekanth.reddy,
suganath-prabu.subramani, ranjan.kumar, jinpu.wang, tglx, mingo,
peterz, juri.lelli, vincent.guittot, akpm, maz, ruanjinjie,
bigeasy, yphbchou0911, wagi, frederic, longman, chenridong, hare,
kch, ming.lei, tom.leiming, steve, sean, chjohnst, neelx, mproche,
nick.lange, marco.crivellari, linux-block, linux-kernel,
virtualization, linux-nvme, linux-scsi, megaraidlinux.pdl,
mpi3mr-linuxdrv.pdl, MPT-FusionLinux.pdl
In-Reply-To: <20260422185215.100929-1-atomlin@atomlin.com>
From: Daniel Wagner <wagi@kernel.org>
The support for the !SMP configuration has been removed from the core by
commit cac5cefbade9 ("sched/smp: Make SMP unconditional").
While one can technically still compile a uniprocessor kernel, the core
scheduler now mandates SMP unconditionally, rendering this particular
!SMP fallback handling redundant. Therefore, remove the #ifdef CONFIG_SMP
guards and the fallback logic.
Signed-off-by: Daniel Wagner <wagi@kernel.org>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
[atomlin: Updated commit message to clarify !SMP removal context]
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
lib/group_cpus.c | 20 --------------------
1 file changed, 20 deletions(-)
diff --git a/lib/group_cpus.c b/lib/group_cpus.c
index e6e18d7a49bb..b8d54398f88a 100644
--- a/lib/group_cpus.c
+++ b/lib/group_cpus.c
@@ -9,8 +9,6 @@
#include <linux/sort.h>
#include <linux/group_cpus.h>
-#ifdef CONFIG_SMP
-
static void grp_spread_init_one(struct cpumask *irqmsk, struct cpumask *nmsk,
unsigned int cpus_per_grp)
{
@@ -564,22 +562,4 @@ struct cpumask *group_cpus_evenly(unsigned int numgrps, unsigned int *nummasks)
*nummasks = min(nr_present + nr_others, numgrps);
return masks;
}
-#else /* CONFIG_SMP */
-struct cpumask *group_cpus_evenly(unsigned int numgrps, unsigned int *nummasks)
-{
- struct cpumask *masks;
-
- if (numgrps == 0)
- return NULL;
-
- masks = kzalloc_objs(*masks, numgrps);
- if (!masks)
- return NULL;
-
- /* assign all CPUs(cpu 0) to the 1st group only */
- cpumask_copy(&masks[0], cpu_possible_mask);
- *nummasks = 1;
- return masks;
-}
-#endif /* CONFIG_SMP */
EXPORT_SYMBOL_GPL(group_cpus_evenly);
--
2.51.0
^ permalink raw reply related
* [PATCH v12 03/13] lib/group_cpus: Add group_mask_cpus_evenly()
From: Aaron Tomlin @ 2026-04-22 18:52 UTC (permalink / raw)
To: axboe, kbusch, hch, sagi, mst
Cc: atomlin, aacraid, James.Bottomley, martin.petersen, liyihang9,
kashyap.desai, sumit.saxena, shivasharan.srikanteshwara,
chandrakanth.patil, sathya.prakash, sreekanth.reddy,
suganath-prabu.subramani, ranjan.kumar, jinpu.wang, tglx, mingo,
peterz, juri.lelli, vincent.guittot, akpm, maz, ruanjinjie,
bigeasy, yphbchou0911, wagi, frederic, longman, chenridong, hare,
kch, ming.lei, tom.leiming, steve, sean, chjohnst, neelx, mproche,
nick.lange, marco.crivellari, linux-block, linux-kernel,
virtualization, linux-nvme, linux-scsi, megaraidlinux.pdl,
mpi3mr-linuxdrv.pdl, MPT-FusionLinux.pdl
In-Reply-To: <20260422185215.100929-1-atomlin@atomlin.com>
From: Daniel Wagner <wagi@kernel.org>
group_mask_cpu_evenly() allows the caller to pass in a CPU mask that
should be evenly distributed. This new function is a more generic
version of the existing group_cpus_evenly(), which always distributes
all present CPUs into groups.
Signed-off-by: Daniel Wagner <wagi@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
[atomlin: Test numgrps == 0 in group_mask_cpus_evenly()]
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
include/linux/group_cpus.h | 3 ++
lib/group_cpus.c | 62 ++++++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+)
diff --git a/include/linux/group_cpus.h b/include/linux/group_cpus.h
index 9d4e5ab6c314..defab4123a82 100644
--- a/include/linux/group_cpus.h
+++ b/include/linux/group_cpus.h
@@ -10,5 +10,8 @@
#include <linux/cpu.h>
struct cpumask *group_cpus_evenly(unsigned int numgrps, unsigned int *nummasks);
+struct cpumask *group_mask_cpus_evenly(unsigned int numgrps,
+ const struct cpumask *mask,
+ unsigned int *nummasks);
#endif
diff --git a/lib/group_cpus.c b/lib/group_cpus.c
index b8d54398f88a..c55a8970db2a 100644
--- a/lib/group_cpus.c
+++ b/lib/group_cpus.c
@@ -8,6 +8,7 @@
#include <linux/cpu.h>
#include <linux/sort.h>
#include <linux/group_cpus.h>
+#include <linux/sched/isolation.h>
static void grp_spread_init_one(struct cpumask *irqmsk, struct cpumask *nmsk,
unsigned int cpus_per_grp)
@@ -563,3 +564,64 @@ struct cpumask *group_cpus_evenly(unsigned int numgrps, unsigned int *nummasks)
return masks;
}
EXPORT_SYMBOL_GPL(group_cpus_evenly);
+
+/**
+ * group_mask_cpus_evenly - Group all CPUs evenly per NUMA/CPU locality
+ * @numgrps: number of cpumasks to create
+ * @mask: CPUs to consider for the grouping
+ * @nummasks: number of initialized cpusmasks
+ *
+ * Return: cpumask array if successful, NULL otherwise. Only the CPUs
+ * marked in the mask will be considered for the grouping. And each
+ * element includes CPUs assigned to this group. nummasks contains the
+ * number of initialized masks which can be less than numgrps. cpu_mask
+ *
+ * Try to put close CPUs from viewpoint of CPU and NUMA locality into
+ * same group, and run two-stage grouping:
+ * 1) allocate present CPUs on these groups evenly first
+ * 2) allocate other possible CPUs on these groups evenly
+ *
+ * We guarantee in the resulted grouping that all CPUs are covered, and
+ * no same CPU is assigned to multiple groups
+ */
+struct cpumask *group_mask_cpus_evenly(unsigned int numgrps,
+ const struct cpumask *mask,
+ unsigned int *nummasks)
+{
+ cpumask_var_t *node_to_cpumask;
+ cpumask_var_t nmsk;
+ int ret = -ENOMEM;
+ struct cpumask *masks = NULL;
+
+ if (numgrps == 0)
+ return NULL;
+
+ if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL))
+ return NULL;
+
+ node_to_cpumask = alloc_node_to_cpumask();
+ if (!node_to_cpumask)
+ goto fail_nmsk;
+
+ masks = kcalloc(numgrps, sizeof(*masks), GFP_KERNEL);
+ if (!masks)
+ goto fail_node_to_cpumask;
+
+ build_node_to_cpumask(node_to_cpumask);
+
+ ret = __group_cpus_evenly(0, numgrps, node_to_cpumask, mask, nmsk,
+ masks);
+
+fail_node_to_cpumask:
+ free_node_to_cpumask(node_to_cpumask);
+
+fail_nmsk:
+ free_cpumask_var(nmsk);
+ if (ret < 0) {
+ kfree(masks);
+ return NULL;
+ }
+ *nummasks = ret;
+ return masks;
+}
+EXPORT_SYMBOL_GPL(group_mask_cpus_evenly);
--
2.51.0
^ permalink raw reply related
* [PATCH v12 04/13] genirq/affinity: Add cpumask to struct irq_affinity
From: Aaron Tomlin @ 2026-04-22 18:52 UTC (permalink / raw)
To: axboe, kbusch, hch, sagi, mst
Cc: atomlin, aacraid, James.Bottomley, martin.petersen, liyihang9,
kashyap.desai, sumit.saxena, shivasharan.srikanteshwara,
chandrakanth.patil, sathya.prakash, sreekanth.reddy,
suganath-prabu.subramani, ranjan.kumar, jinpu.wang, tglx, mingo,
peterz, juri.lelli, vincent.guittot, akpm, maz, ruanjinjie,
bigeasy, yphbchou0911, wagi, frederic, longman, chenridong, hare,
kch, ming.lei, tom.leiming, steve, sean, chjohnst, neelx, mproche,
nick.lange, marco.crivellari, linux-block, linux-kernel,
virtualization, linux-nvme, linux-scsi, megaraidlinux.pdl,
mpi3mr-linuxdrv.pdl, MPT-FusionLinux.pdl
In-Reply-To: <20260422185215.100929-1-atomlin@atomlin.com>
From: Daniel Wagner <wagi@kernel.org>
Pass a cpumask to irq_create_affinity_masks as an additional constraint
to consider when creating the affinity masks. This allows the caller to
exclude specific CPUs, e.g., isolated CPUs (see the 'isolcpus' kernel
command-line parameter).
Signed-off-by: Daniel Wagner <wagi@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
include/linux/interrupt.h | 16 ++++++++++------
kernel/irq/affinity.c | 12 ++++++++++--
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 6cd26ffb0505..afd5a2c75b43 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -287,18 +287,22 @@ struct irq_affinity_notify {
* @nr_sets: The number of interrupt sets for which affinity
* spreading is required
* @set_size: Array holding the size of each interrupt set
+ * @mask: cpumask that constrains which CPUs to consider when
+ * calculating the number and size of the interrupt sets
* @calc_sets: Callback for calculating the number and size
* of interrupt sets
* @priv: Private data for usage by @calc_sets, usually a
* pointer to driver/device specific data.
*/
struct irq_affinity {
- unsigned int pre_vectors;
- unsigned int post_vectors;
- unsigned int nr_sets;
- unsigned int set_size[IRQ_AFFINITY_MAX_SETS];
- void (*calc_sets)(struct irq_affinity *, unsigned int nvecs);
- void *priv;
+ unsigned int pre_vectors;
+ unsigned int post_vectors;
+ unsigned int nr_sets;
+ unsigned int set_size[IRQ_AFFINITY_MAX_SETS];
+ const struct cpumask *mask;
+ void (*calc_sets)(struct irq_affinity *,
+ unsigned int nvecs);
+ void *priv;
};
/**
diff --git a/kernel/irq/affinity.c b/kernel/irq/affinity.c
index 78f2418a8925..e0cf70a99339 100644
--- a/kernel/irq/affinity.c
+++ b/kernel/irq/affinity.c
@@ -70,7 +70,13 @@ irq_create_affinity_masks(unsigned int nvecs, struct irq_affinity *affd)
*/
for (i = 0, usedvecs = 0; i < affd->nr_sets; i++) {
unsigned int nr_masks, this_vecs = affd->set_size[i];
- struct cpumask *result = group_cpus_evenly(this_vecs, &nr_masks);
+ struct cpumask *result;
+
+ if (affd->mask)
+ result = group_mask_cpus_evenly(this_vecs, affd->mask,
+ &nr_masks);
+ else
+ result = group_cpus_evenly(this_vecs, &nr_masks);
if (!result) {
kfree(masks);
@@ -115,7 +121,9 @@ unsigned int irq_calc_affinity_vectors(unsigned int minvec, unsigned int maxvec,
if (resv > minvec)
return 0;
- if (affd->calc_sets)
+ if (affd->mask)
+ set_vecs = cpumask_weight(affd->mask);
+ else if (affd->calc_sets)
set_vecs = maxvec - resv;
else
set_vecs = cpumask_weight(cpu_possible_mask);
--
2.51.0
^ permalink raw reply related
* [PATCH v12 05/13] blk-mq: add blk_mq_{online|possible}_queue_affinity
From: Aaron Tomlin @ 2026-04-22 18:52 UTC (permalink / raw)
To: axboe, kbusch, hch, sagi, mst
Cc: atomlin, aacraid, James.Bottomley, martin.petersen, liyihang9,
kashyap.desai, sumit.saxena, shivasharan.srikanteshwara,
chandrakanth.patil, sathya.prakash, sreekanth.reddy,
suganath-prabu.subramani, ranjan.kumar, jinpu.wang, tglx, mingo,
peterz, juri.lelli, vincent.guittot, akpm, maz, ruanjinjie,
bigeasy, yphbchou0911, wagi, frederic, longman, chenridong, hare,
kch, ming.lei, tom.leiming, steve, sean, chjohnst, neelx, mproche,
nick.lange, marco.crivellari, linux-block, linux-kernel,
virtualization, linux-nvme, linux-scsi, megaraidlinux.pdl,
mpi3mr-linuxdrv.pdl, MPT-FusionLinux.pdl
In-Reply-To: <20260422185215.100929-1-atomlin@atomlin.com>
From: Daniel Wagner <wagi@kernel.org>
Introduce blk_mq_{online|possible}_queue_affinity, which returns the
queue-to-CPU mapping constraints defined by the block layer. This allows
other subsystems (e.g., IRQ affinity setup) to respect block layer
requirements.
It is necessary to provide versions for both the online and possible CPU
masks because some drivers want to spread their I/O queues only across
online CPUs, while others prefer to use all possible CPUs. And the mask
used needs to match with the number of queues requested
(see blk_num_{online|possible}_queues).
Signed-off-by: Daniel Wagner <wagi@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
block/blk-mq-cpumap.c | 24 ++++++++++++++++++++++++
include/linux/blk-mq.h | 2 ++
2 files changed, 26 insertions(+)
diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c
index 705da074ad6c..8244ecf87835 100644
--- a/block/blk-mq-cpumap.c
+++ b/block/blk-mq-cpumap.c
@@ -26,6 +26,30 @@ static unsigned int blk_mq_num_queues(const struct cpumask *mask,
return min_not_zero(num, max_queues);
}
+/**
+ * blk_mq_possible_queue_affinity - Return block layer queue affinity
+ *
+ * Returns an affinity mask that represents the queue-to-CPU mapping
+ * requested by the block layer based on possible CPUs.
+ */
+const struct cpumask *blk_mq_possible_queue_affinity(void)
+{
+ return cpu_possible_mask;
+}
+EXPORT_SYMBOL_GPL(blk_mq_possible_queue_affinity);
+
+/**
+ * blk_mq_online_queue_affinity - Return block layer queue affinity
+ *
+ * Returns an affinity mask that represents the queue-to-CPU mapping
+ * requested by the block layer based on online CPUs.
+ */
+const struct cpumask *blk_mq_online_queue_affinity(void)
+{
+ return cpu_online_mask;
+}
+EXPORT_SYMBOL_GPL(blk_mq_online_queue_affinity);
+
/**
* blk_mq_num_possible_queues - Calc nr of queues for multiqueue devices
* @max_queues: The maximum number of queues the hardware/driver
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 18a2388ba581..ebc45557aee8 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -969,6 +969,8 @@ int blk_mq_freeze_queue_wait_timeout(struct request_queue *q,
void blk_mq_unfreeze_queue_non_owner(struct request_queue *q);
void blk_freeze_queue_start_non_owner(struct request_queue *q);
+const struct cpumask *blk_mq_possible_queue_affinity(void);
+const struct cpumask *blk_mq_online_queue_affinity(void);
unsigned int blk_mq_num_possible_queues(unsigned int max_queues);
unsigned int blk_mq_num_online_queues(unsigned int max_queues);
void blk_mq_map_queues(struct blk_mq_queue_map *qmap);
--
2.51.0
^ permalink raw reply related
* [PATCH v12 06/13] nvme-pci: use block layer helpers to constrain queue affinity
From: Aaron Tomlin @ 2026-04-22 18:52 UTC (permalink / raw)
To: axboe, kbusch, hch, sagi, mst
Cc: atomlin, aacraid, James.Bottomley, martin.petersen, liyihang9,
kashyap.desai, sumit.saxena, shivasharan.srikanteshwara,
chandrakanth.patil, sathya.prakash, sreekanth.reddy,
suganath-prabu.subramani, ranjan.kumar, jinpu.wang, tglx, mingo,
peterz, juri.lelli, vincent.guittot, akpm, maz, ruanjinjie,
bigeasy, yphbchou0911, wagi, frederic, longman, chenridong, hare,
kch, ming.lei, tom.leiming, steve, sean, chjohnst, neelx, mproche,
nick.lange, marco.crivellari, linux-block, linux-kernel,
virtualization, linux-nvme, linux-scsi, megaraidlinux.pdl,
mpi3mr-linuxdrv.pdl, MPT-FusionLinux.pdl
In-Reply-To: <20260422185215.100929-1-atomlin@atomlin.com>
From: Daniel Wagner <wagi@kernel.org>
Ensure that IRQ affinity setup also respects the queue-to-CPU mapping
constraints provided by the block layer. This allows the NVMe driver
to avoid assigning interrupts to CPUs that the block layer has excluded
(e.g., isolated CPUs).
Signed-off-by: Daniel Wagner <wagi@kernel.org>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
drivers/nvme/host/pci.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index db5fc9bf6627..daa041d15d3c 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -2862,6 +2862,7 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues)
.pre_vectors = 1,
.calc_sets = nvme_calc_irq_sets,
.priv = dev,
+ .mask = blk_mq_possible_queue_affinity(),
};
unsigned int irq_queues, poll_queues;
unsigned int flags = PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY;
--
2.51.0
^ permalink raw reply related
* [PATCH v12 07/13] scsi: Use block layer helpers to constrain queue affinity
From: Aaron Tomlin @ 2026-04-22 18:52 UTC (permalink / raw)
To: axboe, kbusch, hch, sagi, mst
Cc: atomlin, aacraid, James.Bottomley, martin.petersen, liyihang9,
kashyap.desai, sumit.saxena, shivasharan.srikanteshwara,
chandrakanth.patil, sathya.prakash, sreekanth.reddy,
suganath-prabu.subramani, ranjan.kumar, jinpu.wang, tglx, mingo,
peterz, juri.lelli, vincent.guittot, akpm, maz, ruanjinjie,
bigeasy, yphbchou0911, wagi, frederic, longman, chenridong, hare,
kch, ming.lei, tom.leiming, steve, sean, chjohnst, neelx, mproche,
nick.lange, marco.crivellari, linux-block, linux-kernel,
virtualization, linux-nvme, linux-scsi, megaraidlinux.pdl,
mpi3mr-linuxdrv.pdl, MPT-FusionLinux.pdl
In-Reply-To: <20260422185215.100929-1-atomlin@atomlin.com>
From: Daniel Wagner <wagi@kernel.org>
Ensure that IRQ affinity setup also respects the queue-to-CPU mapping
constraints provided by the block layer. This allows the SCSI drivers
to avoid assigning interrupts to CPUs that the block layer has excluded
(e.g., isolated CPUs).
Only convert drivers which are already using the
pci_alloc_irq_vectors_affinity with the PCI_IRQ_AFFINITY flag set.
Because these drivers are enabled to let the IRQ core code to
set the affinity. Also don't update qla2xxx because the nvme-fabrics
code is not ready yet.
Signed-off-by: Daniel Wagner <wagi@kernel.org>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 1 +
drivers/scsi/megaraid/megaraid_sas_base.c | 5 ++++-
drivers/scsi/mpi3mr/mpi3mr_fw.c | 6 +++++-
drivers/scsi/mpt3sas/mpt3sas_base.c | 5 ++++-
drivers/scsi/pm8001/pm8001_init.c | 1 +
5 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index fda07b193137..4873c66b9f98 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -2605,6 +2605,7 @@ static int interrupt_preinit_v3_hw(struct hisi_hba *hisi_hba)
struct pci_dev *pdev = hisi_hba->pci_dev;
struct irq_affinity desc = {
.pre_vectors = BASE_VECTORS_V3_HW,
+ .mask = blk_mq_online_queue_affinity(),
};
min_msi = MIN_AFFINE_VECTORS_V3_HW;
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index ecd365d78ae3..006a3bf0cb06 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -5925,7 +5925,10 @@ static int
__megasas_alloc_irq_vectors(struct megasas_instance *instance)
{
int i, irq_flags;
- struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start };
+ struct irq_affinity desc = {
+ .pre_vectors = instance->low_latency_index_start,
+ .mask = blk_mq_online_queue_affinity(),
+ };
struct irq_affinity *descp = &desc;
irq_flags = PCI_IRQ_MSIX;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 31b19ed1528e..156323ab9465 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -830,7 +830,11 @@ static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
int max_vectors, min_vec;
int retval;
int i;
- struct irq_affinity desc = { .pre_vectors = 1, .post_vectors = 1 };
+ struct irq_affinity desc = {
+ .pre_vectors = 1,
+ .post_vectors = 1,
+ .mask = blk_mq_online_queue_affinity(),
+ };
if (mrioc->is_intr_info_set)
return 0;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 79052f2accbd..91e1622b5b77 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -3370,7 +3370,10 @@ static int
_base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc)
{
int i, irq_flags = PCI_IRQ_MSIX;
- struct irq_affinity desc = { .pre_vectors = ioc->high_iops_queues };
+ struct irq_affinity desc = {
+ .pre_vectors = ioc->high_iops_queues,
+ .mask = blk_mq_online_queue_affinity(),
+ };
struct irq_affinity *descp = &desc;
/*
* Don't allocate msix vectors for poll_queues.
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index e93ea76b565e..6360fa95bcf4 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -978,6 +978,7 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
*/
struct irq_affinity desc = {
.pre_vectors = 1,
+ .mask = blk_mq_online_queue_affinity(),
};
rc = pci_alloc_irq_vectors_affinity(
pm8001_ha->pdev, 2, PM8001_MAX_MSIX_VEC,
--
2.51.0
^ permalink raw reply related
* [PATCH v12 08/13] virtio: blk/scsi: use block layer helpers to constrain queue affinity
From: Aaron Tomlin @ 2026-04-22 18:52 UTC (permalink / raw)
To: axboe, kbusch, hch, sagi, mst
Cc: atomlin, aacraid, James.Bottomley, martin.petersen, liyihang9,
kashyap.desai, sumit.saxena, shivasharan.srikanteshwara,
chandrakanth.patil, sathya.prakash, sreekanth.reddy,
suganath-prabu.subramani, ranjan.kumar, jinpu.wang, tglx, mingo,
peterz, juri.lelli, vincent.guittot, akpm, maz, ruanjinjie,
bigeasy, yphbchou0911, wagi, frederic, longman, chenridong, hare,
kch, ming.lei, tom.leiming, steve, sean, chjohnst, neelx, mproche,
nick.lange, marco.crivellari, linux-block, linux-kernel,
virtualization, linux-nvme, linux-scsi, megaraidlinux.pdl,
mpi3mr-linuxdrv.pdl, MPT-FusionLinux.pdl
In-Reply-To: <20260422185215.100929-1-atomlin@atomlin.com>
From: Daniel Wagner <wagi@kernel.org>
Ensure that IRQ affinity setup also respects the queue-to-CPU mapping
constraints provided by the block layer. This allows the virtio drivers
to avoid assigning interrupts to CPUs that the block layer has excluded
(e.g., isolated CPUs).
Signed-off-by: Daniel Wagner <wagi@kernel.org>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
drivers/block/virtio_blk.c | 4 +++-
drivers/scsi/virtio_scsi.c | 5 ++++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index b1c9a27fe00f..9d737510454b 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -964,7 +964,9 @@ static int init_vq(struct virtio_blk *vblk)
unsigned short num_vqs;
unsigned short num_poll_vqs;
struct virtio_device *vdev = vblk->vdev;
- struct irq_affinity desc = { 0, };
+ struct irq_affinity desc = {
+ .mask = blk_mq_possible_queue_affinity(),
+ };
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_MQ,
struct virtio_blk_config, num_queues,
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 5fdaa71f0652..d0b6a137e9b7 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -847,7 +847,10 @@ static int virtscsi_init(struct virtio_device *vdev,
u32 num_vqs, num_poll_vqs, num_req_vqs;
struct virtqueue_info *vqs_info;
struct virtqueue **vqs;
- struct irq_affinity desc = { .pre_vectors = 2 };
+ struct irq_affinity desc = {
+ .pre_vectors = 2,
+ .mask = blk_mq_possible_queue_affinity(),
+ };
num_req_vqs = vscsi->num_queues;
num_vqs = num_req_vqs + VIRTIO_SCSI_VQ_BASE;
--
2.51.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox