[Intel-gfx] [PATCH] softirq: Prevent looping on disabled tasklets
Chris Wilson
chris at chris-wilson.co.uk
Sun Feb 12 14:00:19 UTC 2017
Disabling a tasklet causes it not to run during tasklet_action, but is
put back onto the runnable tasklet list, and a new softirq raised. As
the softirq is raised from within __do_softirq() this causing
__do_softirq() to loop constantly until its timeslice expires and is
transferred to the ksoftirq thread. ksoftirq then permanently spins,
as on each action, the disabled tasklet keeps reraising the softirq.
Break this vicious cycle by moving the softirq from the action to the
final tasklet_enable().
This behaviour appears to be historic (since the first git import).
However, the looping until timeslice duration (to a max of 2ms) was
first introduced in commit c10d73671ad3 ("softirq: reduce latencies"),
with the restart limit restored in commit 34376a50fb1f ("Fix lockup
related to stop_machine being stuck in __do_softirq.")
Reported-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Hannes Reinecke <hare at suse.com>
Cc: Jens Axboe <axboe at kernel.dk>
Cc: Bjorn Helgaas <bhelgaas at google.com>
Cc: Alexander Potapenko <glider at google.com>
Cc: Chen Fan <chen.fan.fnst at cn.fujitsu.com>
Cc: Ingo Molnar <mingo at kernel.org>
Cc: "Peter Zijlstra (Intel)" <peterz at infradead.org>
Cc: Sebastian Andrzej Siewior <bigeasy at linutronix.de>
Cc: Johannes Thumshirn <jthumshirn at suse.de>
Cc: Emese Revfy <re.emese at gmail.com>
Cc: Sagi Grimberg <sagi at grimberg.me>
Cc: Eric Dumazet <edumazet at google.com>
Cc: Tom Herbert <therbert at google.com>
Cc: Ben Hutchings <bhutchings at solarflare.com>
---
include/linux/interrupt.h | 7 +++++--
kernel/softirq.c | 2 --
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 53144e78a369..12750f00d00d 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -613,8 +613,11 @@ static inline void tasklet_disable(struct tasklet_struct *t)
static inline void tasklet_enable(struct tasklet_struct *t)
{
- smp_mb__before_atomic();
- atomic_dec(&t->count);
+ if (!atomic_dec_and_test(&t->count))
+ return;
+
+ if (test_bit(TASKLET_STATE_SCHED, &t->state))
+ raise_softirq(HI_SOFTIRQ | TASKLET_SOFTIRQ);
}
extern void tasklet_kill(struct tasklet_struct *t);
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 744fa611cae0..5a359eb1a541 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -527,7 +527,6 @@ static __latent_entropy void tasklet_action(struct softirq_action *a)
t->next = NULL;
*__this_cpu_read(tasklet_vec.tail) = t;
__this_cpu_write(tasklet_vec.tail, &(t->next));
- __raise_softirq_irqoff(TASKLET_SOFTIRQ);
local_irq_enable();
}
}
@@ -563,7 +562,6 @@ static __latent_entropy void tasklet_hi_action(struct softirq_action *a)
t->next = NULL;
*__this_cpu_read(tasklet_hi_vec.tail) = t;
__this_cpu_write(tasklet_hi_vec.tail, &(t->next));
- __raise_softirq_irqoff(HI_SOFTIRQ);
local_irq_enable();
}
}
--
2.11.0
More information about the Intel-gfx
mailing list