Merge tag 'locking-core-2021-02-17' of git://git.kernel.org/pub/scm/linux/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
...
This commit is contained in:
@@ -3012,7 +3012,7 @@ retry:
|
||||
* 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:
|
||||
@@ -3029,7 +3029,7 @@ retry:
|
||||
* wake_futex_pi has detected invalid state. Tell user
|
||||
* space.
|
||||
*/
|
||||
goto out_putkey;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3050,7 +3050,7 @@ retry:
|
||||
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
goto out_putkey;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3061,7 +3061,6 @@ retry:
|
||||
|
||||
out_unlock:
|
||||
spin_unlock(&hb->lock);
|
||||
out_putkey:
|
||||
return ret;
|
||||
|
||||
pi_retry:
|
||||
@@ -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;
|
||||
@@ -3959,7 +3958,7 @@ err_unlock:
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
@@ -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);
|
||||
|
||||
put_cpu_var(kcsan_rand_state);
|
||||
return (u32)(((u64) res * ep_ro) >> 32);
|
||||
state = 1664525 * state + 1013904223;
|
||||
this_cpu_write(kcsan_rand_state, state);
|
||||
|
||||
return state % ep_ro;
|
||||
}
|
||||
|
||||
static inline void reset_kcsan_skip(void)
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
13
kernel/locking/irqflag-debug.c
Normal file
13
kernel/locking/irqflag-debug.c
Normal file
@@ -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);
|
||||
@@ -1290,6 +1290,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
|
||||
class->name_version = count_matching_names(class);
|
||||
class->wait_type_inner = lock->wait_type_inner;
|
||||
class->wait_type_outer = lock->wait_type_outer;
|
||||
class->lock_type = lock->lock_type;
|
||||
/*
|
||||
* We use RCU's safe list-add method to make
|
||||
* parallel walking of the hash-list safe:
|
||||
@@ -1671,6 +1672,7 @@ static inline struct lock_list *__bfs_next(struct lock_list *lock, int offset)
|
||||
static enum bfs_result __bfs(struct lock_list *source_entry,
|
||||
void *data,
|
||||
bool (*match)(struct lock_list *entry, void *data),
|
||||
bool (*skip)(struct lock_list *entry, void *data),
|
||||
struct lock_list **target_entry,
|
||||
int offset)
|
||||
{
|
||||
@@ -1731,7 +1733,12 @@ static enum bfs_result __bfs(struct lock_list *source_entry,
|
||||
/*
|
||||
* Step 3: we haven't visited this and there is a strong
|
||||
* dependency path to this, so check with @match.
|
||||
* If @skip is provide and returns true, we skip this
|
||||
* lock (and any path this lock is in).
|
||||
*/
|
||||
if (skip && skip(lock, data))
|
||||
continue;
|
||||
|
||||
if (match(lock, data)) {
|
||||
*target_entry = lock;
|
||||
return BFS_RMATCH;
|
||||
@@ -1774,9 +1781,10 @@ static inline enum bfs_result
|
||||
__bfs_forwards(struct lock_list *src_entry,
|
||||
void *data,
|
||||
bool (*match)(struct lock_list *entry, void *data),
|
||||
bool (*skip)(struct lock_list *entry, void *data),
|
||||
struct lock_list **target_entry)
|
||||
{
|
||||
return __bfs(src_entry, data, match, target_entry,
|
||||
return __bfs(src_entry, data, match, skip, target_entry,
|
||||
offsetof(struct lock_class, locks_after));
|
||||
|
||||
}
|
||||
@@ -1785,9 +1793,10 @@ static inline enum bfs_result
|
||||
__bfs_backwards(struct lock_list *src_entry,
|
||||
void *data,
|
||||
bool (*match)(struct lock_list *entry, void *data),
|
||||
bool (*skip)(struct lock_list *entry, void *data),
|
||||
struct lock_list **target_entry)
|
||||
{
|
||||
return __bfs(src_entry, data, match, target_entry,
|
||||
return __bfs(src_entry, data, match, skip, target_entry,
|
||||
offsetof(struct lock_class, locks_before));
|
||||
|
||||
}
|
||||
@@ -2018,7 +2027,7 @@ static unsigned long __lockdep_count_forward_deps(struct lock_list *this)
|
||||
unsigned long count = 0;
|
||||
struct lock_list *target_entry;
|
||||
|
||||
__bfs_forwards(this, (void *)&count, noop_count, &target_entry);
|
||||
__bfs_forwards(this, (void *)&count, noop_count, NULL, &target_entry);
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -2043,7 +2052,7 @@ static unsigned long __lockdep_count_backward_deps(struct lock_list *this)
|
||||
unsigned long count = 0;
|
||||
struct lock_list *target_entry;
|
||||
|
||||
__bfs_backwards(this, (void *)&count, noop_count, &target_entry);
|
||||
__bfs_backwards(this, (void *)&count, noop_count, NULL, &target_entry);
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -2071,11 +2080,12 @@ unsigned long lockdep_count_backward_deps(struct lock_class *class)
|
||||
static noinline enum bfs_result
|
||||
check_path(struct held_lock *target, struct lock_list *src_entry,
|
||||
bool (*match)(struct lock_list *entry, void *data),
|
||||
bool (*skip)(struct lock_list *entry, void *data),
|
||||
struct lock_list **target_entry)
|
||||
{
|
||||
enum bfs_result ret;
|
||||
|
||||
ret = __bfs_forwards(src_entry, target, match, target_entry);
|
||||
ret = __bfs_forwards(src_entry, target, match, skip, target_entry);
|
||||
|
||||
if (unlikely(bfs_error(ret)))
|
||||
print_bfs_bug(ret);
|
||||
@@ -2102,7 +2112,7 @@ check_noncircular(struct held_lock *src, struct held_lock *target,
|
||||
|
||||
debug_atomic_inc(nr_cyclic_checks);
|
||||
|
||||
ret = check_path(target, &src_entry, hlock_conflict, &target_entry);
|
||||
ret = check_path(target, &src_entry, hlock_conflict, NULL, &target_entry);
|
||||
|
||||
if (unlikely(ret == BFS_RMATCH)) {
|
||||
if (!*trace) {
|
||||
@@ -2120,46 +2130,6 @@ check_noncircular(struct held_lock *src, struct held_lock *target,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LOCKDEP_SMALL
|
||||
/*
|
||||
* Check that the dependency graph starting at <src> can lead to
|
||||
* <target> or not. If it can, <src> -> <target> dependency is already
|
||||
* in the graph.
|
||||
*
|
||||
* Return BFS_RMATCH if it does, or BFS_RMATCH if it does not, return BFS_E* if
|
||||
* any error appears in the bfs search.
|
||||
*/
|
||||
static noinline enum bfs_result
|
||||
check_redundant(struct held_lock *src, struct held_lock *target)
|
||||
{
|
||||
enum bfs_result ret;
|
||||
struct lock_list *target_entry;
|
||||
struct lock_list src_entry;
|
||||
|
||||
bfs_init_root(&src_entry, src);
|
||||
/*
|
||||
* Special setup for check_redundant().
|
||||
*
|
||||
* To report redundant, we need to find a strong dependency path that
|
||||
* is equal to or stronger than <src> -> <target>. So if <src> is E,
|
||||
* we need to let __bfs() only search for a path starting at a -(E*)->,
|
||||
* we achieve this by setting the initial node's ->only_xr to true in
|
||||
* that case. And if <prev> is S, we set initial ->only_xr to false
|
||||
* because both -(S*)-> (equal) and -(E*)-> (stronger) are redundant.
|
||||
*/
|
||||
src_entry.only_xr = src->read == 0;
|
||||
|
||||
debug_atomic_inc(nr_redundant_checks);
|
||||
|
||||
ret = check_path(target, &src_entry, hlock_equal, &target_entry);
|
||||
|
||||
if (ret == BFS_RMATCH)
|
||||
debug_atomic_inc(nr_redundant);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
|
||||
/*
|
||||
@@ -2230,6 +2200,44 @@ static inline bool usage_match(struct lock_list *entry, void *mask)
|
||||
return !!((entry->class->usage_mask & LOCKF_IRQ) & *(unsigned long *)mask);
|
||||
}
|
||||
|
||||
static inline bool usage_skip(struct lock_list *entry, void *mask)
|
||||
{
|
||||
/*
|
||||
* Skip local_lock() for irq inversion detection.
|
||||
*
|
||||
* For !RT, local_lock() is not a real lock, so it won't carry any
|
||||
* dependency.
|
||||
*
|
||||
* For RT, an irq inversion happens when we have lock A and B, and on
|
||||
* some CPU we can have:
|
||||
*
|
||||
* lock(A);
|
||||
* <interrupted>
|
||||
* lock(B);
|
||||
*
|
||||
* where lock(B) cannot sleep, and we have a dependency B -> ... -> A.
|
||||
*
|
||||
* Now we prove local_lock() cannot exist in that dependency. First we
|
||||
* have the observation for any lock chain L1 -> ... -> Ln, for any
|
||||
* 1 <= i <= n, Li.inner_wait_type <= L1.inner_wait_type, otherwise
|
||||
* wait context check will complain. And since B is not a sleep lock,
|
||||
* therefore B.inner_wait_type >= 2, and since the inner_wait_type of
|
||||
* local_lock() is 3, which is greater than 2, therefore there is no
|
||||
* way the local_lock() exists in the dependency B -> ... -> A.
|
||||
*
|
||||
* As a result, we will skip local_lock(), when we search for irq
|
||||
* inversion bugs.
|
||||
*/
|
||||
if (entry->class->lock_type == LD_LOCK_PERCPU) {
|
||||
if (DEBUG_LOCKS_WARN_ON(entry->class->wait_type_inner < LD_WAIT_CONFIG))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a node in the forwards-direction dependency sub-graph starting
|
||||
* at @root->class that matches @bit.
|
||||
@@ -2245,7 +2253,7 @@ find_usage_forwards(struct lock_list *root, unsigned long usage_mask,
|
||||
|
||||
debug_atomic_inc(nr_find_usage_forwards_checks);
|
||||
|
||||
result = __bfs_forwards(root, &usage_mask, usage_match, target_entry);
|
||||
result = __bfs_forwards(root, &usage_mask, usage_match, usage_skip, target_entry);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -2262,7 +2270,7 @@ find_usage_backwards(struct lock_list *root, unsigned long usage_mask,
|
||||
|
||||
debug_atomic_inc(nr_find_usage_backwards_checks);
|
||||
|
||||
result = __bfs_backwards(root, &usage_mask, usage_match, target_entry);
|
||||
result = __bfs_backwards(root, &usage_mask, usage_match, usage_skip, target_entry);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -2627,7 +2635,7 @@ static int check_irq_usage(struct task_struct *curr, struct held_lock *prev,
|
||||
*/
|
||||
bfs_init_rootb(&this, prev);
|
||||
|
||||
ret = __bfs_backwards(&this, &usage_mask, usage_accumulate, NULL);
|
||||
ret = __bfs_backwards(&this, &usage_mask, usage_accumulate, usage_skip, NULL);
|
||||
if (bfs_error(ret)) {
|
||||
print_bfs_bug(ret);
|
||||
return 0;
|
||||
@@ -2694,8 +2702,68 @@ static inline int check_irq_usage(struct task_struct *curr,
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool usage_skip(struct lock_list *entry, void *mask)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TRACE_IRQFLAGS */
|
||||
|
||||
#ifdef CONFIG_LOCKDEP_SMALL
|
||||
/*
|
||||
* Check that the dependency graph starting at <src> can lead to
|
||||
* <target> or not. If it can, <src> -> <target> dependency is already
|
||||
* in the graph.
|
||||
*
|
||||
* Return BFS_RMATCH if it does, or BFS_RMATCH if it does not, return BFS_E* if
|
||||
* any error appears in the bfs search.
|
||||
*/
|
||||
static noinline enum bfs_result
|
||||
check_redundant(struct held_lock *src, struct held_lock *target)
|
||||
{
|
||||
enum bfs_result ret;
|
||||
struct lock_list *target_entry;
|
||||
struct lock_list src_entry;
|
||||
|
||||
bfs_init_root(&src_entry, src);
|
||||
/*
|
||||
* Special setup for check_redundant().
|
||||
*
|
||||
* To report redundant, we need to find a strong dependency path that
|
||||
* is equal to or stronger than <src> -> <target>. So if <src> is E,
|
||||
* we need to let __bfs() only search for a path starting at a -(E*)->,
|
||||
* we achieve this by setting the initial node's ->only_xr to true in
|
||||
* that case. And if <prev> is S, we set initial ->only_xr to false
|
||||
* because both -(S*)-> (equal) and -(E*)-> (stronger) are redundant.
|
||||
*/
|
||||
src_entry.only_xr = src->read == 0;
|
||||
|
||||
debug_atomic_inc(nr_redundant_checks);
|
||||
|
||||
/*
|
||||
* Note: we skip local_lock() for redundant check, because as the
|
||||
* comment in usage_skip(), A -> local_lock() -> B and A -> B are not
|
||||
* the same.
|
||||
*/
|
||||
ret = check_path(target, &src_entry, hlock_equal, usage_skip, &target_entry);
|
||||
|
||||
if (ret == BFS_RMATCH)
|
||||
debug_atomic_inc(nr_redundant);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline enum bfs_result
|
||||
check_redundant(struct held_lock *src, struct held_lock *target)
|
||||
{
|
||||
return BFS_RNOMATCH;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void inc_chains(int irq_context)
|
||||
{
|
||||
if (irq_context & LOCK_CHAIN_HARDIRQ_CONTEXT)
|
||||
@@ -2916,7 +2984,6 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LOCKDEP_SMALL
|
||||
/*
|
||||
* Is the <prev> -> <next> link redundant?
|
||||
*/
|
||||
@@ -2925,7 +2992,6 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
|
||||
return 0;
|
||||
else if (ret == BFS_RMATCH)
|
||||
return 2;
|
||||
#endif
|
||||
|
||||
if (!*trace) {
|
||||
*trace = save_trace();
|
||||
@@ -3707,7 +3773,7 @@ static void
|
||||
print_usage_bug(struct task_struct *curr, struct held_lock *this,
|
||||
enum lock_usage_bit prev_bit, enum lock_usage_bit new_bit)
|
||||
{
|
||||
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
|
||||
if (!debug_locks_off() || debug_locks_silent)
|
||||
return;
|
||||
|
||||
pr_warn("\n");
|
||||
@@ -3748,6 +3814,7 @@ valid_state(struct task_struct *curr, struct held_lock *this,
|
||||
enum lock_usage_bit new_bit, enum lock_usage_bit bad_bit)
|
||||
{
|
||||
if (unlikely(hlock_class(this)->usage_mask & (1 << bad_bit))) {
|
||||
graph_unlock();
|
||||
print_usage_bug(curr, this, bad_bit, new_bit);
|
||||
return 0;
|
||||
}
|
||||
@@ -4503,9 +4570,9 @@ print_lock_invalid_wait_context(struct task_struct *curr,
|
||||
*/
|
||||
static int check_wait_context(struct task_struct *curr, struct held_lock *next)
|
||||
{
|
||||
short next_inner = hlock_class(next)->wait_type_inner;
|
||||
short next_outer = hlock_class(next)->wait_type_outer;
|
||||
short curr_inner;
|
||||
u8 next_inner = hlock_class(next)->wait_type_inner;
|
||||
u8 next_outer = hlock_class(next)->wait_type_outer;
|
||||
u8 curr_inner;
|
||||
int depth;
|
||||
|
||||
if (!curr->lockdep_depth || !next_inner || next->trylock)
|
||||
@@ -4528,7 +4595,7 @@ static int check_wait_context(struct task_struct *curr, struct held_lock *next)
|
||||
|
||||
for (; depth < curr->lockdep_depth; depth++) {
|
||||
struct held_lock *prev = curr->held_locks + depth;
|
||||
short prev_inner = hlock_class(prev)->wait_type_inner;
|
||||
u8 prev_inner = hlock_class(prev)->wait_type_inner;
|
||||
|
||||
if (prev_inner) {
|
||||
/*
|
||||
@@ -4577,9 +4644,9 @@ static inline int check_wait_context(struct task_struct *curr,
|
||||
/*
|
||||
* Initialize a lock instance's lock-class mapping info:
|
||||
*/
|
||||
void lockdep_init_map_waits(struct lockdep_map *lock, const char *name,
|
||||
void lockdep_init_map_type(struct lockdep_map *lock, const char *name,
|
||||
struct lock_class_key *key, int subclass,
|
||||
short inner, short outer)
|
||||
u8 inner, u8 outer, u8 lock_type)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -4602,6 +4669,7 @@ void lockdep_init_map_waits(struct lockdep_map *lock, const char *name,
|
||||
|
||||
lock->wait_type_outer = outer;
|
||||
lock->wait_type_inner = inner;
|
||||
lock->lock_type = lock_type;
|
||||
|
||||
/*
|
||||
* No key, no joy, we need to hash something.
|
||||
@@ -4636,7 +4704,7 @@ void lockdep_init_map_waits(struct lockdep_map *lock, const char *name,
|
||||
raw_local_irq_restore(flags);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lockdep_init_map_waits);
|
||||
EXPORT_SYMBOL_GPL(lockdep_init_map_type);
|
||||
|
||||
struct lock_class_key __lockdep_no_validate__;
|
||||
EXPORT_SYMBOL_GPL(__lockdep_no_validate__);
|
||||
|
||||
@@ -86,16 +86,6 @@ bool mutex_is_locked(struct mutex *lock)
|
||||
}
|
||||
EXPORT_SYMBOL(mutex_is_locked);
|
||||
|
||||
__must_check enum mutex_trylock_recursive_enum
|
||||
mutex_trylock_recursive(struct mutex *lock)
|
||||
{
|
||||
if (unlikely(__mutex_owner(lock) == current))
|
||||
return MUTEX_TRYLOCK_RECURSIVE;
|
||||
|
||||
return mutex_trylock(lock);
|
||||
}
|
||||
EXPORT_SYMBOL(mutex_trylock_recursive);
|
||||
|
||||
static inline unsigned long __owner_flags(unsigned long owner)
|
||||
{
|
||||
return owner & MUTEX_FLAGS;
|
||||
|
||||
@@ -1604,8 +1604,11 @@ void __sched rt_mutex_unlock(struct rt_mutex *lock)
|
||||
EXPORT_SYMBOL_GPL(rt_mutex_unlock);
|
||||
|
||||
/**
|
||||
* Futex variant, that since futex variants do not use the fast-path, can be
|
||||
* simple and will not need to retry.
|
||||
* __rt_mutex_futex_unlock - Futex variant, that since futex variants
|
||||
* do not use the fast-path, can be simple and will not need to retry.
|
||||
*
|
||||
* @lock: The rt_mutex to be unlocked
|
||||
* @wake_q: The wake queue head from which to get the next lock waiter
|
||||
*/
|
||||
bool __sched __rt_mutex_futex_unlock(struct rt_mutex *lock,
|
||||
struct wake_q_head *wake_q)
|
||||
@@ -1662,13 +1665,15 @@ void rt_mutex_destroy(struct rt_mutex *lock)
|
||||
EXPORT_SYMBOL_GPL(rt_mutex_destroy);
|
||||
|
||||
/**
|
||||
* __rt_mutex_init - initialize the rt lock
|
||||
* __rt_mutex_init - initialize the rt_mutex
|
||||
*
|
||||
* @lock: the rt lock to be initialized
|
||||
* @lock: The rt_mutex to be initialized
|
||||
* @name: The lock name used for debugging
|
||||
* @key: The lock class key used for debugging
|
||||
*
|
||||
* Initialize the rt lock to unlocked state.
|
||||
* Initialize the rt_mutex to unlocked state.
|
||||
*
|
||||
* Initializing of a locked rt lock is not allowed
|
||||
* Initializing of a locked rt_mutex is not allowed
|
||||
*/
|
||||
void __rt_mutex_init(struct rt_mutex *lock, const char *name,
|
||||
struct lock_class_key *key)
|
||||
|
||||
Reference in New Issue
Block a user