Skip to content

Commit

Permalink
Merge tag 'locking-core-2021-04-28' 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:

 - rtmutex cleanup & spring cleaning pass that removes ~400 lines of
   code

 - Futex simplifications & cleanups

 - Add debugging to the CSD code, to help track down a tenacious race
   (or hw problem)

 - Add lockdep_assert_not_held(), to allow code to require a lock to not
   be held, and propagate this into the ath10k driver

 - Misc LKMM documentation updates

 - Misc KCSAN updates: cleanups & documentation updates

 - Misc fixes and cleanups

 - Fix locktorture bugs with ww_mutexes

* tag 'locking-core-2021-04-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (44 commits)
  kcsan: Fix printk format string
  static_call: Relax static_call_update() function argument type
  static_call: Fix unused variable warn w/o MODULE
  locking/rtmutex: Clean up signal handling in __rt_mutex_slowlock()
  locking/rtmutex: Restrict the trylock WARN_ON() to debug
  locking/rtmutex: Fix misleading comment in rt_mutex_postunlock()
  locking/rtmutex: Consolidate the fast/slowpath invocation
  locking/rtmutex: Make text section and inlining consistent
  locking/rtmutex: Move debug functions as inlines into common header
  locking/rtmutex: Decrapify __rt_mutex_init()
  locking/rtmutex: Remove pointless CONFIG_RT_MUTEXES=n stubs
  locking/rtmutex: Inline chainwalk depth check
  locking/rtmutex: Move rt_mutex_debug_task_free() to rtmutex.c
  locking/rtmutex: Remove empty and unused debug stubs
  locking/rtmutex: Consolidate rt_mutex_init()
  locking/rtmutex: Remove output from deadlock detector
  locking/rtmutex: Remove rtmutex deadlock tester leftovers
  locking/rtmutex: Remove rt_mutex_timed_lock()
  MAINTAINERS: Add myself as futex reviewer
  locking/mutex: Remove repeated declaration
  ...
  • Loading branch information
torvalds committed Apr 28, 2021
2 parents 9a45da9 + f4abe99 commit 0ff0edb
Show file tree
Hide file tree
Showing 44 changed files with 1,246 additions and 827 deletions.
10 changes: 10 additions & 0 deletions Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,16 @@
cs89x0_media= [HW,NET]
Format: { rj45 | aui | bnc }

csdlock_debug= [KNL] Enable debug add-ons of cross-CPU function call
handling. When switched on, additional debug data is
printed to the console in case a hanging CPU is
detected, and that CPU is pinged again in order to try
to resolve the hang situation.
0: disable csdlock debugging (default)
1: enable basic csdlock debugging (minor impact)
ext: enable extended csdlock debugging (more impact,
but more data)

dasd= [HW,NET]
See header of drivers/s390/block/dasd_devmap.c.

Expand Down
3 changes: 3 additions & 0 deletions Documentation/dev-tools/kcsan.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.. SPDX-License-Identifier: GPL-2.0
.. Copyright (C) 2019, Google LLC.
The Kernel Concurrency Sanitizer (KCSAN)
========================================

Expand Down
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -7452,6 +7452,7 @@ M: Thomas Gleixner <[email protected]>
M: Ingo Molnar <[email protected]>
R: Peter Zijlstra <[email protected]>
R: Darren Hart <[email protected]>
R: Davidlohr Bueso <[email protected]>
L: [email protected]
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/include/asm/spinlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
* assembler to insert a extra (16-bit) IT instruction, depending on the
* presence or absence of neighbouring conditional instructions.
*
* To avoid this unpredictableness, an approprite IT is inserted explicitly:
* To avoid this unpredictability, an appropriate IT is inserted explicitly:
* the assembler won't change IT instructions which are explicitly present
* in the input.
*/
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/include/asm/jump_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include <linux/stringify.h>
#include <linux/types.h>

static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
{
asm_volatile_goto("1:"
".byte " __stringify(BYTES_NOP5) "\n\t"
Expand All @@ -30,7 +30,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran
return true;
}

static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
{
asm_volatile_goto("1:"
".byte 0xe9\n\t .long %l[l_yes] - 2f\n\t"
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/ath/ath10k/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -4727,6 +4727,8 @@ static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw,
/* Must not be called with conf_mutex held as workers can use that also. */
void ath10k_drain_tx(struct ath10k *ar)
{
lockdep_assert_not_held(&ar->conf_mutex);

/* make sure rcu-protected mac80211 tx path itself is drained */
synchronize_net();

Expand Down
6 changes: 6 additions & 0 deletions include/linux/kcsan-checks.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* KCSAN access checks and modifiers. These can be used to explicitly check
* uninstrumented accesses, or change KCSAN checking behaviour of accesses.
*
* Copyright (C) 2019, Google LLC.
*/

#ifndef _LINUX_KCSAN_CHECKS_H
#define _LINUX_KCSAN_CHECKS_H
Expand Down
7 changes: 7 additions & 0 deletions include/linux/kcsan.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* The Kernel Concurrency Sanitizer (KCSAN) infrastructure. Public interface and
* data structures to set up runtime. See kcsan-checks.h for explicit checks and
* modifiers. For more info please see Documentation/dev-tools/kcsan.rst.
*
* Copyright (C) 2019, Google LLC.
*/

#ifndef _LINUX_KCSAN_H
#define _LINUX_KCSAN_H
Expand Down
20 changes: 16 additions & 4 deletions include/linux/lockdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ extern void lockdep_set_selftest_task(struct task_struct *task);
extern void lockdep_init_task(struct task_struct *task);

/*
* Split the recrursion counter in two to readily detect 'off' vs recursion.
* Split the recursion counter in two to readily detect 'off' vs recursion.
*/
#define LOCKDEP_RECURSION_BITS 16
#define LOCKDEP_OFF (1U << LOCKDEP_RECURSION_BITS)
Expand Down Expand Up @@ -268,6 +268,11 @@ extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass,

extern void lock_release(struct lockdep_map *lock, unsigned long ip);

/* lock_is_held_type() returns */
#define LOCK_STATE_UNKNOWN -1
#define LOCK_STATE_NOT_HELD 0
#define LOCK_STATE_HELD 1

/*
* Same "read" as for lock_acquire(), except -1 means any.
*/
Expand Down Expand Up @@ -301,8 +306,14 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);

#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)

#define lockdep_assert_held(l) do { \
WARN_ON(debug_locks && !lockdep_is_held(l)); \
#define lockdep_assert_held(l) do { \
WARN_ON(debug_locks && \
lockdep_is_held(l) == LOCK_STATE_NOT_HELD); \
} while (0)

#define lockdep_assert_not_held(l) do { \
WARN_ON(debug_locks && \
lockdep_is_held(l) == LOCK_STATE_HELD); \
} while (0)

#define lockdep_assert_held_write(l) do { \
Expand Down Expand Up @@ -397,7 +408,8 @@ extern int lockdep_is_held(const void *);
#define lockdep_is_held_type(l, r) (1)

#define lockdep_assert_held(l) do { (void)(l); } while (0)
#define lockdep_assert_held_write(l) do { (void)(l); } while (0)
#define lockdep_assert_not_held(l) do { (void)(l); } while (0)
#define lockdep_assert_held_write(l) do { (void)(l); } while (0)
#define lockdep_assert_held_read(l) do { (void)(l); } while (0)
#define lockdep_assert_held_once(l) do { (void)(l); } while (0)
#define lockdep_assert_none_held_once() do { } while (0)
Expand Down
4 changes: 1 addition & 3 deletions include/linux/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/osq_lock.h>
#include <linux/debug_locks.h>

struct ww_class;
struct ww_acquire_ctx;

/*
Expand Down Expand Up @@ -65,9 +66,6 @@ struct mutex {
#endif
};

struct ww_class;
struct ww_acquire_ctx;

struct ww_mutex {
struct mutex base;
struct ww_acquire_ctx *ctx;
Expand Down
35 changes: 3 additions & 32 deletions include/linux/rtmutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@ struct rt_mutex {
raw_spinlock_t wait_lock;
struct rb_root_cached waiters;
struct task_struct *owner;
#ifdef CONFIG_DEBUG_RT_MUTEXES
int save_state;
const char *name, *file;
int line;
void *magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
Expand All @@ -46,35 +40,17 @@ struct rt_mutex_waiter;
struct hrtimer_sleeper;

#ifdef CONFIG_DEBUG_RT_MUTEXES
extern int rt_mutex_debug_check_no_locks_freed(const void *from,
unsigned long len);
extern void rt_mutex_debug_check_no_locks_held(struct task_struct *task);
extern void rt_mutex_debug_task_free(struct task_struct *tsk);
#else
static inline int rt_mutex_debug_check_no_locks_freed(const void *from,
unsigned long len)
{
return 0;
}
# define rt_mutex_debug_check_no_locks_held(task) do { } while (0)
static inline void rt_mutex_debug_task_free(struct task_struct *tsk) { }
#endif

#ifdef CONFIG_DEBUG_RT_MUTEXES
# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname) \
, .name = #mutexname, .file = __FILE__, .line = __LINE__

# define rt_mutex_init(mutex) \
#define rt_mutex_init(mutex) \
do { \
static struct lock_class_key __key; \
__rt_mutex_init(mutex, __func__, &__key); \
} while (0)

extern void rt_mutex_debug_task_free(struct task_struct *tsk);
#else
# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname)
# define rt_mutex_init(mutex) __rt_mutex_init(mutex, NULL, NULL)
# define rt_mutex_debug_task_free(t) do { } while (0)
#endif

#ifdef CONFIG_DEBUG_LOCK_ALLOC
#define __DEP_MAP_RT_MUTEX_INITIALIZER(mutexname) \
, .dep_map = { .name = #mutexname }
Expand All @@ -86,7 +62,6 @@ do { \
{ .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(mutexname.wait_lock) \
, .waiters = RB_ROOT_CACHED \
, .owner = NULL \
__DEBUG_RT_MUTEX_INITIALIZER(mutexname) \
__DEP_MAP_RT_MUTEX_INITIALIZER(mutexname)}

#define DEFINE_RT_MUTEX(mutexname) \
Expand All @@ -104,7 +79,6 @@ static inline int rt_mutex_is_locked(struct rt_mutex *lock)
}

extern void __rt_mutex_init(struct rt_mutex *lock, const char *name, struct lock_class_key *key);
extern void rt_mutex_destroy(struct rt_mutex *lock);

#ifdef CONFIG_DEBUG_LOCK_ALLOC
extern void rt_mutex_lock_nested(struct rt_mutex *lock, unsigned int subclass);
Expand All @@ -115,9 +89,6 @@ extern void rt_mutex_lock(struct rt_mutex *lock);
#endif

extern int rt_mutex_lock_interruptible(struct rt_mutex *lock);
extern int rt_mutex_timed_lock(struct rt_mutex *lock,
struct hrtimer_sleeper *timeout);

extern int rt_mutex_trylock(struct rt_mutex *lock);

extern void rt_mutex_unlock(struct rt_mutex *lock);
Expand Down
2 changes: 1 addition & 1 deletion include/linux/rwsem.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ do { \

/*
* This is the same regardless of which rwsem implementation that is being used.
* It is just a heuristic meant to be called by somebody alreadying holding the
* It is just a heuristic meant to be called by somebody already holding the
* rwsem to see if somebody from an incompatible type is wanting access to the
* lock.
*/
Expand Down
4 changes: 2 additions & 2 deletions include/linux/static_call.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ extern void arch_static_call_transform(void *site, void *tramp, void *func, bool

#define static_call_update(name, func) \
({ \
BUILD_BUG_ON(!__same_type(*(func), STATIC_CALL_TRAMP(name))); \
typeof(&STATIC_CALL_TRAMP(name)) __F = (func); \
__static_call_update(&STATIC_CALL_KEY(name), \
STATIC_CALL_TRAMP_ADDR(name), func); \
STATIC_CALL_TRAMP_ADDR(name), __F); \
})

#define static_call_query(name) (READ_ONCE(STATIC_CALL_KEY(name).func))
Expand Down
17 changes: 2 additions & 15 deletions include/linux/ww_mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,39 +48,26 @@ struct ww_acquire_ctx {
#endif
};

#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define __WW_CLASS_MUTEX_INITIALIZER(lockname, class) \
, .ww_class = class
#else
# define __WW_CLASS_MUTEX_INITIALIZER(lockname, class)
#endif

#define __WW_CLASS_INITIALIZER(ww_class, _is_wait_die) \
{ .stamp = ATOMIC_LONG_INIT(0) \
, .acquire_name = #ww_class "_acquire" \
, .mutex_name = #ww_class "_mutex" \
, .is_wait_die = _is_wait_die }

#define __WW_MUTEX_INITIALIZER(lockname, class) \
{ .base = __MUTEX_INITIALIZER(lockname.base) \
__WW_CLASS_MUTEX_INITIALIZER(lockname, class) }

#define DEFINE_WD_CLASS(classname) \
struct ww_class classname = __WW_CLASS_INITIALIZER(classname, 1)

#define DEFINE_WW_CLASS(classname) \
struct ww_class classname = __WW_CLASS_INITIALIZER(classname, 0)

#define DEFINE_WW_MUTEX(mutexname, ww_class) \
struct ww_mutex mutexname = __WW_MUTEX_INITIALIZER(mutexname, ww_class)

/**
* ww_mutex_init - initialize the w/w mutex
* @lock: the mutex to be initialized
* @ww_class: the w/w class the mutex should belong to
*
* Initialize the w/w mutex to unlocked state and associate it with the given
* class.
* class. Static define macro for w/w mutex is not provided and this function
* is the only way to properly initialize the w/w mutex.
*
* It is not allowed to initialize an already locked mutex.
*/
Expand Down
29 changes: 14 additions & 15 deletions kernel/futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,7 @@ static inline void exit_pi_state_list(struct task_struct *curr) { }
* p->pi_lock:
*
* p->pi_state_list -> pi_state->list, relation
* pi_mutex->owner -> pi_state->owner, relation
*
* pi_state->refcount:
*
Expand Down Expand Up @@ -1494,13 +1495,14 @@ static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q)
static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_pi_state *pi_state)
{
u32 curval, newval;
struct rt_mutex_waiter *top_waiter;
struct task_struct *new_owner;
bool postunlock = false;
DEFINE_WAKE_Q(wake_q);
int ret = 0;

new_owner = rt_mutex_next_owner(&pi_state->pi_mutex);
if (WARN_ON_ONCE(!new_owner)) {
top_waiter = rt_mutex_top_waiter(&pi_state->pi_mutex);
if (WARN_ON_ONCE(!top_waiter)) {
/*
* As per the comment in futex_unlock_pi() this should not happen.
*
Expand All @@ -1513,6 +1515,8 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_pi_state *pi_
goto out_unlock;
}

new_owner = top_waiter->task;

/*
* We pass it to the next owner. The WAITERS bit is always kept
* enabled while there is PI state around. We cleanup the owner
Expand Down Expand Up @@ -2315,19 +2319,15 @@ static int unqueue_me(struct futex_q *q)

/*
* PI futexes can not be requeued and must remove themself from the
* hash bucket. The hash bucket lock (i.e. lock_ptr) is held on entry
* and dropped here.
* hash bucket. The hash bucket lock (i.e. lock_ptr) is held.
*/
static void unqueue_me_pi(struct futex_q *q)
__releases(q->lock_ptr)
{
__unqueue_futex(q);

BUG_ON(!q->pi_state);
put_pi_state(q->pi_state);
q->pi_state = NULL;

spin_unlock(q->lock_ptr);
}

static int __fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
Expand Down Expand Up @@ -2909,8 +2909,8 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
if (res)
ret = (res < 0) ? res : 0;

/* Unqueue and drop the lock */
unqueue_me_pi(&q);
spin_unlock(q.lock_ptr);
goto out;

out_unlock_put_key:
Expand Down Expand Up @@ -3237,15 +3237,14 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
* reference count.
*/

/* Check if the requeue code acquired the second futex for us. */
/*
* Check if the requeue code acquired the second futex for us and do
* any pertinent fixup.
*/
if (!q.rt_waiter) {
/*
* Got the lock. We might not be the anticipated owner if we
* did a lock-steal - fix up the PI-state in that case.
*/
if (q.pi_state && (q.pi_state->owner != current)) {
spin_lock(q.lock_ptr);
ret = fixup_pi_state_owner(uaddr2, &q, current);
ret = fixup_owner(uaddr2, &q, true);
/*
* Drop the reference to the pi state which
* the requeue_pi() code acquired for us.
Expand Down Expand Up @@ -3287,8 +3286,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
if (res)
ret = (res < 0) ? res : 0;

/* Unqueue and drop the lock. */
unqueue_me_pi(&q);
spin_unlock(q.lock_ptr);
}

if (ret == -EINTR) {
Expand Down
Loading

0 comments on commit 0ff0edb

Please sign in to comment.