[PATCH 2/6] alpha: only use a targeted tbi() when the target mm is really current
Magnus Lindholm <[email protected]>
| Newsgroups | gmane.linux.ports.alpha,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
A copy-on-write fault replaces the page and calls ptep_clear_flush(), which ends up in flush_tlb_page(). For a non-executable vma the remote IPI handler issues a targeted tbi(2, addr). tbi() acts on the address space context currently loaded on that CPU, so it means something only when that context belongs to the target mm. current->active_mm is the wrong test: under lazy TLB an idle or kernel task keeps the mm as its active_mm while a different ASN is loaded in the PCB - enter_lazy_tlb() updates only the borrowing task's page table base, not its ASN. The tbi() then invalidates the wrong context and the stale translation survives. Nothing forces the old ASN to be retired afterwards either, because mm->context[cpu] is still valid, so the resuming thread can reuse it along with the stale entry. Use current->mm instead. When no thread of the mm is current, fall back to the deferred invalidation, which forces a fresh ASN at the next switch and is correct whatever is loaded now. This does not make current->mm a guarantee that the mm's context is loaded: kthread_use_mm() sets current->mm and reaches switch_mm_irqs_off() directly, which on alpha only prepares the incoming PCB. That is a separate problem in the switch path rather than in this handler, and it is not addressed here. Signed-off-by: Magnus Lindholm <[email protected]> --- arch/alpha/kernel/smp.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index ed06367ece57..0dfe29b59039 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -669,7 +669,20 @@ 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()) + /* + * tbi() acts on the address space context currently loaded on this + * CPU, so it reaches MM's translations only when a thread of MM is + * really running here. current->active_mm is not sufficient: under + * lazy TLB an idle or kernel task keeps MM as its active_mm while a + * different ASN is loaded in the PCB, so the tbi() invalidates the + * wrong context and the stale entry survives. Nothing forces the + * old ASN to be retired afterwards either, mm->context[cpu] still + * being valid, so the resuming thread can reuse it. + * + * Otherwise fall back to invalidating the context, which forces a + * fresh ASN at the next switch whatever is loaded now. + */ + if (mm == current->mm && !asn_locked()) flush_tlb_current_page(mm, data->vma, data->addr); else flush_tlb_other(mm); -- 2.53.0