From 73d135601d3b533985a65748c0278ba3cfe48290 Mon Sep 17 00:00:00 2001 From: Tal Zussman Date: Sat, 31 Oct 2026 13:45:35 -0400 Subject: [PATCH] vhost-vdpa: unpin mappings by range 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 Message-ID: <20261031-vhost-vdpa-unpin-v1-2-94ffc9683256@columbia.edu> Signed-off-by: Michael S. Tsirkin --- 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 46169c8eb022..76066f6ee567 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -972,20 +972,13 @@ 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) { /* Stop device access before releasing the pinned pages. */ vhost_vdpa_general_unmap(v, map, asid); - 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_iotlb_map_free(iotlb, map); } @@ -1265,8 +1258,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 @@ -1276,8 +1267,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); }