[RFC PATCH 2/3] arm64/mm: make huge zero folio read-only in linear map
From: Xueyuan chen
Date: Tue May 26 2026 - 23:57:31 EST
From: Xueyuan Chen <xueyuan.chen21@xxxxxxxxx>
Implement arch_make_huge_zero_folio_readonly() for arm64. Once allocated,
try to make the folio read-only in the linear map so unexpected writes
fault instead of corrupting shared zero contents.
Respect can_set_direct_map() before touching the linear map, and treat the
pageattr update as best effort: it can still fail while splitting a leaf
mapping or applying new permissions. If that happens, generic THP keeps
using the writable persistent huge zero folio.
Co-developed-by: Lance Yang <lance.yang@xxxxxxxxx>
Signed-off-by: Lance Yang <lance.yang@xxxxxxxxx>
Signed-off-by: Xueyuan Chen <xueyuan.chen21@xxxxxxxxx>
---
arch/arm64/Kconfig | 1 +
arch/arm64/mm/pageattr.c | 16 ++++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fe60738e5943..3cd705dd5251 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -44,6 +44,7 @@ config ARM64
select ARCH_HAS_PREEMPT_LAZY
select ARCH_HAS_PTDUMP
select ARCH_HAS_PTE_SPECIAL
+ select ARCH_HAS_READONLY_HUGE_ZERO_FOLIO
select ARCH_HAS_HW_PTE_YOUNG
select ARCH_HAS_SETUP_DMA_OPS
select ARCH_HAS_SET_DIRECT_MAP
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index ce035e1b4eaf..51ce31e74a18 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -3,7 +3,9 @@
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
+#include <linux/init.h>
#include <linux/mm.h>
+#include <linux/huge_mm.h>
#include <linux/module.h>
#include <linux/mem_encrypt.h>
#include <linux/sched.h>
@@ -147,6 +149,20 @@ static int __change_memory_common(unsigned long start, unsigned long size,
return ret;
}
+#ifdef CONFIG_READONLY_HUGE_ZERO_FOLIO
+bool __init arch_make_huge_zero_folio_readonly(struct folio *folio)
+{
+ unsigned long addr = (unsigned long)folio_address(folio);
+
+ if (!can_set_direct_map())
+ return false;
+
+ return !__change_memory_common(addr, PMD_SIZE,
+ __pgprot(PTE_RDONLY),
+ __pgprot(PTE_WRITE));
+}
+#endif
+
static int change_memory_common(unsigned long addr, int numpages,
pgprot_t set_mask, pgprot_t clear_mask)
{
--
2.47.3