From 73d2e0ce2f4979fa774b077286d2e6b91fddbfa7 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 26 Jun 2013 15:28:11 -0400 Subject: [PATCH 323/352] rt,ntp: Move call to schedule_delayed_work() to helper thread The ntp code for notify_cmos_timer() is called from a hard interrupt context. schedule_delayed_work() under PREEMPT_RT_FULL calls spinlocks that have been converted to mutexes, thus calling schedule_delayed_work() from interrupt is not safe. Add a helper thread that does the call to schedule_delayed_work and wake up that thread instead of calling schedule_delayed_work() directly. This is only for CONFIG_PREEMPT_RT_FULL, otherwise the code still calls schedule_delayed_work() directly in irq context. Note: There's a few places in the kernel that do this. Perhaps the RT code should have a dedicated thread that does the checks. Just register a notifier on boot up for your check and wake up the thread when needed. This will be a todo. Signed-off-by: Steven Rostedt [bigeasy: use swork_queue() instead a helper thread] Signed-off-by: Sebastian Andrzej Siewior --- kernel/time/ntp.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 6df8927..05b7391 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "ntp_internal.h" #include "timekeeping_internal.h" @@ -568,10 +569,35 @@ static void sync_cmos_clock(struct work_struct *work) &sync_cmos_work, timespec64_to_jiffies(&next)); } +#ifdef CONFIG_PREEMPT_RT_FULL + +static void run_clock_set_delay(struct swork_event *event) +{ + queue_delayed_work(system_power_efficient_wq, &sync_cmos_work, 0); +} + +static struct swork_event ntp_cmos_swork; + +void ntp_notify_cmos_timer(void) +{ + swork_queue(&ntp_cmos_swork); +} + +static __init int create_cmos_delay_thread(void) +{ + WARN_ON(swork_get()); + INIT_SWORK(&ntp_cmos_swork, run_clock_set_delay); + return 0; +} +early_initcall(create_cmos_delay_thread); + +#else + void ntp_notify_cmos_timer(void) { queue_delayed_work(system_power_efficient_wq, &sync_cmos_work, 0); } +#endif /* CONFIG_PREEMPT_RT_FULL */ #else void ntp_notify_cmos_timer(void) { } -- 2.7.4