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 <tz2294@columbia.edu>
Message-ID: <20261031-vhost-vdpa-unpin-v1-2-94ffc9683256@columbia.edu>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Tal Zussman 2026-10-31 13:45:35 -04:00 committed by Michael S. Tsirkin
parent fd1462c96b
commit 73d135601d

View File

@ -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);
}