diff options
-rw-r--r-- | include/linux/hrtimer.h | 2 | ||||
-rw-r--r-- | kernel/compat.c | 57 | ||||
-rw-r--r-- | kernel/hrtimer.c | 29 | ||||
-rw-r--r-- | kernel/posix-timers.c | 17 |
4 files changed, 42 insertions, 63 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 540799bc85f8..7a9398e19704 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h | |||
@@ -300,7 +300,7 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval); | |||
300 | 300 | ||
301 | /* Precise sleep: */ | 301 | /* Precise sleep: */ |
302 | extern long hrtimer_nanosleep(struct timespec *rqtp, | 302 | extern long hrtimer_nanosleep(struct timespec *rqtp, |
303 | struct timespec __user *rmtp, | 303 | struct timespec *rmtp, |
304 | const enum hrtimer_mode mode, | 304 | const enum hrtimer_mode mode, |
305 | const clockid_t clockid); | 305 | const clockid_t clockid); |
306 | extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); | 306 | extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); |
diff --git a/kernel/compat.c b/kernel/compat.c index b78328af19ad..42a1ed4b61b1 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
@@ -40,62 +40,27 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user | |||
40 | __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; | 40 | __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; |
41 | } | 41 | } |
42 | 42 | ||
43 | static long compat_nanosleep_restart(struct restart_block *restart) | ||
44 | { | ||
45 | unsigned long expire = restart->arg0, now = jiffies; | ||
46 | struct compat_timespec __user *rmtp; | ||
47 | |||
48 | /* Did it expire while we handled signals? */ | ||
49 | if (!time_after(expire, now)) | ||
50 | return 0; | ||
51 | |||
52 | expire = schedule_timeout_interruptible(expire - now); | ||
53 | if (expire == 0) | ||
54 | return 0; | ||
55 | |||
56 | rmtp = (struct compat_timespec __user *)restart->arg1; | ||
57 | if (rmtp) { | ||
58 | struct compat_timespec ct; | ||
59 | struct timespec t; | ||
60 | |||
61 | jiffies_to_timespec(expire, &t); | ||
62 | ct.tv_sec = t.tv_sec; | ||
63 | ct.tv_nsec = t.tv_nsec; | ||
64 | if (copy_to_user(rmtp, &ct, sizeof(ct))) | ||
65 | return -EFAULT; | ||
66 | } | ||
67 | /* The 'restart' block is already filled in */ | ||
68 | return -ERESTART_RESTARTBLOCK; | ||
69 | } | ||
70 | |||
71 | asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, | 43 | asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, |
72 | struct compat_timespec __user *rmtp) | 44 | struct compat_timespec __user *rmtp) |
73 | { | 45 | { |
74 | struct timespec t; | 46 | struct timespec tu, rmt; |
75 | struct restart_block *restart; | 47 | long ret; |
76 | unsigned long expire; | ||
77 | 48 | ||
78 | if (get_compat_timespec(&t, rqtp)) | 49 | if (get_compat_timespec(&tu, rqtp)) |
79 | return -EFAULT; | 50 | return -EFAULT; |
80 | 51 | ||
81 | if ((t.tv_nsec >= 1000000000L) || (t.tv_nsec < 0) || (t.tv_sec < 0)) | 52 | if (!timespec_valid(&tu)) |
82 | return -EINVAL; | 53 | return -EINVAL; |
83 | 54 | ||
84 | expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); | 55 | ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL, |
85 | expire = schedule_timeout_interruptible(expire); | 56 | CLOCK_MONOTONIC); |
86 | if (expire == 0) | ||
87 | return 0; | ||
88 | 57 | ||
89 | if (rmtp) { | 58 | if (ret && rmtp) { |
90 | jiffies_to_timespec(expire, &t); | 59 | if (put_compat_timespec(&rmt, rmtp)) |
91 | if (put_compat_timespec(&t, rmtp)) | ||
92 | return -EFAULT; | 60 | return -EFAULT; |
93 | } | 61 | } |
94 | restart = ¤t_thread_info()->restart_block; | 62 | |
95 | restart->fn = compat_nanosleep_restart; | 63 | return ret; |
96 | restart->arg0 = jiffies + expire; | ||
97 | restart->arg1 = (unsigned long) rmtp; | ||
98 | return -ERESTART_RESTARTBLOCK; | ||
99 | } | 64 | } |
100 | 65 | ||
101 | static inline long get_compat_itimerval(struct itimerval *o, | 66 | static inline long get_compat_itimerval(struct itimerval *o, |
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index dc8a4451d79b..b2b2c2b0a49b 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -1286,8 +1286,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod | |||
1286 | long __sched hrtimer_nanosleep_restart(struct restart_block *restart) | 1286 | long __sched hrtimer_nanosleep_restart(struct restart_block *restart) |
1287 | { | 1287 | { |
1288 | struct hrtimer_sleeper t; | 1288 | struct hrtimer_sleeper t; |
1289 | struct timespec __user *rmtp; | 1289 | struct timespec *rmtp; |
1290 | struct timespec tu; | ||
1291 | ktime_t time; | 1290 | ktime_t time; |
1292 | 1291 | ||
1293 | restart->fn = do_no_restart_syscall; | 1292 | restart->fn = do_no_restart_syscall; |
@@ -1298,14 +1297,12 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart) | |||
1298 | if (do_nanosleep(&t, HRTIMER_MODE_ABS)) | 1297 | if (do_nanosleep(&t, HRTIMER_MODE_ABS)) |
1299 | return 0; | 1298 | return 0; |
1300 | 1299 | ||
1301 | rmtp = (struct timespec __user *) restart->arg1; | 1300 | rmtp = (struct timespec *)restart->arg1; |
1302 | if (rmtp) { | 1301 | if (rmtp) { |
1303 | time = ktime_sub(t.timer.expires, t.timer.base->get_time()); | 1302 | time = ktime_sub(t.timer.expires, t.timer.base->get_time()); |
1304 | if (time.tv64 <= 0) | 1303 | if (time.tv64 <= 0) |
1305 | return 0; | 1304 | return 0; |
1306 | tu = ktime_to_timespec(time); | 1305 | *rmtp = ktime_to_timespec(time); |
1307 | if (copy_to_user(rmtp, &tu, sizeof(tu))) | ||
1308 | return -EFAULT; | ||
1309 | } | 1306 | } |
1310 | 1307 | ||
1311 | restart->fn = hrtimer_nanosleep_restart; | 1308 | restart->fn = hrtimer_nanosleep_restart; |
@@ -1314,12 +1311,11 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart) | |||
1314 | return -ERESTART_RESTARTBLOCK; | 1311 | return -ERESTART_RESTARTBLOCK; |
1315 | } | 1312 | } |
1316 | 1313 | ||
1317 | long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, | 1314 | long hrtimer_nanosleep(struct timespec *rqtp, struct timespec *rmtp, |
1318 | const enum hrtimer_mode mode, const clockid_t clockid) | 1315 | const enum hrtimer_mode mode, const clockid_t clockid) |
1319 | { | 1316 | { |
1320 | struct restart_block *restart; | 1317 | struct restart_block *restart; |
1321 | struct hrtimer_sleeper t; | 1318 | struct hrtimer_sleeper t; |
1322 | struct timespec tu; | ||
1323 | ktime_t rem; | 1319 | ktime_t rem; |
1324 | 1320 | ||
1325 | hrtimer_init(&t.timer, clockid, mode); | 1321 | hrtimer_init(&t.timer, clockid, mode); |
@@ -1335,9 +1331,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, | |||
1335 | rem = ktime_sub(t.timer.expires, t.timer.base->get_time()); | 1331 | rem = ktime_sub(t.timer.expires, t.timer.base->get_time()); |
1336 | if (rem.tv64 <= 0) | 1332 | if (rem.tv64 <= 0) |
1337 | return 0; | 1333 | return 0; |
1338 | tu = ktime_to_timespec(rem); | 1334 | *rmtp = ktime_to_timespec(rem); |
1339 | if (copy_to_user(rmtp, &tu, sizeof(tu))) | ||
1340 | return -EFAULT; | ||
1341 | } | 1335 | } |
1342 | 1336 | ||
1343 | restart = ¤t_thread_info()->restart_block; | 1337 | restart = ¤t_thread_info()->restart_block; |
@@ -1353,7 +1347,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, | |||
1353 | asmlinkage long | 1347 | asmlinkage long |
1354 | sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) | 1348 | sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) |
1355 | { | 1349 | { |
1356 | struct timespec tu; | 1350 | struct timespec tu, rmt; |
1351 | int ret; | ||
1357 | 1352 | ||
1358 | if (copy_from_user(&tu, rqtp, sizeof(tu))) | 1353 | if (copy_from_user(&tu, rqtp, sizeof(tu))) |
1359 | return -EFAULT; | 1354 | return -EFAULT; |
@@ -1361,7 +1356,15 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) | |||
1361 | if (!timespec_valid(&tu)) | 1356 | if (!timespec_valid(&tu)) |
1362 | return -EINVAL; | 1357 | return -EINVAL; |
1363 | 1358 | ||
1364 | return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); | 1359 | ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL, |
1360 | CLOCK_MONOTONIC); | ||
1361 | |||
1362 | if (ret && rmtp) { | ||
1363 | if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) | ||
1364 | return -EFAULT; | ||
1365 | } | ||
1366 | |||
1367 | return ret; | ||
1365 | } | 1368 | } |
1366 | 1369 | ||
1367 | /* | 1370 | /* |
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index d71ed09fe1dd..d11f579d189a 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c | |||
@@ -981,9 +981,20 @@ sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp) | |||
981 | static int common_nsleep(const clockid_t which_clock, int flags, | 981 | static int common_nsleep(const clockid_t which_clock, int flags, |
982 | struct timespec *tsave, struct timespec __user *rmtp) | 982 | struct timespec *tsave, struct timespec __user *rmtp) |
983 | { | 983 | { |
984 | return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ? | 984 | struct timespec rmt; |
985 | HRTIMER_MODE_ABS : HRTIMER_MODE_REL, | 985 | int ret; |
986 | which_clock); | 986 | |
987 | ret = hrtimer_nanosleep(tsave, rmtp ? &rmt : NULL, | ||
988 | flags & TIMER_ABSTIME ? | ||
989 | HRTIMER_MODE_ABS : HRTIMER_MODE_REL, | ||
990 | which_clock); | ||
991 | |||
992 | if (ret && rmtp) { | ||
993 | if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) | ||
994 | return -EFAULT; | ||
995 | } | ||
996 | |||
997 | return ret; | ||
987 | } | 998 | } |
988 | 999 | ||
989 | asmlinkage long | 1000 | asmlinkage long |