Commit 3b4ba664 authored by Waiman Long's avatar Waiman Long Committed by Ingo Molnar

locking/rwsem: Enhance DEBUG_RWSEMS_WARN_ON() macro

Currently, the DEBUG_RWSEMS_WARN_ON() macro just dumps a stack trace
when the rwsem isn't in the right state. It does not show the actual
states of the rwsem. This may not be that helpful in the debugging
process.

Enhance the DEBUG_RWSEMS_WARN_ON() macro to also show the current
content of the rwsem count and owner fields to give more information
about what is wrong with the rwsem. The debug_locks_off() function is
called as is done inside DEBUG_LOCKS_WARN_ON().
Signed-off-by: default avatarWaiman Long <longman@redhat.com>
Acked-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: default avatarDavidlohr Bueso <dbueso@suse.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Tim Chen <tim.c.chen@linux.intel.com>
Cc: Will Deacon <will.deacon@arm.com>
Link: http://lkml.kernel.org/r/20190404174320.22416-7-longman@redhat.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent a68e2c4c
...@@ -198,7 +198,8 @@ EXPORT_SYMBOL(down_write_killable_nested); ...@@ -198,7 +198,8 @@ EXPORT_SYMBOL(down_write_killable_nested);
void up_read_non_owner(struct rw_semaphore *sem) void up_read_non_owner(struct rw_semaphore *sem)
{ {
DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner & RWSEM_READER_OWNED)); DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner & RWSEM_READER_OWNED),
sem);
__up_read(sem); __up_read(sem);
} }
......
...@@ -27,9 +27,15 @@ ...@@ -27,9 +27,15 @@
#define RWSEM_ANONYMOUSLY_OWNED (1UL << 1) #define RWSEM_ANONYMOUSLY_OWNED (1UL << 1)
#ifdef CONFIG_DEBUG_RWSEMS #ifdef CONFIG_DEBUG_RWSEMS
# define DEBUG_RWSEMS_WARN_ON(c) DEBUG_LOCKS_WARN_ON(c) # define DEBUG_RWSEMS_WARN_ON(c, sem) do { \
if (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 #else
# define DEBUG_RWSEMS_WARN_ON(c) # define DEBUG_RWSEMS_WARN_ON(c, sem)
#endif #endif
/* /*
...@@ -168,7 +174,7 @@ static inline void __down_read(struct rw_semaphore *sem) ...@@ -168,7 +174,7 @@ static inline void __down_read(struct rw_semaphore *sem)
if (unlikely(atomic_long_inc_return_acquire(&sem->count) <= 0)) { if (unlikely(atomic_long_inc_return_acquire(&sem->count) <= 0)) {
rwsem_down_read_failed(sem); rwsem_down_read_failed(sem);
DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner & DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner &
RWSEM_READER_OWNED)); RWSEM_READER_OWNED), sem);
} else { } else {
rwsem_set_reader_owned(sem); rwsem_set_reader_owned(sem);
} }
...@@ -180,7 +186,7 @@ static inline int __down_read_killable(struct rw_semaphore *sem) ...@@ -180,7 +186,7 @@ static inline int __down_read_killable(struct rw_semaphore *sem)
if (IS_ERR(rwsem_down_read_failed_killable(sem))) if (IS_ERR(rwsem_down_read_failed_killable(sem)))
return -EINTR; return -EINTR;
DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner & DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner &
RWSEM_READER_OWNED)); RWSEM_READER_OWNED), sem);
} else { } else {
rwsem_set_reader_owned(sem); rwsem_set_reader_owned(sem);
} }
...@@ -251,7 +257,8 @@ static inline void __up_read(struct rw_semaphore *sem) ...@@ -251,7 +257,8 @@ static inline void __up_read(struct rw_semaphore *sem)
{ {
long tmp; long tmp;
DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner & RWSEM_READER_OWNED)); DEBUG_RWSEMS_WARN_ON(!((unsigned long)sem->owner & RWSEM_READER_OWNED),
sem);
rwsem_clear_reader_owned(sem); rwsem_clear_reader_owned(sem);
tmp = atomic_long_dec_return_release(&sem->count); tmp = atomic_long_dec_return_release(&sem->count);
if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)) if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0))
...@@ -263,7 +270,7 @@ static inline void __up_read(struct rw_semaphore *sem) ...@@ -263,7 +270,7 @@ static inline void __up_read(struct rw_semaphore *sem)
*/ */
static inline void __up_write(struct rw_semaphore *sem) static inline void __up_write(struct rw_semaphore *sem)
{ {
DEBUG_RWSEMS_WARN_ON(sem->owner != current); DEBUG_RWSEMS_WARN_ON(sem->owner != current, sem);
rwsem_clear_owner(sem); rwsem_clear_owner(sem);
if (unlikely(atomic_long_sub_return_release(RWSEM_ACTIVE_WRITE_BIAS, if (unlikely(atomic_long_sub_return_release(RWSEM_ACTIVE_WRITE_BIAS,
&sem->count) < 0)) &sem->count) < 0))
...@@ -284,7 +291,7 @@ static inline void __downgrade_write(struct rw_semaphore *sem) ...@@ -284,7 +291,7 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
* read-locked region is ok to be re-ordered into the * read-locked region is ok to be re-ordered into the
* write side. As such, rely on RELEASE semantics. * write side. As such, rely on RELEASE semantics.
*/ */
DEBUG_RWSEMS_WARN_ON(sem->owner != current); DEBUG_RWSEMS_WARN_ON(sem->owner != current, sem);
tmp = atomic_long_add_return_release(-RWSEM_WAITING_BIAS, &sem->count); tmp = atomic_long_add_return_release(-RWSEM_WAITING_BIAS, &sem->count);
rwsem_set_reader_owned(sem); rwsem_set_reader_owned(sem);
if (tmp < 0) if (tmp < 0)
......
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