X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=kernel%2Fhrtimer.c;h=e65dd0b47cdc13a31abc762315152cb49edea8d8;hb=de34db321a0c4630702b26db1b949b1be4dc790e;hp=dc8a4451d79b15d64a37caf55c9dc4595c6ec5d2;hpb=547307420931344a868275bd7ea7a30f117a15a9;p=linux-2.6-omap-h63xx.git diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index dc8a4451d79..e65dd0b47cd 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -412,7 +412,7 @@ static int hrtimer_reprogram(struct hrtimer *timer, /* * When the callback is running, we do not reprogram the clock event * device. The timer callback is either running on a different CPU or - * the callback is executed in the hrtimer_interupt context. The + * the callback is executed in the hrtimer_interrupt context. The * reprogramming is handled either by the softirq, which called the * callback or at the end of the hrtimer_interrupt. */ @@ -602,7 +602,7 @@ static int hrtimer_switch_to_hres(void) /* "Retrigger" the interrupt to get things going */ retrigger_next_event(NULL); local_irq_restore(flags); - printk(KERN_INFO "Switched to high resolution mode on CPU %d\n", + printk(KERN_DEBUG "Switched to high resolution mode on CPU %d\n", smp_processor_id()); return 1; } @@ -638,7 +638,7 @@ void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer, void *addr) #endif /* - * Counterpart to lock_timer_base above: + * Counterpart to lock_hrtimer_base above: */ static inline void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags) @@ -850,6 +850,14 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) #ifdef CONFIG_TIME_LOW_RES tim = ktime_add(tim, base->resolution); #endif + /* + * Careful here: User space might have asked for a + * very long sleep, so the add above might result in a + * negative number, which enqueues the timer in front + * of the queue. + */ + if (tim.tv64 < 0) + tim.tv64 = KTIME_MAX; } timer->expires = tim; @@ -1286,8 +1294,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod long __sched hrtimer_nanosleep_restart(struct restart_block *restart) { struct hrtimer_sleeper t; - struct timespec __user *rmtp; - struct timespec tu; + struct timespec *rmtp; ktime_t time; restart->fn = do_no_restart_syscall; @@ -1298,14 +1305,12 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart) if (do_nanosleep(&t, HRTIMER_MODE_ABS)) return 0; - rmtp = (struct timespec __user *) restart->arg1; + rmtp = (struct timespec *)restart->arg1; if (rmtp) { time = ktime_sub(t.timer.expires, t.timer.base->get_time()); if (time.tv64 <= 0) return 0; - tu = ktime_to_timespec(time); - if (copy_to_user(rmtp, &tu, sizeof(tu))) - return -EFAULT; + *rmtp = ktime_to_timespec(time); } restart->fn = hrtimer_nanosleep_restart; @@ -1314,12 +1319,11 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart) return -ERESTART_RESTARTBLOCK; } -long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, +long hrtimer_nanosleep(struct timespec *rqtp, struct timespec *rmtp, const enum hrtimer_mode mode, const clockid_t clockid) { struct restart_block *restart; struct hrtimer_sleeper t; - struct timespec tu; ktime_t rem; hrtimer_init(&t.timer, clockid, mode); @@ -1335,9 +1339,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, rem = ktime_sub(t.timer.expires, t.timer.base->get_time()); if (rem.tv64 <= 0) return 0; - tu = ktime_to_timespec(rem); - if (copy_to_user(rmtp, &tu, sizeof(tu))) - return -EFAULT; + *rmtp = ktime_to_timespec(rem); } restart = ¤t_thread_info()->restart_block; @@ -1353,7 +1355,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) { - struct timespec tu; + struct timespec tu, rmt; + int ret; if (copy_from_user(&tu, rqtp, sizeof(tu))) return -EFAULT; @@ -1361,7 +1364,15 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) if (!timespec_valid(&tu)) return -EINVAL; - return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); + ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL, + CLOCK_MONOTONIC); + + if (ret && rmtp) { + if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) + return -EFAULT; + } + + return ret; } /*