* [RFC PATCH 0/2] restore large page mappings in direct map for secretmem
@ 2026-06-03 10:46 Lance Yang
2026-06-03 10:46 ` [RFC PATCH 1/2] mm/secretmem: try to restore large page mappings in direct map Lance Yang
2026-06-03 10:46 ` [RFC PATCH 2/2] x86/mm: restore large page mappings for secretmem Lance Yang
0 siblings, 2 replies; 7+ messages in thread
From: Lance Yang @ 2026-06-03 10:46 UTC (permalink / raw)
To: akpm
Cc: rppt, david, tglx, mingo, bp, dave.hansen, x86, hpa, luto, peterz,
linux-mm, linux-kernel, xueyuan.chen21, ioworker0
Hi all,
secretmem removes the pages backing secretmem mappings from the direct map.
Removing one base page from the direct map can split the covering large
mapping down to PTE mappings. Repeated splits can leave more of the direct
map mapped with PTEs, meaning more TLB entries for the same range and
potentially more TLB pressure.
This series adds an arch hook so secretmem can ask the architecture to try
to restore large page mappings whenever secretmem restores a folio to the
direct map.
Thanks,
Lance
Lance Yang (2):
mm/secretmem: try to restore large page mappings in direct map
x86/mm: restore large page mappings for secretmem
arch/x86/include/asm/set_memory.h | 2 ++
arch/x86/mm/pat/set_memory.c | 27 +++++++++++++++++++++++++++
include/linux/set_memory.h | 6 ++++++
mm/secretmem.c | 12 ++++++++++--
4 files changed, 45 insertions(+), 2 deletions(-)
--
2.49.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH 1/2] mm/secretmem: try to restore large page mappings in direct map
2026-06-03 10:46 [RFC PATCH 0/2] restore large page mappings in direct map for secretmem Lance Yang
@ 2026-06-03 10:46 ` Lance Yang
2026-06-03 10:59 ` Mike Rapoport
2026-06-03 10:46 ` [RFC PATCH 2/2] x86/mm: restore large page mappings for secretmem Lance Yang
1 sibling, 1 reply; 7+ messages in thread
From: Lance Yang @ 2026-06-03 10:46 UTC (permalink / raw)
To: akpm
Cc: rppt, david, tglx, mingo, bp, dave.hansen, x86, hpa, luto, peterz,
linux-mm, linux-kernel, xueyuan.chen21, ioworker0, Lance Yang
From: Lance Yang <lance.yang@linux.dev>
secretmem removes the pages backing secretmem mappings from the direct map.
Removing one base page from the direct map can split the covering large
mapping down to PTE mappings. Repeated splits can leave more of the direct
map mapped with PTEs, meaning more TLB entries for the same range and
potentially more TLB pressure.
So let's try to restore large page mappings whenever secretmem restores a
folio to the direct map.
Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
Signed-off-by: Lance Yang <lance.yang@linux.dev>
---
include/linux/set_memory.h | 6 ++++++
mm/secretmem.c | 12 ++++++++++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h
index 3030d9245f5a..ad2fa414a22d 100644
--- a/include/linux/set_memory.h
+++ b/include/linux/set_memory.h
@@ -58,6 +58,12 @@ static inline bool can_set_direct_map(void)
#endif
#endif /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */
+#ifndef arch_try_collapse_direct_map
+static inline void arch_try_collapse_direct_map(struct page *page)
+{
+}
+#endif
+
#ifdef CONFIG_X86_64
int set_mce_nospec(unsigned long pfn);
int clear_mce_nospec(unsigned long pfn);
diff --git a/mm/secretmem.c b/mm/secretmem.c
index 5f57ac4720d3..82634b99aa2c 100644
--- a/mm/secretmem.c
+++ b/mm/secretmem.c
@@ -47,6 +47,14 @@ bool secretmem_active(void)
return !!atomic_read(&secretmem_users);
}
+static void secretmem_restore_direct_map(struct folio *folio)
+{
+ struct page *page = folio_page(folio, 0);
+
+ if (!set_direct_map_default_noflush(page))
+ arch_try_collapse_direct_map(page);
+}
+
static vm_fault_t secretmem_fault(struct vm_fault *vmf)
{
struct address_space *mapping = vmf->vma->vm_file->f_mapping;
@@ -87,7 +95,7 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
* already happened when we marked the page invalid
* which guarantees that this call won't fail
*/
- set_direct_map_default_noflush(folio_page(folio, 0));
+ secretmem_restore_direct_map(folio);
folio_put(folio);
if (err == -EEXIST)
goto retry;
@@ -151,7 +159,7 @@ static int secretmem_migrate_folio(struct address_space *mapping,
static void secretmem_free_folio(struct folio *folio)
{
- set_direct_map_default_noflush(folio_page(folio, 0));
+ secretmem_restore_direct_map(folio);
folio_zero_segment(folio, 0, folio_size(folio));
}
--
2.49.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH 2/2] x86/mm: restore large page mappings for secretmem
2026-06-03 10:46 [RFC PATCH 0/2] restore large page mappings in direct map for secretmem Lance Yang
2026-06-03 10:46 ` [RFC PATCH 1/2] mm/secretmem: try to restore large page mappings in direct map Lance Yang
@ 2026-06-03 10:46 ` Lance Yang
1 sibling, 0 replies; 7+ messages in thread
From: Lance Yang @ 2026-06-03 10:46 UTC (permalink / raw)
To: akpm
Cc: rppt, david, tglx, mingo, bp, dave.hansen, x86, hpa, luto, peterz,
linux-mm, linux-kernel, xueyuan.chen21, ioworker0, Lance Yang
From: Lance Yang <lance.yang@linux.dev>
secretmem can ask the architecture to restore large page mappings in the
direct map after a page has been restored.
On x86, set_direct_map_invalid_noflush() clears _PAGE_PRESENT, _PAGE_RW
and _PAGE_DIRTY through CPA. CPA also clears _PAGE_GLOBAL after the PTE
becomes non-present, because that bit is used for PROTNONE.
set_direct_map_default_noflush() only restores _PAGE_PRESENT and _PAGE_RW,
so the restored PTE can still differ from the rest of the direct map. Put
back the missing PAGE_KERNEL bits before trying to collapse the range.
Use PAGE_KERNEL so the restored PTE keeps _PAGE_GLOBAL when PAGE_KERNEL
has it, and does not get it when PTI clears _PAGE_GLOBAL from
__default_kernel_pte_mask.
Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
Signed-off-by: Lance Yang <lance.yang@linux.dev>
---
arch/x86/include/asm/set_memory.h | 2 ++
arch/x86/mm/pat/set_memory.c | 27 +++++++++++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/arch/x86/include/asm/set_memory.h b/arch/x86/include/asm/set_memory.h
index 4362c26aa992..f9e94bcd83df 100644
--- a/arch/x86/include/asm/set_memory.h
+++ b/arch/x86/include/asm/set_memory.h
@@ -89,6 +89,8 @@ int set_pages_rw(struct page *page, int numpages);
int set_direct_map_invalid_noflush(struct page *page);
int set_direct_map_default_noflush(struct page *page);
int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid);
+void arch_try_collapse_direct_map(struct page *page);
+#define arch_try_collapse_direct_map arch_try_collapse_direct_map
bool kernel_page_present(struct page *page);
extern int kernel_set_to_readonly;
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index d023a40a1e03..b118619fa83c 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -2654,6 +2654,33 @@ int set_direct_map_default_noflush(struct page *page)
return __set_pages_p(page, 1);
}
+void arch_try_collapse_direct_map(struct page *page)
+{
+ pgprotval_t mask = pgprot_val(PAGE_KERNEL) & (_PAGE_DIRTY | _PAGE_GLOBAL);
+ unsigned long addr;
+ struct cpa_data cpa = { .vaddr = &addr,
+ .pgd = NULL,
+ .numpages = 1,
+ .mask_set = __pgprot(mask),
+ .mask_clr = __pgprot(0),
+ .flags = CPA_NO_CHECK_ALIAS };
+
+ if (PageHighMem(page) || debug_pagealloc_enabled())
+ return;
+
+ addr = (unsigned long)page_address(page);
+
+ /*
+ * set_direct_map_default_noflush() only restores _PAGE_PRESENT and
+ * _PAGE_RW. Put back the other PAGE_KERNEL bits needed for a restored
+ * direct-map PTE to match the rest of the range.
+ */
+ if (__change_page_attr_set_clr(&cpa, 1))
+ return;
+
+ cpa_collapse_large_pages(&cpa);
+}
+
int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid)
{
if (valid)
--
2.49.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 1/2] mm/secretmem: try to restore large page mappings in direct map
2026-06-03 10:46 ` [RFC PATCH 1/2] mm/secretmem: try to restore large page mappings in direct map Lance Yang
@ 2026-06-03 10:59 ` Mike Rapoport
2026-06-03 11:41 ` Lance Yang
0 siblings, 1 reply; 7+ messages in thread
From: Mike Rapoport @ 2026-06-03 10:59 UTC (permalink / raw)
To: Lance Yang
Cc: akpm, david, tglx, mingo, bp, dave.hansen, x86, hpa, luto, peterz,
linux-mm, linux-kernel, xueyuan.chen21, ioworker0
Hi Lance,
On Wed, Jun 03, 2026 at 06:46:23PM +0800, Lance Yang wrote:
> From: Lance Yang <lance.yang@linux.dev>
>
> secretmem removes the pages backing secretmem mappings from the direct map.
>
> Removing one base page from the direct map can split the covering large
> mapping down to PTE mappings. Repeated splits can leave more of the direct
> map mapped with PTEs, meaning more TLB entries for the same range and
> potentially more TLB pressure.
>
> So let's try to restore large page mappings whenever secretmem restores a
> folio to the direct map.
>
> Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
> Signed-off-by: Lance Yang <lance.yang@linux.dev>
> ---
> include/linux/set_memory.h | 6 ++++++
> mm/secretmem.c | 12 ++++++++++--
> 2 files changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h
> index 3030d9245f5a..ad2fa414a22d 100644
> --- a/include/linux/set_memory.h
> +++ b/include/linux/set_memory.h
> @@ -58,6 +58,12 @@ static inline bool can_set_direct_map(void)
> #endif
> #endif /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */
>
> +#ifndef arch_try_collapse_direct_map
> +static inline void arch_try_collapse_direct_map(struct page *page)
> +{
> +}
> +#endif
Did you explore what would it mean to hook collapse_large_pages() into
set_direct_map_default_noflush()?
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 1/2] mm/secretmem: try to restore large page mappings in direct map
2026-06-03 10:59 ` Mike Rapoport
@ 2026-06-03 11:41 ` Lance Yang
2026-06-03 12:35 ` Mike Rapoport
0 siblings, 1 reply; 7+ messages in thread
From: Lance Yang @ 2026-06-03 11:41 UTC (permalink / raw)
To: rppt
Cc: lance.yang, akpm, david, tglx, mingo, bp, dave.hansen, x86, hpa,
luto, peterz, linux-mm, linux-kernel, xueyuan.chen21, ioworker0
On Wed, Jun 03, 2026 at 01:59:39PM +0300, Mike Rapoport wrote:
>Hi Lance,
Hey Mike,
>On Wed, Jun 03, 2026 at 06:46:23PM +0800, Lance Yang wrote:
>> From: Lance Yang <lance.yang@linux.dev>
>>
>> secretmem removes the pages backing secretmem mappings from the direct map.
>>
>> Removing one base page from the direct map can split the covering large
>> mapping down to PTE mappings. Repeated splits can leave more of the direct
>> map mapped with PTEs, meaning more TLB entries for the same range and
>> potentially more TLB pressure.
>>
>> So let's try to restore large page mappings whenever secretmem restores a
>> folio to the direct map.
>>
>> Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
>> Signed-off-by: Lance Yang <lance.yang@linux.dev>
>> ---
>> include/linux/set_memory.h | 6 ++++++
>> mm/secretmem.c | 12 ++++++++++--
>> 2 files changed, 16 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h
>> index 3030d9245f5a..ad2fa414a22d 100644
>> --- a/include/linux/set_memory.h
>> +++ b/include/linux/set_memory.h
>> @@ -58,6 +58,12 @@ static inline bool can_set_direct_map(void)
>> #endif
>> #endif /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */
>>
>> +#ifndef arch_try_collapse_direct_map
>> +static inline void arch_try_collapse_direct_map(struct page *page)
>> +{
>> +}
>> +#endif
>
>Did you explore what would it mean to hook collapse_large_pages() into
>set_direct_map_default_noflush()?
Good point, I kept it separate on purpose :)
Putting collapse into set_direct_map_default_noflush() would change the
semantics of that helper a bit, IMHO.
I would expect arch_try_collapse_direct_map() to also be useful for cases
where a direct-map permission change could split a large maping first,
and the user wants to try restoring the large mapping after changing it
back. One example[1] is making a direct-map range read-only for security,
which I am also working on :)
[1] https://lore.kernel.org/linux-mm/9979fa87-88ef-4baf-8592-502ff4888085@kernel.org/
Cheers, Lance
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 1/2] mm/secretmem: try to restore large page mappings in direct map
2026-06-03 11:41 ` Lance Yang
@ 2026-06-03 12:35 ` Mike Rapoport
2026-06-03 13:09 ` Lance Yang
0 siblings, 1 reply; 7+ messages in thread
From: Mike Rapoport @ 2026-06-03 12:35 UTC (permalink / raw)
To: Lance Yang
Cc: akpm, david, tglx, mingo, bp, dave.hansen, x86, hpa, luto, peterz,
linux-mm, linux-kernel, xueyuan.chen21, ioworker0
On Wed, Jun 03, 2026 at 07:41:34PM +0800, Lance Yang wrote:
> On Wed, Jun 03, 2026 at 01:59:39PM +0300, Mike Rapoport wrote:
> >On Wed, Jun 03, 2026 at 06:46:23PM +0800, Lance Yang wrote:
> >> From: Lance Yang <lance.yang@linux.dev>
> >>
> >> secretmem removes the pages backing secretmem mappings from the direct map.
> >>
> >> Removing one base page from the direct map can split the covering large
> >> mapping down to PTE mappings. Repeated splits can leave more of the direct
> >> map mapped with PTEs, meaning more TLB entries for the same range and
> >> potentially more TLB pressure.
> >>
> >> So let's try to restore large page mappings whenever secretmem restores a
> >> folio to the direct map.
> >>
> >> Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
> >> Signed-off-by: Lance Yang <lance.yang@linux.dev>
> >> ---
> >> include/linux/set_memory.h | 6 ++++++
> >> mm/secretmem.c | 12 ++++++++++--
> >> 2 files changed, 16 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h
> >> index 3030d9245f5a..ad2fa414a22d 100644
> >> --- a/include/linux/set_memory.h
> >> +++ b/include/linux/set_memory.h
> >> @@ -58,6 +58,12 @@ static inline bool can_set_direct_map(void)
> >> #endif
> >> #endif /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */
> >>
> >> +#ifndef arch_try_collapse_direct_map
> >> +static inline void arch_try_collapse_direct_map(struct page *page)
> >> +{
> >> +}
> >> +#endif
> >
> >Did you explore what would it mean to hook collapse_large_pages() into
> >set_direct_map_default_noflush()?
>
> Good point, I kept it separate on purpose :)
>
> Putting collapse into set_direct_map_default_noflush() would change the
> semantics of that helper a bit, IMHO.
For x86 default means present + rw + PSE, so yuu can look at it as actually
better enforcing the semantics :)
> I would expect arch_try_collapse_direct_map() to also be useful for cases
> where a direct-map permission change could split a large maping first,
> and the user wants to try restoring the large mapping after changing it
> back. One example[1] is making a direct-map range read-only for security,
> which I am also working on :)
I don't think users should care. The users care for particular permissions
of a range in the direct map. It should be up to the architecture to select
most suitable mapping size. The splits are implicit, I don't see why
collapses can't be implicit as well.
> [1] https://lore.kernel.org/linux-mm/9979fa87-88ef-4baf-8592-502ff4888085@kernel.org/
>
> Cheers, Lance
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 1/2] mm/secretmem: try to restore large page mappings in direct map
2026-06-03 12:35 ` Mike Rapoport
@ 2026-06-03 13:09 ` Lance Yang
0 siblings, 0 replies; 7+ messages in thread
From: Lance Yang @ 2026-06-03 13:09 UTC (permalink / raw)
To: Mike Rapoport
Cc: akpm, david, tglx, mingo, bp, dave.hansen, x86, hpa, luto, peterz,
linux-mm, linux-kernel, xueyuan.chen21, ioworker0
On 2026/6/3 20:35, Mike Rapoport wrote:
> On Wed, Jun 03, 2026 at 07:41:34PM +0800, Lance Yang wrote:
>> On Wed, Jun 03, 2026 at 01:59:39PM +0300, Mike Rapoport wrote:
>>> On Wed, Jun 03, 2026 at 06:46:23PM +0800, Lance Yang wrote:
>>>> From: Lance Yang <lance.yang@linux.dev>
>>>>
>>>> secretmem removes the pages backing secretmem mappings from the direct map.
>>>>
>>>> Removing one base page from the direct map can split the covering large
>>>> mapping down to PTE mappings. Repeated splits can leave more of the direct
>>>> map mapped with PTEs, meaning more TLB entries for the same range and
>>>> potentially more TLB pressure.
>>>>
>>>> So let's try to restore large page mappings whenever secretmem restores a
>>>> folio to the direct map.
>>>>
>>>> Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
>>>> Signed-off-by: Lance Yang <lance.yang@linux.dev>
>>>> ---
>>>> include/linux/set_memory.h | 6 ++++++
>>>> mm/secretmem.c | 12 ++++++++++--
>>>> 2 files changed, 16 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h
>>>> index 3030d9245f5a..ad2fa414a22d 100644
>>>> --- a/include/linux/set_memory.h
>>>> +++ b/include/linux/set_memory.h
>>>> @@ -58,6 +58,12 @@ static inline bool can_set_direct_map(void)
>>>> #endif
>>>> #endif /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */
>>>>
>>>> +#ifndef arch_try_collapse_direct_map
>>>> +static inline void arch_try_collapse_direct_map(struct page *page)
>>>> +{
>>>> +}
>>>> +#endif
>>>
>>> Did you explore what would it mean to hook collapse_large_pages() into
>>> set_direct_map_default_noflush()?
>>
>> Good point, I kept it separate on purpose :)
>>
>> Putting collapse into set_direct_map_default_noflush() would change the
>> semantics of that helper a bit, IMHO.
>
> For x86 default means present + rw + PSE, so yuu can look at it as actually
> better enforcing the semantics :)
Yep. One x86 detail though, default seems to miss _PAGE_GLOBAL today. Not
sure if that is intentional or just historical. See patch #02.
>> I would expect arch_try_collapse_direct_map() to also be useful for cases
>> where a direct-map permission change could split a large maping first,
>> and the user wants to try restoring the large mapping after changing it
>> back. One example[1] is making a direct-map range read-only for security,
>> which I am also working on :)
>
> I don't think users should care. The users care for particular permissions
> of a range in the direct map. It should be up to the architecture to select
> most suitable mapping size. The splits are implicit, I don't see why
> collapses can't be implicit as well.
And agreed, users should not care about the final mapping size, that is
up to the arch.
TBH, my concern is making the collapse cost implicit for every
set_direct_map_default_noflush() caller. I still lean toward keeping
it opt-in, but happy to hear what folks prefer :)
>
>> [1] https://lore.kernel.org/linux-mm/9979fa87-88ef-4baf-8592-502ff4888085@kernel.org/
>>
>> Cheers, Lance
>>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-06-03 13:09 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-03 10:46 [RFC PATCH 0/2] restore large page mappings in direct map for secretmem Lance Yang
2026-06-03 10:46 ` [RFC PATCH 1/2] mm/secretmem: try to restore large page mappings in direct map Lance Yang
2026-06-03 10:59 ` Mike Rapoport
2026-06-03 11:41 ` Lance Yang
2026-06-03 12:35 ` Mike Rapoport
2026-06-03 13:09 ` Lance Yang
2026-06-03 10:46 ` [RFC PATCH 2/2] x86/mm: restore large page mappings for secretmem Lance Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox