Skip to content

Commit

Permalink
Merge tag 'locking-core-2025-01-20' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/kernel/git/tip/tip

Pull locking updates from Ingo Molnar:
 "Lockdep:

   - Improve and fix lockdep bitsize limits, clarify the Kconfig
     documentation (Carlos Llamas)

   - Fix lockdep build warning on Clang related to
     chain_hlock_class_idx() inlining (Andy Shevchenko)

   - Relax the requirements of PROVE_RAW_LOCK_NESTING arch support by
     not tying it to ARCH_SUPPORTS_RT unnecessarily (Waiman Long)

  Rust integration:

   - Support lock pointers managed by the C side (Lyude Paul)

   - Support guard types (Lyude Paul)

   - Update MAINTAINERS file filters to include the Rust locking code
     (Boqun Feng)

  Wake-queues:

   - Add raw_spin_*wake() helpers to simplify locking code (John Stultz)

  SMP cross-calls:

   - Fix potential data update race by evaluating the local cond_func()
     before IPI side-effects (Mathieu Desnoyers)

  Guard primitives:

   - Ease [c]tags based searches by including the cleanup/guard type
     primitives (Peter Zijlstra)

  ww_mutexes:

   - Simplify the ww_mutex self-test code via swap() (Thorsten Blum)

  Static calls:

   - Update the static calls MAINTAINERS file-pattern (Jiri Slaby)"

* tag 'locking-core-2025-01-20' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  MAINTAINERS: Add static_call_inline.c to STATIC BRANCH/CALL
  cleanup, tags: Create tags for the cleanup primitives
  sched/wake_q: Add helper to call wake_up_q after unlock with preemption disabled
  rust: sync: Add lock::Backend::assert_is_held()
  rust: sync: Add SpinLockGuard type alias
  rust: sync: Add MutexGuard type alias
  rust: sync: Make Guard::new() public
  rust: sync: Add Lock::from_raw() for Lock<(), B>
  locking: MAINTAINERS: Start watching Rust locking primitives
  lockdep: Move lockdep_assert_locked() under #ifdef CONFIG_PROVE_LOCKING
  lockdep: Mark chain_hlock_class_idx() with __maybe_unused
  lockdep: Document MAX_LOCKDEP_CHAIN_HLOCKS calculation
  lockdep: Clarify size for LOCKDEP_*_BITS configs
  lockdep: Fix upper limit for LOCKDEP_*_BITS configs
  locking/ww_mutex/test: Use swap() macro
  smp/scf: Evaluate local cond_func() before IPI side-effects
  locking/lockdep: Enforce PROVE_RAW_LOCK_NESTING only if ARCH_SUPPORTS_RT
  • Loading branch information
Linus Torvalds committed Jan 21, 2025
2 parents b9d8a29 + cb4ccc7 commit 8838a1a
Show file tree
Hide file tree
Showing 17 changed files with 152 additions and 69 deletions.
9 changes: 7 additions & 2 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -13439,8 +13439,8 @@ LOCKING PRIMITIVES
M: Peter Zijlstra <peterz@infradead.org>
M: Ingo Molnar <mingo@redhat.com>
M: Will Deacon <will@kernel.org>
M: Boqun Feng <boqun.feng@gmail.com> (LOCKDEP & RUST)
R: Waiman Long <longman@redhat.com>
R: Boqun Feng <boqun.feng@gmail.com> (LOCKDEP)
L: linux-kernel@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
Expand All @@ -13454,6 +13454,11 @@ F: include/linux/seqlock.h
F: include/linux/spinlock*.h
F: kernel/locking/
F: lib/locking*.[ch]
F: rust/helpers/mutex.c
F: rust/helpers/spinlock.c
F: rust/kernel/sync/lock.rs
F: rust/kernel/sync/lock/
F: rust/kernel/sync/locked_by.rs
X: kernel/locking/locktorture.c

LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP/Vista Dynamic Disks)
Expand Down Expand Up @@ -22467,7 +22472,7 @@ F: arch/*/kernel/static_call.c
F: include/linux/jump_label*.h
F: include/linux/static_call*.h
F: kernel/jump_label.c
F: kernel/static_call.c
F: kernel/static_call*.c

STI AUDIO (ASoC) DRIVERS
M: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
Expand Down
34 changes: 34 additions & 0 deletions include/linux/sched/wake_q.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,38 @@ extern void wake_q_add(struct wake_q_head *head, struct task_struct *task);
extern void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task);
extern void wake_up_q(struct wake_q_head *head);

/* Spin unlock helpers to unlock and call wake_up_q with preempt disabled */
static inline
void raw_spin_unlock_wake(raw_spinlock_t *lock, struct wake_q_head *wake_q)
{
guard(preempt)();
raw_spin_unlock(lock);
if (wake_q) {
wake_up_q(wake_q);
wake_q_init(wake_q);
}
}

static inline
void raw_spin_unlock_irq_wake(raw_spinlock_t *lock, struct wake_q_head *wake_q)
{
guard(preempt)();
raw_spin_unlock_irq(lock);
if (wake_q) {
wake_up_q(wake_q);
wake_q_init(wake_q);
}
}

static inline
void raw_spin_unlock_irqrestore_wake(raw_spinlock_t *lock, unsigned long flags,
struct wake_q_head *wake_q)
{
guard(preempt)();
raw_spin_unlock_irqrestore(lock, flags);
if (wake_q) {
wake_up_q(wake_q);
wake_q_init(wake_q);
}
}
#endif /* _LINUX_SCHED_WAKE_Q_H */
5 changes: 1 addition & 4 deletions kernel/futex/pi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1020,10 +1020,7 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
* it sees the futex_q::pi_state.
*/
ret = __rt_mutex_start_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter, current, &wake_q);
preempt_disable();
raw_spin_unlock_irq(&q.pi_state->pi_mutex.wait_lock);
wake_up_q(&wake_q);
preempt_enable();
raw_spin_unlock_irq_wake(&q.pi_state->pi_mutex.wait_lock, &wake_q);

if (ret) {
if (ret == 1)
Expand Down
4 changes: 3 additions & 1 deletion kernel/locking/lockdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,12 @@ static inline void lockdep_unlock(void)
__this_cpu_dec(lockdep_recursion);
}

#ifdef CONFIG_PROVE_LOCKING
static inline bool lockdep_assert_locked(void)
{
return DEBUG_LOCKS_WARN_ON(__owner != current);
}
#endif

static struct task_struct *lockdep_selftest_task_struct;

Expand Down Expand Up @@ -430,7 +432,7 @@ static inline u16 hlock_id(struct held_lock *hlock)
return (hlock->class_idx | (hlock->read << MAX_LOCKDEP_KEYS_BITS));
}

static inline unsigned int chain_hlock_class_idx(u16 hlock_id)
static inline __maybe_unused unsigned int chain_hlock_class_idx(u16 hlock_id)
{
return hlock_id & (MAX_LOCKDEP_KEYS - 1);
}
Expand Down
3 changes: 2 additions & 1 deletion kernel/locking/lockdep_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ static const unsigned long LOCKF_USED_IN_IRQ_READ =

#define MAX_LOCKDEP_CHAINS (1UL << MAX_LOCKDEP_CHAINS_BITS)

#define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS*5)
#define AVG_LOCKDEP_CHAIN_DEPTH 5
#define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS * AVG_LOCKDEP_CHAIN_DEPTH)

extern struct lock_chain lock_chains[];

Expand Down
16 changes: 4 additions & 12 deletions kernel/locking/mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -657,10 +657,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas
goto err;
}

raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
/* Make sure we do wakeups before calling schedule */
wake_up_q(&wake_q);
wake_q_init(&wake_q);
raw_spin_unlock_irqrestore_wake(&lock->wait_lock, flags, &wake_q);

schedule_preempt_disabled();

Expand Down Expand Up @@ -710,8 +707,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas
if (ww_ctx)
ww_mutex_lock_acquired(ww, ww_ctx);

raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
wake_up_q(&wake_q);
raw_spin_unlock_irqrestore_wake(&lock->wait_lock, flags, &wake_q);
preempt_enable();
return 0;

Expand All @@ -720,10 +716,9 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas
__mutex_remove_waiter(lock, &waiter);
err_early_kill:
trace_contention_end(lock, ret);
raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
raw_spin_unlock_irqrestore_wake(&lock->wait_lock, flags, &wake_q);
debug_mutex_free_waiter(&waiter);
mutex_release(&lock->dep_map, ip);
wake_up_q(&wake_q);
preempt_enable();
return ret;
}
Expand Down Expand Up @@ -935,10 +930,7 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne
if (owner & MUTEX_FLAG_HANDOFF)
__mutex_handoff(lock, next);

preempt_disable();
raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
wake_up_q(&wake_q);
preempt_enable();
raw_spin_unlock_irqrestore_wake(&lock->wait_lock, flags, &wake_q);
}

#ifndef CONFIG_DEBUG_LOCK_ALLOC
Expand Down
32 changes: 5 additions & 27 deletions kernel/locking/rtmutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -1292,13 +1292,7 @@ static int __sched task_blocks_on_rt_mutex(struct rt_mutex_base *lock,
*/
get_task_struct(owner);

preempt_disable();
raw_spin_unlock_irq(&lock->wait_lock);
/* wake up any tasks on the wake_q before calling rt_mutex_adjust_prio_chain */
wake_up_q(wake_q);
wake_q_init(wake_q);
preempt_enable();

raw_spin_unlock_irq_wake(&lock->wait_lock, wake_q);

res = rt_mutex_adjust_prio_chain(owner, chwalk, lock,
next_lock, waiter, task);
Expand Down Expand Up @@ -1642,13 +1636,7 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock,
owner = rt_mutex_owner(lock);
else
owner = NULL;
preempt_disable();
raw_spin_unlock_irq(&lock->wait_lock);
if (wake_q) {
wake_up_q(wake_q);
wake_q_init(wake_q);
}
preempt_enable();
raw_spin_unlock_irq_wake(&lock->wait_lock, wake_q);

if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner))
rt_mutex_schedule();
Expand Down Expand Up @@ -1799,10 +1787,7 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock,
*/
raw_spin_lock_irqsave(&lock->wait_lock, flags);
ret = __rt_mutex_slowlock_locked(lock, ww_ctx, state, &wake_q);
preempt_disable();
raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
wake_up_q(&wake_q);
preempt_enable();
raw_spin_unlock_irqrestore_wake(&lock->wait_lock, flags, &wake_q);
rt_mutex_post_schedule();

return ret;
Expand Down Expand Up @@ -1860,11 +1845,7 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock,
owner = rt_mutex_owner(lock);
else
owner = NULL;
preempt_disable();
raw_spin_unlock_irq(&lock->wait_lock);
wake_up_q(wake_q);
wake_q_init(wake_q);
preempt_enable();
raw_spin_unlock_irq_wake(&lock->wait_lock, wake_q);

if (!owner || !rtmutex_spin_on_owner(lock, &waiter, owner))
schedule_rtlock();
Expand Down Expand Up @@ -1893,10 +1874,7 @@ static __always_inline void __sched rtlock_slowlock(struct rt_mutex_base *lock)

raw_spin_lock_irqsave(&lock->wait_lock, flags);
rtlock_slowlock_locked(lock, &wake_q);
preempt_disable();
raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
wake_up_q(&wake_q);
preempt_enable();
raw_spin_unlock_irqrestore_wake(&lock->wait_lock, flags, &wake_q);
}

#endif /* RT_MUTEX_BUILD_SPINLOCKS */
9 changes: 3 additions & 6 deletions kernel/locking/test-ww_mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ static inline u32 prandom_u32_below(u32 ceil)
static int *get_random_order(int count)
{
int *order;
int n, r, tmp;
int n, r;

order = kmalloc_array(count, sizeof(*order), GFP_KERNEL);
if (!order)
Expand All @@ -415,11 +415,8 @@ static int *get_random_order(int count)

for (n = count - 1; n > 1; n--) {
r = prandom_u32_below(n + 1);
if (r != n) {
tmp = order[n];
order[n] = order[r];
order[r] = tmp;
}
if (r != n)
swap(order[n], order[r]);
}

return order;
Expand Down
5 changes: 3 additions & 2 deletions kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,8 @@ static void smp_call_function_many_cond(const struct cpumask *mask,
WARN_ON_ONCE(!in_task());

/* Check if we need local execution. */
if ((scf_flags & SCF_RUN_LOCAL) && cpumask_test_cpu(this_cpu, mask))
if ((scf_flags & SCF_RUN_LOCAL) && cpumask_test_cpu(this_cpu, mask) &&
(!cond_func || cond_func(this_cpu, info)))
run_local = true;

/* Check if we need remote execution, i.e., any CPU excluding this one. */
Expand Down Expand Up @@ -868,7 +869,7 @@ static void smp_call_function_many_cond(const struct cpumask *mask,
send_call_function_ipi_mask(cfd->cpumask_ipi);
}

if (run_local && (!cond_func || cond_func(this_cpu, info))) {
if (run_local) {
unsigned long flags;

local_irq_save(flags);
Expand Down
22 changes: 11 additions & 11 deletions lib/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -1397,9 +1397,9 @@ config PROVE_LOCKING
For more details, see Documentation/locking/lockdep-design.rst.

config PROVE_RAW_LOCK_NESTING
bool
bool "Enable raw_spinlock - spinlock nesting checks" if !ARCH_SUPPORTS_RT
depends on PROVE_LOCKING
default y
default y if ARCH_SUPPORTS_RT
help
Enable the raw_spinlock vs. spinlock nesting checks which ensure
that the lock nesting rules for PREEMPT_RT enabled kernels are
Expand Down Expand Up @@ -1502,41 +1502,41 @@ config LOCKDEP_SMALL
bool

config LOCKDEP_BITS
int "Bitsize for MAX_LOCKDEP_ENTRIES"
int "Size for MAX_LOCKDEP_ENTRIES (as Nth power of 2)"
depends on LOCKDEP && !LOCKDEP_SMALL
range 10 30
range 10 24
default 15
help
Try increasing this value if you hit "BUG: MAX_LOCKDEP_ENTRIES too low!" message.

config LOCKDEP_CHAINS_BITS
int "Bitsize for MAX_LOCKDEP_CHAINS"
int "Size for MAX_LOCKDEP_CHAINS (as Nth power of 2)"
depends on LOCKDEP && !LOCKDEP_SMALL
range 10 21
default 16
help
Try increasing this value if you hit "BUG: MAX_LOCKDEP_CHAINS too low!" message.

config LOCKDEP_STACK_TRACE_BITS
int "Bitsize for MAX_STACK_TRACE_ENTRIES"
int "Size for MAX_STACK_TRACE_ENTRIES (as Nth power of 2)"
depends on LOCKDEP && !LOCKDEP_SMALL
range 10 30
range 10 26
default 19
help
Try increasing this value if you hit "BUG: MAX_STACK_TRACE_ENTRIES too low!" message.

config LOCKDEP_STACK_TRACE_HASH_BITS
int "Bitsize for STACK_TRACE_HASH_SIZE"
int "Size for STACK_TRACE_HASH_SIZE (as Nth power of 2)"
depends on LOCKDEP && !LOCKDEP_SMALL
range 10 30
range 10 26
default 14
help
Try increasing this value if you need large STACK_TRACE_HASH_SIZE.

config LOCKDEP_CIRCULAR_QUEUE_BITS
int "Bitsize for elements in circular_queue struct"
int "Size for elements in circular_queue struct (as Nth power of 2)"
depends on LOCKDEP
range 10 30
range 10 26
default 12
help
Try increasing this value if you hit "lockdep bfs error:-1" warning due to __cq_enqueue() failure.
Expand Down
5 changes: 5 additions & 0 deletions rust/helpers/mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ void rust_helper___mutex_init(struct mutex *mutex, const char *name,
{
__mutex_init(mutex, name, key);
}

void rust_helper_mutex_assert_is_held(struct mutex *mutex)
{
lockdep_assert_held(mutex);
}
5 changes: 5 additions & 0 deletions rust/helpers/spinlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,8 @@ int rust_helper_spin_trylock(spinlock_t *lock)
{
return spin_trylock(lock);
}

void rust_helper_spin_assert_is_held(spinlock_t *lock)
{
lockdep_assert_held(lock);
}
4 changes: 2 additions & 2 deletions rust/kernel/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub mod poll;
pub use arc::{Arc, ArcBorrow, UniqueArc};
pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};
pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy};
pub use lock::mutex::{new_mutex, Mutex};
pub use lock::spinlock::{new_spinlock, SpinLock};
pub use lock::mutex::{new_mutex, Mutex, MutexGuard};
pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard};
pub use locked_by::LockedBy;

/// Represents a lockdep class. It's a wrapper around C's `lock_class_key`.
Expand Down
Loading

0 comments on commit 8838a1a

Please sign in to comment.