Merge git://git.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-hrt
* git://git.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-hrt:
hrtimer: don't modify restart_block->fn in restart functions
hrtimer: fix *rmtp/restarts handling in compat_sys_nanosleep()
hrtimer: fix *rmtp handling in hrtimer_nanosleep()
ntp: correct inconsistent interval/tick_length usage
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 600fc3b..1ad56a7 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -316,7 +316,7 @@
/* Precise sleep: */
extern long hrtimer_nanosleep(struct timespec *rqtp,
- struct timespec *rmtp,
+ struct timespec __user *rmtp,
const enum hrtimer_mode mode,
const clockid_t clockid);
extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 8ea3e71..c3f3747 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -232,7 +232,14 @@
#else
#define NTP_INTERVAL_FREQ (HZ)
#endif
-#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
+
+#define CLOCK_TICK_OVERFLOW (LATCH * HZ - CLOCK_TICK_RATE)
+#define CLOCK_TICK_ADJUST (((s64)CLOCK_TICK_OVERFLOW * NSEC_PER_SEC) / \
+ (s64)CLOCK_TICK_RATE)
+
+/* Because using NSEC_PER_SEC would be too easy */
+#define NTP_INTERVAL_LENGTH ((((s64)TICK_USEC * NSEC_PER_USEC * USER_HZ) + \
+ CLOCK_TICK_ADJUST) / NTP_INTERVAL_FREQ)
/* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
extern u64 current_tick_length(void);
diff --git a/kernel/compat.c b/kernel/compat.c
index 42a1ed4..5f0e201 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -40,10 +40,35 @@
__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
}
+static long compat_nanosleep_restart(struct restart_block *restart)
+{
+ struct compat_timespec __user *rmtp;
+ struct timespec rmt;
+ mm_segment_t oldfs;
+ long ret;
+
+ rmtp = (struct compat_timespec __user *)(restart->arg1);
+ restart->arg1 = (unsigned long)&rmt;
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = hrtimer_nanosleep_restart(restart);
+ set_fs(oldfs);
+
+ if (ret) {
+ restart->arg1 = (unsigned long)rmtp;
+
+ if (rmtp && put_compat_timespec(&rmt, rmtp))
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
struct compat_timespec __user *rmtp)
{
struct timespec tu, rmt;
+ mm_segment_t oldfs;
long ret;
if (get_compat_timespec(&tu, rqtp))
@@ -52,11 +77,21 @@
if (!timespec_valid(&tu))
return -EINVAL;
- ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL,
- CLOCK_MONOTONIC);
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = hrtimer_nanosleep(&tu,
+ rmtp ? (struct timespec __user *)&rmt : NULL,
+ HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+ set_fs(oldfs);
- if (ret && rmtp) {
- if (put_compat_timespec(&rmt, rmtp))
+ if (ret) {
+ struct restart_block *restart
+ = ¤t_thread_info()->restart_block;
+
+ restart->fn = compat_nanosleep_restart;
+ restart->arg1 = (unsigned long)rmtp;
+
+ if (rmtp && put_compat_timespec(&rmt, rmtp))
return -EFAULT;
}
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 668f396..3f4a57c 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1319,13 +1319,26 @@
return t->task == NULL;
}
+static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp)
+{
+ struct timespec rmt;
+ ktime_t rem;
+
+ rem = ktime_sub(timer->expires, timer->base->get_time());
+ if (rem.tv64 <= 0)
+ return 0;
+ rmt = ktime_to_timespec(rem);
+
+ if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
+ return -EFAULT;
+
+ return 1;
+}
+
long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
{
struct hrtimer_sleeper t;
- struct timespec *rmtp;
- ktime_t time;
-
- restart->fn = do_no_restart_syscall;
+ struct timespec __user *rmtp;
hrtimer_init(&t.timer, restart->arg0, HRTIMER_MODE_ABS);
t.timer.expires.tv64 = ((u64)restart->arg3 << 32) | (u64) restart->arg2;
@@ -1333,26 +1346,22 @@
if (do_nanosleep(&t, HRTIMER_MODE_ABS))
return 0;
- rmtp = (struct timespec *)restart->arg1;
+ rmtp = (struct timespec __user *)restart->arg1;
if (rmtp) {
- time = ktime_sub(t.timer.expires, t.timer.base->get_time());
- if (time.tv64 <= 0)
- return 0;
- *rmtp = ktime_to_timespec(time);
+ int ret = update_rmtp(&t.timer, rmtp);
+ if (ret <= 0)
+ return ret;
}
- restart->fn = hrtimer_nanosleep_restart;
-
/* The other values in restart are already filled in */
return -ERESTART_RESTARTBLOCK;
}
-long hrtimer_nanosleep(struct timespec *rqtp, struct timespec *rmtp,
+long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
const enum hrtimer_mode mode, const clockid_t clockid)
{
struct restart_block *restart;
struct hrtimer_sleeper t;
- ktime_t rem;
hrtimer_init(&t.timer, clockid, mode);
t.timer.expires = timespec_to_ktime(*rqtp);
@@ -1364,10 +1373,9 @@
return -ERESTARTNOHAND;
if (rmtp) {
- rem = ktime_sub(t.timer.expires, t.timer.base->get_time());
- if (rem.tv64 <= 0)
- return 0;
- *rmtp = ktime_to_timespec(rem);
+ int ret = update_rmtp(&t.timer, rmtp);
+ if (ret <= 0)
+ return ret;
}
restart = ¤t_thread_info()->restart_block;
@@ -1383,8 +1391,7 @@
asmlinkage long
sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
{
- struct timespec tu, rmt;
- int ret;
+ struct timespec tu;
if (copy_from_user(&tu, rqtp, sizeof(tu)))
return -EFAULT;
@@ -1392,15 +1399,7 @@
if (!timespec_valid(&tu))
return -EINVAL;
- 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;
+ return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
}
/*
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index ce26896..022c9c3 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -982,20 +982,9 @@
static int common_nsleep(const clockid_t which_clock, int flags,
struct timespec *tsave, struct timespec __user *rmtp)
{
- struct timespec rmt;
- int ret;
-
- ret = hrtimer_nanosleep(tsave, rmtp ? &rmt : NULL,
- flags & TIMER_ABSTIME ?
- HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
- which_clock);
-
- if (ret && rmtp) {
- if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
- return -EFAULT;
- }
-
- return ret;
+ return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ?
+ HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
+ which_clock);
}
asmlinkage long
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index e64efaf..c88b591 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -43,10 +43,6 @@
static long time_reftime; /* time at last adjustment (s) */
long time_adjust;
-#define CLOCK_TICK_OVERFLOW (LATCH * HZ - CLOCK_TICK_RATE)
-#define CLOCK_TICK_ADJUST (((s64)CLOCK_TICK_OVERFLOW * NSEC_PER_SEC) / \
- (s64)CLOCK_TICK_RATE)
-
static void ntp_update_frequency(void)
{
u64 second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ)