From: Sebastian Andrzej Siewior Date: Sat, 22 Jun 2019 00:09:22 +0200 Subject: [PATCH] softirq: Avoid a cancel dead-lock in tasklet handling due to preemptible-softirq Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.2/older/patches-5.2.10-rt5.tar.xz A pending / active tasklet which is preempted by a task on the same CPU will spin indefinitely becauase the tasklet makes no progress. To avoid this deadlock we can disable BH which will acquire the softirq-lock which will force the completion of the softirq and so the tasklet. The BH off/on in tasklet_kill() will force tasklets which are not yet running but scheduled (because ksoftirqd was preempted before it could start the tasklet). The BH off/on in tasklet_unlock_wait() will force tasklets which got preempted while running. Signed-off-by: Sebastian Andrzej Siewior --- include/linux/interrupt.h | 5 ++++- kernel/softirq.c | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -625,7 +625,10 @@ static inline void tasklet_unlock(struct static inline void tasklet_unlock_wait(struct tasklet_struct *t) { - while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); } + while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { + local_bh_disable(); + local_bh_enable(); + } } #else #define tasklet_trylock(t) 1 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -705,7 +705,8 @@ void tasklet_kill(struct tasklet_struct while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { do { - yield(); + local_bh_disable(); + local_bh_enable(); } while (test_bit(TASKLET_STATE_SCHED, &t->state)); } tasklet_unlock_wait(t);