Dear RT folks! I'm pleased to announce the v4.14.8-rt9 patch set. Changes since v4.14.8-rt8: - Tom Zanussi's "tracing: Inter-event (e.g. latency) support" patch has been updated to v8. - The hrtimer-softirq rewrite by Anna-Maria has been updated to v4 (last I claimed I updated to v4 I updated to v3). This update includes the following fix: - Add bh_disable/enable() with a comment in hrtimers_dead_cpu(). Lockdep complained about a possible deadlock, reported by Grygorii Strashko. - Merge the series "timer/nohz: Fix timer/nohz woes" with NOHZ / timer related fixes by Anna-Maria and Thomas Gleixner. - The known issue "crash on UP system with a SMP kernel" reported last time has been resolved by a patch in from Steven Rostedt which is part of v4.14.8. Known issues - A warning triggered in "rcu_note_context_switch" originated from SyS_timer_gettime(). The issue was always there, it is now visible. Reported by Grygorii Strashko and Daniel Wagner. The delta patch against v4.14.8-rt8 is appended below and can be found here: https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.14/incr/patch-4.14.8-rt8-rt9.patch.xz You can get this release via the git tree at: git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v4.14.8-rt9 The RT patch against v4.14.8 can be found here: https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.14/older/patch-4.14.8-rt9.patch.xz The split quilt queue is available at: https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.14/older/patches-4.14.8-rt9.tar.xz Sebastian diff --git a/kernel/softirq.c b/kernel/softirq.c index d9fbc5ff378f..5c9ecaed3645 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -838,7 +838,8 @@ static inline void tick_irq_exit(void) int cpu = smp_processor_id(); /* Make sure that timer wheel updates are propagated */ - if ((idle_cpu(cpu) && !need_resched()) || tick_nohz_full_cpu(cpu)) { + if ((idle_cpu(cpu) || tick_nohz_full_cpu(cpu)) && + !need_resched() && !local_softirq_pending()) { if (!in_interrupt()) tick_nohz_irq_exit(); } diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index c2c344fda487..fb3413d2b738 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -68,9 +68,6 @@ #define HRTIMER_ACTIVE_SOFT (HRTIMER_ACTIVE_HARD << MASK_SHIFT) #define HRTIMER_ACTIVE_ALL (HRTIMER_ACTIVE_SOFT | HRTIMER_ACTIVE_HARD) -/* Define for debug mode check */ -#define HRTIMER_MODECHECK true - /* * The timer bases: * @@ -415,18 +412,8 @@ static inline void debug_hrtimer_init(struct hrtimer *timer) } static inline void debug_hrtimer_activate(struct hrtimer *timer, - enum hrtimer_mode mode, - bool modecheck) + enum hrtimer_mode mode) { - /* - * Check whether the HRTIMER_MODE_SOFT bit and hrtimer.is_soft - * match, when a timer is started via__hrtimer_start_range_ns(). - */ -#ifndef CONFIG_PREEMPT_RT_BASE - if (modecheck) - WARN_ON_ONCE(!(mode & HRTIMER_MODE_SOFT) ^ !timer->is_soft); -#endif - debug_object_activate(timer, &hrtimer_debug_descr); } @@ -461,8 +448,7 @@ EXPORT_SYMBOL_GPL(destroy_hrtimer_on_stack); static inline void debug_hrtimer_init(struct hrtimer *timer) { } static inline void debug_hrtimer_activate(struct hrtimer *timer, - enum hrtimer_mode mode, - bool modecheck) { } + enum hrtimer_mode mode) { } static inline void debug_hrtimer_deactivate(struct hrtimer *timer) { } #endif @@ -475,10 +461,9 @@ debug_init(struct hrtimer *timer, clockid_t clockid, } static inline void debug_activate(struct hrtimer *timer, - enum hrtimer_mode mode, - bool modecheck) + enum hrtimer_mode mode) { - debug_hrtimer_activate(timer, mode, modecheck); + debug_hrtimer_activate(timer, mode); trace_hrtimer_start(timer, mode); } @@ -491,15 +476,15 @@ static inline void debug_deactivate(struct hrtimer *timer) static struct hrtimer_clock_base * __next_base(struct hrtimer_cpu_base *cpu_base, unsigned int *active) { - struct hrtimer_clock_base *base = NULL; + unsigned int idx; - if (*active) { - unsigned int idx = __ffs(*active); - *active &= ~(1U << idx); - base = &cpu_base->clock_base[idx]; - } + if (!*active) + return NULL; - return base; + idx = __ffs(*active); + *active &= ~(1U << idx); + + return &cpu_base->clock_base[idx]; } #define for_each_active_base(base, cpu_base, active) \ @@ -546,11 +531,11 @@ static ktime_t __hrtimer_next_event_base(struct hrtimer_cpu_base *cpu_base, * hrtimer_run_softirq(), hrtimer_update_softirq_timer() will re-add these bases. * * Therefore softirq values are those from the HRTIMER_ACTIVE_SOFT clock bases. - * The !softirq values are the minima across HRTIMER_ACTIVE, unless an actual + * The !softirq values are the minima across HRTIMER_ACTIVE_ALL, unless an actual * softirq is pending, in which case they're the minima of HRTIMER_ACTIVE_HARD. * * @active_mask must be one of: - * - HRTIMER_ACTIVE, + * - HRTIMER_ACTIVE_ALL, * - HRTIMER_ACTIVE_SOFT, or * - HRTIMER_ACTIVE_HARD. */ @@ -801,6 +786,13 @@ static void hrtimer_reprogram(struct hrtimer *timer, bool reprogram) expires = 0; if (timer->is_soft) { + /* + * soft hrtimer could be started on a remote CPU. In this + * case softirq_expires_next needs to be updated on the + * remote CPU. The soft hrtimer will not expire before the + * first hard hrtimer on the remote CPU - + * hrtimer_check_target() prevents this case. + */ struct hrtimer_cpu_base *timer_cpu_base = base->cpu_base; if (timer_cpu_base->softirq_activated) @@ -995,10 +987,9 @@ void hrtimer_wait_for_timer(const struct hrtimer *timer) */ static int enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, - enum hrtimer_mode mode, - bool modecheck) + enum hrtimer_mode mode) { - debug_activate(timer, mode, modecheck); + debug_activate(timer, mode); base->cpu_base->active_bases |= 1 << base->index; @@ -1104,7 +1095,7 @@ hrtimer_update_softirq_timer(struct hrtimer_cpu_base *cpu_base, bool reprogram) * hrtimer expires at the same time than the next hard * hrtimer. cpu_base->softirq_expires_next needs to be updated! */ - if (!reprogram || expires == KTIME_MAX) + if (expires == KTIME_MAX) return; /* @@ -1133,8 +1124,9 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, /* Switch the timer base, if necessary: */ new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED); - return enqueue_hrtimer(timer, new_base, mode, HRTIMER_MODECHECK); + return enqueue_hrtimer(timer, new_base, mode); } + /** * hrtimer_start_range_ns - (re)start an hrtimer * @timer: the timer to be added @@ -1150,6 +1142,14 @@ void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, struct hrtimer_clock_base *base; unsigned long flags; + /* + * Check whether the HRTIMER_MODE_SOFT bit and hrtimer.is_soft + * match. + */ +#ifndef CONFIG_PREEMPT_RT_BASE + WARN_ON_ONCE(!(mode & HRTIMER_MODE_SOFT) ^ !timer->is_soft); +#endif + base = lock_hrtimer_base(timer, &flags); if (__hrtimer_start_range_ns(timer, tim, delta_ns, mode, base)) @@ -1424,8 +1424,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, */ if (restart != HRTIMER_NORESTART && !(timer->state & HRTIMER_STATE_ENQUEUED)) - enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS, - !HRTIMER_MODECHECK); + enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS); /* * Separate the ->running assignment from the ->state assignment. @@ -1939,8 +1938,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, * sort out already expired timers and reprogram the * event device. */ - enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS, - !HRTIMER_MODECHECK); + enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS); } } @@ -1952,6 +1950,12 @@ int hrtimers_dead_cpu(unsigned int scpu) BUG_ON(cpu_online(scpu)); tick_cancel_sched_timer(scpu); + /* + * this BH disable ensures that raise_softirq_irqoff() does + * not wakeup ksoftirqd (and acquire the pi-lock) while + * holding the cpu_base lock + */ + local_bh_disable(); local_irq_disable(); old_base = &per_cpu(hrtimer_bases, scpu); new_base = this_cpu_ptr(&hrtimer_bases); @@ -1979,6 +1983,7 @@ int hrtimers_dead_cpu(unsigned int scpu) /* Check, if we got expired work to do */ __hrtimer_peek_ahead_timers(); local_irq_enable(); + local_bh_enable(); return 0; } diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 40ac38728b7a..26210086c562 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -844,11 +844,10 @@ static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu) struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_STD], cpu); /* - * If the timer is deferrable and nohz is active then we need to use - * the deferrable base. + * If the timer is deferrable and NO_HZ_COMMON is set then we need + * to use the deferrable base. */ - if (is_timers_nohz_active() && - (tflags & TIMER_DEFERRABLE)) + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && (tflags & TIMER_DEFERRABLE)) base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu); return base; } @@ -858,11 +857,10 @@ static inline struct timer_base *get_timer_this_cpu_base(u32 tflags) struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); /* - * If the timer is deferrable and nohz is active then we need to use - * the deferrable base. + * If the timer is deferrable and NO_HZ_COMMON is set then we need + * to use the deferrable base. */ - if (is_timers_nohz_active() && - (tflags & TIMER_DEFERRABLE)) + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && (tflags & TIMER_DEFERRABLE)) base = this_cpu_ptr(&timer_bases[BASE_DEF]); return base; } @@ -1005,8 +1003,6 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) if (!ret && pending_only) goto out_unlock; - debug_activate(timer, expires); - new_base = get_target_base(base, timer->flags); if (base != new_base) { @@ -1030,6 +1026,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) } } + debug_activate(timer, expires); + timer->expires = expires; /* * If 'idx' was calculated above and the base time did not advance @@ -1696,7 +1694,7 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h) base->must_forward_clk = false; __run_timers(base); - if (is_timers_nohz_active()) + if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); } diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index e244f26d4761..8a00d4da91f2 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -613,7 +613,7 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter, /* parameter values */ if (se->fields[i]->is_string) { trace_seq_printf(s, print_fmt, se->fields[i]->name, - (char *)(long)entry->fields[n_u64], + (char *)&entry->fields[n_u64], i == se->n_fields - 1 ? "" : " "); n_u64 += STR_VAR_LEN_MAX / sizeof(u64); } else { @@ -1500,37 +1500,25 @@ static struct trace_event_file *find_var_file(struct trace_array *tr, { struct hist_trigger_data *var_hist_data; struct hist_var_data *var_data; - struct trace_event_call *call; struct trace_event_file *file, *found = NULL; - const char *name; + + if (system) + return find_event_file(tr, system, event_name); list_for_each_entry(var_data, &tr->hist_vars, list) { var_hist_data = var_data->hist_data; file = var_hist_data->event_file; if (file == found) continue; - call = file->event_call; - name = trace_event_name(call); - if (!system || !event_name) { - if (find_var(var_hist_data, file, var_name)) { - if (found) { - hist_err_event("Variable name not unique, need to use fully qualified name (subsys.event.var) for variable: ", system, event_name, var_name); - return NULL; - } - - found = file; + if (find_var_field(var_hist_data, var_name)) { + if (found) { + hist_err_event("Variable name not unique, need to use fully qualified name (subsys.event.var) for variable: ", system, event_name, var_name); + return NULL; } - continue; + + found = file; } - - if (strcmp(event_name, name) != 0) - continue; - if (strcmp(system, call->class->system) != 0) - continue; - - found = file; - break; } return found; @@ -1977,7 +1965,7 @@ static void hist_trigger_elt_data_free(struct tracing_map_elt *elt) static int hist_trigger_elt_data_alloc(struct tracing_map_elt *elt) { struct hist_trigger_data *hist_data = elt->map->private_data; - unsigned int size = TASK_COMM_LEN + 1; + unsigned int size = TASK_COMM_LEN; struct hist_elt_data *elt_data; struct hist_field *key_field; unsigned int i, n_str; diff --git a/lib/timerqueue.c b/lib/timerqueue.c index 4a720ed4fdaf..0d54bcbc8170 100644 --- a/lib/timerqueue.c +++ b/lib/timerqueue.c @@ -33,8 +33,9 @@ * @head: head of timerqueue * @node: timer node to be added * - * Adds the timer node to the timerqueue, sorted by the - * node's expires value. + * Adds the timer node to the timerqueue, sorted by the node's expires + * value. Returns true if the newly added timer is the first expiring timer in + * the queue. */ bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node) { @@ -70,7 +71,8 @@ EXPORT_SYMBOL_GPL(timerqueue_add); * @head: head of timerqueue * @node: timer node to be removed * - * Removes the timer node from the timerqueue. + * Removes the timer node from the timerqueue. Returns true if the queue is + * not empty after the remove. */ bool timerqueue_del(struct timerqueue_head *head, struct timerqueue_node *node) { diff --git a/localversion-rt b/localversion-rt index 700c857efd9b..22746d6390a4 100644 --- a/localversion-rt +++ b/localversion-rt @@ -1 +1 @@ --rt8 +-rt9 -- To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html