Commit e1928328 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking updates from Ingo Molnar:
 "The main changes in this cycle are:

   - rwsem scalability improvements, phase #2, by Waiman Long, which are
     rather impressive:

       "On a 2-socket 40-core 80-thread Skylake system with 40 reader
        and writer locking threads, the min/mean/max locking operations
        done in a 5-second testing window before the patchset were:

         40 readers, Iterations Min/Mean/Max = 1,807/1,808/1,810
         40 writers, Iterations Min/Mean/Max = 1,807/50,344/151,255

        After the patchset, they became:

         40 readers, Iterations Min/Mean/Max = 30,057/31,359/32,741
         40 writers, Iterations Min/Mean/Max = 94,466/95,845/97,098"

     There's a lot of changes to the locking implementation that makes
     it similar to qrwlock, including owner handoff for more fair
     locking.

     Another microbenchmark shows how across the spectrum the
     improvements are:

       "With a locking microbenchmark running on 5.1 based kernel, the
        total locking rates (in kops/s) on a 2-socket Skylake system
        with equal numbers of readers and writers (mixed) before and
        after this patchset were:

        # of Threads   Before Patch      After Patch
        ------------   ------------      -----------
             2            2,618             4,193
             4            1,202             3,726
             8              802             3,622
            16              729             3,359
            32              319             2,826
            64              102             2,744"

     The changes are extensive and the patch-set has been through
     several iterations addressing various locking workloads. There
     might be more regressions, but unless they are pathological I
     believe we want to use this new implementation as the baseline
     going forward.

   - jump-label optimizations by Daniel Bristot de Oliveira: the primary
     motivation was to remove IPI disturbance of isolated RT-workload
     CPUs, which resulted in the implementation of batched jump-label
     updates. Beyond the improvement of the real-time characteristics
     kernel, in one test this patchset improved static key update
     overhead from 57 msecs to just 1.4 msecs - which is a nice speedup
     as well.

   - atomic64_t cross-arch type cleanups by Mark Rutland: over the last
     ~10 years of atomic64_t existence the various types used by the
     APIs only had to be self-consistent within each architecture -
     which means they became wildly inconsistent across architectures.
     Mark puts and end to this by reworking all the atomic64
     implementations to use 's64' as the base type for atomic64_t, and
     to ensure that this type is consistently used for parameters and
     return values in the API, avoiding further problems in this area.

   - A large set of small improvements to lockdep by Yuyang Du: type
     cleanups, output cleanups, function return type and othr cleanups
     all around the place.

   - A set of percpu ops cleanups and fixes by Peter Zijlstra.

   - Misc other changes - please see the Git log for more details"

* 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (82 commits)
  locking/lockdep: increase size of counters for lockdep statistics
  locking/atomics: Use sed(1) instead of non-standard head(1) option
  locking/lockdep: Move mark_lock() inside CONFIG_TRACE_IRQFLAGS && CONFIG_PROVE_LOCKING
  x86/jump_label: Make tp_vec_nr static
  x86/percpu: Optimize raw_cpu_xchg()
  x86/percpu, sched/fair: Avoid local_clock()
  x86/percpu, x86/irq: Relax {set,get}_irq_regs()
  x86/percpu: Relax smp_processor_id()
  x86/percpu: Differentiate this_cpu_{}() and __this_cpu_{}()
  locking/rwsem: Guard against making count negative
  locking/rwsem: Adaptive disabling of reader optimistic spinning
  locking/rwsem: Enable time-based spinning on reader-owned rwsem
  locking/rwsem: Make rwsem->owner an atomic_long_t
  locking/rwsem: Enable readers spinning on writer
  locking/rwsem: Clarify usage of owner's nonspinaable bit
  locking/rwsem: Wake up almost all readers in wait queue
  locking/rwsem: More optimal RT task handling of null owner
  locking/rwsem: Always release wait_lock before waking up tasks
  locking/rwsem: Implement lock handoff to prevent lock starvation
  locking/rwsem: Make rwsem_spin_on_owner() return owner state
  ...
parents 46f1ec23 9156e545
...@@ -81,9 +81,11 @@ Non-RMW ops: ...@@ -81,9 +81,11 @@ Non-RMW ops:
The non-RMW ops are (typically) regular LOADs and STOREs and are canonically The non-RMW ops are (typically) regular LOADs and STOREs and are canonically
implemented using READ_ONCE(), WRITE_ONCE(), smp_load_acquire() and implemented using READ_ONCE(), WRITE_ONCE(), smp_load_acquire() and
smp_store_release() respectively. smp_store_release() respectively. Therefore, if you find yourself only using
the Non-RMW operations of atomic_t, you do not in fact need atomic_t at all
and are doing it wrong.
The one detail to this is that atomic_set{}() should be observable to the RMW A subtle detail of atomic_set{}() is that it should be observable to the RMW
ops. That is: ops. That is:
C atomic-set C atomic-set
...@@ -200,6 +202,9 @@ These helper barriers exist because architectures have varying implicit ...@@ -200,6 +202,9 @@ These helper barriers exist because architectures have varying implicit
ordering on their SMP atomic primitives. For example our TSO architectures ordering on their SMP atomic primitives. For example our TSO architectures
provide full ordered atomics and these barriers are no-ops. provide full ordered atomics and these barriers are no-ops.
NOTE: when the atomic RmW ops are fully ordered, they should also imply a
compiler barrier.
Thus: Thus:
atomic_fetch_add(); atomic_fetch_add();
......
...@@ -15,34 +15,48 @@ tens of thousands of) instantiations. For example a lock in the inode ...@@ -15,34 +15,48 @@ tens of thousands of) instantiations. For example a lock in the inode
struct is one class, while each inode has its own instantiation of that struct is one class, while each inode has its own instantiation of that
lock class. lock class.
The validator tracks the 'state' of lock-classes, and it tracks The validator tracks the 'usage state' of lock-classes, and it tracks
dependencies between different lock-classes. The validator maintains a the dependencies between different lock-classes. Lock usage indicates
rolling proof that the state and the dependencies are correct. how a lock is used with regard to its IRQ contexts, while lock
dependency can be understood as lock order, where L1 -> L2 suggests that
Unlike an lock instantiation, the lock-class itself never goes away: when a task is attempting to acquire L2 while holding L1. From lockdep's
a lock-class is used for the first time after bootup it gets registered, perspective, the two locks (L1 and L2) are not necessarily related; that
and all subsequent uses of that lock-class will be attached to this dependency just means the order ever happened. The validator maintains a
lock-class. continuing effort to prove lock usages and dependencies are correct or
the validator will shoot a splat if incorrect.
A lock-class's behavior is constructed by its instances collectively:
when the first instance of a lock-class is used after bootup the class
gets registered, then all (subsequent) instances will be mapped to the
class and hence their usages and dependecies will contribute to those of
the class. A lock-class does not go away when a lock instance does, but
it can be removed if the memory space of the lock class (static or
dynamic) is reclaimed, this happens for example when a module is
unloaded or a workqueue is destroyed.
State State
----- -----
The validator tracks lock-class usage history into 4 * nSTATEs + 1 separate The validator tracks lock-class usage history and divides the usage into
state bits: (4 usages * n STATEs + 1) categories:
where the 4 usages can be:
- 'ever held in STATE context' - 'ever held in STATE context'
- 'ever held as readlock in STATE context' - 'ever held as readlock in STATE context'
- 'ever held with STATE enabled' - 'ever held with STATE enabled'
- 'ever held as readlock with STATE enabled' - 'ever held as readlock with STATE enabled'
Where STATE can be either one of (kernel/locking/lockdep_states.h) where the n STATEs are coded in kernel/locking/lockdep_states.h and as of
- hardirq now they include:
- softirq - hardirq
- softirq
where the last 1 category is:
- 'ever used' [ == !unused ] - 'ever used' [ == !unused ]
When locking rules are violated, these state bits are presented in the When locking rules are violated, these usage bits are presented in the
locking error messages, inside curlies. A contrived example: locking error messages, inside curlies, with a total of 2 * n STATEs bits.
A contrived example:
modprobe/2287 is trying to acquire lock: modprobe/2287 is trying to acquire lock:
(&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24 (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
...@@ -51,28 +65,67 @@ locking error messages, inside curlies. A contrived example: ...@@ -51,28 +65,67 @@ locking error messages, inside curlies. A contrived example:
(&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24 (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
The bit position indicates STATE, STATE-read, for each of the states listed For a given lock, the bit positions from left to right indicate the usage
above, and the character displayed in each indicates: of the lock and readlock (if exists), for each of the n STATEs listed
above respectively, and the character displayed at each bit position
indicates:
'.' acquired while irqs disabled and not in irq context '.' acquired while irqs disabled and not in irq context
'-' acquired in irq context '-' acquired in irq context
'+' acquired with irqs enabled '+' acquired with irqs enabled
'?' acquired in irq context with irqs enabled. '?' acquired in irq context with irqs enabled.
Unused mutexes cannot be part of the cause of an error. The bits are illustrated with an example:
(&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
||||
||| \-> softirq disabled and not in softirq context
|| \--> acquired in softirq context
| \---> hardirq disabled and not in hardirq context
\----> acquired in hardirq context
For a given STATE, whether the lock is ever acquired in that STATE
context and whether that STATE is enabled yields four possible cases as
shown in the table below. The bit character is able to indicate which
exact case is for the lock as of the reporting time.
-------------------------------------------
| | irq enabled | irq disabled |
|-------------------------------------------|
| ever in irq | ? | - |
|-------------------------------------------|
| never in irq | + | . |
-------------------------------------------
The character '-' suggests irq is disabled because if otherwise the
charactor '?' would have been shown instead. Similar deduction can be
applied for '+' too.
Unused locks (e.g., mutexes) cannot be part of the cause of an error.
Single-lock state rules: Single-lock state rules:
------------------------ ------------------------
A lock is irq-safe means it was ever used in an irq context, while a lock
is irq-unsafe means it was ever acquired with irq enabled.
A softirq-unsafe lock-class is automatically hardirq-unsafe as well. The A softirq-unsafe lock-class is automatically hardirq-unsafe as well. The
following states are exclusive, and only one of them is allowed to be following states must be exclusive: only one of them is allowed to be set
set for any lock-class: for any lock-class based on its usage:
<hardirq-safe> or <hardirq-unsafe>
<softirq-safe> or <softirq-unsafe>
<hardirq-safe> and <hardirq-unsafe> This is because if a lock can be used in irq context (irq-safe) then it
<softirq-safe> and <softirq-unsafe> cannot be ever acquired with irq enabled (irq-unsafe). Otherwise, a
deadlock may happen. For example, in the scenario that after this lock
was acquired but before released, if the context is interrupted this
lock will be attempted to acquire twice, which creates a deadlock,
referred to as lock recursion deadlock.
The validator detects and reports lock usage that violate these The validator detects and reports lock usage that violates these
single-lock state rules. single-lock state rules.
Multi-lock dependency rules: Multi-lock dependency rules:
...@@ -81,15 +134,18 @@ Multi-lock dependency rules: ...@@ -81,15 +134,18 @@ Multi-lock dependency rules:
The same lock-class must not be acquired twice, because this could lead The same lock-class must not be acquired twice, because this could lead
to lock recursion deadlocks. to lock recursion deadlocks.
Furthermore, two locks may not be taken in different order: Furthermore, two locks can not be taken in inverse order:
<L1> -> <L2> <L1> -> <L2>
<L2> -> <L1> <L2> -> <L1>
because this could lead to lock inversion deadlocks. (The validator because this could lead to a deadlock - referred to as lock inversion
finds such dependencies in arbitrary complexity, i.e. there can be any deadlock - as attempts to acquire the two locks form a circle which
other locking sequence between the acquire-lock operations, the could lead to the two contexts waiting for each other permanently. The
validator will still track all dependencies between locks.) validator will find such dependency circle in arbitrary complexity,
i.e., there can be any other locking sequence between the acquire-lock
operations; the validator will still find whether these locks can be
acquired in a circular fashion.
Furthermore, the following usage based lock dependencies are not allowed Furthermore, the following usage based lock dependencies are not allowed
between any two lock-classes: between any two lock-classes:
......
...@@ -93,9 +93,9 @@ static inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v) \ ...@@ -93,9 +93,9 @@ static inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v) \
} }
#define ATOMIC64_OP(op, asm_op) \ #define ATOMIC64_OP(op, asm_op) \
static __inline__ void atomic64_##op(long i, atomic64_t * v) \ static __inline__ void atomic64_##op(s64 i, atomic64_t * v) \
{ \ { \
unsigned long temp; \ s64 temp; \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: ldq_l %0,%1\n" \ "1: ldq_l %0,%1\n" \
" " #asm_op " %0,%2,%0\n" \ " " #asm_op " %0,%2,%0\n" \
...@@ -109,9 +109,9 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ ...@@ -109,9 +109,9 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \
} \ } \
#define ATOMIC64_OP_RETURN(op, asm_op) \ #define ATOMIC64_OP_RETURN(op, asm_op) \
static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \ static __inline__ s64 atomic64_##op##_return_relaxed(s64 i, atomic64_t * v) \
{ \ { \
long temp, result; \ s64 temp, result; \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: ldq_l %0,%1\n" \ "1: ldq_l %0,%1\n" \
" " #asm_op " %0,%3,%2\n" \ " " #asm_op " %0,%3,%2\n" \
...@@ -128,9 +128,9 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \ ...@@ -128,9 +128,9 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \
} }
#define ATOMIC64_FETCH_OP(op, asm_op) \ #define ATOMIC64_FETCH_OP(op, asm_op) \
static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v) \ static __inline__ s64 atomic64_fetch_##op##_relaxed(s64 i, atomic64_t * v) \
{ \ { \
long temp, result; \ s64 temp, result; \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: ldq_l %2,%1\n" \ "1: ldq_l %2,%1\n" \
" " #asm_op " %2,%3,%0\n" \ " " #asm_op " %2,%3,%0\n" \
...@@ -246,9 +246,9 @@ static __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u) ...@@ -246,9 +246,9 @@ static __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u)
* Atomically adds @a to @v, so long as it was not @u. * Atomically adds @a to @v, so long as it was not @u.
* Returns the old value of @v. * Returns the old value of @v.
*/ */
static __inline__ long atomic64_fetch_add_unless(atomic64_t *v, long a, long u) static __inline__ s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
{ {
long c, new, old; s64 c, new, old;
smp_mb(); smp_mb();
__asm__ __volatile__( __asm__ __volatile__(
"1: ldq_l %[old],%[mem]\n" "1: ldq_l %[old],%[mem]\n"
...@@ -276,9 +276,9 @@ static __inline__ long atomic64_fetch_add_unless(atomic64_t *v, long a, long u) ...@@ -276,9 +276,9 @@ static __inline__ long atomic64_fetch_add_unless(atomic64_t *v, long a, long u)
* The function returns the old value of *v minus 1, even if * The function returns the old value of *v minus 1, even if
* the atomic variable, v, was not decremented. * the atomic variable, v, was not decremented.
*/ */
static inline long atomic64_dec_if_positive(atomic64_t *v) static inline s64 atomic64_dec_if_positive(atomic64_t *v)
{ {
long old, tmp; s64 old, tmp;
smp_mb(); smp_mb();
__asm__ __volatile__( __asm__ __volatile__(
"1: ldq_l %[old],%[mem]\n" "1: ldq_l %[old],%[mem]\n"
......
...@@ -321,14 +321,14 @@ ATOMIC_OPS(xor, ^=, CTOP_INST_AXOR_DI_R2_R2_R3) ...@@ -321,14 +321,14 @@ ATOMIC_OPS(xor, ^=, CTOP_INST_AXOR_DI_R2_R2_R3)
*/ */
typedef struct { typedef struct {
aligned_u64 counter; s64 __aligned(8) counter;
} atomic64_t; } atomic64_t;
#define ATOMIC64_INIT(a) { (a) } #define ATOMIC64_INIT(a) { (a) }
static inline long long atomic64_read(const atomic64_t *v) static inline s64 atomic64_read(const atomic64_t *v)
{ {
unsigned long long val; s64 val;
__asm__ __volatile__( __asm__ __volatile__(
" ldd %0, [%1] \n" " ldd %0, [%1] \n"
...@@ -338,7 +338,7 @@ static inline long long atomic64_read(const atomic64_t *v) ...@@ -338,7 +338,7 @@ static inline long long atomic64_read(const atomic64_t *v)
return val; return val;
} }
static inline void atomic64_set(atomic64_t *v, long long a) static inline void atomic64_set(atomic64_t *v, s64 a)
{ {
/* /*
* This could have been a simple assignment in "C" but would need * This could have been a simple assignment in "C" but would need
...@@ -359,9 +359,9 @@ static inline void atomic64_set(atomic64_t *v, long long a) ...@@ -359,9 +359,9 @@ static inline void atomic64_set(atomic64_t *v, long long a)
} }
#define ATOMIC64_OP(op, op1, op2) \ #define ATOMIC64_OP(op, op1, op2) \
static inline void atomic64_##op(long long a, atomic64_t *v) \ static inline void atomic64_##op(s64 a, atomic64_t *v) \
{ \ { \
unsigned long long val; \ s64 val; \
\ \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: \n" \ "1: \n" \
...@@ -372,13 +372,13 @@ static inline void atomic64_##op(long long a, atomic64_t *v) \ ...@@ -372,13 +372,13 @@ static inline void atomic64_##op(long long a, atomic64_t *v) \
" bnz 1b \n" \ " bnz 1b \n" \
: "=&r"(val) \ : "=&r"(val) \
: "r"(&v->counter), "ir"(a) \ : "r"(&v->counter), "ir"(a) \
: "cc"); \ : "cc"); \
} \ } \
#define ATOMIC64_OP_RETURN(op, op1, op2) \ #define ATOMIC64_OP_RETURN(op, op1, op2) \
static inline long long atomic64_##op##_return(long long a, atomic64_t *v) \ static inline s64 atomic64_##op##_return(s64 a, atomic64_t *v) \
{ \ { \
unsigned long long val; \ s64 val; \
\ \
smp_mb(); \ smp_mb(); \
\ \
...@@ -399,9 +399,9 @@ static inline long long atomic64_##op##_return(long long a, atomic64_t *v) \ ...@@ -399,9 +399,9 @@ static inline long long atomic64_##op##_return(long long a, atomic64_t *v) \
} }
#define ATOMIC64_FETCH_OP(op, op1, op2) \ #define ATOMIC64_FETCH_OP(op, op1, op2) \
static inline long long atomic64_fetch_##op(long long a, atomic64_t *v) \ static inline s64 atomic64_fetch_##op(s64 a, atomic64_t *v) \
{ \ { \
unsigned long long val, orig; \ s64 val, orig; \
\ \
smp_mb(); \ smp_mb(); \
\ \
...@@ -441,10 +441,10 @@ ATOMIC64_OPS(xor, xor, xor) ...@@ -441,10 +441,10 @@ ATOMIC64_OPS(xor, xor, xor)
#undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP_RETURN
#undef ATOMIC64_OP #undef ATOMIC64_OP
static inline long long static inline s64
atomic64_cmpxchg(atomic64_t *ptr, long long expected, long long new) atomic64_cmpxchg(atomic64_t *ptr, s64 expected, s64 new)
{ {
long long prev; s64 prev;
smp_mb(); smp_mb();
...@@ -464,9 +464,9 @@ atomic64_cmpxchg(atomic64_t *ptr, long long expected, long long new) ...@@ -464,9 +464,9 @@ atomic64_cmpxchg(atomic64_t *ptr, long long expected, long long new)
return prev; return prev;
} }
static inline long long atomic64_xchg(atomic64_t *ptr, long long new) static inline s64 atomic64_xchg(atomic64_t *ptr, s64 new)
{ {
long long prev; s64 prev;
smp_mb(); smp_mb();
...@@ -492,9 +492,9 @@ static inline long long atomic64_xchg(atomic64_t *ptr, long long new) ...@@ -492,9 +492,9 @@ static inline long long atomic64_xchg(atomic64_t *ptr, long long new)
* the atomic variable, v, was not decremented. * the atomic variable, v, was not decremented.
*/ */
static inline long long atomic64_dec_if_positive(atomic64_t *v) static inline s64 atomic64_dec_if_positive(atomic64_t *v)
{ {
long long val; s64 val;
smp_mb(); smp_mb();
...@@ -525,10 +525,9 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v) ...@@ -525,10 +525,9 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v)
* Atomically adds @a to @v, if it was not @u. * Atomically adds @a to @v, if it was not @u.
* Returns the old value of @v * Returns the old value of @v
*/ */
static inline long long atomic64_fetch_add_unless(atomic64_t *v, long long a, static inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
long long u)
{ {
long long old, temp; s64 old, temp;
smp_mb(); smp_mb();
......
...@@ -246,15 +246,15 @@ ATOMIC_OPS(xor, ^=, eor) ...@@ -246,15 +246,15 @@ ATOMIC_OPS(xor, ^=, eor)
#ifndef CONFIG_GENERIC_ATOMIC64 #ifndef CONFIG_GENERIC_ATOMIC64
typedef struct { typedef struct {
long long counter; s64 counter;
} atomic64_t; } atomic64_t;
#define ATOMIC64_INIT(i) { (i) } #define ATOMIC64_INIT(i) { (i) }
#ifdef CONFIG_ARM_LPAE #ifdef CONFIG_ARM_LPAE
static inline long long atomic64_read(const atomic64_t *v) static inline s64 atomic64_read(const atomic64_t *v)
{ {
long long result; s64 result;
__asm__ __volatile__("@ atomic64_read\n" __asm__ __volatile__("@ atomic64_read\n"
" ldrd %0, %H0, [%1]" " ldrd %0, %H0, [%1]"
...@@ -265,7 +265,7 @@ static inline long long atomic64_read(const atomic64_t *v) ...@@ -265,7 +265,7 @@ static inline long long atomic64_read(const atomic64_t *v)
return result; return result;
} }
static inline void atomic64_set(atomic64_t *v, long long i) static inline void atomic64_set(atomic64_t *v, s64 i)
{ {
__asm__ __volatile__("@ atomic64_set\n" __asm__ __volatile__("@ atomic64_set\n"
" strd %2, %H2, [%1]" " strd %2, %H2, [%1]"
...@@ -274,9 +274,9 @@ static inline void atomic64_set(atomic64_t *v, long long i) ...@@ -274,9 +274,9 @@ static inline void atomic64_set(atomic64_t *v, long long i)
); );
} }
#else #else
static inline long long atomic64_read(const atomic64_t *v) static inline s64 atomic64_read(const atomic64_t *v)
{ {
long long result; s64 result;
__asm__ __volatile__("@ atomic64_read\n" __asm__ __volatile__("@ atomic64_read\n"
" ldrexd %0, %H0, [%1]" " ldrexd %0, %H0, [%1]"
...@@ -287,9 +287,9 @@ static inline long long atomic64_read(const atomic64_t *v) ...@@ -287,9 +287,9 @@ static inline long long atomic64_read(const atomic64_t *v)
return result; return result;
} }
static inline void atomic64_set(atomic64_t *v, long long i) static inline void atomic64_set(atomic64_t *v, s64 i)
{ {
long long tmp; s64 tmp;
prefetchw(&v->counter); prefetchw(&v->counter);
__asm__ __volatile__("@ atomic64_set\n" __asm__ __volatile__("@ atomic64_set\n"
...@@ -304,9 +304,9 @@ static inline void atomic64_set(atomic64_t *v, long long i) ...@@ -304,9 +304,9 @@ static inline void atomic64_set(atomic64_t *v, long long i)
#endif #endif
#define ATOMIC64_OP(op, op1, op2) \ #define ATOMIC64_OP(op, op1, op2) \
static inline void atomic64_##op(long long i, atomic64_t *v) \ static inline void atomic64_##op(s64 i, atomic64_t *v) \
{ \ { \
long long result; \ s64 result; \
unsigned long tmp; \ unsigned long tmp; \
\ \
prefetchw(&v->counter); \ prefetchw(&v->counter); \
...@@ -323,10 +323,10 @@ static inline void atomic64_##op(long long i, atomic64_t *v) \ ...@@ -323,10 +323,10 @@ static inline void atomic64_##op(long long i, atomic64_t *v) \
} \ } \
#define ATOMIC64_OP_RETURN(op, op1, op2) \ #define ATOMIC64_OP_RETURN(op, op1, op2) \
static inline long long \ static inline s64 \
atomic64_##op##_return_relaxed(long long i, atomic64_t *v) \ atomic64_##op##_return_relaxed(s64 i, atomic64_t *v) \
{ \ { \
long long result; \ s64 result; \
unsigned long tmp; \ unsigned long tmp; \
\ \
prefetchw(&v->counter); \ prefetchw(&v->counter); \
...@@ -346,10 +346,10 @@ atomic64_##op##_return_relaxed(long long i, atomic64_t *v) \ ...@@ -346,10 +346,10 @@ atomic64_##op##_return_relaxed(long long i, atomic64_t *v) \
} }
#define ATOMIC64_FETCH_OP(op, op1, op2) \ #define ATOMIC64_FETCH_OP(op, op1, op2) \
static inline long long \ static inline s64 \
atomic64_fetch_##op##_relaxed(long long i, atomic64_t *v) \ atomic64_fetch_##op##_relaxed(s64 i, atomic64_t *v) \
{ \ { \
long long result, val; \ s64 result, val; \
unsigned long tmp; \ unsigned long tmp; \
\ \
prefetchw(&v->counter); \ prefetchw(&v->counter); \
...@@ -403,10 +403,9 @@ ATOMIC64_OPS(xor, eor, eor) ...@@ -403,10 +403,9 @@ ATOMIC64_OPS(xor, eor, eor)
#undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP_RETURN
#undef ATOMIC64_OP #undef ATOMIC64_OP
static inline long long static inline s64 atomic64_cmpxchg_relaxed(atomic64_t *ptr, s64 old, s64 new)
atomic64_cmpxchg_relaxed(atomic64_t *ptr, long long old, long long new)
{ {
long long oldval; s64 oldval;
unsigned long res; unsigned long res;
prefetchw(&ptr->counter); prefetchw(&ptr->counter);
...@@ -427,9 +426,9 @@ atomic64_cmpxchg_relaxed(atomic64_t *ptr, long long old, long long new) ...@@ -427,9 +426,9 @@ atomic64_cmpxchg_relaxed(atomic64_t *ptr, long long old, long long new)
} }
#define atomic64_cmpxchg_relaxed atomic64_cmpxchg_relaxed #define atomic64_cmpxchg_relaxed atomic64_cmpxchg_relaxed
static inline long long atomic64_xchg_relaxed(atomic64_t *ptr, long long new) static inline s64 atomic64_xchg_relaxed(atomic64_t *ptr, s64 new)
{ {
long long result; s64 result;
unsigned long tmp; unsigned long tmp;
prefetchw(&ptr->counter); prefetchw(&ptr->counter);
...@@ -447,9 +446,9 @@ static inline long long atomic64_xchg_relaxed(atomic64_t *ptr, long long new) ...@@ -447,9 +446,9 @@ static inline long long atomic64_xchg_relaxed(atomic64_t *ptr, long long new)
} }
#define atomic64_xchg_relaxed atomic64_xchg_relaxed #define atomic64_xchg_relaxed atomic64_xchg_relaxed
static inline long long atomic64_dec_if_positive(atomic64_t *v) static inline s64 atomic64_dec_if_positive(atomic64_t *v)
{ {
long long result; s64 result;
unsigned long tmp; unsigned long tmp;
smp_mb(); smp_mb();
...@@ -475,10 +474,9 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v) ...@@ -475,10 +474,9 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v)
} }
#define atomic64_dec_if_positive atomic64_dec_if_positive #define atomic64_dec_if_positive atomic64_dec_if_positive
static inline long long atomic64_fetch_add_unless(atomic64_t *v, long long a, static inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
long long u)
{ {
long long oldval, newval; s64 oldval, newval;
unsigned long tmp; unsigned long tmp;
smp_mb(); smp_mb();
......
...@@ -122,9 +122,9 @@ ATOMIC_OPS(xor, eor) ...@@ -122,9 +122,9 @@ ATOMIC_OPS(xor, eor)
#define ATOMIC64_OP(op, asm_op) \ #define ATOMIC64_OP(op, asm_op) \
__LL_SC_INLINE void \ __LL_SC_INLINE void \
__LL_SC_PREFIX(arch_atomic64_##op(long i, atomic64_t *v)) \ __LL_SC_PREFIX(arch_atomic64_##op(s64 i, atomic64_t *v)) \
{ \ { \
long result; \ s64 result; \
unsigned long tmp; \ unsigned long tmp; \
\ \
asm volatile("// atomic64_" #op "\n" \ asm volatile("// atomic64_" #op "\n" \
...@@ -139,10 +139,10 @@ __LL_SC_PREFIX(arch_atomic64_##op(long i, atomic64_t *v)) \ ...@@ -139,10 +139,10 @@ __LL_SC_PREFIX(arch_atomic64_##op(long i, atomic64_t *v)) \
__LL_SC_EXPORT(arch_atomic64_##op); __LL_SC_EXPORT(arch_atomic64_##op);
#define ATOMIC64_OP_RETURN(name, mb, acq, rel, cl, op, asm_op) \ #define ATOMIC64_OP_RETURN(name, mb, acq, rel, cl, op, asm_op) \
__LL_SC_INLINE long \ __LL_SC_INLINE s64 \
__LL_SC_PREFIX(arch_atomic64_##op##_return##name(long i, atomic64_t *v))\ __LL_SC_PREFIX(arch_atomic64_##op##_return##name(s64 i, atomic64_t *v))\
{ \ { \
long result; \ s64 result; \
unsigned long tmp; \ unsigned long tmp; \
\ \
asm volatile("// atomic64_" #op "_return" #name "\n" \ asm volatile("// atomic64_" #op "_return" #name "\n" \
...@@ -161,10 +161,10 @@ __LL_SC_PREFIX(arch_atomic64_##op##_return##name(long i, atomic64_t *v))\ ...@@ -161,10 +161,10 @@ __LL_SC_PREFIX(arch_atomic64_##op##_return##name(long i, atomic64_t *v))\
__LL_SC_EXPORT(arch_atomic64_##op##_return##name); __LL_SC_EXPORT(arch_atomic64_##op##_return##name);
#define ATOMIC64_FETCH_OP(name, mb, acq, rel, cl, op, asm_op) \ #define ATOMIC64_FETCH_OP(name, mb, acq, rel, cl, op, asm_op) \
__LL_SC_INLINE long \ __LL_SC_INLINE s64 \
__LL_SC_PREFIX(arch_atomic64_fetch_##op##name(long i, atomic64_t *v)) \ __LL_SC_PREFIX(arch_atomic64_fetch_##op##name(s64 i, atomic64_t *v)) \
{ \ { \
long result, val; \ s64 result, val; \
unsigned long tmp; \ unsigned long tmp; \
\ \
asm volatile("// atomic64_fetch_" #op #name "\n" \ asm volatile("// atomic64_fetch_" #op #name "\n" \
...@@ -214,10 +214,10 @@ ATOMIC64_OPS(xor, eor) ...@@ -214,10 +214,10 @@ ATOMIC64_OPS(xor, eor)
#undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP_RETURN
#undef ATOMIC64_OP #undef ATOMIC64_OP
__LL_SC_INLINE long __LL_SC_INLINE s64
__LL_SC_PREFIX(arch_atomic64_dec_if_positive(atomic64_t *v)) __LL_SC_PREFIX(arch_atomic64_dec_if_positive(atomic64_t *v))
{ {
long result; s64 result;
unsigned long tmp; unsigned long tmp;
asm volatile("// atomic64_dec_if_positive\n" asm volatile("// atomic64_dec_if_positive\n"
......
...@@ -213,9 +213,9 @@ ATOMIC_FETCH_OP_SUB( , al, "memory") ...@@ -213,9 +213,9 @@ ATOMIC_FETCH_OP_SUB( , al, "memory")
#define __LL_SC_ATOMIC64(op) __LL_SC_CALL(arch_atomic64_##op) #define __LL_SC_ATOMIC64(op) __LL_SC_CALL(arch_atomic64_##op)
#define ATOMIC64_OP(op, asm_op) \ #define ATOMIC64_OP(op, asm_op) \
static inline void arch_atomic64_##op(long i, atomic64_t *v) \ static inline void arch_atomic64_##op(s64 i, atomic64_t *v) \
{ \ { \
register long x0 asm ("x0") = i; \ register s64 x0 asm ("x0") = i; \
register atomic64_t *x1 asm ("x1") = v; \ register atomic64_t *x1 asm ("x1") = v; \
\ \
asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(op), \ asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(op), \
...@@ -233,9 +233,9 @@ ATOMIC64_OP(add, stadd) ...@@ -233,9 +233,9 @@ ATOMIC64_OP(add, stadd)
#undef ATOMIC64_OP #undef ATOMIC64_OP
#define ATOMIC64_FETCH_OP(name, mb, op, asm_op, cl...) \ #define ATOMIC64_FETCH_OP(name, mb, op, asm_op, cl...) \
static inline long arch_atomic64_fetch_##op##name(long i, atomic64_t *v)\ static inline s64 arch_atomic64_fetch_##op##name(s64 i, atomic64_t *v) \
{ \ { \
register long x0 asm ("x0") = i; \ register s64 x0 asm ("x0") = i; \
register atomic64_t *x1 asm ("x1") = v; \ register atomic64_t *x1 asm ("x1") = v; \
\ \
asm volatile(ARM64_LSE_ATOMIC_INSN( \ asm volatile(ARM64_LSE_ATOMIC_INSN( \
...@@ -265,9 +265,9 @@ ATOMIC64_FETCH_OPS(add, ldadd) ...@@ -265,9 +265,9 @@ ATOMIC64_FETCH_OPS(add, ldadd)
#undef ATOMIC64_FETCH_OPS #undef ATOMIC64_FETCH_OPS
#define ATOMIC64_OP_ADD_RETURN(name, mb, cl...) \ #define ATOMIC64_OP_ADD_RETURN(name, mb, cl...) \
static inline long arch_atomic64_add_return##name(long i, atomic64_t *v)\ static inline s64 arch_atomic64_add_return##name(s64 i, atomic64_t *v) \
{ \ { \
register long x0 asm ("x0") = i; \ register s64 x0 asm ("x0") = i; \
register atomic64_t *x1 asm ("x1") = v; \ register atomic64_t *x1 asm ("x1") = v; \
\ \
asm volatile(ARM64_LSE_ATOMIC_INSN( \ asm volatile(ARM64_LSE_ATOMIC_INSN( \
...@@ -291,9 +291,9 @@ ATOMIC64_OP_ADD_RETURN( , al, "memory") ...@@ -291,9 +291,9 @@ ATOMIC64_OP_ADD_RETURN( , al, "memory")
#undef ATOMIC64_OP_ADD_RETURN #undef ATOMIC64_OP_ADD_RETURN
static inline void arch_atomic64_and(long i, atomic64_t *v) static inline void arch_atomic64_and(s64 i, atomic64_t *v)
{ {
register long x0 asm ("x0") = i; register s64 x0 asm ("x0") = i;
register atomic64_t *x1 asm ("x1") = v; register atomic64_t *x1 asm ("x1") = v;
asm volatile(ARM64_LSE_ATOMIC_INSN( asm volatile(ARM64_LSE_ATOMIC_INSN(
...@@ -309,9 +309,9 @@ static inline void arch_atomic64_and(long i, atomic64_t *v) ...@@ -309,9 +309,9 @@ static inline void arch_atomic64_and(long i, atomic64_t *v)
} }
#define ATOMIC64_FETCH_OP_AND(name, mb, cl...) \ #define ATOMIC64_FETCH_OP_AND(name, mb, cl...) \
static inline long arch_atomic64_fetch_and##name(long i, atomic64_t *v) \ static inline s64 arch_atomic64_fetch_and##name(s64 i, atomic64_t *v) \
{ \ { \
register long x0 asm ("x0") = i; \ register s64 x0 asm ("x0") = i; \
register atomic64_t *x1 asm ("x1") = v; \ register atomic64_t *x1 asm ("x1") = v; \
\ \
asm volatile(ARM64_LSE_ATOMIC_INSN( \ asm volatile(ARM64_LSE_ATOMIC_INSN( \
...@@ -335,9 +335,9 @@ ATOMIC64_FETCH_OP_AND( , al, "memory") ...@@ -335,9 +335,9 @@ ATOMIC64_FETCH_OP_AND( , al, "memory")
#undef ATOMIC64_FETCH_OP_AND #undef ATOMIC64_FETCH_OP_AND
static inline void arch_atomic64_sub(long i, atomic64_t *v) static inline void arch_atomic64_sub(s64 i, atomic64_t *v)
{ {
register long x0 asm ("x0") = i; register s64 x0 asm ("x0") = i;
register atomic64_t *x1 asm ("x1") = v; register atomic64_t *x1 asm ("x1") = v;
asm volatile(ARM64_LSE_ATOMIC_INSN( asm volatile(ARM64_LSE_ATOMIC_INSN(
...@@ -353,9 +353,9 @@ static inline void arch_atomic64_sub(long i, atomic64_t *v) ...@@ -353,9 +353,9 @@ static inline void arch_atomic64_sub(long i, atomic64_t *v)
} }
#define ATOMIC64_OP_SUB_RETURN(name, mb, cl...) \ #define ATOMIC64_OP_SUB_RETURN(name, mb, cl...) \
static inline long arch_atomic64_sub_return##name(long i, atomic64_t *v)\ static inline s64 arch_atomic64_sub_return##name(s64 i, atomic64_t *v) \
{ \ { \
register long x0 asm ("x0") = i; \ register s64 x0 asm ("x0") = i; \
register atomic64_t *x1 asm ("x1") = v; \ register atomic64_t *x1 asm ("x1") = v; \
\ \
asm volatile(ARM64_LSE_ATOMIC_INSN( \ asm volatile(ARM64_LSE_ATOMIC_INSN( \
...@@ -381,9 +381,9 @@ ATOMIC64_OP_SUB_RETURN( , al, "memory") ...@@ -381,9 +381,9 @@ ATOMIC64_OP_SUB_RETURN( , al, "memory")
#undef ATOMIC64_OP_SUB_RETURN #undef ATOMIC64_OP_SUB_RETURN
#define ATOMIC64_FETCH_OP_SUB(name, mb, cl...) \ #define ATOMIC64_FETCH_OP_SUB(name, mb, cl...) \
static inline long arch_atomic64_fetch_sub##name(long i, atomic64_t *v) \ static inline s64 arch_atomic64_fetch_sub##name(s64 i, atomic64_t *v) \
{ \ { \
register long x0 asm ("x0") = i; \ register s64 x0 asm ("x0") = i; \
register atomic64_t *x1 asm ("x1") = v; \ register atomic64_t *x1 asm ("x1") = v; \
\ \
asm volatile(ARM64_LSE_ATOMIC_INSN( \ asm volatile(ARM64_LSE_ATOMIC_INSN( \
...@@ -407,7 +407,7 @@ ATOMIC64_FETCH_OP_SUB( , al, "memory") ...@@ -407,7 +407,7 @@ ATOMIC64_FETCH_OP_SUB( , al, "memory")
#undef ATOMIC64_FETCH_OP_SUB #undef ATOMIC64_FETCH_OP_SUB
static inline long arch_atomic64_dec_if_positive(atomic64_t *v) static inline s64 arch_atomic64_dec_if_positive(atomic64_t *v)
{ {
register long x0 asm ("x0") = (long)v; register long x0 asm ("x0") = (long)v;
......
...@@ -124,10 +124,10 @@ ATOMIC_FETCH_OP(xor, ^) ...@@ -124,10 +124,10 @@ ATOMIC_FETCH_OP(xor, ^)
#undef ATOMIC_OP #undef ATOMIC_OP
#define ATOMIC64_OP(op, c_op) \ #define ATOMIC64_OP(op, c_op) \
static __inline__ long \ static __inline__ s64 \
ia64_atomic64_##op (__s64 i, atomic64_t *v) \ ia64_atomic64_##op (s64 i, atomic64_t *v) \
{ \ { \
__s64 old, new; \ s64 old, new; \
CMPXCHG_BUGCHECK_DECL \ CMPXCHG_BUGCHECK_DECL \
\ \
do { \ do { \
...@@ -139,10 +139,10 @@ ia64_atomic64_##op (__s64 i, atomic64_t *v) \ ...@@ -139,10 +139,10 @@ ia64_atomic64_##op (__s64 i, atomic64_t *v) \
} }
#define ATOMIC64_FETCH_OP(op, c_op) \ #define ATOMIC64_FETCH_OP(op, c_op) \
static __inline__ long \ static __inline__ s64 \
ia64_atomic64_fetch_##op (__s64 i, atomic64_t *v) \ ia64_atomic64_fetch_##op (s64 i, atomic64_t *v) \
{ \ { \
__s64 old, new; \ s64 old, new; \
CMPXCHG_BUGCHECK_DECL \ CMPXCHG_BUGCHECK_DECL \
\ \
do { \ do { \
...@@ -162,7 +162,7 @@ ATOMIC64_OPS(sub, -) ...@@ -162,7 +162,7 @@ ATOMIC64_OPS(sub, -)
#define atomic64_add_return(i,v) \ #define atomic64_add_return(i,v) \
({ \ ({ \
long __ia64_aar_i = (i); \ s64 __ia64_aar_i = (i); \
__ia64_atomic_const(i) \ __ia64_atomic_const(i) \
? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \
: ia64_atomic64_add(__ia64_aar_i, v); \ : ia64_atomic64_add(__ia64_aar_i, v); \
...@@ -170,7 +170,7 @@ ATOMIC64_OPS(sub, -) ...@@ -170,7 +170,7 @@ ATOMIC64_OPS(sub, -)
#define atomic64_sub_return(i,v) \ #define atomic64_sub_return(i,v) \
({ \ ({ \
long __ia64_asr_i = (i); \ s64 __ia64_asr_i = (i); \
__ia64_atomic_const(i) \ __ia64_atomic_const(i) \
? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \
: ia64_atomic64_sub(__ia64_asr_i, v); \ : ia64_atomic64_sub(__ia64_asr_i, v); \
...@@ -178,7 +178,7 @@ ATOMIC64_OPS(sub, -) ...@@ -178,7 +178,7 @@ ATOMIC64_OPS(sub, -)
#define atomic64_fetch_add(i,v) \ #define atomic64_fetch_add(i,v) \
({ \ ({ \
long __ia64_aar_i = (i); \ s64 __ia64_aar_i = (i); \
__ia64_atomic_const(i) \ __ia64_atomic_const(i) \
? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq) \ ? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq) \
: ia64_atomic64_fetch_add(__ia64_aar_i, v); \ : ia64_atomic64_fetch_add(__ia64_aar_i, v); \
...@@ -186,7 +186,7 @@ ATOMIC64_OPS(sub, -) ...@@ -186,7 +186,7 @@ ATOMIC64_OPS(sub, -)
#define atomic64_fetch_sub(i,v) \ #define atomic64_fetch_sub(i,v) \
({ \ ({ \
long __ia64_asr_i = (i); \ s64 __ia64_asr_i = (i); \
__ia64_atomic_const(i) \ __ia64_atomic_const(i) \
? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq) \ ? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq) \
: ia64_atomic64_fetch_sub(__ia64_asr_i, v); \ : ia64_atomic64_fetch_sub(__ia64_asr_i, v); \
......
...@@ -254,10 +254,10 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) ...@@ -254,10 +254,10 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
#define atomic64_set(v, i) WRITE_ONCE((v)->counter, (i)) #define atomic64_set(v, i) WRITE_ONCE((v)->counter, (i))
#define ATOMIC64_OP(op, c_op, asm_op) \ #define ATOMIC64_OP(op, c_op, asm_op) \
static __inline__ void atomic64_##op(long i, atomic64_t * v) \ static __inline__ void atomic64_##op(s64 i, atomic64_t * v) \
{ \ { \
if (kernel_uses_llsc) { \ if (kernel_uses_llsc) { \
long temp; \ s64 temp; \
\ \
loongson_llsc_mb(); \ loongson_llsc_mb(); \
__asm__ __volatile__( \ __asm__ __volatile__( \
...@@ -280,12 +280,12 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ ...@@ -280,12 +280,12 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \
} }
#define ATOMIC64_OP_RETURN(op, c_op, asm_op) \ #define ATOMIC64_OP_RETURN(op, c_op, asm_op) \
static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \ static __inline__ s64 atomic64_##op##_return_relaxed(s64 i, atomic64_t * v) \
{ \ { \
long result; \ s64 result; \
\ \
if (kernel_uses_llsc) { \ if (kernel_uses_llsc) { \
long temp; \ s64 temp; \
\ \
loongson_llsc_mb(); \ loongson_llsc_mb(); \
__asm__ __volatile__( \ __asm__ __volatile__( \
...@@ -314,12 +314,12 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \ ...@@ -314,12 +314,12 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \
} }
#define ATOMIC64_FETCH_OP(op, c_op, asm_op) \ #define ATOMIC64_FETCH_OP(op, c_op, asm_op) \
static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v) \ static __inline__ s64 atomic64_fetch_##op##_relaxed(s64 i, atomic64_t * v) \
{ \ { \
long result; \ s64 result; \
\ \
if (kernel_uses_llsc) { \ if (kernel_uses_llsc) { \
long temp; \ s64 temp; \
\ \
loongson_llsc_mb(); \ loongson_llsc_mb(); \
__asm__ __volatile__( \ __asm__ __volatile__( \
...@@ -386,14 +386,14 @@ ATOMIC64_OPS(xor, ^=, xor) ...@@ -386,14 +386,14 @@ ATOMIC64_OPS(xor, ^=, xor)
* Atomically test @v and subtract @i if @v is greater or equal than @i. * Atomically test @v and subtract @i if @v is greater or equal than @i.
* The function returns the old value of @v minus @i. * The function returns the old value of @v minus @i.
*/ */
static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) static __inline__ s64 atomic64_sub_if_positive(s64 i, atomic64_t * v)
{ {
long result; s64 result;
smp_mb__before_llsc(); smp_mb__before_llsc();
if (kernel_uses_llsc) { if (kernel_uses_llsc) {
long temp; s64 temp;
__asm__ __volatile__( __asm__ __volatile__(
" .set push \n" " .set push \n"
......
...@@ -297,24 +297,24 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v) ...@@ -297,24 +297,24 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v)
#define ATOMIC64_INIT(i) { (i) } #define ATOMIC64_INIT(i) { (i) }
static __inline__ long atomic64_read(const atomic64_t *v) static __inline__ s64 atomic64_read(const atomic64_t *v)
{ {
long t; s64 t;
__asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter)); __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter));
return t; return t;
} }
static __inline__ void atomic64_set(atomic64_t *v, long i) static __inline__ void atomic64_set(atomic64_t *v, s64 i)
{ {
__asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
} }
#define ATOMIC64_OP(op, asm_op) \ #define ATOMIC64_OP(op, asm_op) \
static __inline__ void atomic64_##op(long a, atomic64_t *v) \ static __inline__ void atomic64_##op(s64 a, atomic64_t *v) \
{ \ { \
long t; \ s64 t; \
\ \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: ldarx %0,0,%3 # atomic64_" #op "\n" \ "1: ldarx %0,0,%3 # atomic64_" #op "\n" \
...@@ -327,10 +327,10 @@ static __inline__ void atomic64_##op(long a, atomic64_t *v) \ ...@@ -327,10 +327,10 @@ static __inline__ void atomic64_##op(long a, atomic64_t *v) \
} }
#define ATOMIC64_OP_RETURN_RELAXED(op, asm_op) \ #define ATOMIC64_OP_RETURN_RELAXED(op, asm_op) \
static inline long \ static inline s64 \
atomic64_##op##_return_relaxed(long a, atomic64_t *v) \ atomic64_##op##_return_relaxed(s64 a, atomic64_t *v) \
{ \ { \
long t; \ s64 t; \
\ \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: ldarx %0,0,%3 # atomic64_" #op "_return_relaxed\n" \ "1: ldarx %0,0,%3 # atomic64_" #op "_return_relaxed\n" \
...@@ -345,10 +345,10 @@ atomic64_##op##_return_relaxed(long a, atomic64_t *v) \ ...@@ -345,10 +345,10 @@ atomic64_##op##_return_relaxed(long a, atomic64_t *v) \
} }
#define ATOMIC64_FETCH_OP_RELAXED(op, asm_op) \ #define ATOMIC64_FETCH_OP_RELAXED(op, asm_op) \
static inline long \ static inline s64 \
atomic64_fetch_##op##_relaxed(long a, atomic64_t *v) \ atomic64_fetch_##op##_relaxed(s64 a, atomic64_t *v) \
{ \ { \
long res, t; \ s64 res, t; \
\ \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: ldarx %0,0,%4 # atomic64_fetch_" #op "_relaxed\n" \ "1: ldarx %0,0,%4 # atomic64_fetch_" #op "_relaxed\n" \
...@@ -396,7 +396,7 @@ ATOMIC64_OPS(xor, xor) ...@@ -396,7 +396,7 @@ ATOMIC64_OPS(xor, xor)
static __inline__ void atomic64_inc(atomic64_t *v) static __inline__ void atomic64_inc(atomic64_t *v)
{ {
long t; s64 t;
__asm__ __volatile__( __asm__ __volatile__(
"1: ldarx %0,0,%2 # atomic64_inc\n\ "1: ldarx %0,0,%2 # atomic64_inc\n\
...@@ -409,9 +409,9 @@ static __inline__ void atomic64_inc(atomic64_t *v) ...@@ -409,9 +409,9 @@ static __inline__ void atomic64_inc(atomic64_t *v)
} }
#define atomic64_inc atomic64_inc #define atomic64_inc atomic64_inc
static __inline__ long atomic64_inc_return_relaxed(atomic64_t *v) static __inline__ s64 atomic64_inc_return_relaxed(atomic64_t *v)
{ {
long t; s64 t;
__asm__ __volatile__( __asm__ __volatile__(
"1: ldarx %0,0,%2 # atomic64_inc_return_relaxed\n" "1: ldarx %0,0,%2 # atomic64_inc_return_relaxed\n"
...@@ -427,7 +427,7 @@ static __inline__ long atomic64_inc_return_relaxed(atomic64_t *v) ...@@ -427,7 +427,7 @@ static __inline__ long atomic64_inc_return_relaxed(atomic64_t *v)
static __inline__ void atomic64_dec(atomic64_t *v) static __inline__ void atomic64_dec(atomic64_t *v)
{ {
long t; s64 t;
__asm__ __volatile__( __asm__ __volatile__(
"1: ldarx %0,0,%2 # atomic64_dec\n\ "1: ldarx %0,0,%2 # atomic64_dec\n\
...@@ -440,9 +440,9 @@ static __inline__ void atomic64_dec(atomic64_t *v) ...@@ -440,9 +440,9 @@ static __inline__ void atomic64_dec(atomic64_t *v)
} }
#define atomic64_dec atomic64_dec #define atomic64_dec atomic64_dec
static __inline__ long atomic64_dec_return_relaxed(atomic64_t *v) static __inline__ s64 atomic64_dec_return_relaxed(atomic64_t *v)
{ {
long t; s64 t;
__asm__ __volatile__( __asm__ __volatile__(
"1: ldarx %0,0,%2 # atomic64_dec_return_relaxed\n" "1: ldarx %0,0,%2 # atomic64_dec_return_relaxed\n"
...@@ -463,9 +463,9 @@ static __inline__ long atomic64_dec_return_relaxed(atomic64_t *v) ...@@ -463,9 +463,9 @@ static __inline__ long atomic64_dec_return_relaxed(atomic64_t *v)
* Atomically test *v and decrement if it is greater than 0. * Atomically test *v and decrement if it is greater than 0.
* The function returns the old value of *v minus 1. * The function returns the old value of *v minus 1.
*/ */
static __inline__ long atomic64_dec_if_positive(atomic64_t *v) static __inline__ s64 atomic64_dec_if_positive(atomic64_t *v)
{ {
long t; s64 t;
__asm__ __volatile__( __asm__ __volatile__(
PPC_ATOMIC_ENTRY_BARRIER PPC_ATOMIC_ENTRY_BARRIER
...@@ -502,9 +502,9 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v) ...@@ -502,9 +502,9 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
* Atomically adds @a to @v, so long as it was not @u. * Atomically adds @a to @v, so long as it was not @u.
* Returns the old value of @v. * Returns the old value of @v.
*/ */
static __inline__ long atomic64_fetch_add_unless(atomic64_t *v, long a, long u) static __inline__ s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
{ {
long t; s64 t;
__asm__ __volatile__ ( __asm__ __volatile__ (
PPC_ATOMIC_ENTRY_BARRIER PPC_ATOMIC_ENTRY_BARRIER
...@@ -534,7 +534,7 @@ static __inline__ long atomic64_fetch_add_unless(atomic64_t *v, long a, long u) ...@@ -534,7 +534,7 @@ static __inline__ long atomic64_fetch_add_unless(atomic64_t *v, long a, long u)
*/ */
static __inline__ int atomic64_inc_not_zero(atomic64_t *v) static __inline__ int atomic64_inc_not_zero(atomic64_t *v)
{ {
long t1, t2; s64 t1, t2;
__asm__ __volatile__ ( __asm__ __volatile__ (
PPC_ATOMIC_ENTRY_BARRIER PPC_ATOMIC_ENTRY_BARRIER
......
...@@ -38,11 +38,11 @@ static __always_inline void atomic_set(atomic_t *v, int i) ...@@ -38,11 +38,11 @@ static __always_inline void atomic_set(atomic_t *v, int i)
#ifndef CONFIG_GENERIC_ATOMIC64 #ifndef CONFIG_GENERIC_ATOMIC64
#define ATOMIC64_INIT(i) { (i) } #define ATOMIC64_INIT(i) { (i) }
static __always_inline long atomic64_read(const atomic64_t *v) static __always_inline s64 atomic64_read(const atomic64_t *v)
{ {
return READ_ONCE(v->counter); return READ_ONCE(v->counter);
} }
static __always_inline void atomic64_set(atomic64_t *v, long i) static __always_inline void atomic64_set(atomic64_t *v, s64 i)
{ {
WRITE_ONCE(v->counter, i); WRITE_ONCE(v->counter, i);
} }
...@@ -66,11 +66,11 @@ void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ ...@@ -66,11 +66,11 @@ void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \
#ifdef CONFIG_GENERIC_ATOMIC64 #ifdef CONFIG_GENERIC_ATOMIC64
#define ATOMIC_OPS(op, asm_op, I) \ #define ATOMIC_OPS(op, asm_op, I) \
ATOMIC_OP (op, asm_op, I, w, int, ) ATOMIC_OP (op, asm_op, I, w, int, )
#else #else
#define ATOMIC_OPS(op, asm_op, I) \ #define ATOMIC_OPS(op, asm_op, I) \
ATOMIC_OP (op, asm_op, I, w, int, ) \ ATOMIC_OP (op, asm_op, I, w, int, ) \
ATOMIC_OP (op, asm_op, I, d, long, 64) ATOMIC_OP (op, asm_op, I, d, s64, 64)
#endif #endif
ATOMIC_OPS(add, add, i) ATOMIC_OPS(add, add, i)
...@@ -127,14 +127,14 @@ c_type atomic##prefix##_##op##_return(c_type i, atomic##prefix##_t *v) \ ...@@ -127,14 +127,14 @@ c_type atomic##prefix##_##op##_return(c_type i, atomic##prefix##_t *v) \
#ifdef CONFIG_GENERIC_ATOMIC64 #ifdef CONFIG_GENERIC_ATOMIC64
#define ATOMIC_OPS(op, asm_op, c_op, I) \ #define ATOMIC_OPS(op, asm_op, c_op, I) \
ATOMIC_FETCH_OP( op, asm_op, I, w, int, ) \ ATOMIC_FETCH_OP( op, asm_op, I, w, int, ) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, w, int, ) ATOMIC_OP_RETURN(op, asm_op, c_op, I, w, int, )
#else #else
#define ATOMIC_OPS(op, asm_op, c_op, I) \ #define ATOMIC_OPS(op, asm_op, c_op, I) \
ATOMIC_FETCH_OP( op, asm_op, I, w, int, ) \ ATOMIC_FETCH_OP( op, asm_op, I, w, int, ) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, w, int, ) \ ATOMIC_OP_RETURN(op, asm_op, c_op, I, w, int, ) \
ATOMIC_FETCH_OP( op, asm_op, I, d, long, 64) \ ATOMIC_FETCH_OP( op, asm_op, I, d, s64, 64) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, d, long, 64) ATOMIC_OP_RETURN(op, asm_op, c_op, I, d, s64, 64)
#endif #endif
ATOMIC_OPS(add, add, +, i) ATOMIC_OPS(add, add, +, i)
...@@ -166,11 +166,11 @@ ATOMIC_OPS(sub, add, +, -i) ...@@ -166,11 +166,11 @@ ATOMIC_OPS(sub, add, +, -i)
#ifdef CONFIG_GENERIC_ATOMIC64 #ifdef CONFIG_GENERIC_ATOMIC64
#define ATOMIC_OPS(op, asm_op, I) \ #define ATOMIC_OPS(op, asm_op, I) \
ATOMIC_FETCH_OP(op, asm_op, I, w, int, ) ATOMIC_FETCH_OP(op, asm_op, I, w, int, )
#else #else
#define ATOMIC_OPS(op, asm_op, I) \ #define ATOMIC_OPS(op, asm_op, I) \
ATOMIC_FETCH_OP(op, asm_op, I, w, int, ) \ ATOMIC_FETCH_OP(op, asm_op, I, w, int, ) \
ATOMIC_FETCH_OP(op, asm_op, I, d, long, 64) ATOMIC_FETCH_OP(op, asm_op, I, d, s64, 64)
#endif #endif
ATOMIC_OPS(and, and, i) ATOMIC_OPS(and, and, i)
...@@ -219,9 +219,10 @@ static __always_inline int atomic_fetch_add_unless(atomic_t *v, int a, int u) ...@@ -219,9 +219,10 @@ static __always_inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
#define atomic_fetch_add_unless atomic_fetch_add_unless #define atomic_fetch_add_unless atomic_fetch_add_unless
#ifndef CONFIG_GENERIC_ATOMIC64 #ifndef CONFIG_GENERIC_ATOMIC64
static __always_inline long atomic64_fetch_add_unless(atomic64_t *v, long a, long u) static __always_inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
{ {
long prev, rc; s64 prev;
long rc;
__asm__ __volatile__ ( __asm__ __volatile__ (
"0: lr.d %[p], %[c]\n" "0: lr.d %[p], %[c]\n"
...@@ -290,11 +291,11 @@ c_t atomic##prefix##_cmpxchg(atomic##prefix##_t *v, c_t o, c_t n) \ ...@@ -290,11 +291,11 @@ c_t atomic##prefix##_cmpxchg(atomic##prefix##_t *v, c_t o, c_t n) \
#ifdef CONFIG_GENERIC_ATOMIC64 #ifdef CONFIG_GENERIC_ATOMIC64
#define ATOMIC_OPS() \ #define ATOMIC_OPS() \
ATOMIC_OP( int, , 4) ATOMIC_OP(int, , 4)
#else #else
#define ATOMIC_OPS() \ #define ATOMIC_OPS() \
ATOMIC_OP( int, , 4) \ ATOMIC_OP(int, , 4) \
ATOMIC_OP(long, 64, 8) ATOMIC_OP(s64, 64, 8)
#endif #endif
ATOMIC_OPS() ATOMIC_OPS()
...@@ -332,9 +333,10 @@ static __always_inline int atomic_sub_if_positive(atomic_t *v, int offset) ...@@ -332,9 +333,10 @@ static __always_inline int atomic_sub_if_positive(atomic_t *v, int offset)
#define atomic_dec_if_positive(v) atomic_sub_if_positive(v, 1) #define atomic_dec_if_positive(v) atomic_sub_if_positive(v, 1)
#ifndef CONFIG_GENERIC_ATOMIC64 #ifndef CONFIG_GENERIC_ATOMIC64
static __always_inline long atomic64_sub_if_positive(atomic64_t *v, int offset) static __always_inline s64 atomic64_sub_if_positive(atomic64_t *v, s64 offset)
{ {
long prev, rc; s64 prev;
long rc;
__asm__ __volatile__ ( __asm__ __volatile__ (
"0: lr.d %[p], %[c]\n" "0: lr.d %[p], %[c]\n"
......
...@@ -84,9 +84,9 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new) ...@@ -84,9 +84,9 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
#define ATOMIC64_INIT(i) { (i) } #define ATOMIC64_INIT(i) { (i) }
static inline long atomic64_read(const atomic64_t *v) static inline s64 atomic64_read(const atomic64_t *v)
{ {
long c; s64 c;
asm volatile( asm volatile(
" lg %0,%1\n" " lg %0,%1\n"
...@@ -94,49 +94,49 @@ static inline long atomic64_read(const atomic64_t *v) ...@@ -94,49 +94,49 @@ static inline long atomic64_read(const atomic64_t *v)
return c; return c;
} }
static inline void atomic64_set(atomic64_t *v, long i) static inline void atomic64_set(atomic64_t *v, s64 i)
{ {
asm volatile( asm volatile(
" stg %1,%0\n" " stg %1,%0\n"
: "=Q" (v->counter) : "d" (i)); : "=Q" (v->counter) : "d" (i));
} }
static inline long atomic64_add_return(long i, atomic64_t *v) static inline s64 atomic64_add_return(s64 i, atomic64_t *v)
{ {
return __atomic64_add_barrier(i, &v->counter) + i; return __atomic64_add_barrier(i, (long *)&v->counter) + i;
} }
static inline long atomic64_fetch_add(long i, atomic64_t *v) static inline s64 atomic64_fetch_add(s64 i, atomic64_t *v)
{ {
return __atomic64_add_barrier(i, &v->counter); return __atomic64_add_barrier(i, (long *)&v->counter);
} }
static inline void atomic64_add(long i, atomic64_t *v) static inline void atomic64_add(s64 i, atomic64_t *v)
{ {
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
if (__builtin_constant_p(i) && (i > -129) && (i < 128)) { if (__builtin_constant_p(i) && (i > -129) && (i < 128)) {
__atomic64_add_const(i, &v->counter); __atomic64_add_const(i, (long *)&v->counter);
return; return;
} }
#endif #endif
__atomic64_add(i, &v->counter); __atomic64_add(i, (long *)&v->counter);
} }
#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new) static inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
{ {
return __atomic64_cmpxchg(&v->counter, old, new); return __atomic64_cmpxchg((long *)&v->counter, old, new);
} }
#define ATOMIC64_OPS(op) \ #define ATOMIC64_OPS(op) \
static inline void atomic64_##op(long i, atomic64_t *v) \ static inline void atomic64_##op(s64 i, atomic64_t *v) \
{ \ { \
__atomic64_##op(i, &v->counter); \ __atomic64_##op(i, (long *)&v->counter); \
} \ } \
static inline long atomic64_fetch_##op(long i, atomic64_t *v) \ static inline long atomic64_fetch_##op(s64 i, atomic64_t *v) \
{ \ { \
return __atomic64_##op##_barrier(i, &v->counter); \ return __atomic64_##op##_barrier(i, (long *)&v->counter); \
} }
ATOMIC64_OPS(and) ATOMIC64_OPS(and)
...@@ -145,8 +145,8 @@ ATOMIC64_OPS(xor) ...@@ -145,8 +145,8 @@ ATOMIC64_OPS(xor)
#undef ATOMIC64_OPS #undef ATOMIC64_OPS
#define atomic64_sub_return(_i, _v) atomic64_add_return(-(long)(_i), _v) #define atomic64_sub_return(_i, _v) atomic64_add_return(-(s64)(_i), _v)
#define atomic64_fetch_sub(_i, _v) atomic64_fetch_add(-(long)(_i), _v) #define atomic64_fetch_sub(_i, _v) atomic64_fetch_add(-(s64)(_i), _v)
#define atomic64_sub(_i, _v) atomic64_add(-(long)(_i), _v) #define atomic64_sub(_i, _v) atomic64_add(-(s64)(_i), _v)
#endif /* __ARCH_S390_ATOMIC__ */ #endif /* __ARCH_S390_ATOMIC__ */
...@@ -74,7 +74,7 @@ static void pci_sw_counter_show(struct seq_file *m) ...@@ -74,7 +74,7 @@ static void pci_sw_counter_show(struct seq_file *m)
int i; int i;
for (i = 0; i < ARRAY_SIZE(pci_sw_names); i++, counter++) for (i = 0; i < ARRAY_SIZE(pci_sw_names); i++, counter++)
seq_printf(m, "%26s:\t%lu\n", pci_sw_names[i], seq_printf(m, "%26s:\t%llu\n", pci_sw_names[i],
atomic64_read(counter)); atomic64_read(counter));
} }
......
...@@ -23,15 +23,15 @@ ...@@ -23,15 +23,15 @@
#define ATOMIC_OP(op) \ #define ATOMIC_OP(op) \
void atomic_##op(int, atomic_t *); \ void atomic_##op(int, atomic_t *); \
void atomic64_##op(long, atomic64_t *); void atomic64_##op(s64, atomic64_t *);
#define ATOMIC_OP_RETURN(op) \ #define ATOMIC_OP_RETURN(op) \
int atomic_##op##_return(int, atomic_t *); \ int atomic_##op##_return(int, atomic_t *); \
long atomic64_##op##_return(long, atomic64_t *); s64 atomic64_##op##_return(s64, atomic64_t *);
#define ATOMIC_FETCH_OP(op) \ #define ATOMIC_FETCH_OP(op) \
int atomic_fetch_##op(int, atomic_t *); \ int atomic_fetch_##op(int, atomic_t *); \
long atomic64_fetch_##op(long, atomic64_t *); s64 atomic64_fetch_##op(s64, atomic64_t *);
#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op)
...@@ -61,7 +61,7 @@ static inline int atomic_xchg(atomic_t *v, int new) ...@@ -61,7 +61,7 @@ static inline int atomic_xchg(atomic_t *v, int new)
((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n))) ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
long atomic64_dec_if_positive(atomic64_t *v); s64 atomic64_dec_if_positive(atomic64_t *v);
#define atomic64_dec_if_positive atomic64_dec_if_positive #define atomic64_dec_if_positive atomic64_dec_if_positive
#endif /* !(__ARCH_SPARC64_ATOMIC__) */ #endif /* !(__ARCH_SPARC64_ATOMIC__) */
...@@ -2179,7 +2179,7 @@ static void x86_pmu_event_mapped(struct perf_event *event, struct mm_struct *mm) ...@@ -2179,7 +2179,7 @@ static void x86_pmu_event_mapped(struct perf_event *event, struct mm_struct *mm)
* For now, this can't happen because all callers hold mmap_sem * For now, this can't happen because all callers hold mmap_sem
* for write. If this changes, we'll need a different solution. * for write. If this changes, we'll need a different solution.
*/ */
lockdep_assert_held_exclusive(&mm->mmap_sem); lockdep_assert_held_write(&mm->mmap_sem);
if (atomic_inc_return(&mm->context.perf_rdpmc_allowed) == 1) if (atomic_inc_return(&mm->context.perf_rdpmc_allowed) == 1)
on_each_cpu_mask(mm_cpumask(mm), refresh_pce, NULL, 1); on_each_cpu_mask(mm_cpumask(mm), refresh_pce, NULL, 1);
......
...@@ -54,7 +54,7 @@ static __always_inline void arch_atomic_add(int i, atomic_t *v) ...@@ -54,7 +54,7 @@ static __always_inline void arch_atomic_add(int i, atomic_t *v)
{ {
asm volatile(LOCK_PREFIX "addl %1,%0" asm volatile(LOCK_PREFIX "addl %1,%0"
: "+m" (v->counter) : "+m" (v->counter)
: "ir" (i)); : "ir" (i) : "memory");
} }
/** /**
...@@ -68,7 +68,7 @@ static __always_inline void arch_atomic_sub(int i, atomic_t *v) ...@@ -68,7 +68,7 @@ static __always_inline void arch_atomic_sub(int i, atomic_t *v)
{ {
asm volatile(LOCK_PREFIX "subl %1,%0" asm volatile(LOCK_PREFIX "subl %1,%0"
: "+m" (v->counter) : "+m" (v->counter)
: "ir" (i)); : "ir" (i) : "memory");
} }
/** /**
...@@ -95,7 +95,7 @@ static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v) ...@@ -95,7 +95,7 @@ static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v)
static __always_inline void arch_atomic_inc(atomic_t *v) static __always_inline void arch_atomic_inc(atomic_t *v)
{ {
asm volatile(LOCK_PREFIX "incl %0" asm volatile(LOCK_PREFIX "incl %0"
: "+m" (v->counter)); : "+m" (v->counter) :: "memory");
} }
#define arch_atomic_inc arch_atomic_inc #define arch_atomic_inc arch_atomic_inc
...@@ -108,7 +108,7 @@ static __always_inline void arch_atomic_inc(atomic_t *v) ...@@ -108,7 +108,7 @@ static __always_inline void arch_atomic_inc(atomic_t *v)
static __always_inline void arch_atomic_dec(atomic_t *v) static __always_inline void arch_atomic_dec(atomic_t *v)
{ {
asm volatile(LOCK_PREFIX "decl %0" asm volatile(LOCK_PREFIX "decl %0"
: "+m" (v->counter)); : "+m" (v->counter) :: "memory");
} }
#define arch_atomic_dec arch_atomic_dec #define arch_atomic_dec arch_atomic_dec
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
/* An 64bit atomic type */ /* An 64bit atomic type */
typedef struct { typedef struct {
u64 __aligned(8) counter; s64 __aligned(8) counter;
} atomic64_t; } atomic64_t;
#define ATOMIC64_INIT(val) { (val) } #define ATOMIC64_INIT(val) { (val) }
...@@ -71,8 +71,7 @@ ATOMIC64_DECL(add_unless); ...@@ -71,8 +71,7 @@ ATOMIC64_DECL(add_unless);
* the old value. * the old value.
*/ */
static inline long long arch_atomic64_cmpxchg(atomic64_t *v, long long o, static inline s64 arch_atomic64_cmpxchg(atomic64_t *v, s64 o, s64 n)
long long n)
{ {
return arch_cmpxchg64(&v->counter, o, n); return arch_cmpxchg64(&v->counter, o, n);
} }
...@@ -85,9 +84,9 @@ static inline long long arch_atomic64_cmpxchg(atomic64_t *v, long long o, ...@@ -85,9 +84,9 @@ static inline long long arch_atomic64_cmpxchg(atomic64_t *v, long long o,
* Atomically xchgs the value of @v to @n and returns * Atomically xchgs the value of @v to @n and returns
* the old value. * the old value.
*/ */
static inline long long arch_atomic64_xchg(atomic64_t *v, long long n) static inline s64 arch_atomic64_xchg(atomic64_t *v, s64 n)
{ {
long long o; s64 o;
unsigned high = (unsigned)(n >> 32); unsigned high = (unsigned)(n >> 32);
unsigned low = (unsigned)n; unsigned low = (unsigned)n;
alternative_atomic64(xchg, "=&A" (o), alternative_atomic64(xchg, "=&A" (o),
...@@ -103,7 +102,7 @@ static inline long long arch_atomic64_xchg(atomic64_t *v, long long n) ...@@ -103,7 +102,7 @@ static inline long long arch_atomic64_xchg(atomic64_t *v, long long n)
* *
* Atomically sets the value of @v to @n. * Atomically sets the value of @v to @n.
*/ */
static inline void arch_atomic64_set(atomic64_t *v, long long i) static inline void arch_atomic64_set(atomic64_t *v, s64 i)
{ {
unsigned high = (unsigned)(i >> 32); unsigned high = (unsigned)(i >> 32);
unsigned low = (unsigned)i; unsigned low = (unsigned)i;
...@@ -118,9 +117,9 @@ static inline void arch_atomic64_set(atomic64_t *v, long long i) ...@@ -118,9 +117,9 @@ static inline void arch_atomic64_set(atomic64_t *v, long long i)
* *
* Atomically reads the value of @v and returns it. * Atomically reads the value of @v and returns it.
*/ */
static inline long long arch_atomic64_read(const atomic64_t *v) static inline s64 arch_atomic64_read(const atomic64_t *v)
{ {
long long r; s64 r;
alternative_atomic64(read, "=&A" (r), "c" (v) : "memory"); alternative_atomic64(read, "=&A" (r), "c" (v) : "memory");
return r; return r;
} }
...@@ -132,7 +131,7 @@ static inline long long arch_atomic64_read(const atomic64_t *v) ...@@ -132,7 +131,7 @@ static inline long long arch_atomic64_read(const atomic64_t *v)
* *
* Atomically adds @i to @v and returns @i + *@v * Atomically adds @i to @v and returns @i + *@v
*/ */
static inline long long arch_atomic64_add_return(long long i, atomic64_t *v) static inline s64 arch_atomic64_add_return(s64 i, atomic64_t *v)
{ {
alternative_atomic64(add_return, alternative_atomic64(add_return,
ASM_OUTPUT2("+A" (i), "+c" (v)), ASM_OUTPUT2("+A" (i), "+c" (v)),
...@@ -143,7 +142,7 @@ static inline long long arch_atomic64_add_return(long long i, atomic64_t *v) ...@@ -143,7 +142,7 @@ static inline long long arch_atomic64_add_return(long long i, atomic64_t *v)
/* /*
* Other variants with different arithmetic operators: * Other variants with different arithmetic operators:
*/ */
static inline long long arch_atomic64_sub_return(long long i, atomic64_t *v) static inline s64 arch_atomic64_sub_return(s64 i, atomic64_t *v)
{ {
alternative_atomic64(sub_return, alternative_atomic64(sub_return,
ASM_OUTPUT2("+A" (i), "+c" (v)), ASM_OUTPUT2("+A" (i), "+c" (v)),
...@@ -151,18 +150,18 @@ static inline long long arch_atomic64_sub_return(long long i, atomic64_t *v) ...@@ -151,18 +150,18 @@ static inline long long arch_atomic64_sub_return(long long i, atomic64_t *v)
return i; return i;
} }
static inline long long arch_atomic64_inc_return(atomic64_t *v) static inline s64 arch_atomic64_inc_return(atomic64_t *v)
{ {
long long a; s64 a;
alternative_atomic64(inc_return, "=&A" (a), alternative_atomic64(inc_return, "=&A" (a),
"S" (v) : "memory", "ecx"); "S" (v) : "memory", "ecx");
return a; return a;
} }
#define arch_atomic64_inc_return arch_atomic64_inc_return #define arch_atomic64_inc_return arch_atomic64_inc_return
static inline long long arch_atomic64_dec_return(atomic64_t *v) static inline s64 arch_atomic64_dec_return(atomic64_t *v)
{ {
long long a; s64 a;
alternative_atomic64(dec_return, "=&A" (a), alternative_atomic64(dec_return, "=&A" (a),
"S" (v) : "memory", "ecx"); "S" (v) : "memory", "ecx");
return a; return a;
...@@ -176,7 +175,7 @@ static inline long long arch_atomic64_dec_return(atomic64_t *v) ...@@ -176,7 +175,7 @@ static inline long long arch_atomic64_dec_return(atomic64_t *v)
* *
* Atomically adds @i to @v. * Atomically adds @i to @v.
*/ */
static inline long long arch_atomic64_add(long long i, atomic64_t *v) static inline s64 arch_atomic64_add(s64 i, atomic64_t *v)
{ {
__alternative_atomic64(add, add_return, __alternative_atomic64(add, add_return,
ASM_OUTPUT2("+A" (i), "+c" (v)), ASM_OUTPUT2("+A" (i), "+c" (v)),
...@@ -191,7 +190,7 @@ static inline long long arch_atomic64_add(long long i, atomic64_t *v) ...@@ -191,7 +190,7 @@ static inline long long arch_atomic64_add(long long i, atomic64_t *v)
* *
* Atomically subtracts @i from @v. * Atomically subtracts @i from @v.
*/ */
static inline long long arch_atomic64_sub(long long i, atomic64_t *v) static inline s64 arch_atomic64_sub(s64 i, atomic64_t *v)
{ {
__alternative_atomic64(sub, sub_return, __alternative_atomic64(sub, sub_return,
ASM_OUTPUT2("+A" (i), "+c" (v)), ASM_OUTPUT2("+A" (i), "+c" (v)),
...@@ -234,8 +233,7 @@ static inline void arch_atomic64_dec(atomic64_t *v) ...@@ -234,8 +233,7 @@ static inline void arch_atomic64_dec(atomic64_t *v)
* Atomically adds @a to @v, so long as it was not @u. * Atomically adds @a to @v, so long as it was not @u.
* Returns non-zero if the add was done, zero otherwise. * Returns non-zero if the add was done, zero otherwise.
*/ */
static inline int arch_atomic64_add_unless(atomic64_t *v, long long a, static inline int arch_atomic64_add_unless(atomic64_t *v, s64 a, s64 u)
long long u)
{ {
unsigned low = (unsigned)u; unsigned low = (unsigned)u;
unsigned high = (unsigned)(u >> 32); unsigned high = (unsigned)(u >> 32);
...@@ -254,9 +252,9 @@ static inline int arch_atomic64_inc_not_zero(atomic64_t *v) ...@@ -254,9 +252,9 @@ static inline int arch_atomic64_inc_not_zero(atomic64_t *v)
} }
#define arch_atomic64_inc_not_zero arch_atomic64_inc_not_zero #define arch_atomic64_inc_not_zero arch_atomic64_inc_not_zero
static inline long long arch_atomic64_dec_if_positive(atomic64_t *v) static inline s64 arch_atomic64_dec_if_positive(atomic64_t *v)
{ {
long long r; s64 r;
alternative_atomic64(dec_if_positive, "=&A" (r), alternative_atomic64(dec_if_positive, "=&A" (r),
"S" (v) : "ecx", "memory"); "S" (v) : "ecx", "memory");
return r; return r;
...@@ -266,17 +264,17 @@ static inline long long arch_atomic64_dec_if_positive(atomic64_t *v) ...@@ -266,17 +264,17 @@ static inline long long arch_atomic64_dec_if_positive(atomic64_t *v)
#undef alternative_atomic64 #undef alternative_atomic64
#undef __alternative_atomic64 #undef __alternative_atomic64
static inline void arch_atomic64_and(long long i, atomic64_t *v) static inline void arch_atomic64_and(s64 i, atomic64_t *v)
{ {
long long old, c = 0; s64 old, c = 0;
while ((old = arch_atomic64_cmpxchg(v, c, c & i)) != c) while ((old = arch_atomic64_cmpxchg(v, c, c & i)) != c)
c = old; c = old;
} }
static inline long long arch_atomic64_fetch_and(long long i, atomic64_t *v) static inline s64 arch_atomic64_fetch_and(s64 i, atomic64_t *v)
{ {
long long old, c = 0; s64 old, c = 0;
while ((old = arch_atomic64_cmpxchg(v, c, c & i)) != c) while ((old = arch_atomic64_cmpxchg(v, c, c & i)) != c)
c = old; c = old;
...@@ -284,17 +282,17 @@ static inline long long arch_atomic64_fetch_and(long long i, atomic64_t *v) ...@@ -284,17 +282,17 @@ static inline long long arch_atomic64_fetch_and(long long i, atomic64_t *v)
return old; return old;
} }
static inline void arch_atomic64_or(long long i, atomic64_t *v) static inline void arch_atomic64_or(s64 i, atomic64_t *v)
{ {
long long old, c = 0; s64 old, c = 0;
while ((old = arch_atomic64_cmpxchg(v, c, c | i)) != c) while ((old = arch_atomic64_cmpxchg(v, c, c | i)) != c)
c = old; c = old;
} }
static inline long long arch_atomic64_fetch_or(long long i, atomic64_t *v) static inline s64 arch_atomic64_fetch_or(s64 i, atomic64_t *v)
{ {
long long old, c = 0; s64 old, c = 0;
while ((old = arch_atomic64_cmpxchg(v, c, c | i)) != c) while ((old = arch_atomic64_cmpxchg(v, c, c | i)) != c)
c = old; c = old;
...@@ -302,17 +300,17 @@ static inline long long arch_atomic64_fetch_or(long long i, atomic64_t *v) ...@@ -302,17 +300,17 @@ static inline long long arch_atomic64_fetch_or(long long i, atomic64_t *v)
return old; return old;
} }
static inline void arch_atomic64_xor(long long i, atomic64_t *v) static inline void arch_atomic64_xor(s64 i, atomic64_t *v)
{ {
long long old, c = 0; s64 old, c = 0;
while ((old = arch_atomic64_cmpxchg(v, c, c ^ i)) != c) while ((old = arch_atomic64_cmpxchg(v, c, c ^ i)) != c)
c = old; c = old;
} }
static inline long long arch_atomic64_fetch_xor(long long i, atomic64_t *v) static inline s64 arch_atomic64_fetch_xor(s64 i, atomic64_t *v)
{ {
long long old, c = 0; s64 old, c = 0;
while ((old = arch_atomic64_cmpxchg(v, c, c ^ i)) != c) while ((old = arch_atomic64_cmpxchg(v, c, c ^ i)) != c)
c = old; c = old;
...@@ -320,9 +318,9 @@ static inline long long arch_atomic64_fetch_xor(long long i, atomic64_t *v) ...@@ -320,9 +318,9 @@ static inline long long arch_atomic64_fetch_xor(long long i, atomic64_t *v)
return old; return old;
} }
static inline long long arch_atomic64_fetch_add(long long i, atomic64_t *v) static inline s64 arch_atomic64_fetch_add(s64 i, atomic64_t *v)
{ {
long long old, c = 0; s64 old, c = 0;
while ((old = arch_atomic64_cmpxchg(v, c, c + i)) != c) while ((old = arch_atomic64_cmpxchg(v, c, c + i)) != c)
c = old; c = old;
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* Atomically reads the value of @v. * Atomically reads the value of @v.
* Doesn't imply a read memory barrier. * Doesn't imply a read memory barrier.
*/ */
static inline long arch_atomic64_read(const atomic64_t *v) static inline s64 arch_atomic64_read(const atomic64_t *v)
{ {
return READ_ONCE((v)->counter); return READ_ONCE((v)->counter);
} }
...@@ -29,7 +29,7 @@ static inline long arch_atomic64_read(const atomic64_t *v) ...@@ -29,7 +29,7 @@ static inline long arch_atomic64_read(const atomic64_t *v)
* *
* Atomically sets the value of @v to @i. * Atomically sets the value of @v to @i.
*/ */
static inline void arch_atomic64_set(atomic64_t *v, long i) static inline void arch_atomic64_set(atomic64_t *v, s64 i)
{ {
WRITE_ONCE(v->counter, i); WRITE_ONCE(v->counter, i);
} }
...@@ -41,11 +41,11 @@ static inline void arch_atomic64_set(atomic64_t *v, long i) ...@@ -41,11 +41,11 @@ static inline void arch_atomic64_set(atomic64_t *v, long i)
* *
* Atomically adds @i to @v. * Atomically adds @i to @v.
*/ */
static __always_inline void arch_atomic64_add(long i, atomic64_t *v) static __always_inline void arch_atomic64_add(s64 i, atomic64_t *v)
{ {
asm volatile(LOCK_PREFIX "addq %1,%0" asm volatile(LOCK_PREFIX "addq %1,%0"
: "=m" (v->counter) : "=m" (v->counter)
: "er" (i), "m" (v->counter)); : "er" (i), "m" (v->counter) : "memory");
} }
/** /**
...@@ -55,11 +55,11 @@ static __always_inline void arch_atomic64_add(long i, atomic64_t *v) ...@@ -55,11 +55,11 @@ static __always_inline void arch_atomic64_add(long i, atomic64_t *v)
* *
* Atomically subtracts @i from @v. * Atomically subtracts @i from @v.
*/ */
static inline void arch_atomic64_sub(long i, atomic64_t *v) static inline void arch_atomic64_sub(s64 i, atomic64_t *v)
{ {
asm volatile(LOCK_PREFIX "subq %1,%0" asm volatile(LOCK_PREFIX "subq %1,%0"
: "=m" (v->counter) : "=m" (v->counter)
: "er" (i), "m" (v->counter)); : "er" (i), "m" (v->counter) : "memory");
} }
/** /**
...@@ -71,7 +71,7 @@ static inline void arch_atomic64_sub(long i, atomic64_t *v) ...@@ -71,7 +71,7 @@ static inline void arch_atomic64_sub(long i, atomic64_t *v)
* true if the result is zero, or false for all * true if the result is zero, or false for all
* other cases. * other cases.
*/ */
static inline bool arch_atomic64_sub_and_test(long i, atomic64_t *v) static inline bool arch_atomic64_sub_and_test(s64 i, atomic64_t *v)
{ {
return GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, e, "er", i); return GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, e, "er", i);
} }
...@@ -87,7 +87,7 @@ static __always_inline void arch_atomic64_inc(atomic64_t *v) ...@@ -87,7 +87,7 @@ static __always_inline void arch_atomic64_inc(atomic64_t *v)
{ {
asm volatile(LOCK_PREFIX "incq %0" asm volatile(LOCK_PREFIX "incq %0"
: "=m" (v->counter) : "=m" (v->counter)
: "m" (v->counter)); : "m" (v->counter) : "memory");
} }
#define arch_atomic64_inc arch_atomic64_inc #define arch_atomic64_inc arch_atomic64_inc
...@@ -101,7 +101,7 @@ static __always_inline void arch_atomic64_dec(atomic64_t *v) ...@@ -101,7 +101,7 @@ static __always_inline void arch_atomic64_dec(atomic64_t *v)
{ {
asm volatile(LOCK_PREFIX "decq %0" asm volatile(LOCK_PREFIX "decq %0"
: "=m" (v->counter) : "=m" (v->counter)
: "m" (v->counter)); : "m" (v->counter) : "memory");
} }
#define arch_atomic64_dec arch_atomic64_dec #define arch_atomic64_dec arch_atomic64_dec
...@@ -142,7 +142,7 @@ static inline bool arch_atomic64_inc_and_test(atomic64_t *v) ...@@ -142,7 +142,7 @@ static inline bool arch_atomic64_inc_and_test(atomic64_t *v)
* if the result is negative, or false when * if the result is negative, or false when
* result is greater than or equal to zero. * result is greater than or equal to zero.
*/ */
static inline bool arch_atomic64_add_negative(long i, atomic64_t *v) static inline bool arch_atomic64_add_negative(s64 i, atomic64_t *v)
{ {
return GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, s, "er", i); return GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, s, "er", i);
} }
...@@ -155,43 +155,43 @@ static inline bool arch_atomic64_add_negative(long i, atomic64_t *v) ...@@ -155,43 +155,43 @@ static inline bool arch_atomic64_add_negative(long i, atomic64_t *v)
* *
* Atomically adds @i to @v and returns @i + @v * Atomically adds @i to @v and returns @i + @v
*/ */
static __always_inline long arch_atomic64_add_return(long i, atomic64_t *v) static __always_inline s64 arch_atomic64_add_return(s64 i, atomic64_t *v)
{ {
return i + xadd(&v->counter, i); return i + xadd(&v->counter, i);
} }
static inline long arch_atomic64_sub_return(long i, atomic64_t *v) static inline s64 arch_atomic64_sub_return(s64 i, atomic64_t *v)
{ {
return arch_atomic64_add_return(-i, v); return arch_atomic64_add_return(-i, v);
} }
static inline long arch_atomic64_fetch_add(long i, atomic64_t *v) static inline s64 arch_atomic64_fetch_add(s64 i, atomic64_t *v)
{ {
return xadd(&v->counter, i); return xadd(&v->counter, i);
} }
static inline long arch_atomic64_fetch_sub(long i, atomic64_t *v) static inline s64 arch_atomic64_fetch_sub(s64 i, atomic64_t *v)
{ {
return xadd(&v->counter, -i); return xadd(&v->counter, -i);
} }
static inline long arch_atomic64_cmpxchg(atomic64_t *v, long old, long new) static inline s64 arch_atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
{ {
return arch_cmpxchg(&v->counter, old, new); return arch_cmpxchg(&v->counter, old, new);
} }
#define arch_atomic64_try_cmpxchg arch_atomic64_try_cmpxchg #define arch_atomic64_try_cmpxchg arch_atomic64_try_cmpxchg
static __always_inline bool arch_atomic64_try_cmpxchg(atomic64_t *v, s64 *old, long new) static __always_inline bool arch_atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
{ {
return try_cmpxchg(&v->counter, old, new); return try_cmpxchg(&v->counter, old, new);
} }
static inline long arch_atomic64_xchg(atomic64_t *v, long new) static inline s64 arch_atomic64_xchg(atomic64_t *v, s64 new)
{ {
return arch_xchg(&v->counter, new); return arch_xchg(&v->counter, new);
} }
static inline void arch_atomic64_and(long i, atomic64_t *v) static inline void arch_atomic64_and(s64 i, atomic64_t *v)
{ {
asm volatile(LOCK_PREFIX "andq %1,%0" asm volatile(LOCK_PREFIX "andq %1,%0"
: "+m" (v->counter) : "+m" (v->counter)
...@@ -199,7 +199,7 @@ static inline void arch_atomic64_and(long i, atomic64_t *v) ...@@ -199,7 +199,7 @@ static inline void arch_atomic64_and(long i, atomic64_t *v)
: "memory"); : "memory");
} }
static inline long arch_atomic64_fetch_and(long i, atomic64_t *v) static inline s64 arch_atomic64_fetch_and(s64 i, atomic64_t *v)
{ {
s64 val = arch_atomic64_read(v); s64 val = arch_atomic64_read(v);
...@@ -208,7 +208,7 @@ static inline long arch_atomic64_fetch_and(long i, atomic64_t *v) ...@@ -208,7 +208,7 @@ static inline long arch_atomic64_fetch_and(long i, atomic64_t *v)
return val; return val;
} }
static inline void arch_atomic64_or(long i, atomic64_t *v) static inline void arch_atomic64_or(s64 i, atomic64_t *v)
{ {
asm volatile(LOCK_PREFIX "orq %1,%0" asm volatile(LOCK_PREFIX "orq %1,%0"
: "+m" (v->counter) : "+m" (v->counter)
...@@ -216,7 +216,7 @@ static inline void arch_atomic64_or(long i, atomic64_t *v) ...@@ -216,7 +216,7 @@ static inline void arch_atomic64_or(long i, atomic64_t *v)
: "memory"); : "memory");
} }
static inline long arch_atomic64_fetch_or(long i, atomic64_t *v) static inline s64 arch_atomic64_fetch_or(s64 i, atomic64_t *v)
{ {
s64 val = arch_atomic64_read(v); s64 val = arch_atomic64_read(v);
...@@ -225,7 +225,7 @@ static inline long arch_atomic64_fetch_or(long i, atomic64_t *v) ...@@ -225,7 +225,7 @@ static inline long arch_atomic64_fetch_or(long i, atomic64_t *v)
return val; return val;
} }
static inline void arch_atomic64_xor(long i, atomic64_t *v) static inline void arch_atomic64_xor(s64 i, atomic64_t *v)
{ {
asm volatile(LOCK_PREFIX "xorq %1,%0" asm volatile(LOCK_PREFIX "xorq %1,%0"
: "+m" (v->counter) : "+m" (v->counter)
...@@ -233,7 +233,7 @@ static inline void arch_atomic64_xor(long i, atomic64_t *v) ...@@ -233,7 +233,7 @@ static inline void arch_atomic64_xor(long i, atomic64_t *v)
: "memory"); : "memory");
} }
static inline long arch_atomic64_fetch_xor(long i, atomic64_t *v) static inline s64 arch_atomic64_fetch_xor(s64 i, atomic64_t *v)
{ {
s64 val = arch_atomic64_read(v); s64 val = arch_atomic64_read(v);
......
...@@ -80,8 +80,8 @@ do { \ ...@@ -80,8 +80,8 @@ do { \
}) })
/* Atomic operations are already serializing on x86 */ /* Atomic operations are already serializing on x86 */
#define __smp_mb__before_atomic() barrier() #define __smp_mb__before_atomic() do { } while (0)
#define __smp_mb__after_atomic() barrier() #define __smp_mb__after_atomic() do { } while (0)
#include <asm-generic/barrier.h> #include <asm-generic/barrier.h>
......
...@@ -16,7 +16,7 @@ DECLARE_PER_CPU(struct pt_regs *, irq_regs); ...@@ -16,7 +16,7 @@ DECLARE_PER_CPU(struct pt_regs *, irq_regs);
static inline struct pt_regs *get_irq_regs(void) static inline struct pt_regs *get_irq_regs(void)
{ {
return this_cpu_read(irq_regs); return __this_cpu_read(irq_regs);
} }
static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs) static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
...@@ -24,7 +24,7 @@ static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs) ...@@ -24,7 +24,7 @@ static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
struct pt_regs *old_regs; struct pt_regs *old_regs;
old_regs = get_irq_regs(); old_regs = get_irq_regs();
this_cpu_write(irq_regs, new_regs); __this_cpu_write(irq_regs, new_regs);
return old_regs; return old_regs;
} }
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#ifndef _ASM_X86_JUMP_LABEL_H #ifndef _ASM_X86_JUMP_LABEL_H
#define _ASM_X86_JUMP_LABEL_H #define _ASM_X86_JUMP_LABEL_H
#define HAVE_JUMP_LABEL_BATCH
#define JUMP_LABEL_NOP_SIZE 5 #define JUMP_LABEL_NOP_SIZE 5
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
......
This diff is collapsed.
...@@ -162,7 +162,8 @@ __visible void smp_call_function_single_interrupt(struct pt_regs *r); ...@@ -162,7 +162,8 @@ __visible void smp_call_function_single_interrupt(struct pt_regs *r);
* from the initial startup. We map APIC_BASE very early in page_setup(), * from the initial startup. We map APIC_BASE very early in page_setup(),
* so this is correct in the x86 case. * so this is correct in the x86 case.
*/ */
#define raw_smp_processor_id() (this_cpu_read(cpu_number)) #define raw_smp_processor_id() this_cpu_read(cpu_number)
#define __smp_processor_id() __this_cpu_read(cpu_number)
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
extern int safe_smp_processor_id(void); extern int safe_smp_processor_id(void);
......
...@@ -18,6 +18,20 @@ static inline void apply_paravirt(struct paravirt_patch_site *start, ...@@ -18,6 +18,20 @@ static inline void apply_paravirt(struct paravirt_patch_site *start,
#define __parainstructions_end NULL #define __parainstructions_end NULL
#endif #endif
/*
* Currently, the max observed size in the kernel code is
* JUMP_LABEL_NOP_SIZE/RELATIVEJUMP_SIZE, which are 5.
* Raise it if needed.
*/
#define POKE_MAX_OPCODE_SIZE 5
struct text_poke_loc {
void *detour;
void *addr;
size_t len;
const char opcode[POKE_MAX_OPCODE_SIZE];
};
extern void text_poke_early(void *addr, const void *opcode, size_t len); extern void text_poke_early(void *addr, const void *opcode, size_t len);
/* /*
...@@ -38,6 +52,7 @@ extern void *text_poke(void *addr, const void *opcode, size_t len); ...@@ -38,6 +52,7 @@ extern void *text_poke(void *addr, const void *opcode, size_t len);
extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len); extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len);
extern int poke_int3_handler(struct pt_regs *regs); extern int poke_int3_handler(struct pt_regs *regs);
extern void text_poke_bp(void *addr, const void *opcode, size_t len, void *handler); extern void text_poke_bp(void *addr, const void *opcode, size_t len, void *handler);
extern void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries);
extern int after_bootmem; extern int after_bootmem;
extern __ro_after_init struct mm_struct *poking_mm; extern __ro_after_init struct mm_struct *poking_mm;
extern __ro_after_init unsigned long poking_addr; extern __ro_after_init unsigned long poking_addr;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/mmu_context.h> #include <linux/mmu_context.h>
#include <linux/bsearch.h>
#include <asm/text-patching.h> #include <asm/text-patching.h>
#include <asm/alternative.h> #include <asm/alternative.h>
#include <asm/sections.h> #include <asm/sections.h>
...@@ -848,81 +849,133 @@ static void do_sync_core(void *info) ...@@ -848,81 +849,133 @@ static void do_sync_core(void *info)
sync_core(); sync_core();
} }
static bool bp_patching_in_progress; static struct bp_patching_desc {
static void *bp_int3_handler, *bp_int3_addr; struct text_poke_loc *vec;
int nr_entries;
} bp_patching;
static int patch_cmp(const void *key, const void *elt)
{
struct text_poke_loc *tp = (struct text_poke_loc *) elt;
if (key < tp->addr)
return -1;
if (key > tp->addr)
return 1;
return 0;
}
NOKPROBE_SYMBOL(patch_cmp);
int poke_int3_handler(struct pt_regs *regs) int poke_int3_handler(struct pt_regs *regs)
{ {
struct text_poke_loc *tp;
unsigned char int3 = 0xcc;
void *ip;
/* /*
* Having observed our INT3 instruction, we now must observe * Having observed our INT3 instruction, we now must observe
* bp_patching_in_progress. * bp_patching.nr_entries.
* *
* in_progress = TRUE INT3 * nr_entries != 0 INT3
* WMB RMB * WMB RMB
* write INT3 if (in_progress) * write INT3 if (nr_entries)
* *
* Idem for bp_int3_handler. * Idem for other elements in bp_patching.
*/ */
smp_rmb(); smp_rmb();
if (likely(!bp_patching_in_progress)) if (likely(!bp_patching.nr_entries))
return 0; return 0;
if (user_mode(regs) || regs->ip != (unsigned long)bp_int3_addr) if (user_mode(regs))
return 0; return 0;
/* set up the specified breakpoint handler */ /*
regs->ip = (unsigned long) bp_int3_handler; * Discount the sizeof(int3). See text_poke_bp_batch().
*/
ip = (void *) regs->ip - sizeof(int3);
/*
* Skip the binary search if there is a single member in the vector.
*/
if (unlikely(bp_patching.nr_entries > 1)) {
tp = bsearch(ip, bp_patching.vec, bp_patching.nr_entries,
sizeof(struct text_poke_loc),
patch_cmp);
if (!tp)
return 0;
} else {
tp = bp_patching.vec;
if (tp->addr != ip)
return 0;
}
/* set up the specified breakpoint detour */
regs->ip = (unsigned long) tp->detour;
return 1; return 1;
} }
NOKPROBE_SYMBOL(poke_int3_handler); NOKPROBE_SYMBOL(poke_int3_handler);
/** /**
* text_poke_bp() -- update instructions on live kernel on SMP * text_poke_bp_batch() -- update instructions on live kernel on SMP
* @addr: address to patch * @tp: vector of instructions to patch
* @opcode: opcode of new instruction * @nr_entries: number of entries in the vector
* @len: length to copy
* @handler: address to jump to when the temporary breakpoint is hit
* *
* Modify multi-byte instruction by using int3 breakpoint on SMP. * Modify multi-byte instruction by using int3 breakpoint on SMP.
* We completely avoid stop_machine() here, and achieve the * We completely avoid stop_machine() here, and achieve the
* synchronization using int3 breakpoint. * synchronization using int3 breakpoint.
* *
* The way it is done: * The way it is done:
* - add a int3 trap to the address that will be patched * - For each entry in the vector:
* - add a int3 trap to the address that will be patched
* - sync cores * - sync cores
* - update all but the first byte of the patched range * - For each entry in the vector:
* - update all but the first byte of the patched range
* - sync cores * - sync cores
* - replace the first byte (int3) by the first byte of * - For each entry in the vector:
* replacing opcode * - replace the first byte (int3) by the first byte of
* replacing opcode
* - sync cores * - sync cores
*/ */
void text_poke_bp(void *addr, const void *opcode, size_t len, void *handler) void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries)
{ {
int patched_all_but_first = 0;
unsigned char int3 = 0xcc; unsigned char int3 = 0xcc;
unsigned int i;
bp_int3_handler = handler;
bp_int3_addr = (u8 *)addr + sizeof(int3);
bp_patching_in_progress = true;
lockdep_assert_held(&text_mutex); lockdep_assert_held(&text_mutex);
bp_patching.vec = tp;
bp_patching.nr_entries = nr_entries;
/* /*
* Corresponding read barrier in int3 notifier for making sure the * Corresponding read barrier in int3 notifier for making sure the
* in_progress and handler are correctly ordered wrt. patching. * nr_entries and handler are correctly ordered wrt. patching.
*/ */
smp_wmb(); smp_wmb();
text_poke(addr, &int3, sizeof(int3)); /*
* First step: add a int3 trap to the address that will be patched.
*/
for (i = 0; i < nr_entries; i++)
text_poke(tp[i].addr, &int3, sizeof(int3));
on_each_cpu(do_sync_core, NULL, 1); on_each_cpu(do_sync_core, NULL, 1);
if (len - sizeof(int3) > 0) { /*
/* patch all but the first byte */ * Second step: update all but the first byte of the patched range.
text_poke((char *)addr + sizeof(int3), */
(const char *) opcode + sizeof(int3), for (i = 0; i < nr_entries; i++) {
len - sizeof(int3)); if (tp[i].len - sizeof(int3) > 0) {
text_poke((char *)tp[i].addr + sizeof(int3),
(const char *)tp[i].opcode + sizeof(int3),
tp[i].len - sizeof(int3));
patched_all_but_first++;
}
}
if (patched_all_but_first) {
/* /*
* According to Intel, this core syncing is very likely * According to Intel, this core syncing is very likely
* not necessary and we'd be safe even without it. But * not necessary and we'd be safe even without it. But
...@@ -931,14 +984,47 @@ void text_poke_bp(void *addr, const void *opcode, size_t len, void *handler) ...@@ -931,14 +984,47 @@ void text_poke_bp(void *addr, const void *opcode, size_t len, void *handler)
on_each_cpu(do_sync_core, NULL, 1); on_each_cpu(do_sync_core, NULL, 1);
} }
/* patch the first byte */ /*
text_poke(addr, opcode, sizeof(int3)); * Third step: replace the first byte (int3) by the first byte of
* replacing opcode.
*/
for (i = 0; i < nr_entries; i++)
text_poke(tp[i].addr, tp[i].opcode, sizeof(int3));
on_each_cpu(do_sync_core, NULL, 1); on_each_cpu(do_sync_core, NULL, 1);
/* /*
* sync_core() implies an smp_mb() and orders this store against * sync_core() implies an smp_mb() and orders this store against
* the writing of the new instruction. * the writing of the new instruction.
*/ */
bp_patching_in_progress = false; bp_patching.vec = NULL;
bp_patching.nr_entries = 0;
} }
/**
* text_poke_bp() -- update instructions on live kernel on SMP
* @addr: address to patch
* @opcode: opcode of new instruction
* @len: length to copy
* @handler: address to jump to when the temporary breakpoint is hit
*
* Update a single instruction with the vector in the stack, avoiding
* dynamically allocated memory. This function should be used when it is
* not possible to allocate memory.
*/
void text_poke_bp(void *addr, const void *opcode, size_t len, void *handler)
{
struct text_poke_loc tp = {
.detour = handler,
.addr = addr,
.len = len,
};
if (len > POKE_MAX_OPCODE_SIZE) {
WARN_ONCE(1, "len is larger than %d\n", POKE_MAX_OPCODE_SIZE);
return;
}
memcpy((void *)tp.opcode, opcode, len);
text_poke_bp_batch(&tp, 1);
}
...@@ -35,41 +35,43 @@ static void bug_at(unsigned char *ip, int line) ...@@ -35,41 +35,43 @@ static void bug_at(unsigned char *ip, int line)
BUG(); BUG();
} }
static void __ref __jump_label_transform(struct jump_entry *entry, static void __jump_label_set_jump_code(struct jump_entry *entry,
enum jump_label_type type, enum jump_label_type type,
int init) union jump_code_union *code,
int init)
{ {
union jump_code_union jmp;
const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP }; const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5]; const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
const void *expect, *code; const void *expect;
int line; int line;
jmp.jump = 0xe9; code->jump = 0xe9;
jmp.offset = jump_entry_target(entry) - code->offset = jump_entry_target(entry) -
(jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE); (jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE);
if (type == JUMP_LABEL_JMP) { if (init) {
if (init) { expect = default_nop; line = __LINE__;
expect = default_nop; line = __LINE__; } else if (type == JUMP_LABEL_JMP) {
} else { expect = ideal_nop; line = __LINE__;
expect = ideal_nop; line = __LINE__;
}
code = &jmp.code;
} else { } else {
if (init) { expect = code->code; line = __LINE__;
expect = default_nop; line = __LINE__;
} else {
expect = &jmp.code; line = __LINE__;
}
code = ideal_nop;
} }
if (memcmp((void *)jump_entry_code(entry), expect, JUMP_LABEL_NOP_SIZE)) if (memcmp((void *)jump_entry_code(entry), expect, JUMP_LABEL_NOP_SIZE))
bug_at((void *)jump_entry_code(entry), line); bug_at((void *)jump_entry_code(entry), line);
if (type == JUMP_LABEL_NOP)
memcpy(code, ideal_nop, JUMP_LABEL_NOP_SIZE);
}
static void __ref __jump_label_transform(struct jump_entry *entry,
enum jump_label_type type,
int init)
{
union jump_code_union code;
__jump_label_set_jump_code(entry, type, &code, init);
/* /*
* As long as only a single processor is running and the code is still * As long as only a single processor is running and the code is still
* not marked as RO, text_poke_early() can be used; Checking that * not marked as RO, text_poke_early() can be used; Checking that
...@@ -82,12 +84,12 @@ static void __ref __jump_label_transform(struct jump_entry *entry, ...@@ -82,12 +84,12 @@ static void __ref __jump_label_transform(struct jump_entry *entry,
* always nop being the 'currently valid' instruction * always nop being the 'currently valid' instruction
*/ */
if (init || system_state == SYSTEM_BOOTING) { if (init || system_state == SYSTEM_BOOTING) {
text_poke_early((void *)jump_entry_code(entry), code, text_poke_early((void *)jump_entry_code(entry), &code,
JUMP_LABEL_NOP_SIZE); JUMP_LABEL_NOP_SIZE);
return; return;
} }
text_poke_bp((void *)jump_entry_code(entry), code, JUMP_LABEL_NOP_SIZE, text_poke_bp((void *)jump_entry_code(entry), &code, JUMP_LABEL_NOP_SIZE,
(void *)jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE); (void *)jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE);
} }
...@@ -99,6 +101,75 @@ void arch_jump_label_transform(struct jump_entry *entry, ...@@ -99,6 +101,75 @@ void arch_jump_label_transform(struct jump_entry *entry,
mutex_unlock(&text_mutex); mutex_unlock(&text_mutex);
} }
#define TP_VEC_MAX (PAGE_SIZE / sizeof(struct text_poke_loc))
static struct text_poke_loc tp_vec[TP_VEC_MAX];
static int tp_vec_nr;
bool arch_jump_label_transform_queue(struct jump_entry *entry,
enum jump_label_type type)
{
struct text_poke_loc *tp;
void *entry_code;
if (system_state == SYSTEM_BOOTING) {
/*
* Fallback to the non-batching mode.
*/
arch_jump_label_transform(entry, type);
return true;
}
/*
* No more space in the vector, tell upper layer to apply
* the queue before continuing.
*/
if (tp_vec_nr == TP_VEC_MAX)
return false;
tp = &tp_vec[tp_vec_nr];
entry_code = (void *)jump_entry_code(entry);
/*
* The INT3 handler will do a bsearch in the queue, so we need entries
* to be sorted. We can survive an unsorted list by rejecting the entry,
* forcing the generic jump_label code to apply the queue. Warning once,
* to raise the attention to the case of an unsorted entry that is
* better not happen, because, in the worst case we will perform in the
* same way as we do without batching - with some more overhead.
*/
if (tp_vec_nr > 0) {
int prev = tp_vec_nr - 1;
struct text_poke_loc *prev_tp = &tp_vec[prev];
if (WARN_ON_ONCE(prev_tp->addr > entry_code))
return false;
}
__jump_label_set_jump_code(entry, type,
(union jump_code_union *) &tp->opcode, 0);
tp->addr = entry_code;
tp->detour = entry_code + JUMP_LABEL_NOP_SIZE;
tp->len = JUMP_LABEL_NOP_SIZE;
tp_vec_nr++;
return true;
}
void arch_jump_label_transform_apply(void)
{
if (!tp_vec_nr)
return;
mutex_lock(&text_mutex);
text_poke_bp_batch(tp_vec, tp_vec_nr);
mutex_unlock(&text_mutex);
tp_vec_nr = 0;
}
static enum { static enum {
JL_STATE_START, JL_STATE_START,
JL_STATE_NO_UPDATE, JL_STATE_NO_UPDATE,
......
...@@ -856,7 +856,7 @@ static ssize_t nx842_##_name##_show(struct device *dev, \ ...@@ -856,7 +856,7 @@ static ssize_t nx842_##_name##_show(struct device *dev, \
rcu_read_lock(); \ rcu_read_lock(); \
local_devdata = rcu_dereference(devdata); \ local_devdata = rcu_dereference(devdata); \
if (local_devdata) \ if (local_devdata) \
p = snprintf(buf, PAGE_SIZE, "%ld\n", \ p = snprintf(buf, PAGE_SIZE, "%lld\n", \
atomic64_read(&local_devdata->counters->_name)); \ atomic64_read(&local_devdata->counters->_name)); \
rcu_read_unlock(); \ rcu_read_unlock(); \
return p; \ return p; \
...@@ -909,7 +909,7 @@ static ssize_t nx842_timehist_show(struct device *dev, ...@@ -909,7 +909,7 @@ static ssize_t nx842_timehist_show(struct device *dev,
} }
for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) { for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) {
bytes = snprintf(p, bytes_remain, "%u-%uus:\t%ld\n", bytes = snprintf(p, bytes_remain, "%u-%uus:\t%lld\n",
i ? (2<<(i-1)) : 0, (2<<i)-1, i ? (2<<(i-1)) : 0, (2<<i)-1,
atomic64_read(&times[i])); atomic64_read(&times[i]));
bytes_remain -= bytes; bytes_remain -= bytes;
...@@ -917,7 +917,7 @@ static ssize_t nx842_timehist_show(struct device *dev, ...@@ -917,7 +917,7 @@ static ssize_t nx842_timehist_show(struct device *dev,
} }
/* The last bucket holds everything over /* The last bucket holds everything over
* 2<<(NX842_HIST_SLOTS - 2) us */ * 2<<(NX842_HIST_SLOTS - 2) us */
bytes = snprintf(p, bytes_remain, "%uus - :\t%ld\n", bytes = snprintf(p, bytes_remain, "%uus - :\t%lld\n",
2<<(NX842_HIST_SLOTS - 2), 2<<(NX842_HIST_SLOTS - 2),
atomic64_read(&times[(NX842_HIST_SLOTS - 1)])); atomic64_read(&times[(NX842_HIST_SLOTS - 1)]));
p += bytes; p += bytes;
......
...@@ -457,7 +457,7 @@ static int alloc_name(struct ib_device *ibdev, const char *name) ...@@ -457,7 +457,7 @@ static int alloc_name(struct ib_device *ibdev, const char *name)
int rc; int rc;
int i; int i;
lockdep_assert_held_exclusive(&devices_rwsem); lockdep_assert_held_write(&devices_rwsem);
ida_init(&inuse); ida_init(&inuse);
xa_for_each (&devices, index, device) { xa_for_each (&devices, index, device) {
char buf[IB_DEVICE_NAME_MAX]; char buf[IB_DEVICE_NAME_MAX];
......
...@@ -487,7 +487,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) ...@@ -487,7 +487,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
{ {
lockdep_assert_held_exclusive(&tty->ldisc_sem); lockdep_assert_held_write(&tty->ldisc_sem);
WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags)); WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
clear_bit(TTY_LDISC_OPEN, &tty->flags); clear_bit(TTY_LDISC_OPEN, &tty->flags);
if (ld->ops->close) if (ld->ops->close)
...@@ -509,7 +509,7 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld) ...@@ -509,7 +509,7 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld)
struct tty_ldisc *disc = tty_ldisc_get(tty, ld); struct tty_ldisc *disc = tty_ldisc_get(tty, ld);
int r; int r;
lockdep_assert_held_exclusive(&tty->ldisc_sem); lockdep_assert_held_write(&tty->ldisc_sem);
if (IS_ERR(disc)) if (IS_ERR(disc))
return PTR_ERR(disc); return PTR_ERR(disc);
tty->ldisc = disc; tty->ldisc = disc;
...@@ -633,7 +633,7 @@ EXPORT_SYMBOL_GPL(tty_set_ldisc); ...@@ -633,7 +633,7 @@ EXPORT_SYMBOL_GPL(tty_set_ldisc);
*/ */
static void tty_ldisc_kill(struct tty_struct *tty) static void tty_ldisc_kill(struct tty_struct *tty)
{ {
lockdep_assert_held_exclusive(&tty->ldisc_sem); lockdep_assert_held_write(&tty->ldisc_sem);
if (!tty->ldisc) if (!tty->ldisc)
return; return;
/* /*
...@@ -681,7 +681,7 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc) ...@@ -681,7 +681,7 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc)
struct tty_ldisc *ld; struct tty_ldisc *ld;
int retval; int retval;
lockdep_assert_held_exclusive(&tty->ldisc_sem); lockdep_assert_held_write(&tty->ldisc_sem);
ld = tty_ldisc_get(tty, disc); ld = tty_ldisc_get(tty, disc);
if (IS_ERR(ld)) { if (IS_ERR(ld)) {
BUG_ON(disc == N_TTY); BUG_ON(disc == N_TTY);
......
...@@ -1187,7 +1187,7 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, ...@@ -1187,7 +1187,7 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
unsigned flags = 0; unsigned flags = 0;
if (iov_iter_rw(iter) == WRITE) { if (iov_iter_rw(iter) == WRITE) {
lockdep_assert_held_exclusive(&inode->i_rwsem); lockdep_assert_held_write(&inode->i_rwsem);
flags |= IOMAP_WRITE; flags |= IOMAP_WRITE;
} else { } else {
lockdep_assert_held(&inode->i_rwsem); lockdep_assert_held(&inode->i_rwsem);
......
...@@ -10,24 +10,24 @@ ...@@ -10,24 +10,24 @@
#include <linux/types.h> #include <linux/types.h>
typedef struct { typedef struct {
long long counter; s64 counter;
} atomic64_t; } atomic64_t;
#define ATOMIC64_INIT(i) { (i) } #define ATOMIC64_INIT(i) { (i) }
extern long long atomic64_read(const atomic64_t *v); extern s64 atomic64_read(const atomic64_t *v);
extern void atomic64_set(atomic64_t *v, long long i); extern void atomic64_set(atomic64_t *v, s64 i);
#define atomic64_set_release(v, i) atomic64_set((v), (i)) #define atomic64_set_release(v, i) atomic64_set((v), (i))
#define ATOMIC64_OP(op) \ #define ATOMIC64_OP(op) \
extern void atomic64_##op(long long a, atomic64_t *v); extern void atomic64_##op(s64 a, atomic64_t *v);
#define ATOMIC64_OP_RETURN(op) \ #define ATOMIC64_OP_RETURN(op) \
extern long long atomic64_##op##_return(long long a, atomic64_t *v); extern s64 atomic64_##op##_return(s64 a, atomic64_t *v);
#define ATOMIC64_FETCH_OP(op) \ #define ATOMIC64_FETCH_OP(op) \
extern long long atomic64_fetch_##op(long long a, atomic64_t *v); extern s64 atomic64_fetch_##op(s64 a, atomic64_t *v);
#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) ATOMIC64_FETCH_OP(op) #define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) ATOMIC64_FETCH_OP(op)
...@@ -46,11 +46,11 @@ ATOMIC64_OPS(xor) ...@@ -46,11 +46,11 @@ ATOMIC64_OPS(xor)
#undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP_RETURN
#undef ATOMIC64_OP #undef ATOMIC64_OP
extern long long atomic64_dec_if_positive(atomic64_t *v); extern s64 atomic64_dec_if_positive(atomic64_t *v);
#define atomic64_dec_if_positive atomic64_dec_if_positive #define atomic64_dec_if_positive atomic64_dec_if_positive
extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n); extern s64 atomic64_cmpxchg(atomic64_t *v, s64 o, s64 n);
extern long long atomic64_xchg(atomic64_t *v, long long new); extern s64 atomic64_xchg(atomic64_t *v, s64 new);
extern long long atomic64_fetch_add_unless(atomic64_t *v, long long a, long long u); extern s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u);
#define atomic64_fetch_add_unless atomic64_fetch_add_unless #define atomic64_fetch_add_unless atomic64_fetch_add_unless
#endif /* _ASM_GENERIC_ATOMIC64_H */ #endif /* _ASM_GENERIC_ATOMIC64_H */
...@@ -215,6 +215,9 @@ extern void arch_jump_label_transform(struct jump_entry *entry, ...@@ -215,6 +215,9 @@ extern void arch_jump_label_transform(struct jump_entry *entry,
enum jump_label_type type); enum jump_label_type type);
extern void arch_jump_label_transform_static(struct jump_entry *entry, extern void arch_jump_label_transform_static(struct jump_entry *entry,
enum jump_label_type type); enum jump_label_type type);
extern bool arch_jump_label_transform_queue(struct jump_entry *entry,
enum jump_label_type type);
extern void arch_jump_label_transform_apply(void);
extern int jump_label_text_reserved(void *start, void *end); extern int jump_label_text_reserved(void *start, void *end);
extern void static_key_slow_inc(struct static_key *key); extern void static_key_slow_inc(struct static_key *key);
extern void static_key_slow_dec(struct static_key *key); extern void static_key_slow_dec(struct static_key *key);
......
...@@ -203,11 +203,17 @@ struct lock_list { ...@@ -203,11 +203,17 @@ struct lock_list {
struct lock_list *parent; struct lock_list *parent;
}; };
/* /**
* We record lock dependency chains, so that we can cache them: * struct lock_chain - lock dependency chain record
*
* @irq_context: the same as irq_context in held_lock below
* @depth: the number of held locks in this chain
* @base: the index in chain_hlocks for this chain
* @entry: the collided lock chains in lock_chain hash list
* @chain_key: the hash key of this lock_chain
*/ */
struct lock_chain { struct lock_chain {
/* see BUILD_BUG_ON()s in lookup_chain_cache() */ /* see BUILD_BUG_ON()s in add_chain_cache() */
unsigned int irq_context : 2, unsigned int irq_context : 2,
depth : 6, depth : 6,
base : 24; base : 24;
...@@ -217,12 +223,8 @@ struct lock_chain { ...@@ -217,12 +223,8 @@ struct lock_chain {
}; };
#define MAX_LOCKDEP_KEYS_BITS 13 #define MAX_LOCKDEP_KEYS_BITS 13
/* #define MAX_LOCKDEP_KEYS (1UL << MAX_LOCKDEP_KEYS_BITS)
* Subtract one because we offset hlock->class_idx by 1 in order #define INITIAL_CHAIN_KEY -1
* to make 0 mean no class. This avoids overflowing the class_idx
* bitfield and hitting the BUG in hlock_class().
*/
#define MAX_LOCKDEP_KEYS ((1UL << MAX_LOCKDEP_KEYS_BITS) - 1)
struct held_lock { struct held_lock {
/* /*
...@@ -247,6 +249,11 @@ struct held_lock { ...@@ -247,6 +249,11 @@ struct held_lock {
u64 waittime_stamp; u64 waittime_stamp;
u64 holdtime_stamp; u64 holdtime_stamp;
#endif #endif
/*
* class_idx is zero-indexed; it points to the element in
* lock_classes this held lock instance belongs to. class_idx is in
* the range from 0 to (MAX_LOCKDEP_KEYS-1) inclusive.
*/
unsigned int class_idx:MAX_LOCKDEP_KEYS_BITS; unsigned int class_idx:MAX_LOCKDEP_KEYS_BITS;
/* /*
* The lock-stack is unified in that the lock chains of interrupt * The lock-stack is unified in that the lock chains of interrupt
...@@ -281,6 +288,8 @@ extern void lockdep_free_key_range(void *start, unsigned long size); ...@@ -281,6 +288,8 @@ extern void lockdep_free_key_range(void *start, unsigned long size);
extern asmlinkage void lockdep_sys_exit(void); extern asmlinkage void lockdep_sys_exit(void);
extern void lockdep_set_selftest_task(struct task_struct *task); extern void lockdep_set_selftest_task(struct task_struct *task);
extern void lockdep_init_task(struct task_struct *task);
extern void lockdep_off(void); extern void lockdep_off(void);
extern void lockdep_on(void); extern void lockdep_on(void);
...@@ -385,7 +394,7 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie); ...@@ -385,7 +394,7 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);
WARN_ON(debug_locks && !lockdep_is_held(l)); \ WARN_ON(debug_locks && !lockdep_is_held(l)); \
} while (0) } while (0)
#define lockdep_assert_held_exclusive(l) do { \ #define lockdep_assert_held_write(l) do { \
WARN_ON(debug_locks && !lockdep_is_held_type(l, 0)); \ WARN_ON(debug_locks && !lockdep_is_held_type(l, 0)); \
} while (0) } while (0)
...@@ -405,6 +414,10 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie); ...@@ -405,6 +414,10 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);
#else /* !CONFIG_LOCKDEP */ #else /* !CONFIG_LOCKDEP */
static inline void lockdep_init_task(struct task_struct *task)
{
}
static inline void lockdep_off(void) static inline void lockdep_off(void)
{ {
} }
...@@ -466,7 +479,7 @@ struct lockdep_map { }; ...@@ -466,7 +479,7 @@ struct lockdep_map { };
#define lockdep_is_held_type(l, r) (1) #define lockdep_is_held_type(l, r) (1)
#define lockdep_assert_held(l) do { (void)(l); } while (0) #define lockdep_assert_held(l) do { (void)(l); } while (0)
#define lockdep_assert_held_exclusive(l) do { (void)(l); } while (0) #define lockdep_assert_held_write(l) do { (void)(l); } while (0)
#define lockdep_assert_held_read(l) do { (void)(l); } while (0) #define lockdep_assert_held_read(l) do { (void)(l); } while (0)
#define lockdep_assert_held_once(l) do { (void)(l); } while (0) #define lockdep_assert_held_once(l) do { (void)(l); } while (0)
...@@ -497,7 +510,6 @@ enum xhlock_context_t { ...@@ -497,7 +510,6 @@ enum xhlock_context_t {
{ .name = (_name), .key = (void *)(_key), } { .name = (_name), .key = (void *)(_key), }
static inline void lockdep_invariant_state(bool force) {} static inline void lockdep_invariant_state(bool force) {}
static inline void lockdep_init_task(struct task_struct *task) {}
static inline void lockdep_free_task(struct task_struct *task) {} static inline void lockdep_free_task(struct task_struct *task) {}
#ifdef CONFIG_LOCK_STAT #ifdef CONFIG_LOCK_STAT
......
...@@ -121,7 +121,7 @@ static inline void percpu_rwsem_release(struct percpu_rw_semaphore *sem, ...@@ -121,7 +121,7 @@ static inline void percpu_rwsem_release(struct percpu_rw_semaphore *sem,
lock_release(&sem->rw_sem.dep_map, 1, ip); lock_release(&sem->rw_sem.dep_map, 1, ip);
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
if (!read) if (!read)
sem->rw_sem.owner = RWSEM_OWNER_UNKNOWN; atomic_long_set(&sem->rw_sem.owner, RWSEM_OWNER_UNKNOWN);
#endif #endif
} }
...@@ -131,7 +131,7 @@ static inline void percpu_rwsem_acquire(struct percpu_rw_semaphore *sem, ...@@ -131,7 +131,7 @@ static inline void percpu_rwsem_acquire(struct percpu_rw_semaphore *sem,
lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip); lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip);
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
if (!read) if (!read)
sem->rw_sem.owner = current; atomic_long_set(&sem->rw_sem.owner, (long)current);
#endif #endif
} }
......
...@@ -34,12 +34,13 @@ ...@@ -34,12 +34,13 @@
*/ */
struct rw_semaphore { struct rw_semaphore {
atomic_long_t count; atomic_long_t count;
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
/* /*
* Write owner. Used as a speculative check to see * Write owner or one of the read owners as well flags regarding
* if the owner is running on the cpu. * the current state of the rwsem. Can be used as a speculative
* check to see if the write owner is running on the cpu.
*/ */
struct task_struct *owner; atomic_long_t owner;
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
struct optimistic_spin_queue osq; /* spinner MCS lock */ struct optimistic_spin_queue osq; /* spinner MCS lock */
#endif #endif
raw_spinlock_t wait_lock; raw_spinlock_t wait_lock;
...@@ -50,10 +51,10 @@ struct rw_semaphore { ...@@ -50,10 +51,10 @@ struct rw_semaphore {
}; };
/* /*
* Setting bit 1 of the owner field but not bit 0 will indicate * Setting all bits of the owner field except bit 0 will indicate
* that the rwsem is writer-owned with an unknown owner. * that the rwsem is writer-owned with an unknown owner.
*/ */
#define RWSEM_OWNER_UNKNOWN ((struct task_struct *)-2L) #define RWSEM_OWNER_UNKNOWN (-2L)
/* In all implementations count != 0 means locked */ /* In all implementations count != 0 means locked */
static inline int rwsem_is_locked(struct rw_semaphore *sem) static inline int rwsem_is_locked(struct rw_semaphore *sem)
...@@ -73,13 +74,14 @@ static inline int rwsem_is_locked(struct rw_semaphore *sem) ...@@ -73,13 +74,14 @@ static inline int rwsem_is_locked(struct rw_semaphore *sem)
#endif #endif
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
#define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED, .owner = NULL #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_INIT_COUNT(name), \
.owner = ATOMIC_LONG_INIT(0), \
.wait_list = LIST_HEAD_INIT((name).wait_list), \ .wait_list = LIST_HEAD_INIT((name).wait_list), \
.wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \ .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \
__RWSEM_OPT_INIT(name) \ __RWSEM_OPT_INIT(name) \
......
...@@ -51,6 +51,11 @@ static inline void wake_q_init(struct wake_q_head *head) ...@@ -51,6 +51,11 @@ static inline void wake_q_init(struct wake_q_head *head)
head->lastp = &head->first; head->lastp = &head->first;
} }
static inline bool wake_q_empty(struct wake_q_head *head)
{
return head->first == WAKE_Q_TAIL;
}
extern void wake_q_add(struct wake_q_head *head, struct task_struct *task); extern void wake_q_add(struct wake_q_head *head, struct task_struct *task);
extern void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task); extern void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task);
extern void wake_up_q(struct wake_q_head *head); extern void wake_up_q(struct wake_q_head *head);
......
...@@ -180,29 +180,46 @@ static inline int get_boot_cpu_id(void) ...@@ -180,29 +180,46 @@ static inline int get_boot_cpu_id(void)
#endif /* !SMP */ #endif /* !SMP */
/* /**
* smp_processor_id(): get the current CPU ID. * raw_processor_id() - get the current (unstable) CPU id
*
* For then you know what you are doing and need an unstable
* CPU id.
*/
/**
* smp_processor_id() - get the current (stable) CPU id
*
* This is the normal accessor to the CPU id and should be used
* whenever possible.
*
* The CPU id is stable when:
* *
* if DEBUG_PREEMPT is enabled then we check whether it is * - IRQs are disabled;
* used in a preemption-safe way. (smp_processor_id() is safe * - preemption is disabled;
* if it's used in a preemption-off critical section, or in * - the task is CPU affine.
* a thread that is bound to the current CPU.)
* *
* NOTE: raw_smp_processor_id() is for internal use only * When CONFIG_DEBUG_PREEMPT; we verify these assumption and WARN
* (smp_processor_id() is the preferred variant), but in rare * when smp_processor_id() is used when the CPU id is not stable.
* instances it might also be used to turn off false positives
* (i.e. smp_processor_id() use that the debugging code reports but
* which use for some reason is legal). Don't use this to hack around
* the warning message, as your code might not work under PREEMPT.
*/ */
/*
* Allow the architecture to differentiate between a stable and unstable read.
* For example, x86 uses an IRQ-safe asm-volatile read for the unstable but a
* regular asm read for the stable.
*/
#ifndef __smp_processor_id
#define __smp_processor_id(x) raw_smp_processor_id(x)
#endif
#ifdef CONFIG_DEBUG_PREEMPT #ifdef CONFIG_DEBUG_PREEMPT
extern unsigned int debug_smp_processor_id(void); extern unsigned int debug_smp_processor_id(void);
# define smp_processor_id() debug_smp_processor_id() # define smp_processor_id() debug_smp_processor_id()
#else #else
# define smp_processor_id() raw_smp_processor_id() # define smp_processor_id() __smp_processor_id()
#endif #endif
#define get_cpu() ({ preempt_disable(); smp_processor_id(); }) #define get_cpu() ({ preempt_disable(); __smp_processor_id(); })
#define put_cpu() preempt_enable() #define put_cpu() preempt_enable()
/* /*
......
...@@ -174,7 +174,7 @@ typedef struct { ...@@ -174,7 +174,7 @@ typedef struct {
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
typedef struct { typedef struct {
long counter; s64 counter;
} atomic64_t; } atomic64_t;
#endif #endif
......
...@@ -166,6 +166,8 @@ struct task_struct init_task ...@@ -166,6 +166,8 @@ struct task_struct init_task
.softirqs_enabled = 1, .softirqs_enabled = 1,
#endif #endif
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
.lockdep_depth = 0, /* no locks held yet */
.curr_chain_key = INITIAL_CHAIN_KEY,
.lockdep_recursion = 0, .lockdep_recursion = 0,
#endif #endif
#ifdef CONFIG_FUNCTION_GRAPH_TRACER #ifdef CONFIG_FUNCTION_GRAPH_TRACER
......
...@@ -1952,9 +1952,6 @@ static __latent_entropy struct task_struct *copy_process( ...@@ -1952,9 +1952,6 @@ static __latent_entropy struct task_struct *copy_process(
p->pagefault_disabled = 0; p->pagefault_disabled = 0;
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
p->lockdep_depth = 0; /* no locks held yet */
p->curr_chain_key = 0;
p->lockdep_recursion = 0;
lockdep_init_task(p); lockdep_init_task(p);
#endif #endif
......
...@@ -470,6 +470,37 @@ enum futex_access { ...@@ -470,6 +470,37 @@ enum futex_access {
FUTEX_WRITE FUTEX_WRITE
}; };
/**
* futex_setup_timer - set up the sleeping hrtimer.
* @time: ptr to the given timeout value
* @timeout: the hrtimer_sleeper structure to be set up
* @flags: futex flags
* @range_ns: optional range in ns
*
* Return: Initialized hrtimer_sleeper structure or NULL if no timeout
* value given
*/
static inline struct hrtimer_sleeper *
futex_setup_timer(ktime_t *time, struct hrtimer_sleeper *timeout,
int flags, u64 range_ns)
{
if (!time)
return NULL;
hrtimer_init_on_stack(&timeout->timer, (flags & FLAGS_CLOCKRT) ?
CLOCK_REALTIME : CLOCK_MONOTONIC,
HRTIMER_MODE_ABS);
hrtimer_init_sleeper(timeout, current);
/*
* If range_ns is 0, calling hrtimer_set_expires_range_ns() is
* effectively the same as calling hrtimer_set_expires().
*/
hrtimer_set_expires_range_ns(&timeout->timer, *time, range_ns);
return timeout;
}
/** /**
* 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
...@@ -2679,7 +2710,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags, ...@@ -2679,7 +2710,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
ktime_t *abs_time, u32 bitset) ktime_t *abs_time, u32 bitset)
{ {
struct hrtimer_sleeper timeout, *to = NULL; struct hrtimer_sleeper timeout, *to;
struct restart_block *restart; struct restart_block *restart;
struct futex_hash_bucket *hb; struct futex_hash_bucket *hb;
struct futex_q q = futex_q_init; struct futex_q q = futex_q_init;
...@@ -2689,17 +2720,8 @@ static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, ...@@ -2689,17 +2720,8 @@ static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
return -EINVAL; return -EINVAL;
q.bitset = bitset; q.bitset = bitset;
if (abs_time) { to = futex_setup_timer(abs_time, &timeout, flags,
to = &timeout; current->timer_slack_ns);
hrtimer_init_on_stack(&to->timer, (flags & FLAGS_CLOCKRT) ?
CLOCK_REALTIME : CLOCK_MONOTONIC,
HRTIMER_MODE_ABS);
hrtimer_init_sleeper(to, current);
hrtimer_set_expires_range_ns(&to->timer, *abs_time,
current->timer_slack_ns);
}
retry: retry:
/* /*
* Prepare to wait on uaddr. On success, holds hb lock and increments * Prepare to wait on uaddr. On success, holds hb lock and increments
...@@ -2779,7 +2801,7 @@ static long futex_wait_restart(struct restart_block *restart) ...@@ -2779,7 +2801,7 @@ static long futex_wait_restart(struct restart_block *restart)
static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
ktime_t *time, int trylock) ktime_t *time, int trylock)
{ {
struct hrtimer_sleeper timeout, *to = NULL; struct hrtimer_sleeper timeout, *to;
struct futex_pi_state *pi_state = NULL; struct futex_pi_state *pi_state = NULL;
struct rt_mutex_waiter rt_waiter; struct rt_mutex_waiter rt_waiter;
struct futex_hash_bucket *hb; struct futex_hash_bucket *hb;
...@@ -2792,13 +2814,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ...@@ -2792,13 +2814,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
if (refill_pi_state_cache()) if (refill_pi_state_cache())
return -ENOMEM; return -ENOMEM;
if (time) { to = futex_setup_timer(time, &timeout, FLAGS_CLOCKRT, 0);
to = &timeout;
hrtimer_init_on_stack(&to->timer, CLOCK_REALTIME,
HRTIMER_MODE_ABS);
hrtimer_init_sleeper(to, current);
hrtimer_set_expires(&to->timer, *time);
}
retry: retry:
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, FUTEX_WRITE); ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, FUTEX_WRITE);
...@@ -3195,7 +3211,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, ...@@ -3195,7 +3211,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
u32 val, ktime_t *abs_time, u32 bitset, u32 val, ktime_t *abs_time, u32 bitset,
u32 __user *uaddr2) u32 __user *uaddr2)
{ {
struct hrtimer_sleeper timeout, *to = NULL; struct hrtimer_sleeper timeout, *to;
struct futex_pi_state *pi_state = NULL; struct futex_pi_state *pi_state = NULL;
struct rt_mutex_waiter rt_waiter; struct rt_mutex_waiter rt_waiter;
struct futex_hash_bucket *hb; struct futex_hash_bucket *hb;
...@@ -3212,15 +3228,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, ...@@ -3212,15 +3228,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
if (!bitset) if (!bitset)
return -EINVAL; return -EINVAL;
if (abs_time) { to = futex_setup_timer(abs_time, &timeout, flags,
to = &timeout; current->timer_slack_ns);
hrtimer_init_on_stack(&to->timer, (flags & FLAGS_CLOCKRT) ?
CLOCK_REALTIME : CLOCK_MONOTONIC,
HRTIMER_MODE_ABS);
hrtimer_init_sleeper(to, current);
hrtimer_set_expires_range_ns(&to->timer, *abs_time,
current->timer_slack_ns);
}
/* /*
* The waiter is allocated on our stack, manipulated by the requeue * The waiter is allocated on our stack, manipulated by the requeue
......
...@@ -37,12 +37,26 @@ static int jump_label_cmp(const void *a, const void *b) ...@@ -37,12 +37,26 @@ static int jump_label_cmp(const void *a, const void *b)
const struct jump_entry *jea = a; const struct jump_entry *jea = a;
const struct jump_entry *jeb = b; const struct jump_entry *jeb = b;
/*
* Entrires are sorted by key.
*/
if (jump_entry_key(jea) < jump_entry_key(jeb)) if (jump_entry_key(jea) < jump_entry_key(jeb))
return -1; return -1;
if (jump_entry_key(jea) > jump_entry_key(jeb)) if (jump_entry_key(jea) > jump_entry_key(jeb))
return 1; return 1;
/*
* In the batching mode, entries should also be sorted by the code
* inside the already sorted list of entries, enabling a bsearch in
* the vector.
*/
if (jump_entry_code(jea) < jump_entry_code(jeb))
return -1;
if (jump_entry_code(jea) > jump_entry_code(jeb))
return 1;
return 0; return 0;
} }
...@@ -384,25 +398,55 @@ static enum jump_label_type jump_label_type(struct jump_entry *entry) ...@@ -384,25 +398,55 @@ static enum jump_label_type jump_label_type(struct jump_entry *entry)
return enabled ^ branch; return enabled ^ branch;
} }
static bool jump_label_can_update(struct jump_entry *entry, bool init)
{
/*
* Cannot update code that was in an init text area.
*/
if (!init && jump_entry_is_init(entry))
return false;
if (!kernel_text_address(jump_entry_code(entry))) {
WARN_ONCE(1, "can't patch jump_label at %pS", (void *)jump_entry_code(entry));
return false;
}
return true;
}
#ifndef HAVE_JUMP_LABEL_BATCH
static void __jump_label_update(struct static_key *key, static void __jump_label_update(struct static_key *key,
struct jump_entry *entry, struct jump_entry *entry,
struct jump_entry *stop, struct jump_entry *stop,
bool init) bool init)
{ {
for (; (entry < stop) && (jump_entry_key(entry) == key); entry++) { for (; (entry < stop) && (jump_entry_key(entry) == key); entry++) {
/* if (jump_label_can_update(entry, init))
* An entry->code of 0 indicates an entry which has been arch_jump_label_transform(entry, jump_label_type(entry));
* disabled because it was in an init text area. }
*/ }
if (init || !jump_entry_is_init(entry)) { #else
if (kernel_text_address(jump_entry_code(entry))) static void __jump_label_update(struct static_key *key,
arch_jump_label_transform(entry, jump_label_type(entry)); struct jump_entry *entry,
else struct jump_entry *stop,
WARN_ONCE(1, "can't patch jump_label at %pS", bool init)
(void *)jump_entry_code(entry)); {
for (; (entry < stop) && (jump_entry_key(entry) == key); entry++) {
if (!jump_label_can_update(entry, init))
continue;
if (!arch_jump_label_transform_queue(entry, jump_label_type(entry))) {
/*
* Queue is full: Apply the current queue and try again.
*/
arch_jump_label_transform_apply();
BUG_ON(!arch_jump_label_transform_queue(entry, jump_label_type(entry)));
} }
} }
arch_jump_label_transform_apply();
} }
#endif
void __init jump_label_init(void) void __init jump_label_init(void)
{ {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# and is generally not a function of system call inputs. # and is generally not a function of system call inputs.
KCOV_INSTRUMENT := n KCOV_INSTRUMENT := n
obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o rwsem-xadd.o obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o
ifdef CONFIG_FUNCTION_TRACER ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_lockdep.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_lockdep.o = $(CC_FLAGS_FTRACE)
......
...@@ -31,50 +31,13 @@ enum lock_events { ...@@ -31,50 +31,13 @@ enum lock_events {
DECLARE_PER_CPU(unsigned long, lockevents[lockevent_num]); DECLARE_PER_CPU(unsigned long, lockevents[lockevent_num]);
/* /*
* The purpose of the lock event counting subsystem is to provide a low * Increment the statistical counters. use raw_cpu_inc() because of lower
* overhead way to record the number of specific locking events by using * overhead and we don't care if we loose the occasional update.
* percpu counters. It is the percpu sum that matters, not specifically
* how many of them happens in each cpu.
*
* It is possible that the same percpu counter may be modified in both
* the process and interrupt contexts. For architectures that perform
* percpu operation with multiple instructions, it is possible to lose
* count if a process context percpu update is interrupted in the middle
* and the same counter is updated in the interrupt context. Therefore,
* the generated percpu sum may not be precise. The error, if any, should
* be small and insignificant.
*
* For those architectures that do multi-instruction percpu operation,
* preemption in the middle and moving the task to another cpu may cause
* a larger error in the count. Again, this will be few and far between.
* Given the imprecise nature of the count and the possibility of resetting
* the count and doing the measurement again, this is not really a big
* problem.
*
* To get a better picture of what is happening under the hood, it is
* suggested that a few measurements should be taken with the counts
* reset in between to stamp out outliner because of these possible
* error conditions.
*
* To minimize overhead, we use __this_cpu_*() in all cases except when
* CONFIG_DEBUG_PREEMPT is defined. In this particular case, this_cpu_*()
* will be used to avoid the appearance of unwanted BUG messages.
*/
#ifdef CONFIG_DEBUG_PREEMPT
#define lockevent_percpu_inc(x) this_cpu_inc(x)
#define lockevent_percpu_add(x, v) this_cpu_add(x, v)
#else
#define lockevent_percpu_inc(x) __this_cpu_inc(x)
#define lockevent_percpu_add(x, v) __this_cpu_add(x, v)
#endif
/*
* Increment the PV qspinlock statistical counters
*/ */
static inline void __lockevent_inc(enum lock_events event, bool cond) static inline void __lockevent_inc(enum lock_events event, bool cond)
{ {
if (cond) if (cond)
lockevent_percpu_inc(lockevents[event]); raw_cpu_inc(lockevents[event]);
} }
#define lockevent_inc(ev) __lockevent_inc(LOCKEVENT_ ##ev, true) #define lockevent_inc(ev) __lockevent_inc(LOCKEVENT_ ##ev, true)
...@@ -82,7 +45,7 @@ static inline void __lockevent_inc(enum lock_events event, bool cond) ...@@ -82,7 +45,7 @@ static inline void __lockevent_inc(enum lock_events event, bool cond)
static inline void __lockevent_add(enum lock_events event, int inc) static inline void __lockevent_add(enum lock_events event, int inc)
{ {
lockevent_percpu_add(lockevents[event], inc); raw_cpu_add(lockevents[event], inc);
} }
#define lockevent_add(ev, c) __lockevent_add(LOCKEVENT_ ##ev, c) #define lockevent_add(ev, c) __lockevent_add(LOCKEVENT_ ##ev, c)
......
...@@ -56,12 +56,16 @@ LOCK_EVENT(rwsem_sleep_reader) /* # of reader sleeps */ ...@@ -56,12 +56,16 @@ LOCK_EVENT(rwsem_sleep_reader) /* # of reader sleeps */
LOCK_EVENT(rwsem_sleep_writer) /* # of writer sleeps */ LOCK_EVENT(rwsem_sleep_writer) /* # of writer sleeps */
LOCK_EVENT(rwsem_wake_reader) /* # of reader wakeups */ LOCK_EVENT(rwsem_wake_reader) /* # of reader wakeups */
LOCK_EVENT(rwsem_wake_writer) /* # of writer wakeups */ LOCK_EVENT(rwsem_wake_writer) /* # of writer wakeups */
LOCK_EVENT(rwsem_opt_wlock) /* # of write locks opt-spin acquired */ LOCK_EVENT(rwsem_opt_rlock) /* # of opt-acquired read locks */
LOCK_EVENT(rwsem_opt_fail) /* # of failed opt-spinnings */ LOCK_EVENT(rwsem_opt_wlock) /* # of opt-acquired write locks */
LOCK_EVENT(rwsem_opt_fail) /* # of failed optspins */
LOCK_EVENT(rwsem_opt_nospin) /* # of disabled optspins */
LOCK_EVENT(rwsem_opt_norspin) /* # of disabled reader-only optspins */
LOCK_EVENT(rwsem_opt_rlock2) /* # of opt-acquired 2ndary read locks */
LOCK_EVENT(rwsem_rlock) /* # of read locks acquired */ LOCK_EVENT(rwsem_rlock) /* # of read locks acquired */
LOCK_EVENT(rwsem_rlock_fast) /* # of fast read locks acquired */ LOCK_EVENT(rwsem_rlock_fast) /* # of fast read locks acquired */
LOCK_EVENT(rwsem_rlock_fail) /* # of failed read lock acquisitions */ LOCK_EVENT(rwsem_rlock_fail) /* # of failed read lock acquisitions */
LOCK_EVENT(rwsem_rtrylock) /* # of read trylock calls */ LOCK_EVENT(rwsem_rlock_handoff) /* # of read lock handoffs */
LOCK_EVENT(rwsem_wlock) /* # of write locks acquired */ LOCK_EVENT(rwsem_wlock) /* # of write locks acquired */
LOCK_EVENT(rwsem_wlock_fail) /* # of failed write lock acquisitions */ LOCK_EVENT(rwsem_wlock_fail) /* # of failed write lock acquisitions */
LOCK_EVENT(rwsem_wtrylock) /* # of write trylock calls */ LOCK_EVENT(rwsem_wlock_handoff) /* # of write lock handoffs */
This diff is collapsed.
...@@ -131,7 +131,6 @@ extern unsigned int nr_hardirq_chains; ...@@ -131,7 +131,6 @@ extern unsigned int nr_hardirq_chains;
extern unsigned int nr_softirq_chains; extern unsigned int nr_softirq_chains;
extern unsigned int nr_process_chains; extern unsigned int nr_process_chains;
extern unsigned int max_lockdep_depth; extern unsigned int max_lockdep_depth;
extern unsigned int max_recursion_depth;
extern unsigned int max_bfs_queue_depth; extern unsigned int max_bfs_queue_depth;
...@@ -160,25 +159,22 @@ lockdep_count_backward_deps(struct lock_class *class) ...@@ -160,25 +159,22 @@ lockdep_count_backward_deps(struct lock_class *class)
* and we want to avoid too much cache bouncing. * and we want to avoid too much cache bouncing.
*/ */
struct lockdep_stats { struct lockdep_stats {
int chain_lookup_hits; unsigned long chain_lookup_hits;
int chain_lookup_misses; unsigned int chain_lookup_misses;
int hardirqs_on_events; unsigned long hardirqs_on_events;
int hardirqs_off_events; unsigned long hardirqs_off_events;
int redundant_hardirqs_on; unsigned long redundant_hardirqs_on;
int redundant_hardirqs_off; unsigned long redundant_hardirqs_off;
int softirqs_on_events; unsigned long softirqs_on_events;
int softirqs_off_events; unsigned long softirqs_off_events;
int redundant_softirqs_on; unsigned long redundant_softirqs_on;
int redundant_softirqs_off; unsigned long redundant_softirqs_off;
int nr_unused_locks; int nr_unused_locks;
int nr_redundant_checks; unsigned int nr_redundant_checks;
int nr_redundant; unsigned int nr_redundant;
int nr_cyclic_checks; unsigned int nr_cyclic_checks;
int nr_cyclic_check_recursions; unsigned int nr_find_usage_forwards_checks;
int nr_find_usage_forwards_checks; unsigned int nr_find_usage_backwards_checks;
int nr_find_usage_forwards_recursions;
int nr_find_usage_backwards_checks;
int nr_find_usage_backwards_recursions;
/* /*
* Per lock class locking operation stat counts * Per lock class locking operation stat counts
......
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
/*
* The least significant 2 bits of the owner value has the following
* meanings when set.
* - RWSEM_READER_OWNED (bit 0): The rwsem is owned by readers
* - RWSEM_ANONYMOUSLY_OWNED (bit 1): The rwsem is anonymously owned,
* i.e. the owner(s) cannot be readily determined. It can be reader
* owned or the owning writer is indeterminate.
*
* When a writer acquires a rwsem, it puts its task_struct pointer
* into the owner field. It is cleared after an unlock.
*
* When a reader acquires a rwsem, it will also puts its task_struct
* pointer into the owner field with both the RWSEM_READER_OWNED and
* RWSEM_ANONYMOUSLY_OWNED bits set. On unlock, the owner field will
* largely be left untouched. So for a free or reader-owned rwsem,
* the owner value may contain information about the last reader that
* acquires the rwsem. The anonymous bit is set because that particular
* reader may or may not still own the lock.
*
* That information may be helpful in debugging cases where the system
* seems to hang on a reader owned rwsem especially if only one reader
* is involved. Ideally we would like to track all the readers that own
* a rwsem, but the overhead is simply too big.
*/
#include "lock_events.h"
#define RWSEM_READER_OWNED (1UL << 0) #ifndef __INTERNAL_RWSEM_H
#define RWSEM_ANONYMOUSLY_OWNED (1UL << 1) #define __INTERNAL_RWSEM_H
#include <linux/rwsem.h>
#ifdef CONFIG_DEBUG_RWSEMS extern void __down_read(struct rw_semaphore *sem);
# define DEBUG_RWSEMS_WARN_ON(c, sem) do { \ extern void __up_read(struct rw_semaphore *sem);
if (!debug_locks_silent && \
WARN_ONCE(c, "DEBUG_RWSEMS_WARN_ON(%s): count = 0x%lx, owner = 0x%lx, curr 0x%lx, list %sempty\n",\
#c, atomic_long_read(&(sem)->count), \
(long)((sem)->owner), (long)current, \
list_empty(&(sem)->wait_list) ? "" : "not ")) \
debug_locks_off(); \
} while (0)
#else
# define DEBUG_RWSEMS_WARN_ON(c, sem)
#endif
/* #endif /* __INTERNAL_RWSEM_H */
* R/W semaphores originally for PPC using the stuff in lib/rwsem.c.
* Adapted largely from include/asm-i386/rwsem.h
* by Paul Mackerras <paulus@samba.org>.
*/
/*
* the semaphore definition
*/
#ifdef CONFIG_64BIT
# define RWSEM_ACTIVE_MASK 0xffffffffL
#else
# define RWSEM_ACTIVE_MASK 0x0000ffffL
#endif
#define RWSEM_ACTIVE_BIAS 0x00000001L
#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1)
#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
/*
* All writes to owner are protected by WRITE_ONCE() to make sure that
* store tearing can't happen as optimistic spinners may read and use
* the owner value concurrently without lock. Read from owner, however,
* may not need READ_ONCE() as long as the pointer value is only used
* for comparison and isn't being dereferenced.
*/
static inline void rwsem_set_owner(struct rw_semaphore *sem)
{
WRITE_ONCE(sem->owner, current);
}
static inline void rwsem_clear_owner(struct rw_semaphore *sem)
{
WRITE_ONCE(sem->owner, NULL);
}
/*
* The task_struct pointer of the last owning reader will be left in
* the owner field.
*
* Note that the owner value just indicates the task has owned the rwsem
* previously, it may not be the real owner or one of the real owners
* anymore when that field is examined, so take it with a grain of salt.
*/
static inline void __rwsem_set_reader_owned(struct rw_semaphore *sem,
struct task_struct *owner)
{
unsigned long val = (unsigned long)owner | RWSEM_READER_OWNED
| RWSEM_ANONYMOUSLY_OWNED;
WRITE_ONCE(sem->owner, (struct task_struct *)val);
}
static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
{
__rwsem_set_reader_owned(sem, current);
}
/*
* Return true if the a rwsem waiter can spin on the rwsem's owner
* and steal the lock, i.e. the lock is not anonymously owned.
* N.B. !owner is considered spinnable.
*/
static inline bool is_rwsem_owner_spinnable(struct task_struct *owner)
{
return !((unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED);
}
/*
* Return true if rwsem is owned by an anonymous writer or readers.
*/
static inline bool rwsem_has_anonymous_owner(struct task_struct *owner)
{
return (unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED;
}
#ifdef CONFIG_DEBUG_RWSEMS
/*
* With CONFIG_DEBUG_RWSEMS configured, it will make sure that if there
* is a task pointer in owner of a reader-owned rwsem, it will be the
* real owner or one of the real owners. The only exception is when the
* unlock is done by up_read_non_owner().
*/
#define rwsem_clear_reader_owned rwsem_clear_reader_owned
static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem)
{
unsigned long val = (unsigned long)current | RWSEM_READER_OWNED
| RWSEM_ANONYMOUSLY_OWNED;
if (READ_ONCE(sem->owner) == (struct task_struct *)val)
cmpxchg_relaxed((unsigned long *)&sem->owner, val,
RWSEM_READER_OWNED | RWSEM_ANONYMOUSLY_OWNED);
}
#endif
#else
static inline void rwsem_set_owner(struct rw_semaphore *sem)
{
}
static inline void rwsem_clear_owner(struct rw_semaphore *sem)
{
}
static inline void __rwsem_set_reader_owned(struct rw_semaphore *sem,
struct task_struct *owner)
{
}
static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
{
}
#endif
#ifndef rwsem_clear_reader_owned
static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem)
{
}
#endif
extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
extern struct rw_semaphore *rwsem_down_read_failed_killable(struct rw_semaphore *sem);
extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
extern struct rw_semaphore *rwsem_down_write_failed_killable(struct rw_semaphore *sem);
extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
/*
* lock for reading
*/
static inline void __down_read(struct rw_semaphore *sem)
{
if (unlikely(atomic_long_inc_return_acquire(&sem->count) <= 0)) {
rwsem_down_read_failed(sem);
DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner &
RWSEM_READER_OWNED), sem);
} else {
rwsem_set_reader_owned(sem);
}
}
static inline int __down_read_killable(struct rw_semaphore *sem)
{
if (unlikely(atomic_long_inc_return_acquire(&sem->count) <= 0)) {
if (IS_ERR(rwsem_down_read_failed_killable(sem)))
return -EINTR;
DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner &
RWSEM_READER_OWNED), sem);
} else {
rwsem_set_reader_owned(sem);
}
return 0;
}
static inline int __down_read_trylock(struct rw_semaphore *sem)
{
/*
* Optimize for the case when the rwsem is not locked at all.
*/
long tmp = RWSEM_UNLOCKED_VALUE;
lockevent_inc(rwsem_rtrylock);
do {
if (atomic_long_try_cmpxchg_acquire(&sem->count, &tmp,
tmp + RWSEM_ACTIVE_READ_BIAS)) {
rwsem_set_reader_owned(sem);
return 1;
}
} while (tmp >= 0);
return 0;
}
/*
* lock for writing
*/
static inline void __down_write(struct rw_semaphore *sem)
{
long tmp;
tmp = atomic_long_add_return_acquire(RWSEM_ACTIVE_WRITE_BIAS,
&sem->count);
if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
rwsem_down_write_failed(sem);
rwsem_set_owner(sem);
}
static inline int __down_write_killable(struct rw_semaphore *sem)
{
long tmp;
tmp = atomic_long_add_return_acquire(RWSEM_ACTIVE_WRITE_BIAS,
&sem->count);
if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
if (IS_ERR(rwsem_down_write_failed_killable(sem)))
return -EINTR;
rwsem_set_owner(sem);
return 0;
}
static inline int __down_write_trylock(struct rw_semaphore *sem)
{
long tmp;
lockevent_inc(rwsem_wtrylock);
tmp = atomic_long_cmpxchg_acquire(&sem->count, RWSEM_UNLOCKED_VALUE,
RWSEM_ACTIVE_WRITE_BIAS);
if (tmp == RWSEM_UNLOCKED_VALUE) {
rwsem_set_owner(sem);
return true;
}
return false;
}
/*
* unlock after reading
*/
static inline void __up_read(struct rw_semaphore *sem)
{
long tmp;
DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner & RWSEM_READER_OWNED),
sem);
rwsem_clear_reader_owned(sem);
tmp = atomic_long_dec_return_release(&sem->count);
if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0))
rwsem_wake(sem);
}
/*
* unlock after writing
*/
static inline void __up_write(struct rw_semaphore *sem)
{
DEBUG_RWSEMS_WARN_ON(sem->owner != current, sem);
rwsem_clear_owner(sem);
if (unlikely(atomic_long_sub_return_release(RWSEM_ACTIVE_WRITE_BIAS,
&sem->count) < 0))
rwsem_wake(sem);
}
/*
* downgrade write lock to read lock
*/
static inline void __downgrade_write(struct rw_semaphore *sem)
{
long tmp;
/*
* When downgrading from exclusive to shared ownership,
* anything inside the write-locked region cannot leak
* into the read side. In contrast, anything in the
* read-locked region is ok to be re-ordered into the
* write side. As such, rely on RELEASE semantics.
*/
DEBUG_RWSEMS_WARN_ON(sem->owner != current, sem);
tmp = atomic_long_add_return_release(-RWSEM_WAITING_BIAS, &sem->count);
rwsem_set_reader_owned(sem);
if (tmp < 0)
rwsem_downgrade_wake(sem);
}
...@@ -6189,6 +6189,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t ...@@ -6189,6 +6189,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t
u64 time, cost; u64 time, cost;
s64 delta; s64 delta;
int cpu, nr = INT_MAX; int cpu, nr = INT_MAX;
int this = smp_processor_id();
this_sd = rcu_dereference(*this_cpu_ptr(&sd_llc)); this_sd = rcu_dereference(*this_cpu_ptr(&sd_llc));
if (!this_sd) if (!this_sd)
...@@ -6212,7 +6213,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t ...@@ -6212,7 +6213,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t
nr = 4; nr = 4;
} }
time = local_clock(); time = cpu_clock(this);
for_each_cpu_wrap(cpu, sched_domain_span(sd), target) { for_each_cpu_wrap(cpu, sched_domain_span(sd), target) {
if (!--nr) if (!--nr)
...@@ -6223,7 +6224,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t ...@@ -6223,7 +6224,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t
break; break;
} }
time = local_clock() - time; time = cpu_clock(this) - time;
cost = this_sd->avg_scan_cost; cost = this_sd->avg_scan_cost;
delta = (s64)(time - cost) / 8; delta = (s64)(time - cost) / 8;
this_sd->avg_scan_cost += delta; this_sd->avg_scan_cost += delta;
......
...@@ -1095,7 +1095,7 @@ config PROVE_LOCKING ...@@ -1095,7 +1095,7 @@ config PROVE_LOCKING
select DEBUG_SPINLOCK select DEBUG_SPINLOCK
select DEBUG_MUTEXES select DEBUG_MUTEXES
select DEBUG_RT_MUTEXES if RT_MUTEXES select DEBUG_RT_MUTEXES if RT_MUTEXES
select DEBUG_RWSEMS if RWSEM_SPIN_ON_OWNER select DEBUG_RWSEMS
select DEBUG_WW_MUTEX_SLOWPATH select DEBUG_WW_MUTEX_SLOWPATH
select DEBUG_LOCK_ALLOC select DEBUG_LOCK_ALLOC
select TRACE_IRQFLAGS select TRACE_IRQFLAGS
...@@ -1199,10 +1199,10 @@ config DEBUG_WW_MUTEX_SLOWPATH ...@@ -1199,10 +1199,10 @@ config DEBUG_WW_MUTEX_SLOWPATH
config DEBUG_RWSEMS config DEBUG_RWSEMS
bool "RW Semaphore debugging: basic checks" bool "RW Semaphore debugging: basic checks"
depends on DEBUG_KERNEL && RWSEM_SPIN_ON_OWNER depends on DEBUG_KERNEL
help help
This debugging feature allows mismatched rw semaphore locks and unlocks This debugging feature allows mismatched rw semaphore locks
to be detected and reported. and unlocks to be detected and reported.
config DEBUG_LOCK_ALLOC config DEBUG_LOCK_ALLOC
bool "Lock debugging: detect incorrect freeing of live locks" bool "Lock debugging: detect incorrect freeing of live locks"
......
This diff is collapsed.
...@@ -22,7 +22,7 @@ while read header; do ...@@ -22,7 +22,7 @@ while read header; do
OLDSUM="$(tail -n 1 ${LINUXDIR}/include/${header})" OLDSUM="$(tail -n 1 ${LINUXDIR}/include/${header})"
OLDSUM="${OLDSUM#// }" OLDSUM="${OLDSUM#// }"
NEWSUM="$(head -n -1 ${LINUXDIR}/include/${header} | sha1sum)" NEWSUM="$(sed '$d' ${LINUXDIR}/include/${header} | sha1sum)"
NEWSUM="${NEWSUM%% *}" NEWSUM="${NEWSUM%% *}"
if [ "${OLDSUM}" != "${NEWSUM}" ]; then if [ "${OLDSUM}" != "${NEWSUM}" ]; then
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment