aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavide Libenzi <davidel@xmailserver.org>2008-02-05 01:27:26 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:07 -0500
commit4d672e7ac79b5ec5cdc90e450823441e20464691 (patch)
tree66da3aa0bf7f7ac80376a93f17edbb2246b2df06
parent5e05ad7d4e3b11f935998882b5d9c3b257137f1b (diff)
timerfd: new timerfd API
This is the new timerfd API as it is implemented by the following patch: int timerfd_create(int clockid, int flags); int timerfd_settime(int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr); int timerfd_gettime(int ufd, struct itimerspec *otmr); The timerfd_create() API creates an un-programmed timerfd fd. The "clockid" parameter can be either CLOCK_MONOTONIC or CLOCK_REALTIME. The timerfd_settime() API give new settings by the timerfd fd, by optionally retrieving the previous expiration time (in case the "otmr" parameter is not NULL). The time value specified in "utmr" is absolute, if the TFD_TIMER_ABSTIME bit is set in the "flags" parameter. Otherwise it's a relative time. The timerfd_gettime() API returns the next expiration time of the timer, or {0, 0} if the timerfd has not been set yet. Like the previous timerfd API implementation, read(2) and poll(2) are supported (with the same interface). Here's a simple test program I used to exercise the new timerfd APIs: http://www.xmailserver.org/timerfd-test2.c [akpm@linux-foundation.org: coding-style cleanups] [akpm@linux-foundation.org: fix ia64 build] [akpm@linux-foundation.org: fix m68k build] [akpm@linux-foundation.org: fix mips build] [akpm@linux-foundation.org: fix alpha, arm, blackfin, cris, m68k, s390, sparc and sparc64 builds] [heiko.carstens@de.ibm.com: fix s390] [akpm@linux-foundation.org: fix powerpc build] [akpm@linux-foundation.org: fix sparc64 more] Signed-off-by: Davide Libenzi <davidel@xmailserver.org> Cc: Michael Kerrisk <mtk-manpages@gmx.net> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Davide Libenzi <davidel@xmailserver.org> Cc: Michael Kerrisk <mtk-manpages@gmx.net> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Cc: Davide Libenzi <davidel@xmailserver.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/alpha/kernel/systbls.S2
-rw-r--r--arch/arm/kernel/calls.S2
-rw-r--r--arch/blackfin/mach-common/entry.S2
-rw-r--r--arch/cris/arch-v10/kernel/entry.S2
-rw-r--r--arch/ia64/kernel/entry.S2
-rw-r--r--arch/m68k/kernel/entry.S2
-rw-r--r--arch/m68knommu/kernel/syscalltable.S2
-rw-r--r--arch/mips/kernel/scall32-o32.S2
-rw-r--r--arch/mips/kernel/scall64-64.S2
-rw-r--r--arch/mips/kernel/scall64-n32.S2
-rw-r--r--arch/mips/kernel/scall64-o32.S2
-rw-r--r--arch/s390/kernel/compat_wrapper.S8
-rw-r--r--arch/s390/kernel/syscalls.S2
-rw-r--r--arch/sparc/kernel/systbls.S2
-rw-r--r--arch/sparc64/kernel/systbls.S4
-rw-r--r--fs/compat.c32
-rw-r--r--fs/timerfd.c207
-rw-r--r--include/asm-powerpc/systbl.h2
-rw-r--r--include/linux/compat.h7
-rw-r--r--include/linux/hrtimer.h10
-rw-r--r--include/linux/syscalls.h7
-rw-r--r--kernel/hrtimer.c9
-rw-r--r--kernel/posix-timers.c9
-rw-r--r--kernel/sys_ni.c7
24 files changed, 210 insertions, 118 deletions
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index 79de99e32c35..ba914af18c4f 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -495,7 +495,7 @@ sys_call_table:
495 .quad sys_epoll_pwait 495 .quad sys_epoll_pwait
496 .quad sys_utimensat /* 475 */ 496 .quad sys_utimensat /* 475 */
497 .quad sys_signalfd 497 .quad sys_signalfd
498 .quad sys_timerfd 498 .quad sys_ni_syscall
499 .quad sys_eventfd 499 .quad sys_eventfd
500 500
501 .size sys_call_table, . - sys_call_table 501 .size sys_call_table, . - sys_call_table
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index cecf658e3625..283e14fff993 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -359,7 +359,7 @@
359 CALL(sys_kexec_load) 359 CALL(sys_kexec_load)
360 CALL(sys_utimensat) 360 CALL(sys_utimensat)
361 CALL(sys_signalfd) 361 CALL(sys_signalfd)
362/* 350 */ CALL(sys_timerfd) 362/* 350 */ CALL(sys_ni_syscall)
363 CALL(sys_eventfd) 363 CALL(sys_eventfd)
364 CALL(sys_fallocate) 364 CALL(sys_fallocate)
365#ifndef syscalls_counted 365#ifndef syscalls_counted
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 56ff51bc8c21..fdd9bf43361e 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -1373,7 +1373,7 @@ ENTRY(_sys_call_table)
1373 .long _sys_epoll_pwait 1373 .long _sys_epoll_pwait
1374 .long _sys_utimensat 1374 .long _sys_utimensat
1375 .long _sys_signalfd 1375 .long _sys_signalfd
1376 .long _sys_timerfd 1376 .long _sys_ni_syscall
1377 .long _sys_eventfd /* 350 */ 1377 .long _sys_eventfd /* 350 */
1378 .long _sys_pread64 1378 .long _sys_pread64
1379 .long _sys_pwrite64 1379 .long _sys_pwrite64
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S
index ec62c951fa3c..d1361dc119e2 100644
--- a/arch/cris/arch-v10/kernel/entry.S
+++ b/arch/cris/arch-v10/kernel/entry.S
@@ -1167,7 +1167,7 @@ sys_call_table:
1167 .long sys_epoll_pwait 1167 .long sys_epoll_pwait
1168 .long sys_utimensat /* 320 */ 1168 .long sys_utimensat /* 320 */
1169 .long sys_signalfd 1169 .long sys_signalfd
1170 .long sys_timerfd 1170 .long sys_ni_syscall
1171 .long sys_eventfd 1171 .long sys_eventfd
1172 .long sys_fallocate 1172 .long sys_fallocate
1173 1173
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index c36f43c94600..f5d3efbfbeda 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1586,7 +1586,7 @@ sys_call_table:
1586 data8 sys_epoll_pwait // 1305 1586 data8 sys_epoll_pwait // 1305
1587 data8 sys_utimensat 1587 data8 sys_utimensat
1588 data8 sys_signalfd 1588 data8 sys_signalfd
1589 data8 sys_timerfd 1589 data8 sys_ni_syscall
1590 data8 sys_eventfd 1590 data8 sys_eventfd
1591 1591
1592 .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls 1592 .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 918f5dbeaef6..6dfa3b3c0e2a 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -742,7 +742,7 @@ sys_call_table:
742 .long sys_epoll_pwait /* 315 */ 742 .long sys_epoll_pwait /* 315 */
743 .long sys_utimensat 743 .long sys_utimensat
744 .long sys_signalfd 744 .long sys_signalfd
745 .long sys_timerfd 745 .long sys_ni_syscall
746 .long sys_eventfd 746 .long sys_eventfd
747 .long sys_fallocate /* 320 */ 747 .long sys_fallocate /* 320 */
748 748
diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S
index 9620093514bc..1b02b8820068 100644
--- a/arch/m68knommu/kernel/syscalltable.S
+++ b/arch/m68knommu/kernel/syscalltable.S
@@ -336,7 +336,7 @@ ENTRY(sys_call_table)
336 .long sys_epoll_pwait /* 315 */ 336 .long sys_epoll_pwait /* 315 */
337 .long sys_utimensat 337 .long sys_utimensat
338 .long sys_signalfd 338 .long sys_signalfd
339 .long sys_timerfd 339 .long sys_ni_syscall
340 .long sys_eventfd 340 .long sys_eventfd
341 .long sys_fallocate /* 320 */ 341 .long sys_fallocate /* 320 */
342 342
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 82480a1717d8..f798139e888e 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -660,7 +660,7 @@ einval: li v0, -EINVAL
660 sys sys_ioprio_get 2 /* 4315 */ 660 sys sys_ioprio_get 2 /* 4315 */
661 sys sys_utimensat 4 661 sys sys_utimensat 4
662 sys sys_signalfd 3 662 sys sys_signalfd 3
663 sys sys_timerfd 4 663 sys sys_ni_syscall 0
664 sys sys_eventfd 1 664 sys sys_eventfd 1
665 sys sys_fallocate 6 /* 4320 */ 665 sys sys_fallocate 6 /* 4320 */
666 .endm 666 .endm
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index c2c10876da2e..a626be6baea3 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -475,7 +475,7 @@ sys_call_table:
475 PTR sys_ioprio_get 475 PTR sys_ioprio_get
476 PTR sys_utimensat /* 5275 */ 476 PTR sys_utimensat /* 5275 */
477 PTR sys_signalfd 477 PTR sys_signalfd
478 PTR sys_timerfd 478 PTR sys_ni_syscall
479 PTR sys_eventfd 479 PTR sys_eventfd
480 PTR sys_fallocate 480 PTR sys_fallocate
481 .size sys_call_table,.-sys_call_table 481 .size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 01993ec3368b..9d5bcaf1b389 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -401,7 +401,7 @@ EXPORT(sysn32_call_table)
401 PTR sys_ioprio_get 401 PTR sys_ioprio_get
402 PTR compat_sys_utimensat 402 PTR compat_sys_utimensat
403 PTR compat_sys_signalfd /* 5280 */ 403 PTR compat_sys_signalfd /* 5280 */
404 PTR compat_sys_timerfd 404 PTR sys_ni_syscall
405 PTR sys_eventfd 405 PTR sys_eventfd
406 PTR sys_fallocate 406 PTR sys_fallocate
407 .size sysn32_call_table,.-sysn32_call_table 407 .size sysn32_call_table,.-sysn32_call_table
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index dd68afce7da5..fd2019c1ec2d 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -523,7 +523,7 @@ sys_call_table:
523 PTR sys_ioprio_get /* 4315 */ 523 PTR sys_ioprio_get /* 4315 */
524 PTR compat_sys_utimensat 524 PTR compat_sys_utimensat
525 PTR compat_sys_signalfd 525 PTR compat_sys_signalfd
526 PTR compat_sys_timerfd 526 PTR sys_ni_syscall
527 PTR sys_eventfd 527 PTR sys_eventfd
528 PTR sys32_fallocate /* 4320 */ 528 PTR sys32_fallocate /* 4320 */
529 .size sys_call_table,.-sys_call_table 529 .size sys_call_table,.-sys_call_table
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 6ee1bedbd1bf..062c3d4c0394 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1698,14 +1698,6 @@ compat_sys_signalfd_wrapper:
1698 llgfr %r4,%r4 # compat_size_t 1698 llgfr %r4,%r4 # compat_size_t
1699 jg compat_sys_signalfd 1699 jg compat_sys_signalfd
1700 1700
1701 .globl compat_sys_timerfd_wrapper
1702compat_sys_timerfd_wrapper:
1703 lgfr %r2,%r2 # int
1704 lgfr %r3,%r3 # int
1705 lgfr %r4,%r4 # int
1706 llgtr %r5,%r5 # struct compat_itimerspec *
1707 jg compat_sys_timerfd
1708
1709 .globl sys_eventfd_wrapper 1701 .globl sys_eventfd_wrapper
1710sys_eventfd_wrapper: 1702sys_eventfd_wrapper:
1711 llgfr %r2,%r2 # unsigned int 1703 llgfr %r2,%r2 # unsigned int
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 9e26ed9fe4e7..25eac7802fc4 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -325,5 +325,5 @@ SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper)
325SYSCALL(s390_fallocate,sys_fallocate,sys_fallocate_wrapper) 325SYSCALL(s390_fallocate,sys_fallocate,sys_fallocate_wrapper)
326SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */ 326SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */
327SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper) 327SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper)
328SYSCALL(sys_timerfd,sys_timerfd,compat_sys_timerfd_wrapper) 328NI_SYSCALL /* 317 old sys_timer_fd */
329SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper) 329SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 55722840859c..ee010f4532a0 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -79,7 +79,7 @@ sys_call_table:
79/*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare 79/*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
80/*300*/ .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy 80/*300*/ .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
81/*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait 81/*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
82/*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate 82/*310*/ .long sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate
83 83
84#ifdef CONFIG_SUNOS_EMUL 84#ifdef CONFIG_SUNOS_EMUL
85 /* Now the SunOS syscall table. */ 85 /* Now the SunOS syscall table. */
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 06d10907d8ce..b8058906e727 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -80,7 +80,7 @@ sys_call_table32:
80 .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare 80 .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
81/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy 81/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
82 .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait 82 .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
83/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate 83/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_ni_syscall, sys_eventfd, compat_sys_fallocate
84 84
85#endif /* CONFIG_COMPAT */ 85#endif /* CONFIG_COMPAT */
86 86
@@ -152,7 +152,7 @@ sys_call_table:
152 .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare 152 .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
153/*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy 153/*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
154 .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait 154 .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
155/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate 155/*310*/ .word sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate
156 156
157#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ 157#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
158 defined(CONFIG_SOLARIS_EMUL_MODULE) 158 defined(CONFIG_SOLARIS_EMUL_MODULE)
diff --git a/fs/compat.c b/fs/compat.c
index 5216c3fd7517..69baca5ad608 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -2206,19 +2206,41 @@ asmlinkage long compat_sys_signalfd(int ufd,
2206 2206
2207#ifdef CONFIG_TIMERFD 2207#ifdef CONFIG_TIMERFD
2208 2208
2209asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags, 2209asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
2210 const struct compat_itimerspec __user *utmr) 2210 const struct compat_itimerspec __user *utmr,
2211 struct compat_itimerspec __user *otmr)
2211{ 2212{
2213 int error;
2212 struct itimerspec t; 2214 struct itimerspec t;
2213 struct itimerspec __user *ut; 2215 struct itimerspec __user *ut;
2214 2216
2215 if (get_compat_itimerspec(&t, utmr)) 2217 if (get_compat_itimerspec(&t, utmr))
2216 return -EFAULT; 2218 return -EFAULT;
2217 ut = compat_alloc_user_space(sizeof(*ut)); 2219 ut = compat_alloc_user_space(2 * sizeof(struct itimerspec));
2218 if (copy_to_user(ut, &t, sizeof(t))) 2220 if (copy_to_user(&ut[0], &t, sizeof(t)))
2219 return -EFAULT; 2221 return -EFAULT;
2222 error = sys_timerfd_settime(ufd, flags, &ut[0], &ut[1]);
2223 if (!error && otmr)
2224 error = (copy_from_user(&t, &ut[1], sizeof(struct itimerspec)) ||
2225 put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0;
2226
2227 return error;
2228}
2229
2230asmlinkage long compat_sys_timerfd_gettime(int ufd,
2231 struct compat_itimerspec __user *otmr)
2232{
2233 int error;
2234 struct itimerspec t;
2235 struct itimerspec __user *ut;
2220 2236
2221 return sys_timerfd(ufd, clockid, flags, ut); 2237 ut = compat_alloc_user_space(sizeof(struct itimerspec));
2238 error = sys_timerfd_gettime(ufd, ut);
2239 if (!error)
2240 error = (copy_from_user(&t, ut, sizeof(struct itimerspec)) ||
2241 put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0;
2242
2243 return error;
2222} 2244}
2223 2245
2224#endif /* CONFIG_TIMERFD */ 2246#endif /* CONFIG_TIMERFD */
diff --git a/fs/timerfd.c b/fs/timerfd.c
index 61983f3b107c..10c80b59ec4b 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -25,13 +25,15 @@ struct timerfd_ctx {
25 struct hrtimer tmr; 25 struct hrtimer tmr;
26 ktime_t tintv; 26 ktime_t tintv;
27 wait_queue_head_t wqh; 27 wait_queue_head_t wqh;
28 u64 ticks;
28 int expired; 29 int expired;
30 int clockid;
29}; 31};
30 32
31/* 33/*
32 * This gets called when the timer event triggers. We set the "expired" 34 * This gets called when the timer event triggers. We set the "expired"
33 * flag, but we do not re-arm the timer (in case it's necessary, 35 * flag, but we do not re-arm the timer (in case it's necessary,
34 * tintv.tv64 != 0) until the timer is read. 36 * tintv.tv64 != 0) until the timer is accessed.
35 */ 37 */
36static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr) 38static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
37{ 39{
@@ -40,13 +42,24 @@ static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
40 42
41 spin_lock_irqsave(&ctx->wqh.lock, flags); 43 spin_lock_irqsave(&ctx->wqh.lock, flags);
42 ctx->expired = 1; 44 ctx->expired = 1;
45 ctx->ticks++;
43 wake_up_locked(&ctx->wqh); 46 wake_up_locked(&ctx->wqh);
44 spin_unlock_irqrestore(&ctx->wqh.lock, flags); 47 spin_unlock_irqrestore(&ctx->wqh.lock, flags);
45 48
46 return HRTIMER_NORESTART; 49 return HRTIMER_NORESTART;
47} 50}
48 51
49static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags, 52static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
53{
54 ktime_t now, remaining;
55
56 now = ctx->tmr.base->get_time();
57 remaining = ktime_sub(ctx->tmr.expires, now);
58
59 return remaining.tv64 < 0 ? ktime_set(0, 0): remaining;
60}
61
62static void timerfd_setup(struct timerfd_ctx *ctx, int flags,
50 const struct itimerspec *ktmr) 63 const struct itimerspec *ktmr)
51{ 64{
52 enum hrtimer_mode htmode; 65 enum hrtimer_mode htmode;
@@ -57,8 +70,9 @@ static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
57 70
58 texp = timespec_to_ktime(ktmr->it_value); 71 texp = timespec_to_ktime(ktmr->it_value);
59 ctx->expired = 0; 72 ctx->expired = 0;
73 ctx->ticks = 0;
60 ctx->tintv = timespec_to_ktime(ktmr->it_interval); 74 ctx->tintv = timespec_to_ktime(ktmr->it_interval);
61 hrtimer_init(&ctx->tmr, clockid, htmode); 75 hrtimer_init(&ctx->tmr, ctx->clockid, htmode);
62 ctx->tmr.expires = texp; 76 ctx->tmr.expires = texp;
63 ctx->tmr.function = timerfd_tmrproc; 77 ctx->tmr.function = timerfd_tmrproc;
64 if (texp.tv64 != 0) 78 if (texp.tv64 != 0)
@@ -83,7 +97,7 @@ static unsigned int timerfd_poll(struct file *file, poll_table *wait)
83 poll_wait(file, &ctx->wqh, wait); 97 poll_wait(file, &ctx->wqh, wait);
84 98
85 spin_lock_irqsave(&ctx->wqh.lock, flags); 99 spin_lock_irqsave(&ctx->wqh.lock, flags);
86 if (ctx->expired) 100 if (ctx->ticks)
87 events |= POLLIN; 101 events |= POLLIN;
88 spin_unlock_irqrestore(&ctx->wqh.lock, flags); 102 spin_unlock_irqrestore(&ctx->wqh.lock, flags);
89 103
@@ -102,11 +116,11 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
102 return -EINVAL; 116 return -EINVAL;
103 spin_lock_irq(&ctx->wqh.lock); 117 spin_lock_irq(&ctx->wqh.lock);
104 res = -EAGAIN; 118 res = -EAGAIN;
105 if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) { 119 if (!ctx->ticks && !(file->f_flags & O_NONBLOCK)) {
106 __add_wait_queue(&ctx->wqh, &wait); 120 __add_wait_queue(&ctx->wqh, &wait);
107 for (res = 0;;) { 121 for (res = 0;;) {
108 set_current_state(TASK_INTERRUPTIBLE); 122 set_current_state(TASK_INTERRUPTIBLE);
109 if (ctx->expired) { 123 if (ctx->ticks) {
110 res = 0; 124 res = 0;
111 break; 125 break;
112 } 126 }
@@ -121,22 +135,21 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
121 __remove_wait_queue(&ctx->wqh, &wait); 135 __remove_wait_queue(&ctx->wqh, &wait);
122 __set_current_state(TASK_RUNNING); 136 __set_current_state(TASK_RUNNING);
123 } 137 }
124 if (ctx->expired) { 138 if (ctx->ticks) {
125 ctx->expired = 0; 139 ticks = ctx->ticks;
126 if (ctx->tintv.tv64 != 0) { 140 if (ctx->expired && ctx->tintv.tv64) {
127 /* 141 /*
128 * If tintv.tv64 != 0, this is a periodic timer that 142 * If tintv.tv64 != 0, this is a periodic timer that
129 * needs to be re-armed. We avoid doing it in the timer 143 * needs to be re-armed. We avoid doing it in the timer
130 * callback to avoid DoS attacks specifying a very 144 * callback to avoid DoS attacks specifying a very
131 * short timer period. 145 * short timer period.
132 */ 146 */
133 ticks = (u64) 147 ticks += hrtimer_forward_now(&ctx->tmr,
134 hrtimer_forward(&ctx->tmr, 148 ctx->tintv) - 1;
135 hrtimer_cb_get_time(&ctx->tmr),
136 ctx->tintv);
137 hrtimer_restart(&ctx->tmr); 149 hrtimer_restart(&ctx->tmr);
138 } else 150 }
139 ticks = 1; 151 ctx->expired = 0;
152 ctx->ticks = 0;
140 } 153 }
141 spin_unlock_irq(&ctx->wqh.lock); 154 spin_unlock_irq(&ctx->wqh.lock);
142 if (ticks) 155 if (ticks)
@@ -150,76 +163,132 @@ static const struct file_operations timerfd_fops = {
150 .read = timerfd_read, 163 .read = timerfd_read,
151}; 164};
152 165
153asmlinkage long sys_timerfd(int ufd, int clockid, int flags, 166static struct file *timerfd_fget(int fd)
154 const struct itimerspec __user *utmr) 167{
168 struct file *file;
169
170 file = fget(fd);
171 if (!file)
172 return ERR_PTR(-EBADF);
173 if (file->f_op != &timerfd_fops) {
174 fput(file);
175 return ERR_PTR(-EINVAL);
176 }
177
178 return file;
179}
180
181asmlinkage long sys_timerfd_create(int clockid, int flags)
155{ 182{
156 int error; 183 int error, ufd;
157 struct timerfd_ctx *ctx; 184 struct timerfd_ctx *ctx;
158 struct file *file; 185 struct file *file;
159 struct inode *inode; 186 struct inode *inode;
160 struct itimerspec ktmr;
161
162 if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
163 return -EFAULT;
164 187
188 if (flags)
189 return -EINVAL;
165 if (clockid != CLOCK_MONOTONIC && 190 if (clockid != CLOCK_MONOTONIC &&
166 clockid != CLOCK_REALTIME) 191 clockid != CLOCK_REALTIME)
167 return -EINVAL; 192 return -EINVAL;
193
194 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
195 if (!ctx)
196 return -ENOMEM;
197
198 init_waitqueue_head(&ctx->wqh);
199 ctx->clockid = clockid;
200 hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
201
202 error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
203 &timerfd_fops, ctx);
204 if (error) {
205 kfree(ctx);
206 return error;
207 }
208
209 return ufd;
210}
211
212asmlinkage long sys_timerfd_settime(int ufd, int flags,
213 const struct itimerspec __user *utmr,
214 struct itimerspec __user *otmr)
215{
216 struct file *file;
217 struct timerfd_ctx *ctx;
218 struct itimerspec ktmr, kotmr;
219
220 if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
221 return -EFAULT;
222
168 if (!timespec_valid(&ktmr.it_value) || 223 if (!timespec_valid(&ktmr.it_value) ||
169 !timespec_valid(&ktmr.it_interval)) 224 !timespec_valid(&ktmr.it_interval))
170 return -EINVAL; 225 return -EINVAL;
171 226
172 if (ufd == -1) { 227 file = timerfd_fget(ufd);
173 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); 228 if (IS_ERR(file))
174 if (!ctx) 229 return PTR_ERR(file);
175 return -ENOMEM; 230 ctx = file->private_data;
176
177 init_waitqueue_head(&ctx->wqh);
178
179 timerfd_setup(ctx, clockid, flags, &ktmr);
180
181 /*
182 * When we call this, the initialization must be complete, since
183 * anon_inode_getfd() will install the fd.
184 */
185 error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
186 &timerfd_fops, ctx);
187 if (error)
188 goto err_tmrcancel;
189 } else {
190 file = fget(ufd);
191 if (!file)
192 return -EBADF;
193 ctx = file->private_data;
194 if (file->f_op != &timerfd_fops) {
195 fput(file);
196 return -EINVAL;
197 }
198 /*
199 * We need to stop the existing timer before reprogramming
200 * it to the new values.
201 */
202 for (;;) {
203 spin_lock_irq(&ctx->wqh.lock);
204 if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
205 break;
206 spin_unlock_irq(&ctx->wqh.lock);
207 cpu_relax();
208 }
209 /*
210 * Re-program the timer to the new value ...
211 */
212 timerfd_setup(ctx, clockid, flags, &ktmr);
213 231
232 /*
233 * We need to stop the existing timer before reprogramming
234 * it to the new values.
235 */
236 for (;;) {
237 spin_lock_irq(&ctx->wqh.lock);
238 if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
239 break;
214 spin_unlock_irq(&ctx->wqh.lock); 240 spin_unlock_irq(&ctx->wqh.lock);
215 fput(file); 241 cpu_relax();
216 } 242 }
217 243
218 return ufd; 244 /*
245 * If the timer is expired and it's periodic, we need to advance it
246 * because the caller may want to know the previous expiration time.
247 * We do not update "ticks" and "expired" since the timer will be
248 * re-programmed again in the following timerfd_setup() call.
249 */
250 if (ctx->expired && ctx->tintv.tv64)
251 hrtimer_forward_now(&ctx->tmr, ctx->tintv);
219 252
220err_tmrcancel: 253 kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
221 hrtimer_cancel(&ctx->tmr); 254 kotmr.it_interval = ktime_to_timespec(ctx->tintv);
222 kfree(ctx); 255
223 return error; 256 /*
257 * Re-program the timer to the new value ...
258 */
259 timerfd_setup(ctx, flags, &ktmr);
260
261 spin_unlock_irq(&ctx->wqh.lock);
262 fput(file);
263 if (otmr && copy_to_user(otmr, &kotmr, sizeof(kotmr)))
264 return -EFAULT;
265
266 return 0;
267}
268
269asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr)
270{
271 struct file *file;
272 struct timerfd_ctx *ctx;
273 struct itimerspec kotmr;
274
275 file = timerfd_fget(ufd);
276 if (IS_ERR(file))
277 return PTR_ERR(file);
278 ctx = file->private_data;
279
280 spin_lock_irq(&ctx->wqh.lock);
281 if (ctx->expired && ctx->tintv.tv64) {
282 ctx->expired = 0;
283 ctx->ticks +=
284 hrtimer_forward_now(&ctx->tmr, ctx->tintv) - 1;
285 hrtimer_restart(&ctx->tmr);
286 }
287 kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
288 kotmr.it_interval = ktime_to_timespec(ctx->tintv);
289 spin_unlock_irq(&ctx->wqh.lock);
290 fput(file);
291
292 return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0;
224} 293}
225 294
diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
index 0c8b0d679139..e996521fb3a6 100644
--- a/include/asm-powerpc/systbl.h
+++ b/include/asm-powerpc/systbl.h
@@ -309,7 +309,7 @@ SYSCALL_SPU(getcpu)
309COMPAT_SYS(epoll_pwait) 309COMPAT_SYS(epoll_pwait)
310COMPAT_SYS_SPU(utimensat) 310COMPAT_SYS_SPU(utimensat)
311COMPAT_SYS_SPU(signalfd) 311COMPAT_SYS_SPU(signalfd)
312COMPAT_SYS_SPU(timerfd) 312SYSCALL(ni_syscall)
313SYSCALL_SPU(eventfd) 313SYSCALL_SPU(eventfd)
314COMPAT_SYS_SPU(sync_file_range2) 314COMPAT_SYS_SPU(sync_file_range2)
315COMPAT_SYS(fallocate) 315COMPAT_SYS(fallocate)
diff --git a/include/linux/compat.h b/include/linux/compat.h
index d38655f2be70..ae0a483bef9b 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -279,8 +279,11 @@ asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename,
279asmlinkage long compat_sys_signalfd(int ufd, 279asmlinkage long compat_sys_signalfd(int ufd,
280 const compat_sigset_t __user *sigmask, 280 const compat_sigset_t __user *sigmask,
281 compat_size_t sigsetsize); 281 compat_size_t sigsetsize);
282asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags, 282asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
283 const struct compat_itimerspec __user *utmr); 283 const struct compat_itimerspec __user *utmr,
284 struct compat_itimerspec __user *otmr);
285asmlinkage long compat_sys_timerfd_gettime(int ufd,
286 struct compat_itimerspec __user *otmr);
284 287
285#endif /* CONFIG_COMPAT */ 288#endif /* CONFIG_COMPAT */
286#endif /* _LINUX_COMPAT_H */ 289#endif /* _LINUX_COMPAT_H */
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 3fed27c88c01..8371b664b41f 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -301,12 +301,12 @@ static inline int hrtimer_is_queued(struct hrtimer *timer)
301} 301}
302 302
303/* Forward a hrtimer so it expires after now: */ 303/* Forward a hrtimer so it expires after now: */
304extern unsigned long 304extern u64
305hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval); 305hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);
306 306
307/* Forward a hrtimer so it expires after the hrtimer's current now */ 307/* Forward a hrtimer so it expires after the hrtimer's current now */
308static inline unsigned long hrtimer_forward_now(struct hrtimer *timer, 308static inline u64 hrtimer_forward_now(struct hrtimer *timer,
309 ktime_t interval) 309 ktime_t interval)
310{ 310{
311 return hrtimer_forward(timer, timer->base->get_time(), interval); 311 return hrtimer_forward(timer, timer->base->get_time(), interval);
312} 312}
@@ -329,9 +329,9 @@ extern void hrtimer_run_pending(void);
329extern void __init hrtimers_init(void); 329extern void __init hrtimers_init(void);
330 330
331#if BITS_PER_LONG < 64 331#if BITS_PER_LONG < 64
332extern unsigned long ktime_divns(const ktime_t kt, s64 div); 332extern u64 ktime_divns(const ktime_t kt, s64 div);
333#else /* BITS_PER_LONG < 64 */ 333#else /* BITS_PER_LONG < 64 */
334# define ktime_divns(kt, div) (unsigned long)((kt).tv64 / (div)) 334# define ktime_divns(kt, div) (u64)((kt).tv64 / (div))
335#endif 335#endif
336 336
337/* Show pending timers: */ 337/* Show pending timers: */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 61def7c8fbb3..4c2577bd1c85 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -607,8 +607,11 @@ asmlinkage long sys_set_robust_list(struct robust_list_head __user *head,
607 size_t len); 607 size_t len);
608asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); 608asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
609asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask); 609asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask);
610asmlinkage long sys_timerfd(int ufd, int clockid, int flags, 610asmlinkage long sys_timerfd_create(int clockid, int flags);
611 const struct itimerspec __user *utmr); 611asmlinkage long sys_timerfd_settime(int ufd, int flags,
612 const struct itimerspec __user *utmr,
613 struct itimerspec __user *otmr);
614asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr);
612asmlinkage long sys_eventfd(unsigned int count); 615asmlinkage long sys_eventfd(unsigned int count);
613asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); 616asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
614 617
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 1069998fe25f..668f3967eb39 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -306,7 +306,7 @@ EXPORT_SYMBOL_GPL(ktime_sub_ns);
306/* 306/*
307 * Divide a ktime value by a nanosecond value 307 * Divide a ktime value by a nanosecond value
308 */ 308 */
309unsigned long ktime_divns(const ktime_t kt, s64 div) 309u64 ktime_divns(const ktime_t kt, s64 div)
310{ 310{
311 u64 dclc, inc, dns; 311 u64 dclc, inc, dns;
312 int sft = 0; 312 int sft = 0;
@@ -321,7 +321,7 @@ unsigned long ktime_divns(const ktime_t kt, s64 div)
321 dclc >>= sft; 321 dclc >>= sft;
322 do_div(dclc, (unsigned long) div); 322 do_div(dclc, (unsigned long) div);
323 323
324 return (unsigned long) dclc; 324 return dclc;
325} 325}
326#endif /* BITS_PER_LONG >= 64 */ 326#endif /* BITS_PER_LONG >= 64 */
327 327
@@ -656,10 +656,9 @@ void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
656 * Forward the timer expiry so it will expire in the future. 656 * Forward the timer expiry so it will expire in the future.
657 * Returns the number of overruns. 657 * Returns the number of overruns.
658 */ 658 */
659unsigned long 659u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
660hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
661{ 660{
662 unsigned long orun = 1; 661 u64 orun = 1;
663 ktime_t delta; 662 ktime_t delta;
664 663
665 delta = ktime_sub(now, timer->expires); 664 delta = ktime_sub(now, timer->expires);
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 36d563fd9e3b..122d5c787fe2 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -256,8 +256,9 @@ static void schedule_next_timer(struct k_itimer *timr)
256 if (timr->it.real.interval.tv64 == 0) 256 if (timr->it.real.interval.tv64 == 0)
257 return; 257 return;
258 258
259 timr->it_overrun += hrtimer_forward(timer, timer->base->get_time(), 259 timr->it_overrun += (unsigned int) hrtimer_forward(timer,
260 timr->it.real.interval); 260 timer->base->get_time(),
261 timr->it.real.interval);
261 262
262 timr->it_overrun_last = timr->it_overrun; 263 timr->it_overrun_last = timr->it_overrun;
263 timr->it_overrun = -1; 264 timr->it_overrun = -1;
@@ -386,7 +387,7 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
386 now = ktime_add(now, kj); 387 now = ktime_add(now, kj);
387 } 388 }
388#endif 389#endif
389 timr->it_overrun += 390 timr->it_overrun += (unsigned int)
390 hrtimer_forward(timer, now, 391 hrtimer_forward(timer, now,
391 timr->it.real.interval); 392 timr->it.real.interval);
392 ret = HRTIMER_RESTART; 393 ret = HRTIMER_RESTART;
@@ -662,7 +663,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
662 */ 663 */
663 if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING || 664 if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
664 (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) 665 (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
665 timr->it_overrun += hrtimer_forward(timer, now, iv); 666 timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv);
666 667
667 remaining = ktime_sub(timer->expires, now); 668 remaining = ktime_sub(timer->expires, now);
668 /* Return 0 only, when the timer is expired and not pending */ 669 /* Return 0 only, when the timer is expired and not pending */
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index beee5b3b68a2..5b9b467de070 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -154,7 +154,10 @@ cond_syscall(sys_ioprio_get);
154 154
155/* New file descriptors */ 155/* New file descriptors */
156cond_syscall(sys_signalfd); 156cond_syscall(sys_signalfd);
157cond_syscall(sys_timerfd);
158cond_syscall(compat_sys_signalfd); 157cond_syscall(compat_sys_signalfd);
159cond_syscall(compat_sys_timerfd); 158cond_syscall(sys_timerfd_create);
159cond_syscall(sys_timerfd_settime);
160cond_syscall(sys_timerfd_gettime);
161cond_syscall(compat_sys_timerfd_settime);
162cond_syscall(compat_sys_timerfd_gettime);
160cond_syscall(sys_eventfd); 163cond_syscall(sys_eventfd);