diff options
Diffstat (limited to 'kernel/softirq.c')
-rw-r--r-- | kernel/softirq.c | 30 |
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; } |