Merge branch 'WIP.locking/seqlocks' into locking/urgent
Pick up the full seqlock series PeterZ is working on. Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
a703f3633f
|
@ -14,6 +14,7 @@ locking
|
||||||
mutex-design
|
mutex-design
|
||||||
rt-mutex-design
|
rt-mutex-design
|
||||||
rt-mutex
|
rt-mutex
|
||||||
|
seqlock
|
||||||
spinlocks
|
spinlocks
|
||||||
ww-mutex-design
|
ww-mutex-design
|
||||||
preempt-locking
|
preempt-locking
|
||||||
|
|
|
@ -18,7 +18,7 @@ as an alternative to these. This new data structure provided a number
|
||||||
of advantages, including simpler interfaces, and at that time smaller
|
of advantages, including simpler interfaces, and at that time smaller
|
||||||
code (see Disadvantages).
|
code (see Disadvantages).
|
||||||
|
|
||||||
[1] http://lwn.net/Articles/164802/
|
[1] https://lwn.net/Articles/164802/
|
||||||
|
|
||||||
Implementation
|
Implementation
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -0,0 +1,222 @@
|
||||||
|
======================================
|
||||||
|
Sequence counters and sequential locks
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
Sequence counters are a reader-writer consistency mechanism with
|
||||||
|
lockless readers (read-only retry loops), and no writer starvation. They
|
||||||
|
are used for data that's rarely written to (e.g. system time), where the
|
||||||
|
reader wants a consistent set of information and is willing to retry if
|
||||||
|
that information changes.
|
||||||
|
|
||||||
|
A data set is consistent when the sequence count at the beginning of the
|
||||||
|
read side critical section is even and the same sequence count value is
|
||||||
|
read again at the end of the critical section. The data in the set must
|
||||||
|
be copied out inside the read side critical section. If the sequence
|
||||||
|
count has changed between the start and the end of the critical section,
|
||||||
|
the reader must retry.
|
||||||
|
|
||||||
|
Writers increment the sequence count at the start and the end of their
|
||||||
|
critical section. After starting the critical section the sequence count
|
||||||
|
is odd and indicates to the readers that an update is in progress. At
|
||||||
|
the end of the write side critical section the sequence count becomes
|
||||||
|
even again which lets readers make progress.
|
||||||
|
|
||||||
|
A sequence counter write side critical section must never be preempted
|
||||||
|
or interrupted by read side sections. Otherwise the reader will spin for
|
||||||
|
the entire scheduler tick due to the odd sequence count value and the
|
||||||
|
interrupted writer. If that reader belongs to a real-time scheduling
|
||||||
|
class, it can spin forever and the kernel will livelock.
|
||||||
|
|
||||||
|
This mechanism cannot be used if the protected data contains pointers,
|
||||||
|
as the writer can invalidate a pointer that the reader is following.
|
||||||
|
|
||||||
|
|
||||||
|
.. _seqcount_t:
|
||||||
|
|
||||||
|
Sequence counters (``seqcount_t``)
|
||||||
|
==================================
|
||||||
|
|
||||||
|
This is the the raw counting mechanism, which does not protect against
|
||||||
|
multiple writers. Write side critical sections must thus be serialized
|
||||||
|
by an external lock.
|
||||||
|
|
||||||
|
If the write serialization primitive is not implicitly disabling
|
||||||
|
preemption, preemption must be explicitly disabled before entering the
|
||||||
|
write side section. If the read section can be invoked from hardirq or
|
||||||
|
softirq contexts, interrupts or bottom halves must also be respectively
|
||||||
|
disabled before entering the write section.
|
||||||
|
|
||||||
|
If it's desired to automatically handle the sequence counter
|
||||||
|
requirements of writer serialization and non-preemptibility, use
|
||||||
|
:ref:`seqlock_t` instead.
|
||||||
|
|
||||||
|
Initialization::
|
||||||
|
|
||||||
|
/* dynamic */
|
||||||
|
seqcount_t foo_seqcount;
|
||||||
|
seqcount_init(&foo_seqcount);
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
static seqcount_t foo_seqcount = SEQCNT_ZERO(foo_seqcount);
|
||||||
|
|
||||||
|
/* C99 struct init */
|
||||||
|
struct {
|
||||||
|
.seq = SEQCNT_ZERO(foo.seq),
|
||||||
|
} foo;
|
||||||
|
|
||||||
|
Write path::
|
||||||
|
|
||||||
|
/* Serialized context with disabled preemption */
|
||||||
|
|
||||||
|
write_seqcount_begin(&foo_seqcount);
|
||||||
|
|
||||||
|
/* ... [[write-side critical section]] ... */
|
||||||
|
|
||||||
|
write_seqcount_end(&foo_seqcount);
|
||||||
|
|
||||||
|
Read path::
|
||||||
|
|
||||||
|
do {
|
||||||
|
seq = read_seqcount_begin(&foo_seqcount);
|
||||||
|
|
||||||
|
/* ... [[read-side critical section]] ... */
|
||||||
|
|
||||||
|
} while (read_seqcount_retry(&foo_seqcount, seq));
|
||||||
|
|
||||||
|
|
||||||
|
.. _seqcount_locktype_t:
|
||||||
|
|
||||||
|
Sequence counters with associated locks (``seqcount_LOCKTYPE_t``)
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
|
As discussed at :ref:`seqcount_t`, sequence count write side critical
|
||||||
|
sections must be serialized and non-preemptible. This variant of
|
||||||
|
sequence counters associate the lock used for writer serialization at
|
||||||
|
initialization time, which enables lockdep to validate that the write
|
||||||
|
side critical sections are properly serialized.
|
||||||
|
|
||||||
|
This lock association is a NOOP if lockdep is disabled and has neither
|
||||||
|
storage nor runtime overhead. If lockdep is enabled, the lock pointer is
|
||||||
|
stored in struct seqcount and lockdep's "lock is held" assertions are
|
||||||
|
injected at the beginning of the write side critical section to validate
|
||||||
|
that it is properly protected.
|
||||||
|
|
||||||
|
For lock types which do not implicitly disable preemption, preemption
|
||||||
|
protection is enforced in the write side function.
|
||||||
|
|
||||||
|
The following sequence counters with associated locks are defined:
|
||||||
|
|
||||||
|
- ``seqcount_spinlock_t``
|
||||||
|
- ``seqcount_raw_spinlock_t``
|
||||||
|
- ``seqcount_rwlock_t``
|
||||||
|
- ``seqcount_mutex_t``
|
||||||
|
- ``seqcount_ww_mutex_t``
|
||||||
|
|
||||||
|
The plain seqcount read and write APIs branch out to the specific
|
||||||
|
seqcount_LOCKTYPE_t implementation at compile-time. This avoids kernel
|
||||||
|
API explosion per each new seqcount LOCKTYPE.
|
||||||
|
|
||||||
|
Initialization (replace "LOCKTYPE" with one of the supported locks)::
|
||||||
|
|
||||||
|
/* dynamic */
|
||||||
|
seqcount_LOCKTYPE_t foo_seqcount;
|
||||||
|
seqcount_LOCKTYPE_init(&foo_seqcount, &lock);
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
static seqcount_LOCKTYPE_t foo_seqcount =
|
||||||
|
SEQCNT_LOCKTYPE_ZERO(foo_seqcount, &lock);
|
||||||
|
|
||||||
|
/* C99 struct init */
|
||||||
|
struct {
|
||||||
|
.seq = SEQCNT_LOCKTYPE_ZERO(foo.seq, &lock),
|
||||||
|
} foo;
|
||||||
|
|
||||||
|
Write path: same as in :ref:`seqcount_t`, while running from a context
|
||||||
|
with the associated LOCKTYPE lock acquired.
|
||||||
|
|
||||||
|
Read path: same as in :ref:`seqcount_t`.
|
||||||
|
|
||||||
|
.. _seqlock_t:
|
||||||
|
|
||||||
|
Sequential locks (``seqlock_t``)
|
||||||
|
================================
|
||||||
|
|
||||||
|
This contains the :ref:`seqcount_t` mechanism earlier discussed, plus an
|
||||||
|
embedded spinlock for writer serialization and non-preemptibility.
|
||||||
|
|
||||||
|
If the read side section can be invoked from hardirq or softirq context,
|
||||||
|
use the write side function variants which disable interrupts or bottom
|
||||||
|
halves respectively.
|
||||||
|
|
||||||
|
Initialization::
|
||||||
|
|
||||||
|
/* dynamic */
|
||||||
|
seqlock_t foo_seqlock;
|
||||||
|
seqlock_init(&foo_seqlock);
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
static DEFINE_SEQLOCK(foo_seqlock);
|
||||||
|
|
||||||
|
/* C99 struct init */
|
||||||
|
struct {
|
||||||
|
.seql = __SEQLOCK_UNLOCKED(foo.seql)
|
||||||
|
} foo;
|
||||||
|
|
||||||
|
Write path::
|
||||||
|
|
||||||
|
write_seqlock(&foo_seqlock);
|
||||||
|
|
||||||
|
/* ... [[write-side critical section]] ... */
|
||||||
|
|
||||||
|
write_sequnlock(&foo_seqlock);
|
||||||
|
|
||||||
|
Read path, three categories:
|
||||||
|
|
||||||
|
1. Normal Sequence readers which never block a writer but they must
|
||||||
|
retry if a writer is in progress by detecting change in the sequence
|
||||||
|
number. Writers do not wait for a sequence reader::
|
||||||
|
|
||||||
|
do {
|
||||||
|
seq = read_seqbegin(&foo_seqlock);
|
||||||
|
|
||||||
|
/* ... [[read-side critical section]] ... */
|
||||||
|
|
||||||
|
} while (read_seqretry(&foo_seqlock, seq));
|
||||||
|
|
||||||
|
2. Locking readers which will wait if a writer or another locking reader
|
||||||
|
is in progress. A locking reader in progress will also block a writer
|
||||||
|
from entering its critical section. This read lock is
|
||||||
|
exclusive. Unlike rwlock_t, only one locking reader can acquire it::
|
||||||
|
|
||||||
|
read_seqlock_excl(&foo_seqlock);
|
||||||
|
|
||||||
|
/* ... [[read-side critical section]] ... */
|
||||||
|
|
||||||
|
read_sequnlock_excl(&foo_seqlock);
|
||||||
|
|
||||||
|
3. Conditional lockless reader (as in 1), or locking reader (as in 2),
|
||||||
|
according to a passed marker. This is used to avoid lockless readers
|
||||||
|
starvation (too much retry loops) in case of a sharp spike in write
|
||||||
|
activity. First, a lockless read is tried (even marker passed). If
|
||||||
|
that trial fails (odd sequence counter is returned, which is used as
|
||||||
|
the next iteration marker), the lockless read is transformed to a
|
||||||
|
full locking read and no retry loop is necessary::
|
||||||
|
|
||||||
|
/* marker; even initialization */
|
||||||
|
int seq = 0;
|
||||||
|
do {
|
||||||
|
read_seqbegin_or_lock(&foo_seqlock, &seq);
|
||||||
|
|
||||||
|
/* ... [[read-side critical section]] ... */
|
||||||
|
|
||||||
|
} while (need_seqretry(&foo_seqlock, seq));
|
||||||
|
done_seqretry(&foo_seqlock, seq);
|
||||||
|
|
||||||
|
|
||||||
|
API documentation
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/seqlock.h
|
|
@ -24,7 +24,6 @@
|
||||||
#define __atomic_acquire_fence()
|
#define __atomic_acquire_fence()
|
||||||
#define __atomic_post_full_fence()
|
#define __atomic_post_full_fence()
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
#define ATOMIC64_INIT(i) { (i) }
|
#define ATOMIC64_INIT(i) { (i) }
|
||||||
|
|
||||||
#define atomic_read(v) READ_ONCE((v)->counter)
|
#define atomic_read(v) READ_ONCE((v)->counter)
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
#include <asm/smp.h>
|
#include <asm/smp.h>
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
#ifndef CONFIG_ARC_PLAT_EZNPS
|
#ifndef CONFIG_ARC_PLAT_EZNPS
|
||||||
|
|
||||||
#define atomic_read(v) READ_ONCE((v)->counter)
|
#define atomic_read(v) READ_ONCE((v)->counter)
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
#include <asm/cmpxchg.h>
|
#include <asm/cmpxchg.h>
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#ifndef _ASM_ARM_PERCPU_H_
|
#ifndef _ASM_ARM_PERCPU_H_
|
||||||
#define _ASM_ARM_PERCPU_H_
|
#define _ASM_ARM_PERCPU_H_
|
||||||
|
|
||||||
|
register unsigned long current_stack_pointer asm ("sp");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Same as asm-generic/percpu.h, except that we store the per cpu offset
|
* Same as asm-generic/percpu.h, except that we store the per cpu offset
|
||||||
* in the TPIDRPRW. TPIDRPRW only exists on V6K and V7
|
* in the TPIDRPRW. TPIDRPRW only exists on V6K and V7
|
||||||
|
|
|
@ -75,11 +75,6 @@ struct thread_info {
|
||||||
.addr_limit = KERNEL_DS, \
|
.addr_limit = KERNEL_DS, \
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* how to get the current stack pointer in C
|
|
||||||
*/
|
|
||||||
register unsigned long current_stack_pointer asm ("sp");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* how to get the thread information struct from C
|
* how to get the thread information struct from C
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -99,8 +99,6 @@ static inline long arch_atomic64_dec_if_positive(atomic64_t *v)
|
||||||
return __lse_ll_sc_body(atomic64_dec_if_positive, v);
|
return __lse_ll_sc_body(atomic64_dec_if_positive, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
#define arch_atomic_read(v) __READ_ONCE((v)->counter)
|
#define arch_atomic_read(v) __READ_ONCE((v)->counter)
|
||||||
#define arch_atomic_set(v, i) __WRITE_ONCE(((v)->counter), (i))
|
#define arch_atomic_set(v, i) __WRITE_ONCE(((v)->counter), (i))
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
* resource counting etc..
|
* resource counting etc..
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
#define atomic_read(v) READ_ONCE((v)->counter)
|
#define atomic_read(v) READ_ONCE((v)->counter)
|
||||||
#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
|
#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
#include <asm/cmpxchg.h>
|
#include <asm/cmpxchg.h>
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
/* Normal writes in our arch don't clear lock reservations */
|
/* Normal writes in our arch don't clear lock reservations */
|
||||||
|
|
||||||
static inline void atomic_set(atomic_t *v, int new)
|
static inline void atomic_set(atomic_t *v, int new)
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
|
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
#define ATOMIC64_INIT(i) { (i) }
|
#define ATOMIC64_INIT(i) { (i) }
|
||||||
|
|
||||||
#define atomic_read(v) READ_ONCE((v)->counter)
|
#define atomic_read(v) READ_ONCE((v)->counter)
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
* We do not have SMP m68k systems, so we don't have to deal with that.
|
* We do not have SMP m68k systems, so we don't have to deal with that.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
#define atomic_read(v) READ_ONCE((v)->counter)
|
#define atomic_read(v) READ_ONCE((v)->counter)
|
||||||
#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
|
#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,6 @@ static __always_inline type pfx##_xchg(pfx##_t *v, type n) \
|
||||||
return xchg(&v->counter, n); \
|
return xchg(&v->counter, n); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
ATOMIC_OPS(atomic, int)
|
ATOMIC_OPS(atomic, int)
|
||||||
|
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
|
|
|
@ -136,8 +136,6 @@ ATOMIC_OPS(xor, ^=)
|
||||||
#undef ATOMIC_OP_RETURN
|
#undef ATOMIC_OP_RETURN
|
||||||
#undef ATOMIC_OP
|
#undef ATOMIC_OP
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
|
|
||||||
#define ATOMIC64_INIT(i) { (i) }
|
#define ATOMIC64_INIT(i) { (i) }
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
#include <asm/cmpxchg.h>
|
#include <asm/cmpxchg.h>
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since *_return_relaxed and {cmp}xchg_relaxed are implemented with
|
* Since *_return_relaxed and {cmp}xchg_relaxed are implemented with
|
||||||
* a "bne-" instruction at the end, so an isync is enough as a acquire barrier
|
* a "bne-" instruction at the end, so an isync is enough as a acquire barrier
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
#ifndef _ASM_POWERPC_DTL_H
|
||||||
|
#define _ASM_POWERPC_DTL_H
|
||||||
|
|
||||||
|
#include <asm/lppaca.h>
|
||||||
|
#include <linux/spinlock_types.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Layout of entries in the hypervisor's dispatch trace log buffer.
|
||||||
|
*/
|
||||||
|
struct dtl_entry {
|
||||||
|
u8 dispatch_reason;
|
||||||
|
u8 preempt_reason;
|
||||||
|
__be16 processor_id;
|
||||||
|
__be32 enqueue_to_dispatch_time;
|
||||||
|
__be32 ready_to_enqueue_time;
|
||||||
|
__be32 waiting_to_ready_time;
|
||||||
|
__be64 timebase;
|
||||||
|
__be64 fault_addr;
|
||||||
|
__be64 srr0;
|
||||||
|
__be64 srr1;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */
|
||||||
|
#define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dispatch trace log event enable mask:
|
||||||
|
* 0x1: voluntary virtual processor waits
|
||||||
|
* 0x2: time-slice preempts
|
||||||
|
* 0x4: virtual partition memory page faults
|
||||||
|
*/
|
||||||
|
#define DTL_LOG_CEDE 0x1
|
||||||
|
#define DTL_LOG_PREEMPT 0x2
|
||||||
|
#define DTL_LOG_FAULT 0x4
|
||||||
|
#define DTL_LOG_ALL (DTL_LOG_CEDE | DTL_LOG_PREEMPT | DTL_LOG_FAULT)
|
||||||
|
|
||||||
|
extern struct kmem_cache *dtl_cache;
|
||||||
|
extern rwlock_t dtl_access_lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When CONFIG_VIRT_CPU_ACCOUNTING_NATIVE = y, the cpu accounting code controls
|
||||||
|
* reading from the dispatch trace log. If other code wants to consume
|
||||||
|
* DTL entries, it can set this pointer to a function that will get
|
||||||
|
* called once for each DTL entry that gets processed.
|
||||||
|
*/
|
||||||
|
extern void (*dtl_consumer)(struct dtl_entry *entry, u64 index);
|
||||||
|
|
||||||
|
extern void register_dtl_buffer(int cpu);
|
||||||
|
extern void alloc_dtl_buffers(unsigned long *time_limit);
|
||||||
|
extern long hcall_vphn(unsigned long cpu, u64 flags, __be32 *associativity);
|
||||||
|
|
||||||
|
#endif /* _ASM_POWERPC_DTL_H */
|
|
@ -42,7 +42,6 @@
|
||||||
*/
|
*/
|
||||||
#include <linux/cache.h>
|
#include <linux/cache.h>
|
||||||
#include <linux/threads.h>
|
#include <linux/threads.h>
|
||||||
#include <linux/spinlock_types.h>
|
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
#include <asm/mmu.h>
|
#include <asm/mmu.h>
|
||||||
#include <asm/firmware.h>
|
#include <asm/firmware.h>
|
||||||
|
@ -146,49 +145,6 @@ struct slb_shadow {
|
||||||
} save_area[SLB_NUM_BOLTED];
|
} save_area[SLB_NUM_BOLTED];
|
||||||
} ____cacheline_aligned;
|
} ____cacheline_aligned;
|
||||||
|
|
||||||
/*
|
|
||||||
* Layout of entries in the hypervisor's dispatch trace log buffer.
|
|
||||||
*/
|
|
||||||
struct dtl_entry {
|
|
||||||
u8 dispatch_reason;
|
|
||||||
u8 preempt_reason;
|
|
||||||
__be16 processor_id;
|
|
||||||
__be32 enqueue_to_dispatch_time;
|
|
||||||
__be32 ready_to_enqueue_time;
|
|
||||||
__be32 waiting_to_ready_time;
|
|
||||||
__be64 timebase;
|
|
||||||
__be64 fault_addr;
|
|
||||||
__be64 srr0;
|
|
||||||
__be64 srr1;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */
|
|
||||||
#define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dispatch trace log event enable mask:
|
|
||||||
* 0x1: voluntary virtual processor waits
|
|
||||||
* 0x2: time-slice preempts
|
|
||||||
* 0x4: virtual partition memory page faults
|
|
||||||
*/
|
|
||||||
#define DTL_LOG_CEDE 0x1
|
|
||||||
#define DTL_LOG_PREEMPT 0x2
|
|
||||||
#define DTL_LOG_FAULT 0x4
|
|
||||||
#define DTL_LOG_ALL (DTL_LOG_CEDE | DTL_LOG_PREEMPT | DTL_LOG_FAULT)
|
|
||||||
|
|
||||||
extern struct kmem_cache *dtl_cache;
|
|
||||||
extern rwlock_t dtl_access_lock;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When CONFIG_VIRT_CPU_ACCOUNTING_NATIVE = y, the cpu accounting code controls
|
|
||||||
* reading from the dispatch trace log. If other code wants to consume
|
|
||||||
* DTL entries, it can set this pointer to a function that will get
|
|
||||||
* called once for each DTL entry that gets processed.
|
|
||||||
*/
|
|
||||||
extern void (*dtl_consumer)(struct dtl_entry *entry, u64 index);
|
|
||||||
|
|
||||||
extern void register_dtl_buffer(int cpu);
|
|
||||||
extern void alloc_dtl_buffers(unsigned long *time_limit);
|
|
||||||
extern long hcall_vphn(unsigned long cpu, u64 flags, __be32 *associativity);
|
extern long hcall_vphn(unsigned long cpu, u64 flags, __be32 *associativity);
|
||||||
|
|
||||||
#endif /* CONFIG_PPC_BOOK3S */
|
#endif /* CONFIG_PPC_BOOK3S */
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include <asm/hmi.h>
|
#include <asm/hmi.h>
|
||||||
#include <asm/cpuidle.h>
|
#include <asm/cpuidle.h>
|
||||||
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
||||||
#include <asm/rtas-types.h>
|
|
||||||
|
|
||||||
#include <asm-generic/mmiowb_types.h>
|
#include <asm-generic/mmiowb_types.h>
|
||||||
|
|
||||||
|
@ -53,6 +52,7 @@ extern unsigned int debug_smp_processor_id(void); /* from linux/smp.h */
|
||||||
#define get_slb_shadow() (get_paca()->slb_shadow_ptr)
|
#define get_slb_shadow() (get_paca()->slb_shadow_ptr)
|
||||||
|
|
||||||
struct task_struct;
|
struct task_struct;
|
||||||
|
struct rtas_args;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Defines the layout of the paca.
|
* Defines the layout of the paca.
|
||||||
|
|
|
@ -183,6 +183,8 @@ static inline unsigned long read_spurr(unsigned long tb)
|
||||||
|
|
||||||
#ifdef CONFIG_PPC_SPLPAR
|
#ifdef CONFIG_PPC_SPLPAR
|
||||||
|
|
||||||
|
#include <asm/dtl.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan the dispatch trace log and count up the stolen time.
|
* Scan the dispatch trace log and count up the stolen time.
|
||||||
* Should be called with interrupts disabled.
|
* Should be called with interrupts disabled.
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
#include <asm/hw_breakpoint.h>
|
#include <asm/hw_breakpoint.h>
|
||||||
#include <asm/kvm_book3s_uvmem.h>
|
#include <asm/kvm_book3s_uvmem.h>
|
||||||
#include <asm/ultravisor.h>
|
#include <asm/ultravisor.h>
|
||||||
|
#include <asm/dtl.h>
|
||||||
|
|
||||||
#include "book3s.h"
|
#include "book3s.h"
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <asm/smp.h>
|
#include <asm/smp.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <asm/firmware.h>
|
#include <asm/firmware.h>
|
||||||
|
#include <asm/dtl.h>
|
||||||
#include <asm/lppaca.h>
|
#include <asm/lppaca.h>
|
||||||
#include <asm/debugfs.h>
|
#include <asm/debugfs.h>
|
||||||
#include <asm/plpar_wrappers.h>
|
#include <asm/plpar_wrappers.h>
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <asm/fadump.h>
|
#include <asm/fadump.h>
|
||||||
#include <asm/asm-prototypes.h>
|
#include <asm/asm-prototypes.h>
|
||||||
#include <asm/debugfs.h>
|
#include <asm/debugfs.h>
|
||||||
|
#include <asm/dtl.h>
|
||||||
|
|
||||||
#include "pseries.h"
|
#include "pseries.h"
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
#include <asm/idle.h>
|
#include <asm/idle.h>
|
||||||
#include <asm/swiotlb.h>
|
#include <asm/swiotlb.h>
|
||||||
#include <asm/svm.h>
|
#include <asm/svm.h>
|
||||||
|
#include <asm/dtl.h>
|
||||||
|
|
||||||
#include "pseries.h"
|
#include "pseries.h"
|
||||||
#include "../../../../drivers/pci/pci.h"
|
#include "../../../../drivers/pci/pci.h"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <asm/svm.h>
|
#include <asm/svm.h>
|
||||||
#include <asm/swiotlb.h>
|
#include <asm/swiotlb.h>
|
||||||
#include <asm/ultravisor.h>
|
#include <asm/ultravisor.h>
|
||||||
|
#include <asm/dtl.h>
|
||||||
|
|
||||||
static int __init init_svm(void)
|
static int __init init_svm(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
#include <asm/cmpxchg.h>
|
#include <asm/cmpxchg.h>
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
#define __atomic_acquire_fence() \
|
#define __atomic_acquire_fence() \
|
||||||
__asm__ __volatile__(RISCV_ACQUIRE_BARRIER "" ::: "memory")
|
__asm__ __volatile__(RISCV_ACQUIRE_BARRIER "" ::: "memory")
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
#include <asm/cmpxchg.h>
|
#include <asm/cmpxchg.h>
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
static inline int atomic_read(const atomic_t *v)
|
static inline int atomic_read(const atomic_t *v)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include <asm/sigp.h>
|
#include <asm/sigp.h>
|
||||||
#include <asm/lowcore.h>
|
#include <asm/lowcore.h>
|
||||||
|
#include <asm/processor.h>
|
||||||
|
|
||||||
#define raw_smp_processor_id() (S390_lowcore.cpu_nr)
|
#define raw_smp_processor_id() (S390_lowcore.cpu_nr)
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
#include <asm/lowcore.h>
|
#include <asm/lowcore.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/processor.h>
|
|
||||||
|
|
||||||
#define STACK_INIT_OFFSET \
|
#define STACK_INIT_OFFSET \
|
||||||
(THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs))
|
(THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs))
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
#include <asm/cmpxchg.h>
|
#include <asm/cmpxchg.h>
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
#define atomic_read(v) READ_ONCE((v)->counter)
|
#define atomic_read(v) READ_ONCE((v)->counter)
|
||||||
#define atomic_set(v,i) WRITE_ONCE((v)->counter, (i))
|
#define atomic_set(v,i) WRITE_ONCE((v)->counter, (i))
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
#include <asm-generic/atomic64.h>
|
#include <asm-generic/atomic64.h>
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
int atomic_add_return(int, atomic_t *);
|
int atomic_add_return(int, atomic_t *);
|
||||||
int atomic_fetch_add(int, atomic_t *);
|
int atomic_fetch_add(int, atomic_t *);
|
||||||
int atomic_fetch_and(int, atomic_t *);
|
int atomic_fetch_and(int, atomic_t *);
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include <asm/cmpxchg.h>
|
#include <asm/cmpxchg.h>
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
#define ATOMIC64_INIT(i) { (i) }
|
#define ATOMIC64_INIT(i) { (i) }
|
||||||
|
|
||||||
#define atomic_read(v) READ_ONCE((v)->counter)
|
#define atomic_read(v) READ_ONCE((v)->counter)
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
|
|
||||||
|
#ifndef BUILD_VDSO
|
||||||
register unsigned long __local_per_cpu_offset asm("g5");
|
register unsigned long __local_per_cpu_offset asm("g5");
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#ifndef _SPARC_TRAP_BLOCK_H
|
#ifndef _SPARC_TRAP_BLOCK_H
|
||||||
#define _SPARC_TRAP_BLOCK_H
|
#define _SPARC_TRAP_BLOCK_H
|
||||||
|
|
||||||
|
#include <linux/threads.h>
|
||||||
|
|
||||||
#include <asm/hypervisor.h>
|
#include <asm/hypervisor.h>
|
||||||
#include <asm/asi.h>
|
#include <asm/asi.h>
|
||||||
|
|
||||||
|
|
|
@ -559,8 +559,7 @@ SYSCALL_DEFINE0(ni_syscall)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* idtentry_enter_cond_rcu - Handle state tracking on idtentry with conditional
|
* idtentry_enter - Handle state tracking on ordinary idtentries
|
||||||
* RCU handling
|
|
||||||
* @regs: Pointer to pt_regs of interrupted context
|
* @regs: Pointer to pt_regs of interrupted context
|
||||||
*
|
*
|
||||||
* Invokes:
|
* Invokes:
|
||||||
|
@ -572,6 +571,9 @@ SYSCALL_DEFINE0(ni_syscall)
|
||||||
* - The hardirq tracer to keep the state consistent as low level ASM
|
* - The hardirq tracer to keep the state consistent as low level ASM
|
||||||
* entry disabled interrupts.
|
* entry disabled interrupts.
|
||||||
*
|
*
|
||||||
|
* As a precondition, this requires that the entry came from user mode,
|
||||||
|
* idle, or a kernel context in which RCU is watching.
|
||||||
|
*
|
||||||
* For kernel mode entries RCU handling is done conditional. If RCU is
|
* For kernel mode entries RCU handling is done conditional. If RCU is
|
||||||
* watching then the only RCU requirement is to check whether the tick has
|
* watching then the only RCU requirement is to check whether the tick has
|
||||||
* to be restarted. If RCU is not watching then rcu_irq_enter() has to be
|
* to be restarted. If RCU is not watching then rcu_irq_enter() has to be
|
||||||
|
@ -585,18 +587,21 @@ SYSCALL_DEFINE0(ni_syscall)
|
||||||
* establish the proper context for NOHZ_FULL. Otherwise scheduling on exit
|
* establish the proper context for NOHZ_FULL. Otherwise scheduling on exit
|
||||||
* would not be possible.
|
* would not be possible.
|
||||||
*
|
*
|
||||||
* Returns: True if RCU has been adjusted on a kernel entry
|
* Returns: An opaque object that must be passed to idtentry_exit()
|
||||||
* False otherwise
|
|
||||||
*
|
*
|
||||||
* The return value must be fed into the rcu_exit argument of
|
* The return value must be fed into the state argument of
|
||||||
* idtentry_exit_cond_rcu().
|
* idtentry_exit().
|
||||||
*/
|
*/
|
||||||
bool noinstr idtentry_enter_cond_rcu(struct pt_regs *regs)
|
noinstr idtentry_state_t idtentry_enter(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
idtentry_state_t ret = {
|
||||||
|
.exit_rcu = false,
|
||||||
|
};
|
||||||
|
|
||||||
if (user_mode(regs)) {
|
if (user_mode(regs)) {
|
||||||
check_user_regs(regs);
|
check_user_regs(regs);
|
||||||
enter_from_user_mode();
|
enter_from_user_mode();
|
||||||
return false;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -634,7 +639,8 @@ bool noinstr idtentry_enter_cond_rcu(struct pt_regs *regs)
|
||||||
trace_hardirqs_off_finish();
|
trace_hardirqs_off_finish();
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
|
|
||||||
return true;
|
ret.exit_rcu = true;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -649,7 +655,7 @@ bool noinstr idtentry_enter_cond_rcu(struct pt_regs *regs)
|
||||||
trace_hardirqs_off();
|
trace_hardirqs_off();
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
|
|
||||||
return false;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void idtentry_exit_cond_resched(struct pt_regs *regs, bool may_sched)
|
static void idtentry_exit_cond_resched(struct pt_regs *regs, bool may_sched)
|
||||||
|
@ -667,10 +673,9 @@ static void idtentry_exit_cond_resched(struct pt_regs *regs, bool may_sched)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* idtentry_exit_cond_rcu - Handle return from exception with conditional RCU
|
* idtentry_exit - Handle return from exception that used idtentry_enter()
|
||||||
* handling
|
|
||||||
* @regs: Pointer to pt_regs (exception entry regs)
|
* @regs: Pointer to pt_regs (exception entry regs)
|
||||||
* @rcu_exit: Invoke rcu_irq_exit() if true
|
* @state: Return value from matching call to idtentry_enter()
|
||||||
*
|
*
|
||||||
* Depending on the return target (kernel/user) this runs the necessary
|
* Depending on the return target (kernel/user) this runs the necessary
|
||||||
* preemption and work checks if possible and reguired and returns to
|
* preemption and work checks if possible and reguired and returns to
|
||||||
|
@ -679,10 +684,10 @@ static void idtentry_exit_cond_resched(struct pt_regs *regs, bool may_sched)
|
||||||
* This is the last action before returning to the low level ASM code which
|
* This is the last action before returning to the low level ASM code which
|
||||||
* just needs to return to the appropriate context.
|
* just needs to return to the appropriate context.
|
||||||
*
|
*
|
||||||
* Counterpart to idtentry_enter_cond_rcu(). The return value of the entry
|
* Counterpart to idtentry_enter(). The return value of the entry
|
||||||
* function must be fed into the @rcu_exit argument.
|
* function must be fed into the @state argument.
|
||||||
*/
|
*/
|
||||||
void noinstr idtentry_exit_cond_rcu(struct pt_regs *regs, bool rcu_exit)
|
noinstr void idtentry_exit(struct pt_regs *regs, idtentry_state_t state)
|
||||||
{
|
{
|
||||||
lockdep_assert_irqs_disabled();
|
lockdep_assert_irqs_disabled();
|
||||||
|
|
||||||
|
@ -695,7 +700,7 @@ void noinstr idtentry_exit_cond_rcu(struct pt_regs *regs, bool rcu_exit)
|
||||||
* carefully and needs the same ordering of lockdep/tracing
|
* carefully and needs the same ordering of lockdep/tracing
|
||||||
* and RCU as the return to user mode path.
|
* and RCU as the return to user mode path.
|
||||||
*/
|
*/
|
||||||
if (rcu_exit) {
|
if (state.exit_rcu) {
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
/* Tell the tracer that IRET will enable interrupts */
|
/* Tell the tracer that IRET will enable interrupts */
|
||||||
trace_hardirqs_on_prepare();
|
trace_hardirqs_on_prepare();
|
||||||
|
@ -714,7 +719,7 @@ void noinstr idtentry_exit_cond_rcu(struct pt_regs *regs, bool rcu_exit)
|
||||||
* IRQ flags state is correct already. Just tell RCU if it
|
* IRQ flags state is correct already. Just tell RCU if it
|
||||||
* was not watching on entry.
|
* was not watching on entry.
|
||||||
*/
|
*/
|
||||||
if (rcu_exit)
|
if (state.exit_rcu)
|
||||||
rcu_irq_exit();
|
rcu_irq_exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -726,7 +731,7 @@ void noinstr idtentry_exit_cond_rcu(struct pt_regs *regs, bool rcu_exit)
|
||||||
* Invokes enter_from_user_mode() to establish the proper context for
|
* Invokes enter_from_user_mode() to establish the proper context for
|
||||||
* NOHZ_FULL. Otherwise scheduling on exit would not be possible.
|
* NOHZ_FULL. Otherwise scheduling on exit would not be possible.
|
||||||
*/
|
*/
|
||||||
void noinstr idtentry_enter_user(struct pt_regs *regs)
|
noinstr void idtentry_enter_user(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
check_user_regs(regs);
|
check_user_regs(regs);
|
||||||
enter_from_user_mode();
|
enter_from_user_mode();
|
||||||
|
@ -744,13 +749,47 @@ void noinstr idtentry_enter_user(struct pt_regs *regs)
|
||||||
*
|
*
|
||||||
* Counterpart to idtentry_enter_user().
|
* Counterpart to idtentry_enter_user().
|
||||||
*/
|
*/
|
||||||
void noinstr idtentry_exit_user(struct pt_regs *regs)
|
noinstr void idtentry_exit_user(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
lockdep_assert_irqs_disabled();
|
lockdep_assert_irqs_disabled();
|
||||||
|
|
||||||
prepare_exit_to_usermode(regs);
|
prepare_exit_to_usermode(regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noinstr bool idtentry_enter_nmi(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
bool irq_state = lockdep_hardirqs_enabled();
|
||||||
|
|
||||||
|
__nmi_enter();
|
||||||
|
lockdep_hardirqs_off(CALLER_ADDR0);
|
||||||
|
lockdep_hardirq_enter();
|
||||||
|
rcu_nmi_enter();
|
||||||
|
|
||||||
|
instrumentation_begin();
|
||||||
|
trace_hardirqs_off_finish();
|
||||||
|
ftrace_nmi_enter();
|
||||||
|
instrumentation_end();
|
||||||
|
|
||||||
|
return irq_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
noinstr void idtentry_exit_nmi(struct pt_regs *regs, bool restore)
|
||||||
|
{
|
||||||
|
instrumentation_begin();
|
||||||
|
ftrace_nmi_exit();
|
||||||
|
if (restore) {
|
||||||
|
trace_hardirqs_on_prepare();
|
||||||
|
lockdep_hardirqs_on_prepare(CALLER_ADDR0);
|
||||||
|
}
|
||||||
|
instrumentation_end();
|
||||||
|
|
||||||
|
rcu_nmi_exit();
|
||||||
|
lockdep_hardirq_exit();
|
||||||
|
if (restore)
|
||||||
|
lockdep_hardirqs_on(CALLER_ADDR0);
|
||||||
|
__nmi_exit();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_XEN_PV
|
#ifdef CONFIG_XEN_PV
|
||||||
#ifndef CONFIG_PREEMPTION
|
#ifndef CONFIG_PREEMPTION
|
||||||
/*
|
/*
|
||||||
|
@ -800,9 +839,10 @@ static void __xen_pv_evtchn_do_upcall(void)
|
||||||
__visible noinstr void xen_pv_evtchn_do_upcall(struct pt_regs *regs)
|
__visible noinstr void xen_pv_evtchn_do_upcall(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct pt_regs *old_regs;
|
struct pt_regs *old_regs;
|
||||||
bool inhcall, rcu_exit;
|
bool inhcall;
|
||||||
|
idtentry_state_t state;
|
||||||
|
|
||||||
rcu_exit = idtentry_enter_cond_rcu(regs);
|
state = idtentry_enter(regs);
|
||||||
old_regs = set_irq_regs(regs);
|
old_regs = set_irq_regs(regs);
|
||||||
|
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
|
@ -812,13 +852,13 @@ __visible noinstr void xen_pv_evtchn_do_upcall(struct pt_regs *regs)
|
||||||
set_irq_regs(old_regs);
|
set_irq_regs(old_regs);
|
||||||
|
|
||||||
inhcall = get_and_clear_inhcall();
|
inhcall = get_and_clear_inhcall();
|
||||||
if (inhcall && !WARN_ON_ONCE(rcu_exit)) {
|
if (inhcall && !WARN_ON_ONCE(state.exit_rcu)) {
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
idtentry_exit_cond_resched(regs, true);
|
idtentry_exit_cond_resched(regs, true);
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
restore_inhcall(inhcall);
|
restore_inhcall(inhcall);
|
||||||
} else {
|
} else {
|
||||||
idtentry_exit_cond_rcu(regs, rcu_exit);
|
idtentry_exit(regs, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_XEN_PV */
|
#endif /* CONFIG_XEN_PV */
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
* resource counting etc..
|
* resource counting etc..
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* arch_atomic_read - read atomic variable
|
* arch_atomic_read - read atomic variable
|
||||||
* @v: pointer of type atomic_t
|
* @v: pointer of type atomic_t
|
||||||
|
|
|
@ -13,8 +13,15 @@
|
||||||
void idtentry_enter_user(struct pt_regs *regs);
|
void idtentry_enter_user(struct pt_regs *regs);
|
||||||
void idtentry_exit_user(struct pt_regs *regs);
|
void idtentry_exit_user(struct pt_regs *regs);
|
||||||
|
|
||||||
bool idtentry_enter_cond_rcu(struct pt_regs *regs);
|
typedef struct idtentry_state {
|
||||||
void idtentry_exit_cond_rcu(struct pt_regs *regs, bool rcu_exit);
|
bool exit_rcu;
|
||||||
|
} idtentry_state_t;
|
||||||
|
|
||||||
|
idtentry_state_t idtentry_enter(struct pt_regs *regs);
|
||||||
|
void idtentry_exit(struct pt_regs *regs, idtentry_state_t state);
|
||||||
|
|
||||||
|
bool idtentry_enter_nmi(struct pt_regs *regs);
|
||||||
|
void idtentry_exit_nmi(struct pt_regs *regs, bool irq_state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DECLARE_IDTENTRY - Declare functions for simple IDT entry points
|
* DECLARE_IDTENTRY - Declare functions for simple IDT entry points
|
||||||
|
@ -54,12 +61,12 @@ static __always_inline void __##func(struct pt_regs *regs); \
|
||||||
\
|
\
|
||||||
__visible noinstr void func(struct pt_regs *regs) \
|
__visible noinstr void func(struct pt_regs *regs) \
|
||||||
{ \
|
{ \
|
||||||
bool rcu_exit = idtentry_enter_cond_rcu(regs); \
|
idtentry_state_t state = idtentry_enter(regs); \
|
||||||
\
|
\
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
__##func (regs); \
|
__##func (regs); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
idtentry_exit_cond_rcu(regs, rcu_exit); \
|
idtentry_exit(regs, state); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static __always_inline void __##func(struct pt_regs *regs)
|
static __always_inline void __##func(struct pt_regs *regs)
|
||||||
|
@ -101,12 +108,12 @@ static __always_inline void __##func(struct pt_regs *regs, \
|
||||||
__visible noinstr void func(struct pt_regs *regs, \
|
__visible noinstr void func(struct pt_regs *regs, \
|
||||||
unsigned long error_code) \
|
unsigned long error_code) \
|
||||||
{ \
|
{ \
|
||||||
bool rcu_exit = idtentry_enter_cond_rcu(regs); \
|
idtentry_state_t state = idtentry_enter(regs); \
|
||||||
\
|
\
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
__##func (regs, error_code); \
|
__##func (regs, error_code); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
idtentry_exit_cond_rcu(regs, rcu_exit); \
|
idtentry_exit(regs, state); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static __always_inline void __##func(struct pt_regs *regs, \
|
static __always_inline void __##func(struct pt_regs *regs, \
|
||||||
|
@ -199,7 +206,7 @@ static __always_inline void __##func(struct pt_regs *regs, u8 vector); \
|
||||||
__visible noinstr void func(struct pt_regs *regs, \
|
__visible noinstr void func(struct pt_regs *regs, \
|
||||||
unsigned long error_code) \
|
unsigned long error_code) \
|
||||||
{ \
|
{ \
|
||||||
bool rcu_exit = idtentry_enter_cond_rcu(regs); \
|
idtentry_state_t state = idtentry_enter(regs); \
|
||||||
\
|
\
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
irq_enter_rcu(); \
|
irq_enter_rcu(); \
|
||||||
|
@ -207,7 +214,7 @@ __visible noinstr void func(struct pt_regs *regs, \
|
||||||
__##func (regs, (u8)error_code); \
|
__##func (regs, (u8)error_code); \
|
||||||
irq_exit_rcu(); \
|
irq_exit_rcu(); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
idtentry_exit_cond_rcu(regs, rcu_exit); \
|
idtentry_exit(regs, state); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static __always_inline void __##func(struct pt_regs *regs, u8 vector)
|
static __always_inline void __##func(struct pt_regs *regs, u8 vector)
|
||||||
|
@ -241,7 +248,7 @@ static void __##func(struct pt_regs *regs); \
|
||||||
\
|
\
|
||||||
__visible noinstr void func(struct pt_regs *regs) \
|
__visible noinstr void func(struct pt_regs *regs) \
|
||||||
{ \
|
{ \
|
||||||
bool rcu_exit = idtentry_enter_cond_rcu(regs); \
|
idtentry_state_t state = idtentry_enter(regs); \
|
||||||
\
|
\
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
irq_enter_rcu(); \
|
irq_enter_rcu(); \
|
||||||
|
@ -249,7 +256,7 @@ __visible noinstr void func(struct pt_regs *regs) \
|
||||||
run_on_irqstack_cond(__##func, regs, regs); \
|
run_on_irqstack_cond(__##func, regs, regs); \
|
||||||
irq_exit_rcu(); \
|
irq_exit_rcu(); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
idtentry_exit_cond_rcu(regs, rcu_exit); \
|
idtentry_exit(regs, state); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static noinline void __##func(struct pt_regs *regs)
|
static noinline void __##func(struct pt_regs *regs)
|
||||||
|
@ -270,7 +277,7 @@ static __always_inline void __##func(struct pt_regs *regs); \
|
||||||
\
|
\
|
||||||
__visible noinstr void func(struct pt_regs *regs) \
|
__visible noinstr void func(struct pt_regs *regs) \
|
||||||
{ \
|
{ \
|
||||||
bool rcu_exit = idtentry_enter_cond_rcu(regs); \
|
idtentry_state_t state = idtentry_enter(regs); \
|
||||||
\
|
\
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
__irq_enter_raw(); \
|
__irq_enter_raw(); \
|
||||||
|
@ -278,7 +285,7 @@ __visible noinstr void func(struct pt_regs *regs) \
|
||||||
__##func (regs); \
|
__##func (regs); \
|
||||||
__irq_exit_raw(); \
|
__irq_exit_raw(); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
idtentry_exit_cond_rcu(regs, rcu_exit); \
|
idtentry_exit(regs, state); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static __always_inline void __##func(struct pt_regs *regs)
|
static __always_inline void __##func(struct pt_regs *regs)
|
||||||
|
|
|
@ -233,7 +233,7 @@ EXPORT_SYMBOL_GPL(kvm_read_and_reset_apf_flags);
|
||||||
noinstr bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token)
|
noinstr bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token)
|
||||||
{
|
{
|
||||||
u32 reason = kvm_read_and_reset_apf_flags();
|
u32 reason = kvm_read_and_reset_apf_flags();
|
||||||
bool rcu_exit;
|
idtentry_state_t state;
|
||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case KVM_PV_REASON_PAGE_NOT_PRESENT:
|
case KVM_PV_REASON_PAGE_NOT_PRESENT:
|
||||||
|
@ -243,7 +243,7 @@ noinstr bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_exit = idtentry_enter_cond_rcu(regs);
|
state = idtentry_enter(regs);
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -264,7 +264,7 @@ noinstr bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token)
|
||||||
}
|
}
|
||||||
|
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
idtentry_exit_cond_rcu(regs, rcu_exit);
|
idtentry_exit(regs, state);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -330,7 +330,6 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
|
||||||
__this_cpu_write(last_nmi_rip, regs->ip);
|
__this_cpu_write(last_nmi_rip, regs->ip);
|
||||||
|
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
trace_hardirqs_off_finish();
|
|
||||||
|
|
||||||
handled = nmi_handle(NMI_LOCAL, regs);
|
handled = nmi_handle(NMI_LOCAL, regs);
|
||||||
__this_cpu_add(nmi_stats.normal, handled);
|
__this_cpu_add(nmi_stats.normal, handled);
|
||||||
|
@ -417,8 +416,6 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
|
||||||
unknown_nmi_error(reason, regs);
|
unknown_nmi_error(reason, regs);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (regs->flags & X86_EFLAGS_IF)
|
|
||||||
trace_hardirqs_on_prepare();
|
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,6 +475,8 @@ static DEFINE_PER_CPU(unsigned long, nmi_dr7);
|
||||||
|
|
||||||
DEFINE_IDTENTRY_RAW(exc_nmi)
|
DEFINE_IDTENTRY_RAW(exc_nmi)
|
||||||
{
|
{
|
||||||
|
bool irq_state;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id()))
|
if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -491,14 +490,14 @@ nmi_restart:
|
||||||
|
|
||||||
this_cpu_write(nmi_dr7, local_db_save());
|
this_cpu_write(nmi_dr7, local_db_save());
|
||||||
|
|
||||||
nmi_enter();
|
irq_state = idtentry_enter_nmi(regs);
|
||||||
|
|
||||||
inc_irq_stat(__nmi_count);
|
inc_irq_stat(__nmi_count);
|
||||||
|
|
||||||
if (!ignore_nmis)
|
if (!ignore_nmis)
|
||||||
default_do_nmi(regs);
|
default_do_nmi(regs);
|
||||||
|
|
||||||
nmi_exit();
|
idtentry_exit_nmi(regs, irq_state);
|
||||||
|
|
||||||
local_db_restore(this_cpu_read(nmi_dr7));
|
local_db_restore(this_cpu_read(nmi_dr7));
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@ static noinstr bool handle_bug(struct pt_regs *regs)
|
||||||
|
|
||||||
DEFINE_IDTENTRY_RAW(exc_invalid_op)
|
DEFINE_IDTENTRY_RAW(exc_invalid_op)
|
||||||
{
|
{
|
||||||
bool rcu_exit;
|
idtentry_state_t state;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We use UD2 as a short encoding for 'CALL __WARN', as such
|
* We use UD2 as a short encoding for 'CALL __WARN', as such
|
||||||
|
@ -255,11 +255,11 @@ DEFINE_IDTENTRY_RAW(exc_invalid_op)
|
||||||
if (!user_mode(regs) && handle_bug(regs))
|
if (!user_mode(regs) && handle_bug(regs))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rcu_exit = idtentry_enter_cond_rcu(regs);
|
state = idtentry_enter(regs);
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
handle_invalid_op(regs);
|
handle_invalid_op(regs);
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
idtentry_exit_cond_rcu(regs, rcu_exit);
|
idtentry_exit(regs, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_IDTENTRY(exc_coproc_segment_overrun)
|
DEFINE_IDTENTRY(exc_coproc_segment_overrun)
|
||||||
|
@ -405,7 +405,7 @@ DEFINE_IDTENTRY_DF(exc_double_fault)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nmi_enter();
|
idtentry_enter_nmi(regs);
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
|
notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
|
||||||
|
|
||||||
|
@ -651,15 +651,12 @@ DEFINE_IDTENTRY_RAW(exc_int3)
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
idtentry_exit_user(regs);
|
idtentry_exit_user(regs);
|
||||||
} else {
|
} else {
|
||||||
nmi_enter();
|
bool irq_state = idtentry_enter_nmi(regs);
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
trace_hardirqs_off_finish();
|
|
||||||
if (!do_int3(regs))
|
if (!do_int3(regs))
|
||||||
die("int3", regs, 0);
|
die("int3", regs, 0);
|
||||||
if (regs->flags & X86_EFLAGS_IF)
|
|
||||||
trace_hardirqs_on_prepare();
|
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
nmi_exit();
|
idtentry_exit_nmi(regs, irq_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -867,9 +864,8 @@ out:
|
||||||
static __always_inline void exc_debug_kernel(struct pt_regs *regs,
|
static __always_inline void exc_debug_kernel(struct pt_regs *regs,
|
||||||
unsigned long dr6)
|
unsigned long dr6)
|
||||||
{
|
{
|
||||||
nmi_enter();
|
bool irq_state = idtentry_enter_nmi(regs);
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
trace_hardirqs_off_finish();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If something gets miswired and we end up here for a user mode
|
* If something gets miswired and we end up here for a user mode
|
||||||
|
@ -886,10 +882,8 @@ static __always_inline void exc_debug_kernel(struct pt_regs *regs,
|
||||||
|
|
||||||
handle_debug(regs, dr6, false);
|
handle_debug(regs, dr6, false);
|
||||||
|
|
||||||
if (regs->flags & X86_EFLAGS_IF)
|
|
||||||
trace_hardirqs_on_prepare();
|
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
nmi_exit();
|
idtentry_exit_nmi(regs, irq_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline void exc_debug_user(struct pt_regs *regs,
|
static __always_inline void exc_debug_user(struct pt_regs *regs,
|
||||||
|
@ -905,6 +899,7 @@ static __always_inline void exc_debug_user(struct pt_regs *regs,
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
|
|
||||||
handle_debug(regs, dr6, true);
|
handle_debug(regs, dr6, true);
|
||||||
|
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
idtentry_exit_user(regs);
|
idtentry_exit_user(regs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1377,7 +1377,7 @@ handle_page_fault(struct pt_regs *regs, unsigned long error_code,
|
||||||
DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
|
DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
|
||||||
{
|
{
|
||||||
unsigned long address = read_cr2();
|
unsigned long address = read_cr2();
|
||||||
bool rcu_exit;
|
idtentry_state_t state;
|
||||||
|
|
||||||
prefetchw(¤t->mm->mmap_lock);
|
prefetchw(¤t->mm->mmap_lock);
|
||||||
|
|
||||||
|
@ -1412,11 +1412,11 @@ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
|
||||||
* code reenabled RCU to avoid subsequent wreckage which helps
|
* code reenabled RCU to avoid subsequent wreckage which helps
|
||||||
* debugability.
|
* debugability.
|
||||||
*/
|
*/
|
||||||
rcu_exit = idtentry_enter_cond_rcu(regs);
|
state = idtentry_enter(regs);
|
||||||
|
|
||||||
instrumentation_begin();
|
instrumentation_begin();
|
||||||
handle_page_fault(regs, error_code, address);
|
handle_page_fault(regs, error_code, address);
|
||||||
instrumentation_end();
|
instrumentation_end();
|
||||||
|
|
||||||
idtentry_exit_cond_rcu(regs, rcu_exit);
|
idtentry_exit(regs, state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
#include <asm/cmpxchg.h>
|
#include <asm/cmpxchg.h>
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This Xtensa implementation assumes that the right mechanism
|
* This Xtensa implementation assumes that the right mechanism
|
||||||
* for exclusion is for locking interrupts to level EXCM_LEVEL.
|
* for exclusion is for locking interrupts to level EXCM_LEVEL.
|
||||||
|
|
|
@ -406,7 +406,7 @@ struct ioc {
|
||||||
enum ioc_running running;
|
enum ioc_running running;
|
||||||
atomic64_t vtime_rate;
|
atomic64_t vtime_rate;
|
||||||
|
|
||||||
seqcount_t period_seqcount;
|
seqcount_spinlock_t period_seqcount;
|
||||||
u32 period_at; /* wallclock starttime */
|
u32 period_at; /* wallclock starttime */
|
||||||
u64 period_at_vtime; /* vtime starttime */
|
u64 period_at_vtime; /* vtime starttime */
|
||||||
|
|
||||||
|
@ -873,7 +873,6 @@ static void ioc_now(struct ioc *ioc, struct ioc_now *now)
|
||||||
|
|
||||||
static void ioc_start_period(struct ioc *ioc, struct ioc_now *now)
|
static void ioc_start_period(struct ioc *ioc, struct ioc_now *now)
|
||||||
{
|
{
|
||||||
lockdep_assert_held(&ioc->lock);
|
|
||||||
WARN_ON_ONCE(ioc->running != IOC_RUNNING);
|
WARN_ON_ONCE(ioc->running != IOC_RUNNING);
|
||||||
|
|
||||||
write_seqcount_begin(&ioc->period_seqcount);
|
write_seqcount_begin(&ioc->period_seqcount);
|
||||||
|
@ -2001,7 +2000,7 @@ static int blk_iocost_init(struct request_queue *q)
|
||||||
|
|
||||||
ioc->running = IOC_IDLE;
|
ioc->running = IOC_IDLE;
|
||||||
atomic64_set(&ioc->vtime_rate, VTIME_PER_USEC);
|
atomic64_set(&ioc->vtime_rate, VTIME_PER_USEC);
|
||||||
seqcount_init(&ioc->period_seqcount);
|
seqcount_spinlock_init(&ioc->period_seqcount, &ioc->lock);
|
||||||
ioc->period_at = ktime_to_us(ktime_get());
|
ioc->period_at = ktime_to_us(ktime_get());
|
||||||
atomic64_set(&ioc->cur_period, 0);
|
atomic64_set(&ioc->cur_period, 0);
|
||||||
atomic_set(&ioc->hweight_gen, 0);
|
atomic_set(&ioc->hweight_gen, 0);
|
||||||
|
|
|
@ -51,12 +51,6 @@
|
||||||
DEFINE_WD_CLASS(reservation_ww_class);
|
DEFINE_WD_CLASS(reservation_ww_class);
|
||||||
EXPORT_SYMBOL(reservation_ww_class);
|
EXPORT_SYMBOL(reservation_ww_class);
|
||||||
|
|
||||||
struct lock_class_key reservation_seqcount_class;
|
|
||||||
EXPORT_SYMBOL(reservation_seqcount_class);
|
|
||||||
|
|
||||||
const char reservation_seqcount_string[] = "reservation_seqcount";
|
|
||||||
EXPORT_SYMBOL(reservation_seqcount_string);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dma_resv_list_alloc - allocate fence list
|
* dma_resv_list_alloc - allocate fence list
|
||||||
* @shared_max: number of fences we need space for
|
* @shared_max: number of fences we need space for
|
||||||
|
@ -135,9 +129,8 @@ subsys_initcall(dma_resv_lockdep);
|
||||||
void dma_resv_init(struct dma_resv *obj)
|
void dma_resv_init(struct dma_resv *obj)
|
||||||
{
|
{
|
||||||
ww_mutex_init(&obj->lock, &reservation_ww_class);
|
ww_mutex_init(&obj->lock, &reservation_ww_class);
|
||||||
|
seqcount_ww_mutex_init(&obj->seq, &obj->lock);
|
||||||
|
|
||||||
__seqcount_init(&obj->seq, reservation_seqcount_string,
|
|
||||||
&reservation_seqcount_class);
|
|
||||||
RCU_INIT_POINTER(obj->fence, NULL);
|
RCU_INIT_POINTER(obj->fence, NULL);
|
||||||
RCU_INIT_POINTER(obj->fence_excl, NULL);
|
RCU_INIT_POINTER(obj->fence_excl, NULL);
|
||||||
}
|
}
|
||||||
|
@ -267,7 +260,6 @@ void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||||
fobj = dma_resv_get_list(obj);
|
fobj = dma_resv_get_list(obj);
|
||||||
count = fobj->shared_count;
|
count = fobj->shared_count;
|
||||||
|
|
||||||
preempt_disable();
|
|
||||||
write_seqcount_begin(&obj->seq);
|
write_seqcount_begin(&obj->seq);
|
||||||
|
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
|
@ -289,7 +281,6 @@ replace:
|
||||||
smp_store_mb(fobj->shared_count, count);
|
smp_store_mb(fobj->shared_count, count);
|
||||||
|
|
||||||
write_seqcount_end(&obj->seq);
|
write_seqcount_end(&obj->seq);
|
||||||
preempt_enable();
|
|
||||||
dma_fence_put(old);
|
dma_fence_put(old);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_resv_add_shared_fence);
|
EXPORT_SYMBOL(dma_resv_add_shared_fence);
|
||||||
|
@ -316,14 +307,12 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||||
if (fence)
|
if (fence)
|
||||||
dma_fence_get(fence);
|
dma_fence_get(fence);
|
||||||
|
|
||||||
preempt_disable();
|
|
||||||
write_seqcount_begin(&obj->seq);
|
write_seqcount_begin(&obj->seq);
|
||||||
/* write_seqcount_begin provides the necessary memory barrier */
|
/* write_seqcount_begin provides the necessary memory barrier */
|
||||||
RCU_INIT_POINTER(obj->fence_excl, fence);
|
RCU_INIT_POINTER(obj->fence_excl, fence);
|
||||||
if (old)
|
if (old)
|
||||||
old->shared_count = 0;
|
old->shared_count = 0;
|
||||||
write_seqcount_end(&obj->seq);
|
write_seqcount_end(&obj->seq);
|
||||||
preempt_enable();
|
|
||||||
|
|
||||||
/* inplace update, no shared fences */
|
/* inplace update, no shared fences */
|
||||||
while (i--)
|
while (i--)
|
||||||
|
@ -401,13 +390,11 @@ retry:
|
||||||
src_list = dma_resv_get_list(dst);
|
src_list = dma_resv_get_list(dst);
|
||||||
old = dma_resv_get_excl(dst);
|
old = dma_resv_get_excl(dst);
|
||||||
|
|
||||||
preempt_disable();
|
|
||||||
write_seqcount_begin(&dst->seq);
|
write_seqcount_begin(&dst->seq);
|
||||||
/* write_seqcount_begin provides the necessary memory barrier */
|
/* write_seqcount_begin provides the necessary memory barrier */
|
||||||
RCU_INIT_POINTER(dst->fence_excl, new);
|
RCU_INIT_POINTER(dst->fence_excl, new);
|
||||||
RCU_INIT_POINTER(dst->fence, dst_list);
|
RCU_INIT_POINTER(dst->fence, dst_list);
|
||||||
write_seqcount_end(&dst->seq);
|
write_seqcount_end(&dst->seq);
|
||||||
preempt_enable();
|
|
||||||
|
|
||||||
dma_resv_list_free(src_list);
|
dma_resv_list_free(src_list);
|
||||||
dma_fence_put(old);
|
dma_fence_put(old);
|
||||||
|
|
|
@ -258,11 +258,9 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
|
||||||
new->shared_count = k;
|
new->shared_count = k;
|
||||||
|
|
||||||
/* Install the new fence list, seqcount provides the barriers */
|
/* Install the new fence list, seqcount provides the barriers */
|
||||||
preempt_disable();
|
|
||||||
write_seqcount_begin(&resv->seq);
|
write_seqcount_begin(&resv->seq);
|
||||||
RCU_INIT_POINTER(resv->fence, new);
|
RCU_INIT_POINTER(resv->fence, new);
|
||||||
write_seqcount_end(&resv->seq);
|
write_seqcount_end(&resv->seq);
|
||||||
preempt_enable();
|
|
||||||
|
|
||||||
/* Drop the references to the removed fences or move them to ef_list */
|
/* Drop the references to the removed fences or move them to ef_list */
|
||||||
for (i = j, k = 0; i < old->shared_count; ++i) {
|
for (i = j, k = 0; i < old->shared_count; ++i) {
|
||||||
|
|
|
@ -6935,7 +6935,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
|
||||||
} else
|
} else
|
||||||
goto abort;
|
goto abort;
|
||||||
spin_lock_init(&conf->device_lock);
|
spin_lock_init(&conf->device_lock);
|
||||||
seqcount_init(&conf->gen_lock);
|
seqcount_spinlock_init(&conf->gen_lock, &conf->device_lock);
|
||||||
mutex_init(&conf->cache_size_mutex);
|
mutex_init(&conf->cache_size_mutex);
|
||||||
init_waitqueue_head(&conf->wait_for_quiescent);
|
init_waitqueue_head(&conf->wait_for_quiescent);
|
||||||
init_waitqueue_head(&conf->wait_for_stripe);
|
init_waitqueue_head(&conf->wait_for_stripe);
|
||||||
|
|
|
@ -589,7 +589,7 @@ struct r5conf {
|
||||||
int prev_chunk_sectors;
|
int prev_chunk_sectors;
|
||||||
int prev_algo;
|
int prev_algo;
|
||||||
short generation; /* increments with every reshape */
|
short generation; /* increments with every reshape */
|
||||||
seqcount_t gen_lock; /* lock against generation changes */
|
seqcount_spinlock_t gen_lock; /* lock against generation changes */
|
||||||
unsigned long reshape_checkpoint; /* Time we last updated
|
unsigned long reshape_checkpoint; /* Time we last updated
|
||||||
* metadata */
|
* metadata */
|
||||||
long long min_offset_diff; /* minimum difference between
|
long long min_offset_diff; /* minimum difference between
|
||||||
|
|
|
@ -1746,7 +1746,7 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
|
||||||
dentry->d_lockref.count = 1;
|
dentry->d_lockref.count = 1;
|
||||||
dentry->d_flags = 0;
|
dentry->d_flags = 0;
|
||||||
spin_lock_init(&dentry->d_lock);
|
spin_lock_init(&dentry->d_lock);
|
||||||
seqcount_init(&dentry->d_seq);
|
seqcount_spinlock_init(&dentry->d_seq, &dentry->d_lock);
|
||||||
dentry->d_inode = NULL;
|
dentry->d_inode = NULL;
|
||||||
dentry->d_parent = dentry;
|
dentry->d_parent = dentry;
|
||||||
dentry->d_sb = sb;
|
dentry->d_sb = sb;
|
||||||
|
|
|
@ -117,7 +117,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
|
||||||
fs->users = 1;
|
fs->users = 1;
|
||||||
fs->in_exec = 0;
|
fs->in_exec = 0;
|
||||||
spin_lock_init(&fs->lock);
|
spin_lock_init(&fs->lock);
|
||||||
seqcount_init(&fs->seq);
|
seqcount_spinlock_init(&fs->seq, &fs->lock);
|
||||||
fs->umask = old->umask;
|
fs->umask = old->umask;
|
||||||
|
|
||||||
spin_lock(&old->lock);
|
spin_lock(&old->lock);
|
||||||
|
@ -163,6 +163,6 @@ EXPORT_SYMBOL(current_umask);
|
||||||
struct fs_struct init_fs = {
|
struct fs_struct init_fs = {
|
||||||
.users = 1,
|
.users = 1,
|
||||||
.lock = __SPIN_LOCK_UNLOCKED(init_fs.lock),
|
.lock = __SPIN_LOCK_UNLOCKED(init_fs.lock),
|
||||||
.seq = SEQCNT_ZERO(init_fs.seq),
|
.seq = SEQCNT_SPINLOCK_ZERO(init_fs.seq, &init_fs.lock),
|
||||||
.umask = 0022,
|
.umask = 0022,
|
||||||
};
|
};
|
||||||
|
|
|
@ -117,7 +117,7 @@ struct nfs4_state_owner {
|
||||||
unsigned long so_flags;
|
unsigned long so_flags;
|
||||||
struct list_head so_states;
|
struct list_head so_states;
|
||||||
struct nfs_seqid_counter so_seqid;
|
struct nfs_seqid_counter so_seqid;
|
||||||
seqcount_t so_reclaim_seqcount;
|
seqcount_spinlock_t so_reclaim_seqcount;
|
||||||
struct mutex so_delegreturn_mutex;
|
struct mutex so_delegreturn_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -509,7 +509,7 @@ nfs4_alloc_state_owner(struct nfs_server *server,
|
||||||
nfs4_init_seqid_counter(&sp->so_seqid);
|
nfs4_init_seqid_counter(&sp->so_seqid);
|
||||||
atomic_set(&sp->so_count, 1);
|
atomic_set(&sp->so_count, 1);
|
||||||
INIT_LIST_HEAD(&sp->so_lru);
|
INIT_LIST_HEAD(&sp->so_lru);
|
||||||
seqcount_init(&sp->so_reclaim_seqcount);
|
seqcount_spinlock_init(&sp->so_reclaim_seqcount, &sp->so_lock);
|
||||||
mutex_init(&sp->so_delegreturn_mutex);
|
mutex_init(&sp->so_delegreturn_mutex);
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ struct userfaultfd_ctx {
|
||||||
/* waitqueue head for events */
|
/* waitqueue head for events */
|
||||||
wait_queue_head_t event_wqh;
|
wait_queue_head_t event_wqh;
|
||||||
/* a refile sequence protected by fault_pending_wqh lock */
|
/* a refile sequence protected by fault_pending_wqh lock */
|
||||||
struct seqcount refile_seq;
|
seqcount_spinlock_t refile_seq;
|
||||||
/* pseudo fd refcounting */
|
/* pseudo fd refcounting */
|
||||||
refcount_t refcount;
|
refcount_t refcount;
|
||||||
/* userfaultfd syscall flags */
|
/* userfaultfd syscall flags */
|
||||||
|
@ -1998,7 +1998,7 @@ static void init_once_userfaultfd_ctx(void *mem)
|
||||||
init_waitqueue_head(&ctx->fault_wqh);
|
init_waitqueue_head(&ctx->fault_wqh);
|
||||||
init_waitqueue_head(&ctx->event_wqh);
|
init_waitqueue_head(&ctx->event_wqh);
|
||||||
init_waitqueue_head(&ctx->fd_wqh);
|
init_waitqueue_head(&ctx->fd_wqh);
|
||||||
seqcount_init(&ctx->refile_seq);
|
seqcount_spinlock_init(&ctx->refile_seq, &ctx->fault_pending_wqh.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE1(userfaultfd, int, flags)
|
SYSCALL_DEFINE1(userfaultfd, int, flags)
|
||||||
|
|
|
@ -159,8 +159,6 @@ ATOMIC_OP(xor, ^)
|
||||||
* resource counting etc..
|
* resource counting etc..
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ATOMIC_INIT(i) { (i) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* atomic_read - read atomic variable
|
* atomic_read - read atomic variable
|
||||||
* @v: pointer of type atomic_t
|
* @v: pointer of type atomic_t
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#define __ASM_GENERIC_QSPINLOCK_H
|
#define __ASM_GENERIC_QSPINLOCK_H
|
||||||
|
|
||||||
#include <asm-generic/qspinlock_types.h>
|
#include <asm-generic/qspinlock_types.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* queued_spin_is_locked - is the spinlock locked?
|
* queued_spin_is_locked - is the spinlock locked?
|
||||||
|
|
|
@ -9,15 +9,7 @@
|
||||||
#ifndef __ASM_GENERIC_QSPINLOCK_TYPES_H
|
#ifndef __ASM_GENERIC_QSPINLOCK_TYPES_H
|
||||||
#define __ASM_GENERIC_QSPINLOCK_TYPES_H
|
#define __ASM_GENERIC_QSPINLOCK_TYPES_H
|
||||||
|
|
||||||
/*
|
|
||||||
* Including atomic.h with PARAVIRT on will cause compilation errors because
|
|
||||||
* of recursive header file incluson via paravirt_types.h. So don't include
|
|
||||||
* it if PARAVIRT is on.
|
|
||||||
*/
|
|
||||||
#ifndef CONFIG_PARAVIRT
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/atomic.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct qspinlock {
|
typedef struct qspinlock {
|
||||||
union {
|
union {
|
||||||
|
|
|
@ -89,7 +89,7 @@ extern struct dentry_stat_t dentry_stat;
|
||||||
struct dentry {
|
struct dentry {
|
||||||
/* RCU lookup touched fields */
|
/* RCU lookup touched fields */
|
||||||
unsigned int d_flags; /* protected by d_lock */
|
unsigned int d_flags; /* protected by d_lock */
|
||||||
seqcount_t d_seq; /* per dentry seqlock */
|
seqcount_spinlock_t d_seq; /* per dentry seqlock */
|
||||||
struct hlist_bl_node d_hash; /* lookup hash list */
|
struct hlist_bl_node d_hash; /* lookup hash list */
|
||||||
struct dentry *d_parent; /* parent directory */
|
struct dentry *d_parent; /* parent directory */
|
||||||
struct qstr d_name;
|
struct qstr d_name;
|
||||||
|
|
|
@ -46,8 +46,6 @@
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
|
|
||||||
extern struct ww_class reservation_ww_class;
|
extern struct ww_class reservation_ww_class;
|
||||||
extern struct lock_class_key reservation_seqcount_class;
|
|
||||||
extern const char reservation_seqcount_string[];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct dma_resv_list - a list of shared fences
|
* struct dma_resv_list - a list of shared fences
|
||||||
|
@ -71,7 +69,7 @@ struct dma_resv_list {
|
||||||
*/
|
*/
|
||||||
struct dma_resv {
|
struct dma_resv {
|
||||||
struct ww_mutex lock;
|
struct ww_mutex lock;
|
||||||
seqcount_t seq;
|
seqcount_ww_mutex_t seq;
|
||||||
|
|
||||||
struct dma_fence __rcu *fence_excl;
|
struct dma_fence __rcu *fence_excl;
|
||||||
struct dma_resv_list __rcu *fence;
|
struct dma_resv_list __rcu *fence;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
struct fs_struct {
|
struct fs_struct {
|
||||||
int users;
|
int users;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
seqcount_t seq;
|
seqcount_spinlock_t seq;
|
||||||
int umask;
|
int umask;
|
||||||
int in_exec;
|
int in_exec;
|
||||||
struct path root, pwd;
|
struct path root, pwd;
|
||||||
|
|
|
@ -111,32 +111,42 @@ extern void rcu_nmi_exit(void);
|
||||||
/*
|
/*
|
||||||
* nmi_enter() can nest up to 15 times; see NMI_BITS.
|
* nmi_enter() can nest up to 15 times; see NMI_BITS.
|
||||||
*/
|
*/
|
||||||
#define nmi_enter() \
|
#define __nmi_enter() \
|
||||||
do { \
|
do { \
|
||||||
|
lockdep_off(); \
|
||||||
arch_nmi_enter(); \
|
arch_nmi_enter(); \
|
||||||
printk_nmi_enter(); \
|
printk_nmi_enter(); \
|
||||||
lockdep_off(); \
|
|
||||||
BUG_ON(in_nmi() == NMI_MASK); \
|
BUG_ON(in_nmi() == NMI_MASK); \
|
||||||
__preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \
|
__preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \
|
||||||
rcu_nmi_enter(); \
|
} while (0)
|
||||||
|
|
||||||
|
#define nmi_enter() \
|
||||||
|
do { \
|
||||||
|
__nmi_enter(); \
|
||||||
lockdep_hardirq_enter(); \
|
lockdep_hardirq_enter(); \
|
||||||
|
rcu_nmi_enter(); \
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
ftrace_nmi_enter(); \
|
ftrace_nmi_enter(); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define __nmi_exit() \
|
||||||
|
do { \
|
||||||
|
BUG_ON(!in_nmi()); \
|
||||||
|
__preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
|
||||||
|
printk_nmi_exit(); \
|
||||||
|
arch_nmi_exit(); \
|
||||||
|
lockdep_on(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define nmi_exit() \
|
#define nmi_exit() \
|
||||||
do { \
|
do { \
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
ftrace_nmi_exit(); \
|
ftrace_nmi_exit(); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
lockdep_hardirq_exit(); \
|
|
||||||
rcu_nmi_exit(); \
|
rcu_nmi_exit(); \
|
||||||
BUG_ON(!in_nmi()); \
|
lockdep_hardirq_exit(); \
|
||||||
__preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
|
__nmi_exit(); \
|
||||||
lockdep_on(); \
|
|
||||||
printk_nmi_exit(); \
|
|
||||||
arch_nmi_exit(); \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#endif /* LINUX_HARDIRQ_H */
|
#endif /* LINUX_HARDIRQ_H */
|
||||||
|
|
|
@ -159,7 +159,7 @@ struct hrtimer_clock_base {
|
||||||
struct hrtimer_cpu_base *cpu_base;
|
struct hrtimer_cpu_base *cpu_base;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
clockid_t clockid;
|
clockid_t clockid;
|
||||||
seqcount_t seq;
|
seqcount_raw_spinlock_t seq;
|
||||||
struct hrtimer *running;
|
struct hrtimer *running;
|
||||||
struct timerqueue_head active;
|
struct timerqueue_head active;
|
||||||
ktime_t (*get_time)(void);
|
ktime_t (*get_time)(void);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <linux/typecheck.h>
|
#include <linux/typecheck.h>
|
||||||
#include <asm/irqflags.h>
|
#include <asm/irqflags.h>
|
||||||
|
#include <asm/percpu.h>
|
||||||
|
|
||||||
/* Currently lockdep_softirqs_on/off is used only by lockdep */
|
/* Currently lockdep_softirqs_on/off is used only by lockdep */
|
||||||
#ifdef CONFIG_PROVE_LOCKING
|
#ifdef CONFIG_PROVE_LOCKING
|
||||||
|
@ -31,18 +32,22 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||||
|
|
||||||
|
DECLARE_PER_CPU(int, hardirqs_enabled);
|
||||||
|
DECLARE_PER_CPU(int, hardirq_context);
|
||||||
|
|
||||||
extern void trace_hardirqs_on_prepare(void);
|
extern void trace_hardirqs_on_prepare(void);
|
||||||
extern void trace_hardirqs_off_finish(void);
|
extern void trace_hardirqs_off_finish(void);
|
||||||
extern void trace_hardirqs_on(void);
|
extern void trace_hardirqs_on(void);
|
||||||
extern void trace_hardirqs_off(void);
|
extern void trace_hardirqs_off(void);
|
||||||
# define lockdep_hardirq_context(p) ((p)->hardirq_context)
|
# define lockdep_hardirq_context() (this_cpu_read(hardirq_context))
|
||||||
# define lockdep_softirq_context(p) ((p)->softirq_context)
|
# define lockdep_softirq_context(p) ((p)->softirq_context)
|
||||||
# define lockdep_hardirqs_enabled(p) ((p)->hardirqs_enabled)
|
# define lockdep_hardirqs_enabled() (this_cpu_read(hardirqs_enabled))
|
||||||
# define lockdep_softirqs_enabled(p) ((p)->softirqs_enabled)
|
# define lockdep_softirqs_enabled(p) ((p)->softirqs_enabled)
|
||||||
# define lockdep_hardirq_enter() \
|
# define lockdep_hardirq_enter() \
|
||||||
do { \
|
do { \
|
||||||
if (!current->hardirq_context++) \
|
if (this_cpu_inc_return(hardirq_context) == 1) \
|
||||||
current->hardirq_threaded = 0; \
|
current->hardirq_threaded = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
# define lockdep_hardirq_threaded() \
|
# define lockdep_hardirq_threaded() \
|
||||||
do { \
|
do { \
|
||||||
|
@ -50,7 +55,7 @@ do { \
|
||||||
} while (0)
|
} while (0)
|
||||||
# define lockdep_hardirq_exit() \
|
# define lockdep_hardirq_exit() \
|
||||||
do { \
|
do { \
|
||||||
current->hardirq_context--; \
|
this_cpu_dec(hardirq_context); \
|
||||||
} while (0)
|
} while (0)
|
||||||
# define lockdep_softirq_enter() \
|
# define lockdep_softirq_enter() \
|
||||||
do { \
|
do { \
|
||||||
|
@ -104,9 +109,9 @@ do { \
|
||||||
# define trace_hardirqs_off_finish() do { } while (0)
|
# define trace_hardirqs_off_finish() do { } while (0)
|
||||||
# define trace_hardirqs_on() do { } while (0)
|
# define trace_hardirqs_on() do { } while (0)
|
||||||
# define trace_hardirqs_off() do { } while (0)
|
# define trace_hardirqs_off() do { } while (0)
|
||||||
# define lockdep_hardirq_context(p) 0
|
# define lockdep_hardirq_context() 0
|
||||||
# define lockdep_softirq_context(p) 0
|
# define lockdep_softirq_context(p) 0
|
||||||
# define lockdep_hardirqs_enabled(p) 0
|
# define lockdep_hardirqs_enabled() 0
|
||||||
# define lockdep_softirqs_enabled(p) 0
|
# define lockdep_softirqs_enabled(p) 0
|
||||||
# define lockdep_hardirq_enter() do { } while (0)
|
# define lockdep_hardirq_enter() do { } while (0)
|
||||||
# define lockdep_hardirq_threaded() do { } while (0)
|
# define lockdep_hardirq_threaded() do { } while (0)
|
||||||
|
|
|
@ -42,7 +42,7 @@ struct kvm_kernel_irqfd {
|
||||||
wait_queue_entry_t wait;
|
wait_queue_entry_t wait;
|
||||||
/* Update side is protected by irqfds.lock */
|
/* Update side is protected by irqfds.lock */
|
||||||
struct kvm_kernel_irq_routing_entry irq_entry;
|
struct kvm_kernel_irq_routing_entry irq_entry;
|
||||||
seqcount_t irq_entry_sc;
|
seqcount_spinlock_t irq_entry_sc;
|
||||||
/* Used for level IRQ fast-path */
|
/* Used for level IRQ fast-path */
|
||||||
int gsi;
|
int gsi;
|
||||||
struct work_struct inject;
|
struct work_struct inject;
|
||||||
|
|
|
@ -10,33 +10,15 @@
|
||||||
#ifndef __LINUX_LOCKDEP_H
|
#ifndef __LINUX_LOCKDEP_H
|
||||||
#define __LINUX_LOCKDEP_H
|
#define __LINUX_LOCKDEP_H
|
||||||
|
|
||||||
|
#include <linux/lockdep_types.h>
|
||||||
|
#include <asm/percpu.h>
|
||||||
|
|
||||||
struct task_struct;
|
struct task_struct;
|
||||||
struct lockdep_map;
|
|
||||||
|
|
||||||
/* for sysctl */
|
/* for sysctl */
|
||||||
extern int prove_locking;
|
extern int prove_locking;
|
||||||
extern int lock_stat;
|
extern int lock_stat;
|
||||||
|
|
||||||
#define MAX_LOCKDEP_SUBCLASSES 8UL
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
|
|
||||||
enum lockdep_wait_type {
|
|
||||||
LD_WAIT_INV = 0, /* not checked, catch all */
|
|
||||||
|
|
||||||
LD_WAIT_FREE, /* wait free, rcu etc.. */
|
|
||||||
LD_WAIT_SPIN, /* spin loops, raw_spinlock_t etc.. */
|
|
||||||
|
|
||||||
#ifdef CONFIG_PROVE_RAW_LOCK_NESTING
|
|
||||||
LD_WAIT_CONFIG, /* CONFIG_PREEMPT_LOCK, spinlock_t etc.. */
|
|
||||||
#else
|
|
||||||
LD_WAIT_CONFIG = LD_WAIT_SPIN,
|
|
||||||
#endif
|
|
||||||
LD_WAIT_SLEEP, /* sleeping locks, mutex_t etc.. */
|
|
||||||
|
|
||||||
LD_WAIT_MAX, /* must be last */
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_LOCKDEP
|
#ifdef CONFIG_LOCKDEP
|
||||||
|
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
|
@ -44,147 +26,6 @@ enum lockdep_wait_type {
|
||||||
#include <linux/debug_locks.h>
|
#include <linux/debug_locks.h>
|
||||||
#include <linux/stacktrace.h>
|
#include <linux/stacktrace.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* We'd rather not expose kernel/lockdep_states.h this wide, but we do need
|
|
||||||
* the total number of states... :-(
|
|
||||||
*/
|
|
||||||
#define XXX_LOCK_USAGE_STATES (1+2*4)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NR_LOCKDEP_CACHING_CLASSES ... Number of classes
|
|
||||||
* cached in the instance of lockdep_map
|
|
||||||
*
|
|
||||||
* Currently main class (subclass == 0) and signle depth subclass
|
|
||||||
* are cached in lockdep_map. This optimization is mainly targeting
|
|
||||||
* on rq->lock. double_rq_lock() acquires this highly competitive with
|
|
||||||
* single depth.
|
|
||||||
*/
|
|
||||||
#define NR_LOCKDEP_CACHING_CLASSES 2
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A lockdep key is associated with each lock object. For static locks we use
|
|
||||||
* the lock address itself as the key. Dynamically allocated lock objects can
|
|
||||||
* have a statically or dynamically allocated key. Dynamically allocated lock
|
|
||||||
* keys must be registered before being used and must be unregistered before
|
|
||||||
* the key memory is freed.
|
|
||||||
*/
|
|
||||||
struct lockdep_subclass_key {
|
|
||||||
char __one_byte;
|
|
||||||
} __attribute__ ((__packed__));
|
|
||||||
|
|
||||||
/* hash_entry is used to keep track of dynamically allocated keys. */
|
|
||||||
struct lock_class_key {
|
|
||||||
union {
|
|
||||||
struct hlist_node hash_entry;
|
|
||||||
struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct lock_class_key __lockdep_no_validate__;
|
|
||||||
|
|
||||||
struct lock_trace;
|
|
||||||
|
|
||||||
#define LOCKSTAT_POINTS 4
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The lock-class itself. The order of the structure members matters.
|
|
||||||
* reinit_class() zeroes the key member and all subsequent members.
|
|
||||||
*/
|
|
||||||
struct lock_class {
|
|
||||||
/*
|
|
||||||
* class-hash:
|
|
||||||
*/
|
|
||||||
struct hlist_node hash_entry;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Entry in all_lock_classes when in use. Entry in free_lock_classes
|
|
||||||
* when not in use. Instances that are being freed are on one of the
|
|
||||||
* zapped_classes lists.
|
|
||||||
*/
|
|
||||||
struct list_head lock_entry;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* These fields represent a directed graph of lock dependencies,
|
|
||||||
* to every node we attach a list of "forward" and a list of
|
|
||||||
* "backward" graph nodes.
|
|
||||||
*/
|
|
||||||
struct list_head locks_after, locks_before;
|
|
||||||
|
|
||||||
const struct lockdep_subclass_key *key;
|
|
||||||
unsigned int subclass;
|
|
||||||
unsigned int dep_gen_id;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IRQ/softirq usage tracking bits:
|
|
||||||
*/
|
|
||||||
unsigned long usage_mask;
|
|
||||||
const struct lock_trace *usage_traces[XXX_LOCK_USAGE_STATES];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generation counter, when doing certain classes of graph walking,
|
|
||||||
* to ensure that we check one node only once:
|
|
||||||
*/
|
|
||||||
int name_version;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
short wait_type_inner;
|
|
||||||
short wait_type_outer;
|
|
||||||
|
|
||||||
#ifdef CONFIG_LOCK_STAT
|
|
||||||
unsigned long contention_point[LOCKSTAT_POINTS];
|
|
||||||
unsigned long contending_point[LOCKSTAT_POINTS];
|
|
||||||
#endif
|
|
||||||
} __no_randomize_layout;
|
|
||||||
|
|
||||||
#ifdef CONFIG_LOCK_STAT
|
|
||||||
struct lock_time {
|
|
||||||
s64 min;
|
|
||||||
s64 max;
|
|
||||||
s64 total;
|
|
||||||
unsigned long nr;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum bounce_type {
|
|
||||||
bounce_acquired_write,
|
|
||||||
bounce_acquired_read,
|
|
||||||
bounce_contended_write,
|
|
||||||
bounce_contended_read,
|
|
||||||
nr_bounce_types,
|
|
||||||
|
|
||||||
bounce_acquired = bounce_acquired_write,
|
|
||||||
bounce_contended = bounce_contended_write,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lock_class_stats {
|
|
||||||
unsigned long contention_point[LOCKSTAT_POINTS];
|
|
||||||
unsigned long contending_point[LOCKSTAT_POINTS];
|
|
||||||
struct lock_time read_waittime;
|
|
||||||
struct lock_time write_waittime;
|
|
||||||
struct lock_time read_holdtime;
|
|
||||||
struct lock_time write_holdtime;
|
|
||||||
unsigned long bounces[nr_bounce_types];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lock_class_stats lock_stats(struct lock_class *class);
|
|
||||||
void clear_lock_stats(struct lock_class *class);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Map the lock object (the lock instance) to the lock-class object.
|
|
||||||
* This is embedded into specific lock instances:
|
|
||||||
*/
|
|
||||||
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 */
|
|
||||||
#ifdef CONFIG_LOCK_STAT
|
|
||||||
int cpu;
|
|
||||||
unsigned long ip;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void lockdep_copy_map(struct lockdep_map *to,
|
static inline void lockdep_copy_map(struct lockdep_map *to,
|
||||||
struct lockdep_map *from)
|
struct lockdep_map *from)
|
||||||
{
|
{
|
||||||
|
@ -440,8 +281,6 @@ static inline void lock_set_subclass(struct lockdep_map *lock,
|
||||||
|
|
||||||
extern void lock_downgrade(struct lockdep_map *lock, unsigned long ip);
|
extern void lock_downgrade(struct lockdep_map *lock, unsigned long ip);
|
||||||
|
|
||||||
struct pin_cookie { unsigned int val; };
|
|
||||||
|
|
||||||
#define NIL_COOKIE (struct pin_cookie){ .val = 0U, }
|
#define NIL_COOKIE (struct pin_cookie){ .val = 0U, }
|
||||||
|
|
||||||
extern struct pin_cookie lock_pin_lock(struct lockdep_map *lock);
|
extern struct pin_cookie lock_pin_lock(struct lockdep_map *lock);
|
||||||
|
@ -520,10 +359,6 @@ static inline void lockdep_set_selftest_task(struct task_struct *task)
|
||||||
# define lockdep_reset() do { debug_locks = 1; } while (0)
|
# define lockdep_reset() do { debug_locks = 1; } while (0)
|
||||||
# define lockdep_free_key_range(start, size) do { } while (0)
|
# define lockdep_free_key_range(start, size) do { } while (0)
|
||||||
# define lockdep_sys_exit() do { } while (0)
|
# define lockdep_sys_exit() do { } while (0)
|
||||||
/*
|
|
||||||
* The class key takes no space if lockdep is disabled:
|
|
||||||
*/
|
|
||||||
struct lock_class_key { };
|
|
||||||
|
|
||||||
static inline void lockdep_register_key(struct lock_class_key *key)
|
static inline void lockdep_register_key(struct lock_class_key *key)
|
||||||
{
|
{
|
||||||
|
@ -533,11 +368,6 @@ static inline void lockdep_unregister_key(struct lock_class_key *key)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* The lockdep_map takes no space if lockdep is disabled:
|
|
||||||
*/
|
|
||||||
struct lockdep_map { };
|
|
||||||
|
|
||||||
#define lockdep_depth(tsk) (0)
|
#define lockdep_depth(tsk) (0)
|
||||||
|
|
||||||
#define lockdep_is_held_type(l, r) (1)
|
#define lockdep_is_held_type(l, r) (1)
|
||||||
|
@ -549,8 +379,6 @@ struct lockdep_map { };
|
||||||
|
|
||||||
#define lockdep_recursing(tsk) (0)
|
#define lockdep_recursing(tsk) (0)
|
||||||
|
|
||||||
struct pin_cookie { };
|
|
||||||
|
|
||||||
#define NIL_COOKIE (struct pin_cookie){ }
|
#define NIL_COOKIE (struct pin_cookie){ }
|
||||||
|
|
||||||
#define lockdep_pin_lock(l) ({ struct pin_cookie cookie = { }; cookie; })
|
#define lockdep_pin_lock(l) ({ struct pin_cookie cookie = { }; cookie; })
|
||||||
|
@ -703,38 +531,58 @@ do { \
|
||||||
lock_release(&(lock)->dep_map, _THIS_IP_); \
|
lock_release(&(lock)->dep_map, _THIS_IP_); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define lockdep_assert_irqs_enabled() do { \
|
DECLARE_PER_CPU(int, hardirqs_enabled);
|
||||||
WARN_ONCE(debug_locks && !current->lockdep_recursion && \
|
DECLARE_PER_CPU(int, hardirq_context);
|
||||||
!current->hardirqs_enabled, \
|
|
||||||
"IRQs not enabled as expected\n"); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define lockdep_assert_irqs_disabled() do { \
|
#define lockdep_assert_irqs_enabled() \
|
||||||
WARN_ONCE(debug_locks && !current->lockdep_recursion && \
|
do { \
|
||||||
current->hardirqs_enabled, \
|
WARN_ON_ONCE(debug_locks && !this_cpu_read(hardirqs_enabled)); \
|
||||||
"IRQs not disabled as expected\n"); \
|
} while (0)
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define lockdep_assert_in_irq() do { \
|
#define lockdep_assert_irqs_disabled() \
|
||||||
WARN_ONCE(debug_locks && !current->lockdep_recursion && \
|
do { \
|
||||||
!current->hardirq_context, \
|
WARN_ON_ONCE(debug_locks && this_cpu_read(hardirqs_enabled)); \
|
||||||
"Not in hardirq as expected\n"); \
|
} while (0)
|
||||||
} while (0)
|
|
||||||
|
#define lockdep_assert_in_irq() \
|
||||||
|
do { \
|
||||||
|
WARN_ON_ONCE(debug_locks && !this_cpu_read(hardirq_context)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define lockdep_assert_preemption_enabled() \
|
||||||
|
do { \
|
||||||
|
WARN_ON_ONCE(IS_ENABLED(CONFIG_PREEMPT_COUNT) && \
|
||||||
|
debug_locks && \
|
||||||
|
(preempt_count() != 0 || \
|
||||||
|
!this_cpu_read(hardirqs_enabled))); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define lockdep_assert_preemption_disabled() \
|
||||||
|
do { \
|
||||||
|
WARN_ON_ONCE(IS_ENABLED(CONFIG_PREEMPT_COUNT) && \
|
||||||
|
debug_locks && \
|
||||||
|
(preempt_count() == 0 && \
|
||||||
|
this_cpu_read(hardirqs_enabled))); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define might_lock(lock) do { } while (0)
|
# define might_lock(lock) do { } while (0)
|
||||||
# define might_lock_read(lock) do { } while (0)
|
# define might_lock_read(lock) do { } while (0)
|
||||||
# define might_lock_nested(lock, subclass) do { } while (0)
|
# define might_lock_nested(lock, subclass) do { } while (0)
|
||||||
|
|
||||||
# define lockdep_assert_irqs_enabled() do { } while (0)
|
# define lockdep_assert_irqs_enabled() do { } while (0)
|
||||||
# define lockdep_assert_irqs_disabled() do { } while (0)
|
# define lockdep_assert_irqs_disabled() do { } while (0)
|
||||||
# define lockdep_assert_in_irq() do { } while (0)
|
# define lockdep_assert_in_irq() do { } while (0)
|
||||||
|
|
||||||
|
# define lockdep_assert_preemption_enabled() do { } while (0)
|
||||||
|
# define lockdep_assert_preemption_disabled() do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PROVE_RAW_LOCK_NESTING
|
#ifdef CONFIG_PROVE_RAW_LOCK_NESTING
|
||||||
|
|
||||||
# define lockdep_assert_RT_in_threaded_ctx() do { \
|
# define lockdep_assert_RT_in_threaded_ctx() do { \
|
||||||
WARN_ONCE(debug_locks && !current->lockdep_recursion && \
|
WARN_ONCE(debug_locks && !current->lockdep_recursion && \
|
||||||
current->hardirq_context && \
|
lockdep_hardirq_context() && \
|
||||||
!(current->hardirq_threaded || current->irq_config), \
|
!(current->hardirq_threaded || current->irq_config), \
|
||||||
"Not in threaded context on PREEMPT_RT as expected\n"); \
|
"Not in threaded context on PREEMPT_RT as expected\n"); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Runtime locking correctness validator
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
|
||||||
|
* Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
|
||||||
|
*
|
||||||
|
* see Documentation/locking/lockdep-design.rst for more details.
|
||||||
|
*/
|
||||||
|
#ifndef __LINUX_LOCKDEP_TYPES_H
|
||||||
|
#define __LINUX_LOCKDEP_TYPES_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#define MAX_LOCKDEP_SUBCLASSES 8UL
|
||||||
|
|
||||||
|
enum lockdep_wait_type {
|
||||||
|
LD_WAIT_INV = 0, /* not checked, catch all */
|
||||||
|
|
||||||
|
LD_WAIT_FREE, /* wait free, rcu etc.. */
|
||||||
|
LD_WAIT_SPIN, /* spin loops, raw_spinlock_t etc.. */
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROVE_RAW_LOCK_NESTING
|
||||||
|
LD_WAIT_CONFIG, /* CONFIG_PREEMPT_LOCK, spinlock_t etc.. */
|
||||||
|
#else
|
||||||
|
LD_WAIT_CONFIG = LD_WAIT_SPIN,
|
||||||
|
#endif
|
||||||
|
LD_WAIT_SLEEP, /* sleeping locks, mutex_t etc.. */
|
||||||
|
|
||||||
|
LD_WAIT_MAX, /* must be last */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_LOCKDEP
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We'd rather not expose kernel/lockdep_states.h this wide, but we do need
|
||||||
|
* the total number of states... :-(
|
||||||
|
*/
|
||||||
|
#define XXX_LOCK_USAGE_STATES (1+2*4)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NR_LOCKDEP_CACHING_CLASSES ... Number of classes
|
||||||
|
* cached in the instance of lockdep_map
|
||||||
|
*
|
||||||
|
* Currently main class (subclass == 0) and signle depth subclass
|
||||||
|
* are cached in lockdep_map. This optimization is mainly targeting
|
||||||
|
* on rq->lock. double_rq_lock() acquires this highly competitive with
|
||||||
|
* single depth.
|
||||||
|
*/
|
||||||
|
#define NR_LOCKDEP_CACHING_CLASSES 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A lockdep key is associated with each lock object. For static locks we use
|
||||||
|
* the lock address itself as the key. Dynamically allocated lock objects can
|
||||||
|
* have a statically or dynamically allocated key. Dynamically allocated lock
|
||||||
|
* keys must be registered before being used and must be unregistered before
|
||||||
|
* the key memory is freed.
|
||||||
|
*/
|
||||||
|
struct lockdep_subclass_key {
|
||||||
|
char __one_byte;
|
||||||
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
|
/* hash_entry is used to keep track of dynamically allocated keys. */
|
||||||
|
struct lock_class_key {
|
||||||
|
union {
|
||||||
|
struct hlist_node hash_entry;
|
||||||
|
struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct lock_class_key __lockdep_no_validate__;
|
||||||
|
|
||||||
|
struct lock_trace;
|
||||||
|
|
||||||
|
#define LOCKSTAT_POINTS 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The lock-class itself. The order of the structure members matters.
|
||||||
|
* reinit_class() zeroes the key member and all subsequent members.
|
||||||
|
*/
|
||||||
|
struct lock_class {
|
||||||
|
/*
|
||||||
|
* class-hash:
|
||||||
|
*/
|
||||||
|
struct hlist_node hash_entry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Entry in all_lock_classes when in use. Entry in free_lock_classes
|
||||||
|
* when not in use. Instances that are being freed are on one of the
|
||||||
|
* zapped_classes lists.
|
||||||
|
*/
|
||||||
|
struct list_head lock_entry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These fields represent a directed graph of lock dependencies,
|
||||||
|
* to every node we attach a list of "forward" and a list of
|
||||||
|
* "backward" graph nodes.
|
||||||
|
*/
|
||||||
|
struct list_head locks_after, locks_before;
|
||||||
|
|
||||||
|
const struct lockdep_subclass_key *key;
|
||||||
|
unsigned int subclass;
|
||||||
|
unsigned int dep_gen_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IRQ/softirq usage tracking bits:
|
||||||
|
*/
|
||||||
|
unsigned long usage_mask;
|
||||||
|
const struct lock_trace *usage_traces[XXX_LOCK_USAGE_STATES];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generation counter, when doing certain classes of graph walking,
|
||||||
|
* to ensure that we check one node only once:
|
||||||
|
*/
|
||||||
|
int name_version;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
short wait_type_inner;
|
||||||
|
short wait_type_outer;
|
||||||
|
|
||||||
|
#ifdef CONFIG_LOCK_STAT
|
||||||
|
unsigned long contention_point[LOCKSTAT_POINTS];
|
||||||
|
unsigned long contending_point[LOCKSTAT_POINTS];
|
||||||
|
#endif
|
||||||
|
} __no_randomize_layout;
|
||||||
|
|
||||||
|
#ifdef CONFIG_LOCK_STAT
|
||||||
|
struct lock_time {
|
||||||
|
s64 min;
|
||||||
|
s64 max;
|
||||||
|
s64 total;
|
||||||
|
unsigned long nr;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum bounce_type {
|
||||||
|
bounce_acquired_write,
|
||||||
|
bounce_acquired_read,
|
||||||
|
bounce_contended_write,
|
||||||
|
bounce_contended_read,
|
||||||
|
nr_bounce_types,
|
||||||
|
|
||||||
|
bounce_acquired = bounce_acquired_write,
|
||||||
|
bounce_contended = bounce_contended_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lock_class_stats {
|
||||||
|
unsigned long contention_point[LOCKSTAT_POINTS];
|
||||||
|
unsigned long contending_point[LOCKSTAT_POINTS];
|
||||||
|
struct lock_time read_waittime;
|
||||||
|
struct lock_time write_waittime;
|
||||||
|
struct lock_time read_holdtime;
|
||||||
|
struct lock_time write_holdtime;
|
||||||
|
unsigned long bounces[nr_bounce_types];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lock_class_stats lock_stats(struct lock_class *class);
|
||||||
|
void clear_lock_stats(struct lock_class *class);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map the lock object (the lock instance) to the lock-class object.
|
||||||
|
* This is embedded into specific lock instances:
|
||||||
|
*/
|
||||||
|
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 */
|
||||||
|
#ifdef CONFIG_LOCK_STAT
|
||||||
|
int cpu;
|
||||||
|
unsigned long ip;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pin_cookie { unsigned int val; };
|
||||||
|
|
||||||
|
#else /* !CONFIG_LOCKDEP */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The class key takes no space if lockdep is disabled:
|
||||||
|
*/
|
||||||
|
struct lock_class_key { };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The lockdep_map takes no space if lockdep is disabled:
|
||||||
|
*/
|
||||||
|
struct lockdep_map { };
|
||||||
|
|
||||||
|
struct pin_cookie { };
|
||||||
|
|
||||||
|
#endif /* !LOCKDEP */
|
||||||
|
|
||||||
|
#endif /* __LINUX_LOCKDEP_TYPES_H */
|
|
@ -60,39 +60,39 @@ static inline int rwsem_is_locked(struct rw_semaphore *sem)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RWSEM_UNLOCKED_VALUE 0L
|
#define RWSEM_UNLOCKED_VALUE 0L
|
||||||
#define __RWSEM_INIT_COUNT(name) .count = ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE)
|
#define __RWSEM_COUNT_INIT(name) .count = ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE)
|
||||||
|
|
||||||
/* Common initializer macros and functions */
|
/* Common initializer macros and functions */
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||||
# define __RWSEM_DEP_MAP_INIT(lockname) \
|
# define __RWSEM_DEP_MAP_INIT(lockname) \
|
||||||
, .dep_map = { \
|
.dep_map = { \
|
||||||
.name = #lockname, \
|
.name = #lockname, \
|
||||||
.wait_type_inner = LD_WAIT_SLEEP, \
|
.wait_type_inner = LD_WAIT_SLEEP, \
|
||||||
}
|
},
|
||||||
#else
|
#else
|
||||||
# define __RWSEM_DEP_MAP_INIT(lockname)
|
# define __RWSEM_DEP_MAP_INIT(lockname)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_RWSEMS
|
#ifdef CONFIG_DEBUG_RWSEMS
|
||||||
# define __DEBUG_RWSEM_INITIALIZER(lockname) , .magic = &lockname
|
# define __RWSEM_DEBUG_INIT(lockname) .magic = &lockname,
|
||||||
#else
|
#else
|
||||||
# define __DEBUG_RWSEM_INITIALIZER(lockname)
|
# define __RWSEM_DEBUG_INIT(lockname)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
|
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
|
||||||
#define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED
|
#define __RWSEM_OPT_INIT(lockname) .osq = OSQ_LOCK_UNLOCKED,
|
||||||
#else
|
#else
|
||||||
#define __RWSEM_OPT_INIT(lockname)
|
#define __RWSEM_OPT_INIT(lockname)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define __RWSEM_INITIALIZER(name) \
|
#define __RWSEM_INITIALIZER(name) \
|
||||||
{ __RWSEM_INIT_COUNT(name), \
|
{ __RWSEM_COUNT_INIT(name), \
|
||||||
.owner = ATOMIC_LONG_INIT(0), \
|
.owner = ATOMIC_LONG_INIT(0), \
|
||||||
.wait_list = LIST_HEAD_INIT((name).wait_list), \
|
|
||||||
.wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \
|
|
||||||
__RWSEM_OPT_INIT(name) \
|
__RWSEM_OPT_INIT(name) \
|
||||||
__DEBUG_RWSEM_INITIALIZER(name) \
|
.wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock),\
|
||||||
|
.wait_list = LIST_HEAD_INIT((name).wait_list), \
|
||||||
|
__RWSEM_DEBUG_INIT(name) \
|
||||||
__RWSEM_DEP_MAP_INIT(name) }
|
__RWSEM_DEP_MAP_INIT(name) }
|
||||||
|
|
||||||
#define DECLARE_RWSEM(name) \
|
#define DECLARE_RWSEM(name) \
|
||||||
|
|
|
@ -986,8 +986,6 @@ struct task_struct {
|
||||||
unsigned long hardirq_disable_ip;
|
unsigned long hardirq_disable_ip;
|
||||||
unsigned int hardirq_enable_event;
|
unsigned int hardirq_enable_event;
|
||||||
unsigned int hardirq_disable_event;
|
unsigned int hardirq_disable_event;
|
||||||
int hardirqs_enabled;
|
|
||||||
int hardirq_context;
|
|
||||||
u64 hardirq_chain_key;
|
u64 hardirq_chain_key;
|
||||||
unsigned long softirq_disable_ip;
|
unsigned long softirq_disable_ip;
|
||||||
unsigned long softirq_enable_ip;
|
unsigned long softirq_enable_ip;
|
||||||
|
@ -1052,7 +1050,7 @@ struct task_struct {
|
||||||
/* Protected by ->alloc_lock: */
|
/* Protected by ->alloc_lock: */
|
||||||
nodemask_t mems_allowed;
|
nodemask_t mems_allowed;
|
||||||
/* Seqence number to catch updates: */
|
/* Seqence number to catch updates: */
|
||||||
seqcount_t mems_allowed_seq;
|
seqcount_spinlock_t mems_allowed_seq;
|
||||||
int cpuset_mem_spread_rotor;
|
int cpuset_mem_spread_rotor;
|
||||||
int cpuset_slab_spread_rotor;
|
int cpuset_slab_spread_rotor;
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -56,6 +56,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/stringify.h>
|
#include <linux/stringify.h>
|
||||||
#include <linux/bottom_half.h>
|
#include <linux/bottom_half.h>
|
||||||
|
#include <linux/lockdep.h>
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
#include <asm/mmiowb.h>
|
#include <asm/mmiowb.h>
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
# include <linux/spinlock_types_up.h>
|
# include <linux/spinlock_types_up.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <linux/lockdep.h>
|
#include <linux/lockdep_types.h>
|
||||||
|
|
||||||
typedef struct raw_spinlock {
|
typedef struct raw_spinlock {
|
||||||
arch_spinlock_t raw_lock;
|
arch_spinlock_t raw_lock;
|
||||||
|
|
|
@ -167,6 +167,8 @@ typedef struct {
|
||||||
int counter;
|
int counter;
|
||||||
} atomic_t;
|
} atomic_t;
|
||||||
|
|
||||||
|
#define ATOMIC_INIT(i) { (i) }
|
||||||
|
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
typedef struct {
|
typedef struct {
|
||||||
s64 counter;
|
s64 counter;
|
||||||
|
|
|
@ -286,7 +286,7 @@ int nf_conntrack_hash_resize(unsigned int hashsize);
|
||||||
|
|
||||||
extern struct hlist_nulls_head *nf_conntrack_hash;
|
extern struct hlist_nulls_head *nf_conntrack_hash;
|
||||||
extern unsigned int nf_conntrack_htable_size;
|
extern unsigned int nf_conntrack_htable_size;
|
||||||
extern seqcount_t nf_conntrack_generation;
|
extern seqcount_spinlock_t nf_conntrack_generation;
|
||||||
extern unsigned int nf_conntrack_max;
|
extern unsigned int nf_conntrack_max;
|
||||||
|
|
||||||
/* must be called with rcu read lock held */
|
/* must be called with rcu read lock held */
|
||||||
|
|
|
@ -154,7 +154,8 @@ struct task_struct init_task
|
||||||
.trc_holdout_list = LIST_HEAD_INIT(init_task.trc_holdout_list),
|
.trc_holdout_list = LIST_HEAD_INIT(init_task.trc_holdout_list),
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_CPUSETS
|
#ifdef CONFIG_CPUSETS
|
||||||
.mems_allowed_seq = SEQCNT_ZERO(init_task.mems_allowed_seq),
|
.mems_allowed_seq = SEQCNT_SPINLOCK_ZERO(init_task.mems_allowed_seq,
|
||||||
|
&init_task.alloc_lock),
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_RT_MUTEXES
|
#ifdef CONFIG_RT_MUTEXES
|
||||||
.pi_waiters = RB_ROOT_CACHED,
|
.pi_waiters = RB_ROOT_CACHED,
|
||||||
|
|
|
@ -1954,8 +1954,8 @@ static __latent_entropy struct task_struct *copy_process(
|
||||||
|
|
||||||
rt_mutex_init_task(p);
|
rt_mutex_init_task(p);
|
||||||
|
|
||||||
|
lockdep_assert_irqs_enabled();
|
||||||
#ifdef CONFIG_PROVE_LOCKING
|
#ifdef CONFIG_PROVE_LOCKING
|
||||||
DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
|
|
||||||
DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
|
DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
|
||||||
#endif
|
#endif
|
||||||
retval = -EAGAIN;
|
retval = -EAGAIN;
|
||||||
|
@ -2032,11 +2032,10 @@ static __latent_entropy struct task_struct *copy_process(
|
||||||
#ifdef CONFIG_CPUSETS
|
#ifdef CONFIG_CPUSETS
|
||||||
p->cpuset_mem_spread_rotor = NUMA_NO_NODE;
|
p->cpuset_mem_spread_rotor = NUMA_NO_NODE;
|
||||||
p->cpuset_slab_spread_rotor = NUMA_NO_NODE;
|
p->cpuset_slab_spread_rotor = NUMA_NO_NODE;
|
||||||
seqcount_init(&p->mems_allowed_seq);
|
seqcount_spinlock_init(&p->mems_allowed_seq, &p->alloc_lock);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||||
p->irq_events = 0;
|
p->irq_events = 0;
|
||||||
p->hardirqs_enabled = 0;
|
|
||||||
p->hardirq_enable_ip = 0;
|
p->hardirq_enable_ip = 0;
|
||||||
p->hardirq_enable_event = 0;
|
p->hardirq_enable_event = 0;
|
||||||
p->hardirq_disable_ip = _THIS_IP_;
|
p->hardirq_disable_ip = _THIS_IP_;
|
||||||
|
@ -2046,7 +2045,6 @@ static __latent_entropy struct task_struct *copy_process(
|
||||||
p->softirq_enable_event = 0;
|
p->softirq_enable_event = 0;
|
||||||
p->softirq_disable_ip = 0;
|
p->softirq_disable_ip = 0;
|
||||||
p->softirq_disable_event = 0;
|
p->softirq_disable_event = 0;
|
||||||
p->hardirq_context = 0;
|
|
||||||
p->softirq_context = 0;
|
p->softirq_context = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
114
kernel/futex.c
114
kernel/futex.c
|
@ -32,30 +32,13 @@
|
||||||
* "But they come in a choice of three flavours!"
|
* "But they come in a choice of three flavours!"
|
||||||
*/
|
*/
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/poll.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/file.h>
|
|
||||||
#include <linux/jhash.h>
|
#include <linux/jhash.h>
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/futex.h>
|
|
||||||
#include <linux/mount.h>
|
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
#include <linux/signal.h>
|
|
||||||
#include <linux/export.h>
|
|
||||||
#include <linux/magic.h>
|
|
||||||
#include <linux/pid.h>
|
|
||||||
#include <linux/nsproxy.h>
|
|
||||||
#include <linux/ptrace.h>
|
|
||||||
#include <linux/sched/rt.h>
|
|
||||||
#include <linux/sched/wake_q.h>
|
|
||||||
#include <linux/sched/mm.h>
|
|
||||||
#include <linux/hugetlb.h>
|
#include <linux/hugetlb.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
#include <linux/memblock.h>
|
#include <linux/memblock.h>
|
||||||
#include <linux/fault-inject.h>
|
#include <linux/fault-inject.h>
|
||||||
#include <linux/refcount.h>
|
|
||||||
|
|
||||||
#include <asm/futex.h>
|
#include <asm/futex.h>
|
||||||
|
|
||||||
|
@ -476,7 +459,7 @@ static u64 get_inode_sequence_number(struct inode *inode)
|
||||||
/**
|
/**
|
||||||
* get_futex_key() - Get parameters which are the keys for a futex
|
* get_futex_key() - Get parameters which are the keys for a futex
|
||||||
* @uaddr: virtual address of the futex
|
* @uaddr: virtual address of the futex
|
||||||
* @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
|
* @fshared: false for a PROCESS_PRIVATE futex, true for PROCESS_SHARED
|
||||||
* @key: address where result is stored.
|
* @key: address where result is stored.
|
||||||
* @rw: mapping needs to be read/write (values: FUTEX_READ,
|
* @rw: mapping needs to be read/write (values: FUTEX_READ,
|
||||||
* FUTEX_WRITE)
|
* FUTEX_WRITE)
|
||||||
|
@ -500,8 +483,8 @@ static u64 get_inode_sequence_number(struct inode *inode)
|
||||||
*
|
*
|
||||||
* lock_page() might sleep, the caller should not hold a spinlock.
|
* lock_page() might sleep, the caller should not hold a spinlock.
|
||||||
*/
|
*/
|
||||||
static int
|
static int get_futex_key(u32 __user *uaddr, bool fshared, union futex_key *key,
|
||||||
get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, enum futex_access rw)
|
enum futex_access rw)
|
||||||
{
|
{
|
||||||
unsigned long address = (unsigned long)uaddr;
|
unsigned long address = (unsigned long)uaddr;
|
||||||
struct mm_struct *mm = current->mm;
|
struct mm_struct *mm = current->mm;
|
||||||
|
@ -538,7 +521,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, enum futex_a
|
||||||
|
|
||||||
again:
|
again:
|
||||||
/* Ignore any VERIFY_READ mapping (futex common case) */
|
/* Ignore any VERIFY_READ mapping (futex common case) */
|
||||||
if (unlikely(should_fail_futex(fshared)))
|
if (unlikely(should_fail_futex(true)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
err = get_user_pages_fast(address, 1, FOLL_WRITE, &page);
|
err = get_user_pages_fast(address, 1, FOLL_WRITE, &page);
|
||||||
|
@ -626,7 +609,7 @@ again:
|
||||||
* A RO anonymous page will never change and thus doesn't make
|
* A RO anonymous page will never change and thus doesn't make
|
||||||
* sense for futex operations.
|
* sense for futex operations.
|
||||||
*/
|
*/
|
||||||
if (unlikely(should_fail_futex(fshared)) || ro) {
|
if (unlikely(should_fail_futex(true)) || ro) {
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -677,10 +660,6 @@ out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void put_futex_key(union futex_key *key)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fault_in_user_writeable() - Fault in user address and verify RW access
|
* fault_in_user_writeable() - Fault in user address and verify RW access
|
||||||
* @uaddr: pointer to faulting user space address
|
* @uaddr: pointer to faulting user space address
|
||||||
|
@ -1611,13 +1590,13 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
|
||||||
|
|
||||||
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, FUTEX_READ);
|
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, FUTEX_READ);
|
||||||
if (unlikely(ret != 0))
|
if (unlikely(ret != 0))
|
||||||
goto out;
|
return ret;
|
||||||
|
|
||||||
hb = hash_futex(&key);
|
hb = hash_futex(&key);
|
||||||
|
|
||||||
/* Make sure we really have tasks to wakeup */
|
/* Make sure we really have tasks to wakeup */
|
||||||
if (!hb_waiters_pending(hb))
|
if (!hb_waiters_pending(hb))
|
||||||
goto out_put_key;
|
return ret;
|
||||||
|
|
||||||
spin_lock(&hb->lock);
|
spin_lock(&hb->lock);
|
||||||
|
|
||||||
|
@ -1640,9 +1619,6 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
|
||||||
|
|
||||||
spin_unlock(&hb->lock);
|
spin_unlock(&hb->lock);
|
||||||
wake_up_q(&wake_q);
|
wake_up_q(&wake_q);
|
||||||
out_put_key:
|
|
||||||
put_futex_key(&key);
|
|
||||||
out:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1709,10 +1685,10 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
|
||||||
retry:
|
retry:
|
||||||
ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ);
|
ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ);
|
||||||
if (unlikely(ret != 0))
|
if (unlikely(ret != 0))
|
||||||
goto out;
|
return ret;
|
||||||
ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, FUTEX_WRITE);
|
ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, FUTEX_WRITE);
|
||||||
if (unlikely(ret != 0))
|
if (unlikely(ret != 0))
|
||||||
goto out_put_key1;
|
return ret;
|
||||||
|
|
||||||
hb1 = hash_futex(&key1);
|
hb1 = hash_futex(&key1);
|
||||||
hb2 = hash_futex(&key2);
|
hb2 = hash_futex(&key2);
|
||||||
|
@ -1730,13 +1706,13 @@ retry_private:
|
||||||
* an MMU, but we might get them from range checking
|
* an MMU, but we might get them from range checking
|
||||||
*/
|
*/
|
||||||
ret = op_ret;
|
ret = op_ret;
|
||||||
goto out_put_keys;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op_ret == -EFAULT) {
|
if (op_ret == -EFAULT) {
|
||||||
ret = fault_in_user_writeable(uaddr2);
|
ret = fault_in_user_writeable(uaddr2);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_put_keys;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & FLAGS_SHARED)) {
|
if (!(flags & FLAGS_SHARED)) {
|
||||||
|
@ -1744,8 +1720,6 @@ retry_private:
|
||||||
goto retry_private;
|
goto retry_private;
|
||||||
}
|
}
|
||||||
|
|
||||||
put_futex_key(&key2);
|
|
||||||
put_futex_key(&key1);
|
|
||||||
cond_resched();
|
cond_resched();
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
@ -1781,11 +1755,6 @@ retry_private:
|
||||||
out_unlock:
|
out_unlock:
|
||||||
double_unlock_hb(hb1, hb2);
|
double_unlock_hb(hb1, hb2);
|
||||||
wake_up_q(&wake_q);
|
wake_up_q(&wake_q);
|
||||||
out_put_keys:
|
|
||||||
put_futex_key(&key2);
|
|
||||||
out_put_key1:
|
|
||||||
put_futex_key(&key1);
|
|
||||||
out:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1992,20 +1961,18 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
|
||||||
retry:
|
retry:
|
||||||
ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ);
|
ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ);
|
||||||
if (unlikely(ret != 0))
|
if (unlikely(ret != 0))
|
||||||
goto out;
|
return ret;
|
||||||
ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
|
ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
|
||||||
requeue_pi ? FUTEX_WRITE : FUTEX_READ);
|
requeue_pi ? FUTEX_WRITE : FUTEX_READ);
|
||||||
if (unlikely(ret != 0))
|
if (unlikely(ret != 0))
|
||||||
goto out_put_key1;
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The check above which compares uaddrs is not sufficient for
|
* The check above which compares uaddrs is not sufficient for
|
||||||
* shared futexes. We need to compare the keys:
|
* shared futexes. We need to compare the keys:
|
||||||
*/
|
*/
|
||||||
if (requeue_pi && match_futex(&key1, &key2)) {
|
if (requeue_pi && match_futex(&key1, &key2))
|
||||||
ret = -EINVAL;
|
return -EINVAL;
|
||||||
goto out_put_keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
hb1 = hash_futex(&key1);
|
hb1 = hash_futex(&key1);
|
||||||
hb2 = hash_futex(&key2);
|
hb2 = hash_futex(&key2);
|
||||||
|
@ -2025,13 +1992,11 @@ retry_private:
|
||||||
|
|
||||||
ret = get_user(curval, uaddr1);
|
ret = get_user(curval, uaddr1);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_put_keys;
|
return ret;
|
||||||
|
|
||||||
if (!(flags & FLAGS_SHARED))
|
if (!(flags & FLAGS_SHARED))
|
||||||
goto retry_private;
|
goto retry_private;
|
||||||
|
|
||||||
put_futex_key(&key2);
|
|
||||||
put_futex_key(&key1);
|
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
if (curval != *cmpval) {
|
if (curval != *cmpval) {
|
||||||
|
@ -2090,12 +2055,10 @@ retry_private:
|
||||||
case -EFAULT:
|
case -EFAULT:
|
||||||
double_unlock_hb(hb1, hb2);
|
double_unlock_hb(hb1, hb2);
|
||||||
hb_waiters_dec(hb2);
|
hb_waiters_dec(hb2);
|
||||||
put_futex_key(&key2);
|
|
||||||
put_futex_key(&key1);
|
|
||||||
ret = fault_in_user_writeable(uaddr2);
|
ret = fault_in_user_writeable(uaddr2);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
goto retry;
|
goto retry;
|
||||||
goto out;
|
return ret;
|
||||||
case -EBUSY:
|
case -EBUSY:
|
||||||
case -EAGAIN:
|
case -EAGAIN:
|
||||||
/*
|
/*
|
||||||
|
@ -2106,8 +2069,6 @@ retry_private:
|
||||||
*/
|
*/
|
||||||
double_unlock_hb(hb1, hb2);
|
double_unlock_hb(hb1, hb2);
|
||||||
hb_waiters_dec(hb2);
|
hb_waiters_dec(hb2);
|
||||||
put_futex_key(&key2);
|
|
||||||
put_futex_key(&key1);
|
|
||||||
/*
|
/*
|
||||||
* Handle the case where the owner is in the middle of
|
* Handle the case where the owner is in the middle of
|
||||||
* exiting. Wait for the exit to complete otherwise
|
* exiting. Wait for the exit to complete otherwise
|
||||||
|
@ -2216,12 +2177,6 @@ out_unlock:
|
||||||
double_unlock_hb(hb1, hb2);
|
double_unlock_hb(hb1, hb2);
|
||||||
wake_up_q(&wake_q);
|
wake_up_q(&wake_q);
|
||||||
hb_waiters_dec(hb2);
|
hb_waiters_dec(hb2);
|
||||||
|
|
||||||
out_put_keys:
|
|
||||||
put_futex_key(&key2);
|
|
||||||
out_put_key1:
|
|
||||||
put_futex_key(&key1);
|
|
||||||
out:
|
|
||||||
return ret ? ret : task_count;
|
return ret ? ret : task_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2567,7 +2522,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
|
||||||
*/
|
*/
|
||||||
if (q->pi_state->owner != current)
|
if (q->pi_state->owner != current)
|
||||||
ret = fixup_pi_state_owner(uaddr, q, current);
|
ret = fixup_pi_state_owner(uaddr, q, current);
|
||||||
goto out;
|
return ret ? ret : locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2580,7 +2535,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
|
||||||
*/
|
*/
|
||||||
if (q->pi_state->owner == current) {
|
if (q->pi_state->owner == current) {
|
||||||
ret = fixup_pi_state_owner(uaddr, q, NULL);
|
ret = fixup_pi_state_owner(uaddr, q, NULL);
|
||||||
goto out;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2594,8 +2549,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
|
||||||
q->pi_state->owner);
|
q->pi_state->owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
return ret;
|
||||||
return ret ? ret : locked;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2692,12 +2646,11 @@ retry_private:
|
||||||
|
|
||||||
ret = get_user(uval, uaddr);
|
ret = get_user(uval, uaddr);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
return ret;
|
||||||
|
|
||||||
if (!(flags & FLAGS_SHARED))
|
if (!(flags & FLAGS_SHARED))
|
||||||
goto retry_private;
|
goto retry_private;
|
||||||
|
|
||||||
put_futex_key(&q->key);
|
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2706,9 +2659,6 @@ retry_private:
|
||||||
ret = -EWOULDBLOCK;
|
ret = -EWOULDBLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
if (ret)
|
|
||||||
put_futex_key(&q->key);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2853,7 +2803,6 @@ retry_private:
|
||||||
* - EAGAIN: The user space value changed.
|
* - EAGAIN: The user space value changed.
|
||||||
*/
|
*/
|
||||||
queue_unlock(hb);
|
queue_unlock(hb);
|
||||||
put_futex_key(&q.key);
|
|
||||||
/*
|
/*
|
||||||
* Handle the case where the owner is in the middle of
|
* Handle the case where the owner is in the middle of
|
||||||
* exiting. Wait for the exit to complete otherwise
|
* exiting. Wait for the exit to complete otherwise
|
||||||
|
@ -2961,13 +2910,11 @@ no_block:
|
||||||
put_pi_state(pi_state);
|
put_pi_state(pi_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
goto out_put_key;
|
goto out;
|
||||||
|
|
||||||
out_unlock_put_key:
|
out_unlock_put_key:
|
||||||
queue_unlock(hb);
|
queue_unlock(hb);
|
||||||
|
|
||||||
out_put_key:
|
|
||||||
put_futex_key(&q.key);
|
|
||||||
out:
|
out:
|
||||||
if (to) {
|
if (to) {
|
||||||
hrtimer_cancel(&to->timer);
|
hrtimer_cancel(&to->timer);
|
||||||
|
@ -2980,12 +2927,11 @@ uaddr_faulted:
|
||||||
|
|
||||||
ret = fault_in_user_writeable(uaddr);
|
ret = fault_in_user_writeable(uaddr);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_put_key;
|
goto out;
|
||||||
|
|
||||||
if (!(flags & FLAGS_SHARED))
|
if (!(flags & FLAGS_SHARED))
|
||||||
goto retry_private;
|
goto retry_private;
|
||||||
|
|
||||||
put_futex_key(&q.key);
|
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3114,16 +3060,13 @@ retry:
|
||||||
out_unlock:
|
out_unlock:
|
||||||
spin_unlock(&hb->lock);
|
spin_unlock(&hb->lock);
|
||||||
out_putkey:
|
out_putkey:
|
||||||
put_futex_key(&key);
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
pi_retry:
|
pi_retry:
|
||||||
put_futex_key(&key);
|
|
||||||
cond_resched();
|
cond_resched();
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
pi_faulted:
|
pi_faulted:
|
||||||
put_futex_key(&key);
|
|
||||||
|
|
||||||
ret = fault_in_user_writeable(uaddr);
|
ret = fault_in_user_writeable(uaddr);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -3265,7 +3208,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||||||
*/
|
*/
|
||||||
ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
|
ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_key2;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The check above which compares uaddrs is not sufficient for
|
* The check above which compares uaddrs is not sufficient for
|
||||||
|
@ -3274,7 +3217,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||||||
if (match_futex(&q.key, &key2)) {
|
if (match_futex(&q.key, &key2)) {
|
||||||
queue_unlock(hb);
|
queue_unlock(hb);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out_put_keys;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Queue the futex_q, drop the hb lock, wait for wakeup. */
|
/* Queue the futex_q, drop the hb lock, wait for wakeup. */
|
||||||
|
@ -3284,7 +3227,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||||||
ret = handle_early_requeue_pi_wakeup(hb, &q, &key2, to);
|
ret = handle_early_requeue_pi_wakeup(hb, &q, &key2, to);
|
||||||
spin_unlock(&hb->lock);
|
spin_unlock(&hb->lock);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_put_keys;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In order for us to be here, we know our q.key == key2, and since
|
* In order for us to be here, we know our q.key == key2, and since
|
||||||
|
@ -3374,11 +3317,6 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||||||
ret = -EWOULDBLOCK;
|
ret = -EWOULDBLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_put_keys:
|
|
||||||
put_futex_key(&q.key);
|
|
||||||
out_key2:
|
|
||||||
put_futex_key(&key2);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (to) {
|
if (to) {
|
||||||
hrtimer_cancel(&to->timer);
|
hrtimer_cancel(&to->timer);
|
||||||
|
|
|
@ -397,8 +397,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!kcsan_interrupt_watcher)
|
if (!kcsan_interrupt_watcher)
|
||||||
/* Use raw to avoid lockdep recursion via IRQ flags tracing. */
|
local_irq_save(irq_flags);
|
||||||
raw_local_irq_save(irq_flags);
|
|
||||||
|
|
||||||
watchpoint = insert_watchpoint((unsigned long)ptr, size, is_write);
|
watchpoint = insert_watchpoint((unsigned long)ptr, size, is_write);
|
||||||
if (watchpoint == NULL) {
|
if (watchpoint == NULL) {
|
||||||
|
@ -539,7 +538,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
|
||||||
kcsan_counter_dec(KCSAN_COUNTER_USED_WATCHPOINTS);
|
kcsan_counter_dec(KCSAN_COUNTER_USED_WATCHPOINTS);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
if (!kcsan_interrupt_watcher)
|
if (!kcsan_interrupt_watcher)
|
||||||
raw_local_irq_restore(irq_flags);
|
local_irq_restore(irq_flags);
|
||||||
out:
|
out:
|
||||||
user_access_restore(ua_flags);
|
user_access_restore(ua_flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -606,10 +606,11 @@ void kcsan_report(const volatile void *ptr, size_t size, int access_type,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* With TRACE_IRQFLAGS, lockdep's IRQ trace state becomes corrupted if
|
* Because we may generate reports when we're in scheduler code, the use
|
||||||
* we do not turn off lockdep here; this could happen due to recursion
|
* of printk() could deadlock. Until such time that all printing code
|
||||||
* into lockdep via KCSAN if we detect a race in utilities used by
|
* called in print_report() is scheduler-safe, accept the risk, and just
|
||||||
* lockdep.
|
* get our message out. As such, also disable lockdep to hide the
|
||||||
|
* warning, and avoid disabling lockdep for the rest of the kernel.
|
||||||
*/
|
*/
|
||||||
lockdep_off();
|
lockdep_off();
|
||||||
|
|
||||||
|
|
|
@ -395,7 +395,7 @@ void lockdep_init_task(struct task_struct *task)
|
||||||
|
|
||||||
static __always_inline void lockdep_recursion_finish(void)
|
static __always_inline void lockdep_recursion_finish(void)
|
||||||
{
|
{
|
||||||
if (WARN_ON_ONCE(--current->lockdep_recursion))
|
if (WARN_ON_ONCE((--current->lockdep_recursion) & LOCKDEP_RECURSION_MASK))
|
||||||
current->lockdep_recursion = 0;
|
current->lockdep_recursion = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2062,9 +2062,9 @@ print_bad_irq_dependency(struct task_struct *curr,
|
||||||
pr_warn("-----------------------------------------------------\n");
|
pr_warn("-----------------------------------------------------\n");
|
||||||
pr_warn("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] is trying to acquire:\n",
|
pr_warn("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] is trying to acquire:\n",
|
||||||
curr->comm, task_pid_nr(curr),
|
curr->comm, task_pid_nr(curr),
|
||||||
curr->hardirq_context, hardirq_count() >> HARDIRQ_SHIFT,
|
lockdep_hardirq_context(), hardirq_count() >> HARDIRQ_SHIFT,
|
||||||
curr->softirq_context, softirq_count() >> SOFTIRQ_SHIFT,
|
curr->softirq_context, softirq_count() >> SOFTIRQ_SHIFT,
|
||||||
curr->hardirqs_enabled,
|
lockdep_hardirqs_enabled(),
|
||||||
curr->softirqs_enabled);
|
curr->softirqs_enabled);
|
||||||
print_lock(next);
|
print_lock(next);
|
||||||
|
|
||||||
|
@ -3331,9 +3331,9 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
|
||||||
|
|
||||||
pr_warn("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] takes:\n",
|
pr_warn("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] takes:\n",
|
||||||
curr->comm, task_pid_nr(curr),
|
curr->comm, task_pid_nr(curr),
|
||||||
lockdep_hardirq_context(curr), hardirq_count() >> HARDIRQ_SHIFT,
|
lockdep_hardirq_context(), hardirq_count() >> HARDIRQ_SHIFT,
|
||||||
lockdep_softirq_context(curr), softirq_count() >> SOFTIRQ_SHIFT,
|
lockdep_softirq_context(curr), softirq_count() >> SOFTIRQ_SHIFT,
|
||||||
lockdep_hardirqs_enabled(curr),
|
lockdep_hardirqs_enabled(),
|
||||||
lockdep_softirqs_enabled(curr));
|
lockdep_softirqs_enabled(curr));
|
||||||
print_lock(this);
|
print_lock(this);
|
||||||
|
|
||||||
|
@ -3646,10 +3646,19 @@ static void __trace_hardirqs_on_caller(void)
|
||||||
*/
|
*/
|
||||||
void lockdep_hardirqs_on_prepare(unsigned long ip)
|
void lockdep_hardirqs_on_prepare(unsigned long ip)
|
||||||
{
|
{
|
||||||
if (unlikely(!debug_locks || current->lockdep_recursion))
|
if (unlikely(!debug_locks))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (unlikely(current->hardirqs_enabled)) {
|
/*
|
||||||
|
* NMIs do not (and cannot) track lock dependencies, nothing to do.
|
||||||
|
*/
|
||||||
|
if (unlikely(in_nmi()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (unlikely(current->lockdep_recursion & LOCKDEP_RECURSION_MASK))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (unlikely(lockdep_hardirqs_enabled())) {
|
||||||
/*
|
/*
|
||||||
* Neither irq nor preemption are disabled here
|
* Neither irq nor preemption are disabled here
|
||||||
* so this is racy by nature but losing one hit
|
* so this is racy by nature but losing one hit
|
||||||
|
@ -3677,7 +3686,7 @@ void lockdep_hardirqs_on_prepare(unsigned long ip)
|
||||||
* Can't allow enabling interrupts while in an interrupt handler,
|
* Can't allow enabling interrupts while in an interrupt handler,
|
||||||
* that's general bad form and such. Recursion, limited stack etc..
|
* that's general bad form and such. Recursion, limited stack etc..
|
||||||
*/
|
*/
|
||||||
if (DEBUG_LOCKS_WARN_ON(current->hardirq_context))
|
if (DEBUG_LOCKS_WARN_ON(lockdep_hardirq_context()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
current->hardirq_chain_key = current->curr_chain_key;
|
current->hardirq_chain_key = current->curr_chain_key;
|
||||||
|
@ -3692,10 +3701,30 @@ void noinstr lockdep_hardirqs_on(unsigned long ip)
|
||||||
{
|
{
|
||||||
struct task_struct *curr = current;
|
struct task_struct *curr = current;
|
||||||
|
|
||||||
if (unlikely(!debug_locks || curr->lockdep_recursion))
|
if (unlikely(!debug_locks))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (curr->hardirqs_enabled) {
|
/*
|
||||||
|
* NMIs can happen in the middle of local_irq_{en,dis}able() where the
|
||||||
|
* tracking state and hardware state are out of sync.
|
||||||
|
*
|
||||||
|
* NMIs must save lockdep_hardirqs_enabled() to restore IRQ state from,
|
||||||
|
* and not rely on hardware state like normal interrupts.
|
||||||
|
*/
|
||||||
|
if (unlikely(in_nmi())) {
|
||||||
|
/*
|
||||||
|
* Skip:
|
||||||
|
* - recursion check, because NMI can hit lockdep;
|
||||||
|
* - hardware state check, because above;
|
||||||
|
* - chain_key check, see lockdep_hardirqs_on_prepare().
|
||||||
|
*/
|
||||||
|
goto skip_checks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(current->lockdep_recursion & LOCKDEP_RECURSION_MASK))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (lockdep_hardirqs_enabled()) {
|
||||||
/*
|
/*
|
||||||
* Neither irq nor preemption are disabled here
|
* Neither irq nor preemption are disabled here
|
||||||
* so this is racy by nature but losing one hit
|
* so this is racy by nature but losing one hit
|
||||||
|
@ -3720,8 +3749,9 @@ void noinstr lockdep_hardirqs_on(unsigned long ip)
|
||||||
DEBUG_LOCKS_WARN_ON(current->hardirq_chain_key !=
|
DEBUG_LOCKS_WARN_ON(current->hardirq_chain_key !=
|
||||||
current->curr_chain_key);
|
current->curr_chain_key);
|
||||||
|
|
||||||
|
skip_checks:
|
||||||
/* we'll do an OFF -> ON transition: */
|
/* we'll do an OFF -> ON transition: */
|
||||||
curr->hardirqs_enabled = 1;
|
this_cpu_write(hardirqs_enabled, 1);
|
||||||
curr->hardirq_enable_ip = ip;
|
curr->hardirq_enable_ip = ip;
|
||||||
curr->hardirq_enable_event = ++curr->irq_events;
|
curr->hardirq_enable_event = ++curr->irq_events;
|
||||||
debug_atomic_inc(hardirqs_on_events);
|
debug_atomic_inc(hardirqs_on_events);
|
||||||
|
@ -3735,7 +3765,15 @@ void noinstr lockdep_hardirqs_off(unsigned long ip)
|
||||||
{
|
{
|
||||||
struct task_struct *curr = current;
|
struct task_struct *curr = current;
|
||||||
|
|
||||||
if (unlikely(!debug_locks || curr->lockdep_recursion))
|
if (unlikely(!debug_locks))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Matching lockdep_hardirqs_on(), allow NMIs in the middle of lockdep;
|
||||||
|
* they will restore the software state. This ensures the software
|
||||||
|
* state is consistent inside NMIs as well.
|
||||||
|
*/
|
||||||
|
if (unlikely(!in_nmi() && (current->lockdep_recursion & LOCKDEP_RECURSION_MASK)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3745,11 +3783,11 @@ void noinstr lockdep_hardirqs_off(unsigned long ip)
|
||||||
if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
|
if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (curr->hardirqs_enabled) {
|
if (lockdep_hardirqs_enabled()) {
|
||||||
/*
|
/*
|
||||||
* We have done an ON -> OFF transition:
|
* We have done an ON -> OFF transition:
|
||||||
*/
|
*/
|
||||||
curr->hardirqs_enabled = 0;
|
this_cpu_write(hardirqs_enabled, 0);
|
||||||
curr->hardirq_disable_ip = ip;
|
curr->hardirq_disable_ip = ip;
|
||||||
curr->hardirq_disable_event = ++curr->irq_events;
|
curr->hardirq_disable_event = ++curr->irq_events;
|
||||||
debug_atomic_inc(hardirqs_off_events);
|
debug_atomic_inc(hardirqs_off_events);
|
||||||
|
@ -3794,7 +3832,7 @@ void lockdep_softirqs_on(unsigned long ip)
|
||||||
* usage bit for all held locks, if hardirqs are
|
* usage bit for all held locks, if hardirqs are
|
||||||
* enabled too:
|
* enabled too:
|
||||||
*/
|
*/
|
||||||
if (curr->hardirqs_enabled)
|
if (lockdep_hardirqs_enabled())
|
||||||
mark_held_locks(curr, LOCK_ENABLED_SOFTIRQ);
|
mark_held_locks(curr, LOCK_ENABLED_SOFTIRQ);
|
||||||
lockdep_recursion_finish();
|
lockdep_recursion_finish();
|
||||||
}
|
}
|
||||||
|
@ -3843,7 +3881,7 @@ mark_usage(struct task_struct *curr, struct held_lock *hlock, int check)
|
||||||
*/
|
*/
|
||||||
if (!hlock->trylock) {
|
if (!hlock->trylock) {
|
||||||
if (hlock->read) {
|
if (hlock->read) {
|
||||||
if (curr->hardirq_context)
|
if (lockdep_hardirq_context())
|
||||||
if (!mark_lock(curr, hlock,
|
if (!mark_lock(curr, hlock,
|
||||||
LOCK_USED_IN_HARDIRQ_READ))
|
LOCK_USED_IN_HARDIRQ_READ))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3852,7 +3890,7 @@ mark_usage(struct task_struct *curr, struct held_lock *hlock, int check)
|
||||||
LOCK_USED_IN_SOFTIRQ_READ))
|
LOCK_USED_IN_SOFTIRQ_READ))
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
if (curr->hardirq_context)
|
if (lockdep_hardirq_context())
|
||||||
if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ))
|
if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ))
|
||||||
return 0;
|
return 0;
|
||||||
if (curr->softirq_context)
|
if (curr->softirq_context)
|
||||||
|
@ -3890,7 +3928,7 @@ lock_used:
|
||||||
|
|
||||||
static inline unsigned int task_irq_context(struct task_struct *task)
|
static inline unsigned int task_irq_context(struct task_struct *task)
|
||||||
{
|
{
|
||||||
return LOCK_CHAIN_HARDIRQ_CONTEXT * !!task->hardirq_context +
|
return LOCK_CHAIN_HARDIRQ_CONTEXT * !!lockdep_hardirq_context() +
|
||||||
LOCK_CHAIN_SOFTIRQ_CONTEXT * !!task->softirq_context;
|
LOCK_CHAIN_SOFTIRQ_CONTEXT * !!task->softirq_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3983,7 +4021,7 @@ static inline short task_wait_context(struct task_struct *curr)
|
||||||
* Set appropriate wait type for the context; for IRQs we have to take
|
* Set appropriate wait type for the context; for IRQs we have to take
|
||||||
* into account force_irqthread as that is implied by PREEMPT_RT.
|
* into account force_irqthread as that is implied by PREEMPT_RT.
|
||||||
*/
|
*/
|
||||||
if (curr->hardirq_context) {
|
if (lockdep_hardirq_context()) {
|
||||||
/*
|
/*
|
||||||
* Check if force_irqthreads will run us threaded.
|
* Check if force_irqthreads will run us threaded.
|
||||||
*/
|
*/
|
||||||
|
@ -4826,11 +4864,11 @@ static void check_flags(unsigned long flags)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (irqs_disabled_flags(flags)) {
|
if (irqs_disabled_flags(flags)) {
|
||||||
if (DEBUG_LOCKS_WARN_ON(current->hardirqs_enabled)) {
|
if (DEBUG_LOCKS_WARN_ON(lockdep_hardirqs_enabled())) {
|
||||||
printk("possible reason: unannotated irqs-off.\n");
|
printk("possible reason: unannotated irqs-off.\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (DEBUG_LOCKS_WARN_ON(!current->hardirqs_enabled)) {
|
if (DEBUG_LOCKS_WARN_ON(!lockdep_hardirqs_enabled())) {
|
||||||
printk("possible reason: unannotated irqs-on.\n");
|
printk("possible reason: unannotated irqs-on.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,12 @@ static bool ksoftirqd_running(unsigned long pending)
|
||||||
* where hardirqs are disabled legitimately:
|
* where hardirqs are disabled legitimately:
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||||
|
|
||||||
|
DEFINE_PER_CPU(int, hardirqs_enabled);
|
||||||
|
DEFINE_PER_CPU(int, hardirq_context);
|
||||||
|
EXPORT_PER_CPU_SYMBOL_GPL(hardirqs_enabled);
|
||||||
|
EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context);
|
||||||
|
|
||||||
void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
|
void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -224,7 +230,7 @@ static inline bool lockdep_softirq_start(void)
|
||||||
{
|
{
|
||||||
bool in_hardirq = false;
|
bool in_hardirq = false;
|
||||||
|
|
||||||
if (lockdep_hardirq_context(current)) {
|
if (lockdep_hardirq_context()) {
|
||||||
in_hardirq = true;
|
in_hardirq = true;
|
||||||
lockdep_hardirq_exit();
|
lockdep_hardirq_exit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,11 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
|
||||||
* timer->base->cpu_base
|
* timer->base->cpu_base
|
||||||
*/
|
*/
|
||||||
static struct hrtimer_cpu_base migration_cpu_base = {
|
static struct hrtimer_cpu_base migration_cpu_base = {
|
||||||
.clock_base = { { .cpu_base = &migration_cpu_base, }, },
|
.clock_base = { {
|
||||||
|
.cpu_base = &migration_cpu_base,
|
||||||
|
.seq = SEQCNT_RAW_SPINLOCK_ZERO(migration_cpu_base.seq,
|
||||||
|
&migration_cpu_base.lock),
|
||||||
|
}, },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define migration_base migration_cpu_base.clock_base[0]
|
#define migration_base migration_cpu_base.clock_base[0]
|
||||||
|
@ -1998,8 +2002,11 @@ int hrtimers_prepare_cpu(unsigned int cpu)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
|
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
|
||||||
cpu_base->clock_base[i].cpu_base = cpu_base;
|
struct hrtimer_clock_base *clock_b = &cpu_base->clock_base[i];
|
||||||
timerqueue_init_head(&cpu_base->clock_base[i].active);
|
|
||||||
|
clock_b->cpu_base = cpu_base;
|
||||||
|
seqcount_raw_spinlock_init(&clock_b->seq, &cpu_base->lock);
|
||||||
|
timerqueue_init_head(&clock_b->active);
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_base->cpu = cpu;
|
cpu_base->cpu = cpu;
|
||||||
|
|
|
@ -39,18 +39,19 @@ enum timekeeping_adv_mode {
|
||||||
TK_ADV_FREQ
|
TK_ADV_FREQ
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DEFINE_RAW_SPINLOCK(timekeeper_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The most important data for readout fits into a single 64 byte
|
* The most important data for readout fits into a single 64 byte
|
||||||
* cache line.
|
* cache line.
|
||||||
*/
|
*/
|
||||||
static struct {
|
static struct {
|
||||||
seqcount_t seq;
|
seqcount_raw_spinlock_t seq;
|
||||||
struct timekeeper timekeeper;
|
struct timekeeper timekeeper;
|
||||||
} tk_core ____cacheline_aligned = {
|
} tk_core ____cacheline_aligned = {
|
||||||
.seq = SEQCNT_ZERO(tk_core.seq),
|
.seq = SEQCNT_RAW_SPINLOCK_ZERO(tk_core.seq, &timekeeper_lock),
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_RAW_SPINLOCK(timekeeper_lock);
|
|
||||||
static struct timekeeper shadow_timekeeper;
|
static struct timekeeper shadow_timekeeper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,7 +64,7 @@ static struct timekeeper shadow_timekeeper;
|
||||||
* See @update_fast_timekeeper() below.
|
* See @update_fast_timekeeper() below.
|
||||||
*/
|
*/
|
||||||
struct tk_fast {
|
struct tk_fast {
|
||||||
seqcount_t seq;
|
seqcount_raw_spinlock_t seq;
|
||||||
struct tk_read_base base[2];
|
struct tk_read_base base[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,11 +81,13 @@ static struct clocksource dummy_clock = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct tk_fast tk_fast_mono ____cacheline_aligned = {
|
static struct tk_fast tk_fast_mono ____cacheline_aligned = {
|
||||||
|
.seq = SEQCNT_RAW_SPINLOCK_ZERO(tk_fast_mono.seq, &timekeeper_lock),
|
||||||
.base[0] = { .clock = &dummy_clock, },
|
.base[0] = { .clock = &dummy_clock, },
|
||||||
.base[1] = { .clock = &dummy_clock, },
|
.base[1] = { .clock = &dummy_clock, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct tk_fast tk_fast_raw ____cacheline_aligned = {
|
static struct tk_fast tk_fast_raw ____cacheline_aligned = {
|
||||||
|
.seq = SEQCNT_RAW_SPINLOCK_ZERO(tk_fast_raw.seq, &timekeeper_lock),
|
||||||
.base[0] = { .clock = &dummy_clock, },
|
.base[0] = { .clock = &dummy_clock, },
|
||||||
.base[1] = { .clock = &dummy_clock, },
|
.base[1] = { .clock = &dummy_clock, },
|
||||||
};
|
};
|
||||||
|
@ -157,7 +160,7 @@ static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
|
||||||
* tk_clock_read - atomic clocksource read() helper
|
* tk_clock_read - atomic clocksource read() helper
|
||||||
*
|
*
|
||||||
* This helper is necessary to use in the read paths because, while the
|
* This helper is necessary to use in the read paths because, while the
|
||||||
* seqlock ensures we don't return a bad value while structures are updated,
|
* seqcount ensures we don't return a bad value while structures are updated,
|
||||||
* it doesn't protect from potential crashes. There is the possibility that
|
* it doesn't protect from potential crashes. There is the possibility that
|
||||||
* the tkr's clocksource may change between the read reference, and the
|
* the tkr's clocksource may change between the read reference, and the
|
||||||
* clock reference passed to the read function. This can cause crashes if
|
* clock reference passed to the read function. This can cause crashes if
|
||||||
|
@ -222,10 +225,10 @@ static inline u64 timekeeping_get_delta(const struct tk_read_base *tkr)
|
||||||
unsigned int seq;
|
unsigned int seq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we're called holding a seqlock, the data may shift
|
* Since we're called holding a seqcount, the data may shift
|
||||||
* under us while we're doing the calculation. This can cause
|
* under us while we're doing the calculation. This can cause
|
||||||
* false positives, since we'd note a problem but throw the
|
* false positives, since we'd note a problem but throw the
|
||||||
* results away. So nest another seqlock here to atomically
|
* results away. So nest another seqcount here to atomically
|
||||||
* grab the points we are checking with.
|
* grab the points we are checking with.
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
|
@ -486,7 +489,7 @@ EXPORT_SYMBOL_GPL(ktime_get_raw_fast_ns);
|
||||||
*
|
*
|
||||||
* To keep it NMI safe since we're accessing from tracing, we're not using a
|
* To keep it NMI safe since we're accessing from tracing, we're not using a
|
||||||
* separate timekeeper with updates to monotonic clock and boot offset
|
* separate timekeeper with updates to monotonic clock and boot offset
|
||||||
* protected with seqlocks. This has the following minor side effects:
|
* protected with seqcounts. This has the following minor side effects:
|
||||||
*
|
*
|
||||||
* (1) Its possible that a timestamp be taken after the boot offset is updated
|
* (1) Its possible that a timestamp be taken after the boot offset is updated
|
||||||
* but before the timekeeper is updated. If this happens, the new boot offset
|
* but before the timekeeper is updated. If this happens, the new boot offset
|
||||||
|
|
|
@ -1117,6 +1117,7 @@ config PROVE_LOCKING
|
||||||
select DEBUG_RWSEMS
|
select DEBUG_RWSEMS
|
||||||
select DEBUG_WW_MUTEX_SLOWPATH
|
select DEBUG_WW_MUTEX_SLOWPATH
|
||||||
select DEBUG_LOCK_ALLOC
|
select DEBUG_LOCK_ALLOC
|
||||||
|
select PREEMPT_COUNT if !ARCH_NO_PREEMPT
|
||||||
select TRACE_IRQFLAGS
|
select TRACE_IRQFLAGS
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
|
|
|
@ -180,7 +180,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
|
||||||
|
|
||||||
unsigned int nf_conntrack_max __read_mostly;
|
unsigned int nf_conntrack_max __read_mostly;
|
||||||
EXPORT_SYMBOL_GPL(nf_conntrack_max);
|
EXPORT_SYMBOL_GPL(nf_conntrack_max);
|
||||||
seqcount_t nf_conntrack_generation __read_mostly;
|
seqcount_spinlock_t nf_conntrack_generation __read_mostly;
|
||||||
static unsigned int nf_conntrack_hash_rnd __read_mostly;
|
static unsigned int nf_conntrack_hash_rnd __read_mostly;
|
||||||
|
|
||||||
static u32 hash_conntrack_raw(const struct nf_conntrack_tuple *tuple,
|
static u32 hash_conntrack_raw(const struct nf_conntrack_tuple *tuple,
|
||||||
|
@ -2600,7 +2600,8 @@ int nf_conntrack_init_start(void)
|
||||||
/* struct nf_ct_ext uses u8 to store offsets/size */
|
/* struct nf_ct_ext uses u8 to store offsets/size */
|
||||||
BUILD_BUG_ON(total_extension_size() > 255u);
|
BUILD_BUG_ON(total_extension_size() > 255u);
|
||||||
|
|
||||||
seqcount_init(&nf_conntrack_generation);
|
seqcount_spinlock_init(&nf_conntrack_generation,
|
||||||
|
&nf_conntrack_locks_all_lock);
|
||||||
|
|
||||||
for (i = 0; i < CONNTRACK_LOCKS; i++)
|
for (i = 0; i < CONNTRACK_LOCKS; i++)
|
||||||
spin_lock_init(&nf_conntrack_locks[i]);
|
spin_lock_init(&nf_conntrack_locks[i]);
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
struct nft_rbtree {
|
struct nft_rbtree {
|
||||||
struct rb_root root;
|
struct rb_root root;
|
||||||
rwlock_t lock;
|
rwlock_t lock;
|
||||||
seqcount_t count;
|
seqcount_rwlock_t count;
|
||||||
struct delayed_work gc_work;
|
struct delayed_work gc_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -523,7 +523,7 @@ static int nft_rbtree_init(const struct nft_set *set,
|
||||||
struct nft_rbtree *priv = nft_set_priv(set);
|
struct nft_rbtree *priv = nft_set_priv(set);
|
||||||
|
|
||||||
rwlock_init(&priv->lock);
|
rwlock_init(&priv->lock);
|
||||||
seqcount_init(&priv->count);
|
seqcount_rwlock_init(&priv->count, &priv->lock);
|
||||||
priv->root = RB_ROOT;
|
priv->root = RB_ROOT;
|
||||||
|
|
||||||
INIT_DEFERRABLE_WORK(&priv->gc_work, nft_rbtree_gc);
|
INIT_DEFERRABLE_WORK(&priv->gc_work, nft_rbtree_gc);
|
||||||
|
|
|
@ -122,7 +122,7 @@ struct xfrm_pol_inexact_bin {
|
||||||
/* list containing '*:*' policies */
|
/* list containing '*:*' policies */
|
||||||
struct hlist_head hhead;
|
struct hlist_head hhead;
|
||||||
|
|
||||||
seqcount_t count;
|
seqcount_spinlock_t count;
|
||||||
/* tree sorted by daddr/prefix */
|
/* tree sorted by daddr/prefix */
|
||||||
struct rb_root root_d;
|
struct rb_root root_d;
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ static struct xfrm_policy_afinfo const __rcu *xfrm_policy_afinfo[AF_INET6 + 1]
|
||||||
__read_mostly;
|
__read_mostly;
|
||||||
|
|
||||||
static struct kmem_cache *xfrm_dst_cache __ro_after_init;
|
static struct kmem_cache *xfrm_dst_cache __ro_after_init;
|
||||||
static __read_mostly seqcount_t xfrm_policy_hash_generation;
|
static __read_mostly seqcount_mutex_t xfrm_policy_hash_generation;
|
||||||
|
|
||||||
static struct rhashtable xfrm_policy_inexact_table;
|
static struct rhashtable xfrm_policy_inexact_table;
|
||||||
static const struct rhashtable_params xfrm_pol_inexact_params;
|
static const struct rhashtable_params xfrm_pol_inexact_params;
|
||||||
|
@ -719,7 +719,7 @@ xfrm_policy_inexact_alloc_bin(const struct xfrm_policy *pol, u8 dir)
|
||||||
INIT_HLIST_HEAD(&bin->hhead);
|
INIT_HLIST_HEAD(&bin->hhead);
|
||||||
bin->root_d = RB_ROOT;
|
bin->root_d = RB_ROOT;
|
||||||
bin->root_s = RB_ROOT;
|
bin->root_s = RB_ROOT;
|
||||||
seqcount_init(&bin->count);
|
seqcount_spinlock_init(&bin->count, &net->xfrm.xfrm_policy_lock);
|
||||||
|
|
||||||
prev = rhashtable_lookup_get_insert_key(&xfrm_policy_inexact_table,
|
prev = rhashtable_lookup_get_insert_key(&xfrm_policy_inexact_table,
|
||||||
&bin->k, &bin->head,
|
&bin->k, &bin->head,
|
||||||
|
@ -1906,7 +1906,7 @@ static int xfrm_policy_match(const struct xfrm_policy *pol,
|
||||||
|
|
||||||
static struct xfrm_pol_inexact_node *
|
static struct xfrm_pol_inexact_node *
|
||||||
xfrm_policy_lookup_inexact_addr(const struct rb_root *r,
|
xfrm_policy_lookup_inexact_addr(const struct rb_root *r,
|
||||||
seqcount_t *count,
|
seqcount_spinlock_t *count,
|
||||||
const xfrm_address_t *addr, u16 family)
|
const xfrm_address_t *addr, u16 family)
|
||||||
{
|
{
|
||||||
const struct rb_node *parent;
|
const struct rb_node *parent;
|
||||||
|
@ -4153,7 +4153,7 @@ void __init xfrm_init(void)
|
||||||
{
|
{
|
||||||
register_pernet_subsys(&xfrm_net_ops);
|
register_pernet_subsys(&xfrm_net_ops);
|
||||||
xfrm_dev_init();
|
xfrm_dev_init();
|
||||||
seqcount_init(&xfrm_policy_hash_generation);
|
seqcount_mutex_init(&xfrm_policy_hash_generation, &hash_resize_mutex);
|
||||||
xfrm_input_init();
|
xfrm_input_init();
|
||||||
|
|
||||||
#ifdef CONFIG_INET_ESPINTCP
|
#ifdef CONFIG_INET_ESPINTCP
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
#ifndef _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_
|
#ifndef _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_
|
||||||
#define _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_
|
#define _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_
|
||||||
|
|
||||||
# define lockdep_hardirq_context(p) 0
|
# define lockdep_hardirq_context() 0
|
||||||
# define lockdep_softirq_context(p) 0
|
# define lockdep_softirq_context(p) 0
|
||||||
# define lockdep_hardirqs_enabled(p) 0
|
# define lockdep_hardirqs_enabled() 0
|
||||||
# define lockdep_softirqs_enabled(p) 0
|
# define lockdep_softirqs_enabled(p) 0
|
||||||
# define lockdep_hardirq_enter() do { } while (0)
|
# define lockdep_hardirq_enter() do { } while (0)
|
||||||
# define lockdep_hardirq_exit() do { } while (0)
|
# define lockdep_hardirq_exit() do { } while (0)
|
||||||
|
|
|
@ -303,7 +303,7 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
|
||||||
INIT_LIST_HEAD(&irqfd->list);
|
INIT_LIST_HEAD(&irqfd->list);
|
||||||
INIT_WORK(&irqfd->inject, irqfd_inject);
|
INIT_WORK(&irqfd->inject, irqfd_inject);
|
||||||
INIT_WORK(&irqfd->shutdown, irqfd_shutdown);
|
INIT_WORK(&irqfd->shutdown, irqfd_shutdown);
|
||||||
seqcount_init(&irqfd->irq_entry_sc);
|
seqcount_spinlock_init(&irqfd->irq_entry_sc, &kvm->irqfds.lock);
|
||||||
|
|
||||||
f = fdget(args->fd);
|
f = fdget(args->fd);
|
||||||
if (!f.file) {
|
if (!f.file) {
|
||||||
|
|
Loading…
Reference in New Issue