Skip to contentSkip to conversation

Patch "MIPS: Make set_pte() SMP safe." has been added to the 4.1-stable tree

PATCH [email protected] 1 participant 1 message Aug 10, 2015

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer Applied
#0 lore raw

This is a note to let you know that I've just added the patch titled

MIPS: Make set_pte() SMP safe.

to the 4.1-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
mips-make-set_pte-smp-safe.patch
and it can be found in the queue-4.1 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.

Quoted 1 line

From 46011e6ea39235e4aca656673c500eac81a07a17 Mon Sep 17 00:00:00 2001

From: David Daney <[email protected]>
Date: Mon, 3 Aug 2015 17:48:43 -0700
Subject: MIPS: Make set_pte() SMP safe.

From: David Daney <[email protected]>

commit 46011e6ea39235e4aca656673c500eac81a07a17 upstream.

On MIPS the GLOBAL bit of the PTE must have the same value in any aligned pair of PTEs. These pairs of PTEs are referred to as "buddies". In a SMP system is is possible for two CPUs to be calling set_pte() on adjacent PTEs at the same time. There is a race between setting the PTE and a different CPU setting the GLOBAL bit in its buddy PTE.

This race can be observed when multiple CPUs are executing vmap()/vfree() at the same time.

Make setting the buddy PTE's GLOBAL bit an atomic operation to close the race condition.

The case of CONFIG_64BIT_PHYS_ADDR && CONFIG_CPU_MIPS32 is *not* handled.

Patchwork: https://patchwork.linux-mips.org/patch/10835/

---
 arch/mips/include/asm/pgtable.h |   31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
arch/mips/include/asm/pgtable.h +31 -0
@@ -182,8 +182,39 @@ static inline void set_pte(pte_t *ptep,
 		 * Make sure the buddy is global too (if it's !none,
 		 * it better already be global)
 		 */
+#ifdef CONFIG_SMP
+		/*
+		 * For SMP, multiple CPUs can race, so we need to do
+		 * this atomically.
+		 */
+#ifdef CONFIG_64BIT
+#define LL_INSN "lld"
+#define SC_INSN "scd"
+#else /* CONFIG_32BIT */
+#define LL_INSN "ll"
+#define SC_INSN "sc"
+#endif
+		unsigned long page_global = _PAGE_GLOBAL;
+		unsigned long tmp;
+
+		__asm__ __volatile__ (
+			"	.set	push\n"
+			"	.set	noreorder\n"
+			"1:	" LL_INSN "	%[tmp], %[buddy]\n"
+			"	bnez	%[tmp], 2f\n"
+			"	 or	%[tmp], %[tmp], %[global]\n"
+			"	" SC_INSN "	%[tmp], %[buddy]\n"
+			"	beqz	%[tmp], 1b\n"
+			"	 nop\n"
+			"2:\n"
+			"	.set pop"
+			: [buddy] "+m" (buddy->pte),
+			  [tmp] "=&r" (tmp)
+			: [global] "r" (page_global));
+#else /* !CONFIG_SMP */
 		if (pte_none(*buddy))
 			pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;
+#endif /* CONFIG_SMP */
 	}
 #endif
 }

Patches currently in stable-queue which might be from [email protected] are

queue-4.1/mips-make-set_pte-smp-safe.patch