Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 1 | From 0ee4fd72ca45b88431b1c7a6f70d7aa836af8645 Mon Sep 17 00:00:00 2001 |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 2 | From: Thomas Gleixner <tglx@linutronix.de> |
| 3 | Date: Fri, 3 Jul 2009 08:44:31 -0500 |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 4 | Subject: [PATCH 083/351] hrtimer: Fixup hrtimer callback changes for |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 5 | preempt-rt |
| 6 | X-NVConfidentiality: public |
| 7 | |
| 8 | In preempt-rt we can not call the callbacks which take sleeping locks |
| 9 | from the timer interrupt context. |
| 10 | |
| 11 | Bring back the softirq split for now, until we fixed the signal |
| 12 | delivery problem for real. |
| 13 | |
| 14 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| 15 | Signed-off-by: Ingo Molnar <mingo@elte.hu> |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 16 | --- |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 17 | include/linux/hrtimer.h | 4 ++ |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 18 | kernel/sched/core.c | 1 + |
| 19 | kernel/sched/rt.c | 1 + |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 20 | kernel/time/hrtimer.c | 142 +++++++++++++++++++++++++++++++++++++++++++---- |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 21 | kernel/time/tick-sched.c | 1 + |
| 22 | kernel/watchdog.c | 1 + |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 23 | 6 files changed, 139 insertions(+), 11 deletions(-) |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 24 | |
| 25 | diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 26 | index d5e22d72537b..6f78ca13ffdf 100644 |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 27 | --- a/include/linux/hrtimer.h |
| 28 | +++ b/include/linux/hrtimer.h |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 29 | @@ -103,6 +103,8 @@ struct hrtimer { |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 30 | enum hrtimer_restart (*function)(struct hrtimer *); |
| 31 | struct hrtimer_clock_base *base; |
| 32 | u8 state; |
| 33 | + struct list_head cb_entry; |
| 34 | + int irqsafe; |
| 35 | #ifdef CONFIG_MISSED_TIMER_OFFSETS_HIST |
| 36 | ktime_t praecox; |
| 37 | #endif |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 38 | @@ -143,6 +145,7 @@ struct hrtimer_clock_base { |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 39 | int index; |
| 40 | clockid_t clockid; |
| 41 | struct timerqueue_head active; |
| 42 | + struct list_head expired; |
| 43 | ktime_t (*get_time)(void); |
| 44 | ktime_t offset; |
| 45 | } __attribute__((__aligned__(HRTIMER_CLOCK_BASE_ALIGN))); |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 46 | @@ -186,6 +189,7 @@ struct hrtimer_cpu_base { |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 47 | raw_spinlock_t lock; |
| 48 | seqcount_t seq; |
| 49 | struct hrtimer *running; |
| 50 | + struct hrtimer *running_soft; |
| 51 | unsigned int cpu; |
| 52 | unsigned int active_bases; |
| 53 | unsigned int clock_was_set_seq; |
| 54 | diff --git a/kernel/sched/core.c b/kernel/sched/core.c |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 55 | index 7892c1ebe893..f014ae1d81e0 100644 |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 56 | --- a/kernel/sched/core.c |
| 57 | +++ b/kernel/sched/core.c |
| 58 | @@ -439,6 +439,7 @@ static void init_rq_hrtick(struct rq *rq) |
| 59 | |
| 60 | hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| 61 | rq->hrtick_timer.function = hrtick; |
| 62 | + rq->hrtick_timer.irqsafe = 1; |
| 63 | } |
| 64 | #else /* CONFIG_SCHED_HRTICK */ |
| 65 | static inline void hrtick_clear(struct rq *rq) |
| 66 | diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 67 | index 6a839a4c8e13..55e0b4b9c8d9 100644 |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 68 | --- a/kernel/sched/rt.c |
| 69 | +++ b/kernel/sched/rt.c |
| 70 | @@ -47,6 +47,7 @@ void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime) |
| 71 | |
| 72 | hrtimer_init(&rt_b->rt_period_timer, |
| 73 | CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| 74 | + rt_b->rt_period_timer.irqsafe = 1; |
| 75 | rt_b->rt_period_timer.function = sched_rt_period_timer; |
| 76 | } |
| 77 | |
| 78 | diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 79 | index a7c365d33ff5..3c194dd6ebfb 100644 |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 80 | --- a/kernel/time/hrtimer.c |
| 81 | +++ b/kernel/time/hrtimer.c |
| 82 | @@ -730,11 +730,8 @@ static inline int hrtimer_is_hres_enabled(void) { return 0; } |
| 83 | static inline void hrtimer_switch_to_hres(void) { } |
| 84 | static inline void |
| 85 | hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { } |
| 86 | -static inline int hrtimer_reprogram(struct hrtimer *timer, |
| 87 | - struct hrtimer_clock_base *base) |
| 88 | -{ |
| 89 | - return 0; |
| 90 | -} |
| 91 | +static inline void hrtimer_reprogram(struct hrtimer *timer, |
| 92 | + struct hrtimer_clock_base *base) { } |
| 93 | static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { } |
| 94 | static inline void retrigger_next_event(void *arg) { } |
| 95 | |
| 96 | @@ -883,7 +880,7 @@ void hrtimer_wait_for_timer(const struct hrtimer *timer) |
| 97 | { |
| 98 | struct hrtimer_clock_base *base = timer->base; |
| 99 | |
| 100 | - if (base && base->cpu_base && !hrtimer_hres_active()) |
| 101 | + if (base && base->cpu_base && !timer->irqsafe) |
| 102 | wait_event(base->cpu_base->wait, |
| 103 | !(hrtimer_callback_running(timer))); |
| 104 | } |
| 105 | @@ -933,6 +930,11 @@ static void __remove_hrtimer(struct hrtimer *timer, |
| 106 | if (!(state & HRTIMER_STATE_ENQUEUED)) |
| 107 | return; |
| 108 | |
| 109 | + if (unlikely(!list_empty(&timer->cb_entry))) { |
| 110 | + list_del_init(&timer->cb_entry); |
| 111 | + return; |
| 112 | + } |
| 113 | + |
| 114 | if (!timerqueue_del(&base->active, &timer->node)) |
| 115 | cpu_base->active_bases &= ~(1 << base->index); |
| 116 | |
| 117 | @@ -1173,6 +1175,7 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, |
| 118 | |
| 119 | base = hrtimer_clockid_to_base(clock_id); |
| 120 | timer->base = &cpu_base->clock_base[base]; |
| 121 | + INIT_LIST_HEAD(&timer->cb_entry); |
| 122 | timerqueue_init(&timer->node); |
| 123 | |
| 124 | #ifdef CONFIG_TIMER_STATS |
| 125 | @@ -1213,6 +1216,7 @@ bool hrtimer_active(const struct hrtimer *timer) |
| 126 | seq = raw_read_seqcount_begin(&cpu_base->seq); |
| 127 | |
| 128 | if (timer->state != HRTIMER_STATE_INACTIVE || |
| 129 | + cpu_base->running_soft == timer || |
| 130 | cpu_base->running == timer) |
| 131 | return true; |
| 132 | |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 133 | @@ -1311,10 +1315,111 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 134 | cpu_base->running = NULL; |
| 135 | } |
| 136 | |
| 137 | +#ifdef CONFIG_PREEMPT_RT_BASE |
| 138 | +static void hrtimer_rt_reprogram(int restart, struct hrtimer *timer, |
| 139 | + struct hrtimer_clock_base *base) |
| 140 | +{ |
| 141 | + int leftmost; |
| 142 | + |
| 143 | + if (restart != HRTIMER_NORESTART && |
| 144 | + !(timer->state & HRTIMER_STATE_ENQUEUED)) { |
| 145 | + |
| 146 | + leftmost = enqueue_hrtimer(timer, base); |
| 147 | + if (!leftmost) |
| 148 | + return; |
| 149 | +#ifdef CONFIG_HIGH_RES_TIMERS |
| 150 | + if (!hrtimer_is_hres_active(timer)) { |
| 151 | + /* |
| 152 | + * Kick to reschedule the next tick to handle the new timer |
| 153 | + * on dynticks target. |
| 154 | + */ |
| 155 | + if (base->cpu_base->nohz_active) |
| 156 | + wake_up_nohz_cpu(base->cpu_base->cpu); |
| 157 | + } else { |
| 158 | + |
| 159 | + hrtimer_reprogram(timer, base); |
| 160 | + } |
| 161 | +#endif |
| 162 | + } |
| 163 | +} |
| 164 | + |
| 165 | +/* |
| 166 | + * The changes in mainline which removed the callback modes from |
| 167 | + * hrtimer are not yet working with -rt. The non wakeup_process() |
| 168 | + * based callbacks which involve sleeping locks need to be treated |
| 169 | + * seperately. |
| 170 | + */ |
| 171 | +static void hrtimer_rt_run_pending(void) |
| 172 | +{ |
| 173 | + enum hrtimer_restart (*fn)(struct hrtimer *); |
| 174 | + struct hrtimer_cpu_base *cpu_base; |
| 175 | + struct hrtimer_clock_base *base; |
| 176 | + struct hrtimer *timer; |
| 177 | + int index, restart; |
| 178 | + |
| 179 | + local_irq_disable(); |
| 180 | + cpu_base = &per_cpu(hrtimer_bases, smp_processor_id()); |
| 181 | + |
| 182 | + raw_spin_lock(&cpu_base->lock); |
| 183 | + |
| 184 | + for (index = 0; index < HRTIMER_MAX_CLOCK_BASES; index++) { |
| 185 | + base = &cpu_base->clock_base[index]; |
| 186 | + |
| 187 | + while (!list_empty(&base->expired)) { |
| 188 | + timer = list_first_entry(&base->expired, |
| 189 | + struct hrtimer, cb_entry); |
| 190 | + |
| 191 | + /* |
| 192 | + * Same as the above __run_hrtimer function |
| 193 | + * just we run with interrupts enabled. |
| 194 | + */ |
| 195 | + debug_deactivate(timer); |
| 196 | + cpu_base->running_soft = timer; |
| 197 | + raw_write_seqcount_barrier(&cpu_base->seq); |
| 198 | + |
| 199 | + __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE, 0); |
| 200 | + timer_stats_account_hrtimer(timer); |
| 201 | + fn = timer->function; |
| 202 | + |
| 203 | + raw_spin_unlock_irq(&cpu_base->lock); |
| 204 | + restart = fn(timer); |
| 205 | + raw_spin_lock_irq(&cpu_base->lock); |
| 206 | + |
| 207 | + hrtimer_rt_reprogram(restart, timer, base); |
| 208 | + raw_write_seqcount_barrier(&cpu_base->seq); |
| 209 | + |
| 210 | + WARN_ON_ONCE(cpu_base->running_soft != timer); |
| 211 | + cpu_base->running_soft = NULL; |
| 212 | + } |
| 213 | + } |
| 214 | + |
| 215 | + raw_spin_unlock_irq(&cpu_base->lock); |
| 216 | + |
| 217 | + wake_up_timer_waiters(cpu_base); |
| 218 | +} |
| 219 | + |
| 220 | +static int hrtimer_rt_defer(struct hrtimer *timer) |
| 221 | +{ |
| 222 | + if (timer->irqsafe) |
| 223 | + return 0; |
| 224 | + |
| 225 | + __remove_hrtimer(timer, timer->base, timer->state, 0); |
| 226 | + list_add_tail(&timer->cb_entry, &timer->base->expired); |
| 227 | + return 1; |
| 228 | +} |
| 229 | + |
| 230 | +#else |
| 231 | + |
| 232 | +static inline int hrtimer_rt_defer(struct hrtimer *timer) { return 0; } |
| 233 | + |
| 234 | +#endif |
| 235 | + |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 236 | + |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 237 | static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now) |
| 238 | { |
| 239 | struct hrtimer_clock_base *base = cpu_base->clock_base; |
| 240 | unsigned int active = cpu_base->active_bases; |
| 241 | + int raise = 0; |
| 242 | |
| 243 | for (; active; base++, active >>= 1) { |
| 244 | struct timerqueue_node *node; |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 245 | @@ -1354,15 +1459,20 @@ static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now) |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 246 | if (basenow.tv64 < hrtimer_get_softexpires_tv64(timer)) |
| 247 | break; |
| 248 | |
| 249 | - __run_hrtimer(cpu_base, base, timer, &basenow); |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 250 | + if (!hrtimer_rt_defer(timer)) |
| 251 | + __run_hrtimer(cpu_base, base, timer, &basenow); |
| 252 | + else |
| 253 | + raise = 1; |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 254 | } |
| 255 | } |
| 256 | + if (raise) |
| 257 | + raise_softirq_irqoff(HRTIMER_SOFTIRQ); |
| 258 | } |
| 259 | |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 260 | -#ifdef CONFIG_HIGH_RES_TIMERS |
| 261 | - |
| 262 | static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer); |
| 263 | |
| 264 | +#ifdef CONFIG_HIGH_RES_TIMERS |
| 265 | + |
| 266 | /* |
| 267 | * High resolution timer interrupt |
| 268 | * Called with interrupts disabled |
| 269 | @@ -1500,8 +1610,6 @@ void hrtimer_run_queues(void) |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 270 | now = hrtimer_update_base(cpu_base); |
| 271 | __hrtimer_run_queues(cpu_base, now); |
| 272 | raw_spin_unlock(&cpu_base->lock); |
| 273 | - |
| 274 | - wake_up_timer_waiters(cpu_base); |
| 275 | } |
| 276 | |
| 277 | /* |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 278 | @@ -1523,6 +1631,7 @@ static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer) |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 279 | void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task) |
| 280 | { |
| 281 | sl->timer.function = hrtimer_wakeup; |
| 282 | + sl->timer.irqsafe = 1; |
| 283 | sl->task = task; |
| 284 | } |
| 285 | EXPORT_SYMBOL_GPL(hrtimer_init_sleeper); |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 286 | @@ -1657,6 +1766,7 @@ static void init_hrtimers_cpu(int cpu) |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 287 | for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { |
| 288 | cpu_base->clock_base[i].cpu_base = cpu_base; |
| 289 | timerqueue_init_head(&cpu_base->clock_base[i].active); |
| 290 | + INIT_LIST_HEAD(&cpu_base->clock_base[i].expired); |
| 291 | } |
| 292 | |
| 293 | cpu_base->cpu = cpu; |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 294 | @@ -1761,11 +1871,21 @@ static struct notifier_block hrtimers_nb = { |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 295 | .notifier_call = hrtimer_cpu_notify, |
| 296 | }; |
| 297 | |
| 298 | +#ifdef CONFIG_PREEMPT_RT_BASE |
| 299 | +static void run_hrtimer_softirq(struct softirq_action *h) |
| 300 | +{ |
| 301 | + hrtimer_rt_run_pending(); |
| 302 | +} |
| 303 | +#endif |
| 304 | + |
| 305 | void __init hrtimers_init(void) |
| 306 | { |
| 307 | hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE, |
| 308 | (void *)(long)smp_processor_id()); |
| 309 | register_cpu_notifier(&hrtimers_nb); |
| 310 | +#ifdef CONFIG_PREEMPT_RT_BASE |
| 311 | + open_softirq(HRTIMER_SOFTIRQ, run_hrtimer_softirq); |
| 312 | +#endif |
| 313 | } |
| 314 | |
| 315 | /** |
| 316 | diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c |
| 317 | index 9579f7985093..f92ba9983ab9 100644 |
| 318 | --- a/kernel/time/tick-sched.c |
| 319 | +++ b/kernel/time/tick-sched.c |
| 320 | @@ -1105,6 +1105,7 @@ void tick_setup_sched_timer(void) |
| 321 | * Emulate tick processing via per-CPU hrtimers: |
| 322 | */ |
| 323 | hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); |
| 324 | + ts->sched_timer.irqsafe = 1; |
| 325 | ts->sched_timer.function = tick_sched_timer; |
| 326 | |
| 327 | /* Get the next period (per cpu) */ |
| 328 | diff --git a/kernel/watchdog.c b/kernel/watchdog.c |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 329 | index 0d180c9f3d5f..88b20a01af23 100644 |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 330 | --- a/kernel/watchdog.c |
| 331 | +++ b/kernel/watchdog.c |
| 332 | @@ -585,6 +585,7 @@ static void watchdog_enable(unsigned int cpu) |
| 333 | /* kick off the timer for the hardlockup detector */ |
| 334 | hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| 335 | hrtimer->function = watchdog_timer_fn; |
| 336 | + hrtimer->irqsafe = 1; |
| 337 | |
| 338 | /* Enable the perf event */ |
| 339 | watchdog_nmi_enable(cpu); |
| 340 | -- |
Allen Martin | fc468d8 | 2016-11-15 17:57:52 -0800 | [diff] [blame] | 341 | 2.10.1 |
Allen Martin | 685e0f8 | 2016-07-26 19:34:29 -0700 | [diff] [blame] | 342 | |