summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2008-03-17 16:37:20 -0700
committerIngo Molnar <mingo@elte.hu>2008-04-24 23:57:32 +0200
commit229664bee6126e01f8662976a5fe2e79813b77c8 (patch)
tree1e7d2fc69bae4a941952c00fa20f5746d07c0256
parentee8fa1c67f0b873a324960f0ca9fa1d7e49aa86b (diff)
downloadlinux-229664bee6126e01f8662976a5fe2e79813b77c8.tar.gz
linux-229664bee6126e01f8662976a5fe2e79813b77c8.tar.bz2
linux-229664bee6126e01f8662976a5fe2e79813b77c8.zip
xen: short-cut for recursive event handling
If an event comes in while events are currently being processed, then just increment the counter and have the outer event loop reprocess the pending events. This prevents unbounded recursion on heavy event loads (of course massive event storms will cause infinite loops). Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/xen/events.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/arch/x86/xen/events.c b/arch/x86/xen/events.c
index f73b53bd65b7..85bac298b3cb 100644
--- a/arch/x86/xen/events.c
+++ b/arch/x86/xen/events.c
@@ -517,29 +517,43 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
int cpu = get_cpu();
struct shared_info *s = HYPERVISOR_shared_info;
struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
- unsigned long pending_words;
+ static DEFINE_PER_CPU(unsigned, nesting_count);
+ unsigned count;
- vcpu_info->evtchn_upcall_pending = 0;
+ do {
+ unsigned long pending_words;
- /* NB. No need for a barrier here -- XCHG is a barrier on x86. */
- pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
- while (pending_words != 0) {
- unsigned long pending_bits;
- int word_idx = __ffs(pending_words);
- pending_words &= ~(1UL << word_idx);
+ vcpu_info->evtchn_upcall_pending = 0;
- while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) {
- int bit_idx = __ffs(pending_bits);
- int port = (word_idx * BITS_PER_LONG) + bit_idx;
- int irq = evtchn_to_irq[port];
+ if (__get_cpu_var(nesting_count)++)
+ goto out;
- if (irq != -1) {
- regs->orig_ax = ~irq;
- do_IRQ(regs);
+ /* NB. No need for a barrier here -- XCHG is a barrier on x86. */
+ pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
+ while (pending_words != 0) {
+ unsigned long pending_bits;
+ int word_idx = __ffs(pending_words);
+ pending_words &= ~(1UL << word_idx);
+
+ while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) {
+ int bit_idx = __ffs(pending_bits);
+ int port = (word_idx * BITS_PER_LONG) + bit_idx;
+ int irq = evtchn_to_irq[port];
+
+ if (irq != -1) {
+ regs->orig_ax = ~irq;
+ do_IRQ(regs);
+ }
}
}
- }
+ BUG_ON(!irqs_disabled());
+
+ count = __get_cpu_var(nesting_count);
+ __get_cpu_var(nesting_count) = 0;
+ } while(count != 1);
+
+out:
put_cpu();
}