Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] arm64: mm: refresh stale pmd snapshot after split_contpmd()
@ 2026-06-25 11:39 lirongqing
  2026-06-26 13:03 ` Dev Jain
  2026-06-26 22:53 ` Yang Shi
  0 siblings, 2 replies; 5+ messages in thread
From: lirongqing @ 2026-06-25 11:39 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Ryan Roberts, Ard Biesheuvel,
	David Hildenbrand, Anshuman Khandual, Kevin Brodsky, Yang Shi,
	Chaitanya S Prakash, linux-arm-kernel, linux-kernel
  Cc: Li RongQing

From: Li RongQing <lirongqing@baidu.com>

split_contpmd() modifies the pmd entries in-place by clearing the CONT
bit, but the local 'pmd' variable still holds the old snapshot with CONT
set. The subsequent split_pmd() call uses this stale value to derive the
pgprot for the new PTE entries via pmd_pgprot(), causing the resulting
PTEs to be populated with incorrect protection bits.

Fix this by re-reading the pmd from memory after split_contpmd() returns
in both call sites: split_kernel_leaf_mapping_locked() and
split_to_ptes_pmd_entry().

Fixes: a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")
Signed-off-by: Li RongQing <lirongqing@baidu.com>
---
 arch/arm64/mm/mmu.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 12e862c..e510336 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -746,8 +746,10 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
 	if (!pmd_present(pmd))
 		goto out;
 	if (pmd_leaf(pmd)) {
-		if (pmd_cont(pmd))
+		if (pmd_cont(pmd)) {
 			split_contpmd(pmdp);
+			pmd = pmdp_get(pmdp);
+		}
 		/*
 		 * PMD: If addr is PMD aligned then addr already describes a
 		 * leaf boundary. Otherwise, split to contpte.
@@ -891,8 +893,10 @@ static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
 	int ret = 0;
 
 	if (pmd_leaf(pmd)) {
-		if (pmd_cont(pmd))
+		if (pmd_cont(pmd)) {
 			split_contpmd(pmdp);
+			pmd = pmdp_get(pmdp);
+		}
 		ret = split_pmd(pmdp, pmd, gfp, false);
 
 		/*
-- 
2.9.4



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] arm64: mm: refresh stale pmd snapshot after split_contpmd()
  2026-06-25 11:39 [PATCH] arm64: mm: refresh stale pmd snapshot after split_contpmd() lirongqing
@ 2026-06-26 13:03 ` Dev Jain
  2026-06-26 16:03   ` David Hildenbrand (Arm)
  2026-06-26 22:53 ` Yang Shi
  1 sibling, 1 reply; 5+ messages in thread
From: Dev Jain @ 2026-06-26 13:03 UTC (permalink / raw)
  To: lirongqing, Catalin Marinas, Will Deacon, Ryan Roberts,
	Ard Biesheuvel, David Hildenbrand, Anshuman Khandual,
	Kevin Brodsky, Yang Shi, Chaitanya S Prakash, linux-arm-kernel,
	linux-kernel



On 25/06/26 5:09 pm, lirongqing wrote:
> From: Li RongQing <lirongqing@baidu.com>
> 
> split_contpmd() modifies the pmd entries in-place by clearing the CONT
> bit, but the local 'pmd' variable still holds the old snapshot with CONT
> set. The subsequent split_pmd() call uses this stale value to derive the
> pgprot for the new PTE entries via pmd_pgprot(), causing the resulting
> PTEs to be populated with incorrect protection bits.

Since the block was CONTPMD, it means the pgprot was uniform on that block,
so after splitting, it should be safe to derive the pgprot from individual pmd's
right?

> 
> Fix this by re-reading the pmd from memory after split_contpmd() returns
> in both call sites: split_kernel_leaf_mapping_locked() and
> split_to_ptes_pmd_entry().
> 
> Fixes: a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")
> Signed-off-by: Li RongQing <lirongqing@baidu.com>
> ---
>  arch/arm64/mm/mmu.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 12e862c..e510336 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -746,8 +746,10 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>  	if (!pmd_present(pmd))
>  		goto out;
>  	if (pmd_leaf(pmd)) {
> -		if (pmd_cont(pmd))
> +		if (pmd_cont(pmd)) {
>  			split_contpmd(pmdp);
> +			pmd = pmdp_get(pmdp);
> +		}
>  		/*
>  		 * PMD: If addr is PMD aligned then addr already describes a
>  		 * leaf boundary. Otherwise, split to contpte.
> @@ -891,8 +893,10 @@ static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
>  	int ret = 0;
>  
>  	if (pmd_leaf(pmd)) {
> -		if (pmd_cont(pmd))
> +		if (pmd_cont(pmd)) {
>  			split_contpmd(pmdp);
> +			pmd = pmdp_get(pmdp);
> +		}
>  		ret = split_pmd(pmdp, pmd, gfp, false);
>  
>  		/*



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] arm64: mm: refresh stale pmd snapshot after split_contpmd()
  2026-06-26 13:03 ` Dev Jain
@ 2026-06-26 16:03   ` David Hildenbrand (Arm)
  0 siblings, 0 replies; 5+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-26 16:03 UTC (permalink / raw)
  To: Dev Jain, lirongqing, Catalin Marinas, Will Deacon, Ryan Roberts,
	Ard Biesheuvel, Anshuman Khandual, Kevin Brodsky, Yang Shi,
	Chaitanya S Prakash, linux-arm-kernel, linux-kernel

On 6/26/26 15:03, Dev Jain wrote:
> 
> 
> On 25/06/26 5:09 pm, lirongqing wrote:
>> From: Li RongQing <lirongqing@baidu.com>
>>
>> split_contpmd() modifies the pmd entries in-place by clearing the CONT
>> bit, but the local 'pmd' variable still holds the old snapshot with CONT
>> set. The subsequent split_pmd() call uses this stale value to derive the
>> pgprot for the new PTE entries via pmd_pgprot(), causing the resulting
>> PTEs to be populated with incorrect protection bits.
> 
> Since the block was CONTPMD, it means the pgprot was uniform on that block,
> so after splitting, it should be safe to derive the pgprot from individual pmd's
> right?

I'm also confused by that, can we get some details why (and how) the cont bit
misguides  pmd_pgprot?

-- 
Cheers,

David


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] arm64: mm: refresh stale pmd snapshot after split_contpmd()
  2026-06-25 11:39 [PATCH] arm64: mm: refresh stale pmd snapshot after split_contpmd() lirongqing
  2026-06-26 13:03 ` Dev Jain
@ 2026-06-26 22:53 ` Yang Shi
  2026-06-27  2:46   ` 答复: [外部邮件] " Li,Rongqing
  1 sibling, 1 reply; 5+ messages in thread
From: Yang Shi @ 2026-06-26 22:53 UTC (permalink / raw)
  To: lirongqing, Catalin Marinas, Will Deacon, Ryan Roberts,
	Ard Biesheuvel, David Hildenbrand, Anshuman Khandual,
	Kevin Brodsky, Chaitanya S Prakash, linux-arm-kernel,
	linux-kernel



On 6/25/26 4:39 AM, lirongqing wrote:
> From: Li RongQing <lirongqing@baidu.com>
>
> split_contpmd() modifies the pmd entries in-place by clearing the CONT
> bit, but the local 'pmd' variable still holds the old snapshot with CONT
> set. The subsequent split_pmd() call uses this stale value to derive the
> pgprot for the new PTE entries via pmd_pgprot(), causing the resulting
> PTEs to be populated with incorrect protection bits.

If I read the code correctly, CONT bit is cleared by split_pmd(), then 
the bit may be set again for PTEs if we want to have cont ptes. So I 
don't see any problem, did I miss something?

Thanks,
Yang

>
> Fix this by re-reading the pmd from memory after split_contpmd() returns
> in both call sites: split_kernel_leaf_mapping_locked() and
> split_to_ptes_pmd_entry().
>
> Fixes: a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")
> Signed-off-by: Li RongQing <lirongqing@baidu.com>
> ---
>   arch/arm64/mm/mmu.c | 8 ++++++--
>   1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 12e862c..e510336 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -746,8 +746,10 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
>   	if (!pmd_present(pmd))
>   		goto out;
>   	if (pmd_leaf(pmd)) {
> -		if (pmd_cont(pmd))
> +		if (pmd_cont(pmd)) {
>   			split_contpmd(pmdp);
> +			pmd = pmdp_get(pmdp);
> +		}
>   		/*
>   		 * PMD: If addr is PMD aligned then addr already describes a
>   		 * leaf boundary. Otherwise, split to contpte.
> @@ -891,8 +893,10 @@ static int split_to_ptes_pmd_entry(pmd_t *pmdp, unsigned long addr,
>   	int ret = 0;
>   
>   	if (pmd_leaf(pmd)) {
> -		if (pmd_cont(pmd))
> +		if (pmd_cont(pmd)) {
>   			split_contpmd(pmdp);
> +			pmd = pmdp_get(pmdp);
> +		}
>   		ret = split_pmd(pmdp, pmd, gfp, false);
>   
>   		/*



^ permalink raw reply	[flat|nested] 5+ messages in thread

* 答复: [外部邮件] Re: [PATCH] arm64: mm: refresh stale pmd snapshot after split_contpmd()
  2026-06-26 22:53 ` Yang Shi
@ 2026-06-27  2:46   ` Li,Rongqing
  0 siblings, 0 replies; 5+ messages in thread
From: Li,Rongqing @ 2026-06-27  2:46 UTC (permalink / raw)
  To: Yang Shi, Catalin Marinas, Will Deacon, Ryan Roberts,
	Ard Biesheuvel, David Hildenbrand, Anshuman Khandual,
	Kevin Brodsky, Chaitanya S Prakash,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org

> 
> 
> 
> On 6/25/26 4:39 AM, lirongqing wrote:
> > From: Li RongQing <lirongqing@baidu.com>
> >
> > split_contpmd() modifies the pmd entries in-place by clearing the CONT
> > bit, but the local 'pmd' variable still holds the old snapshot with
> > CONT set. The subsequent split_pmd() call uses this stale value to
> > derive the pgprot for the new PTE entries via pmd_pgprot(), causing
> > the resulting PTEs to be populated with incorrect protection bits.
> 
> If I read the code correctly, CONT bit is cleared by split_pmd(), then the bit
> may be set again for PTEs if we want to have cont ptes. So I don't see any
> problem, did I miss something?
> 

You are right, there's no functional issue with the current code.
However, I think explicitly re-reading the pmd is the safer and clearer 
approach — it makes the intent obvious (we need the post-modification state) 
rather than relying on the implicit assumption that "CONT bit doesn't affect pgprot."

Thanks


[Li,Rongqing] 


> Thanks,
> Yang
> 
> >
> > Fix this by re-reading the pmd from memory after split_contpmd()
> > returns in both call sites: split_kernel_leaf_mapping_locked() and
> > split_to_ptes_pmd_entry().
> >
> > Fixes: a166563e7ec3 ("arm64: mm: support large block mapping when
> > rodata=full")
> > Signed-off-by: Li RongQing <lirongqing@baidu.com>
> > ---
> >   arch/arm64/mm/mmu.c | 8 ++++++--
> >   1 file changed, 6 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index
> > 12e862c..e510336 100644
> > --- a/arch/arm64/mm/mmu.c
> > +++ b/arch/arm64/mm/mmu.c
> > @@ -746,8 +746,10 @@ static int
> split_kernel_leaf_mapping_locked(unsigned long addr)
> >   	if (!pmd_present(pmd))
> >   		goto out;
> >   	if (pmd_leaf(pmd)) {
> > -		if (pmd_cont(pmd))
> > +		if (pmd_cont(pmd)) {
> >   			split_contpmd(pmdp);
> > +			pmd = pmdp_get(pmdp);
> > +		}
> >   		/*
> >   		 * PMD: If addr is PMD aligned then addr already describes a
> >   		 * leaf boundary. Otherwise, split to contpte.
> > @@ -891,8 +893,10 @@ static int split_to_ptes_pmd_entry(pmd_t *pmdp,
> unsigned long addr,
> >   	int ret = 0;
> >
> >   	if (pmd_leaf(pmd)) {
> > -		if (pmd_cont(pmd))
> > +		if (pmd_cont(pmd)) {
> >   			split_contpmd(pmdp);
> > +			pmd = pmdp_get(pmdp);
> > +		}
> >   		ret = split_pmd(pmdp, pmd, gfp, false);
> >
> >   		/*


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-06-27  2:47 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-25 11:39 [PATCH] arm64: mm: refresh stale pmd snapshot after split_contpmd() lirongqing
2026-06-26 13:03 ` Dev Jain
2026-06-26 16:03   ` David Hildenbrand (Arm)
2026-06-26 22:53 ` Yang Shi
2026-06-27  2:46   ` 答复: [外部邮件] " Li,Rongqing

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox