[Devel] [PATCH rh7] ms/hrtimer: Allow concurrent hrtimer_start() for self restarting timers
Kirill Tkhai
ktkhai at virtuozzo.com
Tue Sep 25 17:57:21 MSK 2018
On 24.09.2018 15:07, Andrey Ryabinin wrote:
> From: Peter Zijlstra <peterz at infradead.org>
>
> Because we drop cpu_base->lock around calling hrtimer::function, it is
> possible for hrtimer_start() to come in between and enqueue the timer.
>
> If hrtimer::function then returns HRTIMER_RESTART we'll hit the BUG_ON
> because HRTIMER_STATE_ENQUEUED will be set.
>
> Since the above is a perfectly valid scenario, remove the BUG_ON and
> make the enqueue_hrtimer() call conditional on the timer not being
> enqueued already.
>
> NOTE: in that concurrent scenario its entirely common for both sites
> to want to modify the hrtimer, since hrtimers don't provide
> serialization themselves be sure to provide some such that the
> hrtimer::function and the hrtimer_start() caller don't both try and
> fudge the expiration state at the same time.
>
> To that effect, add a WARN when someone tries to forward an already
> enqueued timer, the most common way to change the expiry of self
> restarting timers. Ideally we'd put the WARN in everything modifying
> the expiry but most of that is inlines and we don't need the bloat.
>
> Fixes: 2d44ae4d7135 ("hrtimer: clean up cpu->base locking tricks")
> Signed-off-by: Peter Zijlstra (Intel) <peterz at infradead.org>
> Cc: Ben Segall <bsegall at google.com>
> Cc: Roman Gushchin <klamm at yandex-team.ru>
> Cc: Paul Turner <pjt at google.com>
> Link: http://lkml.kernel.org/r/20150415113105.GT5029@twins.programming.kicks-ass.net
> Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
>
> https://jira.sw.ru/browse/PSBM-88818
> (cherry picked from commit 5de2755c8c8b3a6b8414870e2c284914a2b42e4d)
> Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
Reviewed-by: Kirill Tkhai <ktkhai at virtuozzo.com>
> ---
> kernel/hrtimer.c | 12 +++++++++---
> 1 file changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
> index 70c7747aa61a..30bf706bc211 100644
> --- a/kernel/hrtimer.c
> +++ b/kernel/hrtimer.c
> @@ -843,6 +843,9 @@ u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
> if (delta.tv64 < 0)
> return 0;
>
> + if (WARN_ON(timer->state & HRTIMER_STATE_ENQUEUED))
> + return 0;
> +
> if (interval.tv64 < timer->base->resolution.tv64)
> interval.tv64 = timer->base->resolution.tv64;
>
> @@ -1222,6 +1225,10 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
> * Because we run timers from hardirq context, there is no chance
> * they get migrated to another cpu, therefore its safe to unlock
> * the timer base.
> + *
> + * Note: Because we dropped the cpu_base->lock above,
> + * hrtimer_start_range_ns() can have popped in and enqueued the timer
> + * for us already
> */
> raw_spin_unlock(&cpu_base->lock);
> trace_hrtimer_expire_entry(timer, now);
> @@ -1234,10 +1241,9 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
> * we do not reprogramm the event hardware. Happens either in
> * hrtimer_start_range_ns() or in hrtimer_interrupt()
> */
> - if (restart != HRTIMER_NORESTART) {
> - BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
> + if (restart != HRTIMER_NORESTART &&
> + !(timer->state & HRTIMER_STATE_ENQUEUED))
> enqueue_hrtimer(timer, base);
> - }
>
> WARN_ON_ONCE(!(timer->state & HRTIMER_STATE_CALLBACK));
>
>
More information about the Devel
mailing list