blob: f6c0060752d8450527eac4b00e20056a4a324ef2 [file] [log] [blame]
From 2240b2b55191947323dda3331ef6046c10373be0 Mon Sep 17 00:00:00 2001
From: Jupyung Lee <jupyung@gmail.com>
Date: Tue, 10 Nov 2009 17:31:54 +0900
Subject: [PATCH] softirqs: Add missing preemption point in ksoftirqd
commit ca0b4bfa5994856bbcf4227e29f9c73722efaef2 in tip.
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: Jupyung Lee <jupyung@gmail.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 533b72c..c35f72b 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -1032,10 +1032,10 @@ sleep_more:
goto sleep_more;
}
per_cpu(softirq_running, cpu) |= softirq_mask;
- __preempt_enable_no_resched();
set_softirq_pending(local_softirq_pending() & ~softirq_mask);
local_bh_disable();
local_irq_enable();
+ preempt_enable();
h = &softirq_vec[data->nr];
if (h)
--
1.7.1.1