Hi
Am 26.05.26 um 16:56 schrieb Igor Torrente:
Hi Thomas,
On 5/26/26 11:44, Thomas Zimmermann wrote:
Hi
Am 20.05.26 um 15:11 schrieb Igor Torrente:
[...]
I'm not familiar with the drm_gem, code so I don't any more
insightful information
to share. But hopefully we can find a better fix for this.
Do you have huge pages enabled ?
No, I didn't even compile my kernel with huge pages. I've already been
burned by that before
I see.
The attached patch is a cleaned up version of Boris' fix. Please test
and report back on the results.
Best regards
Thomas
BR,
Igor Torrente
Best regards
Thomas
BR,
Igor Torrente
---
drivers/gpu/drm/drm_gem_shmem_helper.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c
b/drivers/gpu/drm/drm_gem_shmem_helper.c
index c3a054899ba3..0c86ad40a049 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -598,6 +598,9 @@ static vm_fault_t drm_gem_shmem_fault(struct
vm_fault *vmf)
if (ret != VM_FAULT_NOPAGE)
ret = vmf_insert_pfn(vma, vmf->address, pfn);
+ if (likely(!(ret & VM_FAULT_ERROR)))
+ folio_mark_accessed(folio);
+
out:
dma_resv_unlock(obj->resv);
@@ -638,10 +641,27 @@ 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)
+{
+ 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);
+ pgoff_t page_offset = vmf->pgoff - vma->vm_pgoff; /* page
offset within VMA */
+ struct page *page = shmem->pages[page_offset];
+ struct folio *folio = page_folio(page);
+
+ file_update_time(vma->vm_file);
+
+ folio_mark_dirty(folio);
+
+ return 0;
+}
+
const struct vm_operations_struct drm_gem_shmem_vm_ops = {
.fault = drm_gem_shmem_fault,
.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);
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)
From 4478b3e07515194812806c5bfc3b7432d8f8406a Mon Sep 17 00:00:00 2001
From: Thomas Zimmermann <[email protected]>
Date: Wed, 27 May 2026 08:07:19 +0200
Subject: [PATCH] drm/gem-shmem: Always assume writable mmap; drop pfn_mkwrite
Using pfn_mkwrite breaks KVM with "error: kvm run failed Bad address".
Seen on a Mali-G610 GPU. Fix this by always marking the mapped pages
as written.
---
drivers/gpu/drm/drm_gem_shmem_helper.c | 46 +++++++-------------------
1 file changed, 12 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..07e117673124 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,16 @@ 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,
+ vmf->flags & FAULT_FLAG_WRITE);
}
#endif
}
@@ -635,8 +613,15 @@ 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);
+ /*
+ * Always record write access to the buffer. The natural
+ * place would be pfn_mkwrite, but this breaks KVM.
+ */
+ file_update_time(vma->vm_file);
+ folio_mark_dirty(folio);
+ }
out:
dma_resv_unlock(obj->resv);
@@ -683,12 +668,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 +675,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