[patch] "big IRQ lock" removal, 2.5.27-A7

Ingo Molnar
2002-07-21T20:58:02Z

the arch/i386/kernel/vm86.c hacks are fixed now as well:

http://redhat.com/~mingo/remove-irqlock-patches/remove-irqlock-2.5.27-A7

this was relatively simple, the irqbits global variable needed to be
protected by a global spinlock. I found no other global locking assumption
in the code. In fact there was even a small bug in the code - if
free_vm86_irq() was called outside of the global IRQ lock then there's a
irqbits corruption window in free_vm87_irq() - this is true even though
that particular IRQ source will not interfere - it's other IRQ sources
that might change the irqbits variable. The patch fixes this.

this was the last remaining x86 usage of cli()/sti().

Ingo

--- linux/arch/i386/kernel/vm86.c.orig Sun Jun 9 07:27:22 2002
+++ linux/arch/i386/kernel/vm86.c Sun Jul 21 22:55:57 2002
@@ -571,6 +571,8 @@
struct task_struct *tsk;
int sig;
} vm86_irqs[16];
+
+static spinlock_t irqbits_lock = SPIN_LOCK_UNLOCKED;
static int irqbits;

#define ALLOWED_SIGS ( 1 /* 0 = don't send a signal */ \
@@ -580,9 +582,8 @@
static void irq_handler(int intno, void *dev_id, struct pt_regs * regs) {
int irq_bit;
unsigned long flags;
-
- save_flags(flags);
- cli();
+
+ spin_lock_irqsave(&irqbits_lock, flags);
irq_bit = 1 << intno;
if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk)
goto out;
@@ -591,14 +592,19 @@
send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1);
/* else user will poll for IRQs */
out:
- restore_flags(flags);
+ spin_unlock_irqrestore(&irqbits_lock, flags);
}

static inline void free_vm86_irq(int irqnumber)
{
+ unsigned long flags;
+
free_irq(irqnumber,0);
vm86_irqs[irqnumber].tsk = 0;
+
+ spin_lock_irqsave(&irqbits_lock, flags);
irqbits &= ~(1 << irqnumber);
+ spin_unlock_irqrestore(&irqbits_lock, flags);
}

static inline int task_valid(struct task_struct *tsk)
@@ -635,11 +641,10 @@

if ( (irqnumber<3) || (irqnumber>15) ) return 0;
if (vm86_irqs[irqnumber].tsk != current) return 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&irqbits_lock, flags);
bit = irqbits & (1 << irqnumber);
irqbits &= ~bit;
- restore_flags(flags);
+ spin_unlock_irqrestore(&irqbits_lock, flags);
return bit;
}