Re: [PATCH RFC v3 2/4] mm/pgtable: Make pfn_pte() filter out huge page attributes

From: Yin Tirui

Date: Mon Apr 20 2026 - 07:43:49 EST


Hi Will,

On 4/20/2026 4:48 PM, Will Deacon wrote:
On Sat, Feb 28, 2026 at 03:09:04PM +0800, Yin Tirui wrote:
A fundamental principle of page table type safety is that `pte_t` represents
the lowest level page table entry and should never carry huge page attributes.

Currently, passing a pgprot with huge page bits (e.g., extracted via
pmd_pgprot()) into pfn_pte() creates a malformed PTE that retains the huge
attribute, leading to the necessity of the ugly `pte_clrhuge()` anti-pattern.

Enforce type safety by making `pfn_pte()` inherently filter out huge page
attributes:
- On x86: Strip the `_PAGE_PSE` bit.
- On ARM64: Mask out the block descriptor bits in `PTE_TYPE_MASK` and
enforce the `PTE_TYPE_PAGE` format.
- On RISC-V: No changes required, as RISC-V leaf PMDs and PTEs share the
exact same hardware format and do not use a distinct huge bit.

Signed-off-by: Yin Tirui <yintirui@xxxxxxxxxx>
---
arch/arm64/include/asm/pgtable.h | 4 +++-
arch/x86/include/asm/pgtable.h | 4 ++++
2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index b3e58735c49b..f2a7a40106d2 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -141,7 +141,9 @@ static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
#define pte_pfn(pte) (__pte_to_phys(pte) >> PAGE_SHIFT)
#define pfn_pte(pfn,prot) \
- __pte(__phys_to_pte_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
+ __pte(__phys_to_pte_val((phys_addr_t)(pfn) << PAGE_SHIFT) | \
+ ((pgprot_val(prot) & ~(PTE_TYPE_MASK & ~PTE_VALID)) | \
+ (PTE_TYPE_PAGE & ~PTE_VALID)))
Why are you touching arch/arm64? We don't implement pte_clrhuge() afaict.
What does this actually fix?

Originally, this patch aimed to ensure that pfn_pte() always returns a PTE without any

huge page attributes by embedding the logic of pte_clrhuge() directly into pfn_pte().


However, we found this approach doesn't work well on x86, so we've abandoned this design.


Following Matthew Wilcox's suggestion, the current approach is instead to have pmd_pgprot()

return a 4K–formatted pgprot_t (i.e., without huge page attributes), and then explicitly add the

huge page attributes when constructing a PMD via pfn_pmd().


I've already implemented this in my recent commit:

https://github.com/torvalds/linux/commit/5b8ce6d33822dd7776432e03a08fe6d2dedac079



Will

--
Yin Tirui