Skip to content

Commit

Permalink
Merge tag 'locking-core-2021-02-17' 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:
 "Core locking primitives updates:
    - Remove mutex_trylock_recursive() from the API - no users left
    - Simplify + constify the futex code a bit

  Lockdep updates:
    - Teach lockdep about local_lock_t
    - Add CONFIG_DEBUG_IRQFLAGS=y debug config option to check for
      potentially unsafe IRQ mask restoration patterns. (I.e.
      calling raw_local_irq_restore() with IRQs enabled.)
    - Add wait context self-tests
    - Fix graph lock corner case corrupting internal data structures
    - Fix noinstr annotations

  LKMM updates:
    - Simplify the litmus tests
    - Documentation fixes

  KCSAN updates:
    - Re-enable KCSAN instrumentation in lib/random32.c

  Misc fixes:
    - Don't branch-trace static label APIs
    - DocBook fix
    - Remove stale leftover empty file"

* tag 'locking-core-2021-02-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits)
  checkpatch: Don't check for mutex_trylock_recursive()
  locking/mutex: Kill mutex_trylock_recursive()
  s390: Use arch_local_irq_{save,restore}() in early boot code
  lockdep: Noinstr annotate warn_bogus_irq_restore()
  locking/lockdep: Avoid unmatched unlock
  locking/rwsem: Remove empty rwsem.h
  locking/rtmutex: Add missing kernel-doc markup
  futex: Remove unneeded gotos
  futex: Change utime parameter to be 'const ... *'
  lockdep: report broken irq restoration
  jump_label: Do not profile branch annotations
  locking: Add Reviewers
  locking/selftests: Add local_lock inversion tests
  locking/lockdep: Exclude local_lock_t from IRQ inversions
  locking/lockdep: Clean up check_redundant() a bit
  locking/lockdep: Add a skip() function to __bfs()
  locking/lockdep: Mark local_lock_t
  locking/selftests: More granular debug_locks_verbose
  lockdep/selftest: Add wait context selftests
  tools/memory-model: Fix typo in klitmus7 compatibility table
  ...
  • Loading branch information
Linus Torvalds committed Feb 21, 2021
2 parents d089f48 + 3765d01 commit 9eef023
Show file tree
Hide file tree
Showing 57 changed files with 617 additions and 294 deletions.
11 changes: 6 additions & 5 deletions Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -802,13 +802,14 @@
insecure, please do not use on production kernels.

debug_locks_verbose=
[KNL] verbose self-tests
Format=<0|1>
[KNL] verbose locking self-tests
Format: <int>
Print debugging info while doing the locking API
self-tests.
We default to 0 (no extra messages), setting it to
1 will print _a lot_ more information - normally
only useful to kernel developers.
Bitmask for the various LOCKTYPE_ tests. Defaults to 0
(no extra messages), setting it to -1 (all bits set)
will print _a_lot_ more information - normally only
useful to lockdep developers.

debug_objects [KNL] Enable object debugging

Expand Down
2 changes: 2 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -10342,6 +10342,8 @@ LOCKING PRIMITIVES
M: Peter Zijlstra <peterz@infradead.org>
M: Ingo Molnar <mingo@redhat.com>
M: Will Deacon <will@kernel.org>
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 Down
4 changes: 2 additions & 2 deletions drivers/s390/char/sclp_early_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb)
unsigned long flags;
int rc;

raw_local_irq_save(flags);
flags = arch_local_irq_save();
rc = sclp_service_call(cmd, sccb);
if (rc)
goto out;
sclp_early_wait_irq();
out:
raw_local_irq_restore(flags);
arch_local_irq_restore(flags);
return rc;
}

Expand Down
2 changes: 2 additions & 0 deletions include/linux/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
#else
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
# define likely_notrace(x) likely(x)
# define unlikely_notrace(x) unlikely(x)
#endif

/* Optimization barrier */
Expand Down
12 changes: 12 additions & 0 deletions include/linux/irqflags.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,17 @@ do { \
# define start_critical_timings() do { } while (0)
#endif

#ifdef CONFIG_DEBUG_IRQFLAGS
extern void warn_bogus_irq_restore(void);
#define raw_check_bogus_irq_restore() \
do { \
if (unlikely(!arch_irqs_disabled())) \
warn_bogus_irq_restore(); \
} while (0)
#else
#define raw_check_bogus_irq_restore() do { } while (0)
#endif

/*
* Wrap the arch provided IRQ routines to provide appropriate checks.
*/
Expand All @@ -162,6 +173,7 @@ do { \
#define raw_local_irq_restore(flags) \
do { \
typecheck(unsigned long, flags); \
raw_check_bogus_irq_restore(); \
arch_local_irq_restore(flags); \
} while (0)
#define raw_local_save_flags(flags) \
Expand Down
12 changes: 6 additions & 6 deletions include/linux/jump_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,14 @@ static __always_inline void jump_label_init(void)

static __always_inline bool static_key_false(struct static_key *key)
{
if (unlikely(static_key_count(key) > 0))
if (unlikely_notrace(static_key_count(key) > 0))
return true;
return false;
}

static __always_inline bool static_key_true(struct static_key *key)
{
if (likely(static_key_count(key) > 0))
if (likely_notrace(static_key_count(key) > 0))
return true;
return false;
}
Expand Down Expand Up @@ -460,7 +460,7 @@ extern bool ____wrong_branch_error(void);
branch = !arch_static_branch_jump(&(x)->key, true); \
else \
branch = ____wrong_branch_error(); \
likely(branch); \
likely_notrace(branch); \
})

#define static_branch_unlikely(x) \
Expand All @@ -472,13 +472,13 @@ extern bool ____wrong_branch_error(void);
branch = arch_static_branch(&(x)->key, false); \
else \
branch = ____wrong_branch_error(); \
unlikely(branch); \
unlikely_notrace(branch); \
})

#else /* !CONFIG_JUMP_LABEL */

#define static_branch_likely(x) likely(static_key_enabled(&(x)->key))
#define static_branch_unlikely(x) unlikely(static_key_enabled(&(x)->key))
#define static_branch_likely(x) likely_notrace(static_key_enabled(&(x)->key))
#define static_branch_unlikely(x) unlikely_notrace(static_key_enabled(&(x)->key))

#endif /* CONFIG_JUMP_LABEL */

Expand Down
5 changes: 4 additions & 1 deletion include/linux/local_lock_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ typedef struct {
.dep_map = { \
.name = #lockname, \
.wait_type_inner = LD_WAIT_CONFIG, \
.lock_type = LD_LOCK_PERCPU, \
}
#else
# define LL_DEP_MAP_INIT(lockname)
Expand All @@ -30,7 +31,9 @@ do { \
static struct lock_class_key __key; \
\
debug_check_no_locks_freed((void *)lock, sizeof(*lock));\
lockdep_init_map_wait(&(lock)->dep_map, #lock, &__key, 0, LD_WAIT_CONFIG);\
lockdep_init_map_type(&(lock)->dep_map, #lock, &__key, 0, \
LD_WAIT_CONFIG, LD_WAIT_INV, \
LD_LOCK_PERCPU); \
} while (0)

#ifdef CONFIG_DEBUG_LOCK_ALLOC
Expand Down
15 changes: 12 additions & 3 deletions include/linux/lockdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,19 @@ extern void lockdep_unregister_key(struct lock_class_key *key);
* to lockdep:
*/

extern void lockdep_init_map_waits(struct lockdep_map *lock, const char *name,
struct lock_class_key *key, int subclass, short inner, short outer);
extern void lockdep_init_map_type(struct lockdep_map *lock, const char *name,
struct lock_class_key *key, int subclass, u8 inner, u8 outer, u8 lock_type);

static inline void
lockdep_init_map_waits(struct lockdep_map *lock, const char *name,
struct lock_class_key *key, int subclass, u8 inner, u8 outer)
{
lockdep_init_map_type(lock, name, key, subclass, inner, LD_WAIT_INV, LD_LOCK_NORMAL);
}

static inline void
lockdep_init_map_wait(struct lockdep_map *lock, const char *name,
struct lock_class_key *key, int subclass, short inner)
struct lock_class_key *key, int subclass, u8 inner)
{
lockdep_init_map_waits(lock, name, key, subclass, inner, LD_WAIT_INV);
}
Expand Down Expand Up @@ -340,6 +347,8 @@ static inline void lockdep_set_selftest_task(struct task_struct *task)
# define lock_set_class(l, n, k, s, i) do { } while (0)
# define lock_set_subclass(l, s, i) do { } while (0)
# define lockdep_init() do { } while (0)
# define lockdep_init_map_type(lock, name, key, sub, inner, outer, type) \
do { (void)(name); (void)(key); } while (0)
# define lockdep_init_map_waits(lock, name, key, sub, inner, outer) \
do { (void)(name); (void)(key); } while (0)
# define lockdep_init_map_wait(lock, name, key, sub, inner) \
Expand Down
18 changes: 14 additions & 4 deletions include/linux/lockdep_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ enum lockdep_wait_type {
LD_WAIT_MAX, /* must be last */
};

enum lockdep_lock_type {
LD_LOCK_NORMAL = 0, /* normal, catch all */
LD_LOCK_PERCPU, /* percpu */
LD_LOCK_MAX,
};

#ifdef CONFIG_LOCKDEP

/*
Expand Down Expand Up @@ -119,8 +125,10 @@ struct lock_class {
int name_version;
const char *name;

short wait_type_inner;
short wait_type_outer;
u8 wait_type_inner;
u8 wait_type_outer;
u8 lock_type;
/* u8 hole; */

#ifdef CONFIG_LOCK_STAT
unsigned long contention_point[LOCKSTAT_POINTS];
Expand Down Expand Up @@ -169,8 +177,10 @@ struct lockdep_map {
struct lock_class_key *key;
struct lock_class *class_cache[NR_LOCKDEP_CACHING_CLASSES];
const char *name;
short wait_type_outer; /* can be taken in this context */
short wait_type_inner; /* presents this context */
u8 wait_type_outer; /* can be taken in this context */
u8 wait_type_inner; /* presents this context */
u8 lock_type;
/* u8 hole; */
#ifdef CONFIG_LOCK_STAT
int cpu;
unsigned long ip;
Expand Down
25 changes: 0 additions & 25 deletions include/linux/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,29 +199,4 @@ extern void mutex_unlock(struct mutex *lock);

extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);

/*
* These values are chosen such that FAIL and SUCCESS match the
* values of the regular mutex_trylock().
*/
enum mutex_trylock_recursive_enum {
MUTEX_TRYLOCK_FAILED = 0,
MUTEX_TRYLOCK_SUCCESS = 1,
MUTEX_TRYLOCK_RECURSIVE,
};

/**
* mutex_trylock_recursive - trylock variant that allows recursive locking
* @lock: mutex to be locked
*
* This function should not be used, _ever_. It is purely for hysterical GEM
* raisins, and once those are gone this will be removed.
*
* Returns:
* - MUTEX_TRYLOCK_FAILED - trylock failed,
* - MUTEX_TRYLOCK_SUCCESS - lock acquired,
* - MUTEX_TRYLOCK_RECURSIVE - we already owned the lock.
*/
extern /* __deprecated */ __must_check enum mutex_trylock_recursive_enum
mutex_trylock_recursive(struct mutex *lock);

#endif /* __LINUX_MUTEX_H */
8 changes: 4 additions & 4 deletions include/linux/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -607,11 +607,11 @@ asmlinkage long sys_unshare(unsigned long unshare_flags);

/* kernel/futex.c */
asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
struct __kernel_timespec __user *utime, u32 __user *uaddr2,
u32 val3);
const struct __kernel_timespec __user *utime,
u32 __user *uaddr2, u32 val3);
asmlinkage long sys_futex_time32(u32 __user *uaddr, int op, u32 val,
struct old_timespec32 __user *utime, u32 __user *uaddr2,
u32 val3);
const struct old_timespec32 __user *utime,
u32 __user *uaddr2, u32 val3);
asmlinkage long sys_get_robust_list(int pid,
struct robust_list_head __user * __user *head_ptr,
size_t __user *len_ptr);
Expand Down
13 changes: 6 additions & 7 deletions kernel/futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -3012,7 +3012,7 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
* Success, we're done! No tricky corner cases.
*/
if (!ret)
goto out_putkey;
return ret;
/*
* The atomic access to the futex value generated a
* pagefault, so retry the user-access and the wakeup:
Expand All @@ -3029,7 +3029,7 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
* wake_futex_pi has detected invalid state. Tell user
* space.
*/
goto out_putkey;
return ret;
}

/*
Expand All @@ -3050,7 +3050,7 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)

default:
WARN_ON_ONCE(1);
goto out_putkey;
return ret;
}
}

Expand All @@ -3061,7 +3061,6 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)

out_unlock:
spin_unlock(&hb->lock);
out_putkey:
return ret;

pi_retry:
Expand Down Expand Up @@ -3763,8 +3762,8 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,


SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
struct __kernel_timespec __user *, utime, u32 __user *, uaddr2,
u32, val3)
const struct __kernel_timespec __user *, utime,
u32 __user *, uaddr2, u32, val3)
{
struct timespec64 ts;
ktime_t t, *tp = NULL;
Expand Down Expand Up @@ -3959,7 +3958,7 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,

#ifdef CONFIG_COMPAT_32BIT_TIME
SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
struct old_timespec32 __user *, utime, u32 __user *, uaddr2,
const struct old_timespec32 __user *, utime, u32 __user *, uaddr2,
u32, val3)
{
struct timespec64 ts;
Expand Down
26 changes: 13 additions & 13 deletions kernel/kcsan/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include <linux/moduleparam.h>
#include <linux/percpu.h>
#include <linux/preempt.h>
#include <linux/random.h>
#include <linux/sched.h>
#include <linux/uaccess.h>

Expand Down Expand Up @@ -101,7 +100,7 @@ static atomic_long_t watchpoints[CONFIG_KCSAN_NUM_WATCHPOINTS + NUM_SLOTS-1];
static DEFINE_PER_CPU(long, kcsan_skip);

/* For kcsan_prandom_u32_max(). */
static DEFINE_PER_CPU(struct rnd_state, kcsan_rand_state);
static DEFINE_PER_CPU(u32, kcsan_rand_state);

static __always_inline atomic_long_t *find_watchpoint(unsigned long addr,
size_t size,
Expand Down Expand Up @@ -275,20 +274,17 @@ should_watch(const volatile void *ptr, size_t size, int type, struct kcsan_ctx *
}

/*
* Returns a pseudo-random number in interval [0, ep_ro). See prandom_u32_max()
* for more details.
*
* The open-coded version here is using only safe primitives for all contexts
* where we can have KCSAN instrumentation. In particular, we cannot use
* prandom_u32() directly, as its tracepoint could cause recursion.
* Returns a pseudo-random number in interval [0, ep_ro). Simple linear
* congruential generator, using constants from "Numerical Recipes".
*/
static u32 kcsan_prandom_u32_max(u32 ep_ro)
{
struct rnd_state *state = &get_cpu_var(kcsan_rand_state);
const u32 res = prandom_u32_state(state);
u32 state = this_cpu_read(kcsan_rand_state);

state = 1664525 * state + 1013904223;
this_cpu_write(kcsan_rand_state, state);

put_cpu_var(kcsan_rand_state);
return (u32)(((u64) res * ep_ro) >> 32);
return state % ep_ro;
}

static inline void reset_kcsan_skip(void)
Expand Down Expand Up @@ -639,10 +635,14 @@ static __always_inline void check_access(const volatile void *ptr, size_t size,

void __init kcsan_init(void)
{
int cpu;

BUG_ON(!in_task());

kcsan_debugfs_init();
prandom_seed_full_state(&kcsan_rand_state);

for_each_possible_cpu(cpu)
per_cpu(kcsan_rand_state, cpu) = (u32)get_cycles();

/*
* We are in the init task, and no other tasks should be running;
Expand Down
1 change: 1 addition & 0 deletions kernel/locking/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ CFLAGS_REMOVE_mutex-debug.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_rtmutex-debug.o = $(CC_FLAGS_FTRACE)
endif

obj-$(CONFIG_DEBUG_IRQFLAGS) += irqflag-debug.o
obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
obj-$(CONFIG_LOCKDEP) += lockdep.o
ifeq ($(CONFIG_PROC_FS),y)
Expand Down
13 changes: 13 additions & 0 deletions kernel/locking/irqflag-debug.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only

#include <linux/bug.h>
#include <linux/export.h>
#include <linux/irqflags.h>

noinstr void warn_bogus_irq_restore(void)
{
instrumentation_begin();
WARN_ONCE(1, "raw_local_irq_restore() called with IRQs enabled\n");
instrumentation_end();
}
EXPORT_SYMBOL(warn_bogus_irq_restore);
Loading

0 comments on commit 9eef023

Please sign in to comment.