aboutsummaryrefslogtreecommitdiffstats
path: root/fs/timerfd.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/timerfd.c')
-rw-r--r--fs/timerfd.c85
1 files changed, 66 insertions, 19 deletions
diff --git a/fs/timerfd.c b/fs/timerfd.c
index d03822bbf190..0e606b12a59d 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -22,6 +22,7 @@
22#include <linux/anon_inodes.h> 22#include <linux/anon_inodes.h>
23#include <linux/timerfd.h> 23#include <linux/timerfd.h>
24#include <linux/syscalls.h> 24#include <linux/syscalls.h>
25#include <linux/compat.h>
25#include <linux/rcupdate.h> 26#include <linux/rcupdate.h>
26 27
27struct timerfd_ctx { 28struct timerfd_ctx {
@@ -278,21 +279,17 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
278 return ufd; 279 return ufd;
279} 280}
280 281
281SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, 282static int do_timerfd_settime(int ufd, int flags,
282 const struct itimerspec __user *, utmr, 283 const struct itimerspec *new,
283 struct itimerspec __user *, otmr) 284 struct itimerspec *old)
284{ 285{
285 struct fd f; 286 struct fd f;
286 struct timerfd_ctx *ctx; 287 struct timerfd_ctx *ctx;
287 struct itimerspec ktmr, kotmr;
288 int ret; 288 int ret;
289 289
290 if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
291 return -EFAULT;
292
293 if ((flags & ~TFD_SETTIME_FLAGS) || 290 if ((flags & ~TFD_SETTIME_FLAGS) ||
294 !timespec_valid(&ktmr.it_value) || 291 !timespec_valid(&new->it_value) ||
295 !timespec_valid(&ktmr.it_interval)) 292 !timespec_valid(&new->it_interval))
296 return -EINVAL; 293 return -EINVAL;
297 294
298 ret = timerfd_fget(ufd, &f); 295 ret = timerfd_fget(ufd, &f);
@@ -323,27 +320,23 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
323 if (ctx->expired && ctx->tintv.tv64) 320 if (ctx->expired && ctx->tintv.tv64)
324 hrtimer_forward_now(&ctx->tmr, ctx->tintv); 321 hrtimer_forward_now(&ctx->tmr, ctx->tintv);
325 322
326 kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); 323 old->it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
327 kotmr.it_interval = ktime_to_timespec(ctx->tintv); 324 old->it_interval = ktime_to_timespec(ctx->tintv);
328 325
329 /* 326 /*
330 * Re-program the timer to the new value ... 327 * Re-program the timer to the new value ...
331 */ 328 */
332 ret = timerfd_setup(ctx, flags, &ktmr); 329 ret = timerfd_setup(ctx, flags, new);
333 330
334 spin_unlock_irq(&ctx->wqh.lock); 331 spin_unlock_irq(&ctx->wqh.lock);
335 fdput(f); 332 fdput(f);
336 if (otmr && copy_to_user(otmr, &kotmr, sizeof(kotmr)))
337 return -EFAULT;
338
339 return ret; 333 return ret;
340} 334}
341 335
342SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr) 336static int do_timerfd_gettime(int ufd, struct itimerspec *t)
343{ 337{
344 struct fd f; 338 struct fd f;
345 struct timerfd_ctx *ctx; 339 struct timerfd_ctx *ctx;
346 struct itimerspec kotmr;
347 int ret = timerfd_fget(ufd, &f); 340 int ret = timerfd_fget(ufd, &f);
348 if (ret) 341 if (ret)
349 return ret; 342 return ret;
@@ -356,11 +349,65 @@ SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr)
356 hrtimer_forward_now(&ctx->tmr, ctx->tintv) - 1; 349 hrtimer_forward_now(&ctx->tmr, ctx->tintv) - 1;
357 hrtimer_restart(&ctx->tmr); 350 hrtimer_restart(&ctx->tmr);
358 } 351 }
359 kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx)); 352 t->it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
360 kotmr.it_interval = ktime_to_timespec(ctx->tintv); 353 t->it_interval = ktime_to_timespec(ctx->tintv);
361 spin_unlock_irq(&ctx->wqh.lock); 354 spin_unlock_irq(&ctx->wqh.lock);
362 fdput(f); 355 fdput(f);
356 return 0;
357}
358
359SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
360 const struct itimerspec __user *, utmr,
361 struct itimerspec __user *, otmr)
362{
363 struct itimerspec new, old;
364 int ret;
365
366 if (copy_from_user(&new, utmr, sizeof(new)))
367 return -EFAULT;
368 ret = do_timerfd_settime(ufd, flags, &new, &old);
369 if (ret)
370 return ret;
371 if (otmr && copy_to_user(otmr, &old, sizeof(old)))
372 return -EFAULT;
373
374 return ret;
375}
363 376
377SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr)
378{
379 struct itimerspec kotmr;
380 int ret = do_timerfd_gettime(ufd, &kotmr);
381 if (ret)
382 return ret;
364 return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0; 383 return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0;
365} 384}
366 385
386#ifdef COMPAT
387COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
388 const struct itimerspec __user *, utmr,
389 struct itimerspec __user *, otmr)
390{
391 struct itimerspec new, old;
392 int ret;
393
394 if (get_compat_itimerspec(&new, utmr))
395 return -EFAULT;
396 ret = do_timerfd_settime(ufd, flags, &new, &old);
397 if (ret)
398 return ret;
399 if (otmr && put_compat_itimerspec(otmr, &old))
400 return -EFAULT;
401 return ret;
402}
403
404COMPAT_SYSCALL_DEFINE2(timerfd_gettime, int, ufd,
405 struct itimerspec __user *, otmr)
406{
407 struct itimerspec kotmr;
408 int ret = do_timerfd_gettime(ufd, &kotmr);
409 if (ret)
410 return ret;
411 return put_compat_itimerspec(otmr, &t) ? -EFAULT: 0;
412}
413#endif