Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

membarrier: riscv: Add full memory barrier in switch_mm()

The membarrier system call requires a full memory barrier after storing
to rq->curr, before going back to user-space. The barrier is only
needed when switching between processes: the barrier is implied by
mmdrop() when switching from kernel to userspace, and it's not needed
when switching from userspace to kernel.

Rely on the feature/mechanism ARCH_HAS_MEMBARRIER_CALLBACKS and on the
primitive membarrier_arch_switch_mm(), already adopted by the PowerPC
architecture, to insert the required barrier.

Fixes: fab957c11efe2f ("RISC-V: Atomic and Locking Code")
Signed-off-by: Andrea Parri <parri.andrea@gmail.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Link: https://lore.kernel.org/r/20240131144936.29190-2-parri.andrea@gmail.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>

authored by

Andrea Parri and committed by
Palmer Dabbelt
d6cfd177 6613476e

+38 -3
+1 -1
MAINTAINERS
··· 14039 14039 M: "Paul E. McKenney" <paulmck@kernel.org> 14040 14040 L: linux-kernel@vger.kernel.org 14041 14041 S: Supported 14042 - F: arch/powerpc/include/asm/membarrier.h 14042 + F: arch/*/include/asm/membarrier.h 14043 14043 F: include/uapi/linux/membarrier.h 14044 14044 F: kernel/sched/membarrier.c 14045 14045
+1
arch/riscv/Kconfig
··· 27 27 select ARCH_HAS_GCOV_PROFILE_ALL 28 28 select ARCH_HAS_GIGANTIC_PAGE 29 29 select ARCH_HAS_KCOV 30 + select ARCH_HAS_MEMBARRIER_CALLBACKS 30 31 select ARCH_HAS_MMIOWB 31 32 select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE 32 33 select ARCH_HAS_PMEM_API
+31
arch/riscv/include/asm/membarrier.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef _ASM_RISCV_MEMBARRIER_H 3 + #define _ASM_RISCV_MEMBARRIER_H 4 + 5 + static inline void membarrier_arch_switch_mm(struct mm_struct *prev, 6 + struct mm_struct *next, 7 + struct task_struct *tsk) 8 + { 9 + /* 10 + * Only need the full barrier when switching between processes. 11 + * Barrier when switching from kernel to userspace is not 12 + * required here, given that it is implied by mmdrop(). Barrier 13 + * when switching from userspace to kernel is not needed after 14 + * store to rq->curr. 15 + */ 16 + if (IS_ENABLED(CONFIG_SMP) && 17 + likely(!(atomic_read(&next->membarrier_state) & 18 + (MEMBARRIER_STATE_PRIVATE_EXPEDITED | 19 + MEMBARRIER_STATE_GLOBAL_EXPEDITED)) || !prev)) 20 + return; 21 + 22 + /* 23 + * The membarrier system call requires a full memory barrier 24 + * after storing to rq->curr, before going back to user-space. 25 + * Matches a full barrier in the proximity of the membarrier 26 + * system call entry. 27 + */ 28 + smp_mb(); 29 + } 30 + 31 + #endif /* _ASM_RISCV_MEMBARRIER_H */
+2
arch/riscv/mm/context.c
··· 323 323 if (unlikely(prev == next)) 324 324 return; 325 325 326 + membarrier_arch_switch_mm(prev, next, task); 327 + 326 328 /* 327 329 * Mark the current MM context as inactive, and the next as 328 330 * active. This is at least used by the icache flushing
+3 -2
kernel/sched/core.c
··· 6709 6709 * 6710 6710 * Here are the schemes providing that barrier on the 6711 6711 * various architectures: 6712 - * - mm ? switch_mm() : mmdrop() for x86, s390, sparc, PowerPC. 6713 - * switch_mm() rely on membarrier_arch_switch_mm() on PowerPC. 6712 + * - mm ? switch_mm() : mmdrop() for x86, s390, sparc, PowerPC, 6713 + * RISC-V. switch_mm() relies on membarrier_arch_switch_mm() 6714 + * on PowerPC and on RISC-V. 6714 6715 * - finish_lock_switch() for weakly-ordered 6715 6716 * architectures where spin_unlock is a full barrier, 6716 6717 * - switch_to() for arm64 (weakly-ordered, spin_unlock