* [PATCH 1/2] vfio/type1: Periodically try rescheduling when unmapping
2026-07-14 21:03 [PATCH 0/2] vfio/iommufd: Prevent scheduler warnings when unmapping large regions Aaron Lewis
@ 2026-07-14 21:03 ` Aaron Lewis
2026-07-14 21:15 ` sashiko-bot
2026-07-14 21:03 ` [PATCH 2/2] iommufd: Periodically reschedule " Aaron Lewis
1 sibling, 1 reply; 5+ messages in thread
From: Aaron Lewis @ 2026-07-14 21:03 UTC (permalink / raw)
To: kvm; +Cc: alex, dmatlack, jgg, Aaron Lewis
Unmapping large DMA regions can be slow and cause a CPU core to be
unresponsive for a long period of time, leading to kernel scheduler
warnings.
For example:
[ 1404.810673] sched: CPU 19 need_resched set for > 100000026 ns (100 ticks) without schedule
[ 1404.810679] CPU: 19 UID: 0 PID: 34615 Comm: vfio_dma_mappin Kdump: loaded Not tainted 7.1.0-smp-DEV #2 PREEMPTLAZY
[ 1404.810682] Call trace:
[ 1404.810700] resched_latency_warn+0x7c/0x88
[ 1404.810704] sched_tick+0x18c/0x208
[ 1404.810708] update_process_times+0xa8/0xd8
[ 1404.810711] tick_nohz_handler+0x120/0x1c8
[ 1404.810713] __hrtimer_run_queues+0x124/0x3a0
[ 1404.810716] hrtimer_interrupt+0xdc/0x2c0
[ 1404.810718] arch_timer_handler_phys+0x3c/0x58
[ 1404.810721] handle_percpu_devid_irq+0x144/0x1b8
[ 1404.810723] generic_handle_domain_irq+0x44/0x70
[ 1404.810725] gic_handle_irq+0x1b8/0x320
[ 1404.810726] call_on_irq_stack+0x30/0x48
[ 1404.810727] do_interrupt_handler+0x54/0x80
[ 1404.810734] __arm_lpae_iopte_walk+0x15c/0x1b8 (P)
[ 1404.810736] arm_lpae_iova_to_phys+0x60/0xf0
[ 1404.810737] arm_smmu_iova_to_phys+0x24/0x38
[ 1404.810739] iommu_iova_to_phys+0x38/0x58
[ 1404.810752] vfio_unmap_unpin+0x8/0x1c0
[ 1404.810753] vfio_remove_dma+0x38/0x140
[ 1404.810757] vfio_iommu_type1_ioctl+0x8/0xc80
Note that in order for this warning to fire, the kernel must be built
without preemption, or... for testing, the code around the for loop
can explicitly disable preemption.
This warning was produced on ARM using the VFIO selftest
vfio_dma_mapping_perf_test:
./vfio_dma_mapping_perf_test -p -b 256G -a "-v vfio_type1_iommu_anonymous_hugetlb_1gb"
To profile the unmap flow, bpftrace was used with the tooling
described at:
https://lore.kernel.org/kvm/20260630141152.3757722-2-aaronlewis@google.com/
To isolate parts of the runtime, two temporary helper functions were
added to vfio_unmap_unpin() during testing: vfio_try_unpin(), which
encapsulated the outer while loop, and vfio_get_largest_chunk(), which
encapsulated the inner for loop. Doing this helped identify where the
latency issues were coming from and how the code flowed.
The results show:
vfio_iommu_type1_unmap_dma, thread_time = 1124.85ms, count = 1
vfio_unmap_unpin, thread_time = 1124.84ms, count = 1
vfio_try_unpin, thread_time = 1124.80ms, count = 1
vfio_get_largest_chunk, thread_time = 1124.79ms, count = 1
This shows that the execution time is spent entirely inside the
inner for loop. Furthermore, the loop is entered only once. Therefore,
To avoid the scheduler warning and allow the system to remain responsive,
add a cond_resched() to the inner for loop in vfio_unmap_unpin().
Also, limit the cond_resched() to once per 1GB to rate limit
it.
Additional context on what consumes time within the inner loop can be
seen in this sample profile from perf:
24.13% [vfio_dma_mapping_perf_test] ([vfio_dma_mapping_perf_test])
24.12% vfs_ioctl (ioctl.c) Inlined
24.12% vfio_fops_unl_ioctl (container.c)
24.12% vfio_iommu_type1_ioctl (vfio_iommu_type1.c)
19.66% vfio_iommu_type1_unmap_dma (vfio_iommu_type1.c) Inlined
19.66% vfio_dma_do_unmap (vfio_iommu_type1.c) Inlined
19.66% vfio_remove_dma (vfio_iommu_type1.c)
19.66% vfio_unmap_unpin (vfio_iommu_type1.c)
19.65% vfio_try_unpin (vfio_iommu_type1.c)
19.10% vfio_get_largest_chunk (vfio_iommu_type1.c)
15.91% iommu_iova_to_phys (iommu.c)
15.18% arm_smmu_iova_to_phys (arm-smmu-v3.c)
14.09% arm_lpae_iova_to_phys (io-pgtable-arm.c)
11.59% __arm_lpae_iopte_walk (io-pgtable-arm.c)
8.51% io_pgtable_visit (io-pgtable-arm.c) Inlined
5.27% __arm_lpae_iopte_walk (io-pgtable-arm.c)
2.64% io_pgtable_visit (io-pgtable-arm.c) Inlined
Signed-off-by: Aaron Lewis <aaronlewis@google.com>
---
drivers/vfio/vfio_iommu_type1.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index c8151ba54de3..e78bc07d9b6e 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -1153,6 +1153,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma,
int unmapped_region_cnt = 0;
long unlocked = 0;
size_t pos = 0;
+ int i = 0;
if (!dma->size)
return 0;
@@ -1196,6 +1197,8 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma,
next = iommu_iova_to_phys(domain->domain, iova + len);
if (next != phys + len)
break;
+ if ((++i % BIT(PUD_ORDER)) == 0)
+ cond_resched();
}
/*
--
2.55.0.141.g00534a21ce-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/2] iommufd: Periodically reschedule when unmapping
2026-07-14 21:03 [PATCH 0/2] vfio/iommufd: Prevent scheduler warnings when unmapping large regions Aaron Lewis
2026-07-14 21:03 ` [PATCH 1/2] vfio/type1: Periodically try rescheduling when unmapping Aaron Lewis
@ 2026-07-14 21:03 ` Aaron Lewis
2026-07-14 21:34 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Aaron Lewis @ 2026-07-14 21:03 UTC (permalink / raw)
To: kvm; +Cc: alex, dmatlack, jgg, Aaron Lewis
Unmapping large DMA regions can be slow and cause a CPU core to be
unresponsive for a long period of time, leading to kernel scheduler
warnings.
For example:
[ 1389.148910] vfio-pci 0007:01:01.3: resetting
[ 1389.252814] vfio-pci 0007:01:01.3: reset done
[ 1392.943771] sched: CPU 49 need_resched set for > 100000053 ns (100 ticks) without schedule
[ 1392.943776] CPU: 49 UID: 0 PID: 32912 Comm: vfio_dma_mappin Kdump: loaded Not tainted 7.1.0-smp-DEV #1 PREEMPTLAZY
[ 1392.943780] Call trace:
[ 1392.943796] resched_latency_warn+0x7c/0x88
[ 1392.943800] sched_tick+0x18c/0x208
[ 1392.943804] update_process_times+0xa8/0xd8
[ 1392.943808] tick_nohz_handler+0x120/0x1c8
[ 1392.943810] __hrtimer_run_queues+0x124/0x3a0
[ 1392.943833] arm_lpae_iova_to_phys+0x80/0xf0 (P)
[ 1392.943835] arm_smmu_iova_to_phys+0x24/0x38
[ 1392.943837] iommu_iova_to_phys+0x38/0x58
[ 1392.943839] batch_from_domain+0x16c/0x218
[ 1392.943840] __iopt_area_unfill_domain+0x2f0/0x5d8
[ 1392.943841] iopt_area_unfill_domains+0x9c/0x1c8
[ 1392.943842] iopt_unmap_iova_range+0xec/0x218
[ 1392.943844] iopt_unmap_iova+0x38/0x50
[ 1392.943846] iommufd_ioas_unmap+0xac/0x1f8
[ 1392.943847] iommufd_fops_ioctl+0x200/0x348
Note that in order for this warning to fire, the kernel must be built
without preemption, or... for testing, the code in batch_from_domain()
can explicitly disable preemption.
This warning was produced on ARM using the VFIO selftest
vfio_dma_mapping_perf_test:
./vfio_dma_mapping_perf_test -p -b 256G -a "-v iommufd_anonymous_hugetlb_1gb"
To profile the unmap flow, bpftrace was used with the tooling
described at:
https://lore.kernel.org/kvm/20260630141152.3757722-2-aaronlewis@google.com/
The results show:
iommufd_ioas_unmap, thread_time = 1086.52ms, count = 1
__iopt_area_unfill_domain, thread_time = 1086.51ms, count = 1
batch_from_domain, thread_time = 1086.48ms, count = 1
This shows that the execution time is spent entirely inside
batch_from_domain(). Furthermore, the function is entered only once.
Therefore, to avoid the scheduler warning and allow the core to remain
responsive, add a cond_resched() call to the loop in
batch_from_domain(). Also, limit the cond_resched() call to once
per 1GB to rate limit it.
Additional context on what consumes time within the inner loop can be
seen in this sample perf profile:
22.96% [vfio_dma_mapping_perf_test] ([vfio_dma_mapping_perf_test])
22.96% vfs_ioctl (ioctl.c) Inlined
22.96% iommufd_fops_ioctl (main.c)
19.38% iommufd_ioas_unmap (ioas.c)
19.38% iopt_unmap_iova (io_pagetable.c)
19.38% iopt_unmap_iova_range (io_pagetable.c)
19.38% iopt_area_unfill_domains (pages.c)
19.38% iopt_area_unfill_domain (pages.c) Inlined
19.38% __iopt_area_unfill_domain (pages.c)
19.38% iopt_area_unpin_domain (pages.c) Inlined
18.84% batch_from_domain (pages.c)
15.06% iommu_iova_to_phys (iommu.c)
14.27% arm_smmu_iova_to_phys (arm-smmu-v3.c)
13.29% arm_lpae_iova_to_phys (io-pgtable-arm.c)
10.60% __arm_lpae_iopte_walk (io-pgtable-arm.c)
7.70% io_pgtable_visit (io-pgtable-arm.c) Inlined
4.71% __arm_lpae_iopte_walk (io-pgtable-arm.c)
2.31% io_pgtable_visit (io-pgtable-arm.c) Inlined
Signed-off-by: Aaron Lewis <aaronlewis@google.com>
---
drivers/iommu/iommufd/pages.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/iommu/iommufd/pages.c b/drivers/iommu/iommufd/pages.c
index 9bdb2945afe1..e478771c0ccf 100644
--- a/drivers/iommu/iommufd/pages.c
+++ b/drivers/iommu/iommufd/pages.c
@@ -412,6 +412,7 @@ static void batch_from_domain(struct pfn_batch *batch,
unsigned int page_offset = 0;
unsigned long iova;
phys_addr_t phys;
+ int i = 0;
iova = iopt_area_index_to_iova(area, start_index);
if (start_index == iopt_area_index(area))
@@ -428,6 +429,9 @@ static void batch_from_domain(struct pfn_batch *batch,
iova += PAGE_SIZE - page_offset;
page_offset = 0;
start_index++;
+
+ if ((++i % BIT(PUD_ORDER)) == 0)
+ cond_resched();
}
}
--
2.55.0.141.g00534a21ce-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread