* Re: [PATCH] arm64: hugetlb: fix BBM for mprotect() on contiguous PTEs
2026-09-02 14:46 ` Dev Jain
@ 2026-09-02 16:16 ` Ryan Roberts
2026-09-02 17:06 ` Karl Mehltretter
2026-09-03 10:45 ` Will Deacon
2 siblings, 0 replies; 9+ messages in thread
From: Ryan Roberts @ 2026-09-02 16:16 UTC (permalink / raw)
To: Dev Jain, Karl Mehltretter, Catalin Marinas, Will Deacon,
linux-arm-kernel
Cc: Anshuman Khandual, Mark Rutland, Andrew Morton, Muchun Song,
Oscar Salvador, David Hildenbrand, linux-mm, linux-kernel
On 02/09/2026 15:46, Dev Jain wrote:
>
>
> On 01/09/26 6:48 pm, Karl Mehltretter wrote:
>> huge_ptep_modify_prot_start() clears a hugetlb entry before changing its
>> permissions. For contiguous PTE mappings, break-before-make (BBM)
>> requires a TLB invalidation after clearing the set and before making any
>> entry valid again.
>>
>> Commit fb396bb459c1 ("arm64/hugetlb: Drop TLB flush from
>> get_clear_flush()") removed this invalidation, relying on the deferred
>> flush from the core code. Commit 410982303772 ("arm64: hugetlb: Restore
>> TLB invalidation for BBM on contiguous ptes") restored it for
>> huge_ptep_set_{access_flags,wrprotect}(), since a deferred flush is too
>> late for the break step. The modify-prot path has the same problem.
>>
>> Use huge_ptep_clear_flush() for contiguous entries so that the TLB is
>> invalidated during the break step. Leave huge_ptep_get_and_clear()
>> unchanged because it is also used by teardown paths, where the deferred
>> flush is sufficient.
>>
>> Fixes: fb396bb459c1 ("arm64/hugetlb: Drop TLB flush from get_clear_flush()")
>> Assisted-by: LLM
>> Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
>> ---
Is there a user-visible bug here? Or is this just AI-assisted hypothesising?
>
> The transition happening here is:
>
> old_prot+cont -> zero -> new_prot+cont ... (i)
> and then TLB flush.
>
> Arm Arm rule R_JQQTC says:
> "For a TLB lookup in a contiguous region mapped by translation table entries
> that have consistent values for the Contiguous bit, but have the OA, attributes,
> or permissions misprogrammed, that TLB lookup is permitted to produce an OA,
> access permissions, and memory attributes that are consistent with any one
> of the programmed translation table values."
>
> This implies that a live update like
> old_prot+cont -> new_prot+cont then TLB flush ... (ii)
>
> is safe. Which should also imply that the transition (i) is safe,
> since the configurations the PE can observe for (ii) is the same
> for (i), except that in (ii) the PE can fault too, which is fine.
>
> Upon discussing with Ryan I got to know, he was implementing the
> contpte stuff for non-hugetlb user mappings and that basically
> drove a clarification on the semantics of contiguous bit and
> this rule was added.
>
> If you see currently for non-hugetlb mprotect() we do not flush
> during contpte teardown.
>
> So if the above reasoning makes sense, I can infact audit and
> remove the flushes in the hugetlb helpers.
I agree with this analysis. I believe it is safe to elide the intermediate flush
in this case (as is done in contpte_wrprotect_ptes()). And I agree that we can
likely remove some existing TLB maintenance in hugetlb helpers.
Thanks,
Ryan
>
>> An instrumented QEMU detected the missing break-step TLBI on an unpatched
>> kernel and none with this change. A fork() control exercising
>> huge_ptep_set_wrprotect() remained clean. No user-visible failure was
>> reproduced.
>>
>> The QEMU checker was exercised with 4K and 64K base-page kernels. The
>> patched kernel passed the LTP hugetlb tests with both -cpu max and -cpu
>> cortex-a72 (16 TPASS and no failures).
>>
>> Testing on Neoverse N1 hardware would be welcome, as it can use the
>> contiguous hint and can be configured to report TLB conflicts.
>>
>> arch/arm64/mm/hugetlbpage.c | 7 ++++++-
>> 1 file changed, 6 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
>> index 8e799c1fe0aa..bb53a04b73b2 100644
>> --- a/arch/arm64/mm/hugetlbpage.c
>> +++ b/arch/arm64/mm/hugetlbpage.c
>> @@ -517,6 +517,11 @@ bool __init arch_hugetlb_valid_size(unsigned long size)
>> pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
>> {
>> unsigned long psize = huge_page_size(hstate_vma(vma));
>> + pte_t pte = __ptep_get(ptep);
>> +
>> + /* The break step for contiguous PTEs must include the TLB flush. */
>> + if (pte_cont(pte))
>> + return huge_ptep_clear_flush(vma, addr, ptep);
>>
>> if (alternative_has_cap_unlikely(ARM64_WORKAROUND_2645198)) {
>> /*
>> @@ -524,7 +529,7 @@ pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr
>> * when the permission changes from executable to non-executable
>> * in cases where cpu is affected with errata #2645198.
>> */
>> - if (pte_user_exec(__ptep_get(ptep)))
>> + if (pte_user_exec(pte))
>> return huge_ptep_clear_flush(vma, addr, ptep);
>> }
>> return huge_ptep_get_and_clear(vma->vm_mm, addr, ptep, psize);
>>
>> base-commit: 786262be6048deab760f68c8acc2c85607165894
>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] arm64: hugetlb: fix BBM for mprotect() on contiguous PTEs
2026-09-02 14:46 ` Dev Jain
2026-09-02 16:16 ` Ryan Roberts
@ 2026-09-02 17:06 ` Karl Mehltretter
2026-09-03 10:45 ` Will Deacon
2 siblings, 0 replies; 9+ messages in thread
From: Karl Mehltretter @ 2026-09-02 17:06 UTC (permalink / raw)
To: Dev Jain
Cc: Catalin Marinas, Will Deacon, linux-arm-kernel, Anshuman Khandual,
Ryan Roberts, Mark Rutland, Andrew Morton, Muchun Song,
Oscar Salvador, David Hildenbrand, linux-mm, linux-kernel
On Wed, Sep 02, 2026 at 08:16:36PM +0100, Dev Jain wrote:
> Upon discussing with Ryan I got to know, he was implementing the
> contpte stuff for non-hugetlb user mappings and that basically
> drove a clarification on the semantics of contiguous bit and
> this rule was added.
>
> If you see currently for non-hugetlb mprotect() we do not flush
> during contpte teardown.
>
> So if the above reasoning makes sense, I can infact audit and
> remove the flushes in the hugetlb helpers.
>
Well, that's quite a turn of events! I wasn't aware of R_JQQTC or the
architectural clarification behind contpte_wrprotect_ptes().
My QEMU checker was based on the older assumption in commit
410982303772 and the existing hugetlb comments, so it treated a
clear and remake without an intermediate TLBI as a violation.
So... Please consider this patch withdrawn.
It's good that this may have uncovered an opportunity to remove
the flushes in the hugetlb helpers.
Thanks,
Karl
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] arm64: hugetlb: fix BBM for mprotect() on contiguous PTEs
2026-09-02 14:46 ` Dev Jain
2026-09-02 16:16 ` Ryan Roberts
2026-09-02 17:06 ` Karl Mehltretter
@ 2026-09-03 10:45 ` Will Deacon
2026-09-04 10:56 ` Ryan Roberts
2 siblings, 1 reply; 9+ messages in thread
From: Will Deacon @ 2026-09-03 10:45 UTC (permalink / raw)
To: Dev Jain
Cc: Karl Mehltretter, Catalin Marinas, linux-arm-kernel,
Anshuman Khandual, Ryan Roberts, Mark Rutland, Andrew Morton,
Muchun Song, Oscar Salvador, David Hildenbrand, linux-mm,
linux-kernel
On Wed, Sep 02, 2026 at 08:16:36PM +0530, Dev Jain wrote:
>
>
> On 01/09/26 6:48 pm, Karl Mehltretter wrote:
> > huge_ptep_modify_prot_start() clears a hugetlb entry before changing its
> > permissions. For contiguous PTE mappings, break-before-make (BBM)
> > requires a TLB invalidation after clearing the set and before making any
> > entry valid again.
> >
> > Commit fb396bb459c1 ("arm64/hugetlb: Drop TLB flush from
> > get_clear_flush()") removed this invalidation, relying on the deferred
> > flush from the core code. Commit 410982303772 ("arm64: hugetlb: Restore
> > TLB invalidation for BBM on contiguous ptes") restored it for
> > huge_ptep_set_{access_flags,wrprotect}(), since a deferred flush is too
> > late for the break step. The modify-prot path has the same problem.
> >
> > Use huge_ptep_clear_flush() for contiguous entries so that the TLB is
> > invalidated during the break step. Leave huge_ptep_get_and_clear()
> > unchanged because it is also used by teardown paths, where the deferred
> > flush is sufficient.
> >
> > Fixes: fb396bb459c1 ("arm64/hugetlb: Drop TLB flush from get_clear_flush()")
> > Assisted-by: LLM
> > Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
> > ---
>
> The transition happening here is:
>
> old_prot+cont -> zero -> new_prot+cont ... (i)
> and then TLB flush.
>
> Arm Arm rule R_JQQTC says:
> "For a TLB lookup in a contiguous region mapped by translation table entries
> that have consistent values for the Contiguous bit, but have the OA, attributes,
> or permissions misprogrammed, that TLB lookup is permitted to produce an OA,
> access permissions, and memory attributes that are consistent with any one
> of the programmed translation table values."
>
> This implies that a live update like
> old_prot+cont -> new_prot+cont then TLB flush ... (ii)
>
> is safe. Which should also imply that the transition (i) is safe,
> since the configurations the PE can observe for (ii) is the same
> for (i), except that in (ii) the PE can fault too, which is fine.
I'm not sure I agree. As written, the text above says that if the
permissions are misprogrammed (which they are in this case) then the TLB
can produce an OA consistent with any of the entries. Hopefully it just
needs some further clarification.
There are probably also cases where we're changing the attributes and the
permissions at the same time, so it's not clear to me that it's safe to
allow those to be inconsistent (e.g. tagged/guarded vs read/write). If
I was going from untagged read/write -> tagged read-only then I presumably
wouldn't expect to see a tag check fault on a write?
Will
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] arm64: hugetlb: fix BBM for mprotect() on contiguous PTEs
2026-09-03 10:45 ` Will Deacon
@ 2026-09-04 10:56 ` Ryan Roberts
2026-10-30 14:33 ` Will Deacon
0 siblings, 1 reply; 9+ messages in thread
From: Ryan Roberts @ 2026-09-04 10:56 UTC (permalink / raw)
To: Will Deacon, Dev Jain
Cc: Karl Mehltretter, Catalin Marinas, linux-arm-kernel,
Anshuman Khandual, Mark Rutland, Andrew Morton, Muchun Song,
Oscar Salvador, David Hildenbrand, linux-mm, linux-kernel
On 03/09/2026 11:45, Will Deacon wrote:
> On Wed, Sep 02, 2026 at 08:16:36PM +0530, Dev Jain wrote:
>>
>>
>> On 01/09/26 6:48 pm, Karl Mehltretter wrote:
>>> huge_ptep_modify_prot_start() clears a hugetlb entry before changing its
>>> permissions. For contiguous PTE mappings, break-before-make (BBM)
>>> requires a TLB invalidation after clearing the set and before making any
>>> entry valid again.
>>>
>>> Commit fb396bb459c1 ("arm64/hugetlb: Drop TLB flush from
>>> get_clear_flush()") removed this invalidation, relying on the deferred
>>> flush from the core code. Commit 410982303772 ("arm64: hugetlb: Restore
>>> TLB invalidation for BBM on contiguous ptes") restored it for
>>> huge_ptep_set_{access_flags,wrprotect}(), since a deferred flush is too
>>> late for the break step. The modify-prot path has the same problem.
>>>
>>> Use huge_ptep_clear_flush() for contiguous entries so that the TLB is
>>> invalidated during the break step. Leave huge_ptep_get_and_clear()
>>> unchanged because it is also used by teardown paths, where the deferred
>>> flush is sufficient.
>>>
>>> Fixes: fb396bb459c1 ("arm64/hugetlb: Drop TLB flush from get_clear_flush()")
>>> Assisted-by: LLM
>>> Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
>>> ---
>>
>> The transition happening here is:
>>
>> old_prot+cont -> zero -> new_prot+cont ... (i)
>> and then TLB flush.
>>
>> Arm Arm rule R_JQQTC says:
>> "For a TLB lookup in a contiguous region mapped by translation table entries
>> that have consistent values for the Contiguous bit, but have the OA, attributes,
>> or permissions misprogrammed, that TLB lookup is permitted to produce an OA,
>> access permissions, and memory attributes that are consistent with any one
>> of the programmed translation table values."
>>
>> This implies that a live update like
>> old_prot+cont -> new_prot+cont then TLB flush ... (ii)
>>
>> is safe. Which should also imply that the transition (i) is safe,
>> since the configurations the PE can observe for (ii) is the same
>> for (i), except that in (ii) the PE can fault too, which is fine.
>
> I'm not sure I agree. As written, the text above says that if the
> permissions are misprogrammed (which they are in this case) then the TLB
> can produce an OA consistent with any of the entries. Hopefully it just
> needs some further clarification.
I'm not sure I understand your concern here. Is your concern that the OA could
be pulled from one of the invalid entries? The intent is that any entry that
does not have the VALID bit set is not considered an "entry" within the
"contiguous range" for the purposes of this. (because it is invalid).
That's implied (if you squint) from:
IPGVGZ: The Contiguous bit is present only in valid Block and Page translation
table descriptors, and therefore neither of the following configurations are
considered as misprogramming of the Contiguous bit:
- A contiguous range of descriptors that are each either invalid, or valid
with Contiguous set to 1.
- A contiguous range of descriptors that are each either invalid, or valid
with Contiguous set to 0.
In general I am of the opinion that the rules around contiguous mappings are not
as clear as they could be and the VMSA architect has indicated that he hopes to
clean them up over time. Bit I don't quite see your concern in this case.
>
> There are probably also cases where we're changing the attributes and the
> permissions at the same time, so it's not clear to me that it's safe to
> allow those to be inconsistent (e.g. tagged/guarded vs read/write). If
> I was going from untagged read/write -> tagged read-only then I presumably
> wouldn't expect to see a tag check fault on a write?
Again, I'm not sure I follow, but I'll take a stab. I think you're implying that
a write permission fault should take precedence over a tag check fault? (I have
no idea off the top of my head). And you're further implying that with this
transition the HW might see an intermediate "tagged read/write" entry, and if it
does then it will raise a tag check fault, not a write fault for an attempted
write. But I don't see how R_JQQTC permits that because it says "consistent with
any one of the programmed translation table values" so the HW can't pick
attributes from one entry and permissions from another. It will either see the
old "untagged read/write" or the new "tagged read-only".
Sorry if I've missed the point!!
Thanks,
Ryan
>
> Will
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] arm64: hugetlb: fix BBM for mprotect() on contiguous PTEs
2026-09-04 10:56 ` Ryan Roberts
@ 2026-10-30 14:33 ` Will Deacon
0 siblings, 0 replies; 9+ messages in thread
From: Will Deacon @ 2026-10-30 14:33 UTC (permalink / raw)
To: Ryan Roberts
Cc: Dev Jain, Karl Mehltretter, Catalin Marinas, linux-arm-kernel,
Anshuman Khandual, Mark Rutland, Andrew Morton, Muchun Song,
Oscar Salvador, David Hildenbrand, linux-mm, linux-kernel
Hi Ryan,
Sorry for the slow reply here.
On Fri, Sep 04, 2026 at 11:56:25AM +0100, Ryan Roberts wrote:
> On 03/09/2026 11:45, Will Deacon wrote:
> > On Wed, Sep 02, 2026 at 08:16:36PM +0530, Dev Jain wrote:
> >> The transition happening here is:
> >>
> >> old_prot+cont -> zero -> new_prot+cont ... (i)
> >> and then TLB flush.
> >>
> >> Arm Arm rule R_JQQTC says:
> >> "For a TLB lookup in a contiguous region mapped by translation table entries
> >> that have consistent values for the Contiguous bit, but have the OA, attributes,
> >> or permissions misprogrammed, that TLB lookup is permitted to produce an OA,
> >> access permissions, and memory attributes that are consistent with any one
> >> of the programmed translation table values."
> >>
> >> This implies that a live update like
> >> old_prot+cont -> new_prot+cont then TLB flush ... (ii)
> >>
> >> is safe. Which should also imply that the transition (i) is safe,
> >> since the configurations the PE can observe for (ii) is the same
> >> for (i), except that in (ii) the PE can fault too, which is fine.
> >
> > I'm not sure I agree. As written, the text above says that if the
> > permissions are misprogrammed (which they are in this case) then the TLB
> > can produce an OA consistent with any of the entries. Hopefully it just
> > needs some further clarification.
>
> I'm not sure I understand your concern here. Is your concern that the OA could
> be pulled from one of the invalid entries? The intent is that any entry that
> does not have the VALID bit set is not considered an "entry" within the
> "contiguous range" for the purposes of this. (because it is invalid).
Not invalid, no, but from the old_prot+cont. There hasn't been an
invalidation, so that could still be reachable.
> That's implied (if you squint) from:
>
> IPGVGZ: The Contiguous bit is present only in valid Block and Page translation
> table descriptors, and therefore neither of the following configurations are
> considered as misprogramming of the Contiguous bit:
> - A contiguous range of descriptors that are each either invalid, or valid
> with Contiguous set to 1.
> - A contiguous range of descriptors that are each either invalid, or valid
> with Contiguous set to 0.
>
> In general I am of the opinion that the rules around contiguous mappings are not
> as clear as they could be and the VMSA architect has indicated that he hopes to
> clean them up over time. Bit I don't quite see your concern in this case.
I'm happy to review any proposed cleanups to the wording, fwiw.
> > There are probably also cases where we're changing the attributes and the
> > permissions at the same time, so it's not clear to me that it's safe to
> > allow those to be inconsistent (e.g. tagged/guarded vs read/write). If
> > I was going from untagged read/write -> tagged read-only then I presumably
> > wouldn't expect to see a tag check fault on a write?
>
> Again, I'm not sure I follow, but I'll take a stab. I think you're implying that
> a write permission fault should take precedence over a tag check fault? (I have
> no idea off the top of my head). And you're further implying that with this
> transition the HW might see an intermediate "tagged read/write" entry, and if it
> does then it will raise a tag check fault, not a write fault for an attempted
> write. But I don't see how R_JQQTC permits that because it says "consistent with
> any one of the programmed translation table values" so the HW can't pick
> attributes from one entry and permissions from another. It will either see the
> old "untagged read/write" or the new "tagged read-only".
ah, I think that's where we read it differently. You're interpreting "ANY
any one of the programmed translation table values" as "EXACTLY one of the
programmed translation table value"; i.e. OA, perms and attrs are read
atomically from the same pte. Maybe (hopefully!) that's the intention,
but it's not how I read it. Now that I see how you're reading it, I can
convince myself either way!
Will
^ permalink raw reply [flat|nested] 9+ messages in thread