| 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 |
| |