]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] irqlock patch 2.5.27-H6
authorIngo Molnar <mingo@elte.hu>
Wed, 24 Jul 2002 03:04:01 +0000 (20:04 -0700)
committerIngo Molnar <mingo@elte.hu>
Wed, 24 Jul 2002 03:04:01 +0000 (20:04 -0700)
 - init thread needs to have preempt_count of 1 until sched_init().
   (William Lee Irwin III)
 - clean up the irq-mask macros. (Linus)
 - add barrier() to irq_enter() and irq_exit(). (based on Oleg Nesterov's
   comment.)
 - move the irqs-off check into preempt_schedule() and remove
   CONFIG_DEBUG_IRQ_SCHEDULE.
 - remove spin_unlock_no_resched() and comment the affected places more
   agressively.
 - slab.c needs to spin_unlock_no_resched(), instead of spin_unlock(). (It
   also has to check for preemption in the right spot.) This should fix
   the memory corruption.
 - irq_exit() needs to run softirqs if interrupts not active - in the
   previous patch it ran them when preempt_count() was 0, which is
   incorrect.
 - spinlock macros are updated to enable preemption after enabling
   interrupts. Besides avoiding false positive warnings, this also
 - fork.c has to call scheduler_tick() with preemption disabled -
   otherwise scheduler_tick()'s spin_unlock can preempt!
 - irqs_disabled() macro introduced.
 - [ all other local_irq_enable() or sti instances conditional on
     CONFIG_DEBUG_IRQ_SCHEDULE are to fix false positive warnings. ]
 - fix buggy in_softirq(). Fortunately the bug made the test broader,
   which didnt result in algorithmical breakage, just suboptimal
   performance.
 - move do_softirq() processing into irq_exit() => this also fixes the
   softirq processing bugs present in apic.c IRQ handlers that did not
   test for softirqs after irq_exit().
 - simplify local_bh_enable().

36 files changed:
arch/i386/kernel/apic.c
arch/i386/kernel/entry.S
arch/i386/kernel/irq.c
arch/i386/kernel/mtrr.c
arch/i386/kernel/smp.c
arch/i386/pci/direct.c
arch/i386/pci/pcbios.c
drivers/char/tty_io.c
drivers/char/vt.c
drivers/ide/main.c
drivers/input/joystick/a3d.c
drivers/input/joystick/adi.c
drivers/input/joystick/analog.c
drivers/input/joystick/cobra.c
drivers/input/joystick/gamecon.c
drivers/input/joystick/gf2k.c
drivers/input/joystick/grip.c
drivers/input/joystick/guillemot.c
drivers/input/joystick/interact.c
drivers/input/joystick/sidewinder.c
drivers/input/joystick/tmdc.c
drivers/net/acenic.c
drivers/s390/char/tubio.h
drivers/s390/cio/s390io.c
drivers/s390/s390mach.c
fs/buffer.c
include/asm-i386/hardirq.h
include/asm-i386/softirq.h
include/asm-i386/system.h
include/asm-i386/thread_info.h
include/linux/spinlock.h
kernel/fork.c
kernel/sched.c
mm/slab.c
net/core/skbuff.c
sound/oss/esssolo1.c

index 19f45080e906c0b6971f1f529ca3f0ebe95e1d2f..d1abf23f0133f37c7e6d45509b67bc9cd076000c 100644 (file)
@@ -485,8 +485,7 @@ static void apic_pm_suspend(void *data)
        apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
        apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
        
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        disable_local_APIC();
        rdmsr(MSR_IA32_APICBASE, l, h);
        l &= ~MSR_IA32_APICBASE_ENABLE;
@@ -499,8 +498,7 @@ static void apic_pm_resume(void *data)
        unsigned int l, h;
        unsigned long flags;
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        rdmsr(MSR_IA32_APICBASE, l, h);
        l &= ~MSR_IA32_APICBASE_BASE;
        l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
@@ -1087,9 +1085,6 @@ void smp_apic_timer_interrupt(struct pt_regs regs)
        irq_enter();
        smp_local_timer_interrupt(&regs);
        irq_exit();
-
-       if (softirq_pending(cpu))
-               do_softirq();
 }
 
 /*
index 641062bbcbf201c64bd91ce941ef32c3ac6d0a67..f10564893337a23cd361a9468fda2ae7089a30a1 100644 (file)
@@ -185,8 +185,10 @@ ENTRY(ret_from_fork)
 
        # userspace resumption stub bypassing syscall exit tracing
        ALIGN
-ret_from_intr:
 ret_from_exception:
+       preempt_stop
+ret_from_intr:
+       GET_THREAD_INFO(%ebx)
        movl EFLAGS(%esp), %eax         # mix EFLAGS and CS
        movb CS(%esp), %al
        testl $(VM_MASK | 3), %eax
@@ -262,7 +264,7 @@ work_resched:
 
 work_notifysig:                                # deal with pending signals and
                                        # notify-resume requests
-       testl $(VM_MASK),EFLAGS(%esp)
+       testl $VM_MASK, EFLAGS(%esp)
        movl %esp, %eax
        jne work_notifysig_v86          # returning to kernel-space or
                                        # vm86-space
@@ -333,14 +335,12 @@ vector=vector+1
 common_interrupt:
        SAVE_ALL
        call do_IRQ
-       GET_THREAD_INFO(%ebx)
        jmp ret_from_intr
 
 #define BUILD_INTERRUPT(name, nr)      \
 ENTRY(name)                            \
        pushl $nr-256;                  \
        SAVE_ALL                        \
-       GET_THREAD_INFO(%ebx);          \
        call smp_/**/name;      \
        jmp ret_from_intr;
 
@@ -400,10 +400,8 @@ error_code:
        movl $(__KERNEL_DS), %edx
        movl %edx, %ds
        movl %edx, %es
-       GET_THREAD_INFO(%ebx)
        call *%edi
        addl $8, %esp
-       preempt_stop
        jmp ret_from_exception
 
 ENTRY(coprocessor_error)
@@ -430,7 +428,6 @@ device_not_available_emulate:
        pushl $0                        # temporary storage for ORIG_EIP
        call math_emulate
        addl $4, %esp
-       preempt_stop
        jmp ret_from_exception
 
 ENTRY(debug)
index 7acd3f1417b974412a8a29666865bd69a056dbf6..85c360b3db51547c8ce9452b9d71cefdae7ef14d 100644 (file)
@@ -187,6 +187,10 @@ int show_interrupts(struct seq_file *p, void *v)
 #if CONFIG_SMP
 inline void synchronize_irq(unsigned int irq)
 {
+       /* is there anything to synchronize with? */
+       if (!irq_desc[irq].action)
+               return;
+
        while (irq_desc[irq].status & IRQ_INPROGRESS)
                cpu_relax();
 }
@@ -392,8 +396,6 @@ out:
 
        irq_exit();
 
-       if (softirq_pending(cpu))
-               do_softirq();
        return 1;
 }
 
index 1ce749174636d4b227015ef15b9bde67b6e14b79..05eb8e9d7e661ab59b490fc01bcd4cb54c80d959 100644 (file)
@@ -381,7 +381,7 @@ static int arr3_protected;
 static void set_mtrr_prepare_save (struct set_mtrr_context *ctxt)
 {
     /*  Disable interrupts locally  */
-    local_save_flags (ctxt->flags); local_irq_disable ();
+    local_irq_save(ctxt->flags);
 
     if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR )
         return;
@@ -546,7 +546,7 @@ static void cyrix_get_arr (unsigned int reg, unsigned long *base,
     arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
 
     /* Save flags and disable interrupts */
-    local_save_flags (flags); local_irq_disable ();
+    local_irq_save(flags);
 
     ccr3 = getCx86 (CX86_CCR3);
     setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10);         /* enable MAPEN */
index d762d602a0b1c83d9dad3a96701da24bfe3cdd9f..8c903feb9bb4b0c9ce3253b796e1436109a86503 100644 (file)
@@ -161,9 +161,7 @@ static inline void send_IPI_mask_bitmask(int mask, int vector)
        unsigned long cfg;
        unsigned long flags;
 
-       local_save_flags(flags);
-       local_irq_disable();
-
+       local_irq_save(flags);
                
        /*
         * Wait for idle.
@@ -200,8 +198,7 @@ static inline void send_IPI_mask_sequence(int mask, int vector)
         * should be modified to do 1 message per cluster ID - mbligh
         */ 
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
 
        for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
                query_mask = 1 << query_cpu;
index ea4f3c51f37729cdd6cfdfceb1d67bf61b78f85a..2e443ea074f919557574a4d185ed7ee3273d71ea 100644 (file)
@@ -306,7 +306,7 @@ static struct pci_ops * __devinit pci_check_direct(void)
        unsigned int tmp;
        unsigned long flags;
 
-       local_save_flags(flags); local_irq_disable();
+       local_irq_save(flags);
 
        /*
         * Check if configuration type 1 works.
index ccf3c2b090dacac420bddd9ec7dd347096e50077..d625ff6c07de335679fc13174a5647d589ce82a9 100644 (file)
@@ -82,7 +82,7 @@ static unsigned long bios32_service(unsigned long service)
        unsigned long entry;            /* %edx */
        unsigned long flags;
 
-       local_save_flags(flags); local_irq_disable();
+       local_irq_save(flags);
        __asm__("lcall *(%%edi); cld"
                : "=a" (return_code),
                  "=b" (address),
@@ -122,7 +122,7 @@ static int __devinit check_pcibios(void)
        if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
                pci_indirect.address = pcibios_entry + PAGE_OFFSET;
 
-               local_save_flags(flags); local_irq_disable();
+               local_irq_save(flags);
                __asm__(
                        "lcall *(%%edi); cld\n\t"
                        "jc 1f\n\t"
index f8ee5491cce2ff5c34b7707a3012fa57da89f92d..269abc0905140dc2a085ab17d177d2dfb7cdab94 100644 (file)
@@ -460,7 +460,7 @@ void do_tty_hangup(void *data)
        {
                unsigned long flags;
 
-               local_save_flags(flags); local_irq_disable(); // FIXME: is this safe?
+               local_irq_save(flags); // FIXME: is this safe?
                if (tty->ldisc.flush_buffer)
                        tty->ldisc.flush_buffer(tty);
                if (tty->driver.flush_buffer)
@@ -1900,7 +1900,7 @@ static void flush_to_ldisc(void *private_)
                fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
                tty->flip.buf_num = 0;
 
-               local_save_flags(flags); local_irq_disable(); // FIXME: is this safe?
+               local_irq_save(flags); // FIXME: is this safe?
                tty->flip.char_buf_ptr = tty->flip.char_buf;
                tty->flip.flag_buf_ptr = tty->flip.flag_buf;
        } else {
@@ -1908,7 +1908,7 @@ static void flush_to_ldisc(void *private_)
                fp = tty->flip.flag_buf;
                tty->flip.buf_num = 1;
 
-               local_save_flags(flags); local_irq_disable(); // FIXME: is this safe?
+               local_irq_save(flags); // FIXME: is this safe?
                tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
                tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
        }
index bee0db2bc75820049e2594addbe7ae9258ea6a77..2aa987b15c407a8712881fc5b847c758c656f52d 100644 (file)
@@ -113,8 +113,7 @@ _kd_mksound(unsigned int hz, unsigned int ticks)
        if (hz > 20 && hz < 32767)
                count = 1193180 / hz;
        
-       local_save_flags(flags); // FIXME: is this safe?
-       local_irq_disable();
+       local_irq_save(flags); // FIXME: is this safe?
        del_timer(&sound_timer);
        if (count) {
                /* enable counter 2 */
index d1052495e97c597dd9ee6985f834b460b416ff03..890e5e14b1f71efc1bf65832ff07a6e20cb478aa 100644 (file)
@@ -1082,28 +1082,19 @@ int ide_unregister_subdriver(struct ata_device *drive)
 {
        unsigned long flags;
 
-       local_save_flags(flags); // FIXME: is this safe?
-       local_irq_disable();
-
 #if 0
-       if (__MOD_IN_USE(ata_ops(drive)->owner)) {
-               local_irq_restore(flags); // FIXME: is this safe?
+       if (__MOD_IN_USE(ata_ops(drive)->owner))
                return 1;
-       }
 #endif
 
-       if (drive->usage || drive->busy || !ata_ops(drive)) {
-               local_irq_restore(flags);       // FIXME: is this safe?
+       if (drive->usage || drive->busy || !ata_ops(drive))
                return 1;
-       }
 
 #if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
        pnpide_init(0);
 #endif
        drive->driver = NULL;
 
-       local_irq_restore(flags); // FIXME: is this safe?
-
        return 0;
 }
 
index 945eecc05120dea2dd2f7138b1af3908bf1d2f6c..b5e0f8911cc2df7045630e8cef7bbd3f01e41d99 100644 (file)
@@ -84,8 +84,7 @@ static int a3d_read_packet(struct gameport *gameport, int length, char *data)
        t = gameport_time(gameport, A3D_MAX_START);
        s = gameport_time(gameport, A3D_MAX_STROBE);
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        gameport_trigger(gameport);
        v = gameport_read(gameport);
 
index 4ad09c0f2bf577e84d9219772da2872605985e53..e0f070343acd44d10025670284584bd527b199a6 100644 (file)
@@ -152,8 +152,7 @@ static void adi_read_packet(struct adi_port *port)
                s[i] = 0;
        }
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
 
        gameport_trigger(gameport);
        v = z = gameport_read(gameport);
index f091805b3ea7f33af7c657f6196d9de94ce6bb83..88521c7e0cb3a5d1d975a8e0e8eb87a3dc5d0429 100644 (file)
@@ -232,8 +232,7 @@ static int analog_cooked_read(struct analog_port *port)
        loopout = (ANALOG_LOOP_TIME * port->loop) / 1000;
        timeout = ANALOG_MAX_TIME * port->speed;
        
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        gameport_trigger(gameport);
        GET_TIME(now);
        local_irq_restore(flags);
index eafdca07c3810b2073a80419c6e3f77c270ba554..85312ccfdeb0e2afc6b166c8c1841f53e15a9a35 100644 (file)
@@ -73,8 +73,7 @@ static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *
                t[i] = COBRA_MAX_STROBE;
        }
        
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
 
        u = gameport_read(gameport);
 
index d8d58db2e230356d565f5a8b061abd5e41f45de2..17e743db6cbec031d5a6825284d27c53af4f4513 100644 (file)
@@ -113,8 +113,7 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
  * Request the pad to transmit data
  */
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
                parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
                udelay(GC_N64_DWS);
@@ -270,8 +269,7 @@ static int gc_psx_read_packet(struct gc *gc, unsigned char *data)
        parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);                  /* Deselect, begin command */
        udelay(GC_PSX_DELAY * 2);
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
 
        gc_psx_command(gc, 0x01);                                                       /* Access pad */
        id = gc_psx_command(gc, 0x42);                                                  /* Get device id */
index 8bd3c5a3e7c6c862d43e12cc2b9eead32b74e553..b303fa7a20e853f773b09a50de15dd8ee9cc4b01 100644 (file)
@@ -106,8 +106,7 @@ static int gf2k_read_packet(struct gameport *gameport, int length, char *data)
 
        i = 0;
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
 
        gameport_trigger(gameport);
        v = gameport_read(gameport);;
@@ -137,8 +136,7 @@ static void gf2k_trigger_seq(struct gameport *gameport, short *seq)
        unsigned long flags;
        int i, t;
 
-        local_save_flags(flags);
-        local_irq_disable();
+        local_irq_save(flags);
 
        i = 0;
         do {
index da806f47320f00cc75385a2289d7632f968621cb..d16a810325482fac4ad7015dcb0694e608cd06b0 100644 (file)
@@ -98,8 +98,7 @@ static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned i
        t = strobe;
        i = 0;
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
 
        v = gameport_read(gameport) >> shift;
 
@@ -140,8 +139,7 @@ static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned in
        status = buf = i = j = 0;
        t = strobe;
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
 
        v = w = (gameport_read(gameport) >> shift) & 3;
 
index 2a4903fe4d2141a9e73e1298a3e28b325ed1b461..b287829b0e1e4905d4ae05ab453b93d18f497b54 100644 (file)
@@ -98,8 +98,7 @@ static int guillemot_read_packet(struct gameport *gameport, u8 *data)
        t = gameport_time(gameport, GUILLEMOT_MAX_START);
        s = gameport_time(gameport, GUILLEMOT_MAX_STROBE);
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        gameport_trigger(gameport);
        v = gameport_read(gameport);
 
index edb606a33bc2757a1d1487751638ff3fbec61d92..039bf72e7ba33b9c0afcb66475f319abe9ac7e2b 100644 (file)
@@ -103,8 +103,7 @@ static int interact_read_packet(struct gameport *gameport, int length, u32 *data
        t = gameport_time(gameport, INTERACT_MAX_START);
        s = gameport_time(gameport, INTERACT_MAX_STROBE);
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        gameport_trigger(gameport);
        v = gameport_read(gameport);
 
index 0bc0f403f62515d4cf51d445f422739b75b3b9d8..5195927248908f490aacfa7b42d7b0d0402e3863 100644 (file)
@@ -149,8 +149,7 @@ static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int len
        pending = 0;
        sched = 0;
 
-        local_save_flags(flags);                                       /* Quiet, please */
-        local_irq_disable();
+        local_irq_save(flags);                                 /* Quiet, please */
 
        gameport_trigger(gameport);                             /* Trigger */
        v = gameport_read(gameport);
@@ -245,8 +244,7 @@ static void sw_init_digital(struct gameport *gameport)
        unsigned long flags;
        int i, t;
 
-        local_save_flags(flags);
-        local_irq_disable();
+        local_irq_save(flags);
 
        i = 0;
         do {
index fa3efbeae1e394dd37e90c6b79f5763d92ebe4cd..11eb335e5362a423f57711a5d9cbbc02e2d74aaa 100644 (file)
@@ -125,8 +125,7 @@ static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMD
                i[k] = j[k] = 0;
        }
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        gameport_trigger(gameport);
        
        w = gameport_read(gameport) >> 4;
index dfe2f73298b353a987ecfb7e6c9ef09054ff673c..626de1f0a6d3b4bbf1b9d275226a30290bcc8ce4 100644 (file)
@@ -3389,8 +3389,7 @@ static int __init read_eeprom_byte(struct net_device *dev,
         * Don't take interrupts on this CPU will bit banging
         * the %#%#@$ I2C device
         */
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
 
        eeprom_start(regs);
 
index e9a6d04cfd8c99a2337a6369ed2869edc18a3174..51c66392ace3d6384c52cf60def9dc00ea988ee0 100644 (file)
@@ -338,8 +338,7 @@ extern void fs3270_devfs_unregister(tub_t *);
 #define spin_trylock_irqsave(lock, flags) \
 ({ \
        int success; \
-       local_save_flags(flags); \
-       local_irq_disable(); \
+       local_irq_save(flags); \
        success = spin_trylock(lock); \
        if (success == 0) \
                local_irq_restore(flags); \
index 1e4e0fac63ec1979f1425cca1ffaf7c944ac5c7e..7524a6323e4c5b8d01f674e4926cc0c16fb284f9 100644 (file)
@@ -163,11 +163,10 @@ s390_init_IRQ (void)
         *  function we resestablish the old environment.
         *
         * Note : as we don't need a system wide lock, therefore
-        *        we shouldn't use cli(), but local_irq_disable() as this
+        *        we shouldn't use cli(), but local_irq_save() as this
         *        affects the current CPU only.
         */
-       local_save_flags (flags);
-       local_irq_disable ();
+       local_irq_save(flags);
 
        /*
         * disable all interrupts
@@ -578,10 +577,9 @@ read_dev_chars (int irq, void **buffer, int length)
         *   also require to run disabled.
         *
         * Note : as no global lock is required, we must not use
-        *        cli(), but local_irq_disable() instead.   
+        *        cli(), but local_irq_save() instead.   
         */
-       local_save_flags (flags);
-       local_irq_disable ();
+       local_irq_save(flags);
 
        rdc_ccw = &ioinfo[irq]->senseccw;
 
@@ -720,8 +718,7 @@ read_conf_data (int irq, void **buffer, int *length, __u8 lpm)
                int emulated = 0;       /* no i/O handler installed */
                int retry = 5;  /* retry count */
 
-               local_save_flags (flags);
-               local_irq_disable ();
+               local_irq_save(flags);
 
                if (!ioinfo[irq]->ui.flags.ready) {
                        pdevstat = &devstat;
index 6cbd8545ebbaf3cf0e508caf1874486bebece09a..234a21ad851afbb9f26c650166e807ada6d14fa7 100644 (file)
@@ -254,8 +254,7 @@ s390_machine_check_handler(void *parm)
 
                found = 0;      /* init ... */
 
-               local_save_flags(flags);
-               local_irq_disable();
+               local_irq_save(flags);
 
                do {
 
index 107d4409a926e644cc68655e71b1de0dac282869..cde52fee66a43b748ca95d3a98a62efb77005e18 100644 (file)
@@ -62,10 +62,7 @@ void __buffer_error(char *file, int line)
        printk("buffer layer error at %s:%d\n", file, line);
 #ifdef CONFIG_X86
        printk("Pass this trace through ksymoops for reporting\n");
-       {
-               extern void show_stack(long *esp);
-               show_stack(0);
-       }
+       show_stack(0);
 #endif
 }
 EXPORT_SYMBOL(__buffer_error);
index cbd78d1dcaa17e702ebac8cb93f33fa67695a8aa..5629c508f99afd3bb589b70a72d0d1210d281960 100644 (file)
@@ -16,22 +16,81 @@ typedef struct {
 
 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
 
-#define IRQ_OFFSET 64
+/*
+ * We put the hardirq and softirq counter into the preemption
+ * counter. The bitmask has the following meaning:
+ *
+ * - bits 0-7 are the preemption count (max preemption depth: 256)
+ * - bits 8-15 are the softirq count (max # of softirqs: 256)
+ * - bits 16-23 are the hardirq count (max # of hardirqs: 256)
+ *
+ * - ( bit 26 is the PREEMPT_ACTIVE flag. )
+ *
+ * PREEMPT_MASK: 0x000000ff
+ * HARDIRQ_MASK: 0x0000ff00
+ * SOFTIRQ_MASK: 0x00ff0000
+ * IRQ_MASK:     0x00ffff00
+ */
+
+#define PREEMPT_BITS   8
+#define SOFTIRQ_BITS   8
+#define HARDIRQ_BITS   8
+
+#define PREEMPT_SHIFT  0
+#define SOFTIRQ_SHIFT  (PREEMPT_SHIFT + PREEMPT_BITS)
+#define HARDIRQ_SHIFT  (SOFTIRQ_SHIFT + SOFTIRQ_BITS)
+
+#define __MASK(x)      ((1UL << (x))-1)
+
+#define PREEMPT_MASK   (__MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
+#define HARDIRQ_MASK   (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
+#define SOFTIRQ_MASK   (__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
+
+#define hardirq_count()        (preempt_count() & HARDIRQ_MASK)
+#define softirq_count()        (preempt_count() & SOFTIRQ_MASK)
+#define irq_count()    (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))
+
+#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT)
+#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT)
+#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT)
+
+#define IRQ_MASK       (HARDIRQ_MASK | SOFTIRQ_MASK)
+
+/*
+ * The hardirq mask has to be large enough to have
+ * space for potentially all IRQ sources in the system
+ * nesting on a single CPU:
+ */
+#if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+#endif
 
 /*
- * Are we in an interrupt context? Either doing bottom half
- * or hardware interrupt processing?
+ * Are we doing bottom half or hardware interrupt processing?
+ * Are we in a softirq context? Interrupt context?
  */
-#define in_interrupt() \
-               ((preempt_count() & ~PREEMPT_ACTIVE) >= IRQ_OFFSET)
+#define in_irq()               (hardirq_count())
+#define in_softirq()           (softirq_count())
+#define in_interrupt()         (irq_count())
 
-#define in_irq in_interrupt
 
 #define hardirq_trylock()      (!in_interrupt())
 #define hardirq_endlock()      do { } while (0)
 
-#define irq_enter()            (preempt_count() += IRQ_OFFSET)
-#define irq_exit()             (preempt_count() -= IRQ_OFFSET)
+#define irq_enter()            (preempt_count() += HARDIRQ_OFFSET)
+
+#if CONFIG_PREEMPT
+# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
+#else
+# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
+#endif
+#define irq_exit()                                                     \
+do {                                                                   \
+               preempt_count() -= IRQ_EXIT_OFFSET;                     \
+               if (!in_interrupt() && softirq_pending(smp_processor_id())) \
+                       do_softirq();                                   \
+               preempt_enable_no_resched();                            \
+} while (0)
 
 #ifndef CONFIG_SMP
 # define synchronize_irq(irq)  barrier()
@@ -39,4 +98,6 @@ typedef struct {
   extern void synchronize_irq(unsigned int irq);
 #endif /* CONFIG_SMP */
 
+extern void show_stack(unsigned long * esp);
+
 #endif /* __ASM_HARDIRQ_H */
index c28019d821af5e3d6fba8fece199e57b7721fe44..d944be956a25a66a29668eb6008f0867f25e550f 100644 (file)
@@ -5,23 +5,16 @@
 #include <asm/hardirq.h>
 
 #define local_bh_disable() \
-               do { preempt_count() += IRQ_OFFSET; barrier(); } while (0)
+               do { preempt_count() += SOFTIRQ_OFFSET; barrier(); } while (0)
 #define __local_bh_enable() \
-               do { barrier(); preempt_count() -= IRQ_OFFSET; } while (0)
+               do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0)
 
 #define local_bh_enable()                                              \
 do {                                                                   \
-       if (unlikely((preempt_count() == IRQ_OFFSET) &&                 \
-                               softirq_pending(smp_processor_id()))) { \
-               __local_bh_enable();                                    \
+       __local_bh_enable();                                            \
+       if (unlikely(!in_interrupt() && softirq_pending(smp_processor_id()))) \
                do_softirq();                                           \
-               preempt_check_resched();                                \
-       } else {                                                        \
-               __local_bh_enable();                                    \
-               preempt_check_resched();                                \
-       }                                                               \
+       preempt_check_resched();                                        \
 } while (0)
 
-#define in_softirq() in_interrupt()
-
 #endif /* __ASM_SOFTIRQ_H */
index d10a7622384141e7a303f5a53baa2d5a75af5229..b5bfa022bde766bc05bbbd4499dca5383281d49a 100644 (file)
@@ -318,19 +318,16 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 /* used in the idle loop; sti takes one instruction cycle to complete */
 #define safe_halt()            __asm__ __volatile__("sti; hlt": : :"memory")
 
+#define irqs_disabled()                        \
+({                                     \
+       unsigned long flags;            \
+       local_save_flags(flags);        \
+       !(flags & (1<<9));              \
+})
+
 /* For spinlocks etc */
 #define local_irq_save(x)      __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
 
-/*
- * Compatibility macros - they will be removed after some time.
- */
-#if !CONFIG_SMP
-# define sti() local_irq_enable()
-# define cli() local_irq_disable()
-# define save_flags(flags) local_save_flags(flags)
-# define restore_flags(flags) local_irq_restore(flags)
-#endif
-
 /*
  * disable hlt during certain critical i/o operations
  */
index 5673b1cdc6a4a910c09e5e1a319251f4781f15eb..d8a2f6c4d2edd1a612a46b5b6a8c9464f4779d69 100644 (file)
@@ -51,6 +51,8 @@ struct thread_info {
 
 /*
  * macros/functions for gaining access to the thread information structure
+ *
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 #define INIT_THREAD_INFO(tsk)                  \
@@ -59,6 +61,7 @@ struct thread_info {
        exec_domain:    &default_exec_domain,   \
        flags:          0,                      \
        cpu:            0,                      \
+       preempt_count:  1,                      \
        addr_limit:     KERNEL_DS,              \
 }
 
index d9f4af4103e48c1c1083d3b1b6b0aa093c35b3c4..749d3054b2dc3cd11be09b6125329968531b3a9e 100644 (file)
 #define write_lock_irq(lock)                   do { local_irq_disable();        write_lock(lock); } while (0)
 #define write_lock_bh(lock)                    do { local_bh_disable();         write_lock(lock); } while (0)
 
-#define spin_unlock_irqrestore(lock, flags)    do { spin_unlock(lock);  local_irq_restore(flags); } while (0)
+#define spin_unlock_irqrestore(lock, flags)    do { _raw_spin_unlock(lock);  local_irq_restore(flags); preempt_enable(); } while (0)
 #define _raw_spin_unlock_irqrestore(lock, flags) do { _raw_spin_unlock(lock);  local_irq_restore(flags); } while (0)
-#define spin_unlock_irq(lock)                  do { spin_unlock(lock);  local_irq_enable();       } while (0)
-#define spin_unlock_bh(lock)                   do { spin_unlock(lock);  local_bh_enable();        } while (0)
+#define spin_unlock_irq(lock)                  do { _raw_spin_unlock(lock);  local_irq_enable(); preempt_enable();       } while (0)
+#define spin_unlock_bh(lock)                   do { spin_unlock(lock); local_bh_enable(); } while (0)
 
-#define read_unlock_irqrestore(lock, flags)    do { read_unlock(lock);  local_irq_restore(flags); } while (0)
-#define read_unlock_irq(lock)                  do { read_unlock(lock);  local_irq_enable();       } while (0)
+#define read_unlock_irqrestore(lock, flags)    do { _raw_read_unlock(lock);  local_irq_restore(flags); preempt_enable(); } while (0)
+#define read_unlock_irq(lock)                  do { _raw_read_unlock(lock);  local_irq_enable(); preempt_enable(); } while (0)
 #define read_unlock_bh(lock)                   do { read_unlock(lock);  local_bh_enable();        } while (0)
 
-#define write_unlock_irqrestore(lock, flags)   do { write_unlock(lock); local_irq_restore(flags); } while (0)
-#define write_unlock_irq(lock)                 do { write_unlock(lock); local_irq_enable();       } while (0)
+#define write_unlock_irqrestore(lock, flags)   do { _raw_write_unlock(lock); local_irq_restore(flags); preempt_enable(); } while (0)
+#define write_unlock_irq(lock)                 do { _raw_write_unlock(lock); local_irq_enable(); preempt_enable();       } while (0)
 #define write_unlock_bh(lock)                  do { write_unlock(lock); local_bh_enable();        } while (0)
 #define spin_trylock_bh(lock)                  ({ int __r; local_bh_disable();\
                                                __r = spin_trylock(lock);      \
@@ -135,12 +135,6 @@ do { \
        preempt_enable(); \
 } while (0)
 
-#define spin_unlock_no_resched(lock) \
-do { \
-       _raw_spin_unlock(lock); \
-       preempt_enable_no_resched(); \
-} while (0)
-
 #define read_lock(lock)                ({preempt_disable(); _raw_read_lock(lock);})
 #define read_unlock(lock)      ({_raw_read_unlock(lock); preempt_enable();})
 #define write_lock(lock)       ({preempt_disable(); _raw_write_lock(lock);})
@@ -153,7 +147,6 @@ do { \
 #define spin_lock(lock)                        _raw_spin_lock(lock)
 #define spin_trylock(lock)             _raw_spin_trylock(lock)
 #define spin_unlock(lock)              _raw_spin_unlock(lock)
-#define spin_unlock_no_resched(lock)   _raw_spin_unlock(lock)
 
 #define read_lock(lock)                        _raw_read_lock(lock)
 #define read_unlock(lock)              _raw_read_unlock(lock)
index 99ac5e5799d3f1f45901f9fd8ad3521f4e3fbf51..8fbe794a5ece296415415bf70bd054db36623431 100644 (file)
@@ -740,10 +740,10 @@ struct task_struct *do_fork(unsigned long clone_flags,
         * total amount of pending timeslices in the system doesnt change,
         * resulting in more scheduling fairness.
         */
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        p->time_slice = (current->time_slice + 1) >> 1;
        current->time_slice >>= 1;
+       p->sleep_timestamp = jiffies;
        if (!current->time_slice) {
                /*
                 * This case is rare, it happens when the parent has only
@@ -751,10 +751,12 @@ struct task_struct *do_fork(unsigned long clone_flags,
                 * runqueue lock is not a problem.
                 */
                current->time_slice = 1;
+               preempt_disable();
                scheduler_tick(0, 0);
-       }
-       p->sleep_timestamp = jiffies;
-       local_irq_restore(flags);
+               local_irq_restore(flags);
+               preempt_enable();
+       } else
+               local_irq_restore(flags);
 
        /*
         * Ok, add it to the run-queues and make it
index 1a6ce9d15d8ada33a99a8553018dbc9408e8a558..ccceab9745dba45b210697b060d518326bbc6fe9 100644 (file)
@@ -728,7 +728,7 @@ void scheduler_tick(int user_tick, int system)
 
        if (p == rq->idle) {
                /* note: this timer irq context must be accounted for as well */
-               if (preempt_count() >= 2*IRQ_OFFSET)
+               if (irq_count() >= 2*HARDIRQ_OFFSET)
                        kstat.per_cpu_system[cpu] += system;
 #if CONFIG_SMP
                idle_tick();
@@ -902,6 +902,12 @@ asmlinkage void preempt_schedule(void)
 
        if (unlikely(ti->preempt_count))
                return;
+       if (unlikely(irqs_disabled())) {
+               preempt_disable();
+               printk("bad: schedule() with irqs disabled!\n");
+               show_stack(NULL);
+               preempt_enable_no_resched();
+       }
 
 need_resched:
        ti->preempt_count = PREEMPT_ACTIVE;
@@ -1020,7 +1026,7 @@ void wait_for_completion(struct completion *x)
        wait_queue_t wait;                      \
        init_waitqueue_entry(&wait, current);
 
-#define        SLEEP_ON_HEAD                                   \
+#define SLEEP_ON_HEAD                                  \
        spin_lock_irqsave(&q->lock,flags);              \
        __add_wait_queue(q, &wait);                     \
        spin_unlock(&q->lock);
@@ -1467,7 +1473,12 @@ asmlinkage long sys_sched_yield(void)
                list_add_tail(&current->run_list, array->queue + current->prio);
                __set_bit(current->prio, array->bitmap);
        }
-       spin_unlock_no_resched(&rq->lock);
+       /*
+        * Since we are going to call schedule() anyway, there's
+        * no need to preempt:
+        */
+       _raw_spin_unlock(&rq->lock);
+       preempt_enable_no_resched();
 
        schedule();
 
@@ -1680,8 +1691,7 @@ void __init init_idle(task_t *idle, int cpu)
        runqueue_t *idle_rq = cpu_rq(cpu), *rq = cpu_rq(task_cpu(idle));
        unsigned long flags;
 
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        double_rq_lock(idle_rq, rq);
 
        idle_rq->curr = idle_rq->idle = idle;
@@ -1697,6 +1707,8 @@ void __init init_idle(task_t *idle, int cpu)
        /* Set the preempt count _outside_ the spinlocks! */
 #if CONFIG_PREEMPT
        idle->thread_info->preempt_count = (idle->lock_depth >= 0);
+#else
+       idle->thread_info->preempt_count = 0;
 #endif
 }
 
index 1b5ef5f68a3ec0a5f9d7c484aa49883986d79f57..bdd3e35bded7e7b47b618e2c1738f3bc420688de 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1355,7 +1355,11 @@ void* kmem_cache_alloc_batch(kmem_cache_t* cachep, int flags)
                cc_entry(cc)[cc->avail++] =
                                kmem_cache_alloc_one_tail(cachep, slabp);
        }
-       spin_unlock(&cachep->spinlock);
+       /*
+        * CAREFUL: do not enable preemption yet, the per-CPU
+        * entries rely on us being atomic.
+        */
+       _raw_spin_unlock(&cachep->spinlock);
 
        if (cc->avail)
                return cc_entry(cc)[--cc->avail];
@@ -1382,8 +1386,12 @@ try_again:
                        } else {
                                STATS_INC_ALLOCMISS(cachep);
                                objp = kmem_cache_alloc_batch(cachep,flags);
+                               local_irq_restore(save_flags);
+                               /* end of non-preemptible region */
+                               preempt_enable();
                                if (!objp)
                                        goto alloc_new_slab_nolock;
+                               return objp;
                        }
                } else {
                        spin_lock(&cachep->spinlock);
@@ -1399,9 +1407,11 @@ try_again:
 alloc_new_slab:
 #ifdef CONFIG_SMP
        spin_unlock(&cachep->spinlock);
-alloc_new_slab_nolock:
 #endif
        local_irq_restore(save_flags);
+#ifdef CONFIG_SMP
+alloc_new_slab_nolock:
+#endif
        if (kmem_cache_grow(cachep, flags))
                /* Someone may have stolen our objs.  Doesn't matter, we'll
                 * just come back here again.
index 0f327d594231113b9ea7a5e4be858c35a17118ef..74cbdeb53734f38a181c26ab8379a725941eec99 100644 (file)
@@ -318,7 +318,7 @@ void __kfree_skb(struct sk_buff *skb)
 
        dst_release(skb->dst);
        if(skb->destructor) {
-               if (0 && in_irq())
+               if (in_irq())
                        printk(KERN_WARNING "Warning: kfree_skb on "
                                            "hard IRQ %p\n", NET_CALLER(skb));
                skb->destructor(skb);
index 0b148d05bb6ae2a78ad6ba20d6030725fc413e90..f70b1fddfa228fdd6077d09c291807582ec1ecfd 100644 (file)
@@ -235,10 +235,9 @@ static inline void write_seq(struct solo1_state *s, unsigned char data)
         int i;
        unsigned long flags;
 
-       /* the local_irq_disable stunt is to send the data within the command window */
+       /* the local_irq_save stunt is to send the data within the command window */
         for (i = 0; i < 0xffff; i++) {
-               local_save_flags(flags);
-               local_irq_disable();
+               local_irq_save(flags);
                 if (!(inb(s->sbbase+0xc) & 0x80)) {
                         outb(data, s->sbbase+0xc);
                        local_irq_restore(flags);