Moving of IRQs is done in hardirq context so the sparse_irq_lock needs to be raw_spinlock_t. For this to work we need to move the memory allocation before actually taking the lock itself. This patch doesn't seem to do 100% the right thing since I still get the following from lockdep: [ INFO: inconsistent lock state ] 2.6.29.4-rt16-rt #2 --------------------------------- inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage. swapper/0 [HC1[1]:SC0[0]:HE0:SE1] takes: (per_cpu__lock_slab_locked#5){?.+...}, at: [<ffffffff802f85d5>] _slab_irq_disab le+0x40/0x63 {HARDIRQ-ON-W} state was registered at: [<ffffffff80287b64>] mark_lock+0x296/0x3ed [<ffffffff80287d79>] mark_irqflags+0xbe/0x125 [<ffffffff8028a2a8>] __lock_acquire+0x692/0x855 [<ffffffff8028a56f>] lock_acquire+0x104/0x130 [<ffffffff804e9e50>] rt_spin_lock+0x7d/0x81 [<ffffffff804e70ee>] cpuup_callback+0x48/0x229 [<ffffffff804ee098>] notifier_call_chain+0x33/0x5b [<ffffffff8027d463>] __raw_notifier_call_chain+0x9/0xb [<ffffffff804e57ee>] _cpu_up+0x75/0x12e [<ffffffff804e5908>] cpu_up+0x61/0x76 [<ffffffff8079466b>] smp_init+0x52/0xa0 [<ffffffff80794787>] kernel_init+0x80/0x19b [<ffffffff8022609a>] child_rip+0xa/0x20 [<ffffffffffffffff>] 0xffffffffffffffff irq event stamp: 119862 hardirqs last enabled at (119861): [<ffffffff802b6622>] __rcu_read_lock+0xa9/0x bc hardirqs last disabled at (119862): [<ffffffff80224d3a>] save_args+0x6a/0x70 softirqs last enabled at (0): [<ffffffff80262759>] copy_process+0x573/0x111f softirqs last disabled at (0): [<(null)>] (null) other info that might help us debug this: 1 lock held by swapper/0: #0: (&irq_desc_lock_class){-.....}, at: [<ffffffff802b430d>] handle_fasteoi_ir q+0x20/0xff stack backtrace: Pid: 0, comm: swapper Tainted: G N 2.6.29.4-rt16-rt #2 Call Trace: [<ffffffff80227cba>] dump_trace+0xda/0x3d0 [<ffffffff80228a6f>] show_trace_log_lvl+0x4c/0x58 [<ffffffff80228a8b>] show_trace+0x10/0x12 [<ffffffff804e7691>] dump_stack+0x72/0x7b [<ffffffff802876a0>] print_usage_bug+0x1ce/0x1df [<ffffffff80287766>] mark_lock_irq+0xb5/0x21d [<ffffffff80287b88>] mark_lock+0x2ba/0x3ed [<ffffffff80287d0f>] mark_irqflags+0x54/0x125 [<ffffffff8028a2a8>] __lock_acquire+0x692/0x855 [<ffffffff8028a56f>] lock_acquire+0x104/0x130 [<ffffffff804e9e50>] rt_spin_lock+0x7d/0x81 [<ffffffff802f85d5>] _slab_irq_disable+0x40/0x63 [<ffffffff802fa520>] kmem_cache_alloc_node+0x41/0x225 [<ffffffff802b5349>] __real_move_irq_desc+0x44/0x1bd [<ffffffff802b5504>] move_irq_desc+0x42/0x56 [<ffffffff8023c0be>] irq_complete_move+0x80/0x95 [<ffffffff8023d91b>] ack_apic_level+0x20/0x101 [<ffffffff802b43cf>] handle_fasteoi_irq+0xe2/0xff [<ffffffff8022764f>] handle_irq+0x1f/0x27 [<ffffffff80226db6>] do_IRQ+0x5e/0xc6 [<ffffffff80225953>] ret_from_intr+0x0/0x16 DWARF2 unwinder stuck at ret_from_intr+0x0/0x16 Leftover inexact backtrace: <IRQ> <EOI> [<ffffffff802b6627>] ? __rcu_read_lock+0xae/0xbc [<ffffffff804ee0ec>] ? __atomic_notifier_call_chain+0x2c/0x56 [<ffffffff804ee125>] ? atomic_notifier_call_chain+0xf/0x11 [<ffffffff80224121>] ? cpu_idle+0x7d/0xca [<ffffffff804e427f>] ? start_secondary+0xc5/0xca Signed-off-by: Jan Blunck <jblunck@xxxxxxx> --- kernel/irq/handle.c | 38 ++++++++++++++++++++++++++------------ kernel/irq/internals.h | 2 +- kernel/irq/numa_migrate.c | 38 +++++++++++++++++++++----------------- kernel/softirq.c | 6 ++++++ 4 files changed, 54 insertions(+), 30 deletions(-) Index: b/kernel/irq/handle.c =================================================================== --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -124,10 +124,17 @@ static void init_one_irq_desc(int irq, s arch_init_chip_data(desc, cpu); } +static void free_one_irq_desc(struct irq_desc *desc) +{ + kfree(desc->kstat_irqs); + desc->kstat_irqs = NULL; + arch_free_chip_data(desc, &irq_desc_init); +} + /* * Protect the sparse_irqs: */ -DEFINE_SPINLOCK(sparse_irq_lock); +DEFINE_RAW_SPINLOCK(sparse_irq_lock); struct irq_desc **irq_desc_ptrs __read_mostly; @@ -191,7 +198,7 @@ struct irq_desc *irq_to_desc(unsigned in struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu) { - struct irq_desc *desc; + struct irq_desc *desc, *tmp; unsigned long flags; int node; @@ -205,6 +212,17 @@ struct irq_desc *irq_to_desc_alloc_cpu(u if (desc) return desc; + /* Allocate memory before disabling interrupts */ + node = cpu_to_node(cpu); + tmp = kzalloc_node(sizeof(*tmp), GFP_ATOMIC, node); + printk(KERN_DEBUG " alloc irq_desc for %d on cpu %d node %d\n", + irq, cpu, node); + if (!tmp) { + printk(KERN_ERR "can not alloc irq_desc\n"); + BUG_ON(1); + } + init_one_irq_desc(irq, tmp, cpu); + spin_lock_irqsave(&sparse_irq_lock, flags); /* We have to check it to avoid races with another CPU */ @@ -212,20 +230,16 @@ struct irq_desc *irq_to_desc_alloc_cpu(u if (desc) goto out_unlock; - node = cpu_to_node(cpu); - desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node); - printk(KERN_DEBUG " alloc irq_desc for %d on cpu %d node %d\n", - irq, cpu, node); - if (!desc) { - printk(KERN_ERR "can not alloc irq_desc\n"); - BUG_ON(1); - } - init_one_irq_desc(irq, desc, cpu); + irq_desc_ptrs[irq] = tmp; + desc = tmp; + spin_unlock_irqrestore(&sparse_irq_lock, flags); - irq_desc_ptrs[irq] = desc; + return desc; out_unlock: spin_unlock_irqrestore(&sparse_irq_lock, flags); + free_one_irq_desc(tmp); + kfree(tmp); return desc; } Index: b/kernel/irq/internals.h =================================================================== --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -16,7 +16,7 @@ extern int __irq_set_trigger(struct irq_ extern struct lock_class_key irq_desc_lock_class; extern void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr); extern void clear_kstat_irqs(struct irq_desc *desc); -extern spinlock_t sparse_irq_lock; +extern raw_spinlock_t sparse_irq_lock; #ifdef CONFIG_SPARSE_IRQ /* irq_desc_ptrs allocated at boot time */ Index: b/kernel/irq/numa_migrate.c =================================================================== --- a/kernel/irq/numa_migrate.c +++ b/kernel/irq/numa_migrate.c @@ -61,38 +61,40 @@ static void free_one_irq_desc(struct irq static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc, int cpu) { - struct irq_desc *desc; + struct irq_desc *desc, *tmp; unsigned int irq; unsigned long flags; int node; irq = old_desc->irq; - spin_lock_irqsave(&sparse_irq_lock, flags); - - /* We have to check it to avoid races with another CPU */ - desc = irq_desc_ptrs[irq]; - - if (desc && old_desc != desc) - goto out_unlock; - + /* Allocate memory before disabling IRQs */ node = cpu_to_node(cpu); - desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node); - if (!desc) { + tmp = kzalloc_node(sizeof(*tmp), GFP_ATOMIC, node); + if (!tmp) { printk(KERN_ERR "irq %d: can not get new irq_desc " "for migration.\n", irq); /* still use old one */ desc = old_desc; - goto out_unlock; + goto out; } - if (!init_copy_one_irq_desc(irq, old_desc, desc, cpu)) { + if (!init_copy_one_irq_desc(irq, old_desc, tmp, cpu)) { /* still use old one */ - kfree(desc); + kfree(tmp); desc = old_desc; - goto out_unlock; + goto out; } - irq_desc_ptrs[irq] = desc; + spin_lock_irqsave(&sparse_irq_lock, flags); + + /* We have to check it to avoid races with another CPU */ + desc = irq_desc_ptrs[irq]; + + if (desc && old_desc != desc) + goto out_unlock; + + irq_desc_ptrs[irq] = tmp; + desc = tmp; spin_unlock_irqrestore(&sparse_irq_lock, flags); /* free the old one */ @@ -105,7 +107,9 @@ static struct irq_desc *__real_move_irq_ out_unlock: spin_unlock_irqrestore(&sparse_irq_lock, flags); - + free_one_irq_desc(tmp, old_desc); + kfree(tmp); +out: return desc; } Index: b/kernel/softirq.c =================================================================== --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -1202,3 +1202,9 @@ int __weak arch_init_chip_data(struct ir { return 0; } + +void __weak arch_free_chip_data(struct irq_desc *old_desc, + struct irq_desc *desc) +{ + return; +} -- To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html