Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed6b676c authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds
Browse files

[PATCH] x86_64: Switch to the interrupt stack when running a softirq in local_bh_enable()



This avoids some potential stack overflows with very deep softirq callchains.
i386 does this too.

TOADD CFI annotation

Signed-off-by: default avatarAndi Kleen <ak@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3829ee6b
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -918,3 +918,15 @@ ENTRY(machine_check)
ENTRY(call_debug)
       zeroentry do_call_debug

ENTRY(call_softirq)
	movq %gs:pda_irqstackptr,%rax
	pushq %r15
	movq %rsp,%r15
	incl %gs:pda_irqcount
	cmove %rax,%rsp
	call __do_softirq
	movq %r15,%rsp
	decl %gs:pda_irqcount
	popq %r15
	ret
+19 −0
Original line number Diff line number Diff line
@@ -135,3 +135,22 @@ void fixup_irqs(cpumask_t map)
	local_irq_disable();
}
#endif

extern void call_softirq(void);

asmlinkage void do_softirq(void)
{
 	__u32 pending;
 	unsigned long flags;

 	if (in_interrupt())
 		return;

 	local_irq_save(flags);
 	pending = local_softirq_pending();
 	/* Switch to interrupt stack */
 	if (pending)
		call_softirq();
 	local_irq_restore(flags);
}
EXPORT_SYMBOL(do_softirq);
+2 −0
Original line number Diff line number Diff line
@@ -57,4 +57,6 @@ int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
extern void fixup_irqs(cpumask_t map);
#endif

#define __ARCH_HAS_DO_SOFTIRQ 1

#endif /* _ASM_IRQ_H */
+2 −2
Original line number Diff line number Diff line
@@ -86,7 +86,7 @@ asmlinkage void __do_softirq(void)
	/* Reset the pending bitmask before enabling irqs */
	local_softirq_pending() = 0;

	local_irq_enable();
	//local_irq_enable();

	h = softirq_vec;

@@ -99,7 +99,7 @@ asmlinkage void __do_softirq(void)
		pending >>= 1;
	} while (pending);

	local_irq_disable();
	//local_irq_disable();

	pending = local_softirq_pending();
	if (pending && --max_restart)