diff options
author | Gerald Schaefer <gerald.schaefer@de.ibm.com> | 2014-05-06 21:41:36 +0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-05-20 10:58:52 +0400 |
commit | 2e4006b34d06681ed95d55510d4450f29a13c417 (patch) | |
tree | 0ff439559cfcfc2bac5eb1b41d6412694fd49a03 /arch/s390/lib | |
parent | f1a858206804a5a694f30196e50756b86eb7d68c (diff) | |
download | linux-2e4006b34d06681ed95d55510d4450f29a13c417.tar.xz |
s390/spinlock: fix system hang with spin_retry <= 0
On LPAR, when spin_retry is set to <= 0, arch_spin_lock_wait() and
arch_spin_lock_wait_flags() may end up in a while(1) loop w/o doing
any compare and swap operation. To fix this, use do/while instead of
for loop.
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/lib')
-rw-r--r-- | arch/s390/lib/spinlock.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index 3ca9de4d9cb9..3f0e682b7e62 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -26,19 +26,20 @@ __setup("spin_retry=", spin_retry_setup); void arch_spin_lock_wait(arch_spinlock_t *lp) { - int count = spin_retry; unsigned int cpu = SPINLOCK_LOCKVAL; unsigned int owner; + int count; while (1) { owner = lp->lock; if (!owner || smp_vcpu_scheduled(~owner)) { - for (count = spin_retry; count > 0; count--) { + count = spin_retry; + do { if (arch_spin_is_locked(lp)) continue; if (_raw_compare_and_swap(&lp->lock, 0, cpu)) return; - } + } while (count-- > 0); if (MACHINE_IS_LPAR) continue; } @@ -53,22 +54,23 @@ EXPORT_SYMBOL(arch_spin_lock_wait); void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags) { - int count = spin_retry; unsigned int cpu = SPINLOCK_LOCKVAL; unsigned int owner; + int count; local_irq_restore(flags); while (1) { owner = lp->lock; if (!owner || smp_vcpu_scheduled(~owner)) { - for (count = spin_retry; count > 0; count--) { + count = spin_retry; + do { if (arch_spin_is_locked(lp)) continue; local_irq_disable(); if (_raw_compare_and_swap(&lp->lock, 0, cpu)) return; local_irq_restore(flags); - } + } while (count-- > 0); if (MACHINE_IS_LPAR) continue; } |