* [PATCH RFC 0/2] mm: add huge pfnmap support for remap_pfn_range()
@ 2025-09-23 13:31 ` Yin Tirui
0 siblings, 0 replies; 21+ messages in thread
From: Yin Tirui @ 2025-09-23 13:31 UTC (permalink / raw)
To: akpm, david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain, baohua,
catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102, yintirui
Overview
========
This patch series adds huge page support for remap_pfn_range(),
automatically creating huge mappings when prerequisites are satisfied
(size, alignment, architecture support, etc.) and falling back to
normal page mappings otherwise.
This work builds on Peter Xu's previous efforts on huge pfnmap
support [0].
TODO
====
- Add PUD-level huge page support. Currently, only PMD-level huge
pages are supported.
- Consider the logic related to vmap_page_range and extract
reusable common code.
Tests Done
==========
- Cross-build tests.
- Performance tests with custom device driver implementing mmap()
with remap_pfn_range():
- lat_mem_rd benchmark modified to use mmap(device_fd) instead of
malloc() shows around 40% improvement in memory access latency with
huge page support compared to normal page mappings.
numactl -C 0 lat_mem_rd -t 4096M (stride=64)
Memory Size (MB) Without Huge Mapping With Huge Mapping Improvement
---------------- ----------------- -------------- -----------
64.00 148.858 ns 100.780 ns 32.3%
128.00 164.745 ns 103.537 ns 37.2%
256.00 169.907 ns 103.179 ns 39.3%
512.00 171.285 ns 103.072 ns 39.8%
1024.00 173.054 ns 103.055 ns 40.4%
2048.00 172.820 ns 103.091 ns 40.3%
4096.00 172.877 ns 103.115 ns 40.4%
- Custom memory copy operations on mmap(device_fd) show around 18% performance
improvement with huge page support compared to normal page mappings.
numactl -C 0 memcpy_test (memory copy performance test)
Memory Size (MB) Without Huge Mapping With Huge Mapping Improvement
---------------- ----------------- -------------- -----------
1024.00 95.76 ms 77.91 ms 18.6%
2048.00 190.87 ms 155.64 ms 18.5%
4096.00 380.84 ms 311.45 ms 18.2%
[0] https://lore.kernel.org/all/20240826204353.2228736-2-peterx@redhat.com/T/#u
Yin Tirui (2):
pgtable: add pte_clrhuge() implementation for arm64 and riscv
mm: add PMD-level huge page support for remap_pfn_range()
arch/arm64/include/asm/pgtable.h | 8 ++++
arch/riscv/include/asm/pgtable.h | 5 +++
include/linux/pgtable.h | 6 ++-
mm/huge_memory.c | 22 +++++++---
mm/memory.c | 74 ++++++++++++++++++++++++++++----
5 files changed, 98 insertions(+), 17 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH RFC 0/2] mm: add huge pfnmap support for remap_pfn_range()
@ 2025-09-23 13:31 ` Yin Tirui
0 siblings, 0 replies; 21+ messages in thread
From: Yin Tirui @ 2025-09-23 13:31 UTC (permalink / raw)
To: akpm, david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain, baohua,
catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102, yintirui
Overview
========
This patch series adds huge page support for remap_pfn_range(),
automatically creating huge mappings when prerequisites are satisfied
(size, alignment, architecture support, etc.) and falling back to
normal page mappings otherwise.
This work builds on Peter Xu's previous efforts on huge pfnmap
support [0].
TODO
====
- Add PUD-level huge page support. Currently, only PMD-level huge
pages are supported.
- Consider the logic related to vmap_page_range and extract
reusable common code.
Tests Done
==========
- Cross-build tests.
- Performance tests with custom device driver implementing mmap()
with remap_pfn_range():
- lat_mem_rd benchmark modified to use mmap(device_fd) instead of
malloc() shows around 40% improvement in memory access latency with
huge page support compared to normal page mappings.
numactl -C 0 lat_mem_rd -t 4096M (stride=64)
Memory Size (MB) Without Huge Mapping With Huge Mapping Improvement
---------------- ----------------- -------------- -----------
64.00 148.858 ns 100.780 ns 32.3%
128.00 164.745 ns 103.537 ns 37.2%
256.00 169.907 ns 103.179 ns 39.3%
512.00 171.285 ns 103.072 ns 39.8%
1024.00 173.054 ns 103.055 ns 40.4%
2048.00 172.820 ns 103.091 ns 40.3%
4096.00 172.877 ns 103.115 ns 40.4%
- Custom memory copy operations on mmap(device_fd) show around 18% performance
improvement with huge page support compared to normal page mappings.
numactl -C 0 memcpy_test (memory copy performance test)
Memory Size (MB) Without Huge Mapping With Huge Mapping Improvement
---------------- ----------------- -------------- -----------
1024.00 95.76 ms 77.91 ms 18.6%
2048.00 190.87 ms 155.64 ms 18.5%
4096.00 380.84 ms 311.45 ms 18.2%
[0] https://lore.kernel.org/all/20240826204353.2228736-2-peterx@redhat.com/T/#u
Yin Tirui (2):
pgtable: add pte_clrhuge() implementation for arm64 and riscv
mm: add PMD-level huge page support for remap_pfn_range()
arch/arm64/include/asm/pgtable.h | 8 ++++
arch/riscv/include/asm/pgtable.h | 5 +++
include/linux/pgtable.h | 6 ++-
mm/huge_memory.c | 22 +++++++---
mm/memory.c | 74 ++++++++++++++++++++++++++++----
5 files changed, 98 insertions(+), 17 deletions(-)
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH RFC 1/2] pgtable: add pte_clrhuge() implementation for arm64 and riscv
2025-09-23 13:31 ` Yin Tirui
@ 2025-09-23 13:31 ` Yin Tirui
-1 siblings, 0 replies; 21+ messages in thread
From: Yin Tirui @ 2025-09-23 13:31 UTC (permalink / raw)
To: akpm, david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain, baohua,
catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102, yintirui
Add pte_clrhuge() helper function for architectures that enable
ARCH_SUPPORTS_HUGE_PFNMAP to clear huge page attributes from PTE
entries.
This function provides the inverse operation of pte_mkhuge() and will
be needed for upcoming huge page splitting, where PTE entries derived
from huge page mappings need to have their huge page attributes cleared.
Signed-off-by: Yin Tirui <yintirui@huawei.com>
---
arch/arm64/include/asm/pgtable.h | 8 ++++++++
arch/riscv/include/asm/pgtable.h | 5 +++++
2 files changed, 13 insertions(+)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index abd2dee416b3..244755bad46f 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -366,6 +366,14 @@ static inline pte_t pte_mkinvalid(pte_t pte)
return pte;
}
+static inline pte_t pte_clrhuge(pte_t pte)
+{
+ pteval_t mask = PTE_TYPE_MASK & ~PTE_VALID;
+ pteval_t val = PTE_TYPE_PAGE & ~PTE_VALID;
+
+ return __pte((pte_val(pte) & ~mask) | val);
+}
+
static inline pmd_t pmd_mkcont(pmd_t pmd)
{
return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 91697fbf1f90..125b241e6d2c 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -455,6 +455,11 @@ static inline pte_t pte_mkhuge(pte_t pte)
return pte;
}
+static inline pte_t pte_clrhuge(pte_t pte)
+{
+ return pte;
+}
+
#ifdef CONFIG_RISCV_ISA_SVNAPOT
#define pte_leaf_size(pte) (pte_napot(pte) ? \
napot_cont_size(napot_cont_order(pte)) :\
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH RFC 1/2] pgtable: add pte_clrhuge() implementation for arm64 and riscv
@ 2025-09-23 13:31 ` Yin Tirui
0 siblings, 0 replies; 21+ messages in thread
From: Yin Tirui @ 2025-09-23 13:31 UTC (permalink / raw)
To: akpm, david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain, baohua,
catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102, yintirui
Add pte_clrhuge() helper function for architectures that enable
ARCH_SUPPORTS_HUGE_PFNMAP to clear huge page attributes from PTE
entries.
This function provides the inverse operation of pte_mkhuge() and will
be needed for upcoming huge page splitting, where PTE entries derived
from huge page mappings need to have their huge page attributes cleared.
Signed-off-by: Yin Tirui <yintirui@huawei.com>
---
arch/arm64/include/asm/pgtable.h | 8 ++++++++
arch/riscv/include/asm/pgtable.h | 5 +++++
2 files changed, 13 insertions(+)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index abd2dee416b3..244755bad46f 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -366,6 +366,14 @@ static inline pte_t pte_mkinvalid(pte_t pte)
return pte;
}
+static inline pte_t pte_clrhuge(pte_t pte)
+{
+ pteval_t mask = PTE_TYPE_MASK & ~PTE_VALID;
+ pteval_t val = PTE_TYPE_PAGE & ~PTE_VALID;
+
+ return __pte((pte_val(pte) & ~mask) | val);
+}
+
static inline pmd_t pmd_mkcont(pmd_t pmd)
{
return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 91697fbf1f90..125b241e6d2c 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -455,6 +455,11 @@ static inline pte_t pte_mkhuge(pte_t pte)
return pte;
}
+static inline pte_t pte_clrhuge(pte_t pte)
+{
+ return pte;
+}
+
#ifdef CONFIG_RISCV_ISA_SVNAPOT
#define pte_leaf_size(pte) (pte_napot(pte) ? \
napot_cont_size(napot_cont_order(pte)) :\
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
2025-09-23 13:31 ` Yin Tirui
@ 2025-09-23 13:31 ` Yin Tirui
-1 siblings, 0 replies; 21+ messages in thread
From: Yin Tirui @ 2025-09-23 13:31 UTC (permalink / raw)
To: akpm, david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain, baohua,
catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102, yintirui
Add PMD-level huge page support to remap_pfn_range(), automatically
creating huge mappings when prerequisites are satisfied (size, alignment,
architecture support, etc.) and falling back to normal page mappings
otherwise.
Implement special huge PMD splitting by utilizing the pgtable deposit/
withdraw mechanism. When splitting is needed, the deposited pgtable is
withdrawn and populated with individual PTEs created from the original
huge mapping, using pte_clrhuge() to clear huge page attributes.
Update arch_needs_pgtable_deposit() to return true when PMD pfnmap
support is enabled, ensuring proper pgtable management for huge
pfnmap operations.
Introduce pfnmap_max_page_shift parameter to control maximum page
size and "nohugepfnmap" boot option to disable huge pfnmap entirely.
Signed-off-by: Yin Tirui <yintirui@huawei.com>
---
include/linux/pgtable.h | 6 +++-
mm/huge_memory.c | 22 ++++++++----
mm/memory.c | 74 ++++++++++++++++++++++++++++++++++++-----
3 files changed, 85 insertions(+), 17 deletions(-)
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 4c035637eeb7..4028318552ca 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -1025,7 +1025,11 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
#endif
#ifndef arch_needs_pgtable_deposit
-#define arch_needs_pgtable_deposit() (false)
+#define arch_needs_pgtable_deposit arch_needs_pgtable_deposit
+static inline bool arch_needs_pgtable_deposit(void)
+{
+ return IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_PFNMAP);
+}
#endif
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 9c38a95e9f09..9f20adcbbb55 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2857,14 +2857,22 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
if (!vma_is_anonymous(vma)) {
old_pmd = pmdp_huge_clear_flush(vma, haddr, pmd);
- /*
- * We are going to unmap this huge page. So
- * just go ahead and zap it
- */
- if (arch_needs_pgtable_deposit())
- zap_deposited_table(mm, pmd);
- if (!vma_is_dax(vma) && vma_is_special_huge(vma))
+ if (!vma_is_dax(vma) && vma_is_special_huge(vma)) {
+ pte_t entry;
+
+ pgtable = pgtable_trans_huge_withdraw(mm, pmd);
+ if (unlikely(!pgtable))
+ return;
+ pmd_populate(mm, &_pmd, pgtable);
+ pte = pte_offset_map(&_pmd, haddr);
+ entry = pte_clrhuge(pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
+ set_ptes(mm, haddr, pte, entry, HPAGE_PMD_NR);
+ pte_unmap(pte);
+
+ smp_wmb(); /* make pte visible before pmd */
+ pmd_populate(mm, pmd, pgtable);
return;
+ }
if (unlikely(is_pmd_migration_entry(old_pmd))) {
swp_entry_t entry;
diff --git a/mm/memory.c b/mm/memory.c
index 0ba4f6b71847..c4aaf3bd9cad 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2674,6 +2674,19 @@ vm_fault_t vmf_insert_mixed_mkwrite(struct vm_area_struct *vma,
return __vm_insert_mixed(vma, addr, pfn, true);
}
+#ifdef CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP
+static unsigned int __ro_after_init pfnmap_max_page_shift = BITS_PER_LONG - 1;
+
+static int __init set_nohugepfnmap(char *str)
+{
+ pfnmap_max_page_shift = PAGE_SHIFT;
+ return 0;
+}
+early_param("nohugepfnmap", set_nohugepfnmap);
+#else /* CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP */
+static const unsigned int pfnmap_max_page_shift = PAGE_SHIFT;
+#endif /* CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP */
+
/*
* maps a range of physical memory into the requested pages. the old
* mappings are removed. any references to nonexistent pages results
@@ -2705,9 +2718,47 @@ static int remap_pte_range(struct mm_struct *mm, pmd_t *pmd,
return err;
}
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
+static int remap_try_huge_pmd(struct mm_struct *mm, pmd_t *pmd,
+ unsigned long addr, unsigned long end,
+ unsigned long pfn, pgprot_t prot,
+ unsigned int page_shift)
+{
+ pgtable_t pgtable;
+ spinlock_t *ptl;
+
+ if (page_shift < PMD_SHIFT)
+ return 0;
+
+ if ((end - addr) != PMD_SIZE)
+ return 0;
+
+ if (!IS_ALIGNED(addr, PMD_SIZE))
+ return 0;
+
+ if (!IS_ALIGNED(pfn, 1 << (PMD_SHIFT - PAGE_SHIFT)))
+ return 0;
+
+ if (pmd_present(*pmd) && !pmd_free_pte_page(pmd, addr))
+ return 0;
+
+ set_pmd_at(mm, addr, pmd, pmd_mkspecial(pmd_mkhuge(pfn_pmd(pfn, prot))));
+
+ pgtable = pte_alloc_one(mm);
+ if (unlikely(!pgtable))
+ return 1;
+ mm_inc_nr_ptes(mm);
+ ptl = pmd_lock(mm, pmd);
+ pgtable_trans_huge_deposit(mm, pmd, pgtable);
+ spin_unlock(ptl);
+
+ return 1;
+}
+#endif
+
static inline int remap_pmd_range(struct mm_struct *mm, pud_t *pud,
unsigned long addr, unsigned long end,
- unsigned long pfn, pgprot_t prot)
+ unsigned long pfn, pgprot_t prot, unsigned int max_page_shift)
{
pmd_t *pmd;
unsigned long next;
@@ -2720,6 +2771,12 @@ static inline int remap_pmd_range(struct mm_struct *mm, pud_t *pud,
VM_BUG_ON(pmd_trans_huge(*pmd));
do {
next = pmd_addr_end(addr, end);
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
+ if (remap_try_huge_pmd(mm, pmd, addr, next,
+ pfn + (addr >> PAGE_SHIFT), prot, max_page_shift)) {
+ continue;
+ }
+#endif
err = remap_pte_range(mm, pmd, addr, next,
pfn + (addr >> PAGE_SHIFT), prot);
if (err)
@@ -2730,7 +2787,7 @@ static inline int remap_pmd_range(struct mm_struct *mm, pud_t *pud,
static inline int remap_pud_range(struct mm_struct *mm, p4d_t *p4d,
unsigned long addr, unsigned long end,
- unsigned long pfn, pgprot_t prot)
+ unsigned long pfn, pgprot_t prot, unsigned int max_page_shift)
{
pud_t *pud;
unsigned long next;
@@ -2743,7 +2800,7 @@ static inline int remap_pud_range(struct mm_struct *mm, p4d_t *p4d,
do {
next = pud_addr_end(addr, end);
err = remap_pmd_range(mm, pud, addr, next,
- pfn + (addr >> PAGE_SHIFT), prot);
+ pfn + (addr >> PAGE_SHIFT), prot, max_page_shift);
if (err)
return err;
} while (pud++, addr = next, addr != end);
@@ -2752,7 +2809,7 @@ static inline int remap_pud_range(struct mm_struct *mm, p4d_t *p4d,
static inline int remap_p4d_range(struct mm_struct *mm, pgd_t *pgd,
unsigned long addr, unsigned long end,
- unsigned long pfn, pgprot_t prot)
+ unsigned long pfn, pgprot_t prot, unsigned int max_page_shift)
{
p4d_t *p4d;
unsigned long next;
@@ -2765,7 +2822,7 @@ static inline int remap_p4d_range(struct mm_struct *mm, pgd_t *pgd,
do {
next = p4d_addr_end(addr, end);
err = remap_pud_range(mm, p4d, addr, next,
- pfn + (addr >> PAGE_SHIFT), prot);
+ pfn + (addr >> PAGE_SHIFT), prot, max_page_shift);
if (err)
return err;
} while (p4d++, addr = next, addr != end);
@@ -2773,7 +2830,7 @@ static inline int remap_p4d_range(struct mm_struct *mm, pgd_t *pgd,
}
static int remap_pfn_range_internal(struct vm_area_struct *vma, unsigned long addr,
- unsigned long pfn, unsigned long size, pgprot_t prot)
+ unsigned long pfn, unsigned long size, pgprot_t prot, unsigned int max_page_shift)
{
pgd_t *pgd;
unsigned long next;
@@ -2817,7 +2874,7 @@ static int remap_pfn_range_internal(struct vm_area_struct *vma, unsigned long ad
do {
next = pgd_addr_end(addr, end);
err = remap_p4d_range(mm, pgd, addr, next,
- pfn + (addr >> PAGE_SHIFT), prot);
+ pfn + (addr >> PAGE_SHIFT), prot, max_page_shift);
if (err)
return err;
} while (pgd++, addr = next, addr != end);
@@ -2832,8 +2889,7 @@ static int remap_pfn_range_internal(struct vm_area_struct *vma, unsigned long ad
int remap_pfn_range_notrack(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
{
- int error = remap_pfn_range_internal(vma, addr, pfn, size, prot);
-
+ int error = remap_pfn_range_internal(vma, addr, pfn, size, prot, pfnmap_max_page_shift);
if (!error)
return 0;
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
@ 2025-09-23 13:31 ` Yin Tirui
0 siblings, 0 replies; 21+ messages in thread
From: Yin Tirui @ 2025-09-23 13:31 UTC (permalink / raw)
To: akpm, david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain, baohua,
catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102, yintirui
Add PMD-level huge page support to remap_pfn_range(), automatically
creating huge mappings when prerequisites are satisfied (size, alignment,
architecture support, etc.) and falling back to normal page mappings
otherwise.
Implement special huge PMD splitting by utilizing the pgtable deposit/
withdraw mechanism. When splitting is needed, the deposited pgtable is
withdrawn and populated with individual PTEs created from the original
huge mapping, using pte_clrhuge() to clear huge page attributes.
Update arch_needs_pgtable_deposit() to return true when PMD pfnmap
support is enabled, ensuring proper pgtable management for huge
pfnmap operations.
Introduce pfnmap_max_page_shift parameter to control maximum page
size and "nohugepfnmap" boot option to disable huge pfnmap entirely.
Signed-off-by: Yin Tirui <yintirui@huawei.com>
---
include/linux/pgtable.h | 6 +++-
mm/huge_memory.c | 22 ++++++++----
mm/memory.c | 74 ++++++++++++++++++++++++++++++++++++-----
3 files changed, 85 insertions(+), 17 deletions(-)
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 4c035637eeb7..4028318552ca 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -1025,7 +1025,11 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
#endif
#ifndef arch_needs_pgtable_deposit
-#define arch_needs_pgtable_deposit() (false)
+#define arch_needs_pgtable_deposit arch_needs_pgtable_deposit
+static inline bool arch_needs_pgtable_deposit(void)
+{
+ return IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_PFNMAP);
+}
#endif
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 9c38a95e9f09..9f20adcbbb55 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2857,14 +2857,22 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
if (!vma_is_anonymous(vma)) {
old_pmd = pmdp_huge_clear_flush(vma, haddr, pmd);
- /*
- * We are going to unmap this huge page. So
- * just go ahead and zap it
- */
- if (arch_needs_pgtable_deposit())
- zap_deposited_table(mm, pmd);
- if (!vma_is_dax(vma) && vma_is_special_huge(vma))
+ if (!vma_is_dax(vma) && vma_is_special_huge(vma)) {
+ pte_t entry;
+
+ pgtable = pgtable_trans_huge_withdraw(mm, pmd);
+ if (unlikely(!pgtable))
+ return;
+ pmd_populate(mm, &_pmd, pgtable);
+ pte = pte_offset_map(&_pmd, haddr);
+ entry = pte_clrhuge(pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
+ set_ptes(mm, haddr, pte, entry, HPAGE_PMD_NR);
+ pte_unmap(pte);
+
+ smp_wmb(); /* make pte visible before pmd */
+ pmd_populate(mm, pmd, pgtable);
return;
+ }
if (unlikely(is_pmd_migration_entry(old_pmd))) {
swp_entry_t entry;
diff --git a/mm/memory.c b/mm/memory.c
index 0ba4f6b71847..c4aaf3bd9cad 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2674,6 +2674,19 @@ vm_fault_t vmf_insert_mixed_mkwrite(struct vm_area_struct *vma,
return __vm_insert_mixed(vma, addr, pfn, true);
}
+#ifdef CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP
+static unsigned int __ro_after_init pfnmap_max_page_shift = BITS_PER_LONG - 1;
+
+static int __init set_nohugepfnmap(char *str)
+{
+ pfnmap_max_page_shift = PAGE_SHIFT;
+ return 0;
+}
+early_param("nohugepfnmap", set_nohugepfnmap);
+#else /* CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP */
+static const unsigned int pfnmap_max_page_shift = PAGE_SHIFT;
+#endif /* CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP */
+
/*
* maps a range of physical memory into the requested pages. the old
* mappings are removed. any references to nonexistent pages results
@@ -2705,9 +2718,47 @@ static int remap_pte_range(struct mm_struct *mm, pmd_t *pmd,
return err;
}
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
+static int remap_try_huge_pmd(struct mm_struct *mm, pmd_t *pmd,
+ unsigned long addr, unsigned long end,
+ unsigned long pfn, pgprot_t prot,
+ unsigned int page_shift)
+{
+ pgtable_t pgtable;
+ spinlock_t *ptl;
+
+ if (page_shift < PMD_SHIFT)
+ return 0;
+
+ if ((end - addr) != PMD_SIZE)
+ return 0;
+
+ if (!IS_ALIGNED(addr, PMD_SIZE))
+ return 0;
+
+ if (!IS_ALIGNED(pfn, 1 << (PMD_SHIFT - PAGE_SHIFT)))
+ return 0;
+
+ if (pmd_present(*pmd) && !pmd_free_pte_page(pmd, addr))
+ return 0;
+
+ set_pmd_at(mm, addr, pmd, pmd_mkspecial(pmd_mkhuge(pfn_pmd(pfn, prot))));
+
+ pgtable = pte_alloc_one(mm);
+ if (unlikely(!pgtable))
+ return 1;
+ mm_inc_nr_ptes(mm);
+ ptl = pmd_lock(mm, pmd);
+ pgtable_trans_huge_deposit(mm, pmd, pgtable);
+ spin_unlock(ptl);
+
+ return 1;
+}
+#endif
+
static inline int remap_pmd_range(struct mm_struct *mm, pud_t *pud,
unsigned long addr, unsigned long end,
- unsigned long pfn, pgprot_t prot)
+ unsigned long pfn, pgprot_t prot, unsigned int max_page_shift)
{
pmd_t *pmd;
unsigned long next;
@@ -2720,6 +2771,12 @@ static inline int remap_pmd_range(struct mm_struct *mm, pud_t *pud,
VM_BUG_ON(pmd_trans_huge(*pmd));
do {
next = pmd_addr_end(addr, end);
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
+ if (remap_try_huge_pmd(mm, pmd, addr, next,
+ pfn + (addr >> PAGE_SHIFT), prot, max_page_shift)) {
+ continue;
+ }
+#endif
err = remap_pte_range(mm, pmd, addr, next,
pfn + (addr >> PAGE_SHIFT), prot);
if (err)
@@ -2730,7 +2787,7 @@ static inline int remap_pmd_range(struct mm_struct *mm, pud_t *pud,
static inline int remap_pud_range(struct mm_struct *mm, p4d_t *p4d,
unsigned long addr, unsigned long end,
- unsigned long pfn, pgprot_t prot)
+ unsigned long pfn, pgprot_t prot, unsigned int max_page_shift)
{
pud_t *pud;
unsigned long next;
@@ -2743,7 +2800,7 @@ static inline int remap_pud_range(struct mm_struct *mm, p4d_t *p4d,
do {
next = pud_addr_end(addr, end);
err = remap_pmd_range(mm, pud, addr, next,
- pfn + (addr >> PAGE_SHIFT), prot);
+ pfn + (addr >> PAGE_SHIFT), prot, max_page_shift);
if (err)
return err;
} while (pud++, addr = next, addr != end);
@@ -2752,7 +2809,7 @@ static inline int remap_pud_range(struct mm_struct *mm, p4d_t *p4d,
static inline int remap_p4d_range(struct mm_struct *mm, pgd_t *pgd,
unsigned long addr, unsigned long end,
- unsigned long pfn, pgprot_t prot)
+ unsigned long pfn, pgprot_t prot, unsigned int max_page_shift)
{
p4d_t *p4d;
unsigned long next;
@@ -2765,7 +2822,7 @@ static inline int remap_p4d_range(struct mm_struct *mm, pgd_t *pgd,
do {
next = p4d_addr_end(addr, end);
err = remap_pud_range(mm, p4d, addr, next,
- pfn + (addr >> PAGE_SHIFT), prot);
+ pfn + (addr >> PAGE_SHIFT), prot, max_page_shift);
if (err)
return err;
} while (p4d++, addr = next, addr != end);
@@ -2773,7 +2830,7 @@ static inline int remap_p4d_range(struct mm_struct *mm, pgd_t *pgd,
}
static int remap_pfn_range_internal(struct vm_area_struct *vma, unsigned long addr,
- unsigned long pfn, unsigned long size, pgprot_t prot)
+ unsigned long pfn, unsigned long size, pgprot_t prot, unsigned int max_page_shift)
{
pgd_t *pgd;
unsigned long next;
@@ -2817,7 +2874,7 @@ static int remap_pfn_range_internal(struct vm_area_struct *vma, unsigned long ad
do {
next = pgd_addr_end(addr, end);
err = remap_p4d_range(mm, pgd, addr, next,
- pfn + (addr >> PAGE_SHIFT), prot);
+ pfn + (addr >> PAGE_SHIFT), prot, max_page_shift);
if (err)
return err;
} while (pgd++, addr = next, addr != end);
@@ -2832,8 +2889,7 @@ static int remap_pfn_range_internal(struct vm_area_struct *vma, unsigned long ad
int remap_pfn_range_notrack(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
{
- int error = remap_pfn_range_internal(vma, addr, pfn, size, prot);
-
+ int error = remap_pfn_range_internal(vma, addr, pfn, size, prot, pfnmap_max_page_shift);
if (!error)
return 0;
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
2025-09-23 13:31 ` Yin Tirui
@ 2025-09-23 22:39 ` Matthew Wilcox
-1 siblings, 0 replies; 21+ messages in thread
From: Matthew Wilcox @ 2025-09-23 22:39 UTC (permalink / raw)
To: Yin Tirui
Cc: akpm, david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain, baohua,
catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, apopple, samuel.holland,
luxu.kernel, abrestic, yongxuan.wang, linux-mm, linux-kernel,
linux-arm-kernel, linux-riscv, wangkefeng.wang, chenjun102
On Tue, Sep 23, 2025 at 09:31:04PM +0800, Yin Tirui wrote:
> + entry = pte_clrhuge(pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
This doesn't make sense. And I'm not saying you got this wrong; I
suspect in terms of how things work today it's actually necessary.
But the way we handle this stuff is so insane.
pte_clrhuge() should not exist. If we have a PTE, it can't have the
huge bit set, by definition (don't anybody mention hugetlbfs because
that is an entirely separate pile of broken horrors). I understand what
you're trying to do here. You want to construct a PTE that points to
the same address as the first page of the PMD and has the same
permissions. But that *should* be written as:
entry = pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
right? Now, pmd_pgprot() might or might not want to return the huge bit
set. I'm not sure. Perhaps you could have a look through and figure it
out. But pfn_pte() should never return a PTE with the huge bit set.
So if it is set in the pgorot on entry, it should filter it out.
There are going to be consequences to this. Maybe there's code
somewhere that relies on pfn_pte() returning a PTE with the huge bit
set. Perhaps it's hugetlbfs.
But we have to start cleaning this garbage up. I did some work with
e3981db444a0 and the commits leading up to that. See
https://lkml.kernel.org/r/20250402181709.2386022-12-willy@infradead.org
I'd like pte_clrhuge() to be deleted from x86, not added to arm and
riscv.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
@ 2025-09-23 22:39 ` Matthew Wilcox
0 siblings, 0 replies; 21+ messages in thread
From: Matthew Wilcox @ 2025-09-23 22:39 UTC (permalink / raw)
To: Yin Tirui
Cc: akpm, david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain, baohua,
catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, apopple, samuel.holland,
luxu.kernel, abrestic, yongxuan.wang, linux-mm, linux-kernel,
linux-arm-kernel, linux-riscv, wangkefeng.wang, chenjun102
On Tue, Sep 23, 2025 at 09:31:04PM +0800, Yin Tirui wrote:
> + entry = pte_clrhuge(pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
This doesn't make sense. And I'm not saying you got this wrong; I
suspect in terms of how things work today it's actually necessary.
But the way we handle this stuff is so insane.
pte_clrhuge() should not exist. If we have a PTE, it can't have the
huge bit set, by definition (don't anybody mention hugetlbfs because
that is an entirely separate pile of broken horrors). I understand what
you're trying to do here. You want to construct a PTE that points to
the same address as the first page of the PMD and has the same
permissions. But that *should* be written as:
entry = pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
right? Now, pmd_pgprot() might or might not want to return the huge bit
set. I'm not sure. Perhaps you could have a look through and figure it
out. But pfn_pte() should never return a PTE with the huge bit set.
So if it is set in the pgorot on entry, it should filter it out.
There are going to be consequences to this. Maybe there's code
somewhere that relies on pfn_pte() returning a PTE with the huge bit
set. Perhaps it's hugetlbfs.
But we have to start cleaning this garbage up. I did some work with
e3981db444a0 and the commits leading up to that. See
https://lkml.kernel.org/r/20250402181709.2386022-12-willy@infradead.org
I'd like pte_clrhuge() to be deleted from x86, not added to arm and
riscv.
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* [syzbot ci] Re: mm: add huge pfnmap support for remap_pfn_range()
2025-09-23 13:31 ` Yin Tirui
@ 2025-09-23 22:53 ` syzbot ci
-1 siblings, 0 replies; 21+ messages in thread
From: syzbot ci @ 2025-09-23 22:53 UTC (permalink / raw)
To: abrestic, akpm, alex, anshuman.khandual, aou, apopple, ardb,
baohua, baolin.wang, catalin.marinas, chenjun102, david, dev.jain,
liam.howlett, linux-arm-kernel, linux-kernel, linux-mm,
linux-riscv, lorenzo.stoakes, luxu.kernel, mhocko, npache, palmer,
paul.walmsley, rppt, ryan.roberts, samuel.holland, surenb, vbabka,
wangkefeng.wang, will, willy, yangyicong, yintirui, yongxuan.wang,
ziy
Cc: syzbot, syzkaller-bugs
syzbot ci has tested the following series
[v1] mm: add huge pfnmap support for remap_pfn_range()
https://lore.kernel.org/all/20250923133104.926672-1-yintirui@huawei.com
* [PATCH RFC 1/2] pgtable: add pte_clrhuge() implementation for arm64 and riscv
* [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
and found the following issues:
* BUG: non-zero pgtables_bytes on freeing mm: NUM
* stack segment fault in pgtable_trans_huge_withdraw
Full report is available here:
https://ci.syzbot.org/series/633cbff7-ef54-4f3a-9133-71cc271396ee
***
BUG: non-zero pgtables_bytes on freeing mm: NUM
tree: torvalds
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
base: 07e27ad16399afcd693be20211b0dfae63e0615f
arch: amd64
compiler: Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
config: https://ci.syzbot.org/builds/72b4b6cf-5400-40d6-94b6-1cfc0e85050d/config
C repro: https://ci.syzbot.org/findings/3450ef75-3540-4c00-8b33-5625d4aa40ef/c_repro
syz repro: https://ci.syzbot.org/findings/3450ef75-3540-4c00-8b33-5625d4aa40ef/syz_repro
BUG: non-zero pgtables_bytes on freeing mm: 4096
***
stack segment fault in pgtable_trans_huge_withdraw
tree: torvalds
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
base: 07e27ad16399afcd693be20211b0dfae63e0615f
arch: amd64
compiler: Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
config: https://ci.syzbot.org/builds/72b4b6cf-5400-40d6-94b6-1cfc0e85050d/config
C repro: https://ci.syzbot.org/findings/dcfb72b5-c263-48da-830a-7f51aaa927db/c_repro
syz repro: https://ci.syzbot.org/findings/dcfb72b5-c263-48da-830a-7f51aaa927db/syz_repro
Oops: stack segment: 0000 [#1] SMP KASAN PTI
CPU: 0 UID: 0 PID: 6000 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
RIP: 0010:pgtable_trans_huge_withdraw+0x115/0x310 mm/pgtable-generic.c:188
Code: c3 10 48 89 d8 48 c1 e8 03 42 80 3c 28 00 74 08 48 89 df e8 5d 38 13 00 48 8b 03 48 89 04 24 4c 8d 78 08 4c 89 fd 48 c1 ed 03 <42> 80 7c 2d 00 00 74 08 4c 89 ff e8 3b 38 13 00 49 8b 07 48 8d 48
RSP: 0018:ffffc90002d5f300 EFLAGS: 00010202
RAX: 0000000000000000 RBX: ffffea0000fb3dd0 RCX: ffff888107769cc0
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000001 R08: ffff888022b90843 R09: 1ffff11004572108
R10: dffffc0000000000 R11: ffffed1004572109 R12: ffff88803ecf7000
R13: dffffc0000000000 R14: ffff88803ecf7000 R15: 0000000000000008
FS: 0000555576e7a500(0000) GS:ffff8880b8612000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 0000000107d74000 CR4: 00000000000006f0
Call Trace:
<TASK>
zap_deposited_table mm/huge_memory.c:2177 [inline]
zap_huge_pmd+0xa25/0xf50 mm/huge_memory.c:2205
zap_pmd_range mm/memory.c:1798 [inline]
zap_pud_range mm/memory.c:1847 [inline]
zap_p4d_range mm/memory.c:1868 [inline]
unmap_page_range+0x9fe/0x4370 mm/memory.c:1889
unmap_single_vma mm/memory.c:1932 [inline]
unmap_vmas+0x399/0x580 mm/memory.c:1976
exit_mmap+0x248/0xb50 mm/mmap.c:1280
__mmput+0x118/0x430 kernel/fork.c:1129
copy_process+0x2910/0x3c00 kernel/fork.c:2454
kernel_clone+0x21e/0x840 kernel/fork.c:2605
__do_sys_clone kernel/fork.c:2748 [inline]
__se_sys_clone kernel/fork.c:2732 [inline]
__x64_sys_clone+0x18b/0x1e0 kernel/fork.c:2732
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f96b638ec29
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffc07e618c8 EFLAGS: 00000206 ORIG_RAX: 0000000000000038
RAX: ffffffffffffffda RBX: 00007f96b65d5fa0 RCX: 00007f96b638ec29
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000002001000
RBP: 00007f96b6411e41 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000000
R13: 00007f96b65d5fa0 R14: 00007f96b65d5fa0 R15: 0000000000000006
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:pgtable_trans_huge_withdraw+0x115/0x310 mm/pgtable-generic.c:188
Code: c3 10 48 89 d8 48 c1 e8 03 42 80 3c 28 00 74 08 48 89 df e8 5d 38 13 00 48 8b 03 48 89 04 24 4c 8d 78 08 4c 89 fd 48 c1 ed 03 <42> 80 7c 2d 00 00 74 08 4c 89 ff e8 3b 38 13 00 49 8b 07 48 8d 48
RSP: 0018:ffffc90002d5f300 EFLAGS: 00010202
RAX: 0000000000000000 RBX: ffffea0000fb3dd0 RCX: ffff888107769cc0
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000001 R08: ffff888022b90843 R09: 1ffff11004572108
R10: dffffc0000000000 R11: ffffed1004572109 R12: ffff88803ecf7000
R13: dffffc0000000000 R14: ffff88803ecf7000 R15: 0000000000000008
FS: 0000555576e7a500(0000) GS:ffff8880b8612000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 0000000107d74000 CR4: 00000000000006f0
----------------
Code disassembly (best guess):
0: c3 ret
1: 10 48 89 adc %cl,-0x77(%rax)
4: d8 48 c1 fmuls -0x3f(%rax)
7: e8 03 42 80 3c call 0x3c80420f
c: 28 00 sub %al,(%rax)
e: 74 08 je 0x18
10: 48 89 df mov %rbx,%rdi
13: e8 5d 38 13 00 call 0x133875
18: 48 8b 03 mov (%rbx),%rax
1b: 48 89 04 24 mov %rax,(%rsp)
1f: 4c 8d 78 08 lea 0x8(%rax),%r15
23: 4c 89 fd mov %r15,%rbp
26: 48 c1 ed 03 shr $0x3,%rbp
* 2a: 42 80 7c 2d 00 00 cmpb $0x0,0x0(%rbp,%r13,1) <-- trapping instruction
30: 74 08 je 0x3a
32: 4c 89 ff mov %r15,%rdi
35: e8 3b 38 13 00 call 0x133875
3a: 49 8b 07 mov (%r15),%rax
3d: 48 rex.W
3e: 8d .byte 0x8d
3f: 48 rex.W
***
If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
Tested-by: syzbot@syzkaller.appspotmail.com
---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.
^ permalink raw reply [flat|nested] 21+ messages in thread
* [syzbot ci] Re: mm: add huge pfnmap support for remap_pfn_range()
@ 2025-09-23 22:53 ` syzbot ci
0 siblings, 0 replies; 21+ messages in thread
From: syzbot ci @ 2025-09-23 22:53 UTC (permalink / raw)
To: abrestic, akpm, alex, anshuman.khandual, aou, apopple, ardb,
baohua, baolin.wang, catalin.marinas, chenjun102, david, dev.jain,
liam.howlett, linux-arm-kernel, linux-kernel, linux-mm,
linux-riscv, lorenzo.stoakes, luxu.kernel, mhocko, npache, palmer,
paul.walmsley, rppt, ryan.roberts, samuel.holland, surenb, vbabka,
wangkefeng.wang, will, willy, yangyicong, yintirui, yongxuan.wang,
ziy
Cc: syzbot, syzkaller-bugs
syzbot ci has tested the following series
[v1] mm: add huge pfnmap support for remap_pfn_range()
https://lore.kernel.org/all/20250923133104.926672-1-yintirui@huawei.com
* [PATCH RFC 1/2] pgtable: add pte_clrhuge() implementation for arm64 and riscv
* [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
and found the following issues:
* BUG: non-zero pgtables_bytes on freeing mm: NUM
* stack segment fault in pgtable_trans_huge_withdraw
Full report is available here:
https://ci.syzbot.org/series/633cbff7-ef54-4f3a-9133-71cc271396ee
***
BUG: non-zero pgtables_bytes on freeing mm: NUM
tree: torvalds
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
base: 07e27ad16399afcd693be20211b0dfae63e0615f
arch: amd64
compiler: Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
config: https://ci.syzbot.org/builds/72b4b6cf-5400-40d6-94b6-1cfc0e85050d/config
C repro: https://ci.syzbot.org/findings/3450ef75-3540-4c00-8b33-5625d4aa40ef/c_repro
syz repro: https://ci.syzbot.org/findings/3450ef75-3540-4c00-8b33-5625d4aa40ef/syz_repro
BUG: non-zero pgtables_bytes on freeing mm: 4096
***
stack segment fault in pgtable_trans_huge_withdraw
tree: torvalds
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
base: 07e27ad16399afcd693be20211b0dfae63e0615f
arch: amd64
compiler: Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
config: https://ci.syzbot.org/builds/72b4b6cf-5400-40d6-94b6-1cfc0e85050d/config
C repro: https://ci.syzbot.org/findings/dcfb72b5-c263-48da-830a-7f51aaa927db/c_repro
syz repro: https://ci.syzbot.org/findings/dcfb72b5-c263-48da-830a-7f51aaa927db/syz_repro
Oops: stack segment: 0000 [#1] SMP KASAN PTI
CPU: 0 UID: 0 PID: 6000 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
RIP: 0010:pgtable_trans_huge_withdraw+0x115/0x310 mm/pgtable-generic.c:188
Code: c3 10 48 89 d8 48 c1 e8 03 42 80 3c 28 00 74 08 48 89 df e8 5d 38 13 00 48 8b 03 48 89 04 24 4c 8d 78 08 4c 89 fd 48 c1 ed 03 <42> 80 7c 2d 00 00 74 08 4c 89 ff e8 3b 38 13 00 49 8b 07 48 8d 48
RSP: 0018:ffffc90002d5f300 EFLAGS: 00010202
RAX: 0000000000000000 RBX: ffffea0000fb3dd0 RCX: ffff888107769cc0
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000001 R08: ffff888022b90843 R09: 1ffff11004572108
R10: dffffc0000000000 R11: ffffed1004572109 R12: ffff88803ecf7000
R13: dffffc0000000000 R14: ffff88803ecf7000 R15: 0000000000000008
FS: 0000555576e7a500(0000) GS:ffff8880b8612000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 0000000107d74000 CR4: 00000000000006f0
Call Trace:
<TASK>
zap_deposited_table mm/huge_memory.c:2177 [inline]
zap_huge_pmd+0xa25/0xf50 mm/huge_memory.c:2205
zap_pmd_range mm/memory.c:1798 [inline]
zap_pud_range mm/memory.c:1847 [inline]
zap_p4d_range mm/memory.c:1868 [inline]
unmap_page_range+0x9fe/0x4370 mm/memory.c:1889
unmap_single_vma mm/memory.c:1932 [inline]
unmap_vmas+0x399/0x580 mm/memory.c:1976
exit_mmap+0x248/0xb50 mm/mmap.c:1280
__mmput+0x118/0x430 kernel/fork.c:1129
copy_process+0x2910/0x3c00 kernel/fork.c:2454
kernel_clone+0x21e/0x840 kernel/fork.c:2605
__do_sys_clone kernel/fork.c:2748 [inline]
__se_sys_clone kernel/fork.c:2732 [inline]
__x64_sys_clone+0x18b/0x1e0 kernel/fork.c:2732
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f96b638ec29
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffc07e618c8 EFLAGS: 00000206 ORIG_RAX: 0000000000000038
RAX: ffffffffffffffda RBX: 00007f96b65d5fa0 RCX: 00007f96b638ec29
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000002001000
RBP: 00007f96b6411e41 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000000
R13: 00007f96b65d5fa0 R14: 00007f96b65d5fa0 R15: 0000000000000006
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:pgtable_trans_huge_withdraw+0x115/0x310 mm/pgtable-generic.c:188
Code: c3 10 48 89 d8 48 c1 e8 03 42 80 3c 28 00 74 08 48 89 df e8 5d 38 13 00 48 8b 03 48 89 04 24 4c 8d 78 08 4c 89 fd 48 c1 ed 03 <42> 80 7c 2d 00 00 74 08 4c 89 ff e8 3b 38 13 00 49 8b 07 48 8d 48
RSP: 0018:ffffc90002d5f300 EFLAGS: 00010202
RAX: 0000000000000000 RBX: ffffea0000fb3dd0 RCX: ffff888107769cc0
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000001 R08: ffff888022b90843 R09: 1ffff11004572108
R10: dffffc0000000000 R11: ffffed1004572109 R12: ffff88803ecf7000
R13: dffffc0000000000 R14: ffff88803ecf7000 R15: 0000000000000008
FS: 0000555576e7a500(0000) GS:ffff8880b8612000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 0000000107d74000 CR4: 00000000000006f0
----------------
Code disassembly (best guess):
0: c3 ret
1: 10 48 89 adc %cl,-0x77(%rax)
4: d8 48 c1 fmuls -0x3f(%rax)
7: e8 03 42 80 3c call 0x3c80420f
c: 28 00 sub %al,(%rax)
e: 74 08 je 0x18
10: 48 89 df mov %rbx,%rdi
13: e8 5d 38 13 00 call 0x133875
18: 48 8b 03 mov (%rbx),%rax
1b: 48 89 04 24 mov %rax,(%rsp)
1f: 4c 8d 78 08 lea 0x8(%rax),%r15
23: 4c 89 fd mov %r15,%rbp
26: 48 c1 ed 03 shr $0x3,%rbp
* 2a: 42 80 7c 2d 00 00 cmpb $0x0,0x0(%rbp,%r13,1) <-- trapping instruction
30: 74 08 je 0x3a
32: 4c 89 ff mov %r15,%rdi
35: e8 3b 38 13 00 call 0x133875
3a: 49 8b 07 mov (%r15),%rax
3d: 48 rex.W
3e: 8d .byte 0x8d
3f: 48 rex.W
***
If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
Tested-by: syzbot@syzkaller.appspotmail.com
---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
2025-09-23 13:31 ` Yin Tirui
@ 2025-09-24 9:50 ` David Hildenbrand
-1 siblings, 0 replies; 21+ messages in thread
From: David Hildenbrand @ 2025-09-24 9:50 UTC (permalink / raw)
To: Yin Tirui, akpm, lorenzo.stoakes, Liam.Howlett, vbabka, rppt,
surenb, mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain,
baohua, catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102
On 23.09.25 15:31, Yin Tirui wrote:
> Add PMD-level huge page support to remap_pfn_range(), automatically
> creating huge mappings when prerequisites are satisfied (size, alignment,
> architecture support, etc.) and falling back to normal page mappings
> otherwise.
>
> Implement special huge PMD splitting by utilizing the pgtable deposit/
> withdraw mechanism. When splitting is needed, the deposited pgtable is
> withdrawn and populated with individual PTEs created from the original
> huge mapping, using pte_clrhuge() to clear huge page attributes.
>
> Update arch_needs_pgtable_deposit() to return true when PMD pfnmap
> support is enabled, ensuring proper pgtable management for huge
> pfnmap operations.
>
> Introduce pfnmap_max_page_shift parameter to control maximum page
> size and "nohugepfnmap" boot option to disable huge pfnmap entirely.
Why? If an arch supports it we should just do it. Or what's the reason
behind that?
>
> Signed-off-by: Yin Tirui <yintirui@huawei.com>
> ---
> include/linux/pgtable.h | 6 +++-
> mm/huge_memory.c | 22 ++++++++----
> mm/memory.c | 74 ++++++++++++++++++++++++++++++++++++-----
> 3 files changed, 85 insertions(+), 17 deletions(-)
>
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index 4c035637eeb7..4028318552ca 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -1025,7 +1025,11 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
> #endif
>
> #ifndef arch_needs_pgtable_deposit
> -#define arch_needs_pgtable_deposit() (false)
> +#define arch_needs_pgtable_deposit arch_needs_pgtable_deposit
> +static inline bool arch_needs_pgtable_deposit(void)
> +{
> + return IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_PFNMAP);
> +}
> #endif
>
> #ifdef CONFIG_TRANSPARENT_HUGEPAGE
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 9c38a95e9f09..9f20adcbbb55 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -2857,14 +2857,22 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
>
> if (!vma_is_anonymous(vma)) {
> old_pmd = pmdp_huge_clear_flush(vma, haddr, pmd);
> - /*
> - * We are going to unmap this huge page. So
> - * just go ahead and zap it
> - */
> - if (arch_needs_pgtable_deposit())
> - zap_deposited_table(mm, pmd);
Are you sure we can just entirely remove this block for
!vma_is_anonymous(vma)?
--
Cheers
David / dhildenb
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
@ 2025-09-24 9:50 ` David Hildenbrand
0 siblings, 0 replies; 21+ messages in thread
From: David Hildenbrand @ 2025-09-24 9:50 UTC (permalink / raw)
To: Yin Tirui, akpm, lorenzo.stoakes, Liam.Howlett, vbabka, rppt,
surenb, mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain,
baohua, catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102
On 23.09.25 15:31, Yin Tirui wrote:
> Add PMD-level huge page support to remap_pfn_range(), automatically
> creating huge mappings when prerequisites are satisfied (size, alignment,
> architecture support, etc.) and falling back to normal page mappings
> otherwise.
>
> Implement special huge PMD splitting by utilizing the pgtable deposit/
> withdraw mechanism. When splitting is needed, the deposited pgtable is
> withdrawn and populated with individual PTEs created from the original
> huge mapping, using pte_clrhuge() to clear huge page attributes.
>
> Update arch_needs_pgtable_deposit() to return true when PMD pfnmap
> support is enabled, ensuring proper pgtable management for huge
> pfnmap operations.
>
> Introduce pfnmap_max_page_shift parameter to control maximum page
> size and "nohugepfnmap" boot option to disable huge pfnmap entirely.
Why? If an arch supports it we should just do it. Or what's the reason
behind that?
>
> Signed-off-by: Yin Tirui <yintirui@huawei.com>
> ---
> include/linux/pgtable.h | 6 +++-
> mm/huge_memory.c | 22 ++++++++----
> mm/memory.c | 74 ++++++++++++++++++++++++++++++++++++-----
> 3 files changed, 85 insertions(+), 17 deletions(-)
>
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index 4c035637eeb7..4028318552ca 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -1025,7 +1025,11 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
> #endif
>
> #ifndef arch_needs_pgtable_deposit
> -#define arch_needs_pgtable_deposit() (false)
> +#define arch_needs_pgtable_deposit arch_needs_pgtable_deposit
> +static inline bool arch_needs_pgtable_deposit(void)
> +{
> + return IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_PFNMAP);
> +}
> #endif
>
> #ifdef CONFIG_TRANSPARENT_HUGEPAGE
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 9c38a95e9f09..9f20adcbbb55 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -2857,14 +2857,22 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
>
> if (!vma_is_anonymous(vma)) {
> old_pmd = pmdp_huge_clear_flush(vma, haddr, pmd);
> - /*
> - * We are going to unmap this huge page. So
> - * just go ahead and zap it
> - */
> - if (arch_needs_pgtable_deposit())
> - zap_deposited_table(mm, pmd);
Are you sure we can just entirely remove this block for
!vma_is_anonymous(vma)?
--
Cheers
David / dhildenb
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
2025-09-24 9:50 ` David Hildenbrand
@ 2025-09-25 1:43 ` Yin Tirui
-1 siblings, 0 replies; 21+ messages in thread
From: Yin Tirui @ 2025-09-25 1:43 UTC (permalink / raw)
To: David Hildenbrand, akpm, lorenzo.stoakes, Liam.Howlett, vbabka,
rppt, surenb, mhocko, ziy, baolin.wang, npache, ryan.roberts,
dev.jain, baohua, catalin.marinas, will, paul.walmsley, palmer,
aou, alex, anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102
On 9/24/2025 5:50 PM, David Hildenbrand wrote:
>> Introduce pfnmap_max_page_shift parameter to control maximum page
>> size and "nohugepfnmap" boot option to disable huge pfnmap entirely.
>
> Why? If an arch supports it we should just do it. Or what's the reason
> behind that?
>
There's no specific reason for this - it was just intended to provide an
additional option. I'll remove it in the next version.
...
> Are you sure we can just entirely remove this block for !
> vma_is_anonymous(vma)?
>
Thank you for pointing this out!
There is definitely a problem with removing this block entirely for
non-anonymous VMAs. I've also found some other problems. I'll fix all of
them in the next version.
--
Best regards,
Yin Tirui
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
@ 2025-09-25 1:43 ` Yin Tirui
0 siblings, 0 replies; 21+ messages in thread
From: Yin Tirui @ 2025-09-25 1:43 UTC (permalink / raw)
To: David Hildenbrand, akpm, lorenzo.stoakes, Liam.Howlett, vbabka,
rppt, surenb, mhocko, ziy, baolin.wang, npache, ryan.roberts,
dev.jain, baohua, catalin.marinas, will, paul.walmsley, palmer,
aou, alex, anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102
On 9/24/2025 5:50 PM, David Hildenbrand wrote:
>> Introduce pfnmap_max_page_shift parameter to control maximum page
>> size and "nohugepfnmap" boot option to disable huge pfnmap entirely.
>
> Why? If an arch supports it we should just do it. Or what's the reason
> behind that?
>
There's no specific reason for this - it was just intended to provide an
additional option. I'll remove it in the next version.
...
> Are you sure we can just entirely remove this block for !
> vma_is_anonymous(vma)?
>
Thank you for pointing this out!
There is definitely a problem with removing this block entirely for
non-anonymous VMAs. I've also found some other problems. I'll fix all of
them in the next version.
--
Best regards,
Yin Tirui
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
2025-09-23 22:39 ` Matthew Wilcox
@ 2025-09-25 2:17 ` Yin Tirui
-1 siblings, 0 replies; 21+ messages in thread
From: Yin Tirui @ 2025-09-25 2:17 UTC (permalink / raw)
To: Matthew Wilcox
Cc: akpm, david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain, baohua,
catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, apopple, samuel.holland,
luxu.kernel, abrestic, yongxuan.wang, linux-mm, linux-kernel,
linux-arm-kernel, linux-riscv, wangkefeng.wang, chenjun102
On 9/24/2025 6:39 AM, Matthew Wilcox wrote:
> On Tue, Sep 23, 2025 at 09:31:04PM +0800, Yin Tirui wrote:
>> + entry = pte_clrhuge(pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
>
> This doesn't make sense. And I'm not saying you got this wrong; I
> suspect in terms of how things work today it's actually necessary.
> But the way we handle this stuff is so insane.
Thank you for pointing this out and the broader context.
>
> pte_clrhuge() should not exist. If we have a PTE, it can't have the
> huge bit set, by definition (don't anybody mention hugetlbfs because
> that is an entirely separate pile of broken horrors). I understand what
> you're trying to do here. You want to construct a PTE that points to
> the same address as the first page of the PMD and has the same
> permissions. But that *should* be written as:
>
> entry = pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
>
> right? Now, pmd_pgprot() might or might not want to return the huge bit
> set. I'm not sure. Perhaps you could have a look through and figure it
I've tested this on arm64, and pmd_pgprot() does return the huge bit
set, which is exactly why I added pte_clrhuge().
> out. But pfn_pte() should never return a PTE with the huge bit set.
> So if it is set in the pgorot on entry, it should filter it out.
>
> There are going to be consequences to this. Maybe there's code
> somewhere that relies on pfn_pte() returning a PTE with the huge bit
> set. Perhaps it's hugetlbfs.
I'll try to refactor pfn_pte() and related functions to filter out the
huge bit set and test its impact on hugetlbfs.
>
> But we have to start cleaning this garbage up. I did some work with
> e3981db444a0 and the commits leading up to that. See
> https://lkml.kernel.org/r/20250402181709.2386022-12-willy@infradead.org
>
> I'd like pte_clrhuge() to be deleted from x86, not added to arm and
> riscv.
>
I completely agree with the goal of deleting pte_clrhuge() rather than
expanding it. I'll study your referenced work and align my approach with
your efforts.
Would you recommend I address the pfn_pte() and related function
refactoring as part of this patch series, or should I submit it as a
separate patch series?
--
Best regards,
Yin Tirui
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
@ 2025-09-25 2:17 ` Yin Tirui
0 siblings, 0 replies; 21+ messages in thread
From: Yin Tirui @ 2025-09-25 2:17 UTC (permalink / raw)
To: Matthew Wilcox
Cc: akpm, david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain, baohua,
catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, apopple, samuel.holland,
luxu.kernel, abrestic, yongxuan.wang, linux-mm, linux-kernel,
linux-arm-kernel, linux-riscv, wangkefeng.wang, chenjun102
On 9/24/2025 6:39 AM, Matthew Wilcox wrote:
> On Tue, Sep 23, 2025 at 09:31:04PM +0800, Yin Tirui wrote:
>> + entry = pte_clrhuge(pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
>
> This doesn't make sense. And I'm not saying you got this wrong; I
> suspect in terms of how things work today it's actually necessary.
> But the way we handle this stuff is so insane.
Thank you for pointing this out and the broader context.
>
> pte_clrhuge() should not exist. If we have a PTE, it can't have the
> huge bit set, by definition (don't anybody mention hugetlbfs because
> that is an entirely separate pile of broken horrors). I understand what
> you're trying to do here. You want to construct a PTE that points to
> the same address as the first page of the PMD and has the same
> permissions. But that *should* be written as:
>
> entry = pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
>
> right? Now, pmd_pgprot() might or might not want to return the huge bit
> set. I'm not sure. Perhaps you could have a look through and figure it
I've tested this on arm64, and pmd_pgprot() does return the huge bit
set, which is exactly why I added pte_clrhuge().
> out. But pfn_pte() should never return a PTE with the huge bit set.
> So if it is set in the pgorot on entry, it should filter it out.
>
> There are going to be consequences to this. Maybe there's code
> somewhere that relies on pfn_pte() returning a PTE with the huge bit
> set. Perhaps it's hugetlbfs.
I'll try to refactor pfn_pte() and related functions to filter out the
huge bit set and test its impact on hugetlbfs.
>
> But we have to start cleaning this garbage up. I did some work with
> e3981db444a0 and the commits leading up to that. See
> https://lkml.kernel.org/r/20250402181709.2386022-12-willy@infradead.org
>
> I'd like pte_clrhuge() to be deleted from x86, not added to arm and
> riscv.
>
I completely agree with the goal of deleting pte_clrhuge() rather than
expanding it. I'll study your referenced work and align my approach with
your efforts.
Would you recommend I address the pfn_pte() and related function
refactoring as part of this patch series, or should I submit it as a
separate patch series?
--
Best regards,
Yin Tirui
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
2025-09-23 13:31 ` Yin Tirui
` (2 preceding siblings ...)
(?)
@ 2025-09-25 3:14 ` kernel test robot
-1 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2025-09-25 3:14 UTC (permalink / raw)
To: Yin Tirui; +Cc: oe-kbuild-all
Hi Yin,
[This is a private test report for your RFC patch.]
kernel test robot noticed the following build errors:
[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on soc/for-next linus/master v6.17-rc7 next-20250924]
[cannot apply to akpm-mm/mm-everything]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yin-Tirui/pgtable-add-pte_clrhuge-implementation-for-arm64-and-riscv/20250923-213919
base: https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
patch link: https://lore.kernel.org/r/20250923133104.926672-3-yintirui%40huawei.com
patch subject: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
config: s390-randconfig-002-20250925 (https://download.01.org/0day-ci/archive/20250925/202509251011.a6EgAfsn-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 13.4.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250925/202509251011.a6EgAfsn-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509251011.a6EgAfsn-lkp@intel.com/
All errors (new ones prefixed by >>):
mm/huge_memory.c: In function '__split_huge_pmd_locked':
>> mm/huge_memory.c:2868:33: error: implicit declaration of function 'pte_clrhuge'; did you mean 'pte_mkhuge'? [-Werror=implicit-function-declaration]
2868 | entry = pte_clrhuge(pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
| ^~~~~~~~~~~
| pte_mkhuge
>> mm/huge_memory.c:2868:33: error: incompatible types when assigning to type 'pte_t' from type 'int'
cc1: some warnings being treated as errors
vim +2868 mm/huge_memory.c
2836
2837 static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
2838 unsigned long haddr, bool freeze)
2839 {
2840 struct mm_struct *mm = vma->vm_mm;
2841 struct folio *folio;
2842 struct page *page;
2843 pgtable_t pgtable;
2844 pmd_t old_pmd, _pmd;
2845 bool young, write, soft_dirty, pmd_migration = false, uffd_wp = false;
2846 bool anon_exclusive = false, dirty = false;
2847 unsigned long addr;
2848 pte_t *pte;
2849 int i;
2850
2851 VM_BUG_ON(haddr & ~HPAGE_PMD_MASK);
2852 VM_BUG_ON_VMA(vma->vm_start > haddr, vma);
2853 VM_BUG_ON_VMA(vma->vm_end < haddr + HPAGE_PMD_SIZE, vma);
2854 VM_BUG_ON(!is_pmd_migration_entry(*pmd) && !pmd_trans_huge(*pmd));
2855
2856 count_vm_event(THP_SPLIT_PMD);
2857
2858 if (!vma_is_anonymous(vma)) {
2859 old_pmd = pmdp_huge_clear_flush(vma, haddr, pmd);
2860 if (!vma_is_dax(vma) && vma_is_special_huge(vma)) {
2861 pte_t entry;
2862
2863 pgtable = pgtable_trans_huge_withdraw(mm, pmd);
2864 if (unlikely(!pgtable))
2865 return;
2866 pmd_populate(mm, &_pmd, pgtable);
2867 pte = pte_offset_map(&_pmd, haddr);
> 2868 entry = pte_clrhuge(pfn_pte(pmd_pfn(old_pmd), pmd_pgprot(old_pmd)));
2869 set_ptes(mm, haddr, pte, entry, HPAGE_PMD_NR);
2870 pte_unmap(pte);
2871
2872 smp_wmb(); /* make pte visible before pmd */
2873 pmd_populate(mm, pmd, pgtable);
2874 return;
2875 }
2876 if (unlikely(is_pmd_migration_entry(old_pmd))) {
2877 swp_entry_t entry;
2878
2879 entry = pmd_to_swp_entry(old_pmd);
2880 folio = pfn_swap_entry_folio(entry);
2881 } else if (is_huge_zero_pmd(old_pmd)) {
2882 return;
2883 } else {
2884 page = pmd_page(old_pmd);
2885 folio = page_folio(page);
2886 if (!folio_test_dirty(folio) && pmd_dirty(old_pmd))
2887 folio_mark_dirty(folio);
2888 if (!folio_test_referenced(folio) && pmd_young(old_pmd))
2889 folio_set_referenced(folio);
2890 folio_remove_rmap_pmd(folio, page, vma);
2891 folio_put(folio);
2892 }
2893 add_mm_counter(mm, mm_counter_file(folio), -HPAGE_PMD_NR);
2894 return;
2895 }
2896
2897 if (is_huge_zero_pmd(*pmd)) {
2898 /*
2899 * FIXME: Do we want to invalidate secondary mmu by calling
2900 * mmu_notifier_arch_invalidate_secondary_tlbs() see comments below
2901 * inside __split_huge_pmd() ?
2902 *
2903 * We are going from a zero huge page write protected to zero
2904 * small page also write protected so it does not seems useful
2905 * to invalidate secondary mmu at this time.
2906 */
2907 return __split_huge_zero_page_pmd(vma, haddr, pmd);
2908 }
2909
2910 pmd_migration = is_pmd_migration_entry(*pmd);
2911 if (unlikely(pmd_migration)) {
2912 swp_entry_t entry;
2913
2914 old_pmd = *pmd;
2915 entry = pmd_to_swp_entry(old_pmd);
2916 page = pfn_swap_entry_to_page(entry);
2917 write = is_writable_migration_entry(entry);
2918 if (PageAnon(page))
2919 anon_exclusive = is_readable_exclusive_migration_entry(entry);
2920 young = is_migration_entry_young(entry);
2921 dirty = is_migration_entry_dirty(entry);
2922 soft_dirty = pmd_swp_soft_dirty(old_pmd);
2923 uffd_wp = pmd_swp_uffd_wp(old_pmd);
2924 } else {
2925 /*
2926 * Up to this point the pmd is present and huge and userland has
2927 * the whole access to the hugepage during the split (which
2928 * happens in place). If we overwrite the pmd with the not-huge
2929 * version pointing to the pte here (which of course we could if
2930 * all CPUs were bug free), userland could trigger a small page
2931 * size TLB miss on the small sized TLB while the hugepage TLB
2932 * entry is still established in the huge TLB. Some CPU doesn't
2933 * like that. See
2934 * http://support.amd.com/TechDocs/41322_10h_Rev_Gd.pdf, Erratum
2935 * 383 on page 105. Intel should be safe but is also warns that
2936 * it's only safe if the permission and cache attributes of the
2937 * two entries loaded in the two TLB is identical (which should
2938 * be the case here). But it is generally safer to never allow
2939 * small and huge TLB entries for the same virtual address to be
2940 * loaded simultaneously. So instead of doing "pmd_populate();
2941 * flush_pmd_tlb_range();" we first mark the current pmd
2942 * notpresent (atomically because here the pmd_trans_huge must
2943 * remain set at all times on the pmd until the split is
2944 * complete for this pmd), then we flush the SMP TLB and finally
2945 * we write the non-huge version of the pmd entry with
2946 * pmd_populate.
2947 */
2948 old_pmd = pmdp_invalidate(vma, haddr, pmd);
2949 page = pmd_page(old_pmd);
2950 folio = page_folio(page);
2951 if (pmd_dirty(old_pmd)) {
2952 dirty = true;
2953 folio_set_dirty(folio);
2954 }
2955 write = pmd_write(old_pmd);
2956 young = pmd_young(old_pmd);
2957 soft_dirty = pmd_soft_dirty(old_pmd);
2958 uffd_wp = pmd_uffd_wp(old_pmd);
2959
2960 VM_WARN_ON_FOLIO(!folio_ref_count(folio), folio);
2961 VM_WARN_ON_FOLIO(!folio_test_anon(folio), folio);
2962
2963 /*
2964 * Without "freeze", we'll simply split the PMD, propagating the
2965 * PageAnonExclusive() flag for each PTE by setting it for
2966 * each subpage -- no need to (temporarily) clear.
2967 *
2968 * With "freeze" we want to replace mapped pages by
2969 * migration entries right away. This is only possible if we
2970 * managed to clear PageAnonExclusive() -- see
2971 * set_pmd_migration_entry().
2972 *
2973 * In case we cannot clear PageAnonExclusive(), split the PMD
2974 * only and let try_to_migrate_one() fail later.
2975 *
2976 * See folio_try_share_anon_rmap_pmd(): invalidate PMD first.
2977 */
2978 anon_exclusive = PageAnonExclusive(page);
2979 if (freeze && anon_exclusive &&
2980 folio_try_share_anon_rmap_pmd(folio, page))
2981 freeze = false;
2982 if (!freeze) {
2983 rmap_t rmap_flags = RMAP_NONE;
2984
2985 folio_ref_add(folio, HPAGE_PMD_NR - 1);
2986 if (anon_exclusive)
2987 rmap_flags |= RMAP_EXCLUSIVE;
2988 folio_add_anon_rmap_ptes(folio, page, HPAGE_PMD_NR,
2989 vma, haddr, rmap_flags);
2990 }
2991 }
2992
2993 /*
2994 * Withdraw the table only after we mark the pmd entry invalid.
2995 * This's critical for some architectures (Power).
2996 */
2997 pgtable = pgtable_trans_huge_withdraw(mm, pmd);
2998 pmd_populate(mm, &_pmd, pgtable);
2999
3000 pte = pte_offset_map(&_pmd, haddr);
3001 VM_BUG_ON(!pte);
3002
3003 /*
3004 * Note that NUMA hinting access restrictions are not transferred to
3005 * avoid any possibility of altering permissions across VMAs.
3006 */
3007 if (freeze || pmd_migration) {
3008 for (i = 0, addr = haddr; i < HPAGE_PMD_NR; i++, addr += PAGE_SIZE) {
3009 pte_t entry;
3010 swp_entry_t swp_entry;
3011
3012 if (write)
3013 swp_entry = make_writable_migration_entry(
3014 page_to_pfn(page + i));
3015 else if (anon_exclusive)
3016 swp_entry = make_readable_exclusive_migration_entry(
3017 page_to_pfn(page + i));
3018 else
3019 swp_entry = make_readable_migration_entry(
3020 page_to_pfn(page + i));
3021 if (young)
3022 swp_entry = make_migration_entry_young(swp_entry);
3023 if (dirty)
3024 swp_entry = make_migration_entry_dirty(swp_entry);
3025 entry = swp_entry_to_pte(swp_entry);
3026 if (soft_dirty)
3027 entry = pte_swp_mksoft_dirty(entry);
3028 if (uffd_wp)
3029 entry = pte_swp_mkuffd_wp(entry);
3030
3031 VM_WARN_ON(!pte_none(ptep_get(pte + i)));
3032 set_pte_at(mm, addr, pte + i, entry);
3033 }
3034 } else {
3035 pte_t entry;
3036
3037 entry = mk_pte(page, READ_ONCE(vma->vm_page_prot));
3038 if (write)
3039 entry = pte_mkwrite(entry, vma);
3040 if (!young)
3041 entry = pte_mkold(entry);
3042 /* NOTE: this may set soft-dirty too on some archs */
3043 if (dirty)
3044 entry = pte_mkdirty(entry);
3045 if (soft_dirty)
3046 entry = pte_mksoft_dirty(entry);
3047 if (uffd_wp)
3048 entry = pte_mkuffd_wp(entry);
3049
3050 for (i = 0; i < HPAGE_PMD_NR; i++)
3051 VM_WARN_ON(!pte_none(ptep_get(pte + i)));
3052
3053 set_ptes(mm, haddr, pte, entry, HPAGE_PMD_NR);
3054 }
3055 pte_unmap(pte);
3056
3057 if (!pmd_migration)
3058 folio_remove_rmap_pmd(folio, page, vma);
3059 if (freeze)
3060 put_page(page);
3061
3062 smp_wmb(); /* make pte visible before pmd */
3063 pmd_populate(mm, pmd, pgtable);
3064 }
3065
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
2025-09-25 1:43 ` Yin Tirui
@ 2025-09-25 9:38 ` David Hildenbrand
-1 siblings, 0 replies; 21+ messages in thread
From: David Hildenbrand @ 2025-09-25 9:38 UTC (permalink / raw)
To: Yin Tirui, akpm, lorenzo.stoakes, Liam.Howlett, vbabka, rppt,
surenb, mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain,
baohua, catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102
On 25.09.25 03:43, Yin Tirui wrote:
>
>
> On 9/24/2025 5:50 PM, David Hildenbrand wrote:
>>> Introduce pfnmap_max_page_shift parameter to control maximum page
>>> size and "nohugepfnmap" boot option to disable huge pfnmap entirely.
>>
>> Why? If an arch supports it we should just do it. Or what's the reason
>> behind that?
>>
> There's no specific reason for this - it was just intended to provide an
> additional option. I'll remove it in the next version.
Good, then let's keep it simple :)
--
Cheers
David / dhildenb
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
@ 2025-09-25 9:38 ` David Hildenbrand
0 siblings, 0 replies; 21+ messages in thread
From: David Hildenbrand @ 2025-09-25 9:38 UTC (permalink / raw)
To: Yin Tirui, akpm, lorenzo.stoakes, Liam.Howlett, vbabka, rppt,
surenb, mhocko, ziy, baolin.wang, npache, ryan.roberts, dev.jain,
baohua, catalin.marinas, will, paul.walmsley, palmer, aou, alex,
anshuman.khandual, yangyicong, ardb, willy, apopple,
samuel.holland, luxu.kernel, abrestic, yongxuan.wang, linux-mm,
linux-kernel, linux-arm-kernel, linux-riscv
Cc: wangkefeng.wang, chenjun102
On 25.09.25 03:43, Yin Tirui wrote:
>
>
> On 9/24/2025 5:50 PM, David Hildenbrand wrote:
>>> Introduce pfnmap_max_page_shift parameter to control maximum page
>>> size and "nohugepfnmap" boot option to disable huge pfnmap entirely.
>>
>> Why? If an arch supports it we should just do it. Or what's the reason
>> behind that?
>>
> There's no specific reason for this - it was just intended to provide an
> additional option. I'll remove it in the next version.
Good, then let's keep it simple :)
--
Cheers
David / dhildenb
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
* [syzbot ci] Re: mm: add huge pfnmap support for remap_pfn_range()
2025-10-16 11:27 [PATCH RFC v2 0/2] " Yin Tirui
@ 2025-10-16 16:23 ` syzbot ci
0 siblings, 0 replies; 21+ messages in thread
From: syzbot ci @ 2025-10-16 16:23 UTC (permalink / raw)
To: abrestic, akpm, alex, anshuman.khandual, aou, apopple, ardb,
baohua, baolin.wang, catalin.marinas, chenjun102, david, dev.jain,
liam.howlett, linux-arm-kernel, linux-kernel, linux-mm,
linux-riscv, lorenzo.stoakes, luxu.kernel, mhocko, npache, palmer,
paul.walmsley, rppt, ryan.roberts, samuel.holland, surenb, vbabka,
wangkefeng.wang, will, willy, yangyicong, yintirui, yongxuan.wang,
ziy
Cc: syzbot, syzkaller-bugs
syzbot ci has tested the following series
[v2] mm: add huge pfnmap support for remap_pfn_range()
https://lore.kernel.org/all/20251016112704.179280-1-yintirui@huawei.com
* [PATCH RFC 1/2] pgtable: add pte_clrhuge() implementation for arm64 and riscv
* [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
and found the following issue:
stack segment fault in pgtable_trans_huge_withdraw
Full report is available here:
https://ci.syzbot.org/series/d04c2914-0d99-4132-89d4-899e22abf904
***
stack segment fault in pgtable_trans_huge_withdraw
tree: torvalds
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
base: 3a8660878839faadb4f1a6dd72c3179c1df56787
arch: amd64
compiler: Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
config: https://ci.syzbot.org/builds/9d7864e5-ad3a-4c0d-b21d-86cfc476792e/config
C repro: https://ci.syzbot.org/findings/b9fca361-413d-4db1-b8b2-1849cd2c50dd/c_repro
syz repro: https://ci.syzbot.org/findings/b9fca361-413d-4db1-b8b2-1849cd2c50dd/syz_repro
Oops: stack segment: 0000 [#1] SMP KASAN PTI
CPU: 0 UID: 0 PID: 5968 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
RIP: 0010:pgtable_trans_huge_withdraw+0x115/0x310 mm/pgtable-generic.c:188
Code: c3 10 48 89 d8 48 c1 e8 03 42 80 3c 28 00 74 08 48 89 df e8 9d e9 13 00 48 8b 03 48 89 04 24 4c 8d 78 08 4c 89 fd 48 c1 ed 03 <42> 80 7c 2d 00 00 74 08 4c 89 ff e8 7b e9 13 00 49 8b 07 48 8d 48
RSP: 0018:ffffc90003717300 EFLAGS: 00010202
RAX: 0000000000000000 RBX: ffffea00044848d0 RCX: ffff88816c890000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000001 R08: ffff88816db66a23 R09: 1ffff1102db6cd44
R10: dffffc0000000000 R11: ffffed102db6cd45 R12: ffff888112123000
R13: dffffc0000000000 R14: ffff888112123000 R15: 0000000000000008
FS: 000055556cb5f500(0000) GS:ffff88818e70c000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 00000001102a4000 CR4: 00000000000006f0
Call Trace:
<TASK>
zap_deposited_table mm/huge_memory.c:2169 [inline]
zap_huge_pmd+0xa25/0xf50 mm/huge_memory.c:2197
zap_pmd_range mm/memory.c:1926 [inline]
zap_pud_range mm/memory.c:1975 [inline]
zap_p4d_range mm/memory.c:1996 [inline]
unmap_page_range+0x9fe/0x4370 mm/memory.c:2017
unmap_single_vma mm/memory.c:2060 [inline]
unmap_vmas+0x399/0x580 mm/memory.c:2104
exit_mmap+0x240/0xb40 mm/mmap.c:1280
__mmput+0x118/0x430 kernel/fork.c:1133
copy_process+0x2910/0x3c00 kernel/fork.c:2460
kernel_clone+0x21e/0x840 kernel/fork.c:2609
__do_sys_clone kernel/fork.c:2750 [inline]
__se_sys_clone kernel/fork.c:2734 [inline]
__x64_sys_clone+0x18b/0x1e0 kernel/fork.c:2734
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f946958eec9
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffc41c94258 EFLAGS: 00000206 ORIG_RAX: 0000000000000038
RAX: ffffffffffffffda RBX: 00007f94697e5fa0 RCX: 00007f946958eec9
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000002001000
RBP: 00007f9469611f91 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000000
R13: 00007f94697e5fa0 R14: 00007f94697e5fa0 R15: 0000000000000006
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:pgtable_trans_huge_withdraw+0x115/0x310 mm/pgtable-generic.c:188
Code: c3 10 48 89 d8 48 c1 e8 03 42 80 3c 28 00 74 08 48 89 df e8 9d e9 13 00 48 8b 03 48 89 04 24 4c 8d 78 08 4c 89 fd 48 c1 ed 03 <42> 80 7c 2d 00 00 74 08 4c 89 ff e8 7b e9 13 00 49 8b 07 48 8d 48
RSP: 0018:ffffc90003717300 EFLAGS: 00010202
RAX: 0000000000000000 RBX: ffffea00044848d0 RCX: ffff88816c890000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000001 R08: ffff88816db66a23 R09: 1ffff1102db6cd44
R10: dffffc0000000000 R11: ffffed102db6cd45 R12: ffff888112123000
R13: dffffc0000000000 R14: ffff888112123000 R15: 0000000000000008
FS: 000055556cb5f500(0000) GS:ffff88818e70c000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 00000001102a4000 CR4: 00000000000006f0
----------------
Code disassembly (best guess):
0: c3 ret
1: 10 48 89 adc %cl,-0x77(%rax)
4: d8 48 c1 fmuls -0x3f(%rax)
7: e8 03 42 80 3c call 0x3c80420f
c: 28 00 sub %al,(%rax)
e: 74 08 je 0x18
10: 48 89 df mov %rbx,%rdi
13: e8 9d e9 13 00 call 0x13e9b5
18: 48 8b 03 mov (%rbx),%rax
1b: 48 89 04 24 mov %rax,(%rsp)
1f: 4c 8d 78 08 lea 0x8(%rax),%r15
23: 4c 89 fd mov %r15,%rbp
26: 48 c1 ed 03 shr $0x3,%rbp
* 2a: 42 80 7c 2d 00 00 cmpb $0x0,0x0(%rbp,%r13,1) <-- trapping instruction
30: 74 08 je 0x3a
32: 4c 89 ff mov %r15,%rdi
35: e8 7b e9 13 00 call 0x13e9b5
3a: 49 8b 07 mov (%r15),%rax
3d: 48 rex.W
3e: 8d .byte 0x8d
3f: 48 rex.W
***
If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
Tested-by: syzbot@syzkaller.appspotmail.com
---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.
^ permalink raw reply [flat|nested] 21+ messages in thread
* [syzbot ci] Re: mm: add huge pfnmap support for remap_pfn_range()
@ 2025-10-16 16:23 ` syzbot ci
0 siblings, 0 replies; 21+ messages in thread
From: syzbot ci @ 2025-10-16 16:23 UTC (permalink / raw)
To: abrestic, akpm, alex, anshuman.khandual, aou, apopple, ardb,
baohua, baolin.wang, catalin.marinas, chenjun102, david, dev.jain,
liam.howlett, linux-arm-kernel, linux-kernel, linux-mm,
linux-riscv, lorenzo.stoakes, luxu.kernel, mhocko, npache, palmer,
paul.walmsley, rppt, ryan.roberts, samuel.holland, surenb, vbabka,
wangkefeng.wang, will, willy, yangyicong, yintirui, yongxuan.wang,
ziy
Cc: syzbot, syzkaller-bugs
syzbot ci has tested the following series
[v2] mm: add huge pfnmap support for remap_pfn_range()
https://lore.kernel.org/all/20251016112704.179280-1-yintirui@huawei.com
* [PATCH RFC 1/2] pgtable: add pte_clrhuge() implementation for arm64 and riscv
* [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range()
and found the following issue:
stack segment fault in pgtable_trans_huge_withdraw
Full report is available here:
https://ci.syzbot.org/series/d04c2914-0d99-4132-89d4-899e22abf904
***
stack segment fault in pgtable_trans_huge_withdraw
tree: torvalds
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
base: 3a8660878839faadb4f1a6dd72c3179c1df56787
arch: amd64
compiler: Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
config: https://ci.syzbot.org/builds/9d7864e5-ad3a-4c0d-b21d-86cfc476792e/config
C repro: https://ci.syzbot.org/findings/b9fca361-413d-4db1-b8b2-1849cd2c50dd/c_repro
syz repro: https://ci.syzbot.org/findings/b9fca361-413d-4db1-b8b2-1849cd2c50dd/syz_repro
Oops: stack segment: 0000 [#1] SMP KASAN PTI
CPU: 0 UID: 0 PID: 5968 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
RIP: 0010:pgtable_trans_huge_withdraw+0x115/0x310 mm/pgtable-generic.c:188
Code: c3 10 48 89 d8 48 c1 e8 03 42 80 3c 28 00 74 08 48 89 df e8 9d e9 13 00 48 8b 03 48 89 04 24 4c 8d 78 08 4c 89 fd 48 c1 ed 03 <42> 80 7c 2d 00 00 74 08 4c 89 ff e8 7b e9 13 00 49 8b 07 48 8d 48
RSP: 0018:ffffc90003717300 EFLAGS: 00010202
RAX: 0000000000000000 RBX: ffffea00044848d0 RCX: ffff88816c890000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000001 R08: ffff88816db66a23 R09: 1ffff1102db6cd44
R10: dffffc0000000000 R11: ffffed102db6cd45 R12: ffff888112123000
R13: dffffc0000000000 R14: ffff888112123000 R15: 0000000000000008
FS: 000055556cb5f500(0000) GS:ffff88818e70c000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 00000001102a4000 CR4: 00000000000006f0
Call Trace:
<TASK>
zap_deposited_table mm/huge_memory.c:2169 [inline]
zap_huge_pmd+0xa25/0xf50 mm/huge_memory.c:2197
zap_pmd_range mm/memory.c:1926 [inline]
zap_pud_range mm/memory.c:1975 [inline]
zap_p4d_range mm/memory.c:1996 [inline]
unmap_page_range+0x9fe/0x4370 mm/memory.c:2017
unmap_single_vma mm/memory.c:2060 [inline]
unmap_vmas+0x399/0x580 mm/memory.c:2104
exit_mmap+0x240/0xb40 mm/mmap.c:1280
__mmput+0x118/0x430 kernel/fork.c:1133
copy_process+0x2910/0x3c00 kernel/fork.c:2460
kernel_clone+0x21e/0x840 kernel/fork.c:2609
__do_sys_clone kernel/fork.c:2750 [inline]
__se_sys_clone kernel/fork.c:2734 [inline]
__x64_sys_clone+0x18b/0x1e0 kernel/fork.c:2734
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0xfa0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f946958eec9
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffc41c94258 EFLAGS: 00000206 ORIG_RAX: 0000000000000038
RAX: ffffffffffffffda RBX: 00007f94697e5fa0 RCX: 00007f946958eec9
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000002001000
RBP: 00007f9469611f91 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000000
R13: 00007f94697e5fa0 R14: 00007f94697e5fa0 R15: 0000000000000006
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:pgtable_trans_huge_withdraw+0x115/0x310 mm/pgtable-generic.c:188
Code: c3 10 48 89 d8 48 c1 e8 03 42 80 3c 28 00 74 08 48 89 df e8 9d e9 13 00 48 8b 03 48 89 04 24 4c 8d 78 08 4c 89 fd 48 c1 ed 03 <42> 80 7c 2d 00 00 74 08 4c 89 ff e8 7b e9 13 00 49 8b 07 48 8d 48
RSP: 0018:ffffc90003717300 EFLAGS: 00010202
RAX: 0000000000000000 RBX: ffffea00044848d0 RCX: ffff88816c890000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000001 R08: ffff88816db66a23 R09: 1ffff1102db6cd44
R10: dffffc0000000000 R11: ffffed102db6cd45 R12: ffff888112123000
R13: dffffc0000000000 R14: ffff888112123000 R15: 0000000000000008
FS: 000055556cb5f500(0000) GS:ffff88818e70c000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 00000001102a4000 CR4: 00000000000006f0
----------------
Code disassembly (best guess):
0: c3 ret
1: 10 48 89 adc %cl,-0x77(%rax)
4: d8 48 c1 fmuls -0x3f(%rax)
7: e8 03 42 80 3c call 0x3c80420f
c: 28 00 sub %al,(%rax)
e: 74 08 je 0x18
10: 48 89 df mov %rbx,%rdi
13: e8 9d e9 13 00 call 0x13e9b5
18: 48 8b 03 mov (%rbx),%rax
1b: 48 89 04 24 mov %rax,(%rsp)
1f: 4c 8d 78 08 lea 0x8(%rax),%r15
23: 4c 89 fd mov %r15,%rbp
26: 48 c1 ed 03 shr $0x3,%rbp
* 2a: 42 80 7c 2d 00 00 cmpb $0x0,0x0(%rbp,%r13,1) <-- trapping instruction
30: 74 08 je 0x3a
32: 4c 89 ff mov %r15,%rdi
35: e8 7b e9 13 00 call 0x13e9b5
3a: 49 8b 07 mov (%r15),%rax
3d: 48 rex.W
3e: 8d .byte 0x8d
3f: 48 rex.W
***
If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
Tested-by: syzbot@syzkaller.appspotmail.com
---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2025-10-16 16:24 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-23 13:31 [PATCH RFC 0/2] mm: add huge pfnmap support for remap_pfn_range() Yin Tirui
2025-09-23 13:31 ` Yin Tirui
2025-09-23 13:31 ` [PATCH RFC 1/2] pgtable: add pte_clrhuge() implementation for arm64 and riscv Yin Tirui
2025-09-23 13:31 ` Yin Tirui
2025-09-23 13:31 ` [PATCH RFC 2/2] mm: add PMD-level huge page support for remap_pfn_range() Yin Tirui
2025-09-23 13:31 ` Yin Tirui
2025-09-23 22:39 ` Matthew Wilcox
2025-09-23 22:39 ` Matthew Wilcox
2025-09-25 2:17 ` Yin Tirui
2025-09-25 2:17 ` Yin Tirui
2025-09-24 9:50 ` David Hildenbrand
2025-09-24 9:50 ` David Hildenbrand
2025-09-25 1:43 ` Yin Tirui
2025-09-25 1:43 ` Yin Tirui
2025-09-25 9:38 ` David Hildenbrand
2025-09-25 9:38 ` David Hildenbrand
2025-09-25 3:14 ` kernel test robot
2025-09-23 22:53 ` [syzbot ci] Re: mm: add huge pfnmap " syzbot ci
2025-09-23 22:53 ` syzbot ci
-- strict thread matches above, loose matches on Subject: below --
2025-10-16 11:27 [PATCH RFC v2 0/2] " Yin Tirui
2025-10-16 16:23 ` [syzbot ci] " syzbot ci
2025-10-16 16:23 ` syzbot ci
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.