[PATCH 3/6] alpha: fix the local TLB invalidate in flush_tlb_page()

Magnus Lindholm <[email protected]>
Newsgroups org.kernel.vger.linux-alpha,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
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, so as in the IPI handler it reaches nothing when only active_mm
names the mm, and nothing forces the old ASN to be retired afterwards.

Test current->mm instead. When no thread of the mm is current, clear
mm->context[cpu] so a fresh ASN is taken at the next switch. That also
covers the case where the mm is not this CPU's active_mm at all: the CPU
may still hold translations for it, and smp_call_function() does not call
back into the caller.

Reached in practice by folio_mkclean() from the writeback flusher
kworker, which has no mm of its own: about half the calls during
writeback of a shared mapping, and none at all on anonymous memory.

flush_tlb_mm() does not need the same active_mm to current->mm change,
because its active_mm path loads a new context rather than issuing a
targeted tbi(). It does have the separate caller-CPU omission when the
target mm is not active_mm; that is fixed in the following patch.

Signed-off-by: Magnus Lindholm <[email protected]>
---
 arch/alpha/kernel/smp.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 0dfe29b59039..d167b3ba1303 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -696,7 +696,15 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 
 	preempt_disable();
 
-	if (mm == current->active_mm) {
+	/*
+	 * As in ipi_flush_tlb_page(): the targeted tbi() reaches MM's
+	 * translations only when a thread of MM is current, so test
+	 * current->mm.  Otherwise - lazily borrowing MM, or not running it
+	 * at all - clear mm->context[cpu] so a fresh ASN is taken at the
+	 * next switch.  smp_call_function() below does not call back into
+	 * this CPU, so this is the only chance to retire what it holds.
+	 */
+	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();
@@ -709,6 +717,8 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 			preempt_enable();
 			return;
 		}
+	} else {
+		flush_tlb_other(mm);
 	}
 
 	data.vma = vma;
-- 
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.