Merge tag 'locking-core-2025-03-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking updates from Ingo Molnar:
 "Locking primitives:
   - Micro-optimize percpu_{,try_}cmpxchg{64,128}_op() and
     {,try_}cmpxchg{64,128} on x86 (Uros Bizjak)
   - mutexes: extend debug checks in mutex_lock() (Yunhui Cui)
   - Misc cleanups (Uros Bizjak)

  Lockdep:
   - Fix might_fault() lockdep check of current->mm->mmap_lock (Peter
     Zijlstra)
   - Don't disable interrupts on RT in disable_irq_nosync_lockdep.*()
     (Sebastian Andrzej Siewior)
   - Disable KASAN instrumentation of lockdep.c (Waiman Long)
   - Add kasan_check_byte() check in lock_acquire() (Waiman Long)
   - Misc cleanups (Sebastian Andrzej Siewior)

  Rust runtime integration:
   - Use Pin for all LockClassKey usages (Mitchell Levy)
   - sync: Add accessor for the lock behind a given guard (Alice Ryhl)
   - sync: condvar: Add wait_interruptible_freezable() (Alice Ryhl)
   - sync: lock: Add an example for Guard:: Lock_ref() (Boqun Feng)

  Split-lock detection feature (x86):
   - Fix warning mode with disabled mitigation mode (Maksim Davydov)

  Locking events:
   - Add locking events for rtmutex slow paths (Waiman Long)
   - Add locking events for lockdep (Waiman Long)"

* tag 'locking-core-2025-03-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  lockdep: Remove disable_irq_lockdep()
  lockdep: Don't disable interrupts on RT in disable_irq_nosync_lockdep.*()
  rust: lockdep: Use Pin for all LockClassKey usages
  rust: sync: condvar: Add wait_interruptible_freezable()
  rust: sync: lock: Add an example for Guard:: Lock_ref()
  rust: sync: Add accessor for the lock behind a given guard
  locking/lockdep: Add kasan_check_byte() check in lock_acquire()
  locking/lockdep: Disable KASAN instrumentation of lockdep.c
  locking/lock_events: Add locking events for lockdep
  locking/lock_events: Add locking events for rtmutex slow paths
  x86/split_lock: Fix the delayed detection logic
  lockdep/mm: Fix might_fault() lockdep check of current->mm->mmap_lock
  x86/locking: Remove semicolon from "lock" prefix
  locking/mutex: Add MUTEX_WARN_ON() into fast path
  x86/locking: Use asm_inline for {,try_}cmpxchg{64,128} emulations
  x86/locking: Use ALT_OUTPUT_SP() for percpu_{,try_}cmpxchg{64,128}_op()
This commit is contained in:
Linus Torvalds
2025-03-24 20:55:03 -07:00
24 changed files with 294 additions and 109 deletions

View File

@@ -11,12 +11,13 @@
init::PinInit,
pin_init,
str::CStr,
task::{MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE},
task::{
MAX_SCHEDULE_TIMEOUT, TASK_FREEZABLE, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE,
},
time::Jiffies,
types::Opaque,
};
use core::marker::PhantomPinned;
use core::ptr;
use core::{marker::PhantomPinned, pin::Pin, ptr};
use macros::pin_data;
/// Creates a [`CondVar`] initialiser with the given name and a newly-created lock class.
@@ -101,7 +102,7 @@ unsafe impl Sync for CondVar {}
impl CondVar {
/// Constructs a new condvar initialiser.
pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
pin_init!(Self {
_pin: PhantomPinned,
// SAFETY: `slot` is valid while the closure is called and both `name` and `key` have
@@ -159,6 +160,25 @@ pub fn wait_interruptible<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T,
crate::current!().signal_pending()
}
/// Releases the lock and waits for a notification in interruptible and freezable mode.
///
/// The process is allowed to be frozen during this sleep. No lock should be held when calling
/// this function, and there is a lockdep assertion for this. Freezing a task that holds a lock
/// can trivially deadlock vs another task that needs that lock to complete before it too can
/// hit freezable.
#[must_use = "wait_interruptible_freezable returns if a signal is pending, so the caller must check the return value"]
pub fn wait_interruptible_freezable<T: ?Sized, B: Backend>(
&self,
guard: &mut Guard<'_, T, B>,
) -> bool {
self.wait_internal(
TASK_INTERRUPTIBLE | TASK_FREEZABLE,
guard,
MAX_SCHEDULE_TIMEOUT,
);
crate::current!().signal_pending()
}
/// Releases the lock and waits for a notification in interruptible mode.
///
/// Atomically releases the given lock (whose ownership is proven by the guard) and puts the

View File

@@ -12,7 +12,7 @@
str::CStr,
types::{NotThreadSafe, Opaque, ScopeGuard},
};
use core::{cell::UnsafeCell, marker::PhantomPinned};
use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
use macros::pin_data;
pub mod mutex;
@@ -129,7 +129,7 @@ unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
impl<T, B: Backend> Lock<T, B> {
/// Constructs a new lock initialiser.
pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
pub fn new(t: T, name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
pin_init!(Self {
data: UnsafeCell::new(t),
_pin: PhantomPinned,
@@ -199,7 +199,36 @@ pub struct Guard<'a, T: ?Sized, B: Backend> {
// SAFETY: `Guard` is sync when the data protected by the lock is also sync.
unsafe impl<T: Sync + ?Sized, B: Backend> Sync for Guard<'_, T, B> {}
impl<T: ?Sized, B: Backend> Guard<'_, T, B> {
impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> {
/// Returns the lock that this guard originates from.
///
/// # Examples
///
/// The following example shows how to use [`Guard::lock_ref()`] to assert the corresponding
/// lock is held.
///
/// ```
/// # use kernel::{new_spinlock, stack_pin_init, sync::lock::{Backend, Guard, Lock}};
///
/// fn assert_held<T, B: Backend>(guard: &Guard<'_, T, B>, lock: &Lock<T, B>) {
/// // Address-equal means the same lock.
/// assert!(core::ptr::eq(guard.lock_ref(), lock));
/// }
///
/// // Creates a new lock on the stack.
/// stack_pin_init!{
/// let l = new_spinlock!(42)
/// }
///
/// let g = l.lock();
///
/// // `g` originates from `l`.
/// assert_held(&g, &l);
/// ```
pub fn lock_ref(&self) -> &'a Lock<T, B> {
self.lock
}
pub(crate) fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U {
// SAFETY: The caller owns the lock, so it is safe to unlock it.
unsafe { B::unlock(self.lock.state.get(), &self.state) };

View File

@@ -13,6 +13,7 @@
use core::{
cell::UnsafeCell,
marker::{PhantomData, PhantomPinned},
pin::Pin,
};
/// Trait implemented for marker types for global locks.
@@ -26,7 +27,7 @@ pub trait GlobalLockBackend {
/// The backend used for this global lock.
type Backend: Backend + 'static;
/// The class for this global lock.
fn get_lock_class() -> &'static LockClassKey;
fn get_lock_class() -> Pin<&'static LockClassKey>;
}
/// Type used for global locks.
@@ -270,7 +271,7 @@ impl $crate::sync::lock::GlobalLockBackend for $name {
type Item = $valuety;
type Backend = $crate::global_lock_inner!(backend $kind);
fn get_lock_class() -> &'static $crate::sync::LockClassKey {
fn get_lock_class() -> Pin<&'static $crate::sync::LockClassKey> {
$crate::static_lock_class!()
}
}

View File

@@ -89,7 +89,7 @@ pub struct PollCondVar {
impl PollCondVar {
/// Constructs a new condvar initialiser.
pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
pin_init!(Self {
inner <- CondVar::new(name, key),
})