* [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback
@ 2026-10-09 21:03 Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 1/8] alpha: load the MMU context when switch_mm() switches the current task Magnus Lindholm
` (8 more replies)
0 siblings, 9 replies; 14+ messages in thread
From: Magnus Lindholm @ 2026-10-09 21:03 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
On Alpha, stale TLB translations can break copy-on-write and shared-mapping
writeback: a multi-threaded process can lose its own stores, read data
belonging to its child, or lose writes through a shared file mapping. The
copy-on-write failures need more than one CPU; the writeback failure also
happens on a uniprocessor.
This is the first of two series, based on for-next at 33465f6ab697
("alpha: support the remaining kernel compression formats"). Apply all
eight patches here, then the two patches in "alpha: complete the direct-mm
shootdown fixes" v3. There is no interleaving or external prerequisite for
this first series.
Patch 1 moves here from v2 of the direct-switch series:
https://lore.kernel.org/linux-alpha/20261008195608.965266-2-linmag7@gmail.com/
It loads the context when switch_mm() is called directly for current,
before kthread_use_mm() can reach the hook added by patch 2. This closes
the dependency that previously required applying one patch from the other
series first. Its code and Matt's review and test tags are unchanged.
Patch 2 completes the deferred-ASN handshake from
finish_arch_post_lock_switch(), including the first switch to a newly
created task. Its old location after alpha_switch_to() was bypassed when
a new task reached schedule_tail(), leaving asn_lock set.
The hook runs after interrupts are enabled. Set need_new_asn whether
switch_mm() reused or allocated an ASN, so a deferred IPI cannot leave
a live hardware context with a zero slot. This is also required before
the second series uses those slots to decide whether to skip shootdowns.
Drop the preemptible() guard: Alpha has no kernel preemption and the
direct-switch callers do not sleep before the hook, including when
RCU_STRICT_GRACE_PERIOD enables PREEMPT_COUNT.
Patches 3, 5 and 6 test current->mm before issuing targeted tbi(), since
a lazy active_mm does not establish which ASN is actually loaded. Patches
4, 7 and 8 retire the calling CPU's context when the local current-context
test fails; smp_call_function() only visits the other CPUs.
Patch 4 deliberately precedes patch 5. The missing else branch must be
present before lazy callers are routed to it, so no intermediate commit
loses their local invalidate. This matters on EV7 where a foreign-context
tbi() appeared to work. The full-mm and icache callers retain their
active_mm tests because those paths load a new context instead of using
a targeted tbi(). The second series separately changes their IPI handlers
to retire slots on lazy CPUs rather than keeping those slots visible.
Testing
Cross-build validation for this revision covers arch/alpha/kernel/,
arch/alpha/mm/, kernel/sched/core.o and kernel/kthread.o with GCC 15.0.1:
ALPHA_GENERIC SMP and UP with COMPACTION=n, and SMP with COMPACTION=y,
RCU_STRICT_GRACE_PERIOD=y, PREEMPT_COUNT=y and NR_CPUS=4. These are compile
checks; all three passed. All ten patches pass checkpatch without warnings,
and sequential application reproduces the committed trees at both series
boundaries. No new boot or hardware runtime results are claimed.
Historical results from the earlier stale-TLB series, on an ES40,
EV68AL (21264C) Tsunami with three CPUs, v7.2-rc2 and v7.2-rc6:
before after
smoke test, stale-read check 7 of 9 rounds 0 of 9
lost stores 11 of 40 0 of 400
writeback (mkclean4), SMP [*] 10 of 10 0 of 10
writeback (mkclean4), UP [*] every round 0 of 8
tst-malloc-fork-deadlock-
malloc-check 8 of 10 fail 25/25 pass
[*] CONFIG_COMPACTION=n.
alpha-cow-smoketest.c uses pthreads and forked children. Each thread owns
its slot, and the main thread reads only after joining. Slots are 128
bytes apart so threads share a page; writing once and reading repeatedly
avoids hiding stale translations with another faulting write. It does
not fail when restricted to one CPU.
mkclean4.c exercises patches 4 and 5 together on SMP, and patch 6 on UP.
It compares a small MAP_SHARED mapping with its backing file after
background writeback, with the writer and flusher pinned to the same CPU
on SMP. It needs root and COMPACTION=n. With COMPACTION=y, Alpha overrides
ptep_clear_flush() to use migrate_flush_tlb_page(), so folio_mkclean() does
not exercise flush_tlb_page(). Earlier unpatched COMPACTION=y runs passed
103 rounds; separate regression runs under continuous compaction migrated
368522 folios without failures.
Matt's earlier ES47 (EV7) testing on v7.3-rc1 with one CPU online found no
regressions in fork/COW, writeback and gdb breakpoint tests on SMP and UP
builds. He could not reproduce the unpatched writeback failure despite
counters showing foreign-context targeted invalidates. The fix rests on
the tbi() contract, not on every implementation exhibiting the failure.
Patches 7 and 8 still have no isolated reproducer. A gdb breakpoint
exerciser covered patch 8's path for regressions. Matt suggested
move_pages() on another process's hugetlb mapping, with the caller pinned
to the CPU the target last ran on, as a possible reproducer for patch 7.
That is unverified; the proposed hugetlb support is not in this base.
Changes since v3:
- Move patch 1 of the v2 "alpha: load the MMU context on a direct mm
switch" series here as patch 1, so the stale-TLB series can be
applied first, followed by the remaining MMU fixes.
- Drop the post-switch hook's preemptible() guard.
- Set need_new_asn on both reused and newly allocated ASN paths.
- Put the missing local flush_tlb_page() else branch before changing
the current->mm test, as requested by Matt.
- Rebase on for-next and update numbering and dependency descriptions.
- Mention the proposed hugetlb caller without claiming a new reproducer.
- Drop the old review tag from the materially changed hook patch;
retain tags on the other patches.
Thanks to Matt Turner for the review and EV7 testing.
v3: https://lore.kernel.org/linux-alpha/20260923074903.862898-1-linmag7@gmail.com/
Magnus Lindholm (8):
alpha: load the MMU context when switch_mm() switches the current task
alpha: run check_mmu_context() from finish_arch_post_lock_switch()
alpha: only use a targeted tbi() when the target mm is really current
alpha: invalidate the local context in flush_tlb_page()
alpha: fix the local TLB invalidate in flush_tlb_page()
alpha: fix the local TLB invalidate in the UP flush_tlb_page()
alpha: invalidate the local context in flush_tlb_mm()
alpha: invalidate the local context in flush_icache_user_page()
arch/alpha/include/asm/mmu_context.h | 23 ++++++++++++++++++++---
arch/alpha/include/asm/switch_to.h | 1 -
arch/alpha/include/asm/tlbflush.h | 3 ++-
arch/alpha/kernel/smp.c | 15 +++++++++++++--
4 files changed, 35 insertions(+), 7 deletions(-)
base-commit: 33465f6ab697abceafd9a340067a544d551c4412
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v4 1/8] alpha: load the MMU context when switch_mm() switches the current task
2026-10-09 21:03 [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Magnus Lindholm
@ 2026-10-09 21:03 ` Magnus Lindholm
2026-10-10 1:42 ` Matt Turner
2026-10-09 21:03 ` [PATCH v4 2/8] alpha: run check_mmu_context() from finish_arch_post_lock_switch() Magnus Lindholm
` (7 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Magnus Lindholm @ 2026-10-09 21:03 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7, stable
ev5_switch_mm() only prepares the incoming PCB. The context is installed
by PAL_swpctx, which alpha_switch_to() issues against that PCB on the way
out of the scheduler.
Two callers reach switch_mm_irqs_off() without going through
alpha_switch_to(): kthread_use_mm(), which borrows an mm for the current
kernel thread, and sched_force_init_mm() on the CPU-hotplug teardown path.
Neither explicitly loads the context, so the task can carry on running
under whatever was loaded before while current->mm says otherwise.
The stale page-table root need not be swapper_pg_dir; it may belong to a
user process that ran on the CPU earlier, and the kthread's user accesses
can then read and write that process's memory wherever the stale mappings
allow. Translations taken that way can also end up tagged with the
borrowed mm's ASN: ev5_switch_mm() writes that ASN into the PCB, which the
next PAL_swpctx installs against the stale ptbr. An address the stale
tables do not map faults instead, and since do_page_fault() resolves
faults against current->mm without reloading the context, the same access
can fault again on return.
sched_force_init_mm() needs CONFIG_HOTPLUG_CPU, which alpha does not
support, so kthread_use_mm() is the only one of the two reachable in
practice; the fix below tests the caller's identity rather than
special-casing either one.
The scheduler passes the incoming task, which is not current until
alpha_switch_to() runs; both direct callers pass current. Test for that
and load the context the way activate_mm() does. Both hold interrupts
disabled across switch_mm_irqs_off(), so this completes before any
shootdown can be taken and needs no asn_lock handshake.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: <stable@vger.kernel.org>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Tested-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Message-ID: <20261008195608.965266-2-linmag7@gmail.com>
---
arch/alpha/include/asm/mmu_context.h | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/include/asm/mmu_context.h b/arch/alpha/include/asm/mmu_context.h
index eee8fe836a59..c5cf7dbe6161 100644
--- a/arch/alpha/include/asm/mmu_context.h
+++ b/arch/alpha/include/asm/mmu_context.h
@@ -130,6 +130,8 @@ __get_new_mm_context(struct mm_struct *mm, long cpu)
return next;
}
+extern void __load_new_mm_context(struct mm_struct *);
+
__EXTERN_INLINE void
ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
struct task_struct *next)
@@ -139,6 +141,15 @@ ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
unsigned long mmc;
long cpu = smp_processor_id();
+ /*
+ * kthread_use_mm() and sched_force_init_mm() switch current's mm
+ * without alpha_switch_to(), which is what loads the context.
+ */
+ if (next == current) {
+ __load_new_mm_context(next_mm);
+ return;
+ }
+
#ifdef CONFIG_SMP
cpu_data[cpu].asn_lock = 1;
barrier();
@@ -160,7 +171,6 @@ ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
task_thread_info(next)->pcb.asn = mmc & HARDWARE_ASN_MASK;
}
-extern void __load_new_mm_context(struct mm_struct *);
asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr,
long cause, struct pt_regs *regs);
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v4 2/8] alpha: run check_mmu_context() from finish_arch_post_lock_switch()
2026-10-09 21:03 [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 1/8] alpha: load the MMU context when switch_mm() switches the current task Magnus Lindholm
@ 2026-10-09 21:03 ` Magnus Lindholm
2026-10-10 1:42 ` Matt Turner
2026-10-09 21:03 ` [PATCH v4 3/8] alpha: only use a targeted tbi() when the target mm is really current Magnus Lindholm
` (6 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Magnus Lindholm @ 2026-10-09 21:03 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7, stable
check_mmu_context() clears asn_lock and acts on need_new_asn, but it
runs only as the tail of switch_to(), after alpha_switch_to() returns.
A newly forked task never gets there: its first context switch resumes
at ret_from_fork and reaches schedule_tail() without returning to the
code following alpha_switch_to(). New kernel threads take the same
path through schedule_tail().
asn_lock is left set on that CPU, so the new task can run with
interrupts enabled while shootdown IPIs keep taking the deferred path.
The handshake meant to complete those invalidations never runs.
Move check_mmu_context() to finish_arch_post_lock_switch(), which is
called by finish_task_switch() for both existing and newly created tasks.
Drop the now redundant call from switch_to().
The hook runs after finish_lock_switch() releases the rq lock and enables
interrupts. An IPI arriving before asn_lock is cleared retires the slot
through flush_tlb_other(); an IPI arriving afterwards can flush directly,
since PAL_swpctx has already installed the incoming context.
Set need_new_asn whether ev5_switch_mm() reuses or allocates an ASN. An
IPI in that interval can zero either slot. Without this, the allocated
case can return to user space with a live ASN but a zero context slot,
which a later context-based shootdown shortcut could mistake for an
inactive CPU. check_mmu_context() reloads only when the slot is zero.
Call the hook unconditionally. Alpha selects ARCH_NO_PREEMPT, and neither
kthread_use_mm() nor sched_force_init_mm() sleeps between the direct
switch and this hook. RCU_STRICT_GRACE_PERIOD can enable PREEMPT_COUNT,
but cannot make those callers migrate there. Testing preemptible() would
only leave asn_lock set in that configuration.
This requires the preceding direct-switch fix, "alpha: load the MMU
context when switch_mm() switches the current task". It installs the
borrowed context before kthread_use_mm() reaches this hook, so clearing
asn_lock cannot expose a targeted invalidate against the wrong context.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/mmu_context.h | 11 +++++++++--
arch/alpha/include/asm/switch_to.h | 1 -
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/arch/alpha/include/asm/mmu_context.h b/arch/alpha/include/asm/mmu_context.h
index c5cf7dbe6161..e5a5737506db 100644
--- a/arch/alpha/include/asm/mmu_context.h
+++ b/arch/alpha/include/asm/mmu_context.h
@@ -161,8 +161,8 @@ ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
next_mm->context[cpu] = mmc;
}
#ifdef CONFIG_SMP
- else
- cpu_data[cpu].need_new_asn = 1;
+ /* A deferred shootdown can also invalidate a newly allocated ASN. */
+ cpu_data[cpu].need_new_asn = 1;
#endif
/* Always update the PCB ASN. Another thread may have allocated
@@ -191,6 +191,13 @@ do { \
#define check_mmu_context() do { } while(0)
#endif
+/* Alpha has no kernel preemption; these callers cannot migrate here. */
+#define finish_arch_post_lock_switch finish_arch_post_lock_switch
+static inline void finish_arch_post_lock_switch(void)
+{
+ check_mmu_context();
+}
+
__EXTERN_INLINE void
ev5_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm)
{
diff --git a/arch/alpha/include/asm/switch_to.h b/arch/alpha/include/asm/switch_to.h
index 762b7f975310..35c4b2c9d992 100644
--- a/arch/alpha/include/asm/switch_to.h
+++ b/arch/alpha/include/asm/switch_to.h
@@ -9,7 +9,6 @@ extern struct task_struct *alpha_switch_to(unsigned long, struct task_struct *);
#define switch_to(P,N,L) \
do { \
(L) = alpha_switch_to(virt_to_phys(&task_thread_info(N)->pcb), (P)); \
- check_mmu_context(); \
} while (0)
#endif /* __ALPHA_SWITCH_TO_H */
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v4 3/8] alpha: only use a targeted tbi() when the target mm is really current
2026-10-09 21:03 [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 1/8] alpha: load the MMU context when switch_mm() switches the current task Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 2/8] alpha: run check_mmu_context() from finish_arch_post_lock_switch() Magnus Lindholm
@ 2026-10-09 21:03 ` Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 4/8] alpha: invalidate the local context in flush_tlb_page() Magnus Lindholm
` (5 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Magnus Lindholm @ 2026-10-09 21:03 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7, stable
ipi_flush_tlb_page() gates a targeted tbi() on current->active_mm.
tbi() acts on the address space context currently loaded on the CPU, so
it is only guaranteed to reach an mm's translations when a thread of
that mm is running there. current->active_mm is not sufficient: under
lazy TLB an idle or kernel task keeps an mm as its active_mm while a
different ASN is loaded, so the invalidate is issued against the wrong
context and the stale entry can survive. Nothing retires the old ASN
afterwards either, mm->context[cpu] still being valid, so the resuming
thread can reuse it.
Test current->mm instead and otherwise fall back to flush_tlb_other(),
which clears mm->context[cpu] and forces a fresh ASN at the next switch
whatever is loaded now.
For an mm borrowed through kthread_use_mm(), the prerequisite direct-switch
fix installs the context before the task can take a shootdown IPI. The
current->mm test therefore covers that case as well.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reviewed-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Message-ID: <20260923074903.862898-3-linmag7@gmail.com>
---
arch/alpha/kernel/smp.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index ed06367ece57..1ad448105201 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -669,7 +669,8 @@ ipi_flush_tlb_page(void *x)
struct flush_tlb_page_struct *data = x;
struct mm_struct * mm = data->mm;
- if (mm == current->active_mm && !asn_locked())
+ /* A targeted tbi() needs a thread of MM to be current. */
+ if (mm == current->mm && !asn_locked())
flush_tlb_current_page(mm, data->vma, data->addr);
else
flush_tlb_other(mm);
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v4 4/8] alpha: invalidate the local context in flush_tlb_page()
2026-10-09 21:03 [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Magnus Lindholm
` (2 preceding siblings ...)
2026-10-09 21:03 ` [PATCH v4 3/8] alpha: only use a targeted tbi() when the target mm is really current Magnus Lindholm
@ 2026-10-09 21:03 ` Magnus Lindholm
2026-10-10 1:44 ` Matt Turner
2026-10-09 21:03 ` [PATCH v4 5/8] alpha: fix the local TLB invalidate " Magnus Lindholm
` (4 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Magnus Lindholm @ 2026-10-09 21:03 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7, stable
When the target mm is not the calling CPU's active_mm, flush_tlb_page()
does nothing locally, and smp_call_function() reaches only the other CPUs.
This CPU may still
hold translations for the mm and can later reuse the old ASN together with
them.
Add the missing else branch. flush_tlb_other() clears mm->context[cpu] so
a fresh ASN is taken at the next switch. Add this before changing the
current->active_mm test to current->mm: that change will also send lazy
callers here, so their local invalidate must already be in place.
The uniprocessor implementations of flush_tlb_mm() and
flush_icache_user_page() in asm/tlbflush.h and asm/cacheflush.h already
contain exactly this branch.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reviewed-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Message-ID: <20260923074903.862898-5-linmag7@gmail.com>
---
arch/alpha/kernel/smp.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 1ad448105201..e4ba0aab8a66 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -697,6 +697,9 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
preempt_enable();
return;
}
+ } else {
+ /* smp_call_function() does not call back into this CPU. */
+ flush_tlb_other(mm);
}
data.vma = vma;
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v4 5/8] alpha: fix the local TLB invalidate in flush_tlb_page()
2026-10-09 21:03 [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Magnus Lindholm
` (3 preceding siblings ...)
2026-10-09 21:03 ` [PATCH v4 4/8] alpha: invalidate the local context in flush_tlb_page() Magnus Lindholm
@ 2026-10-09 21:03 ` Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 6/8] alpha: fix the local TLB invalidate in the UP flush_tlb_page() Magnus Lindholm
` (3 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Magnus Lindholm @ 2026-10-09 21:03 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7, stable
flush_tlb_page() invalidates the calling CPU itself before asking the
others, and gates that on current->active_mm. For a non-executable vma
that means a targeted tbi(2, addr), which acts on the context currently
loaded and is only guaranteed to invalidate the intended translations
when the target mm's context is the loaded one. A lazy active_mm does
not establish that, so as in ipi_flush_tlb_page() the target mm's stale
translations can survive, and nothing forces the old ASN to be retired
afterwards.
Test current->mm instead. A lazy caller then takes the flush_tlb_other()
branch added by the previous patch, retiring its local context. Adding
that branch first preserves the local invalidate at every step, including
on EV7 where a targeted tbi() against a foreign ASN appeared to work.
Which callers reach here with a foreign mm depends on the configuration.
folio_mkclean(), from the writeback flusher kworker that has no mm of its
own, accounted for about half the calls during writeback of a shared
mapping and none at all on anonymous memory. Those counts were measured
with CONFIG_COMPACTION=n: with COMPACTION=y, asm/pgtable.h overrides
ptep_clear_flush() to call migrate_flush_tlb_page(), which rendezvouses
with every CPU and handles the context itself, so folio_mkclean() does
not reach this function.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reviewed-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Message-ID: <20260923074903.862898-4-linmag7@gmail.com>
---
arch/alpha/kernel/smp.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index e4ba0aab8a66..a5a42ae4a7d8 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -684,7 +684,8 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
preempt_disable();
- if (mm == current->active_mm) {
+ /* As in ipi_flush_tlb_page(): a targeted tbi() needs MM current. */
+ if (mm == current->mm) {
flush_tlb_current_page(mm, vma, addr);
if (atomic_read(&mm->mm_users) <= 1) {
int cpu, this_cpu = smp_processor_id();
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v4 6/8] alpha: fix the local TLB invalidate in the UP flush_tlb_page()
2026-10-09 21:03 [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Magnus Lindholm
` (4 preceding siblings ...)
2026-10-09 21:03 ` [PATCH v4 5/8] alpha: fix the local TLB invalidate " Magnus Lindholm
@ 2026-10-09 21:03 ` Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 7/8] alpha: invalidate the local context in flush_tlb_mm() Magnus Lindholm
` (2 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Magnus Lindholm @ 2026-10-09 21:03 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7, stable
The uniprocessor flush_tlb_page() in asm/tlbflush.h has the same wrong
test as the SMP one: a targeted tbi() is only guaranteed to invalidate
the intended translations when the target mm's context is loaded, but
the gate is current->active_mm, which a lazily borrowed mm also
satisfies.
Test current->mm instead. The else branch it falls to already exists
here, so unlike the SMP side this is the whole fix.
arch/alpha/kernel/smp.c is not built with CONFIG_SMP=n, so this is how
the same defect reaches a uniprocessor, where the flusher kworker
necessarily shares the only CPU with the writer.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reviewed-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Message-ID: <20260923074903.862898-6-linmag7@gmail.com>
---
arch/alpha/include/asm/tlbflush.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/include/asm/tlbflush.h b/arch/alpha/include/asm/tlbflush.h
index 0c8529997f54..9ae1902faf8e 100644
--- a/arch/alpha/include/asm/tlbflush.h
+++ b/arch/alpha/include/asm/tlbflush.h
@@ -87,7 +87,8 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
{
struct mm_struct *mm = vma->vm_mm;
- if (mm == current->active_mm)
+ /* A targeted tbi() needs a thread of MM to be current. */
+ if (mm == current->mm)
flush_tlb_current_page(mm, vma, addr);
else
flush_tlb_other(mm);
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v4 7/8] alpha: invalidate the local context in flush_tlb_mm()
2026-10-09 21:03 [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Magnus Lindholm
` (5 preceding siblings ...)
2026-10-09 21:03 ` [PATCH v4 6/8] alpha: fix the local TLB invalidate in the UP flush_tlb_page() Magnus Lindholm
@ 2026-10-09 21:03 ` Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 8/8] alpha: invalidate the local context in flush_icache_user_page() Magnus Lindholm
2026-10-10 1:42 ` [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Matt Turner
8 siblings, 0 replies; 14+ messages in thread
From: Magnus Lindholm @ 2026-10-09 21:03 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7, stable
flush_tlb_mm() has the same caller-CPU omission that was fixed in
flush_tlb_page(): when the target mm is not the calling CPU's active_mm
nothing happens locally, and smp_call_function() handles only the other
CPUs, so this CPU may later reuse the old ASN together with the
translations it still holds.
The active_mm test itself is left alone here. That path calls
flush_tlb_current(), which loads a fresh context through
__load_new_mm_context() rather than issuing a targeted tbi() against
whatever ASN happens to be loaded, so it does not depend on which context
is current.
The uniprocessor implementation in asm/tlbflush.h already has the missing
branch. Counted over a fork-heavy run, flush_tlb_mm() was entered with the
mm not this CPU's active_mm 2934 times, and 632 times while otherwise idle.
The proposed Alpha hugetlb support routes hugetlb invalidations through
flush_tlb_range(), which calls this function. Unmapping or migrating a
hugetlb folio from another context will also need this local invalidate.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reviewed-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Message-ID: <20260923074903.862898-7-linmag7@gmail.com>
---
arch/alpha/kernel/smp.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index a5a42ae4a7d8..988e397b0b8a 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -649,6 +649,9 @@ flush_tlb_mm(struct mm_struct *mm)
preempt_enable();
return;
}
+ } else {
+ /* smp_call_function() does not call back into this CPU. */
+ flush_tlb_other(mm);
}
smp_call_function(ipi_flush_tlb_mm, mm, 1);
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v4 8/8] alpha: invalidate the local context in flush_icache_user_page()
2026-10-09 21:03 [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Magnus Lindholm
` (6 preceding siblings ...)
2026-10-09 21:03 ` [PATCH v4 7/8] alpha: invalidate the local context in flush_tlb_mm() Magnus Lindholm
@ 2026-10-09 21:03 ` Magnus Lindholm
2026-10-10 1:42 ` [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Matt Turner
8 siblings, 0 replies; 14+ messages in thread
From: Magnus Lindholm @ 2026-10-09 21:03 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7, stable
flush_icache_user_page() has the same caller-CPU omission that the
previous patch fixed in flush_tlb_mm(): when the target mm is not the
calling CPU's active_mm nothing happens locally, and smp_call_function()
handles only the other CPUs, so this CPU may later reuse the old ASN
together with the translations it still holds.
This matters here in particular because the function exists for
operating on another process's mappings: the comment above it describes
setting breakpoints through ptrace, and access_remote_vm() reaches it
through copy_to_user_page(). The calling CPU is therefore often running
something other than the target mm.
As in flush_tlb_mm(), the uniprocessor implementation in
asm/cacheflush.h already has the missing case.
No imb() is needed, here or in ipi_flush_icache_page(). Alpha's
user-space I-cache flush works by allocating a new ASN rather than by
invalidating the I-cache: the entries stay, but they are tagged with the
old ASN and can no longer match. An imb() is only required when the ASN
space wraps and numbers are reused, and __get_new_mm_context() already
does one in that case.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reviewed-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Message-ID: <20260923074903.862898-8-linmag7@gmail.com>
---
arch/alpha/kernel/smp.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 988e397b0b8a..e21bc3920bec 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -758,6 +758,9 @@ flush_icache_user_page(struct vm_area_struct *vma, struct page *page,
preempt_enable();
return;
}
+ } else {
+ /* smp_call_function() does not call back into this CPU. */
+ flush_tlb_other(mm);
}
smp_call_function(ipi_flush_icache_page, mm, 1);
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback
2026-10-09 21:03 [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Magnus Lindholm
` (7 preceding siblings ...)
2026-10-09 21:03 ` [PATCH v4 8/8] alpha: invalidate the local context in flush_icache_user_page() Magnus Lindholm
@ 2026-10-10 1:42 ` Matt Turner
2026-10-10 1:45 ` Matt Turner
8 siblings, 1 reply; 14+ messages in thread
From: Matt Turner @ 2026-10-10 1:42 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: richard.henderson, linux-kernel, linux-alpha
On Fri, Oct 09, 2026 at 11:03:45PM +0200, Magnus Lindholm wrote:
> Changes since v3:
All three things I asked for in v3 are here. Compile-tested SMP and UP
at each commit, nothing run on hardware yet.
Patches 1 and 3-8 have a Message-ID: trailer pointing at the previous
posting, I assume from git am -m. Please drop those when you apply.
Two changelog leftovers, neither worth a v5:
3/8 still says "the prerequisite direct-switch fix". That is patch 1
of this series now.
4/8 has a short line in the first paragraph ("This CPU may still").
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v4 1/8] alpha: load the MMU context when switch_mm() switches the current task
2026-10-09 21:03 ` [PATCH v4 1/8] alpha: load the MMU context when switch_mm() switches the current task Magnus Lindholm
@ 2026-10-10 1:42 ` Matt Turner
0 siblings, 0 replies; 14+ messages in thread
From: Matt Turner @ 2026-10-10 1:42 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: richard.henderson, linux-kernel, linux-alpha, stable
On Fri, Oct 09, 2026 at 11:03:46PM +0200, Magnus Lindholm wrote:
> + /*
> + * kthread_use_mm() and sched_force_init_mm() switch current's mm
> + * without alpha_switch_to(), which is what loads the context.
> + */
There is a third one: do_shoot_lazy_tlb() in kernel/fork.c calls
switch_mm(mm, &init_mm, current) from an IPI. It needs
MMU_LAZY_TLB_SHOOTDOWN, which alpha does not select, and the
next == current test handles it the same way. Only the comment and the
changelog are short by one. My tags stand.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v4 2/8] alpha: run check_mmu_context() from finish_arch_post_lock_switch()
2026-10-09 21:03 ` [PATCH v4 2/8] alpha: run check_mmu_context() from finish_arch_post_lock_switch() Magnus Lindholm
@ 2026-10-10 1:42 ` Matt Turner
0 siblings, 0 replies; 14+ messages in thread
From: Matt Turner @ 2026-10-10 1:42 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: richard.henderson, linux-kernel, linux-alpha, stable
On Fri, Oct 09, 2026 at 11:03:47PM +0200, Magnus Lindholm wrote:
> +/* Alpha has no kernel preemption; these callers cannot migrate here. */
Nothing in the file says who "these callers" are. Something like:
/*
* Also called from kthread_use_mm() with preemption enabled. Alpha has
* no kernel preemption, so the task is still on the CPU that ran
* switch_mm().
*/
> + /* A deferred shootdown can also invalidate a newly allocated ASN. */
> + cpu_data[cpu].need_new_asn = 1;
That closes the zero-slot case. I went through the window again with
this in place. An IPI that sees asn_lock zeroes the slot and the hook
reloads. One that arrives after asn_lock is cleared flushes the
context PAL_swpctx already loaded, and the hook finds the slot nonzero.
The hook's __load_new_mm_context() now runs with interrupts on, so an
IPI can nest inside it. Both are loading the same mm, so the worst
outcome is that it gets the same ASN twice. flush_tlb_mm() from process
context has always had that.
Reviewed-by: Matt Turner <mattst88@gmail.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v4 4/8] alpha: invalidate the local context in flush_tlb_page()
2026-10-09 21:03 ` [PATCH v4 4/8] alpha: invalidate the local context in flush_tlb_page() Magnus Lindholm
@ 2026-10-10 1:44 ` Matt Turner
0 siblings, 0 replies; 14+ messages in thread
From: Matt Turner @ 2026-10-10 1:44 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: richard.henderson, linux-kernel, linux-alpha, stable
On Fri, Oct 09, 2026 at 11:03:49PM +0200, Magnus Lindholm wrote:
> Add this before changing the
> current->active_mm test to current->mm: that change will also send lazy
> callers here, so their local invalidate must already be in place.
Thanks, this is the order I wanted. With only this patch applied a lazy
caller still does the old targeted tbi(), so no step is worse than the
one before it.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback
2026-10-10 1:42 ` [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Matt Turner
@ 2026-10-10 1:45 ` Matt Turner
0 siblings, 0 replies; 14+ messages in thread
From: Matt Turner @ 2026-10-10 1:45 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: richard.henderson, linux-kernel, linux-alpha
On Fri, Oct 9, 2026 at 9:42 PM Matt Turner <mattst88@gmail.com> wrote:
>
> On Fri, Oct 09, 2026 at 11:03:45PM +0200, Magnus Lindholm wrote:
> > Changes since v3:
>
> All three things I asked for in v3 are here. Compile-tested SMP and UP
> at each commit, nothing run on hardware yet.
>
> Patches 1 and 3-8 have a Message-ID: trailer pointing at the previous
> posting, I assume from git am -m. Please drop those when you apply.
>
> Two changelog leftovers, neither worth a v5:
>
> 3/8 still says "the prerequisite direct-switch fix". That is patch 1
> of this series now.
>
> 4/8 has a short line in the first paragraph ("This CPU may still").
I should add, the whole series is
Reviewed-by: Matt Turner <mattst88@gmail.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-10-10 1:46 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-09 21:03 [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 1/8] alpha: load the MMU context when switch_mm() switches the current task Magnus Lindholm
2026-10-10 1:42 ` Matt Turner
2026-10-09 21:03 ` [PATCH v4 2/8] alpha: run check_mmu_context() from finish_arch_post_lock_switch() Magnus Lindholm
2026-10-10 1:42 ` Matt Turner
2026-10-09 21:03 ` [PATCH v4 3/8] alpha: only use a targeted tbi() when the target mm is really current Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 4/8] alpha: invalidate the local context in flush_tlb_page() Magnus Lindholm
2026-10-10 1:44 ` Matt Turner
2026-10-09 21:03 ` [PATCH v4 5/8] alpha: fix the local TLB invalidate " Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 6/8] alpha: fix the local TLB invalidate in the UP flush_tlb_page() Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 7/8] alpha: invalidate the local context in flush_tlb_mm() Magnus Lindholm
2026-10-09 21:03 ` [PATCH v4 8/8] alpha: invalidate the local context in flush_icache_user_page() Magnus Lindholm
2026-10-10 1:42 ` [PATCH v4 0/8] alpha: fix stale TLB translations breaking copy-on-write and writeback Matt Turner
2026-10-10 1:45 ` Matt Turner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®