[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.