git: 2db75e8df850 - stable/14 - linuxkpi: work with numpages > 1 in the set_pages_*() KPIs
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 10 Jun 2026 04:01:07 UTC
The branch stable/14 has been updated by kevans:
URL: https://cgit.FreeBSD.org/src/commit/?id=2db75e8df85044a9865c62d44f4261041f2bbcbc
commit 2db75e8df85044a9865c62d44f4261041f2bbcbc
Author: Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2026-05-19 03:22:21 +0000
Commit: Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2026-06-10 04:00:47 +0000
linuxkpi: work with numpages > 1 in the set_pages_*() KPIs
These calls are used for buddy pages at least in drm's ttm_pool, which
leads to a panic when we invoke lowmem handlers and drm tries to shrink
the pool.
Cope with numpages > 1 by traversing the contiguous pages and executing
the adjustment there, as well, as suggested by markj@. Previous
versions have tried to use the corresponding `set_memory_*()` functions,
but it is believed that not updating `md.pat_mode` breaks subsequent
userspace mappings in ways that may result in things like screen tearing
or other artifacts when running i915kms.
This stabilized my amdgpu laptop running two VMs, chromium and a
concurrent buildworld.
Reviewed by: bz, markj
(cherry picked from commit 67f7f2781daa9bd398b424ffe2bd0be67f37f03d)
(cherry picked from commit 8dad29555a5807bf21941807752e1589e20312de)
---
sys/compat/linuxkpi/common/include/asm/set_memory.h | 15 +++------------
sys/compat/linuxkpi/common/include/linux/page.h | 2 ++
sys/compat/linuxkpi/common/src/linux_page.c | 21 +++++++++++++++++++++
3 files changed, 26 insertions(+), 12 deletions(-)
diff --git a/sys/compat/linuxkpi/common/include/asm/set_memory.h b/sys/compat/linuxkpi/common/include/asm/set_memory.h
index 1019aaf264a0..54a1311ef9a5 100644
--- a/sys/compat/linuxkpi/common/include/asm/set_memory.h
+++ b/sys/compat/linuxkpi/common/include/asm/set_memory.h
@@ -65,32 +65,23 @@ set_memory_wb(unsigned long addr, int numpages)
static inline int
set_pages_uc(struct page *page, int numpages)
{
- KASSERT(numpages == 1, ("%s: numpages %d", __func__, numpages));
-
- pmap_page_set_memattr(page, VM_MEMATTR_UNCACHEABLE);
- return (0);
+ return (lkpi_set_pages_attr(page, numpages, VM_MEMATTR_UNCACHEABLE));
}
static inline int
set_pages_wc(struct page *page, int numpages)
{
- KASSERT(numpages == 1, ("%s: numpages %d", __func__, numpages));
-
#ifdef VM_MEMATTR_WRITE_COMBINING
- pmap_page_set_memattr(page, VM_MEMATTR_WRITE_COMBINING);
+ return (lkpi_set_pages_attr(page, numpages, VM_MEMATTR_WRITE_COMBINING));
#else
return (set_pages_uc(page, numpages));
#endif
- return (0);
}
static inline int
set_pages_wb(struct page *page, int numpages)
{
- KASSERT(numpages == 1, ("%s: numpages %d", __func__, numpages));
-
- pmap_page_set_memattr(page, VM_MEMATTR_WRITE_BACK);
- return (0);
+ return (lkpi_set_pages_attr(page, numpages, VM_MEMATTR_WRITE_BACK));
}
static inline int
diff --git a/sys/compat/linuxkpi/common/include/linux/page.h b/sys/compat/linuxkpi/common/include/linux/page.h
index 37ab593a64e9..6f5f37d2fd0f 100644
--- a/sys/compat/linuxkpi/common/include/linux/page.h
+++ b/sys/compat/linuxkpi/common/include/linux/page.h
@@ -127,4 +127,6 @@ clflush_cache_range(void *addr, unsigned int size)
}
#endif
+int lkpi_set_pages_attr(struct page *page, int numpages, vm_memattr_t ma);
+
#endif /* _LINUXKPI_LINUX_PAGE_H_ */
diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c
index 15b90eb3c470..3eb2fab03359 100644
--- a/sys/compat/linuxkpi/common/src/linux_page.c
+++ b/sys/compat/linuxkpi/common/src/linux_page.c
@@ -512,6 +512,27 @@ lkpi_arch_phys_wc_del(int reg)
#endif
}
+int
+lkpi_set_pages_attr(struct page *page, int numpages, vm_memattr_t ma)
+{
+ while (numpages-- > 0) {
+ /*
+ * pmap_page_set_memattr() would only update the DMAP mapping
+ * if it's a normal page, leaving the kernel map untouched.
+ */
+ MPASS(page->object != kernel_object);
+
+ /*
+ * pmap_page_set_memattr() sets page->md.pat_mode, which is
+ * crucial for future userspace mappings.
+ */
+ pmap_page_set_memattr(page, ma);
+ page++;
+ }
+
+ return (0);
+}
+
/*
* This is a highly simplified version of the Linux page_frag_cache.
* We only support up-to 1 single page as fragment size and we will