Skip to contentSkip to conversation

ioapic: fix potential resume deadlock

PATCH In review Daniel J Blueman 3 participants 11 messages May 9, 2011 – May 16, 2011 x86

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 ioapic: fix potential resume deadlock

Fix a potential deadlock when resuming; here the calling function has disabled interrupts, so we cannot sleep.

---
 arch/x86/kernel/apic/io_apic.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +2 -2
index 45fd33d..df63620 100644
@@ -621,14 +621,14 @@ struct IO_APIC_route_entry **alloc_ioapic_entries(void)
 	struct IO_APIC_route_entry **ioapic_entries;
 
 	ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
-				GFP_KERNEL);
+				GFP_ATOMIC);
 	if (!ioapic_entries)
 		return 0;
 
 	for (apic = 0; apic < nr_ioapics; apic++) {
 		ioapic_entries[apic] =
 			kzalloc(sizeof(struct IO_APIC_route_entry) *
-				nr_ioapic_registers[apic], GFP_KERNEL);
+				nr_ioapic_registers[apic], GFP_ATOMIC);
 		if (!ioapic_entries[apic])
 			goto nomem;
 	}
Signature · 1 line
1.7.4.1
#1 lore raw

Hi Thomas, Ingo, HPA,

Quoted 23 lines · Daniel J Blueman

Fix a potential deadlock when resuming; here the calling function has disabled interrupts, so we cannot sleep.

---
 arch/x86/kernel/apic/io_apic.c |    4 ++--

 1 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +1 -1
index 45fd33d..df63620 100644
@@ -621,14 +621,14 @@ struct IO_APIC_route_entry **alloc_ioapic_entries(void)
        struct IO_APIC_route_entry **ioapic_entries;
 
        ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
-                               GFP_KERNEL);
+                               GFP_ATOMIC);
        if (!ioapic_entries)
                return 0;
 
        for (apic = 0; apic < nr_ioapics; apic++) {
Quoted 7 lines

               ioapic_entries[apic] =
                       kzalloc(sizeof(struct IO_APIC_route_entry) *
-                               nr_ioapic_registers[apic], GFP_KERNEL);
+                               nr_ioapic_registers[apic], GFP_ATOMIC); if (!ioapic_entries[apic])
                       goto nomem;
       }

Any feedback on this? I tested it on 2.6.39-rc6 and it does address the potential deadlock warning I receive when resuming from suspend. If positive, it would be good to get into -rc8, as rc7 is released.

Thanks,
Daniel

Signature · 1 line
Daniel J Blueman
#2 lore raw
In reply to Daniel J Blueman
Quoted 20 lines · Daniel J Blueman

Fix a potential deadlock when resuming; here the calling function has disabled interrupts, so we cannot sleep.

---
 arch/x86/kernel/apic/io_apic.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +1 -1
index 45fd33d..df63620 100644
@@ -621,14 +621,14 @@ struct IO_APIC_route_entry **alloc_ioapic_entries(void)
 	struct IO_APIC_route_entry **ioapic_entries;
 
 	ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
-				GFP_KERNEL);
+				GFP_ATOMIC);
 	if (!ioapic_entries)

arch/x86/kernel/apic/io_apic.c struct IO_APIC_route_entry **alloc_ioapic_entries(void) · line 634

Quoted 10 lines
arch/x86/kernel/apic/io_apic.c +1 -1
 		return 0;
 
 	for (apic = 0; apic < nr_ioapics; apic++) {
 		ioapic_entries[apic] =
 			kzalloc(sizeof(struct IO_APIC_route_entry) *
-				nr_ioapic_registers[apic], GFP_KERNEL);
+				nr_ioapic_registers[apic], GFP_ATOMIC);
 		if (!ioapic_entries[apic])
 			goto nomem;
 	}

Hm, there must be some other bug here.

ioapic entries should be allocated on system bootup and should never really be deallocated.

The bug might be in the idea to call to enable_IR_x2apic() on resume - why are ioapic entries reallocated there? That call in default_setup_apic_routing() was introduced some time ago in:

fa47f7e52874: x86, x2apic: Simplify apic init in SMP and UP builds

and that it results in reallocation in the suspend patch is distinctly wrong.

I suspect the reason why this has not triggered for others is the relative rarity of affected systems?

Suresh?

Thanks,

Ingo

#3 lore raw
Quoted 42 lines · Ingo Molnar
Quoted 23 lines · Daniel J Blueman

Fix a potential deadlock when resuming; here the calling function has disabled interrupts, so we cannot sleep.

---
 arch/x86/kernel/apic/io_apic.c |    4 ++--

 1 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +1 -1
index 45fd33d..df63620 100644
@@ -621,14 +621,14 @@ struct IO_APIC_route_entry **alloc_ioapic_entries(void)
       struct IO_APIC_route_entry **ioapic_entries;
 
       ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
-                             GFP_KERNEL);
+                             GFP_ATOMIC);
       if (!ioapic_entries)
               return 0;
 
       for (apic = 0; apic < nr_ioapics; apic++) {
Quoted 7 lines

              ioapic_entries[apic] =
                      kzalloc(sizeof(struct IO_APIC_route_entry) *
-                             nr_ioapic_registers[apic], GFP_KERNEL);
+                             nr_ioapic_registers[apic], GFP_ATOMIC); if (!ioapic_entries[apic])
                      goto nomem;
      }

Hm, there must be some other bug here.

ioapic entries should be allocated on system bootup and should never really be deallocated.

The bug might be in the idea to call to enable_IR_x2apic() on resume - why are ioapic entries reallocated there? That call in default_setup_apic_routing() was introduced some time ago in:

Quoted 8 lines

 fa47f7e52874: x86, x2apic: Simplify apic init in SMP and UP builds

and that it results in reallocation in the suspend patch is distinctly wrong.

I suspect the reason why this has not triggered for others is the relative rarity of affected systems?

Suresh?

For reference, this is the warning I get on resume with debugging enabled:

BUG: sleeping function called from invalid context at mm/slub.c:824
in_atomic(): 0, irqs_disabled(): 1, pid: 1842, name: pm-suspend
INFO: lockdep is turned off.
irq event stamp: 0
hardirqs last  enabled at (0): [<          (null)>]           (null)
hardirqs last disabled at (0): [<ffffffff8105eca2>] copy_process+
0x4e2/0x1040
softirqs last  enabled at (0): [<ffffffff8105eca2>] copy_process+0x4e2/0x1040
softirqs last disabled at (0): [<          (null)>]           (null)
Pid: 1842, comm: pm-suspend Tainted: G   M        2.6.39-rc6-330cd+ #3
Call Trace:
 [<ffffffff81098290>] ? print_irqtrace_events+0xd0/0xe0
 [<ffffffff8104a11d>] __might_sleep+0xed/0x120
 [<ffffffff8112f7c3>] __kmalloc+0xd3/0x140
 [<ffffffff81025566>] alloc_ioapic_entries+0x66/0xb0
 [<ffffffff81022bc5>] lapic_resume+0x265/0x350
 [<ffffffff814059d5>] syscore_resume+0x35/0xd0
 [<ffffffff810a8ace>] suspend_enter+0xde/0x120
 [<ffffffff810a8b7a>] suspend_devices_and_enter+0x6a/0xb0
 [<ffffffff810a8c91>] enter_state+0xd1/0x100
 [<ffffffff810a81c6>] state_store+0xc6/0x100
 [<ffffffff81329c37>] kobj_attr_store+0x17/0x20
 [<ffffffff811a78d1>] sysfs_write_file+0xe1/0x160
 [<ffffffff811400c6>] vfs_write+0xc6/0x180
 [<ffffffff811403dc>] sys_write+0x4c/0x90
 [<ffffffff8170927b>] system_call_fastpath+0x16/0x1b
Signature · 1 line
Daniel J Blueman
#4 lore raw
Quoted 10 lines · Daniel J Blueman
Quoted 9 lines · Ingo Molnar

Hm, there must be some other bug here.

ioapic entries should be allocated on system bootup and should never really be deallocated.

The bug might be in the idea to call to enable_IR_x2apic() on resume - why are ioapic entries reallocated there? That call in default_setup_apic_routing() was introduced some time ago in:

Quoted 8 lines
Quoted 8 lines

fa47f7e52874: x86, x2apic: Simplify apic init in SMP and UP builds

and that it results in reallocation in the suspend patch is distinctly wrong.

I suspect the reason why this has not triggered for others is the relative rarity of affected systems?

Suresh?

This will happen only on interrupt-remapping enabled systems and hence hidden so far.

enable_IR_x2apic() / default_setup_apic_routing() routines don't get called during resume. Problem is with the lapic_resume() path which is trying to re-enable x2apic mode and this requires masking io-apic entries, re-enabling x2apic and interrupt-remapping, restoring io-apic entries etc. ioapic entry allocation that is happening in lapic_resume() is just for storing the original io-apic RTE's during the mask/restore operations that happen around re-enabling x2apic.

Anyways looking at that code, there is some duplicate code between x2apic code and the io-apic suspend/resume sequence. So a better fix will be to remove this duplicate code.

Daniel, I appended a quick patch which should fix the problem you reported. This is not a final patch, as I can do some more cleanup and re-use the io-apic suspend/resume code a bit more.

If this patch works for you, then I can spend some more time to do the complete cleanup patch in a day or two. Thanks.

 arch/x86/include/asm/io_apic.h |    1 +
 arch/x86/kernel/apic/apic.c    |   26 ++++----------------------
 arch/x86/kernel/apic/io_apic.c |    2 +-
 3 files changed, 6 insertions(+), 23 deletions(-)
arch/x86/include/asm/io_apic.h +1 -0
index a97a240..9e229be 100644
@@ -177,6 +177,7 @@ extern void __init pre_init_apic_IRQ0(void);
 extern void mp_save_irq(struct mpc_intsrc *m);
 
 extern void disable_ioapic_support(void);
+extern struct IO_APIC_route_entry *ioapic_saved_data[MAX_IO_APICS];
 
 #else  /* !CONFIG_X86_IO_APIC */
 
arch/x86/kernel/apic/apic.c +4 -22
index fabf01e..9000409 100644
@@ -2088,28 +2088,14 @@ static void lapic_resume(void)
 {
 	unsigned int l, h;
 	unsigned long flags;
-	int maxlvt, ret;
-	struct IO_APIC_route_entry **ioapic_entries = NULL;
+	int maxlvt;
 
 	if (!apic_pm_state.active)
 		return;
 
 	local_irq_save(flags);
 	if (intr_remapping_enabled) {
-		ioapic_entries = alloc_ioapic_entries();
-		if (!ioapic_entries) {
-			WARN(1, "Alloc ioapic_entries in lapic resume failed.");
-			goto restore;
-		}
-
-		ret = save_IO_APIC_setup(ioapic_entries);
-		if (ret) {
-			WARN(1, "Saving IO-APIC state failed: %d\n", ret);
-			free_ioapic_entries(ioapic_entries);
-			goto restore;
-		}
-
-		mask_IO_APIC_setup(ioapic_entries);
+		mask_IO_APIC_setup(ioapic_saved_data);
 		legacy_pic->mask_all();
 	}
 
@@ -2152,13 +2138,9 @@ static void lapic_resume(void)
 	apic_write(APIC_ESR, 0);
 	apic_read(APIC_ESR);
 
-	if (intr_remapping_enabled) {
+	if (intr_remapping_enabled)
 		reenable_intr_remapping(x2apic_mode);
-		legacy_pic->restore_mask();
-		restore_IO_APIC_setup(ioapic_entries);
-		free_ioapic_entries(ioapic_entries);
-	}
-restore:
+
 	local_irq_restore(flags);
 }
 
arch/x86/kernel/apic/io_apic.c +1 -1
index 45fd33d..5e6a78e 100644
@@ -2918,7 +2918,7 @@ static int __init io_apic_bug_finalize(void)
 
 late_initcall(io_apic_bug_finalize);
 
-static struct IO_APIC_route_entry *ioapic_saved_data[MAX_IO_APICS];
+struct IO_APIC_route_entry *ioapic_saved_data[MAX_IO_APICS];
 
 static void suspend_ioapic(int ioapic_id)
 {
author Tested-by
#5 lore raw
Quoted 35 lines · Suresh Siddha
Quoted 10 lines · Daniel J Blueman
Quoted 9 lines · Ingo Molnar

Hm, there must be some other bug here.

ioapic entries should be allocated on system bootup and should never really be deallocated.

The bug might be in the idea to call to enable_IR_x2apic() on resume - why are ioapic entries reallocated there? That call in default_setup_apic_routing() was introduced some time ago in:

Quoted 8 lines
Quoted 8 lines

 fa47f7e52874: x86, x2apic: Simplify apic init in SMP and UP builds

and that it results in reallocation in the suspend patch is distinctly wrong.

I suspect the reason why this has not triggered for others is the relative rarity of affected systems?

Suresh?

This will happen only on interrupt-remapping enabled systems and hence hidden so far.

enable_IR_x2apic() / default_setup_apic_routing() routines don't get called during resume. Problem is with the lapic_resume() path which is trying to re-enable x2apic mode and this requires masking io-apic entries, re-enabling x2apic and interrupt-remapping, restoring io-apic entries etc. ioapic entry allocation that is happening in lapic_resume() is just for storing the original io-apic RTE's during the mask/restore operations that happen around re-enabling x2apic.

Anyways looking at that code, there is some duplicate code between x2apic code and the io-apic suspend/resume sequence. So a better fix will be to remove this duplicate code.

Quoted 6 lines

Daniel, I appended a quick patch which should fix the problem you reported. This is not a final patch, as I can do some more cleanup and re-use the io-apic suspend/resume code a bit more.

If this patch works for you, then I can spend some more time to do the complete cleanup patch in a day or two. Thanks.

[...]

Superb, this works, tested against 2.6.39-rc7 and addresses the "BUG:
sleeping function called from invalid context at mm/slub.c:824" warning I was previously seeing. It would be good to get this fix into 2.6.39-final if possible.

Thanks,
Daniel

Signature · 1 line
Daniel J Blueman
#6 lore raw
Quoted 6 lines · Daniel J Blueman

Superb, this works, tested against 2.6.39-rc7 and addresses the "BUG:
sleeping function called from invalid context at mm/slub.c:824" warning I was previously seeing. It would be good to get this fix into 2.6.39-final if possible.

Thanks Daniel for testing my quick patch. I have appended the complete patch which cleans up this code.

Ingo, This patch is relatively big (mostly removes the duplicate code and changes the location where we allocate ioapic_saved_data, so that this can be shared between interrupt-remapping and io-apic suspend/resume flows). May be this can go into 2.6.40-rc1 and probably go to 2.6.39-stable?

Or we can take the Daniel's GFP_ATOMIC patch for 2.6.39 and push this patch for 2.6.40-rc1. I am ok either way.

Thanks.
---

From: Suresh Siddha <[email protected]>
Subject: x86, ioapic: Remove the duplicate code for saving/restoring io-apic RTE's

Daniel reported that x2apic and interrupt-remapping resume code flow is allocating memory with GFP_KERNEL while the interrupts are disabled.

Code flow for enabling interrupt-remapping has its own routines for saving and restoring io-apic RTE's. ioapic suspend/resume code flow also has similar routines. Remove the duplicate code. This will consolidate code aswell as remove the unnecessary allocation/free of the temporary buffers during suspend/resume of interrupt-remapping enabled platforms (and thus avoid the GFP_KERNEL allocation in the interrupts disabled context).

---

 arch/x86/include/asm/io_apic.h |   21 ++----
 arch/x86/kernel/apic/apic.c    |   49 ++++----------
 arch/x86/kernel/apic/io_apic.c |  148 +++++++++++-----------------------------
 3 files changed, 61 insertions(+), 157 deletions(-)
arch/x86/include/asm/io_apic.h +6 -15
index a97a240..7e52404 100644
@@ -152,11 +152,9 @@ extern void ioapic_insert_resources(void);
 
 int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr);
 
-extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
-extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
-extern int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
-extern void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
-extern int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
+extern int save_ioapic_entries(void);
+extern void mask_ioapic_entries(void);
+extern void restore_ioapic_entries(void);
 
 extern int get_nr_irqs_gsi(void);
 
@@ -192,21 +190,14 @@ struct io_apic_irq_attr;
 static inline int io_apic_set_pci_routing(struct device *dev, int irq,
 		 struct io_apic_irq_attr *irq_attr) { return 0; }
 
-static inline struct IO_APIC_route_entry **alloc_ioapic_entries(void)
-{
-	return NULL;
-}
-
-static inline void free_ioapic_entries(struct IO_APIC_route_entry **ent) { }
-static inline int save_IO_APIC_setup(struct IO_APIC_route_entry **ent)
+static inline int save_ioapic_entries(void)
 {
 	return -ENOMEM;
 }
 
-static inline void mask_IO_APIC_setup(struct IO_APIC_route_entry **ent) { }
-static inline int restore_IO_APIC_setup(struct IO_APIC_route_entry **ent)
+static inline void mask_ioapic_entries(void) { }
+static inline void restore_ioapic_entries(void)
 {
-	return -ENOMEM;
 }
 
 static inline void mp_save_irq(struct mpc_intsrc *m) { };
arch/x86/kernel/apic/apic.c +14 -35

96 lines not on this page · raw message

arch/x86/kernel/apic/io_apic.c +41 -107

246 lines not on this page · raw message

#7 lore raw

Hi Suresh,

Quoted 11 lines · Suresh Siddha
Quoted 6 lines · Daniel J Blueman

Superb, this works, tested against 2.6.39-rc7 and addresses the "BUG:
sleeping function called from invalid context at mm/slub.c:824" warning I was previously seeing. It would be good to get this fix into 2.6.39-final if possible.

Thanks Daniel for testing my quick patch. I have appended the complete patch which cleans up this code.

Quoted 8 lines

Ingo, This patch is relatively big (mostly removes the duplicate code and changes the location where we allocate ioapic_saved_data, so that this can be shared between interrupt-remapping and io-apic suspend/resume flows). May be this can go into 2.6.40-rc1 and probably go to 2.6.39-stable?

Or we can take the Daniel's GFP_ATOMIC patch for 2.6.39 and push this patch for 2.6.40-rc1. I am ok either way.

[]

Testing this, all looks well in that the patch resolves the potentially sleeping allocation, however I do see (on boot) this suspicious message (though suspend and resume does work):

IOAPIC 0: suspend/resume impossible!

I guess it's not expected...

Signature · 1 line
Daniel J Blueman
#8 lore raw
Quoted 24 lines · Daniel J Blueman

Hi Suresh,

Quoted 11 lines · Suresh Siddha
Quoted 6 lines · Daniel J Blueman

Superb, this works, tested against 2.6.39-rc7 and addresses the "BUG:
sleeping function called from invalid context at mm/slub.c:824" warning I was previously seeing. It would be good to get this fix into 2.6.39-final if possible.

Thanks Daniel for testing my quick patch. I have appended the complete patch which cleans up this code.

Quoted 8 lines

Ingo, This patch is relatively big (mostly removes the duplicate code and changes the location where we allocate ioapic_saved_data, so that this can be shared between interrupt-remapping and io-apic suspend/resume flows). May be this can go into 2.6.40-rc1 and probably go to 2.6.39-stable?

Or we can take the Daniel's GFP_ATOMIC patch for 2.6.39 and push this patch for 2.6.40-rc1. I am ok either way.

[]

Quoted 7 lines

Testing this, all looks well in that the patch resolves the potentially sleeping allocation, however I do see (on boot) this suspicious message (though suspend and resume does work):

IOAPIC 0: suspend/resume impossible!

I guess it's not expected...

No. Has this been introduced by Suresh's patch?

Thanks,

Ingo

#9 lore raw
Quoted 26 lines · Ingo Molnar
Quoted 24 lines · Daniel J Blueman

Hi Suresh,

Quoted 11 lines · Suresh Siddha
Quoted 6 lines · Daniel J Blueman

Superb, this works, tested against 2.6.39-rc7 and addresses the "BUG:
sleeping function called from invalid context at mm/slub.c:824" warning I was previously seeing. It would be good to get this fix into 2.6.39-final if possible.

Thanks Daniel for testing my quick patch. I have appended the complete patch which cleans up this code.

Quoted 8 lines

Ingo, This patch is relatively big (mostly removes the duplicate code and changes the location where we allocate ioapic_saved_data, so that this can be shared between interrupt-remapping and io-apic suspend/resume flows). May be this can go into 2.6.40-rc1 and probably go to 2.6.39-stable?

Or we can take the Daniel's GFP_ATOMIC patch for 2.6.39 and push this patch for 2.6.40-rc1. I am ok either way.

[]

Quoted 7 lines
Quoted 7 lines

Testing this, all looks well in that the patch resolves the potentially sleeping allocation, however I do see (on boot) this suspicious message (though suspend and resume does work):

IOAPIC 0: suspend/resume impossible!

I guess it's not expected...

oops. I had a spurious initialization, from the earlier attempts to fix this that was still left out.

Quoted 1 line

No. Has this been introduced by Suresh's patch?

Ofcourse yes ;(

Will fix this and split the patch into multiple steps.

thanks,
suresh

#10 lore raw
In reply to Suresh Siddha
Quoted 8 lines · Suresh Siddha
Quoted 6 lines · Daniel J Blueman

Superb, this works, tested against 2.6.39-rc7 and addresses the "BUG:
sleeping function called from invalid context at mm/slub.c:824" warning I was previously seeing. It would be good to get this fix into 2.6.39-final if possible.

Quoted 8 lines

Thanks Daniel for testing my quick patch. I have appended the complete patch which cleans up this code.

Ingo, This patch is relatively big (mostly removes the duplicate code and changes the location where we allocate ioapic_saved_data, so that this can be shared between interrupt-remapping and io-apic suspend/resume flows). May be this can go into 2.6.40-rc1 and probably go to 2.6.39-stable?

Could you please split it up into multiple steps? Commits with such a diffstat:

Quoted 4 lines
 arch/x86/include/asm/io_apic.h |   21 ++----
 arch/x86/kernel/apic/apic.c    |   49 ++++----------
 arch/x86/kernel/apic/io_apic.c |  148 +++++++++++-----------------------------
 3 files changed, 61 insertions(+), 157 deletions(-)

... rarely come without regressions attached, and it's a whole lot easier to figure out what's wrong with a small patch out of 3-4 than with such a big patch.

I'd suggest to make the end result exactly the same as this one big patch, so that we preserve Daniel's testing results.

Thanks,

Ingo