intel_gvt_dma_map_guest_page() unmaps and frees the cache entry of a gfn when it is requested with a different size, and maps the page again. The entry is still referenced: shadow GTT entries and dma-bufs keep using its DMA address after the page is unpinned and the DMA mapping is torn down. When the new mapping gets the same DMA address, their later intel_gvt_dma_unmap_guest_page() calls also drop the references of the new entry. Keep the existing entry instead. A 2M mapping covers a 4K request for its first page, so take a reference on it. If the entry is smaller than the request, fail and let the caller split the 2M entry into 4K pages, as it already does when a 2M mapping cannot be set up. Fixes: 7366aeb77cd8 ("drm/i915/gvt: fix incorrect cache entry for guest page mapping") Cc: stable@vger.kernel.org Signed-off-by: Yuho Choi --- Compile-tested only (x86_64 defconfig + DRM_I915_GVT_KVMGT, W=1, sparse). drivers/gpu/drm/i915/gvt/kvmgt.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index ec62db5cc3675..9a3e305253469 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -1626,19 +1626,15 @@ int intel_gvt_dma_map_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, ret = __gvt_cache_add(vgpu, gfn, *dma_addr, size); if (ret) goto err_unmap; - } else if (entry->size != size) { - /* the same gfn with different size: unmap and re-map */ - gvt_dma_unmap_page(vgpu, gfn, entry->dma_addr, entry->size); - __gvt_cache_remove_entry(vgpu, entry); - - ret = gvt_dma_map_page(vgpu, gfn, dma_addr, size); - if (ret) - goto err_unlock; - - ret = __gvt_cache_add(vgpu, gfn, *dma_addr, size); - if (ret) - goto err_unmap; + } else if (entry->size < size) { + /* + * The smaller mapping may still be in use, so don't replace + * it. Fail and let the caller map the range in smaller pages. + */ + ret = -EBUSY; + goto err_unlock; } else { + /* A mapping of the same or a larger size covers the request */ kref_get(&entry->ref); *dma_addr = entry->dma_addr; } base-commit: 7704c4c5bb127673b4f0ead839919db573559e38 -- 2.43.0