Linux virtualization list
 help / color / mirror / Atom feed
* [PATCH 7.2 v9 1/2] mm/mmu_gather: prepare to skip redundant sync IPIs
From: Lance Yang @ 2026-04-20  3:08 UTC (permalink / raw)
  To: akpm
  Cc: peterz, david, dave.hansen, dave.hansen, ypodemsk, hughd, will,
	aneesh.kumar, npiggin, tglx, mingo, bp, x86, hpa, arnd, ljs, ziy,
	baolin.wang, Liam.Howlett, npache, ryan.roberts, dev.jain, baohua,
	shy828301, riel, jannh, jgross, seanjc, pbonzini, boris.ostrovsky,
	virtualization, kvm, linux-arch, linux-mm, linux-kernel,
	ioworker0, Lance Yang
In-Reply-To: <20260420030851.6735-1-lance.yang@linux.dev>

From: Lance Yang <lance.yang@linux.dev>

When page table operations require synchronization with software/lockless
walkers, they call tlb_remove_table_sync_{one,rcu}() after flushing the
TLB (tlb->freed_tables or tlb->unshared_tables).

On architectures where the TLB flush already sends IPIs to all target CPUs,
the subsequent sync IPI broadcast is redundant. This is not only costly on
large systems where it disrupts all CPUs even for single-process page table
operations, but has also been reported to hurt RT workloads[1].

Introduce tlb_table_flush_implies_ipi_broadcast() to check if the prior TLB
flush already provided the necessary synchronization. When true, the sync
calls can early-return.

A few cases rely on this synchronization:

1) hugetlb PMD unshare[2]: The problem is not the freeing but the reuse
   of the PMD table for other purposes in the last remaining user after
   unsharing.

2) khugepaged collapse[3]: Ensure no concurrent GUP-fast before collapsing
   and (possibly) freeing the page table / re-depositing it.

Currently always returns false (no behavior change). The follow-up patch
will enable the optimization for x86.

[1] https://lore.kernel.org/linux-mm/1b27a3fa-359a-43d0-bdeb-c31341749367@kernel.org/
[2] https://lore.kernel.org/linux-mm/6a364356-5fea-4a6c-b959-ba3b22ce9c88@kernel.org/
[3] https://lore.kernel.org/linux-mm/2cb4503d-3a3f-4f6c-8038-7b3d1c74b3c2@kernel.org/

Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Lance Yang <lance.yang@linux.dev>
---
 include/asm-generic/tlb.h | 17 +++++++++++++++++
 mm/mmu_gather.c           | 15 +++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index bdcc2778ac64..cb41cc6a0024 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -240,6 +240,23 @@ static inline void tlb_remove_table(struct mmu_gather *tlb, void *table)
 }
 #endif /* CONFIG_MMU_GATHER_TABLE_FREE */
 
+/**
+ * tlb_table_flush_implies_ipi_broadcast - does TLB flush imply IPI sync
+ *
+ * When page table operations require synchronization with software/lockless
+ * walkers, they flush the TLB (tlb->freed_tables or tlb->unshared_tables)
+ * then call tlb_remove_table_sync_{one,rcu}(). If the flush already sent
+ * IPIs to all CPUs, the sync call is redundant.
+ *
+ * Returns false by default. Architectures can override by defining this.
+ */
+#ifndef tlb_table_flush_implies_ipi_broadcast
+static inline bool tlb_table_flush_implies_ipi_broadcast(void)
+{
+	return false;
+}
+#endif
+
 #ifdef CONFIG_MMU_GATHER_RCU_TABLE_FREE
 /*
  * This allows an architecture that does not use the linux page-tables for
diff --git a/mm/mmu_gather.c b/mm/mmu_gather.c
index 3985d856de7f..37a6a711c37e 100644
--- a/mm/mmu_gather.c
+++ b/mm/mmu_gather.c
@@ -283,6 +283,14 @@ void tlb_remove_table_sync_one(void)
 	 * It is however sufficient for software page-table walkers that rely on
 	 * IRQ disabling.
 	 */
+
+	/*
+	 * Skip IPI if the preceding TLB flush already synchronized with
+	 * all CPUs that could be doing software/lockless page table walks.
+	 */
+	if (tlb_table_flush_implies_ipi_broadcast())
+		return;
+
 	smp_call_function(tlb_remove_table_smp_sync, NULL, 1);
 }
 
@@ -312,6 +320,13 @@ static void tlb_remove_table_free(struct mmu_table_batch *batch)
  */
 void tlb_remove_table_sync_rcu(void)
 {
+	/*
+	 * Skip RCU wait if the preceding TLB flush already synchronized
+	 * with all CPUs that could be doing software/lockless page table walks.
+	 */
+	if (tlb_table_flush_implies_ipi_broadcast())
+		return;
+
 	synchronize_rcu();
 }
 
-- 
2.49.0


^ permalink raw reply related

* [PATCH 7.2 v9 0/2] skip redundant sync IPIs when TLB flush sent them
From: Lance Yang @ 2026-04-20  3:08 UTC (permalink / raw)
  To: akpm
  Cc: peterz, david, dave.hansen, dave.hansen, ypodemsk, hughd, will,
	aneesh.kumar, npiggin, tglx, mingo, bp, x86, hpa, arnd, ljs, ziy,
	baolin.wang, Liam.Howlett, npache, ryan.roberts, dev.jain, baohua,
	shy828301, riel, jannh, jgross, seanjc, pbonzini, boris.ostrovsky,
	virtualization, kvm, linux-arch, linux-mm, linux-kernel,
	ioworker0

Hi all,

When page table operations require synchronization with software/lockless
walkers, they call tlb_remove_table_sync_{one,rcu}() after flushing the
TLB (tlb->freed_tables or tlb->unshared_tables).

On architectures where the TLB flush already sends IPIs to all target CPUs,
the subsequent sync IPI broadcast is redundant. This is not only costly on
large systems where it disrupts all CPUs even for single-process page table
operations, but has also been reported to hurt RT workloads[1].

This series introduces tlb_table_flush_implies_ipi_broadcast() to check if
the prior TLB flush already provided the necessary synchronization. When
true, the sync calls can early-return.

A few cases rely on this synchronization:

1) hugetlb PMD unshare[2]: The problem is not the freeing but the reuse
   of the PMD table for other purposes in the last remaining user after
   unsharing.

2) khugepaged collapse[3]: Ensure no concurrent GUP-fast before collapsing
   and (possibly) freeing the page table / re-depositing it.

Two-step plan as David suggested[4]:

Step 1 (this series): Skip redundant sync when we're 100% certain the TLB
flush sent IPIs. INVLPGB is excluded because when supported, we cannot
guarantee IPIs were sent, keeping it clean and simple.

Step 2 (future work): Send targeted IPIs only to CPUs actually doing
software/lockless page table walks, benefiting all architectures.

Regarding Step 2, it obviously only applies to setups where Step 1 does not
apply: like x86 with INVLPGB or arm64. Step 2 work is ongoing; early
attempts showed ~3% GUP-fast overhead. Reducing the overhead requires more
work and tuning; it will be submitted separately once ready.

On a 64-core Intel x86 server, the CAL interrupt count in
/proc/interrupts dropped from 646,316 to 785 when collapsing a 20 GiB
range with this series applied.

David Hildenbrand did the initial implementation. I built on his work and
relied on off-list discussions to push it further - thanks a lot David!

[1] https://lore.kernel.org/linux-mm/1b27a3fa-359a-43d0-bdeb-c31341749367@kernel.org/
[2] https://lore.kernel.org/linux-mm/6a364356-5fea-4a6c-b959-ba3b22ce9c88@kernel.org/
[3] https://lore.kernel.org/linux-mm/2cb4503d-3a3f-4f6c-8038-7b3d1c74b3c2@kernel.org/
[4] https://lore.kernel.org/linux-mm/bbfdf226-4660-4949-b17b-0d209ee4ef8c@kernel.org/

v8 -> v9:
- Rebase on mm-new; re-tested, no code changes.
- https://lore.kernel.org/linux-mm/20260324085238.44477-1-lance.yang@linux.dev/

v7 -> v8:
- Pick up Acked-by tags from David, thanks!
- Add CAL interrupt numbers to the cover letter (per Andrew, thanks!)
- Rewrite the [2/2] changelog and reword the comment (per David, thanks!)
- https://lore.kernel.org/linux-mm/20260309020711.20831-1-lance.yang@linux.dev/

v6 -> v7:
- Simplify init logic and eliminate duplicated X86_FEATURE_INVLPGB checks
  (per Dave, thanks!)
- Remove flush_tlb_multi_implies_ipi_broadcast property because no PV
  backend sets it today.
- https://lore.kernel.org/linux-mm/20260304021046.18550-1-lance.yang@linux.dev/

v5 -> v6:
- Use static_branch to eliminate the branch overhead (per Peter, thanks!)
- https://lore.kernel.org/linux-mm/20260302063048.9479-1-lance.yang@linux.dev/

v4 -> v5:
- Drop per-CPU tracking (active_lockless_pt_walk_mm) from this series;
  defer to Step 2 as it adds ~3% GUP-fast overhead
- Keep pv_ops property false for PV backends like KVM: preempted vCPUs
  cannot be assumed safe (per Sean, thanks!)
  https://lore.kernel.org/linux-mm/aaCP95l-m8ISXF78@google.com/
- https://lore.kernel.org/linux-mm/20260202074557.16544-1-lance.yang@linux.dev/ 

v3 -> v4:
- Rework based on David's two-step direction and per-CPU idea:
  1) Targeted IPIs: per-CPU variable when entering/leaving lockless page
     table walk; tlb_remove_table_sync_mm() IPIs only those CPUs.
  2) On x86, pv_mmu_ops property set at init to skip the extra sync when
     flush_tlb_multi() already sends IPIs.
  https://lore.kernel.org/linux-mm/bbfdf226-4660-4949-b17b-0d209ee4ef8c@kernel.org/
- https://lore.kernel.org/linux-mm/20260106120303.38124-1-lance.yang@linux.dev/

v2 -> v3:
- Complete rewrite: use dynamic IPI tracking instead of static checks
  (per Dave Hansen, thanks!)
- Track IPIs via mmu_gather: native_flush_tlb_multi() sets flag when
  actually sending IPIs
- Motivation for skipping redundant IPIs explained by David:
  https://lore.kernel.org/linux-mm/1b27a3fa-359a-43d0-bdeb-c31341749367@kernel.org/
- https://lore.kernel.org/linux-mm/20251229145245.85452-1-lance.yang@linux.dev/

v1 -> v2:
- Fix cover letter encoding to resolve send-email issues. Apologies for
  any email flood caused by the failed send attempts :(

RFC -> v1:
- Use a callback function in pv_mmu_ops instead of comparing function
  pointers (per David)
- Embed the check directly in tlb_remove_table_sync_one() instead of
  requiring every caller to check explicitly (per David)
- Move tlb_table_flush_implies_ipi_broadcast() outside of
  CONFIG_MMU_GATHER_RCU_TABLE_FREE to fix build error on architectures
  that don't enable this config.
  https://lore.kernel.org/oe-kbuild-all/202512142156.cShiu6PU-lkp@intel.com/
- https://lore.kernel.org/linux-mm/20251213080038.10917-1-lance.yang@linux.dev/

Lance Yang (2):
  mm/mmu_gather: prepare to skip redundant sync IPIs
  x86/tlb: skip redundant sync IPIs for native TLB flush

 arch/x86/include/asm/tlb.h      | 18 +++++++++++++++++-
 arch/x86/include/asm/tlbflush.h |  2 ++
 arch/x86/kernel/smpboot.c       |  1 +
 arch/x86/mm/tlb.c               | 15 +++++++++++++++
 include/asm-generic/tlb.h       | 17 +++++++++++++++++
 mm/mmu_gather.c                 | 15 +++++++++++++++
 6 files changed, 67 insertions(+), 1 deletion(-)

-- 
2.49.0

^ permalink raw reply

* [PATCH] virtio_console: Fix spelling mistake "colums" -> "columns"
From: Ethan Carter Edwards @ 2026-04-19  0:49 UTC (permalink / raw)
  To: Amit Shah, Michael S. Tsirkin, Jason Wang, Xuan Zhuo,
	Eugenio Pérez
  Cc: virtualization, linux-kernel, kernel-janitors,
	Ethan Carter Edwards

There is a spelling mistake in a struct description. Fix it.

Signed-off-by: Ethan Carter Edwards <ethan@ethancedwards.com>
---
 include/uapi/linux/virtio_console.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/uapi/linux/virtio_console.h b/include/uapi/linux/virtio_console.h
index 7e6ec2ff0560..0506539e6553 100644
--- a/include/uapi/linux/virtio_console.h
+++ b/include/uapi/linux/virtio_console.h
@@ -44,7 +44,7 @@
 #define VIRTIO_CONSOLE_BAD_ID		(~(__u32)0)
 
 struct virtio_console_config {
-	/* colums of the screens */
+	/* columns of the screens */
 	__virtio16 cols;
 	/* rows of the screens */
 	__virtio16 rows;

---
base-commit: c7275b05bc428c7373d97aa2da02d3a7fa6b9f66
change-id: 20260418-virtio-typo-19cbbad5820d

Best regards,
-- 
Ethan Carter Edwards <ethan@ethancedwards.com>


^ permalink raw reply related

* Re: [PATCH v2] hwrng: virtio: clamp device-reported used.len at copy_data()
From: Michael Bommarito @ 2026-04-18 17:56 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Olivia Mackall, Herbert Xu, linux-crypto, Jason Wang,
	virtualization, linux-kernel
In-Reply-To: <20260418133030-mutt-send-email-mst@kernel.org>

On Sat, Apr 18, 2026 at 1:39 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> Maybe we do I'm just not sure I understand how do
> all these checks help, and for what threat.
> It could be just me being dense.

I also don't feel confident about how much the differences matter.
For background, I think I lifted the pattern from similar issues in
kvm and io_uring.  Your point about request_entropy is right either
way.

Maybe we'll see if anyone else weighs in over the next few days and if
not, I'll go with your shorter fix for v3.

^ permalink raw reply

* Re: [PATCH v2] hwrng: virtio: clamp device-reported used.len at copy_data()
From: Michael S. Tsirkin @ 2026-04-18 17:38 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: Olivia Mackall, Herbert Xu, linux-crypto, Jason Wang,
	virtualization, linux-kernel
In-Reply-To: <CAJJ9bXzgpAR3Gm+mZu=mZJyUrc6bpd+_crOGa7HLxteKxw1DzA@mail.gmail.com>

On Sat, Apr 18, 2026 at 01:25:35PM -0400, Michael Bommarito wrote:
> I think the difference comes back to how much you care about the
> threat model and something like Spectre on the memcpy later in
> copy_data. 

Maybe we do I'm just not sure I understand how do
all these checks help, and for what threat.
It could be just me being dense.

The commit log merely describes use.len being OOB
and also mentions data_idx.
Requests are always for sizeof(vi->data)
and they reset data_idx to 0:

static void request_entropy(struct virtrng_info *vi)
{
        struct scatterlist sg;

        reinit_completion(&vi->have_data);
        vi->data_idx = 0;

        sg_init_one(&sg, vi->data, sizeof(vi->data));

        /* There should always be room for one buffer. */
        virtqueue_add_inbuf(vi->vq, &sg, 1, vi->data, GFP_KERNEL);

        virtqueue_kick(vi->vq);
}


so to me, it looks like
clamping that at sizeof(vi->data) addresses that.


is there another threat you are worried about then?




> The more verbose patch would keep the barrier at the cost
> of the code complexity and a few extra cycles, but then we're back to
> same tradeoffs that have haunted just about everyone.
> 
> Will obviously defer to you on which path is really preferred, so let
> me know if you want v3 with the simple nospec clamp.
> 
> Thanks,
> Michael Bommarito
> 
> On Sat, Apr 18, 2026 at 1:18 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> >
> > On Sat, Apr 18, 2026 at 11:06:13AM -0400, Michael Bommarito wrote:
> > > random_recv_done() stores the device-reported used.len directly into
> > > vi->data_avail.  copy_data() then indexes vi->data[] using
> > > vi->data_idx (advanced by previous copy_data() calls) and issues a
> > > memcpy() without re-validating either value against the posted
> > > buffer size sizeof(vi->data) (SMP_CACHE_BYTES bytes, typically 32
> > > or 64).
> > >
> > > A malicious or buggy virtio-rng backend can set used.len beyond
> > > sizeof(vi->data), steering the memcpy() past the end of the inline
> > > array into adjacent kmalloc-1k slab bytes.  hwrng_fillfn() mixes
> > > those bytes into the guest RNG, and guest root can also observe
> > > them directly via /dev/hwrng.
> > >
> > > Concrete impact is inside the guest:
> > >
> > >  - Memory-safety / hardening: any virtio-rng backend that
> > >    over-reports used.len causes the driver to read past vi->data
> > >    into unrelated slab contents.  hwrng_fillfn() is a kernel thread
> > >    that runs as soon as the device is probed; no guest userspace
> > >    interaction is required to first-trigger the OOB.
> > >
> > >  - Cross-boundary leak (confidential-compute threat model): a
> > >    malicious hypervisor cooperating with a malicious or compromised
> > >    guest root userspace can use /dev/hwrng as a leak channel for
> > >    guest-kernel heap data.  The host sets a large used.len, guest
> > >    root reads /dev/hwrng, and the returned bytes contain guest
> > >    kernel slab contents that were adjacent to vi->data.  In
> > >    practice, confidential-compute guests (SEV-SNP, TDX) usually
> > >    disable virtio-rng entirely, so this path is narrow, but the
> > >    fix is still worth carrying because the underlying
> > >    memory-safety bug contaminates the guest RNG on any host.
> > >
> > > KASAN confirms the OOB on a guest booted under a QEMU 9.0 whose
> > > virtio-rng backend has been patched to report used.len = 0x10000:
> > >
> > >   BUG: KASAN: slab-out-of-bounds in virtio_read+0x394/0x5d0
> > >   Read of size 64 at addr ffff8880089c2220 by task hwrng/52
> > >   Call Trace:
> > >    __asan_memcpy
> > >    virtio_read+0x394/0x5d0
> > >    hwrng_fillfn+0xb2/0x470
> > >    kthread
> > >   Allocated by task 1:
> > >    probe_common+0xa5/0x660
> > >    virtio_dev_probe+0x549/0xbc0
> > >   The buggy address belongs to the object at ffff8880089c2000
> > >    which belongs to the cache kmalloc-1k of size 1024
> > >   The buggy address is located 0 bytes to the right of
> > >    allocated 544-byte region [ffff8880089c2000, ffff8880089c2220)
> > >
> > > Same class of bug as commit c04db81cd028 ("net/9p: Fix buffer
> > > overflow in USB transport layer"), which hardened
> > > usb9pfs_rx_complete() against unchecked device-reported length in
> > > the USB 9p transport.
> > >
> > > With the clamp at point of use and array_index_nospec() in place,
> > > the same harness boots cleanly: copy_data() returns zero for the
> > > bogus report, the device-supplied bytes after data_idx are
> > > discarded, and the driver issues a fresh request.


there should be --- here, btw.

> > > Changes in v2 (per Michael S. Tsirkin review):
> > > - move the bound check from random_recv_done() into copy_data(),
> > >   so the clamp sits immediately next to the memcpy it protects
> > > - clamp to sizeof(vi->data) rather than substituting len = 0, so a
> > >   previously-working but buggy device that occasionally over-reports
> > >   used.len does not start returning zero-length reads
> > > - add array_index_nospec() on vi->data_idx to defeat a speculative
> > >   out-of-bounds read given the malicious-backend threat model
> > > - expand the commit message to describe the /dev/hwrng observation
> > >   path and the hypervisor + guest-root cooperation scenario
> > >
> > > Fixes: f7f510ec1957 ("virtio: An entropy device, as suggested by hpa.")
> > > Cc: stable@vger.kernel.org
> > > Suggested-by: Michael S. Tsirkin <mst@redhat.com>
> > > Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> > > Assisted-by: Claude:claude-opus-4-7
> > > ---
> > >  drivers/char/hw_random/virtio-rng.c | 23 +++++++++++++++++++++--
> > >  1 file changed, 21 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
> > > index 0ce02d7e5048..5e83ffa105e4 100644
> > > --- a/drivers/char/hw_random/virtio-rng.c
> > > +++ b/drivers/char/hw_random/virtio-rng.c
> > > @@ -7,6 +7,7 @@
> > >  #include <asm/barrier.h>
> > >  #include <linux/err.h>
> > >  #include <linux/hw_random.h>
> > > +#include <linux/nospec.h>
> > >  #include <linux/scatterlist.h>
> > >  #include <linux/spinlock.h>
> > >  #include <linux/virtio.h>
> > > @@ -69,8 +70,26 @@ static void request_entropy(struct virtrng_info *vi)
> > >  static unsigned int copy_data(struct virtrng_info *vi, void *buf,
> > >                             unsigned int size)
> > >  {
> > > -     size = min_t(unsigned int, size, vi->data_avail);
> > > -     memcpy(buf, vi->data + vi->data_idx, size);
> > > +     unsigned int idx, avail;
> > > +
> > > +     /*
> > > +      * vi->data_avail was set from the device-reported used.len and
> > > +      * vi->data_idx was advanced by previous copy_data() calls.  A
> > > +      * malicious or buggy virtio-rng backend can drive either past
> > > +      * sizeof(vi->data).  Clamp at point of use and harden the index
> > > +      * with array_index_nospec() so the memcpy() below cannot be
> > > +      * steered into adjacent slab memory, including under
> > > +      * speculation.
> > > +      */
> > > +     avail = min_t(unsigned int, vi->data_avail, sizeof(vi->data));
> > > +     if (vi->data_idx >= avail) {
> > > +             vi->data_avail = 0;
> > > +             request_entropy(vi);
> > > +             return 0;
> > > +     }
> > > +     size = min_t(unsigned int, size, avail - vi->data_idx);
> > > +     idx = array_index_nospec(vi->data_idx, sizeof(vi->data));
> > > +     memcpy(buf, vi->data + idx, size);
> > >       vi->data_idx += size;
> > >       vi->data_avail -= size;
> > >       if (vi->data_avail == 0)
> > > --
> >
> >
> > This came out quite complex.
> > Tell me, will the following do the trick?
> >
> >
> > diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
> > index 0ce02d7e5048..e887a68cc151 100644
> > --- a/drivers/char/hw_random/virtio-rng.c
> > +++ b/drivers/char/hw_random/virtio-rng.c
> > @@ -47,6 +47,8 @@ static void random_recv_done(struct virtqueue *vq)
> >         if (!virtqueue_get_buf(vi->vq, &len))
> >                 return;
> >
> > +       len = array_index_nospec(len, sizeof(vi->data));
> > +
> >         smp_store_release(&vi->data_avail, len);
> >         complete(&vi->have_data);
> >  }
> >
> >
> >
> > > 2.53.0
> >


^ permalink raw reply

* Re: [PATCH v2] hwrng: virtio: clamp device-reported used.len at copy_data()
From: Michael Bommarito @ 2026-04-18 17:25 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Olivia Mackall, Herbert Xu, linux-crypto, Jason Wang,
	virtualization, linux-kernel
In-Reply-To: <20260418131110-mutt-send-email-mst@kernel.org>

I think the difference comes back to how much you care about the
threat model and something like Spectre on the memcpy later in
copy_data.  The more verbose patch would keep the barrier at the cost
of the code complexity and a few extra cycles, but then we're back to
same tradeoffs that have haunted just about everyone.

Will obviously defer to you on which path is really preferred, so let
me know if you want v3 with the simple nospec clamp.

Thanks,
Michael Bommarito

On Sat, Apr 18, 2026 at 1:18 PM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Sat, Apr 18, 2026 at 11:06:13AM -0400, Michael Bommarito wrote:
> > random_recv_done() stores the device-reported used.len directly into
> > vi->data_avail.  copy_data() then indexes vi->data[] using
> > vi->data_idx (advanced by previous copy_data() calls) and issues a
> > memcpy() without re-validating either value against the posted
> > buffer size sizeof(vi->data) (SMP_CACHE_BYTES bytes, typically 32
> > or 64).
> >
> > A malicious or buggy virtio-rng backend can set used.len beyond
> > sizeof(vi->data), steering the memcpy() past the end of the inline
> > array into adjacent kmalloc-1k slab bytes.  hwrng_fillfn() mixes
> > those bytes into the guest RNG, and guest root can also observe
> > them directly via /dev/hwrng.
> >
> > Concrete impact is inside the guest:
> >
> >  - Memory-safety / hardening: any virtio-rng backend that
> >    over-reports used.len causes the driver to read past vi->data
> >    into unrelated slab contents.  hwrng_fillfn() is a kernel thread
> >    that runs as soon as the device is probed; no guest userspace
> >    interaction is required to first-trigger the OOB.
> >
> >  - Cross-boundary leak (confidential-compute threat model): a
> >    malicious hypervisor cooperating with a malicious or compromised
> >    guest root userspace can use /dev/hwrng as a leak channel for
> >    guest-kernel heap data.  The host sets a large used.len, guest
> >    root reads /dev/hwrng, and the returned bytes contain guest
> >    kernel slab contents that were adjacent to vi->data.  In
> >    practice, confidential-compute guests (SEV-SNP, TDX) usually
> >    disable virtio-rng entirely, so this path is narrow, but the
> >    fix is still worth carrying because the underlying
> >    memory-safety bug contaminates the guest RNG on any host.
> >
> > KASAN confirms the OOB on a guest booted under a QEMU 9.0 whose
> > virtio-rng backend has been patched to report used.len = 0x10000:
> >
> >   BUG: KASAN: slab-out-of-bounds in virtio_read+0x394/0x5d0
> >   Read of size 64 at addr ffff8880089c2220 by task hwrng/52
> >   Call Trace:
> >    __asan_memcpy
> >    virtio_read+0x394/0x5d0
> >    hwrng_fillfn+0xb2/0x470
> >    kthread
> >   Allocated by task 1:
> >    probe_common+0xa5/0x660
> >    virtio_dev_probe+0x549/0xbc0
> >   The buggy address belongs to the object at ffff8880089c2000
> >    which belongs to the cache kmalloc-1k of size 1024
> >   The buggy address is located 0 bytes to the right of
> >    allocated 544-byte region [ffff8880089c2000, ffff8880089c2220)
> >
> > Same class of bug as commit c04db81cd028 ("net/9p: Fix buffer
> > overflow in USB transport layer"), which hardened
> > usb9pfs_rx_complete() against unchecked device-reported length in
> > the USB 9p transport.
> >
> > With the clamp at point of use and array_index_nospec() in place,
> > the same harness boots cleanly: copy_data() returns zero for the
> > bogus report, the device-supplied bytes after data_idx are
> > discarded, and the driver issues a fresh request.
> >
> > Changes in v2 (per Michael S. Tsirkin review):
> > - move the bound check from random_recv_done() into copy_data(),
> >   so the clamp sits immediately next to the memcpy it protects
> > - clamp to sizeof(vi->data) rather than substituting len = 0, so a
> >   previously-working but buggy device that occasionally over-reports
> >   used.len does not start returning zero-length reads
> > - add array_index_nospec() on vi->data_idx to defeat a speculative
> >   out-of-bounds read given the malicious-backend threat model
> > - expand the commit message to describe the /dev/hwrng observation
> >   path and the hypervisor + guest-root cooperation scenario
> >
> > Fixes: f7f510ec1957 ("virtio: An entropy device, as suggested by hpa.")
> > Cc: stable@vger.kernel.org
> > Suggested-by: Michael S. Tsirkin <mst@redhat.com>
> > Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> > Assisted-by: Claude:claude-opus-4-7
> > ---
> >  drivers/char/hw_random/virtio-rng.c | 23 +++++++++++++++++++++--
> >  1 file changed, 21 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
> > index 0ce02d7e5048..5e83ffa105e4 100644
> > --- a/drivers/char/hw_random/virtio-rng.c
> > +++ b/drivers/char/hw_random/virtio-rng.c
> > @@ -7,6 +7,7 @@
> >  #include <asm/barrier.h>
> >  #include <linux/err.h>
> >  #include <linux/hw_random.h>
> > +#include <linux/nospec.h>
> >  #include <linux/scatterlist.h>
> >  #include <linux/spinlock.h>
> >  #include <linux/virtio.h>
> > @@ -69,8 +70,26 @@ static void request_entropy(struct virtrng_info *vi)
> >  static unsigned int copy_data(struct virtrng_info *vi, void *buf,
> >                             unsigned int size)
> >  {
> > -     size = min_t(unsigned int, size, vi->data_avail);
> > -     memcpy(buf, vi->data + vi->data_idx, size);
> > +     unsigned int idx, avail;
> > +
> > +     /*
> > +      * vi->data_avail was set from the device-reported used.len and
> > +      * vi->data_idx was advanced by previous copy_data() calls.  A
> > +      * malicious or buggy virtio-rng backend can drive either past
> > +      * sizeof(vi->data).  Clamp at point of use and harden the index
> > +      * with array_index_nospec() so the memcpy() below cannot be
> > +      * steered into adjacent slab memory, including under
> > +      * speculation.
> > +      */
> > +     avail = min_t(unsigned int, vi->data_avail, sizeof(vi->data));
> > +     if (vi->data_idx >= avail) {
> > +             vi->data_avail = 0;
> > +             request_entropy(vi);
> > +             return 0;
> > +     }
> > +     size = min_t(unsigned int, size, avail - vi->data_idx);
> > +     idx = array_index_nospec(vi->data_idx, sizeof(vi->data));
> > +     memcpy(buf, vi->data + idx, size);
> >       vi->data_idx += size;
> >       vi->data_avail -= size;
> >       if (vi->data_avail == 0)
> > --
>
>
> This came out quite complex.
> Tell me, will the following do the trick?
>
>
> diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
> index 0ce02d7e5048..e887a68cc151 100644
> --- a/drivers/char/hw_random/virtio-rng.c
> +++ b/drivers/char/hw_random/virtio-rng.c
> @@ -47,6 +47,8 @@ static void random_recv_done(struct virtqueue *vq)
>         if (!virtqueue_get_buf(vi->vq, &len))
>                 return;
>
> +       len = array_index_nospec(len, sizeof(vi->data));
> +
>         smp_store_release(&vi->data_avail, len);
>         complete(&vi->have_data);
>  }
>
>
>
> > 2.53.0
>

^ permalink raw reply

* Re: [PATCH v2] hwrng: virtio: clamp device-reported used.len at copy_data()
From: Michael S. Tsirkin @ 2026-04-18 17:18 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: Olivia Mackall, Herbert Xu, linux-crypto, Jason Wang,
	virtualization, linux-kernel
In-Reply-To: <20260418150613.3522589-1-michael.bommarito@gmail.com>

On Sat, Apr 18, 2026 at 11:06:13AM -0400, Michael Bommarito wrote:
> random_recv_done() stores the device-reported used.len directly into
> vi->data_avail.  copy_data() then indexes vi->data[] using
> vi->data_idx (advanced by previous copy_data() calls) and issues a
> memcpy() without re-validating either value against the posted
> buffer size sizeof(vi->data) (SMP_CACHE_BYTES bytes, typically 32
> or 64).
> 
> A malicious or buggy virtio-rng backend can set used.len beyond
> sizeof(vi->data), steering the memcpy() past the end of the inline
> array into adjacent kmalloc-1k slab bytes.  hwrng_fillfn() mixes
> those bytes into the guest RNG, and guest root can also observe
> them directly via /dev/hwrng.
> 
> Concrete impact is inside the guest:
> 
>  - Memory-safety / hardening: any virtio-rng backend that
>    over-reports used.len causes the driver to read past vi->data
>    into unrelated slab contents.  hwrng_fillfn() is a kernel thread
>    that runs as soon as the device is probed; no guest userspace
>    interaction is required to first-trigger the OOB.
> 
>  - Cross-boundary leak (confidential-compute threat model): a
>    malicious hypervisor cooperating with a malicious or compromised
>    guest root userspace can use /dev/hwrng as a leak channel for
>    guest-kernel heap data.  The host sets a large used.len, guest
>    root reads /dev/hwrng, and the returned bytes contain guest
>    kernel slab contents that were adjacent to vi->data.  In
>    practice, confidential-compute guests (SEV-SNP, TDX) usually
>    disable virtio-rng entirely, so this path is narrow, but the
>    fix is still worth carrying because the underlying
>    memory-safety bug contaminates the guest RNG on any host.
> 
> KASAN confirms the OOB on a guest booted under a QEMU 9.0 whose
> virtio-rng backend has been patched to report used.len = 0x10000:
> 
>   BUG: KASAN: slab-out-of-bounds in virtio_read+0x394/0x5d0
>   Read of size 64 at addr ffff8880089c2220 by task hwrng/52
>   Call Trace:
>    __asan_memcpy
>    virtio_read+0x394/0x5d0
>    hwrng_fillfn+0xb2/0x470
>    kthread
>   Allocated by task 1:
>    probe_common+0xa5/0x660
>    virtio_dev_probe+0x549/0xbc0
>   The buggy address belongs to the object at ffff8880089c2000
>    which belongs to the cache kmalloc-1k of size 1024
>   The buggy address is located 0 bytes to the right of
>    allocated 544-byte region [ffff8880089c2000, ffff8880089c2220)
> 
> Same class of bug as commit c04db81cd028 ("net/9p: Fix buffer
> overflow in USB transport layer"), which hardened
> usb9pfs_rx_complete() against unchecked device-reported length in
> the USB 9p transport.
> 
> With the clamp at point of use and array_index_nospec() in place,
> the same harness boots cleanly: copy_data() returns zero for the
> bogus report, the device-supplied bytes after data_idx are
> discarded, and the driver issues a fresh request.
> 
> Changes in v2 (per Michael S. Tsirkin review):
> - move the bound check from random_recv_done() into copy_data(),
>   so the clamp sits immediately next to the memcpy it protects
> - clamp to sizeof(vi->data) rather than substituting len = 0, so a
>   previously-working but buggy device that occasionally over-reports
>   used.len does not start returning zero-length reads
> - add array_index_nospec() on vi->data_idx to defeat a speculative
>   out-of-bounds read given the malicious-backend threat model
> - expand the commit message to describe the /dev/hwrng observation
>   path and the hypervisor + guest-root cooperation scenario
> 
> Fixes: f7f510ec1957 ("virtio: An entropy device, as suggested by hpa.")
> Cc: stable@vger.kernel.org
> Suggested-by: Michael S. Tsirkin <mst@redhat.com>
> Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> Assisted-by: Claude:claude-opus-4-7
> ---
>  drivers/char/hw_random/virtio-rng.c | 23 +++++++++++++++++++++--
>  1 file changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
> index 0ce02d7e5048..5e83ffa105e4 100644
> --- a/drivers/char/hw_random/virtio-rng.c
> +++ b/drivers/char/hw_random/virtio-rng.c
> @@ -7,6 +7,7 @@
>  #include <asm/barrier.h>
>  #include <linux/err.h>
>  #include <linux/hw_random.h>
> +#include <linux/nospec.h>
>  #include <linux/scatterlist.h>
>  #include <linux/spinlock.h>
>  #include <linux/virtio.h>
> @@ -69,8 +70,26 @@ static void request_entropy(struct virtrng_info *vi)
>  static unsigned int copy_data(struct virtrng_info *vi, void *buf,
>  			      unsigned int size)
>  {
> -	size = min_t(unsigned int, size, vi->data_avail);
> -	memcpy(buf, vi->data + vi->data_idx, size);
> +	unsigned int idx, avail;
> +
> +	/*
> +	 * vi->data_avail was set from the device-reported used.len and
> +	 * vi->data_idx was advanced by previous copy_data() calls.  A
> +	 * malicious or buggy virtio-rng backend can drive either past
> +	 * sizeof(vi->data).  Clamp at point of use and harden the index
> +	 * with array_index_nospec() so the memcpy() below cannot be
> +	 * steered into adjacent slab memory, including under
> +	 * speculation.
> +	 */
> +	avail = min_t(unsigned int, vi->data_avail, sizeof(vi->data));
> +	if (vi->data_idx >= avail) {
> +		vi->data_avail = 0;
> +		request_entropy(vi);
> +		return 0;
> +	}
> +	size = min_t(unsigned int, size, avail - vi->data_idx);
> +	idx = array_index_nospec(vi->data_idx, sizeof(vi->data));
> +	memcpy(buf, vi->data + idx, size);
>  	vi->data_idx += size;
>  	vi->data_avail -= size;
>  	if (vi->data_avail == 0)
> -- 


This came out quite complex.
Tell me, will the following do the trick?


diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 0ce02d7e5048..e887a68cc151 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -47,6 +47,8 @@ static void random_recv_done(struct virtqueue *vq)
 	if (!virtqueue_get_buf(vi->vq, &len))
 		return;
 
+	len = array_index_nospec(len, sizeof(vi->data));
+
 	smp_store_release(&vi->data_avail, len);
 	complete(&vi->have_data);
 }



> 2.53.0


^ permalink raw reply related

* [PATCH v2] hwrng: virtio: clamp device-reported used.len at copy_data()
From: Michael Bommarito @ 2026-04-18 15:06 UTC (permalink / raw)
  To: Olivia Mackall, Herbert Xu, linux-crypto
  Cc: Michael S . Tsirkin, Jason Wang, virtualization, linux-kernel
In-Reply-To: <20260418000020.1847122-1-michael.bommarito@gmail.com>

random_recv_done() stores the device-reported used.len directly into
vi->data_avail.  copy_data() then indexes vi->data[] using
vi->data_idx (advanced by previous copy_data() calls) and issues a
memcpy() without re-validating either value against the posted
buffer size sizeof(vi->data) (SMP_CACHE_BYTES bytes, typically 32
or 64).

A malicious or buggy virtio-rng backend can set used.len beyond
sizeof(vi->data), steering the memcpy() past the end of the inline
array into adjacent kmalloc-1k slab bytes.  hwrng_fillfn() mixes
those bytes into the guest RNG, and guest root can also observe
them directly via /dev/hwrng.

Concrete impact is inside the guest:

 - Memory-safety / hardening: any virtio-rng backend that
   over-reports used.len causes the driver to read past vi->data
   into unrelated slab contents.  hwrng_fillfn() is a kernel thread
   that runs as soon as the device is probed; no guest userspace
   interaction is required to first-trigger the OOB.

 - Cross-boundary leak (confidential-compute threat model): a
   malicious hypervisor cooperating with a malicious or compromised
   guest root userspace can use /dev/hwrng as a leak channel for
   guest-kernel heap data.  The host sets a large used.len, guest
   root reads /dev/hwrng, and the returned bytes contain guest
   kernel slab contents that were adjacent to vi->data.  In
   practice, confidential-compute guests (SEV-SNP, TDX) usually
   disable virtio-rng entirely, so this path is narrow, but the
   fix is still worth carrying because the underlying
   memory-safety bug contaminates the guest RNG on any host.

KASAN confirms the OOB on a guest booted under a QEMU 9.0 whose
virtio-rng backend has been patched to report used.len = 0x10000:

  BUG: KASAN: slab-out-of-bounds in virtio_read+0x394/0x5d0
  Read of size 64 at addr ffff8880089c2220 by task hwrng/52
  Call Trace:
   __asan_memcpy
   virtio_read+0x394/0x5d0
   hwrng_fillfn+0xb2/0x470
   kthread
  Allocated by task 1:
   probe_common+0xa5/0x660
   virtio_dev_probe+0x549/0xbc0
  The buggy address belongs to the object at ffff8880089c2000
   which belongs to the cache kmalloc-1k of size 1024
  The buggy address is located 0 bytes to the right of
   allocated 544-byte region [ffff8880089c2000, ffff8880089c2220)

Same class of bug as commit c04db81cd028 ("net/9p: Fix buffer
overflow in USB transport layer"), which hardened
usb9pfs_rx_complete() against unchecked device-reported length in
the USB 9p transport.

With the clamp at point of use and array_index_nospec() in place,
the same harness boots cleanly: copy_data() returns zero for the
bogus report, the device-supplied bytes after data_idx are
discarded, and the driver issues a fresh request.

Changes in v2 (per Michael S. Tsirkin review):
- move the bound check from random_recv_done() into copy_data(),
  so the clamp sits immediately next to the memcpy it protects
- clamp to sizeof(vi->data) rather than substituting len = 0, so a
  previously-working but buggy device that occasionally over-reports
  used.len does not start returning zero-length reads
- add array_index_nospec() on vi->data_idx to defeat a speculative
  out-of-bounds read given the malicious-backend threat model
- expand the commit message to describe the /dev/hwrng observation
  path and the hypervisor + guest-root cooperation scenario

Fixes: f7f510ec1957 ("virtio: An entropy device, as suggested by hpa.")
Cc: stable@vger.kernel.org
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
 drivers/char/hw_random/virtio-rng.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 0ce02d7e5048..5e83ffa105e4 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -7,6 +7,7 @@
 #include <asm/barrier.h>
 #include <linux/err.h>
 #include <linux/hw_random.h>
+#include <linux/nospec.h>
 #include <linux/scatterlist.h>
 #include <linux/spinlock.h>
 #include <linux/virtio.h>
@@ -69,8 +70,26 @@ static void request_entropy(struct virtrng_info *vi)
 static unsigned int copy_data(struct virtrng_info *vi, void *buf,
 			      unsigned int size)
 {
-	size = min_t(unsigned int, size, vi->data_avail);
-	memcpy(buf, vi->data + vi->data_idx, size);
+	unsigned int idx, avail;
+
+	/*
+	 * vi->data_avail was set from the device-reported used.len and
+	 * vi->data_idx was advanced by previous copy_data() calls.  A
+	 * malicious or buggy virtio-rng backend can drive either past
+	 * sizeof(vi->data).  Clamp at point of use and harden the index
+	 * with array_index_nospec() so the memcpy() below cannot be
+	 * steered into adjacent slab memory, including under
+	 * speculation.
+	 */
+	avail = min_t(unsigned int, vi->data_avail, sizeof(vi->data));
+	if (vi->data_idx >= avail) {
+		vi->data_avail = 0;
+		request_entropy(vi);
+		return 0;
+	}
+	size = min_t(unsigned int, size, avail - vi->data_idx);
+	idx = array_index_nospec(vi->data_idx, sizeof(vi->data));
+	memcpy(buf, vi->data + idx, size);
 	vi->data_idx += size;
 	vi->data_avail -= size;
 	if (vi->data_avail == 0)
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH] hwrng: virtio: reject invalid used.len from the device
From: Michael S. Tsirkin @ 2026-04-18 12:11 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: Olivia Mackall, Herbert Xu, linux-crypto, linux-kernel,
	Jason Wang, virtualization
In-Reply-To: <CAJJ9bXweZ2k+F5A7rOWSodzTN6UYOP3rf2oBbrVirOuof0tqNg@mail.gmail.com>

On Fri, Apr 17, 2026 at 08:47:09PM -0400, Michael Bommarito wrote:
> On Fri, Apr 17, 2026 at 8:31 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> > Actionable meaning what?
> 
> Well, between the BLAKE2 pass and the fact that 99% of guests already
> shouldn't trust what's above, I agree that actionable doesn't mean
> much to most people, not even for breaking KASLR.
> 
> But after doing some research, I realized that SEV-SNP/TDX guests that
> expect lockdown=confidentiality might actually expect otherwise under
> that security model.  Still not a lot to work with, but more than just
> correctness in those cases, and those might be the environments that
> care the most.

Sorry this went over my head. We are talking about a device where guest
trusts host to feed it randomness, enabling it is already a questionable
enterprise for SEV-SNP/TDX. So what does it matter whether guest gets by
data from host directly or by tricking it into feeding its own data to
it?  It's all supposed to be securely mixed with the cpu rng, right?

I am not arguing we should not fix it, I am trying to figure out
the actual security impact.


> > Maybe clamp at sizeof(vi->data) then? 0 might break buggy devices that
> > were working earlier.
> > Or just clamp where it's used, for clarity.
> > And maybe we need the array_index dance, given
> > you are worried about malicious.
> 
> Happy to send a v2 with those changes but I can only test on a 1-2 TDX
> variants at home and don't have access to an EPYC bare metal box, so
> not very confident about your buggy device point


I am not sure why this matters.

-- 
MST


^ permalink raw reply

* Re: [PATCH] hwrng: virtio: reject invalid used.len from the device
From: Michael Bommarito @ 2026-04-18  0:47 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Olivia Mackall, Herbert Xu, linux-crypto, linux-kernel,
	Jason Wang, virtualization
In-Reply-To: <20260417202330-mutt-send-email-mst@kernel.org>

On Fri, Apr 17, 2026 at 8:31 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> Actionable meaning what?

Well, between the BLAKE2 pass and the fact that 99% of guests already
shouldn't trust what's above, I agree that actionable doesn't mean
much to most people, not even for breaking KASLR.

But after doing some research, I realized that SEV-SNP/TDX guests that
expect lockdown=confidentiality might actually expect otherwise under
that security model.  Still not a lot to work with, but more than just
correctness in those cases, and those might be the environments that
care the most.

> Maybe clamp at sizeof(vi->data) then? 0 might break buggy devices that
> were working earlier.
> Or just clamp where it's used, for clarity.
> And maybe we need the array_index dance, given
> you are worried about malicious.

Happy to send a v2 with those changes but I can only test on a 1-2 TDX
variants at home and don't have access to an EPYC bare metal box, so
not very confident about your buggy device point

^ permalink raw reply

* Re: [PATCH] hwrng: virtio: reject invalid used.len from the device
From: Michael S. Tsirkin @ 2026-04-18  0:31 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: Olivia Mackall, Herbert Xu, linux-crypto, linux-kernel,
	Jason Wang, virtualization
In-Reply-To: <CAJJ9bXzhKTBx4m3-SCM+ccGd6ZhTXTAbRxKekCzidnXY6yXbWg@mail.gmail.com>

On Fri, Apr 17, 2026 at 08:18:06PM -0400, Michael Bommarito wrote:
> "Actionable" is probably the better word there, sorry.

Actionable meaning what?

>  If it were
> otherwise, I wouldn't have filed publicly
> 
> If you end up ACKing the correctness change, I can send v2 with better log
> 
> Thanks,
> Michael Bommarito
> 
> On Fri, Apr 17, 2026 at 8:13 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> >
> > On Fri, Apr 17, 2026 at 08:00:20PM -0400, Michael Bommarito wrote:
> > > random_recv_done() stored the device-reported used.len directly into
> > > vi->data_avail without validating it against the posted buffer size
> > > sizeof(vi->data) (SMP_CACHE_BYTES bytes, typically 32 or 64).  A
> > > malicious or buggy virtio-rng backend could set used.len beyond
> > > vi->data so that the subsequent copy_data() in virtio_read() issues
> > > memcpy() from vi->data + vi->data_idx past the end of the inline
> > > array, reading adjacent kmalloc-1k slab bytes into the hwrng core's
> > > buffer and from there into /dev/hwrng consumers and the kernel
> > > entropy pool.
> > >
> > > Exploitable most clearly in threat models that do not trust the
> > > hypervisor (confidential-compute guests on SEV-SNP or TDX; vhost-user
> > > split backends).
> >
> > Exploitable? I don't get it. How is reading this data into hwrng
> > a problem?
> >
> >
> > > KASAN confirms the OOB on a guest booted under a QEMU 9.0 whose
> > > virtio-rng backend has been patched to report used.len = 0x10000:
> > >
> > >   BUG: KASAN: slab-out-of-bounds in virtio_read+0x394/0x5d0
> > >   Read of size 64 at addr ffff8880089c2220 by task hwrng/52
> > >   Call Trace:
> > >    __asan_memcpy
> > >    virtio_read+0x394/0x5d0
> > >    hwrng_fillfn+0xb2/0x470
> > >    kthread
> > >   Allocated by task 1:
> > >    probe_common+0xa5/0x660
> > >    virtio_dev_probe+0x549/0xbc0
> > >   The buggy address belongs to the object at ffff8880089c2000
> > >    which belongs to the cache kmalloc-1k of size 1024
> > >   The buggy address is located 0 bytes to the right of
> > >    allocated 544-byte region [ffff8880089c2000, ffff8880089c2220)
> > >
> > > hwrng_fillfn is a kernel thread that runs as soon as the device is
> > > probed; no guest userspace interaction is needed.
> > >
> > > Same class of bug as commit c04db81cd028 ("net/9p: Fix buffer overflow in USB transport layer"),
> > > which hardened usb9pfs_rx_complete against unchecked device-reported
> > > length in the USB 9p transport.
> > >
> > > With the added len-vs-sizeof(vi->data) clamp in place the same
> > > harness boots cleanly: the driver logs "bogus used.len" once and
> > > subsequent reads wait for a honest response.
> > >
> > > Fixes: f7f510ec1957 ("virtio: An entropy device, as suggested by hpa.")
> > > Cc: stable@vger.kernel.org
> > > Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> > > Assisted-by: Claude:claude-opus-4-7
> > > ---
> > >  drivers/char/hw_random/virtio-rng.c | 12 ++++++++++++
> > >  1 file changed, 12 insertions(+)
> > >
> > > diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
> > > index 0ce02d7e5048..6cff480787ca 100644
> > > --- a/drivers/char/hw_random/virtio-rng.c
> > > +++ b/drivers/char/hw_random/virtio-rng.c
> > > @@ -47,6 +47,18 @@ static void random_recv_done(struct virtqueue *vq)
> > >       if (!virtqueue_get_buf(vi->vq, &len))
> > >               return;
> > >
> > > +     /*
> > > +      * The device sets used.len; a malicious or buggy backend can
> > > +      * report more bytes than we posted.  Clamp before it reaches
> > > +      * copy_data() which indexes vi->data[].




> > > +      */
> > > +     if (len > sizeof(vi->data)) {
> > > +             dev_err(&vq->vdev->dev,
> > > +                     "bogus used.len %u > buffer size %zu\n",
> > > +                     len, sizeof(vi->data));
> > > +             len = 0;
> > > +     }


Maybe clamp at sizeof(vi->data) then? 0 might break buggy devices that
were working earlier.  
Or just clamp where it's used, for clarity.
And maybe we need the array_index dance, given
you are worried about malicious.


> > > +
> > >       smp_store_release(&vi->data_avail, len);
> > >       complete(&vi->have_data);
> > >  }
> > > --
> > > 2.53.0
> >


^ permalink raw reply

* Re: [PATCH] hwrng: virtio: reject invalid used.len from the device
From: Michael Bommarito @ 2026-04-18  0:18 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Olivia Mackall, Herbert Xu, linux-crypto, linux-kernel,
	Jason Wang, virtualization
In-Reply-To: <20260417201129-mutt-send-email-mst@kernel.org>

"Actionable" is probably the better word there, sorry.  If it were
otherwise, I wouldn't have filed publicly

If you end up ACKing the correctness change, I can send v2 with better log

Thanks,
Michael Bommarito

On Fri, Apr 17, 2026 at 8:13 PM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Fri, Apr 17, 2026 at 08:00:20PM -0400, Michael Bommarito wrote:
> > random_recv_done() stored the device-reported used.len directly into
> > vi->data_avail without validating it against the posted buffer size
> > sizeof(vi->data) (SMP_CACHE_BYTES bytes, typically 32 or 64).  A
> > malicious or buggy virtio-rng backend could set used.len beyond
> > vi->data so that the subsequent copy_data() in virtio_read() issues
> > memcpy() from vi->data + vi->data_idx past the end of the inline
> > array, reading adjacent kmalloc-1k slab bytes into the hwrng core's
> > buffer and from there into /dev/hwrng consumers and the kernel
> > entropy pool.
> >
> > Exploitable most clearly in threat models that do not trust the
> > hypervisor (confidential-compute guests on SEV-SNP or TDX; vhost-user
> > split backends).
>
> Exploitable? I don't get it. How is reading this data into hwrng
> a problem?
>
>
> > KASAN confirms the OOB on a guest booted under a QEMU 9.0 whose
> > virtio-rng backend has been patched to report used.len = 0x10000:
> >
> >   BUG: KASAN: slab-out-of-bounds in virtio_read+0x394/0x5d0
> >   Read of size 64 at addr ffff8880089c2220 by task hwrng/52
> >   Call Trace:
> >    __asan_memcpy
> >    virtio_read+0x394/0x5d0
> >    hwrng_fillfn+0xb2/0x470
> >    kthread
> >   Allocated by task 1:
> >    probe_common+0xa5/0x660
> >    virtio_dev_probe+0x549/0xbc0
> >   The buggy address belongs to the object at ffff8880089c2000
> >    which belongs to the cache kmalloc-1k of size 1024
> >   The buggy address is located 0 bytes to the right of
> >    allocated 544-byte region [ffff8880089c2000, ffff8880089c2220)
> >
> > hwrng_fillfn is a kernel thread that runs as soon as the device is
> > probed; no guest userspace interaction is needed.
> >
> > Same class of bug as commit c04db81cd028 ("net/9p: Fix buffer overflow in USB transport layer"),
> > which hardened usb9pfs_rx_complete against unchecked device-reported
> > length in the USB 9p transport.
> >
> > With the added len-vs-sizeof(vi->data) clamp in place the same
> > harness boots cleanly: the driver logs "bogus used.len" once and
> > subsequent reads wait for a honest response.
> >
> > Fixes: f7f510ec1957 ("virtio: An entropy device, as suggested by hpa.")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> > Assisted-by: Claude:claude-opus-4-7
> > ---
> >  drivers/char/hw_random/virtio-rng.c | 12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> >
> > diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
> > index 0ce02d7e5048..6cff480787ca 100644
> > --- a/drivers/char/hw_random/virtio-rng.c
> > +++ b/drivers/char/hw_random/virtio-rng.c
> > @@ -47,6 +47,18 @@ static void random_recv_done(struct virtqueue *vq)
> >       if (!virtqueue_get_buf(vi->vq, &len))
> >               return;
> >
> > +     /*
> > +      * The device sets used.len; a malicious or buggy backend can
> > +      * report more bytes than we posted.  Clamp before it reaches
> > +      * copy_data() which indexes vi->data[].
> > +      */
> > +     if (len > sizeof(vi->data)) {
> > +             dev_err(&vq->vdev->dev,
> > +                     "bogus used.len %u > buffer size %zu\n",
> > +                     len, sizeof(vi->data));
> > +             len = 0;
> > +     }
> > +
> >       smp_store_release(&vi->data_avail, len);
> >       complete(&vi->have_data);
> >  }
> > --
> > 2.53.0
>

^ permalink raw reply

* Re: [PATCH] hwrng: virtio: reject invalid used.len from the device
From: Michael S. Tsirkin @ 2026-04-18  0:13 UTC (permalink / raw)
  To: Michael Bommarito
  Cc: Olivia Mackall, Herbert Xu, linux-crypto, linux-kernel,
	Jason Wang, virtualization
In-Reply-To: <20260418000020.1847122-1-michael.bommarito@gmail.com>

On Fri, Apr 17, 2026 at 08:00:20PM -0400, Michael Bommarito wrote:
> random_recv_done() stored the device-reported used.len directly into
> vi->data_avail without validating it against the posted buffer size
> sizeof(vi->data) (SMP_CACHE_BYTES bytes, typically 32 or 64).  A
> malicious or buggy virtio-rng backend could set used.len beyond
> vi->data so that the subsequent copy_data() in virtio_read() issues
> memcpy() from vi->data + vi->data_idx past the end of the inline
> array, reading adjacent kmalloc-1k slab bytes into the hwrng core's
> buffer and from there into /dev/hwrng consumers and the kernel
> entropy pool.
> 
> Exploitable most clearly in threat models that do not trust the
> hypervisor (confidential-compute guests on SEV-SNP or TDX; vhost-user
> split backends).

Exploitable? I don't get it. How is reading this data into hwrng
a problem?


> KASAN confirms the OOB on a guest booted under a QEMU 9.0 whose
> virtio-rng backend has been patched to report used.len = 0x10000:
> 
>   BUG: KASAN: slab-out-of-bounds in virtio_read+0x394/0x5d0
>   Read of size 64 at addr ffff8880089c2220 by task hwrng/52
>   Call Trace:
>    __asan_memcpy
>    virtio_read+0x394/0x5d0
>    hwrng_fillfn+0xb2/0x470
>    kthread
>   Allocated by task 1:
>    probe_common+0xa5/0x660
>    virtio_dev_probe+0x549/0xbc0
>   The buggy address belongs to the object at ffff8880089c2000
>    which belongs to the cache kmalloc-1k of size 1024
>   The buggy address is located 0 bytes to the right of
>    allocated 544-byte region [ffff8880089c2000, ffff8880089c2220)
> 
> hwrng_fillfn is a kernel thread that runs as soon as the device is
> probed; no guest userspace interaction is needed.
> 
> Same class of bug as commit c04db81cd028 ("net/9p: Fix buffer overflow in USB transport layer"),
> which hardened usb9pfs_rx_complete against unchecked device-reported
> length in the USB 9p transport.
> 
> With the added len-vs-sizeof(vi->data) clamp in place the same
> harness boots cleanly: the driver logs "bogus used.len" once and
> subsequent reads wait for a honest response.
> 
> Fixes: f7f510ec1957 ("virtio: An entropy device, as suggested by hpa.")
> Cc: stable@vger.kernel.org
> Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> Assisted-by: Claude:claude-opus-4-7
> ---
>  drivers/char/hw_random/virtio-rng.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
> index 0ce02d7e5048..6cff480787ca 100644
> --- a/drivers/char/hw_random/virtio-rng.c
> +++ b/drivers/char/hw_random/virtio-rng.c
> @@ -47,6 +47,18 @@ static void random_recv_done(struct virtqueue *vq)
>  	if (!virtqueue_get_buf(vi->vq, &len))
>  		return;
>  
> +	/*
> +	 * The device sets used.len; a malicious or buggy backend can
> +	 * report more bytes than we posted.  Clamp before it reaches
> +	 * copy_data() which indexes vi->data[].
> +	 */
> +	if (len > sizeof(vi->data)) {
> +		dev_err(&vq->vdev->dev,
> +			"bogus used.len %u > buffer size %zu\n",
> +			len, sizeof(vi->data));
> +		len = 0;
> +	}
> +
>  	smp_store_release(&vi->data_avail, len);
>  	complete(&vi->have_data);
>  }
> -- 
> 2.53.0


^ permalink raw reply

* [PATCH] Bluetooth: virtio_bt: clamp rx length before skb_put
From: Michael Bommarito @ 2026-04-18  0:01 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, linux-bluetooth
  Cc: linux-kernel, Soenke Huster, Michael S . Tsirkin, virtualization

virtbt_rx_work() calls skb_put(skb, len) where len comes directly
from virtqueue_get_buf() with no validation against the skb we
posted.  The RX skb is allocated as alloc_skb(1000) in
virtbt_add_inbuf().  A malicious or buggy virtio-bt backend that
reports used.len larger than the skb's tailroom causes skb_put() to
call skb_over_panic() in net/core/skbuff.c, which triggers
BUG() and panics the guest.

Reproduced on a QEMU 9.0 whose virtio-bt backend reports
used.len = 4096 into a 1000-byte rx skb:

  skbuff: skb_over_panic: text:ffffffff83958e84 len:4096 put:4096
      head:ffff88800c071000 data:ffff88800c071000 tail:0x1000
      end:0x6c0 dev:<NULL>
  ------------[ cut here ]------------
  kernel BUG at net/core/skbuff.c:214!
  Call Trace:
   skb_panic+0x160/0x162
   skb_put.cold+0x31/0x31
   virtbt_rx_work+0x94/0x250
   process_one_work+0x80d/0x1510
   worker_thread+0x4af/0xd20
   kthread+0x2cc/0x3a0

Reject any len that exceeds skb_tailroom().  Drop the skb on the
error path; virtbt_add_inbuf() reposts a fresh one for the next
iteration.  With the check in place the same harness runs without
BUG(); the driver logs "rx reply len %u exceeds skb tailroom %u"
and the device keeps running.

Same class of bug as commit c04db81cd028 ("net/9p: Fix buffer overflow in USB transport layer"),
which hardened the USB 9p transport against unchecked device-reported length.

Fixes: 160fbcf3bfb9 ("Bluetooth: virtio_bt: Use skb_put to set length")
Cc: stable@vger.kernel.org
Cc: Soenke Huster <soenke.huster@eknoes.de>
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
 drivers/bluetooth/virtio_bt.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c
index 76d61af8a275..157e68b6e75f 100644
--- a/drivers/bluetooth/virtio_bt.c
+++ b/drivers/bluetooth/virtio_bt.c
@@ -227,8 +227,15 @@ static void virtbt_rx_work(struct work_struct *work)
 	if (!skb)
 		return;
 
-	skb_put(skb, len);
-	virtbt_rx_handle(vbt, skb);
+	if (len > skb_tailroom(skb)) {
+		bt_dev_err(vbt->hdev,
+			   "rx reply len %u exceeds skb tailroom %u\n",
+			   len, skb_tailroom(skb));
+		kfree_skb(skb);
+	} else {
+		skb_put(skb, len);
+		virtbt_rx_handle(vbt, skb);
+	}
 
 	if (virtbt_add_inbuf(vbt) < 0)
 		return;
-- 
2.53.0


^ permalink raw reply related

* [PATCH] hwrng: virtio: reject invalid used.len from the device
From: Michael Bommarito @ 2026-04-18  0:00 UTC (permalink / raw)
  To: Olivia Mackall, Herbert Xu, linux-crypto
  Cc: linux-kernel, Michael S . Tsirkin, Jason Wang, virtualization

random_recv_done() stored the device-reported used.len directly into
vi->data_avail without validating it against the posted buffer size
sizeof(vi->data) (SMP_CACHE_BYTES bytes, typically 32 or 64).  A
malicious or buggy virtio-rng backend could set used.len beyond
vi->data so that the subsequent copy_data() in virtio_read() issues
memcpy() from vi->data + vi->data_idx past the end of the inline
array, reading adjacent kmalloc-1k slab bytes into the hwrng core's
buffer and from there into /dev/hwrng consumers and the kernel
entropy pool.

Exploitable most clearly in threat models that do not trust the
hypervisor (confidential-compute guests on SEV-SNP or TDX; vhost-user
split backends).

KASAN confirms the OOB on a guest booted under a QEMU 9.0 whose
virtio-rng backend has been patched to report used.len = 0x10000:

  BUG: KASAN: slab-out-of-bounds in virtio_read+0x394/0x5d0
  Read of size 64 at addr ffff8880089c2220 by task hwrng/52
  Call Trace:
   __asan_memcpy
   virtio_read+0x394/0x5d0
   hwrng_fillfn+0xb2/0x470
   kthread
  Allocated by task 1:
   probe_common+0xa5/0x660
   virtio_dev_probe+0x549/0xbc0
  The buggy address belongs to the object at ffff8880089c2000
   which belongs to the cache kmalloc-1k of size 1024
  The buggy address is located 0 bytes to the right of
   allocated 544-byte region [ffff8880089c2000, ffff8880089c2220)

hwrng_fillfn is a kernel thread that runs as soon as the device is
probed; no guest userspace interaction is needed.

Same class of bug as commit c04db81cd028 ("net/9p: Fix buffer overflow in USB transport layer"),
which hardened usb9pfs_rx_complete against unchecked device-reported
length in the USB 9p transport.

With the added len-vs-sizeof(vi->data) clamp in place the same
harness boots cleanly: the driver logs "bogus used.len" once and
subsequent reads wait for a honest response.

Fixes: f7f510ec1957 ("virtio: An entropy device, as suggested by hpa.")
Cc: stable@vger.kernel.org
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
 drivers/char/hw_random/virtio-rng.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 0ce02d7e5048..6cff480787ca 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -47,6 +47,18 @@ static void random_recv_done(struct virtqueue *vq)
 	if (!virtqueue_get_buf(vi->vq, &len))
 		return;
 
+	/*
+	 * The device sets used.len; a malicious or buggy backend can
+	 * report more bytes than we posted.  Clamp before it reaches
+	 * copy_data() which indexes vi->data[].
+	 */
+	if (len > sizeof(vi->data)) {
+		dev_err(&vq->vdev->dev,
+			"bogus used.len %u > buffer size %zu\n",
+			len, sizeof(vi->data));
+		len = 0;
+	}
+
 	smp_store_release(&vi->data_avail, len);
 	complete(&vi->have_data);
 }
-- 
2.53.0


^ permalink raw reply related

* [PATCH 4/4] virtio-scsi: Support scsi_devices without a device wide limit
From: Mike Christie @ 2026-04-17 22:57 UTC (permalink / raw)
  To: martin.petersen, linux-scsi, james.bottomley, virtualization, mst,
	pbonzini, stefanha, eperezma
  Cc: Mike Christie
In-Reply-To: <20260417230751.117836-1-michael.christie@oracle.com>

When exporting a NVMe drive or other high perf multiqueue enabled
devices we may want to pass commands from the guest to the physical
device without been throttled for artificial device wide limits. To
allow the user to tell virtio-scsi that we don't have a LU wide
command limit, this patch uses U32_MAX as a special cmd_per_lun value.

If U32_MAX is used for cmd_per_lun, virtio-scsi will set
SCSI_UNLIMITED_CMD_PER_LUN for the scsi_device's queue limit. In this
case there is no scsi_device wide queue limit and we only go by the
the virtqueue limits (virtqueue limit is translated to scsi host
can_queue which is translated to block layer per hardware queue limit).

There's a small chance of regression where an existing user could be
using U32_MAX and we have been setting the cmd_per_lun to can_queue.
However, I think in the cases the user was doing this, they will want
the new behavior where they are only limited by can_queue because
they have been trying to get the highest queue value possible.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/virtio_scsi.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 0ed8558dad72..9b31f613ad7e 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -953,7 +953,10 @@ static int virtscsi_probe(struct virtio_device *vdev)
 	shost->can_queue = virtqueue_get_vring_size(vscsi->req_vqs[0].vq);
 
 	cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1;
-	shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue);
+	if (cmd_per_lun == U32_MAX)
+		shost->cmd_per_lun = SCSI_UNLIMITED_CMD_PER_LUN;
+	else
+		shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue);
 	shost->max_sectors = virtscsi_config_get(vdev, max_sectors) ?: 0xFFFF;
 
 	/* LUNs > 256 are reported with format 1, so they go in the range
-- 
2.47.1


^ permalink raw reply related

* [PATCH 3/4] scsi: Support scsi_devices without a device wide limit
From: Mike Christie @ 2026-04-17 22:57 UTC (permalink / raw)
  To: martin.petersen, linux-scsi, james.bottomley, virtualization, mst,
	pbonzini, stefanha, eperezma
  Cc: Mike Christie
In-Reply-To: <20260417230751.117836-1-michael.christie@oracle.com>

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;
 
-	/*
-	 * Use .can_queue as budget map's depth because we have to
-	 * support adjusting queue depth from sysfs. Meantime use
-	 * default device queue depth to figure out sbitmap shift
-	 * since we use this queue depth most of times.
-	 */
-	if (scsi_realloc_sdev_budget_map(sdev, depth))
-		goto out_device_destroy;
+		/*
+		 * Use .can_queue as budget map's depth because we have to
+		 * support adjusting queue depth from sysfs. Meantime use
+		 * default device queue depth to figure out sbitmap shift
+		 * since we use this queue depth most of times.
+		 */
+		if (scsi_realloc_sdev_budget_map(sdev, depth))
+			goto out_device_destroy;
 
-	scsi_change_queue_depth(sdev, depth);
+		scsi_change_queue_depth(sdev, depth);
+	}
 
 	if (shost->hostt->sdev_init) {
 		ret = shost->hostt->sdev_init(sdev);
@@ -1108,7 +1110,8 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
 	 * Set up budget map again since memory consumption of the map depends
 	 * on actual queue depth.
 	 */
-	if (hostt->sdev_configure)
+	if (hostt->sdev_configure &&
+	    sdev->host->cmd_per_lun != SCSI_UNLIMITED_CMD_PER_LUN)
 		scsi_realloc_sdev_budget_map(sdev, sdev->queue_depth);
 
 	if (sdev->scsi_level >= SCSI_3)
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 7c747b566bc3..7555898dba25 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -443,6 +443,7 @@ struct scsi_host_template {
 	 */
 #define SCSI_DEFAULT_MAX_SECTORS	1024
 
+#define SCSI_UNLIMITED_CMD_PER_LUN	-1
 	/*
 	 * True if this host adapter can make good use of linked commands.
 	 * This will allow more than one command to be queued to a given
@@ -451,6 +452,9 @@ struct scsi_host_template {
 	 * command block per lun, 2 for two, etc.  Do not set this to 0.
 	 * You should make sure that the host adapter will do the right thing
 	 * before you try setting this above 1.
+	 *
+	 * Adapters that do not have a device limit can set this to
+	 * SCSI_UNLIMITED_CMD_PER_LUN.
 	 */
 	short cmd_per_lun;
 
-- 
2.47.1


^ permalink raw reply related

* [PATCH 1/4] scsi: Fix can_queue comments
From: Mike Christie @ 2026-04-17 22:57 UTC (permalink / raw)
  To: martin.petersen, linux-scsi, james.bottomley, virtualization, mst,
	pbonzini, stefanha, eperezma
  Cc: Mike Christie
In-Reply-To: <20260417230751.117836-1-michael.christie@oracle.com>

The Scsi_Host can_queue comment assumes the old pre-mq can_queue use or
it assumed host_tagset is set. This syncs the scsi_host_template and
Scsi_Host comment so they are in sync.

It also redirects the nr_hw_queues comment to can_queue so we only
have to describe how can_queue and nr_hw_queues are related in one
place.

I also dropped the non-interrupt vs interrupt driven comment because it
doesn't seem to apply anymore.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 include/scsi/scsi_host.h | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index f6e12565a81d..7c747b566bc3 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -381,10 +381,13 @@ struct scsi_host_template {
 	const char *proc_name;
 
 	/*
-	 * This determines if we will use a non-interrupt driven
-	 * or an interrupt driven scheme.  It is set to the maximum number
-	 * of simultaneous commands a single hw queue in HBA will accept
-	 * excluding internal commands.
+	 * If host_tagset is set, this is the maximum number of simultaneous
+	 * commands the host will accept excluding internal commands.
+	 *
+	 * If host_tagset is not set, this is the maximum number simultaneous
+	 * commands a single hw queue in the host will accept excluding
+	 * internal commands. In other words, the total queue depth per host
+	 * is nr_hw_queues * can_queue.
 	 */
 	int can_queue;
 
@@ -631,10 +634,7 @@ struct Scsi_Host {
 
 	int this_id;
 
-	/*
-	 * Number of commands this host can handle at the same time.
-	 * This excludes reserved commands as specified by nr_reserved_cmds.
-	 */
+	/* See scsi_host_template's can_queue. */
 	int can_queue;
 	/*
 	 * Number of reserved commands to allocate, if any.
@@ -653,10 +653,7 @@ struct Scsi_Host {
 	/*
 	 * In scsi-mq mode, the number of hardware queues supported by the LLD.
 	 *
-	 * Note: it is assumed that each hardware queue has a queue depth of
-	 * can_queue. In other words, the total queue depth per host
-	 * is nr_hw_queues * can_queue. However, for when host_tagset is set,
-	 * the total queue depth is can_queue.
+	 * See scsi_host_template's can_queue for queueing requirements.
 	 */
 	unsigned nr_hw_queues;
 	unsigned nr_maps;
-- 
2.47.1


^ permalink raw reply related

* [PATCH 2/4] scsi: qedi: Fix command overqueueing
From: Mike Christie @ 2026-04-17 22:57 UTC (permalink / raw)
  To: martin.petersen, linux-scsi, james.bottomley, virtualization, mst,
	pbonzini, stefanha, eperezma
  Cc: Mike Christie
In-Reply-To: <20260417230751.117836-1-michael.christie@oracle.com>

qedi supports a total of can_queue commands over all queues so set
host_tagset when multiple queues are used.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/qedi/qedi_main.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index 227ff7bd1bdc..0be0a9f30ee2 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -657,6 +657,8 @@ static struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev)
 	qedi->max_sqes = QEDI_SQ_SIZE;
 
 	shost->nr_hw_queues = MIN_NUM_CPUS_MSIX(qedi);
+	if (shost->nr_hw_queues > 1)
+		shost->host_tagset = 1;
 
 	pci_set_drvdata(pdev, qedi);
 
-- 
2.47.1


^ permalink raw reply related

* [PATCH 0/4] scsi: Support devices that don't have a cmd_per_lun limit
From: Mike Christie @ 2026-04-17 22:57 UTC (permalink / raw)
  To: martin.petersen, linux-scsi, james.bottomley, virtualization, mst,
	pbonzini, stefanha, eperezma

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.


^ permalink raw reply

* Re: [PATCH 1/2] vfio/pci: Set up VFIO barmap before creating a DMABUF
From: Matt Evans @ 2026-04-17 19:11 UTC (permalink / raw)
  To: Tian, Kevin, Alex Williamson
  Cc: Ankit Agrawal, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum,
	Alistair Popple, Leon Romanovsky, Kasireddy, Vivek, Kees Cook,
	Zhi Wang, Peter Xu, Alexey Kardashevskiy, Eric Auger,
	kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	virtualization@lists.linux.dev
In-Reply-To: <BN9PR11MB52768421EA5D79C469B899C18C202@BN9PR11MB5276.namprd11.prod.outlook.com>

Hi Kevin, Alex,

On 17/04/2026 06:16, Tian, Kevin wrote:
> 
>> From: Alex Williamson <alex@shazbot.org>
>> Sent: Friday, April 17, 2026 6:44 AM
>>
>> On Wed, 15 Apr 2026 11:14:22 -0700
>> Matt Evans <mattev@meta.com> wrote:
>>
>>> A DMABUF exports access to BAR resources which need to be requested
>>> before the DMABUF is handed out.  Usually the resources are requested
>>> when setting up the barmap when the VFIO device fd is mmap()ed, but
>>> there's no guarantee that's done before a DMABUF is created.
>>>
>>> Set up the barmap (and so request resources) in the DMABUF-creation
>>> path.
>>>
>>> Fixes: 5d74781ebc86c ("vfio/pci: Add dma-buf export support for MMIO
>> regions")
>>> Signed-off-by: Matt Evans <mattev@meta.com>
>>> ---
>>>   drivers/vfio/pci/vfio_pci_dmabuf.c | 9 +++++++++
>>>   1 file changed, 9 insertions(+)
>>>
>>> diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c
>> b/drivers/vfio/pci/vfio_pci_dmabuf.c
>>> index 4ccaf3531e02..fefe7cf4256b 100644
>>> --- a/drivers/vfio/pci/vfio_pci_dmabuf.c
>>> +++ b/drivers/vfio/pci/vfio_pci_dmabuf.c
>>> @@ -272,6 +272,15 @@ int vfio_pci_core_feature_dma_buf(struct
>> vfio_pci_core_device *vdev, u32 flags,
>>>   		goto err_free_priv;
>>>   	}
>>>
>>> +	/*
>>> +	 * See comment in vfio_pci_core_mmap(); ensure PCI regions
>>> +	 * were requested before returning DMABUFs that reference
>>> +	 * them.  Barmap setup does this:
>>> +	 */
>>> +	ret = vfio_pci_core_setup_barmap(vdev, get_dma_buf.region_index);
>>> +	if (ret)
>>> +		goto err_free_phys;
>>> +
>>>   	priv->vdev = vdev;
>>>   	priv->nr_ranges = get_dma_buf.nr_ranges;
>>>   	priv->size = length;
>>
>> Wouldn't this get a lot easier if we just setup all the barmaps in
>> vfio_pci_core_enable(), conditional on pci_resource_len() just like we
>> use to filter in REGION_INFO?
>>
>> I don't recall if there's some reason we've avoid this so far, maybe
>> others can shout it out if they do.
> 
> I don't remember too. probably just because it's not a wide requirement
> then was made in this on-demand approach...
> 
>>
>> We already tear them all down in vfio_pci_core_disable().  It would be
>> a small patch to add that, which we would mark as Fixes:, then a small
>> follow-up on top of that that removes any then redundant or unnecessary
>> callers (all of them).  Thoughts?  Thanks,
>>
> 
> Agree. then the next patch fixing the racing conditions is also not required.

Oh, if we can do it earlier it's all much cleaner, agreed.  I'd naively 
thought there was a reason it was done lazily.  One benefit is truly 
huge TB-scale BARs don't get ioremap()ed until actually used by 
userspace.  I can't think of a good usage example that relies on open 
performance.

If you say fine, then great:  Ignore these, and I'll post a new pair of 
patches doing that (...with a cover letter this time).


Thank you,


Matt

^ permalink raw reply

* Re: [PATCH v11 11/13] blk-mq: prevent offlining hk CPUs with associated online isolated CPUs
From: Aaron Tomlin @ 2026-04-17 18:06 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: <20260417161116.373130-1-marco.crivellari@suse.com>

[-- Attachment #1: Type: text/plain, Size: 304 bytes --]

On Fri, Apr 17, 2026 at 06:11:16PM +0200, Marco Crivellari wrote:
> Hi,
> 
> Seems like the commit log of this patch is duplicated, isn't it?
> I noticed it's like this from v7.
> 
Hi Marco,

Yes, that is correct. Thank you for bringing this to my attention.

Kind regards,
-- 
Aaron Tomlin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH v11 11/13] blk-mq: prevent offlining hk CPUs with associated online isolated CPUs
From: Marco Crivellari @ 2026-04-17 16:11 UTC (permalink / raw)
  To: atomlin
  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,
	Marco Crivellari
In-Reply-To: <20260416192942.1243421-12-atomlin@atomlin.com>

Hi,

Seems like the commit log of this patch is duplicated, isn't it?
I noticed it's like this from v7.

Thanks!

--

Marco Crivellari

SUSE Labs


^ permalink raw reply

* [PATCH] virtio: rtc: tear down old virtqueues before restore
From: JiaJia @ 2026-04-17  9:08 UTC (permalink / raw)
  To: Peter Hilber, Michael S. Tsirkin, Jason Wang
  Cc: Xuan Zhuo, Eugenio Pérez, virtualization, linux-kernel,
	JiaJia

virtio_device_restore() resets the device and restores the negotiated
features before calling ->restore(). viortc_freeze() intentionally
leaves the existing virtqueues in place so the alarm queue can still
wake the system, but viortc_restore() immediately calls
viortc_init_vqs() without first deleting those old queues.

If virtqueue reinitialization fails on virtio-pci, the transport error
path runs vp_del_vqs() against a new vp_dev->vqs array while vdev->vqs
still holds the old virtqueues. vp_del_vqs() then looks up queue state
through that new array and can dereference a NULL info pointer in
vp_del_vq(), crashing the guest kernel during restore.

Delete any old virtqueues before rebuilding them, and clear the cached
queue pointers so later message requests fail cleanly if restore does
not complete.

Signed-off-by: JiaJia <physicalmtea@gmail.com>
---
Runtime evidence from a standard hibernation test_resume run on a guest
with virtio-rtc-pci (no fault injection):

  KASAN null-ptr-deref report in vp_del_vq.isra.0+0x70/0xd0

  Call trace:
    vp_del_vq.isra.0+0x70/0xd0
    vp_del_vqs+0xec/0x358
    vp_find_vqs_msix+0x24c/0x6a8
    vp_find_vqs+0x88/0x360
    vp_modern_find_vqs+0x20/0x90
    viortc_init_vqs+0xd0/0x128
    viortc_restore+0x28/0xb8
    virtio_device_restore_priv+0x184/0x288
    virtio_pci_restore+0x44/0x58

 drivers/virtio/virtio_rtc_driver.c | 38 ++++++++++++++++++++++++++----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/virtio/virtio_rtc_driver.c b/drivers/virtio/virtio_rtc_driver.c
index a57d5e06e..c1adde27d 100644
--- a/drivers/virtio/virtio_rtc_driver.c
+++ b/drivers/virtio/virtio_rtc_driver.c
@@ -427,6 +427,15 @@ static int viortc_msg_xfer(struct viortc_vq *vq, struct viortc_msg *msg,
 	sg_init_one(out_sg, msg->req, msg->req_size);
 	sg_init_one(in_sg, msg->resp, msg->resp_cap);
 
+	if (!vq->vq) {
+		/*
+		 * Keep runtime interfaces in a safe failed state if restore
+		 * teardown removed the virtqueues.
+		 */
+		viortc_msg_release(msg);
+		return -ENODEV;
+	}
+
 	spin_lock_irqsave(&vq->lock, flags);
 
 	ret = virtqueue_add_sgs(vq->vq, sgs, 1, 1, msg, GFP_ATOMIC);
@@ -478,6 +487,17 @@ static int viortc_msg_xfer(struct viortc_vq *vq, struct viortc_msg *msg,
 	return 0;
 }
 
+static void viortc_del_vqs(struct viortc_dev *viortc)
+{
+	struct virtio_device *vdev = viortc->vdev;
+	unsigned int i;
+
+	vdev->config->del_vqs(vdev);
+
+	for (i = 0; i < ARRAY_SIZE(viortc->vqs); i++)
+		viortc->vqs[i].vq = NULL;
+}
+
 /*
  * common message handle macros for messages of different types
  */
@@ -1316,7 +1336,7 @@ static int viortc_probe(struct virtio_device *vdev)
 
 err_reset_vdev:
 	virtio_reset_device(vdev);
-	vdev->config->del_vqs(vdev);
+	viortc_del_vqs(viortc);
 
 	return ret;
 }
@@ -1332,7 +1352,7 @@ static void viortc_remove(struct virtio_device *vdev)
 	viortc_clocks_deinit(viortc);
 
 	virtio_reset_device(vdev);
-	vdev->config->del_vqs(vdev);
+	viortc_del_vqs(viortc);
 }
 
 static int viortc_freeze(struct virtio_device *dev)
@@ -1353,9 +1373,11 @@ static int viortc_restore(struct virtio_device *dev)
 	bool notify = false;
 	int ret;
 
+	viortc_del_vqs(viortc);
+
 	ret = viortc_init_vqs(viortc);
 	if (ret)
-		return ret;
+		goto err_del_vqs;
 
 	alarm_viortc_vq = &viortc->vqs[VIORTC_ALARMQ];
 	alarm_vq = alarm_viortc_vq->vq;
@@ -1364,16 +1386,22 @@ static int viortc_restore(struct virtio_device *dev)
 		ret = viortc_populate_vq(viortc, alarm_viortc_vq,
 					 VIORTC_ALARMQ_BUF_CAP, false);
 		if (ret)
-			return ret;
+			goto err_del_vqs;
 
 		notify = virtqueue_kick_prepare(alarm_vq);
 	}
 
 	virtio_device_ready(dev);
 
-	if (notify && !virtqueue_notify(alarm_vq))
+	if (notify && !virtqueue_notify(alarm_vq)) {
 		ret = -EIO;
+		goto err_del_vqs;
+	}
+
+	return ret;
 
+err_del_vqs:
+	viortc_del_vqs(viortc);
 	return ret;
 }
 
-- 
2.34.1

^ permalink raw reply related

* [RFC PATCH v2 4/4] virtio-mmio: wire up noirq system sleep PM callbacks
From: Sungho Bae @ 2026-04-17 13:34 UTC (permalink / raw)
  To: mst, jasowang
  Cc: xuanzhuo, eperezma, virtualization, linux-kernel, Sungho Bae
In-Reply-To: <20260417133430.507-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 | 131 ++++++++++++++++++++++++-----------
 1 file changed, 92 insertions(+), 39 deletions(-)

diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index 595c2274fbb5..7cde042e15ac 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-init vring */
+		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,
@@ -553,8 +587,27 @@ static int virtio_mmio_restore(struct device *dev)
 	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


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox