aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time
diff options
context:
space:
mode:
authorJohn Stultz <john.stultz@linaro.org>2015-05-08 16:47:23 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-05-13 04:19:35 -0400
commitf7bcb70ebae0dcdb5a2d859b09e4465784d99029 (patch)
tree2a6a5386f7753172e3acc5b78874eeaeb1547401 /kernel/time
parent030bbdbf4c833bc69f502eae58498bc5572db736 (diff)
ktime: Fix ktime_divns to do signed division
It was noted that the 32bit implementation of ktime_divns() was doing unsigned division and didn't properly handle negative values. And when a ktime helper was changed to utilize ktime_divns, it caused a regression on some IR blasters. See the following bugzilla for details: https://bugzilla.redhat.com/show_bug.cgi?id=1200353 This patch fixes the problem in ktime_divns by checking and preserving the sign bit, and then reapplying it if appropriate after the division, it also changes the return type to a s64 to make it more obvious this is expected. Nicolas also pointed out that negative dividers would cause infinite loops on 32bit systems, negative dividers is unlikely for users of this function, but out of caution this patch adds checks for negative dividers for both 32-bit (BUG_ON) and 64-bit(WARN_ON) versions to make sure no such use cases creep in. [ tglx: Hand an u64 to do_div() to avoid the compiler warning ] Fixes: 166afb64511e 'ktime: Sanitize ktime_to_us/ms conversion' Reported-and-tested-by: Trevor Cordes <trevor@tecnopolis.ca> Signed-off-by: John Stultz <john.stultz@linaro.org> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Josh Boyer <jwboyer@redhat.com> Cc: One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk> Cc: <stable@vger.kernel.org> Link: http://lkml.kernel.org/r/1431118043-23452-1-git-send-email-john.stultz@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time')
-rw-r--r--kernel/time/hrtimer.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 76d4bd962b19..93ef7190bdea 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -266,21 +266,23 @@ lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
266/* 266/*
267 * Divide a ktime value by a nanosecond value 267 * Divide a ktime value by a nanosecond value
268 */ 268 */
269u64 __ktime_divns(const ktime_t kt, s64 div) 269s64 __ktime_divns(const ktime_t kt, s64 div)
270{ 270{
271 u64 dclc;
272 int sft = 0; 271 int sft = 0;
272 s64 dclc;
273 u64 tmp;
273 274
274 dclc = ktime_to_ns(kt); 275 dclc = ktime_to_ns(kt);
276 tmp = dclc < 0 ? -dclc : dclc;
277
275 /* Make sure the divisor is less than 2^32: */ 278 /* Make sure the divisor is less than 2^32: */
276 while (div >> 32) { 279 while (div >> 32) {
277 sft++; 280 sft++;
278 div >>= 1; 281 div >>= 1;
279 } 282 }
280 dclc >>= sft; 283 tmp >>= sft;
281 do_div(dclc, (unsigned long) div); 284 do_div(tmp, (unsigned long) div);
282 285 return dclc < 0 ? -tmp : tmp;
283 return dclc;
284} 286}
285EXPORT_SYMBOL_GPL(__ktime_divns); 287EXPORT_SYMBOL_GPL(__ktime_divns);
286#endif /* BITS_PER_LONG >= 64 */ 288#endif /* BITS_PER_LONG >= 64 */