summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorPeng Wang <peng_wang@linux.alibaba.com>2026-10-23 22:51:00 +0800
committerThomas Gleixner <tglx@kernel.org>2026-10-25 22:43:19 +0100
commite389ae428847a2e6a3b698b5967df68ccf90361c (patch)
tree1b13ba6c164a772d971a5ed4d0016ae13fcda3c0 /kernel
parent45aeb7b3039355cfaf01ee1f7e104a55a8d61d0b (diff)
downloadlinux-e389ae428847a2e6a3b698b5967df68ccf90361c.tar.gz
linux-e389ae428847a2e6a3b698b5967df68ccf90361c.zip
tick/nohz: Reevaluate the tick for kicks flushed outside hardirq
The nohz full kick relies on interrupt exit to reevaluate the tick. However, a remote kick can also be flushed from task context without an interrupt exit guaranteed to follow. If a tick dependency is set or an earlier timer is queued after the idle-exit reevaluation, the required tick update can be delayed until another interrupt. Reevaluate the tick directly from the callback outside hardirq context. Keep the existing interrupt exit handling for hardirq callbacks. The offline flush remains harmless because tick_sched_timer_dying() has already cleared TS_FLAG_NOHZ. Fixes: 4b44a21dd640 ("irq_work, smp: Allow irq_work on call_single_queue") Fixes: a5183862e76f ("tick/nohz: Conditionally restart tick on idle exit") Suggested-by: Frederic Weisbecker <frederic@kernel.org> Co-developed-by: He Rongguang <herongguang@linux.alibaba.com> Signed-off-by: He Rongguang <herongguang@linux.alibaba.com> Signed-off-by: Peng Wang <peng_wang@linux.alibaba.com> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Reviewed-by: Frederic Weisbecker <frederic@kernel.org> Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20261023145101.8217-1-peng_wang@linux.alibaba.com
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/tick-sched.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 6c3fea386713..baa3ac9b48f8 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -400,9 +400,21 @@ static bool can_stop_full_tick(int cpu, struct tick_sched *ts)
return true;
}
+static void tick_nohz_full_update_tick(struct tick_sched *ts);
+
static void nohz_full_kick_func(struct irq_work *work)
{
- /* Empty, the tick restart happens on tick_nohz_irq_exit() */
+ struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
+
+ if (WARN_ON_ONCE(!tick_nohz_full_cpu(smp_processor_id())))
+ return;
+
+ /* Task-context flushes may not be followed by an IRQ exit. */
+ if (!in_hardirq()) {
+ if (WARN_ON_ONCE(tick_sched_flag_test(ts, TS_FLAG_INIDLE)))
+ return;
+ tick_nohz_full_update_tick(ts);
+ }
}
static DEFINE_PER_CPU(struct irq_work, nohz_full_kick_work) =