[PATCH v2] arm64: tlbflush: Reset active_cpu on ASID rollover
Sayali Kulkarni
sk at gentwo.org
Wed Jun 24 15:13:12 PDT 2026
Thank you for catching this. After going through the patch again, I
realize that the race is real. Resetting active_cpu to ACTIVE_CPU_NONE on
rollover can leave it in an inconsistent state when stale entries still
live. Note that the rollover state entries themselves aren’t the issue.
Those are handled by the existing reserved_asids/tlb_flush_pending
mechanism. It’s specifically active_cpu’s own record going inconsistent.
For v3, I am exploring handling active_cpu together with the generation so
that the reset can’t open a NONE window. Doing it in the slow path after
local flush and updating to the current CPU rather than NONE. Does that
direction seem reasonable or is there a cleaner way to avoid the
under-claim window? Will follow up with a patch once it’s figured out.
Thanks,
Sayali
On Thu, 18 Jun 2026, Linu Cherian wrote:
> Hi,
>
> On Fri, Jun 12, 2026 at 04:21:06PM -0700, Sayali Kulkarni wrote:
>> From: Sayali Kulkarni <sskulkarni at amperecomputing.com>
>>
>> Hi Catalin,
>>
>> Thank you for the review. I’ve addressed your feedback in v2:
>>
>> - Moved `WRITE_ONCE(mm->context.active_cpu, ACTIVE_CPU_NONE)` from `check_and_switch_context()` to `new_context()` after the `set_asid` label. At this point, a brand new ASID has been allocated that no CPU has ever used, so the reset is safe even for multi-threaded processes where other CPUs may still be running with the old ASID via `reserved_asids`.
>> - Updated the commit message to correct the safety reasoning: `flush_context()` only sets `tlb_flush_pending`; it does not issue a global TLB flush.
>>
>> Thanks,
>> Sayali
>>
>>
>> Once active_cpu flips to ACTIVE_CPU_MULTIPLE it never resets, even if
>> the process settles back to one CPU. Reset it to ACTIVE_CPU_NONE in
>> new_context() after a new ASID is allocated at the set_asid label.
>>
>> At this point a brand new ASID has been assigned that no CPU has ever
>> used, so ACTIVE_CPU_NONE accurately reflects reality. Any other threads
>> of the same process continue running with the old ASID via
>> reserved_asids and are unaffected.
>>
>> This gives processes a fresh chance at the local-only flush fast path
>> after each ASID generation rollover.
>>
>> Signed-off-by: Sayali Kulkarni <sskulkarni at amperecomputing.com> (Ampere)
>> ---
>> arch/arm64/mm/context.c | 1 +
>> 1 file changed, 1 insertion(+)
>>
>> diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
>> index f34ed78393e0..46c7fd07b9bf 100644
>> --- a/arch/arm64/mm/context.c
>> +++ b/arch/arm64/mm/context.c
>> @@ -209,6 +209,7 @@ static u64 new_context(struct mm_struct *mm)
>> set_asid:
>> __set_bit(asid, asid_map);
>> cur_idx = asid;
>> + WRITE_ONCE(mm->context.active_cpu, ACTIVE_CPU_NONE);
>
> Can the above store race with the store to active_cpu in another thread,
> that updates it to ACTIVE_CPU_MULTIPLE ?
>
> Lets say we have two threads both initially running in CPU 0,
>
> Thread 1: Runs in CPU 0
>
> Encounters a rollover, updates mm->context.active_cpu to ACTIVE_CPU_NONE and
> updates mm->context.id to new asid.
>
> Thread 2: Scheduled to run on CPU 1 for the first time
>
> Observes the updated mm->context.id that belongs to the current
> generation(after the rollover) and hence proceeds to switch_mm_fastpath
> and ends up updating the active_cpu to ACTIVE_CPU_MULTIPLE.
>
> If Thread 1 and Thread 2 races, then active_cpu can get corrupted ?
>
> The reason this could be possible is that, write to active_cpu and
> mm->context.id can get reordered and we need to enforce ordering for
> correctness ?
>
> Do you see this as a valid scenario ?
>
> --
> Thanks,
> Linu Cherian.
>
>
>
>
>
>
>
>
>
>
More information about the linux-arm-kernel
mailing list