Commit ca0b4bfa authored by Jupyung Lee's avatar Jupyung Lee Committed by Thomas Gleixner

softirqs: Add missing preemption point in ksoftirqd

In its current implementation, ksoftirq() includes a series of primitives
related with kernel preemption and irq on/off, in the following order:

preempt_disable()		... (1)
local_irq_disable()		... (2)
__preempt_enable_no_resched()	... (3)
local_irq_enable()		... (4)

A problem arises if a task is woken up between (1) and (2) because it
is not given a chance to preempt the currently running process until
interrupts are enabled at (4). At this point the the kernel is
preemptible, but there is no explicit reschedule point.

This is only true for a preempt-rt enabled kernel as !preempt-rt has
preemption disabled at that point via local_bh_disable().

A simple suggestion to resolve the problem is to add a reschedule point,
preempt_check_resched(), just after (4).

[ tglx: Modified: delete __preempt_enable_no_resched() and add
  	preempt_enable() after local_irq_enable() ]
Signed-off-by: default avatarJupyung Lee <jupyung@gmail.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 3c8167f9
...@@ -1033,10 +1033,10 @@ sleep_more: ...@@ -1033,10 +1033,10 @@ sleep_more:
goto sleep_more; goto sleep_more;
} }
per_cpu(softirq_running, cpu) |= softirq_mask; per_cpu(softirq_running, cpu) |= softirq_mask;
__preempt_enable_no_resched();
set_softirq_pending(local_softirq_pending() & ~softirq_mask); set_softirq_pending(local_softirq_pending() & ~softirq_mask);
local_bh_disable(); local_bh_disable();
local_irq_enable(); local_irq_enable();
preempt_enable();
h = &softirq_vec[data->nr]; h = &softirq_vec[data->nr];
if (h) if (h)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment