Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e4006b3 authored by Gerald Schaefer's avatar Gerald Schaefer Committed by Martin Schwidefsky
Browse files

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: default avatarGerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent f1a85820
Loading
Loading
Loading
Loading
+8 −6
Original line number Original line Diff line number Diff line
@@ -26,19 +26,20 @@ __setup("spin_retry=", spin_retry_setup);


void arch_spin_lock_wait(arch_spinlock_t *lp)
void arch_spin_lock_wait(arch_spinlock_t *lp)
{
{
	int count = spin_retry;
	unsigned int cpu = SPINLOCK_LOCKVAL;
	unsigned int cpu = SPINLOCK_LOCKVAL;
	unsigned int owner;
	unsigned int owner;
	int count;


	while (1) {
	while (1) {
		owner = lp->lock;
		owner = lp->lock;
		if (!owner || smp_vcpu_scheduled(~owner)) {
		if (!owner || smp_vcpu_scheduled(~owner)) {
			for (count = spin_retry; count > 0; count--) {
			count = spin_retry;
			do {
				if (arch_spin_is_locked(lp))
				if (arch_spin_is_locked(lp))
					continue;
					continue;
				if (_raw_compare_and_swap(&lp->lock, 0, cpu))
				if (_raw_compare_and_swap(&lp->lock, 0, cpu))
					return;
					return;
			}
			} while (count-- > 0);
			if (MACHINE_IS_LPAR)
			if (MACHINE_IS_LPAR)
				continue;
				continue;
		}
		}
@@ -53,22 +54,23 @@ EXPORT_SYMBOL(arch_spin_lock_wait);


void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags)
void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags)
{
{
	int count = spin_retry;
	unsigned int cpu = SPINLOCK_LOCKVAL;
	unsigned int cpu = SPINLOCK_LOCKVAL;
	unsigned int owner;
	unsigned int owner;
	int count;


	local_irq_restore(flags);
	local_irq_restore(flags);
	while (1) {
	while (1) {
		owner = lp->lock;
		owner = lp->lock;
		if (!owner || smp_vcpu_scheduled(~owner)) {
		if (!owner || smp_vcpu_scheduled(~owner)) {
			for (count = spin_retry; count > 0; count--) {
			count = spin_retry;
			do {
				if (arch_spin_is_locked(lp))
				if (arch_spin_is_locked(lp))
					continue;
					continue;
				local_irq_disable();
				local_irq_disable();
				if (_raw_compare_and_swap(&lp->lock, 0, cpu))
				if (_raw_compare_and_swap(&lp->lock, 0, cpu))
					return;
					return;
				local_irq_restore(flags);
				local_irq_restore(flags);
			}
			} while (count-- > 0);
			if (MACHINE_IS_LPAR)
			if (MACHINE_IS_LPAR)
				continue;
				continue;
		}
		}