All of lore.kernel.org
 help / color / mirror / Atom feed
From: Samuel Crossley <samuelcrossley@gmail.com>
To: Alex Williamson <alex@shazbot.org>
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	 Samuel Crossley <samuelcrossley@gmail.com>
Subject: [PATCH v2] vfio/type1: avoid walking reserved-only mappings while unpinning
Date: Sat, 19 Sep 2026 15:13:03 -0700	[thread overview]
Message-ID: <20260919-vfio-v2-1-68e7ed355972@gmail.com> (raw)

Tearing down a large device-passthrough DMA mapping can process tens of
millions of reserved pfns in a single VFIO_IOMMU_UNMAP_DMA.  A 128 GiB
reserved mapping holds about 33.6 million 4KiB pfns, and
vfio_unpin_pages_remote() walks every one of them whenever dma->has_rsvd
is set, because reserved and non-reserved pfns might be mixed.  For a
mapping that contains only reserved pfns every put_pfn() is a no-op, but
each one still pays for the pfn_valid()/PageReserved() classification.

Seen on GPU-passthrough hosts running 6.13 with the v6.18 type1 series
backported, where a single VFIO_IOMMU_UNMAP_DMA held a CPU past the
soft-lockup watchdog (host identification, register dump and module list
trimmed):

 watchdog: BUG: soft lockup - CPU#261 stuck for 22s! [qemu-system-x86:134503]
 RIP: 0010:vfio_unpin_pages_remote+0x139/0x2a0 [vfio_iommu_type1]
 Code: 90 4c 89 e1 48 c1 e9 34 75 74 4c 89 e1 48 c1 e9 22 75 6b 48 8b 0d f7 6f c2 e3 48 85 c9 74 5f 4c 89 e2 48 c1 ea 16 48 8b 0c d1 <48> 85 c9 74 4f 41 8b 55 30 4c 89 e6 48 c1 ee 0f 83 e6 7f c1 e6 05
 Call Trace:
  <IRQ>
  ? watchdog_timer_fn+0x3d6/0x440
  ? running_clock+0x10/0x10
  ? hrtimer_interrupt+0x185/0x580
  ? __sysvec_apic_timer_interrupt+0x44/0xe0
  ? sysvec_apic_timer_interrupt+0x6b/0x80
  </IRQ>
  <TASK>
  ? asm_sysvec_apic_timer_interrupt+0x16/0x20
  ? vfio_unpin_pages_remote+0x139/0x2a0 [vfio_iommu_type1]
  vfio_sync_unpin+0x96/0xf0 [vfio_iommu_type1]
  vfio_unmap_unpin+0x324/0x3d0 [vfio_iommu_type1]
  vfio_remove_dma+0x25/0xa0 [vfio_iommu_type1]
  vfio_iommu_type1_ioctl+0xcd5/0x1760 [vfio_iommu_type1]
  ? amd_pmu_v2_enable_all+0xa/0x30
  ? perf_pmu_sched_task+0xbf/0xf0
  x64_sys_call+0x282/0x1ac0
  ? syscall_trace_enter+0x1e5/0x1f0
  do_syscall_64+0x68/0x130
  entry_SYSCALL_64_after_hwframe+0x4b/0x53

RIP is the mem_section root test in pfn_valid(), inlined into put_pfn()
through is_invalid_reserved_pfn(), so the stall is in the dma->has_rsvd
per-page loop.  mem_section[] has no root for that pfn, so pfn_valid()
returns false and put_pfn() does nothing - for every pfn in the mapping.

Track whether the mapping also contains non-reserved pfns and skip the
walk entirely for reserved-only mappings.  Mixed mappings keep the
existing per-pfn walk, and ordinary mappings keep the existing batched
unpin path.

Tested on an affected host: reserved-only mappings up to 128 GiB take the
new path and complete in microseconds.  The ordinary-page path was
exercised unchanged.

Suggested-by: Alex Williamson <alex@shazbot.org>
Link: https://lore.kernel.org/all/20260803154707.71cc0d6b@shazbot.org/
Signed-off-by: Samuel Crossley <samuelcrossley@gmail.com>
---
This is the reserved-only fast path you suggested on v1, tested on
the affected hosts. There is indeed no evidence that the non-reserved
VFIO path needs chunking, and agree any such change to
unpin_user_page_range_dirty_lock() would belong in mm, so not
including it in this patch.
---
Changes in v2:
- Replace v1's cond_resched() chunking with the reserved-only fast path.
- Tested on an affected host; reserved-only mappings up to 128 GiB now
  complete in microseconds instead of walking ~33.6M pfns.
- Link to v1: https://patch.msgid.link/20260723-vfio-v1-1-3b59579916c6@gmail.com
---
 drivers/vfio/vfio_iommu_type1.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index c8151ba54de3..f7addfbe1aab 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -94,6 +94,7 @@ struct vfio_dma {
 	bool			lock_cap;	/* capable(CAP_IPC_LOCK) */
 	bool			vaddr_invalid;
 	bool			has_rsvd;	/* has 1 or more rsvd pfns */
+	bool			has_non_rsvd;	/* has 1 or more !rsvd pfns */
 	struct task_struct	*task;
 	struct rb_root		pfn_list;	/* Ex-user pinned pfn list */
 	unsigned long		*bitmap;
@@ -791,6 +792,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
 
 out:
 	dma->has_rsvd |= rsvd;
+	dma->has_non_rsvd |= !rsvd;
 	ret = vfio_lock_acct(dma, lock_acct, false);
 
 unpin_out:
@@ -821,11 +823,13 @@ static long vfio_unpin_pages_remote(struct vfio_dma *dma, dma_addr_t iova,
 	long unlocked = 0, locked = vpfn_pages(dma, iova, npage);
 
 	if (dma->has_rsvd) {
-		unsigned long i;
+		if (dma->has_non_rsvd) {
+			unsigned long i;
 
-		for (i = 0; i < npage; i++)
-			if (put_pfn(pfn++, dma->prot))
-				unlocked++;
+			for (i = 0; i < npage; i++)
+				if (put_pfn(pfn++, dma->prot))
+					unlocked++;
+		}
 	} else {
 		put_valid_unreserved_pfns(pfn, npage, dma->prot);
 		unlocked = npage;

---
base-commit: 4e3c1fc8abcb8eff062150b4340fa4569696d645
change-id: 20260723-vfio-decd86bf3cf6

Best regards,
--  
Samuel Crossley <samuelcrossley@gmail.com>


             reply	other threads:[~2026-09-19 22:17 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-19 22:13 Samuel Crossley [this message]
2026-09-25 20:49 ` [PATCH v2] vfio/type1: avoid walking reserved-only mappings while unpinning Alex Williamson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260919-vfio-v2-1-68e7ed355972@gmail.com \
    --to=samuelcrossley@gmail.com \
    --cc=alex@shazbot.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.