* [PATCH] drm/gem-shmem: Immediately record writable mmap; drop pfn_mkwrite
@ 2026-05-28 10:27 Thomas Zimmermann
2026-05-28 11:38 ` Boris Brezillon
0 siblings, 1 reply; 2+ messages in thread
From: Thomas Zimmermann @ 2026-05-28 10:27 UTC (permalink / raw)
To: boris.brezillon, igor.torrente, simona, airlied, mripard,
maarten.lankhorst
Cc: dri-devel, Thomas Zimmermann
Using pfn_mkwrite breaks KVM with "error: kvm run failed Bad address".
Seen on a Mali-G610 GPU. Fix this by marking writable mmapped pages as
written when installing the mapping in the page table.
Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reported-by: Igor Torrente <igor.torrente@collabora.com>
Closes: https://lore.kernel.org/dri-devel/d89422f1-f00a-47b1-b68a-d949d6d6a974@collabora.com/raw
Tested-by: Igor Torrente <igor.torrente@collabora.com>
Fixes: 28e3918179aa ("drm/gem-shmem: Track folio accessed/dirty status in mmap")
---
drivers/gpu/drm/drm_gem_shmem_helper.c | 48 ++++++++------------------
1 file changed, 14 insertions(+), 34 deletions(-)
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 545933c7f712..7af31932af84 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -554,21 +554,6 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
-static void drm_gem_shmem_record_mkwrite(struct vm_fault *vmf)
-{
- struct vm_area_struct *vma = vmf->vma;
- struct drm_gem_object *obj = vma->vm_private_data;
- struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
- loff_t num_pages = obj->size >> PAGE_SHIFT;
- pgoff_t page_offset = vmf->pgoff - vma->vm_pgoff; /* page offset within VMA */
-
- if (drm_WARN_ON(obj->dev, !shmem->pages || page_offset >= num_pages))
- return;
-
- file_update_time(vma->vm_file);
- folio_mark_dirty(page_folio(shmem->pages[page_offset]));
-}
-
static vm_fault_t try_insert_pfn(struct vm_fault *vmf, unsigned int order,
unsigned long pfn)
{
@@ -581,23 +566,15 @@ static vm_fault_t try_insert_pfn(struct vm_fault *vmf, unsigned int order,
if (aligned &&
folio_test_pmd_mappable(page_folio(pfn_to_page(pfn)))) {
- vm_fault_t ret;
-
pfn &= PMD_MASK >> PAGE_SHIFT;
- /* Unlike PTEs which are automatically upgraded to
+ /*
+ * Unlike PTEs which are automatically upgraded to
* writeable entries, the PMD upgrades go through
* .huge_fault(). Make sure we pass the "write" info
* along in that case.
- * This also means we have to record the write fault
- * here, instead of in .pfn_mkwrite().
*/
- ret = vmf_insert_pfn_pmd(vmf, pfn,
- vmf->flags & FAULT_FLAG_WRITE);
- if (ret == VM_FAULT_NOPAGE && (vmf->flags & FAULT_FLAG_WRITE))
- drm_gem_shmem_record_mkwrite(vmf);
-
- return ret;
+ return vmf_insert_pfn_pmd(vmf, pfn, false);
}
#endif
}
@@ -635,8 +612,18 @@ static vm_fault_t drm_gem_shmem_any_fault(struct vm_fault *vmf, unsigned int ord
pfn = page_to_pfn(page);
ret = try_insert_pfn(vmf, order, pfn);
- if (ret == VM_FAULT_NOPAGE)
+ if (ret == VM_FAULT_NOPAGE) {
folio_mark_accessed(folio);
+ /*
+ * Immediately record write access to the buffer. The
+ * natural place would be pfn_mkwrite at the time when
+ * the access happens, but this breaks KVM.
+ */
+ if (vma->vm_flags & VM_WRITE) {
+ file_update_time(vma->vm_file);
+ folio_mark_dirty(folio);
+ }
+ }
out:
dma_resv_unlock(obj->resv);
@@ -683,12 +670,6 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
drm_gem_vm_close(vma);
}
-static vm_fault_t drm_gem_shmem_pfn_mkwrite(struct vm_fault *vmf)
-{
- drm_gem_shmem_record_mkwrite(vmf);
- return 0;
-}
-
const struct vm_operations_struct drm_gem_shmem_vm_ops = {
.fault = drm_gem_shmem_fault,
#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
@@ -696,7 +677,6 @@ const struct vm_operations_struct drm_gem_shmem_vm_ops = {
#endif
.open = drm_gem_shmem_vm_open,
.close = drm_gem_shmem_vm_close,
- .pfn_mkwrite = drm_gem_shmem_pfn_mkwrite,
};
EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
--
2.54.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH] drm/gem-shmem: Immediately record writable mmap; drop pfn_mkwrite
2026-05-28 10:27 [PATCH] drm/gem-shmem: Immediately record writable mmap; drop pfn_mkwrite Thomas Zimmermann
@ 2026-05-28 11:38 ` Boris Brezillon
0 siblings, 0 replies; 2+ messages in thread
From: Boris Brezillon @ 2026-05-28 11:38 UTC (permalink / raw)
To: Thomas Zimmermann
Cc: igor.torrente, simona, airlied, mripard, maarten.lankhorst,
dri-devel
On Thu, 28 May 2026 12:27:59 +0200
Thomas Zimmermann <tzimmermann@suse.de> wrote:
> Using pfn_mkwrite breaks KVM with "error: kvm run failed Bad address".
> Seen on a Mali-G610 GPU. Fix this by marking writable mmapped pages as
> written when installing the mapping in the page table.
>
> Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Reported-by: Igor Torrente <igor.torrente@collabora.com>
> Closes: https://lore.kernel.org/dri-devel/d89422f1-f00a-47b1-b68a-d949d6d6a974@collabora.com/raw
> Tested-by: Igor Torrente <igor.torrente@collabora.com>
> Fixes: 28e3918179aa ("drm/gem-shmem: Track folio accessed/dirty status in mmap")
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Two nits below.
> ---
> drivers/gpu/drm/drm_gem_shmem_helper.c | 48 ++++++++------------------
> 1 file changed, 14 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index 545933c7f712..7af31932af84 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -554,21 +554,6 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
> }
> EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
>
> -static void drm_gem_shmem_record_mkwrite(struct vm_fault *vmf)
> -{
> - struct vm_area_struct *vma = vmf->vma;
> - struct drm_gem_object *obj = vma->vm_private_data;
> - struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> - loff_t num_pages = obj->size >> PAGE_SHIFT;
> - pgoff_t page_offset = vmf->pgoff - vma->vm_pgoff; /* page offset within VMA */
> -
> - if (drm_WARN_ON(obj->dev, !shmem->pages || page_offset >= num_pages))
> - return;
> -
> - file_update_time(vma->vm_file);
> - folio_mark_dirty(page_folio(shmem->pages[page_offset]));
> -}
> -
> static vm_fault_t try_insert_pfn(struct vm_fault *vmf, unsigned int order,
> unsigned long pfn)
> {
> @@ -581,23 +566,15 @@ static vm_fault_t try_insert_pfn(struct vm_fault *vmf, unsigned int order,
>
> if (aligned &&
> folio_test_pmd_mappable(page_folio(pfn_to_page(pfn)))) {
> - vm_fault_t ret;
> -
> pfn &= PMD_MASK >> PAGE_SHIFT;
>
> - /* Unlike PTEs which are automatically upgraded to
> + /*
> + * Unlike PTEs which are automatically upgraded to
> * writeable entries, the PMD upgrades go through
> * .huge_fault(). Make sure we pass the "write" info
> * along in that case.
> - * This also means we have to record the write fault
> - * here, instead of in .pfn_mkwrite().
> */
We can drop the comment altogether since we no longer have this
read-only -> rw upgrade now that pfn_mkwrite is gone.
> - ret = vmf_insert_pfn_pmd(vmf, pfn,
> - vmf->flags & FAULT_FLAG_WRITE);
> - if (ret == VM_FAULT_NOPAGE && (vmf->flags & FAULT_FLAG_WRITE))
> - drm_gem_shmem_record_mkwrite(vmf);
> -
> - return ret;
> + return vmf_insert_pfn_pmd(vmf, pfn, false);
> }
> #endif
> }
> @@ -635,8 +612,18 @@ static vm_fault_t drm_gem_shmem_any_fault(struct vm_fault *vmf, unsigned int ord
> pfn = page_to_pfn(page);
>
> ret = try_insert_pfn(vmf, order, pfn);
> - if (ret == VM_FAULT_NOPAGE)
> + if (ret == VM_FAULT_NOPAGE) {
> folio_mark_accessed(folio);
Please add a blank line here.
> + /*
> + * Immediately record write access to the buffer. The
> + * natural place would be pfn_mkwrite at the time when
> + * the access happens, but this breaks KVM.
> + */
> + if (vma->vm_flags & VM_WRITE) {
> + file_update_time(vma->vm_file);
> + folio_mark_dirty(folio);
> + }
> + }
>
> out:
> dma_resv_unlock(obj->resv);
> @@ -683,12 +670,6 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
> drm_gem_vm_close(vma);
> }
>
> -static vm_fault_t drm_gem_shmem_pfn_mkwrite(struct vm_fault *vmf)
> -{
> - drm_gem_shmem_record_mkwrite(vmf);
> - return 0;
> -}
> -
> const struct vm_operations_struct drm_gem_shmem_vm_ops = {
> .fault = drm_gem_shmem_fault,
> #ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
> @@ -696,7 +677,6 @@ const struct vm_operations_struct drm_gem_shmem_vm_ops = {
> #endif
> .open = drm_gem_shmem_vm_open,
> .close = drm_gem_shmem_vm_close,
> - .pfn_mkwrite = drm_gem_shmem_pfn_mkwrite,
> };
> EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-28 11:39 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-28 10:27 [PATCH] drm/gem-shmem: Immediately record writable mmap; drop pfn_mkwrite Thomas Zimmermann
2026-05-28 11:38 ` Boris Brezillon
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.