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

Yin Tirui yintirui at huawei.com
Mon Apr 20 04:43:20 PDT 2026


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 at huawei.com>
>> ---
>>   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




More information about the linux-arm-kernel mailing list