Skip to content
This repository has been archived by the owner on Aug 5, 2022. It is now read-only.

Commit

Permalink
irqwork: Move irq safe work to irq context
Browse files Browse the repository at this point in the history
On architectures where arch_irq_work_has_interrupt() returns false, we
end up running the irq safe work from the softirq context. That
results in a potential deadlock in the scheduler irq work which
expects that function to be called with interrupts disabled.

Split the irq_work_tick() function into a hard and soft variant. Call
the hard variant from the tick interrupt and add the soft variant to
the timer softirq.

Reported-and-tested-by: Yanjiang Jin <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Cc: [email protected]
  • Loading branch information
KAGA-KOKO authored and andrewkim-pkt committed Jan 22, 2019
1 parent e6f3637 commit 18e5cab
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 4 deletions.
6 changes: 6 additions & 0 deletions include/linux/irq_work.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,10 @@ static inline bool irq_work_needs_cpu(void) { return false; }
static inline void irq_work_run(void) { }
#endif

#if defined(CONFIG_IRQ_WORK) && defined(CONFIG_PREEMPT_RT_FULL)
void irq_work_tick_soft(void);
#else
static inline void irq_work_tick_soft(void) { }
#endif

#endif /* _LINUX_IRQ_WORK_H */
9 changes: 9 additions & 0 deletions kernel/irq_work.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,17 @@ void irq_work_tick(void)

if (!llist_empty(raised) && !arch_irq_work_has_interrupt())
irq_work_run_list(raised);

if (!IS_ENABLED(CONFIG_PREEMPT_RT_FULL))
irq_work_run_list(this_cpu_ptr(&lazy_list));
}

#if defined(CONFIG_IRQ_WORK) && defined(CONFIG_PREEMPT_RT_FULL)
void irq_work_tick_soft(void)
{
irq_work_run_list(this_cpu_ptr(&lazy_list));
}
#endif

/*
* Synchronize against the irq_work @entry, ensures the entry is not
Expand Down
6 changes: 2 additions & 4 deletions kernel/time/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1661,7 +1661,7 @@ void update_process_times(int user_tick)
scheduler_tick();
run_local_timers();
rcu_check_callbacks(user_tick);
#if defined(CONFIG_IRQ_WORK) && !defined(CONFIG_PREEMPT_RT_FULL)
#if defined(CONFIG_IRQ_WORK)
if (in_irq())
irq_work_tick();
#endif
Expand Down Expand Up @@ -1717,9 +1717,7 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h)
{
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);

#if defined(CONFIG_IRQ_WORK) && defined(CONFIG_PREEMPT_RT_FULL)
irq_work_tick();
#endif
irq_work_tick_soft();

__run_timers(base);
if (IS_ENABLED(CONFIG_NO_HZ_COMMON))
Expand Down

0 comments on commit 18e5cab

Please sign in to comment.