diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-07-19 12:25:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-07-19 12:25:03 -0400 |
commit | b495c23cd4ed0a7ad827eb07c7c9f61767f6674f (patch) | |
tree | 01f711ddc0aaa6a42b75ccab99499b78a18e580d | |
parent | da5b99b4545e2bae9a08876e6e827589dbfdcd9a (diff) | |
parent | 16927776ae757d0d132bdbfabbfe2c498342bd59 (diff) |
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer fix from Thomas Gleixner:
"A single fix for a long standing issue in the alarm timer subsystem,
which was noticed recently when people finally started to use alarm
timers for serious work"
* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
alarmtimer: Fix bug where relative alarm timers were treated as absolute
-rw-r--r-- | kernel/time/alarmtimer.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 88c9c65a430d..fe75444ae7ec 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c | |||
@@ -585,9 +585,14 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, | |||
585 | struct itimerspec *new_setting, | 585 | struct itimerspec *new_setting, |
586 | struct itimerspec *old_setting) | 586 | struct itimerspec *old_setting) |
587 | { | 587 | { |
588 | ktime_t exp; | ||
589 | |||
588 | if (!rtcdev) | 590 | if (!rtcdev) |
589 | return -ENOTSUPP; | 591 | return -ENOTSUPP; |
590 | 592 | ||
593 | if (flags & ~TIMER_ABSTIME) | ||
594 | return -EINVAL; | ||
595 | |||
591 | if (old_setting) | 596 | if (old_setting) |
592 | alarm_timer_get(timr, old_setting); | 597 | alarm_timer_get(timr, old_setting); |
593 | 598 | ||
@@ -597,8 +602,16 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, | |||
597 | 602 | ||
598 | /* start the timer */ | 603 | /* start the timer */ |
599 | timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval); | 604 | timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval); |
600 | alarm_start(&timr->it.alarm.alarmtimer, | 605 | exp = timespec_to_ktime(new_setting->it_value); |
601 | timespec_to_ktime(new_setting->it_value)); | 606 | /* Convert (if necessary) to absolute time */ |
607 | if (flags != TIMER_ABSTIME) { | ||
608 | ktime_t now; | ||
609 | |||
610 | now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime(); | ||
611 | exp = ktime_add(now, exp); | ||
612 | } | ||
613 | |||
614 | alarm_start(&timr->it.alarm.alarmtimer, exp); | ||
602 | return 0; | 615 | return 0; |
603 | } | 616 | } |
604 | 617 | ||
@@ -730,6 +743,9 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, | |||
730 | if (!alarmtimer_get_rtcdev()) | 743 | if (!alarmtimer_get_rtcdev()) |
731 | return -ENOTSUPP; | 744 | return -ENOTSUPP; |
732 | 745 | ||
746 | if (flags & ~TIMER_ABSTIME) | ||
747 | return -EINVAL; | ||
748 | |||
733 | if (!capable(CAP_WAKE_ALARM)) | 749 | if (!capable(CAP_WAKE_ALARM)) |
734 | return -EPERM; | 750 | return -EPERM; |
735 | 751 | ||