Ill-advised use of on_each_cpu() can lead to sleep with interrupts
disabled. This is best explained with a backtrace:
BUG: sleeping function called from invalid context at
/home/armbru/linux-2.6.tip-xen-quintela.hg/mm/slab.c:2783
in_atomic():0, irqs_disabled():1
[<c0104f36>] show_trace+0x13/0x15
[<c0105439>] dump_stack+0x18/0x1c
[<c01161ac>] __might_sleep+0x9f/0xa7
[<c0158823>] __kmalloc+0x65/0x110
[<c018e01d>] proc_create+0x8d/0xe2
[<c018e12d>] proc_mkdir_mode+0x1a/0x4d
[<c018e173>] proc_mkdir+0x13/0x15
[<c013de9b>] register_handler_proc+0x90/0x9e
[<c013d729>] setup_irq+0xdf/0xf5
[<c013d7a9>] request_irq+0x6a/0x8a
[<c0231817>] bind_virq_to_irqhandler+0xe3/0x101
[<f4c83b02>] bind_virq_cpu+0x28/0x62 [oprofile]
[<c0121453>] on_each_cpu+0x36/0x5d
[<f4c83c3b>] xenoprof_setup+0x22/0x14a [oprofile]
[<f4c820bf>] oprofile_setup+0x45/0x8b [oprofile]
[<f4c82fa3>] event_buffer_open+0x3e/0x62 [oprofile]
[<c0159eda>] __dentry_open+0xc7/0x1b0
[<c015a034>] nameidata_to_filp+0x20/0x34
[<c015a078>] do_filp_open+0x30/0x39
[<c015afe6>] do_sys_open+0x40/0xb0
[<c015b07f>] sys_open+0x13/0x15
[<c01048cf>] syscall_call+0x7/0xb
on_each_cpu() disables interrupts. proc_create() calls passes
GFP_KERNEL to kmalloc().
The patch converts from on_each_cpu() to for_each_cpu(), and then
simplifies things.
diff -rup linux-2.6.16.13-xen/arch/i386/oprofile/xenoprof.c
linux-2.6.16.13-xen.patched-1/arch/i386/oprofile/xenoprof.c
--- linux-2.6.16.13-xen/arch/i386/oprofile/xenoprof.c 2006-05-15
10:32:22.000000000 +0200
+++ linux-2.6.16.13-xen.patched-1/arch/i386/oprofile/xenoprof.c 2006-05-15
10:30:49.000000000 +0200
@@ -141,56 +141,40 @@ xenoprof_ovf_interrupt(int irq, void * d
}
-static void unbind_virq_cpu(void * info)
-{
- int cpu = smp_processor_id();
- if (ovf_irq[cpu] >= 0) {
- unbind_from_irqhandler(ovf_irq[cpu], NULL);
- ovf_irq[cpu] = -1;
- }
-}
-
-
static void unbind_virq(void)
{
- on_each_cpu(unbind_virq_cpu, NULL, 0, 1);
-}
-
-
-int bind_virq_error;
-
-static void bind_virq_cpu(void * info)
-{
- int result;
- int cpu = smp_processor_id();
+ int i;
- result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
- cpu,
- xenoprof_ovf_interrupt,
- SA_INTERRUPT,
- "xenoprof",
- NULL);
-
- if (result<0) {
- bind_virq_error = result;
- printk("xenoprof.c: binding VIRQ_XENOPROF to IRQ failed on CPU "
- "%d\n", cpu);
- } else {
- ovf_irq[cpu] = result;
+ for_each_cpu(i) {
+ if (ovf_irq[i] >= 0) {
+ unbind_from_irqhandler(ovf_irq[i], NULL);
+ ovf_irq[i] = -1;
+ }
}
}
static int bind_virq(void)
{
- bind_virq_error = 0;
- on_each_cpu(bind_virq_cpu, NULL, 0, 1);
- if (bind_virq_error) {
- unbind_virq();
- return bind_virq_error;
- } else {
- return 0;
+ int i, result;
+
+ for_each_cpu(i) {
+ result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
+ i,
+ xenoprof_ovf_interrupt,
+ SA_INTERRUPT,
+ "xenoprof",
+ NULL);
+
+ if (result < 0) {
+ unbind_virq();
+ return result;
+ }
+
+ ovf_irq[i] = result;
}
+
+ return 0;
}
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|