All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Zijlstra <peterz@infradead.org>
To: Thomas Gleixner <tglx@linutronix.de>
Cc: mingo@kernel.org, linux-kernel@vger.kernel.org,
	Ben Segall <bsegall@google.com>,
	Roman Gushchin <klamm@yandex-team.ru>,
	Paul Turner <pjt@google.com>
Subject: Re: [PATCH 1/3] hrtimer: Fix race between hrtimer_start() and __run_hrtimer()
Date: Wed, 15 Apr 2015 13:31:05 +0200	[thread overview]
Message-ID: <20150415113105.GT5029@twins.programming.kicks-ass.net> (raw)
In-Reply-To: <alpine.DEB.2.11.1504151209510.3845@nanos>

On Wed, Apr 15, 2015 at 12:26:58PM +0200, Thomas Gleixner wrote:
> On Wed, 15 Apr 2015, Peter Zijlstra wrote:
> > hrtimer: Fix race between hrtimer_start() and __run_hrtimer()
> 
> I don't think that subject line is correct.
> 
> Back in the early hrtimer days we made deliberately the design
> decision that this kind of usage is forbidden. The reason for this is
> that the hrtimer infrastructure cannot provide proper
> serialization. So we thought it would be a sane restruction that
> restarting a timer from the callback should not be mixed with
> concurrent restarts from a different call site.

Ah I was not aware. Until I changed the locking it was possible simply
because everything was serialized by the base lock. So the concurrent
start would either land before the callback or after it but not in the
middle like it can now.

> So I rather prefer a subject line like this
> 
> hrtimer: Allow concurrent hrtimer_start() for self restarting timers
> 

/me copy/paste, done! :-)

> > To that effect, add a WARN when someone tries to forward an already
> > enqueued timer.
> 
> The warnon itself is nice, but what about sites which use
> hrtimer_set_expires() and hrtimer_start_expires()?

They are all inlines, furthermore forward is the most common way to
change the expiry of periodic / self restarting timers so would gain us
most.

How about this then?

---
Subject: hrtimer: Allow concurrent hrtimer_start() for self restarting timers
From: Peter Zijlstra <peterz@infradead.org>
Date: Tue May 20 15:49:48 CEST 2014

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")
Cc: Ben Segall <bsegall@google.com>
Cc: Roman Gushchin <klamm@yandex-team.ru>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Paul Turner <pjt@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
 kernel/time/hrtimer.c |   12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -791,6 +791,9 @@ u64 hrtimer_forward(struct hrtimer *time
 	if (delta.tv64 < 0)
 		return 0;
 
+	if (WARN_ON(timer->state & HRTIMER_STATE_ENQUEUED))
+		return 0;
+
 	if (interval.tv64 < hrtimer_resolution)
 		interval.tv64 = hrtimer_resolution;
 
@@ -1131,11 +1134,14 @@ static void __run_hrtimer(struct hrtimer
 	 * Note: We clear the CALLBACK bit after enqueue_hrtimer and
 	 * we do not reprogramm the event hardware. Happens either in
 	 * hrtimer_start_range_ns() or in hrtimer_interrupt()
+	 *
+	 * Note: Because we dropped the cpu_base->lock above,
+	 * hrtimer_start_range_ns() can have popped in and enqueued the timer
+	 * for us already.
 	 */
-	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));
 

  reply	other threads:[~2015-04-15 11:31 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-15  9:41 [PATCH 0/3] hrtimer (related) fixes Peter Zijlstra
2015-04-15  9:41 ` [PATCH 1/3] hrtimer: Fix race between hrtimer_start() and __run_hrtimer() Peter Zijlstra
2015-04-15 10:26   ` Thomas Gleixner
2015-04-15 11:31     ` Peter Zijlstra [this message]
2015-04-15 11:35       ` Thomas Gleixner
2015-04-15 11:43         ` Peter Zijlstra
2015-04-22 19:15       ` [tip:timers/core] hrtimer: Allow concurrent hrtimer_start() for self restarting timers tip-bot for Peter Zijlstra
2015-05-12 13:52         ` Sasha Levin
2015-05-13 13:43           ` Peter Zijlstra
2015-05-13 13:54             ` Ingo Molnar
2015-05-13 17:25             ` bsegall
2015-05-13 23:09             ` Sasha Levin
2015-05-14 10:23               ` Peter Zijlstra
2015-05-18 15:21                 ` [tip:timers/core] sched,perf: Fix periodic timers tip-bot for Peter Zijlstra
2015-04-15  9:41 ` [PATCH 2/3] sched: Cleanup bandwidth timers Peter Zijlstra
2015-04-16 20:03   ` bsegall
2015-04-22 19:15   ` [tip:timers/core] " tip-bot for Peter Zijlstra
2015-04-15  9:41 ` [PATCH 3/3] perf: Fix mux_interval hrtimer wreckage Peter Zijlstra
2015-04-15 13:48   ` David Ahern
2015-04-15 14:20     ` Peter Zijlstra
2015-04-22 15:12   ` Thomas Gleixner
2015-04-22 19:15   ` [tip:timers/core] " tip-bot for Peter Zijlstra

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150415113105.GT5029@twins.programming.kicks-ass.net \
    --to=peterz@infradead.org \
    --cc=bsegall@google.com \
    --cc=klamm@yandex-team.ru \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=pjt@google.com \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.