wait_on_irq race condition? (and solution??)

Troy Benjegerdes hozer at drgw.net
Sun Aug 19 16:04:59 EST 2001


I've run into problems with 'wait_on_irq' where global_irq_count was 1,
but neither had anything in local_irq_count.

I think the race condition that Linus found that we ignore might actually
matter..

Anway, I made our irq.c look more like x86's, and it seems to have solved
the problem on my MTX so far.

Should I commit this to 2_4_devel?

--
Troy Benjegerdes | master of mispeeling | 'da hozer' |  hozer at drgw.net
-----"If this message isn't misspelled, I didn't write it" -- Me -----
"Why do musicians compose symphonies and poets write poems? They do it
because life wouldn't have any meaning for them if they didn't. That's
why I draw cartoons. It's my life." -- Charles Shulz
-------------- next part --------------
# This is a BitKeeper generated patch for the following project:
# Project Name: Linux 2.4
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.323   -> 1.324
#	arch/ppc/kernel/irq.c	1.34    -> 1.35
#	arch/ppc/kernel/ppc_ksyms.c	1.53    -> 1.54
#	include/asm-ppc/hardirq.h	1.13    -> 1.14
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 01/08/19	hozer at narn.(none)	1.324
# Fix what seems to be a subtle race in wait_on_irq
# --------------------------------------------
#
diff -Nru a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
--- a/arch/ppc/kernel/irq.c	Sun Aug 19 00:55:33 2001
+++ b/arch/ppc/kernel/irq.c	Sun Aug 19 00:55:33 2001
@@ -592,7 +592,6 @@
 #ifdef CONFIG_SMP
 unsigned char global_irq_holder = NO_PROC_ID;
 unsigned volatile long global_irq_lock; /* pendantic :long for set_bit--RR*/
-atomic_t global_irq_count;

 atomic_t global_bh_count;

@@ -603,8 +602,7 @@
 	int cpu = smp_processor_id();

 	printk("\n%s, CPU %d:\n", str, cpu);
-	printk("irq:  %d [%d %d]\n",
-	       atomic_read(&global_irq_count),
+	printk("irq:  [%d %d]\n",
 	       local_irq_count(0),
 	       local_irq_count(1));
 	printk("bh:   %d [%d %d]\n",
@@ -644,11 +642,9 @@
 		 * for bottom half handlers unless we're
 		 * already executing in one..
 		 */
-		if (!atomic_read(&global_irq_count)) {
-			if (local_bh_count(cpu)
-			    || !atomic_read(&global_bh_count))
-				break;
-		}
+		if (!irqs_running())
+			if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock))
+					break;

 		/* Duh, we have to loop. Release the lock to avoid deadlocks */
 		clear_bit(0,&global_irq_lock);
@@ -656,19 +652,18 @@
 		for (;;) {
 			if (!--count) {
 				show("wait_on_irq");
-				count = ~0;
+				count = MAXCOUNT;
+				xmon(0);
 			}
 			__sti();
-			/* don't worry about the lock race Linus found
-			 * on intel here. -- Cort
-			 */
+			/* We have to allow irqs to arrive between __sti and __cli */
+			__asm__ __volatile__ ("nop")
 			__cli();
-			if (atomic_read(&global_irq_count))
+			if (irqs_running())
 				continue;
 			if (global_irq_lock)
 				continue;
-			if (!local_bh_count(cpu)
-			    && atomic_read(&global_bh_count))
+			if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock))
 				continue;
 			if (!test_and_set_bit(0,&global_irq_lock))
 				break;
@@ -699,7 +694,7 @@
  */
 void synchronize_irq(void)
 {
-	if (atomic_read(&global_irq_count)) {
+	if (irqs_running()) {
 		/* Stupid approach */
 		cli();
 		sti();
diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c	Sun Aug 19 00:55:33 2001
+++ b/arch/ppc/kernel/ppc_ksyms.c	Sun Aug 19 00:55:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
+ * BK Id: SCCS/s.ppc_ksyms.c 1.53 08/17/01 12:19:59 trini
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -193,7 +193,6 @@
 #endif /* CONFIG_ALTIVEC */
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(global_irq_lock);
-EXPORT_SYMBOL(global_irq_count);
 EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
@@ -204,10 +203,10 @@
 EXPORT_SYMBOL(_spin_unlock);
 EXPORT_SYMBOL(spin_trylock);
 #endif
-EXPORT_SYMBOL(_read_lock);
-EXPORT_SYMBOL(_read_unlock);
-EXPORT_SYMBOL(_write_lock);
-EXPORT_SYMBOL(_write_unlock);
+EXPORT_SYMBOL(read_lock);
+EXPORT_SYMBOL(read_unlock);
+EXPORT_SYMBOL(write_lock);
+EXPORT_SYMBOL(write_unlock);
 EXPORT_SYMBOL(smp_call_function);
 EXPORT_SYMBOL(smp_hw_index);
 EXPORT_SYMBOL(smp_num_cpus);
diff -Nru a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h
--- a/include/asm-ppc/hardirq.h	Sun Aug 19 00:55:33 2001
+++ b/include/asm-ppc/hardirq.h	Sun Aug 19 00:55:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
+ * BK Id: SCCS/s.hardirq.h 1.13 07/18/01 20:18:42 %#%
  */
 #ifdef __KERNEL__
 #ifndef __ASM_HARDIRQ_H
@@ -52,6 +52,16 @@
 extern unsigned char global_irq_holder;
 extern unsigned volatile long global_irq_lock;
 extern atomic_t global_irq_count;
+
+static inline int irqs_running (void)
+{
+	int i;
+
+	for (i = 0; i < smp_num_cpus; i++)
+		if (local_irq_count(i))
+			return 1;
+		return 0;
+}

 static inline void release_irqlock(int cpu)
 {


More information about the Linuxppc-dev mailing list