[PATCH] Allocate memory before disabling memory in irq_to_desc_alloc_node()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



[ I already send a similar patch to the list on May 29th ([RFC] Convert
sparse_irq_lock to raw_spinlock_t). ]

When allocating struct irq_desc we can get the memory before disabling the
interrupts.

[   22.867664] BUG: sleeping function called from invalid context at
/usr/src/pa
ckages/BUILD/kernel-rt-2.6.31/linux-2.6.30/kernel/rtmutex.c:684
[   22.867682] in_atomic(): 1, irqs_disabled(): 1, pid: 4084, name: ip
[   22.867691] Pid: 4084, comm: ip Tainted: G          N  2.6.31-rc7-rt8-20-rt
#
1
[   22.867702] Call Trace:
[   22.867727]  [<ffffffff81011711>] try_stack_unwind+0x171/0x1c0
[   22.867742]  [<ffffffff8101002c>] dump_trace+0xac/0x2f0
[   22.867755]  [<ffffffff81011204>] show_trace_log_lvl+0x64/0x90
[   22.867768]  [<ffffffff81011253>] show_trace+0x23/0x40
[   22.867782]  [<ffffffff814de2be>] dump_stack+0x81/0xa3
[   22.867793]  [<ffffffff81057209>] __might_sleep+0x109/0x120
[   22.867806]  [<ffffffff814e18e1>] rt_spin_lock+0x41/0xb0
[   22.867822]  [<ffffffff811568fe>] _slab_irq_disable+0x5e/0x90
[   22.867837]  [<ffffffff811578c6>] kmem_cache_alloc_node+0x46/0x280
[   22.867850]  [<ffffffff81158efa>] __kmalloc_node+0x7a/0x160
[   22.867868]  [<ffffffff810df452>] kzalloc_node+0x22/0x40
[   22.867884]  [<ffffffff814c6c70>] irq_to_desc_alloc_node+0x100/0x1e0
[   22.867899]  [<ffffffff8102f9fc>] create_irq_nr+0x5c/0x150
[   22.867913]  [<ffffffff8102fbd2>] arch_setup_msi_irqs+0xe2/0x1d0
[   22.867931]  [<ffffffff8129ff20>] msi_capability_init+0x130/0x250
[   22.867945]  [<ffffffff812a0136>] pci_enable_msi_block+0xf6/0x150
[   22.867977]  [<ffffffffa026184a>] nv_request_irq+0x27a/0x430 [forcedeth]
[   22.868001]  [<ffffffffa0264f2d>] nv_open+0x3ad/0x610 [forcedeth]
[   22.868020]  [<ffffffff813ee052>] dev_open+0xf2/0x140
[   22.868034]  [<ffffffff813ed33c>] dev_change_flags+0xac/0x200
[   22.868048]  [<ffffffff813f9844>] do_setlink+0x2a4/0x460
[   22.868061]  [<ffffffff813fb3fb>] rtnl_newlink+0x49b/0x560
[   22.868071]  [<ffffffff813fad24>] rtnetlink_rcv_msg+0x1b4/0x270
[   22.868083]  [<ffffffff81412f59>] netlink_rcv_skb+0xa9/0xe0
[   22.868094]  [<ffffffff813fab46>] rtnetlink_rcv+0x36/0x60
[   22.868103]  [<ffffffff81412bbd>] netlink_unicast+0x2cd/0x2e0
[   22.868121]  [<ffffffff814139e4>] netlink_sendmsg+0x234/0x330
[   22.868131]  [<ffffffff813d7b06>] sock_sendmsg+0x116/0x160
[   22.868142]  [<ffffffff813d7d12>] sys_sendmsg+0x1c2/0x370
[   22.868153]  [<ffffffff8100c7c2>] system_call_fastpath+0x16/0x1b
[   22.868176]  [<00007fc1bf778220>] 0x7fc1bf778220

Signed-off-by: Jan Blunck <jblunck@xxxxxxx>
---
 kernel/irq/handle.c       |   46 ++++++++++++++++++++++++++++-----------
 kernel/irq/internals.h    |    1 
 kernel/irq/numa_migrate.c |   53 ++++++++++++++++++----------------------------
 kernel/softirq.c          |    6 +++++
 4 files changed, 61 insertions(+), 45 deletions(-)

Index: b/kernel/irq/handle.c
===================================================================
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -126,6 +126,22 @@ static void init_one_irq_desc(int irq, s
 	arch_init_chip_data(desc, node);
 }
 
+static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc)
+{
+	if (old_desc->kstat_irqs == desc->kstat_irqs)
+		return;
+
+	kfree(old_desc->kstat_irqs);
+	old_desc->kstat_irqs = NULL;
+}
+
+void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc)
+{
+	free_kstat_irqs(old_desc, desc);
+	free_desc_masks(old_desc, desc);
+	arch_free_chip_data(old_desc, desc);
+}
+
 /*
  * Protect the sparse_irqs:
  */
@@ -195,7 +211,7 @@ struct irq_desc *irq_to_desc(unsigned in
 
 struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node)
 {
-	struct irq_desc *desc;
+	struct irq_desc *desc, *tmp;
 	unsigned long flags;
 
 	if (irq >= nr_irqs) {
@@ -208,26 +224,30 @@ struct irq_desc * __ref irq_to_desc_allo
 	if (desc)
 		return desc;
 
-	atomic_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)
-		goto out_unlock;
-
 	if (slab_is_available())
-		desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
+		tmp = kzalloc_node(sizeof(*tmp), GFP_ATOMIC, node);
 	else
-		desc = alloc_bootmem_node(NODE_DATA(node), sizeof(*desc));
+		tmp = alloc_bootmem_node(NODE_DATA(node), sizeof(*tmp));
 
 	printk(KERN_DEBUG "  alloc irq_desc for %d on node %d\n", irq, node);
-	if (!desc) {
+	if (!tmp) {
 		printk(KERN_ERR "can not alloc irq_desc\n");
 		BUG_ON(1);
 	}
-	init_one_irq_desc(irq, desc, node);
+	init_one_irq_desc(irq, tmp, node);
+
+	atomic_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) {
+		free_one_irq_desc(tmp, desc);
+		kfree(tmp);
+		goto out_unlock;
+	}
 
-	irq_desc_ptrs[irq] = desc;
+	irq_desc_ptrs[irq] = tmp;
+	desc = tmp;
 
 out_unlock:
 	atomic_spin_unlock_irqrestore(&sparse_irq_lock, flags);
Index: b/kernel/irq/internals.h
===================================================================
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -16,6 +16,7 @@ extern void __disable_irq(struct irq_des
 extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume);
 
 extern struct lock_class_key irq_desc_lock_class;
+extern void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc);
 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
 extern void clear_kstat_irqs(struct irq_desc *desc);
 extern atomic_spinlock_t sparse_irq_lock;
Index: b/kernel/irq/numa_migrate.c
===================================================================
--- a/kernel/irq/numa_migrate.c
+++ b/kernel/irq/numa_migrate.c
@@ -24,15 +24,6 @@ static void init_copy_kstat_irqs(struct
 			 nr * sizeof(*desc->kstat_irqs));
 }
 
-static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc)
-{
-	if (old_desc->kstat_irqs == desc->kstat_irqs)
-		return;
-
-	kfree(old_desc->kstat_irqs);
-	old_desc->kstat_irqs = NULL;
-}
-
 static bool init_copy_one_irq_desc(int irq, struct irq_desc *old_desc,
 		 struct irq_desc *desc, int node)
 {
@@ -51,46 +42,41 @@ static bool init_copy_one_irq_desc(int i
 	return true;
 }
 
-static void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc)
-{
-	free_kstat_irqs(old_desc, desc);
-	free_desc_masks(old_desc, desc);
-	arch_free_chip_data(old_desc, desc);
-}
-
 static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
 						int node)
 {
-	struct irq_desc *desc;
+	struct irq_desc *desc, *tmp;
 	unsigned int irq;
 	unsigned long flags;
 
 	irq = old_desc->irq;
 
-	atomic_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;
-
-	desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
-	if (!desc) {
+	/* Allocate memory before disabling IRQs */
+	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, node)) {
+	if (!init_copy_one_irq_desc(irq, old_desc, tmp, node)) {
 		/* still use old one */
-		kfree(desc);
+		kfree(tmp);
 		desc = old_desc;
-		goto out_unlock;
+		goto out;
 	}
 
-	irq_desc_ptrs[irq] = desc;
+	atomic_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;
 	atomic_spin_unlock_irqrestore(&sparse_irq_lock, flags);
 
 	/* free the old one */
@@ -102,6 +88,9 @@ static struct irq_desc *__real_move_irq_
 out_unlock:
 	atomic_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
@@ -1291,3 +1291,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;
+}


Regards,
	Jan

-- 
Jan Blunck <jblunck@xxxxxxx>
--
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

[Index of Archives]     [RT Stable]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]

  Powered by Linux