s390/spinlock: fix system hang with spin_retry <= 0
authorGerald Schaefer <gerald.schaefer@de.ibm.com>
Tue, 6 May 2014 17:41:36 +0000 (19:41 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 20 May 2014 06:58:52 +0000 (08:58 +0200)
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>
arch/s390/lib/spinlock.c

index 3ca9de4..3f0e682 100644 (file)
@@ -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;
                }