summaryrefslogtreecommitdiff
path: root/kernel/softirq.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/softirq.c')
-rw-r--r--kernel/softirq.c30
1 files changed, 23 insertions, 7 deletions
diff --git a/kernel/softirq.c b/kernel/softirq.c
index d69b77fc7cc1..a4aefd8152b9 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -252,7 +252,7 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
struct softirq_action *h;
bool in_hardirq;
__u32 deferred;
- __u32 pending;
+ __u32 pending, pending_now, pending_delay, pending_mask;
int softirq_bit;
/*
@@ -262,7 +262,21 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
*/
current->flags &= ~PF_MEMALLOC;
+ /*
+ * If this is not the ksoftirqd thread,
+ * and there is an RT task that is running or is waiting to run,
+ * delay handling the long-running softirq handlers by leaving
+ * them for the ksoftirqd thread.
+ */
+ if (current != __this_cpu_read(ksoftirqd) &&
+ cpu_has_rt_task(smp_processor_id()))
+ pending_mask = LONG_SOFTIRQ_MASK;
+ else
+ pending_mask = 0;
+
pending = local_softirq_pending();
+ pending_delay = pending & pending_mask;
+ pending_now = pending & ~pending_mask;
deferred = softirq_deferred_for_rt(pending);
account_irq_enter_time(current);
__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
@@ -270,14 +284,14 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
restart:
/* Reset the pending bitmask before enabling irqs */
- set_softirq_pending(deferred);
- __this_cpu_write(active_softirqs, pending);
+ __this_cpu_write(active_softirqs, pending_now);
+ set_softirq_pending(pending_delay);
local_irq_enable();
h = softirq_vec;
- while ((softirq_bit = ffs(pending))) {
+ while ((softirq_bit = ffs(pending_now))) {
unsigned int vec_nr;
int prev_count;
@@ -298,7 +312,7 @@ restart:
preempt_count_set(prev_count);
}
h++;
- pending >>= softirq_bit;
+ pending_now >>= softirq_bit;
}
__this_cpu_write(active_softirqs, 0);
@@ -307,10 +321,12 @@ restart:
pending = local_softirq_pending();
deferred = softirq_deferred_for_rt(pending);
+ pending_delay = pending & pending_mask;
+ pending_now = pending & ~pending_mask;
if (pending) {
- if (time_before(jiffies, end) && !need_resched() &&
- --max_restart)
+ if (pending_now && time_before(jiffies, end) &&
+ !need_resched() && --max_restart && !deferred)
goto restart;
}