浏览代码

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
Linus Torvalds 11 年之前
父节点
当前提交
b495c23cd4
共有 1 个文件被更改,包括 18 次插入2 次删除
  1. 18 2
      kernel/time/alarmtimer.c

+ 18 - 2
kernel/time/alarmtimer.c

@@ -585,9 +585,14 @@ static int alarm_timer_set(struct k_itimer *timr, int flags,
 				struct itimerspec *new_setting,
 				struct itimerspec *new_setting,
 				struct itimerspec *old_setting)
 				struct itimerspec *old_setting)
 {
 {
+	ktime_t exp;
+
 	if (!rtcdev)
 	if (!rtcdev)
 		return -ENOTSUPP;
 		return -ENOTSUPP;
 
 
+	if (flags & ~TIMER_ABSTIME)
+		return -EINVAL;
+
 	if (old_setting)
 	if (old_setting)
 		alarm_timer_get(timr, old_setting);
 		alarm_timer_get(timr, old_setting);
 
 
@@ -597,8 +602,16 @@ static int alarm_timer_set(struct k_itimer *timr, int flags,
 
 
 	/* start the timer */
 	/* start the timer */
 	timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval);
 	timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval);
-	alarm_start(&timr->it.alarm.alarmtimer,
-			timespec_to_ktime(new_setting->it_value));
+	exp = timespec_to_ktime(new_setting->it_value);
+	/* Convert (if necessary) to absolute time */
+	if (flags != TIMER_ABSTIME) {
+		ktime_t now;
+
+		now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime();
+		exp = ktime_add(now, exp);
+	}
+
+	alarm_start(&timr->it.alarm.alarmtimer, exp);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -730,6 +743,9 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
 	if (!alarmtimer_get_rtcdev())
 	if (!alarmtimer_get_rtcdev())
 		return -ENOTSUPP;
 		return -ENOTSUPP;
 
 
+	if (flags & ~TIMER_ABSTIME)
+		return -EINVAL;
+
 	if (!capable(CAP_WAKE_ALARM))
 	if (!capable(CAP_WAKE_ALARM))
 		return -EPERM;
 		return -EPERM;