[PATCH 2/2] vhost-vdpa: unpin mappings by range

From: Tal Zussman

Date: Sat Oct 31 2026 - 13:47:47 EST


vhost_vdpa_pa_unmap() unpins each mapping a page at a time, dirtying
each page first if the mapping is writable. Each mapping is physically
contiguous, so use unpin_user_page_range_dirty_lock() instead, which
marks every folio dirty once and drops its pins in one go. Do the same
for the pages left pinned in the vhost_vdpa_pa_map() error path.

This removes the last use of set_page_dirty_lock() in vhost.

Signed-off-by: Tal Zussman <tz2294@xxxxxxxxxxxx>
---
drivers/vhost/vdpa.c | 20 ++++++--------------
1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
index d9af728942b3..cd5da522fdc0 100644
--- a/drivers/vhost/vdpa.c
+++ b/drivers/vhost/vdpa.c
@@ -972,18 +972,11 @@ static void vhost_vdpa_pa_unmap(struct vhost_vdpa *v, struct vhost_iotlb *iotlb,
{
struct vhost_dev *dev = &v->vdev;
struct vhost_iotlb_map *map;
- struct page *page;
- unsigned long pfn, pinned;

while ((map = vhost_iotlb_itree_first(iotlb, start, last)) != NULL) {
- pinned = PFN_DOWN(map->size);
- for (pfn = PFN_DOWN(map->addr);
- pinned > 0; pfn++, pinned--) {
- page = pfn_to_page(pfn);
- if (map->perm & VHOST_ACCESS_WO)
- set_page_dirty_lock(page);
- unpin_user_page(page);
- }
+ unpin_user_page_range_dirty_lock(pfn_to_page(PFN_DOWN(map->addr)),
+ PFN_DOWN(map->size),
+ map->perm & VHOST_ACCESS_WO);
atomic64_sub(PFN_DOWN(map->size), &dev->mm->pinned_vm);
vhost_vdpa_general_unmap(v, map, asid);
vhost_iotlb_map_free(iotlb, map);
@@ -1246,8 +1239,6 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
out:
if (ret) {
if (last_pfn) {
- unsigned long pfn;
-
/*
* Unpin the outstanding pages which are yet to be
* mapped but haven't due to vdpa_map() or
@@ -1257,8 +1248,9 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
* the corresponding unpinning will be handled by
* vdpa_unmap().
*/
- for (pfn = map_pfn; pfn <= last_pfn; pfn++)
- unpin_user_page(pfn_to_page(pfn));
+ unpin_user_page_range_dirty_lock(pfn_to_page(map_pfn),
+ last_pfn - map_pfn + 1,
+ false);
}
vhost_vdpa_unmap(v, iotlb, start, size);
}

--
2.39.5