From: Hans-Joachim Picht <hpicht@redhat.com> Date: Thu, 6 Nov 2008 15:43:29 +0100 Subject: [s390] sclp: incorrect softirq disable/enable Message-id: 20081106144329.GB12027@redhat.com O-Subject: [RHEL5 U4 PATCH 2/4] s390 - sclp: Incorrect softirq disable/enable. Bugzilla: 468021 RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com> Description ============ The user might see a warning like BUG: warning at kernel/softirq.c:121/_local_bh_enable() followed by a kernel stackstrace. When a lot of printks are done in interrupt context the sclp console driver calls local_bh_enable()/_local_bh_enable() to prevent softirq execution. Calling _local_bh_enable() from interrupt context triggers a warning. Since softirqs are disabled anyway when in interrupt context, just add a check in which context the kernel is presently and only call local_bh_disable()/_local_bh_enable() when on process context. Bugzilla ========= BZ 468021 https://bugzilla.redhat.com/show_bug.cgi?id=468021 Upstream status of the patch: ============================= Fixed upstream with git commit c59d744bd8a0e283daf6726881e4c9aa4bd2526. First kernel which has this fixed is 2.6.21. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=c59d744bd8a0e283daf6726881e4c9aa4bd25261 Test status: ============ The patch has been tested and fixes the problem. The fix has been verified by the IBM test department. Please ACK. With best regards, --Hans diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 86aaad1..d5b67ee 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -414,6 +414,7 @@ sclp_sync_wait(void) unsigned long flags; unsigned long cr0, cr0_sync; u64 timeout; + int irq_context; /* We'll be disabling timer interrupts, so we need a custom timeout * mechanism */ @@ -426,7 +427,9 @@ sclp_sync_wait(void) } local_irq_save(flags); /* Prevent bottom half from executing once we force interrupts open */ - local_bh_disable(); + irq_context = in_interrupt(); + if (!irq_context) + local_bh_disable(); /* Enable service-signal interruption, disable timer interrupts */ trace_hardirqs_on(); __ctl_store(cr0, 0, 0); @@ -448,7 +451,8 @@ sclp_sync_wait(void) } local_irq_disable(); __ctl_load(cr0, 0, 0); - _local_bh_enable(); + if (!irq_context) + _local_bh_enable(); local_irq_restore(flags); }