Commit 4d672e7ac79b5ec5cdc90e450823441e20464691

Authored by Davide Libenzi
Committed by Linus Torvalds
1 parent 5e05ad7d4e

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>

Showing 24 changed files with 210 additions and 118 deletions Side-by-side Diff

arch/alpha/kernel/systbls.S
... ... @@ -495,7 +495,7 @@
495 495 .quad sys_epoll_pwait
496 496 .quad sys_utimensat /* 475 */
497 497 .quad sys_signalfd
498   - .quad sys_timerfd
  498 + .quad sys_ni_syscall
499 499 .quad sys_eventfd
500 500  
501 501 .size sys_call_table, . - sys_call_table
arch/arm/kernel/calls.S
... ... @@ -359,7 +359,7 @@
359 359 CALL(sys_kexec_load)
360 360 CALL(sys_utimensat)
361 361 CALL(sys_signalfd)
362   -/* 350 */ CALL(sys_timerfd)
  362 +/* 350 */ CALL(sys_ni_syscall)
363 363 CALL(sys_eventfd)
364 364 CALL(sys_fallocate)
365 365 #ifndef syscalls_counted
arch/blackfin/mach-common/entry.S
... ... @@ -1373,7 +1373,7 @@
1373 1373 .long _sys_epoll_pwait
1374 1374 .long _sys_utimensat
1375 1375 .long _sys_signalfd
1376   - .long _sys_timerfd
  1376 + .long _sys_ni_syscall
1377 1377 .long _sys_eventfd /* 350 */
1378 1378 .long _sys_pread64
1379 1379 .long _sys_pwrite64
arch/cris/arch-v10/kernel/entry.S
... ... @@ -1167,7 +1167,7 @@
1167 1167 .long sys_epoll_pwait
1168 1168 .long sys_utimensat /* 320 */
1169 1169 .long sys_signalfd
1170   - .long sys_timerfd
  1170 + .long sys_ni_syscall
1171 1171 .long sys_eventfd
1172 1172 .long sys_fallocate
1173 1173  
arch/ia64/kernel/entry.S
... ... @@ -1586,7 +1586,7 @@
1586 1586 data8 sys_epoll_pwait // 1305
1587 1587 data8 sys_utimensat
1588 1588 data8 sys_signalfd
1589   - data8 sys_timerfd
  1589 + data8 sys_ni_syscall
1590 1590 data8 sys_eventfd
1591 1591  
1592 1592 .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
arch/m68k/kernel/entry.S
... ... @@ -742,7 +742,7 @@
742 742 .long sys_epoll_pwait /* 315 */
743 743 .long sys_utimensat
744 744 .long sys_signalfd
745   - .long sys_timerfd
  745 + .long sys_ni_syscall
746 746 .long sys_eventfd
747 747 .long sys_fallocate /* 320 */
arch/m68knommu/kernel/syscalltable.S
... ... @@ -336,7 +336,7 @@
336 336 .long sys_epoll_pwait /* 315 */
337 337 .long sys_utimensat
338 338 .long sys_signalfd
339   - .long sys_timerfd
  339 + .long sys_ni_syscall
340 340 .long sys_eventfd
341 341 .long sys_fallocate /* 320 */
342 342  
arch/mips/kernel/scall32-o32.S
... ... @@ -660,7 +660,7 @@
660 660 sys sys_ioprio_get 2 /* 4315 */
661 661 sys sys_utimensat 4
662 662 sys sys_signalfd 3
663   - sys sys_timerfd 4
  663 + sys sys_ni_syscall 0
664 664 sys sys_eventfd 1
665 665 sys sys_fallocate 6 /* 4320 */
666 666 .endm
arch/mips/kernel/scall64-64.S
... ... @@ -475,7 +475,7 @@
475 475 PTR sys_ioprio_get
476 476 PTR sys_utimensat /* 5275 */
477 477 PTR sys_signalfd
478   - PTR sys_timerfd
  478 + PTR sys_ni_syscall
479 479 PTR sys_eventfd
480 480 PTR sys_fallocate
481 481 .size sys_call_table,.-sys_call_table
arch/mips/kernel/scall64-n32.S
... ... @@ -401,7 +401,7 @@
401 401 PTR sys_ioprio_get
402 402 PTR compat_sys_utimensat
403 403 PTR compat_sys_signalfd /* 5280 */
404   - PTR compat_sys_timerfd
  404 + PTR sys_ni_syscall
405 405 PTR sys_eventfd
406 406 PTR sys_fallocate
407 407 .size sysn32_call_table,.-sysn32_call_table
arch/mips/kernel/scall64-o32.S
... ... @@ -523,7 +523,7 @@
523 523 PTR sys_ioprio_get /* 4315 */
524 524 PTR compat_sys_utimensat
525 525 PTR compat_sys_signalfd
526   - PTR compat_sys_timerfd
  526 + PTR sys_ni_syscall
527 527 PTR sys_eventfd
528 528 PTR sys32_fallocate /* 4320 */
529 529 .size sys_call_table,.-sys_call_table
arch/s390/kernel/compat_wrapper.S
... ... @@ -1698,14 +1698,6 @@
1698 1698 llgfr %r4,%r4 # compat_size_t
1699 1699 jg compat_sys_signalfd
1700 1700  
1701   - .globl compat_sys_timerfd_wrapper
1702   -compat_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 1701 .globl sys_eventfd_wrapper
1710 1702 sys_eventfd_wrapper:
1711 1703 llgfr %r2,%r2 # unsigned int
arch/s390/kernel/syscalls.S
... ... @@ -325,6 +325,6 @@
325 325 SYSCALL(s390_fallocate,sys_fallocate,sys_fallocate_wrapper)
326 326 SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */
327 327 SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper)
328   -SYSCALL(sys_timerfd,sys_timerfd,compat_sys_timerfd_wrapper)
  328 +NI_SYSCALL /* 317 old sys_timer_fd */
329 329 SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
arch/sparc/kernel/systbls.S
... ... @@ -79,7 +79,7 @@
79 79 /*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
80 80 /*300*/ .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
81 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 84 #ifdef CONFIG_SUNOS_EMUL
85 85 /* Now the SunOS syscall table. */
arch/sparc64/kernel/systbls.S
... ... @@ -80,7 +80,7 @@
80 80 .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
81 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 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 85 #endif /* CONFIG_COMPAT */
86 86  
... ... @@ -152,7 +152,7 @@
152 152 .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
153 153 /*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
154 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 157 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
158 158 defined(CONFIG_SOLARIS_EMUL_MODULE)
... ... @@ -2206,19 +2206,41 @@
2206 2206  
2207 2207 #ifdef CONFIG_TIMERFD
2208 2208  
2209   -asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags,
2210   - const struct compat_itimerspec __user *utmr)
  2209 +asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
  2210 + const struct compat_itimerspec __user *utmr,
  2211 + struct compat_itimerspec __user *otmr)
2211 2212 {
  2213 + int error;
2212 2214 struct itimerspec t;
2213 2215 struct itimerspec __user *ut;
2214 2216  
2215 2217 if (get_compat_itimerspec(&t, utmr))
2216 2218 return -EFAULT;
2217   - ut = compat_alloc_user_space(sizeof(*ut));
2218   - if (copy_to_user(ut, &t, sizeof(t)))
  2219 + ut = compat_alloc_user_space(2 * sizeof(struct itimerspec));
  2220 + if (copy_to_user(&ut[0], &t, sizeof(t)))
2219 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;
2220 2226  
2221   - return sys_timerfd(ufd, clockid, flags, ut);
  2227 + return error;
  2228 +}
  2229 +
  2230 +asmlinkage 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;
  2236 +
  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 2246 #endif /* CONFIG_TIMERFD */
... ... @@ -25,13 +25,15 @@
25 25 struct hrtimer tmr;
26 26 ktime_t tintv;
27 27 wait_queue_head_t wqh;
  28 + u64 ticks;
28 29 int expired;
  30 + int clockid;
29 31 };
30 32  
31 33 /*
32 34 * This gets called when the timer event triggers. We set the "expired"
33 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 */
36 38 static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
37 39 {
38 40  
... ... @@ -40,13 +42,24 @@
40 42  
41 43 spin_lock_irqsave(&ctx->wqh.lock, flags);
42 44 ctx->expired = 1;
  45 + ctx->ticks++;
43 46 wake_up_locked(&ctx->wqh);
44 47 spin_unlock_irqrestore(&ctx->wqh.lock, flags);
45 48  
46 49 return HRTIMER_NORESTART;
47 50 }
48 51  
49   -static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
  52 +static 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 +
  62 +static void timerfd_setup(struct timerfd_ctx *ctx, int flags,
50 63 const struct itimerspec *ktmr)
51 64 {
52 65 enum hrtimer_mode htmode;
53 66  
... ... @@ -57,8 +70,9 @@
57 70  
58 71 texp = timespec_to_ktime(ktmr->it_value);
59 72 ctx->expired = 0;
  73 + ctx->ticks = 0;
60 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 76 ctx->tmr.expires = texp;
63 77 ctx->tmr.function = timerfd_tmrproc;
64 78 if (texp.tv64 != 0)
... ... @@ -83,7 +97,7 @@
83 97 poll_wait(file, &ctx->wqh, wait);
84 98  
85 99 spin_lock_irqsave(&ctx->wqh.lock, flags);
86   - if (ctx->expired)
  100 + if (ctx->ticks)
87 101 events |= POLLIN;
88 102 spin_unlock_irqrestore(&ctx->wqh.lock, flags);
89 103  
90 104  
... ... @@ -102,11 +116,11 @@
102 116 return -EINVAL;
103 117 spin_lock_irq(&ctx->wqh.lock);
104 118 res = -EAGAIN;
105   - if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) {
  119 + if (!ctx->ticks && !(file->f_flags & O_NONBLOCK)) {
106 120 __add_wait_queue(&ctx->wqh, &wait);
107 121 for (res = 0;;) {
108 122 set_current_state(TASK_INTERRUPTIBLE);
109   - if (ctx->expired) {
  123 + if (ctx->ticks) {
110 124 res = 0;
111 125 break;
112 126 }
113 127  
114 128  
... ... @@ -121,22 +135,21 @@
121 135 __remove_wait_queue(&ctx->wqh, &wait);
122 136 __set_current_state(TASK_RUNNING);
123 137 }
124   - if (ctx->expired) {
125   - ctx->expired = 0;
126   - if (ctx->tintv.tv64 != 0) {
  138 + if (ctx->ticks) {
  139 + ticks = ctx->ticks;
  140 + if (ctx->expired && ctx->tintv.tv64) {
127 141 /*
128 142 * If tintv.tv64 != 0, this is a periodic timer that
129 143 * needs to be re-armed. We avoid doing it in the timer
130 144 * callback to avoid DoS attacks specifying a very
131 145 * short timer period.
132 146 */
133   - ticks = (u64)
134   - hrtimer_forward(&ctx->tmr,
135   - hrtimer_cb_get_time(&ctx->tmr),
136   - ctx->tintv);
  147 + ticks += hrtimer_forward_now(&ctx->tmr,
  148 + ctx->tintv) - 1;
137 149 hrtimer_restart(&ctx->tmr);
138   - } else
139   - ticks = 1;
  150 + }
  151 + ctx->expired = 0;
  152 + ctx->ticks = 0;
140 153 }
141 154 spin_unlock_irq(&ctx->wqh.lock);
142 155 if (ticks)
143 156  
144 157  
145 158  
146 159  
147 160  
148 161  
149 162  
150 163  
151 164  
152 165  
153 166  
... ... @@ -150,76 +163,132 @@
150 163 .read = timerfd_read,
151 164 };
152 165  
153   -asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
154   - const struct itimerspec __user *utmr)
  166 +static struct file *timerfd_fget(int fd)
155 167 {
156   - int error;
  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 +
  181 +asmlinkage long sys_timerfd_create(int clockid, int flags)
  182 +{
  183 + int error, ufd;
157 184 struct timerfd_ctx *ctx;
158 185 struct file *file;
159 186 struct inode *inode;
160   - struct itimerspec ktmr;
161 187  
162   - if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
163   - return -EFAULT;
164   -
  188 + if (flags)
  189 + return -EINVAL;
165 190 if (clockid != CLOCK_MONOTONIC &&
166 191 clockid != CLOCK_REALTIME)
167 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 +
  212 +asmlinkage 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 223 if (!timespec_valid(&ktmr.it_value) ||
169 224 !timespec_valid(&ktmr.it_interval))
170 225 return -EINVAL;
171 226  
172   - if (ufd == -1) {
173   - ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
174   - if (!ctx)
175   - return -ENOMEM;
  227 + file = timerfd_fget(ufd);
  228 + if (IS_ERR(file))
  229 + return PTR_ERR(file);
  230 + ctx = file->private_data;
176 231  
177   - init_waitqueue_head(&ctx->wqh);
  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;
  240 + spin_unlock_irq(&ctx->wqh.lock);
  241 + cpu_relax();
  242 + }
178 243  
179   - timerfd_setup(ctx, clockid, flags, &ktmr);
  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);
180 252  
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);
  253 + kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
  254 + kotmr.it_interval = ktime_to_timespec(ctx->tintv);
213 255  
214   - spin_unlock_irq(&ctx->wqh.lock);
215   - fput(file);
216   - }
  256 + /*
  257 + * Re-program the timer to the new value ...
  258 + */
  259 + timerfd_setup(ctx, flags, &ktmr);
217 260  
218   - return ufd;
  261 + spin_unlock_irq(&ctx->wqh.lock);
  262 + fput(file);
  263 + if (otmr && copy_to_user(otmr, &kotmr, sizeof(kotmr)))
  264 + return -EFAULT;
219 265  
220   -err_tmrcancel:
221   - hrtimer_cancel(&ctx->tmr);
222   - kfree(ctx);
223   - return error;
  266 + return 0;
  267 +}
  268 +
  269 +asmlinkage 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 }
include/asm-powerpc/systbl.h
... ... @@ -309,7 +309,7 @@
309 309 COMPAT_SYS(epoll_pwait)
310 310 COMPAT_SYS_SPU(utimensat)
311 311 COMPAT_SYS_SPU(signalfd)
312   -COMPAT_SYS_SPU(timerfd)
  312 +SYSCALL(ni_syscall)
313 313 SYSCALL_SPU(eventfd)
314 314 COMPAT_SYS_SPU(sync_file_range2)
315 315 COMPAT_SYS(fallocate)
include/linux/compat.h
... ... @@ -279,8 +279,11 @@
279 279 asmlinkage long compat_sys_signalfd(int ufd,
280 280 const compat_sigset_t __user *sigmask,
281 281 compat_size_t sigsetsize);
282   -asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags,
283   - const struct compat_itimerspec __user *utmr);
  282 +asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
  283 + const struct compat_itimerspec __user *utmr,
  284 + struct compat_itimerspec __user *otmr);
  285 +asmlinkage long compat_sys_timerfd_gettime(int ufd,
  286 + struct compat_itimerspec __user *otmr);
284 287  
285 288 #endif /* CONFIG_COMPAT */
286 289 #endif /* _LINUX_COMPAT_H */
include/linux/hrtimer.h
... ... @@ -301,12 +301,12 @@
301 301 }
302 302  
303 303 /* Forward a hrtimer so it expires after now: */
304   -extern unsigned long
  304 +extern u64
305 305 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);
306 306  
307 307 /* Forward a hrtimer so it expires after the hrtimer's current now */
308   -static inline unsigned long hrtimer_forward_now(struct hrtimer *timer,
309   - ktime_t interval)
  308 +static inline u64 hrtimer_forward_now(struct hrtimer *timer,
  309 + ktime_t interval)
310 310 {
311 311 return hrtimer_forward(timer, timer->base->get_time(), interval);
312 312 }
313 313  
... ... @@ -329,9 +329,9 @@
329 329 extern void __init hrtimers_init(void);
330 330  
331 331 #if BITS_PER_LONG < 64
332   -extern unsigned long ktime_divns(const ktime_t kt, s64 div);
  332 +extern u64 ktime_divns(const ktime_t kt, s64 div);
333 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 335 #endif
336 336  
337 337 /* Show pending timers: */
include/linux/syscalls.h
... ... @@ -607,8 +607,11 @@
607 607 size_t len);
608 608 asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
609 609 asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask);
610   -asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
611   - const struct itimerspec __user *utmr);
  610 +asmlinkage long sys_timerfd_create(int clockid, int flags);
  611 +asmlinkage long sys_timerfd_settime(int ufd, int flags,
  612 + const struct itimerspec __user *utmr,
  613 + struct itimerspec __user *otmr);
  614 +asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr);
612 615 asmlinkage long sys_eventfd(unsigned int count);
613 616 asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
614 617  
... ... @@ -306,7 +306,7 @@
306 306 /*
307 307 * Divide a ktime value by a nanosecond value
308 308 */
309   -unsigned long ktime_divns(const ktime_t kt, s64 div)
  309 +u64 ktime_divns(const ktime_t kt, s64 div)
310 310 {
311 311 u64 dclc, inc, dns;
312 312 int sft = 0;
... ... @@ -321,7 +321,7 @@
321 321 dclc >>= sft;
322 322 do_div(dclc, (unsigned long) div);
323 323  
324   - return (unsigned long) dclc;
  324 + return dclc;
325 325 }
326 326 #endif /* BITS_PER_LONG >= 64 */
327 327  
328 328  
... ... @@ -656,10 +656,9 @@
656 656 * Forward the timer expiry so it will expire in the future.
657 657 * Returns the number of overruns.
658 658 */
659   -unsigned long
660   -hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
  659 +u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
661 660 {
662   - unsigned long orun = 1;
  661 + u64 orun = 1;
663 662 ktime_t delta;
664 663  
665 664 delta = ktime_sub(now, timer->expires);
kernel/posix-timers.c
... ... @@ -256,8 +256,9 @@
256 256 if (timr->it.real.interval.tv64 == 0)
257 257 return;
258 258  
259   - timr->it_overrun += hrtimer_forward(timer, timer->base->get_time(),
260   - timr->it.real.interval);
  259 + timr->it_overrun += (unsigned int) hrtimer_forward(timer,
  260 + timer->base->get_time(),
  261 + timr->it.real.interval);
261 262  
262 263 timr->it_overrun_last = timr->it_overrun;
263 264 timr->it_overrun = -1;
... ... @@ -386,7 +387,7 @@
386 387 now = ktime_add(now, kj);
387 388 }
388 389 #endif
389   - timr->it_overrun +=
  390 + timr->it_overrun += (unsigned int)
390 391 hrtimer_forward(timer, now,
391 392 timr->it.real.interval);
392 393 ret = HRTIMER_RESTART;
... ... @@ -662,7 +663,7 @@
662 663 */
663 664 if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
664 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 668 remaining = ktime_sub(timer->expires, now);
668 669 /* Return 0 only, when the timer is expired and not pending */
... ... @@ -154,8 +154,11 @@
154 154  
155 155 /* New file descriptors */
156 156 cond_syscall(sys_signalfd);
157   -cond_syscall(sys_timerfd);
158 157 cond_syscall(compat_sys_signalfd);
159   -cond_syscall(compat_sys_timerfd);
  158 +cond_syscall(sys_timerfd_create);
  159 +cond_syscall(sys_timerfd_settime);
  160 +cond_syscall(sys_timerfd_gettime);
  161 +cond_syscall(compat_sys_timerfd_settime);
  162 +cond_syscall(compat_sys_timerfd_gettime);
160 163 cond_syscall(sys_eventfd);