* [PATCH 0/3] alpha: load the MMU context on a direct mm switch
@ 2026-09-04 16:23 Magnus Lindholm
2026-09-04 16:23 ` [PATCH 1/3] alpha: do not clear remote MMU contexts in migrate_flush_tlb_page() Magnus Lindholm
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Magnus Lindholm @ 2026-09-04 16:23 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Three fixes for how alpha handles an mm that is switched in directly
rather than by the scheduler.
Patch 1 removes a stale clearing loop in migrate_flush_tlb_page() that
patch 2 depends on being gone. Patch 2 stops the TLB shootdown shortcut
from skipping a CPU that is borrowing an mm through kthread_use_mm(),
using mm->context[cpu] as a lockless publication of which CPUs may be
using the mm once patch 1 makes every write to it single-writer. Patch 3
then makes those direct mm switches actually load the MMU context, which
they currently do not: kthread_use_mm() and sched_force_init_mm() call
switch_mm_irqs_off() directly rather than through the scheduler, so the
hardware context is never installed and the task keeps running under
whatever was loaded before.
Reproducing it. A KUnit test was written for patch 3; source can be made
available on request. It uses kunit_attach_mm(), which calls
kthread_use_mm(), and then compares the loaded context against current->mm:
# alpha_use_mm_loads_context: EXPECTATION FAILED
Expected pcb->ptbr == mm_to_ptbr(current->mm), but
pcb->ptbr == 384 (0x180)
mm_to_ptbr(current->mm) == 12555 (0x310b)
0x180 is swapper_pg_dir: the kernel thread is running on the page tables
it had before the switch. The pcb.asn check in the same test passes,
which is the signature - ev5_switch_mm() does write the ASN, so it is the
load that is missing rather than the bookkeeping.
Do not detect this by dereferencing the borrowed mm's user addresses.
do_page_fault() resolves faults against current->mm and never reloads the
context, so with a stale ptbr the same access faults indefinitely.
Testing. ES40, EV68AL (21264C) Tsunami, 3 CPUs, v7.2-rc6.
before after
KUnit alpha_mmu_context 0 of 2 pass 2 of 2 pass
Patch 2 was measured rather than argued. Dropping the shortcut outright
is the obvious fix and costs far too much, so it tests mm->context[cpu]
instead:
fork/s, single-threaded shortcut as before 1360
shortcut removed 1050 -23%
patch 1 1360
Medians of seven, seven and twelve runs, spread 1352-1367, 1046-1052 and
1340-1366. The unchanged throughput shows the shortcut remains effective
for this workload, and neither the barrier nor the context marking shows
above the noise on this machine.
No regressions in the wider suite: glibc malloc-check 25/25 and four
related tests 10/10 each, the copy-on-write and writeback reproducers
from the previous series clean, and the same again under continuous
compaction with 359768 folios migrated during the run.
One adjacent problem is deliberately not addressed. enter_lazy_tlb() sets
pcb.ptbr for the borrowed mm without setting pcb.asn, so a kernel thread
switched in through PAL_swpctx loads one address space's page tables
against another's ASN. I have not found an observable failure from that
mismatch outside kernel-thread user accesses, which go through
kthread_use_mm() and are a matched pair after patch 2. Changing it would
mean touching the VPTB self-map behaviour on every lazy switch, with no
reproducer to justify the risk.
Patches 2 and 3 have no Cc: stable: kthread_use_mm() is the only
reachable caller on alpha through KUnit's kunit_attach_mm():
lib/tests/usercopy_kunit.c, lib/tests/kunit_iov_iter.c,
mm/kasan/kasan_test_c.c and drivers/android/tests/binder_alloc_kunit.c all
map user memory that way; sched_force_init_mm() and the driver callers
need configs or hardware alpha does not have. No ordinary alpha kernel
reaches either fix.
Patch 1 is different. migrate_flush_tlb_page() runs under plain
CONFIG_COMPACTION, and the clearing loop it removes can fire from ordinary
lazy-TLB retention on a single-threaded process's previous CPU, not just
kthread borrowing. The compaction stress testing above exercises that path
and has not caught it doing observable harm, so patch 1 also carries no Cc:
stable, but for that reason, not for being unreachable.
This applies on top of the "alpha: fix stale TLB translations breaking
copy-on-write and writeback" series and depends on it: patch 2 rewrites the
same flush_tlb_page() and flush_tlb_mm() shortcuts that series touches, and
does not apply without it.
https://lore.kernel.org/linux-alpha/20260810193902.3286353-1-linmag7@gmail.com/
Magnus Lindholm (3):
alpha: do not clear remote MMU contexts in migrate_flush_tlb_page()
alpha: do not skip TLB shootdown IPIs for kthread-borrowed mms
alpha: load the MMU context when switch_mm() switches the current task
arch/alpha/include/asm/mmu_context.h | 11 +++++--
arch/alpha/kernel/smp.c | 48 ++++++++++++++--------------
arch/alpha/mm/fault.c | 2 +-
arch/alpha/mm/tlbflush.c | 16 ----------
4 files changed, 34 insertions(+), 43 deletions(-)
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
--
2.55.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/3] alpha: do not clear remote MMU contexts in migrate_flush_tlb_page()
2026-09-04 16:23 [PATCH 0/3] alpha: load the MMU context on a direct mm switch Magnus Lindholm
@ 2026-09-04 16:23 ` Magnus Lindholm
2026-09-04 16:23 ` [PATCH 2/3] alpha: do not skip TLB shootdown IPIs for kthread-borrowed mms Magnus Lindholm
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Magnus Lindholm @ 2026-09-04 16:23 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
After the on_each_cpu() rendezvous, migrate_flush_tlb_page() walks the
other CPUs and zeroes their mm->context[cpu] when mm_users is at most one,
described as mimicking flush_tlb_mm()'s mm_users<=1 optimization.
It is not one. flush_tlb_mm() tests mm_users before deciding whether to
send the IPIs; here every CPU has already been visited and waited for, so
nothing is saved. The callback has also just set each CPU's own slot
correctly, so the loop only overwrites it and does so while that CPU may
still be running in the address space.
Remove it. Every runtime write to mm->context[] then targets the writing
CPU's own slot, which is the invariant the next patch depends on when it
reads those slots to decide whether a shootdown can be skipped.
Fixes: dd5712f3379c ("alpha: fix user-space corruption during memory compaction")
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/mm/tlbflush.c | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/arch/alpha/mm/tlbflush.c b/arch/alpha/mm/tlbflush.c
index ccbc317b9a34..239c72b8a741 100644
--- a/arch/alpha/mm/tlbflush.c
+++ b/arch/alpha/mm/tlbflush.c
@@ -90,22 +90,6 @@ void migrate_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
*/
preempt_disable();
on_each_cpu(ipi_flush_mm_and_page, &d, 1);
-
- /*
- * mimic flush_tlb_mm()'s mm_users<=1 optimization.
- */
- if (atomic_read(&mm->mm_users) <= 1) {
-
- int cpu, this_cpu;
- this_cpu = smp_processor_id();
-
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- if (!cpu_online(cpu) || cpu == this_cpu)
- continue;
- if (READ_ONCE(mm->context[cpu]))
- WRITE_ONCE(mm->context[cpu], 0);
- }
- }
preempt_enable();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/3] alpha: do not skip TLB shootdown IPIs for kthread-borrowed mms
2026-09-04 16:23 [PATCH 0/3] alpha: load the MMU context on a direct mm switch Magnus Lindholm
2026-09-04 16:23 ` [PATCH 1/3] alpha: do not clear remote MMU contexts in migrate_flush_tlb_page() Magnus Lindholm
@ 2026-09-04 16:23 ` Magnus Lindholm
2026-09-04 16:23 ` [PATCH 3/3] alpha: load the MMU context when switch_mm() switches the current task Magnus Lindholm
2026-09-22 16:38 ` [PATCH 0/3] alpha: load the MMU context on a direct mm switch Matt Turner
3 siblings, 0 replies; 6+ messages in thread
From: Magnus Lindholm @ 2026-09-04 16:23 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
flush_tlb_mm(), flush_tlb_page() and flush_icache_user_page() skip the
shootdown IPI when mm_users <= 1, on the assumption that no other CPU can
be running the mm. A task that borrows an mm through kthread_use_mm()
takes mmgrab() rather than mmget(), so it never appears in mm_users, and
kthread_use_mm() may be handed an mm that is already the caller's
active_mm and loaded on that CPU. Such a CPU was not only left without
an IPI, its mm->context[cpu] was cleared from under it.
mm->context[cpu] is already the record of which CPUs hold an ASN for the
mm. Test it rather than clearing it: take the shortcut only when no
other CPU has one, and otherwise fall through to the IPI, which
invalidates those CPUs properly. A CPU that merely ran the mm in the
past also holds a context and now costs an IPI, which errs in the safe
direction.
Dropping that clearing loop leaves every runtime write to mm->context[]
targeting the writing CPU's own slot, so the array becomes a lockless
publication of which CPUs may be using the mm, with a single writer per
slot. Mark the two stores that are now observed from other CPUs;
flush_tlb_other() already uses WRITE_ONCE(). The uniprocessor
flush_icache_user_page() is left alone, as nothing reads another CPU's
slot there, and init_new_context() runs before the mm is shared.
The reads also need ordering against the changes that led to the flush.
A CPU that publishes a context is in turn ordered before it goes on to
access the mm, by two different barriers: kthread_use_mm() issues one
through mmdrop_lazy_tlb() for the initial direct switch, and if the task
later migrates, the context published from ev5_switch_mm() is followed by
the scheduler's post-switch barrier, on alpha the mb() in
arch_spin_unlock() from finish_lock_switch(), as described in
Documentation/scheduler/membarrier.rst. So a CPU either already holds a
context and is seen here, or it allocates a fresh one before going on to
use the mm, and a fresh ASN carries nothing over from the previous
context.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/mmu_context.h | 2 +-
arch/alpha/kernel/smp.c | 48 ++++++++++++++--------------
arch/alpha/mm/fault.c | 2 +-
3 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/arch/alpha/include/asm/mmu_context.h b/arch/alpha/include/asm/mmu_context.h
index 825d3b9605c9..a829f557396d 100644
--- a/arch/alpha/include/asm/mmu_context.h
+++ b/arch/alpha/include/asm/mmu_context.h
@@ -147,7 +147,7 @@ ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
mmc = next_mm->context[cpu];
if ((mmc ^ asn) & ~HARDWARE_ASN_MASK) {
mmc = __get_new_mm_context(next_mm, cpu);
- next_mm->context[cpu] = mmc;
+ WRITE_ONCE(next_mm->context[cpu], mmc);
}
#ifdef CONFIG_SMP
else
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index e21bc3920bec..c4d12d8312a7 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -631,6 +631,24 @@ ipi_flush_tlb_mm(void *x)
flush_tlb_other(mm);
}
+/* True if a CPU other than this one holds an ASN for MM. */
+static bool
+mm_context_elsewhere(struct mm_struct *mm)
+{
+ int cpu, this_cpu = smp_processor_id();
+
+ /* Pairs with the barrier the publishing CPU issues before using MM. */
+ smp_mb();
+
+ for_each_online_cpu(cpu) {
+ if (cpu == this_cpu)
+ continue;
+ if (READ_ONCE(mm->context[cpu]))
+ return true;
+ }
+ return false;
+}
+
void
flush_tlb_mm(struct mm_struct *mm)
{
@@ -638,14 +656,8 @@ flush_tlb_mm(struct mm_struct *mm)
if (mm == current->active_mm) {
flush_tlb_current(mm);
- if (atomic_read(&mm->mm_users) <= 1) {
- int cpu, this_cpu = smp_processor_id();
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- if (!cpu_online(cpu) || cpu == this_cpu)
- continue;
- if (mm->context[cpu])
- mm->context[cpu] = 0;
- }
+ if (atomic_read(&mm->mm_users) <= 1 &&
+ !mm_context_elsewhere(mm)) {
preempt_enable();
return;
}
@@ -690,14 +702,8 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
/* 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();
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- if (!cpu_online(cpu) || cpu == this_cpu)
- continue;
- if (mm->context[cpu])
- mm->context[cpu] = 0;
- }
+ if (atomic_read(&mm->mm_users) <= 1 &&
+ !mm_context_elsewhere(mm)) {
preempt_enable();
return;
}
@@ -747,14 +753,8 @@ flush_icache_user_page(struct vm_area_struct *vma, struct page *page,
if (mm == current->active_mm) {
__load_new_mm_context(mm);
- if (atomic_read(&mm->mm_users) <= 1) {
- int cpu, this_cpu = smp_processor_id();
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- if (!cpu_online(cpu) || cpu == this_cpu)
- continue;
- if (mm->context[cpu])
- mm->context[cpu] = 0;
- }
+ if (atomic_read(&mm->mm_users) <= 1 &&
+ !mm_context_elsewhere(mm)) {
preempt_enable();
return;
}
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index a9816bbc9f34..7bbba9010dac 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -45,7 +45,7 @@ __load_new_mm_context(struct mm_struct *next_mm)
struct pcb_struct *pcb;
mmc = __get_new_mm_context(next_mm, smp_processor_id());
- next_mm->context[smp_processor_id()] = mmc;
+ WRITE_ONCE(next_mm->context[smp_processor_id()], mmc);
pcb = ¤t_thread_info()->pcb;
pcb->asn = mmc & HARDWARE_ASN_MASK;
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/3] alpha: load the MMU context when switch_mm() switches the current task
2026-09-04 16:23 [PATCH 0/3] alpha: load the MMU context on a direct mm switch Magnus Lindholm
2026-09-04 16:23 ` [PATCH 1/3] alpha: do not clear remote MMU contexts in migrate_flush_tlb_page() Magnus Lindholm
2026-09-04 16:23 ` [PATCH 2/3] alpha: do not skip TLB shootdown IPIs for kthread-borrowed mms Magnus Lindholm
@ 2026-09-04 16:23 ` Magnus Lindholm
2026-09-22 16:38 ` [PATCH 0/3] alpha: load the MMU context on a direct mm switch Matt Turner
3 siblings, 0 replies; 6+ messages in thread
From: Magnus Lindholm @ 2026-09-04 16:23 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
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. Its
user accesses can therefore resolve in the wrong address space, and
because do_page_fault() resolves faults against current->mm without
reloading, a fault taken that way repeats indefinitely.
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")
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/mmu_context.h | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/include/asm/mmu_context.h b/arch/alpha/include/asm/mmu_context.h
index a829f557396d..caa6a9c4e3ca 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,12 @@ ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
unsigned long mmc;
long cpu = smp_processor_id();
+ /* A direct switch never reaches alpha_switch_to(); load it here. */
+ if (next == current) {
+ __load_new_mm_context(next_mm);
+ return;
+ }
+
#ifdef CONFIG_SMP
cpu_data[cpu].asn_lock = 1;
barrier();
@@ -160,7 +168,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 related [flat|nested] 6+ messages in thread
* Re: [PATCH 0/3] alpha: load the MMU context on a direct mm switch
2026-09-04 16:23 [PATCH 0/3] alpha: load the MMU context on a direct mm switch Magnus Lindholm
` (2 preceding siblings ...)
2026-09-04 16:23 ` [PATCH 3/3] alpha: load the MMU context when switch_mm() switches the current task Magnus Lindholm
@ 2026-09-22 16:38 ` Matt Turner
2026-09-22 21:18 ` Magnus Lindholm
3 siblings, 1 reply; 6+ messages in thread
From: Matt Turner @ 2026-09-22 16:38 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: linux-alpha
On Fri, Sep 04, 2026 at 06:23:28PM +0200, Magnus Lindholm wrote:
> Reproducing it. A KUnit test was written for patch 3; source can be made
> available on request. It uses kunit_attach_mm(), which calls
> kthread_use_mm(), and then compares the loaded context against current->mm:
I wrote a similar one and ran it on an ES47 (EV7), on v7.3-rc1 with
the v2 stale-TLB series applied, with and without this series. Only
one CPU was online, so patch 2's shortcut never had another CPU to
look at.
Without the series the ptbr check fails. With it the test passes
(3/3, including user accesses before and after sleeping), and so do
usercopy_kunit (4/4) and kunit_iov_iter (17/17). A fork/COW check
running under continuous compact_memory showed no corruption, and
fork throughput was unchanged.
One difference from what you saw: the stale ptbr here was not
swapper_pg_dir.
Expected pcb->ptbr == mm_ptbr(current->mm), but
pcb->ptbr == 44986 (0xafba)
mm_ptbr(current->mm) == 42112 (0xa480)
swapper_pg_dir is PFN 0x800 on this kernel, so 0xafba is the page
table of whatever user process ran on that CPU last. The kthread then
reads and writes that process's memory at any address mapped in both,
and TLB fills made that way get tagged with the borrowed mm's ASN.
That is worse than a fault loop.
> Patches 2 and 3 have no Cc: stable: kthread_use_mm() is the only
> reachable caller on alpha through KUnit's kunit_attach_mm():
I don't think that holds. vhost still has a kthread worker mode
(vhost_run_work_kthread_list()) that calls kthread_use_mm().
VHOST_ENABLE_FORK_OWNER_CONTROL defaults to y, and userspace can pick
that mode with VHOST_SET_FORK_FROM_OWNER or fork_from_owner_default=0.
The USB gadget f_fs and gadgetfs AIO paths call it too, and dummy_hcd
works on any architecture. vdpa_sim is another. Given that the failure
is cross-process memory access, I'd add Cc: stable to 3, and to 2,
which fixes the missed shootdowns for the same borrowed mms.
Two notes on the patches themselves.
In patch 2, it would help to say in the commit message why keeping
stale slots is cheap: the IPI makes each remote CPU that isn't running
the mm clear its own slot in flush_tlb_other(), so a process that
migrated once pays one extra round of IPIs and then goes back to the
shortcut. That was the first question I had reading it, and the answer
is only implicit in the cover letter's fork numbers.
In patch 3, the next == current test is fine, but the comment could
name kthread_use_mm() and sched_force_init_mm() so the next person
knows why the scheduler never takes that branch.
For patch 3:
Tested-by: Matt Turner <mattst88@gmail.com>
Patches 1 and 2 only matter with more than one CPU, and with one
online neither the removed loop nor the new check has anything to
look at, so no tags on those until I can test on SMP.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 0/3] alpha: load the MMU context on a direct mm switch
2026-09-22 16:38 ` [PATCH 0/3] alpha: load the MMU context on a direct mm switch Matt Turner
@ 2026-09-22 21:18 ` Magnus Lindholm
0 siblings, 0 replies; 6+ messages in thread
From: Magnus Lindholm @ 2026-09-22 21:18 UTC (permalink / raw)
To: Matt Turner; +Cc: linux-alpha
Hi Matt,
On Tue, Sep 22, 2026 at 6:38 PM Matt Turner <mattst88@gmail.com> wrote:
>
> On Fri, Sep 04, 2026 at 06:23:28PM +0200, Magnus Lindholm wrote:
> > Reproducing it. A KUnit test was written for patch 3; source can be made
> > available on request. It uses kunit_attach_mm(), which calls
> > kthread_use_mm(), and then compares the loaded context against current->mm:
>
> I wrote a similar one and ran it on an ES47 (EV7), on v7.3-rc1 with
> the v2 stale-TLB series applied, with and without this series. Only
> one CPU was online, so patch 2's shortcut never had another CPU to
> look at.
>
> Without the series the ptbr check fails. With it the test passes
> (3/3, including user accesses before and after sleeping), and so do
> usercopy_kunit (4/4) and kunit_iov_iter (17/17). A fork/COW check
> running under continuous compact_memory showed no corruption, and
> fork throughput was unchanged.
>
> One difference from what you saw: the stale ptbr here was not
> swapper_pg_dir.
>
> Expected pcb->ptbr == mm_ptbr(current->mm), but
> pcb->ptbr == 44986 (0xafba)
> mm_ptbr(current->mm) == 42112 (0xa480)
>
> swapper_pg_dir is PFN 0x800 on this kernel, so 0xafba is the page
> table of whatever user process ran on that CPU last. The kthread then
> reads and writes that process's memory at any address mapped in both,
> and TLB fills made that way get tagged with the borrowed mm's ASN.
> That is worse than a fault loop.
>
Thanks, that is the better description and v2 uses it: the stale root need
not be swapper_pg_dir, it may belong to a user process that ran on the CPU
earlier. I kept the ASN part conditional, though. ev5_switch_mm() writes
the ASN field but nothing loads it, so the fills only pick that ASN up once
a swpctx has installed the half-updated PCB against the stale ptbr.
> > Patches 2 and 3 have no Cc: stable: kthread_use_mm() is the only
> > reachable caller on alpha through KUnit's kunit_attach_mm():
>
> I don't think that holds. vhost still has a kthread worker mode
> (vhost_run_work_kthread_list()) that calls kthread_use_mm().
> VHOST_ENABLE_FORK_OWNER_CONTROL defaults to y, and userspace can pick
> that mode with VHOST_SET_FORK_FROM_OWNER or fork_from_owner_default=0.
> The USB gadget f_fs and gadgetfs AIO paths call it too, and dummy_hcd
> works on any architecture. vdpa_sim is another. Given that the failure
> is cross-process memory access, I'd add Cc: stable to 3, and to 2,
> which fixes the missed shootdowns for the same borrowed mms.
>
Agreed, and patch 1 with them, since patch 2 is not correct without it.
One thing worth knowing for the backport: several of those callers hold an
mm_users reference across the borrow (vhost through get_task_mm(), f_fs,
gadgetfs and vdpa_sim through mmget_not_zero()), so whether a flush reaches
patch 2's mm_users <= 1 decision is caller-dependent. kunit_attach_mm() is
the unambiguous case, and patch 3 is not conditional on any of it.
> Two notes on the patches themselves.
>
> In patch 2, it would help to say in the commit message why keeping
> stale slots is cheap: the IPI makes each remote CPU that isn't running
> the mm clear its own slot in flush_tlb_other(), so a process that
> migrated once pays one extra round of IPIs and then goes back to the
> shortcut. That was the first question I had reading it, and the answer
> is only implicit in the cover letter's fork numbers.
>
Added, with one qualification: the shortcut is available again only while
mm_users stays at most one and no other CPU has since taken or kept a
context.
> In patch 3, the next == current test is fine, but the comment could
> name kthread_use_mm() and sched_force_init_mm() so the next person
> knows why the scheduler never takes that branch.
>
Done.
> For patch 3:
>
> Tested-by: Matt Turner <mattst88@gmail.com>
>
> Patches 1 and 2 only matter with more than one CPU, and with one
> online neither the removed loop nor the new check has anything to
> look at, so no tags on those until I can test on SMP.
I pick up this tag for patch-3 only.
Thanks alot for taking the time to take a close look at this series.
I'll be sending out a v2 asap
Magnus
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-09-22 21:19 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-04 16:23 [PATCH 0/3] alpha: load the MMU context on a direct mm switch Magnus Lindholm
2026-09-04 16:23 ` [PATCH 1/3] alpha: do not clear remote MMU contexts in migrate_flush_tlb_page() Magnus Lindholm
2026-09-04 16:23 ` [PATCH 2/3] alpha: do not skip TLB shootdown IPIs for kthread-borrowed mms Magnus Lindholm
2026-09-04 16:23 ` [PATCH 3/3] alpha: load the MMU context when switch_mm() switches the current task Magnus Lindholm
2026-09-22 16:38 ` [PATCH 0/3] alpha: load the MMU context on a direct mm switch Matt Turner
2026-09-22 21:18 ` Magnus Lindholm
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.