rust: sync: Add memory barriers

Memory barriers are building blocks for concurrent code, hence provide
a minimal set of them.

The compiler barrier, barrier(), is implemented in inline asm instead of
using core::sync::atomic::compiler_fence() because memory models are
different: kernel's atomics are implemented in inline asm therefore the
compiler barrier should be implemented in inline asm as well. Also it's
currently only public to the kernel crate until there's a reasonable
driver usage.

Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Elle Rhumsaa <elle@weathered-steel.dev>
Link: https://lore.kernel.org/all/20250719030827.61357-10-boqun.feng@gmail.com/
This commit is contained in:
Boqun Feng
2025-09-04 21:41:36 -07:00
committed by Peter Zijlstra
parent 84c6d36bca
commit d9ea5a41ce
4 changed files with 81 additions and 0 deletions

18
rust/helpers/barrier.c Normal file
View File

@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0
#include <asm/barrier.h>
void rust_helper_smp_mb(void)
{
smp_mb();
}
void rust_helper_smp_wmb(void)
{
smp_wmb();
}
void rust_helper_smp_rmb(void)
{
smp_rmb();
}

View File

@@ -9,6 +9,7 @@
#include "atomic.c"
#include "auxiliary.c"
#include "barrier.c"
#include "blk.c"
#include "bug.c"
#include "build_assert.c"

View File

@@ -12,6 +12,7 @@ use pin_init;
mod arc;
pub mod aref;
pub mod atomic;
pub mod barrier;
pub mod completion;
mod condvar;
pub mod lock;

View File

@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0
//! Memory barriers.
//!
//! These primitives have the same semantics as their C counterparts: and the precise definitions
//! of semantics can be found at [`LKMM`].
//!
//! [`LKMM`]: srctree/tools/memory-model/
/// A compiler barrier.
///
/// A barrier that prevents compiler from reordering memory accesses across the barrier.
#[inline(always)]
pub(crate) fn barrier() {
// By default, Rust inline asms are treated as being able to access any memory or flags, hence
// it suffices as a compiler barrier.
//
// SAFETY: An empty asm block.
unsafe { core::arch::asm!("") };
}
/// A full memory barrier.
///
/// A barrier that prevents compiler and CPU from reordering memory accesses across the barrier.
#[inline(always)]
pub fn smp_mb() {
if cfg!(CONFIG_SMP) {
// SAFETY: `smp_mb()` is safe to call.
unsafe { bindings::smp_mb() };
} else {
barrier();
}
}
/// A write-write memory barrier.
///
/// A barrier that prevents compiler and CPU from reordering memory write accesses across the
/// barrier.
#[inline(always)]
pub fn smp_wmb() {
if cfg!(CONFIG_SMP) {
// SAFETY: `smp_wmb()` is safe to call.
unsafe { bindings::smp_wmb() };
} else {
barrier();
}
}
/// A read-read memory barrier.
///
/// A barrier that prevents compiler and CPU from reordering memory read accesses across the
/// barrier.
#[inline(always)]
pub fn smp_rmb() {
if cfg!(CONFIG_SMP) {
// SAFETY: `smp_rmb()` is safe to call.
unsafe { bindings::smp_rmb() };
} else {
barrier();
}
}