diff options
| author | Waiman Long <Waiman.Long@hp.com> | 2015-07-11 21:19:19 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2015-07-21 04:18:07 -0400 |
| commit | cba77f03f2c7b6cc0b0a44a3c679e0abade7da62 (patch) | |
| tree | daba72ef7775e93627688ce9dd086a6e421c1feb /kernel/locking | |
| parent | 9d634c410b07be7bf637ea03362d3ff132088fe3 (diff) | |
locking/pvqspinlock: Fix kernel panic in locking-selftest
Enabling locking-selftest in a VM guest may cause the following
kernel panic:
kernel BUG at .../kernel/locking/qspinlock_paravirt.h:137!
This is due to the fact that the pvqspinlock unlock function is
expecting either a _Q_LOCKED_VAL or _Q_SLOW_VAL in the lock
byte. This patch prevents that bug report by ignoring it when
debug_locks_silent is set. Otherwise, a warning will be printed
if it contains an unexpected value.
With this patch applied, the kernel locking-selftest completed
without any noise.
Tested-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Waiman Long <Waiman.Long@hp.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1436663959-53092-1-git-send-email-Waiman.Long@hp.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/locking')
| -rw-r--r-- | kernel/locking/qspinlock_paravirt.h | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/kernel/locking/qspinlock_paravirt.h b/kernel/locking/qspinlock_paravirt.h index 04ab18151cc8..df19ae4debd0 100644 --- a/kernel/locking/qspinlock_paravirt.h +++ b/kernel/locking/qspinlock_paravirt.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <linux/hash.h> | 5 | #include <linux/hash.h> |
| 6 | #include <linux/bootmem.h> | 6 | #include <linux/bootmem.h> |
| 7 | #include <linux/debug_locks.h> | ||
| 7 | 8 | ||
| 8 | /* | 9 | /* |
| 9 | * Implement paravirt qspinlocks; the general idea is to halt the vcpus instead | 10 | * Implement paravirt qspinlocks; the general idea is to halt the vcpus instead |
| @@ -286,15 +287,23 @@ __visible void __pv_queued_spin_unlock(struct qspinlock *lock) | |||
| 286 | { | 287 | { |
| 287 | struct __qspinlock *l = (void *)lock; | 288 | struct __qspinlock *l = (void *)lock; |
| 288 | struct pv_node *node; | 289 | struct pv_node *node; |
| 290 | u8 lockval = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0); | ||
| 289 | 291 | ||
| 290 | /* | 292 | /* |
| 291 | * We must not unlock if SLOW, because in that case we must first | 293 | * We must not unlock if SLOW, because in that case we must first |
| 292 | * unhash. Otherwise it would be possible to have multiple @lock | 294 | * unhash. Otherwise it would be possible to have multiple @lock |
| 293 | * entries, which would be BAD. | 295 | * entries, which would be BAD. |
| 294 | */ | 296 | */ |
| 295 | if (likely(cmpxchg(&l->locked, _Q_LOCKED_VAL, 0) == _Q_LOCKED_VAL)) | 297 | if (likely(lockval == _Q_LOCKED_VAL)) |
| 296 | return; | 298 | return; |
| 297 | 299 | ||
| 300 | if (unlikely(lockval != _Q_SLOW_VAL)) { | ||
| 301 | if (debug_locks_silent) | ||
| 302 | return; | ||
| 303 | WARN(1, "pvqspinlock: lock %p has corrupted value 0x%x!\n", lock, atomic_read(&lock->val)); | ||
| 304 | return; | ||
| 305 | } | ||
| 306 | |||
| 298 | /* | 307 | /* |
| 299 | * Since the above failed to release, this must be the SLOW path. | 308 | * Since the above failed to release, this must be the SLOW path. |
| 300 | * Therefore start by looking up the blocked node and unhashing it. | 309 | * Therefore start by looking up the blocked node and unhashing it. |
