Skip to contentSkip to conversation

fix livelock in non atomic brlocks

PATCH New Anton Blanchard 1 participant 1 message Nov 15, 2001 Library code

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 fix livelock in non atomic brlocks

Hi,

One characteristic of brlocks is that you must be able to take recursive read locks (sparc64, ppc64 interrupt handling and netfilter make use of this property). On a 16 cpu ppc64 machine I have seen the following scenario:

cpu 1 (in br_write_lock)
again:

	spin_lock(&__br_write_locks[idx].lock);
		/* discover reader is present so backoff */
	spin_unlock(&__br_write_locks[idx].lock);
	goto again;

cpu 2 (in br_read_lock)
again:

	read_count++;
	mb();
	/* discover __br_write_locks[idx].lock is locked */
	read_count--;
	wmb();
	goto again;

If the read retry path is much slower than the write retry path (in this case mb(); read_count--; wmb(); is quite slow), then both cpus will spin forever and get nowhere.

We need to make sure the write retry path backs off long enough to ensure forward progress. A udelay(1) is a rather large hammer but a br_write_lock is known to be very slow and should not be called much.

Anton

lib/brlock.c +3 -1
@@ -14,6 +14,7 @@
 
 #include <linux/sched.h>
 #include <linux/brlock.h>
+#include <linux/delay.h>
 
 #ifdef __BRLOCK_USE_ATOMICS
 
@@ -54,7 +55,8 @@
 		if (__brlock_array[cpu_logical_map(i)][idx] != 0) {
 			spin_unlock(&__br_write_locks[idx].lock);
 			barrier();
-			cpu_relax();
+			/* We must allow recursive readers to make progress */
+			udelay(1);
 			goto again;
 		}
 }