Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
[linux-2.6.git] / fs / timerfd.c
index 77c2bc9..8c4fc14 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/time.h>
@@ -52,11 +53,9 @@ static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
 
 static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
 {
-       ktime_t now, remaining;
-
-       now = ctx->tmr.base->get_time();
-       remaining = ktime_sub(ctx->tmr.expires, now);
+       ktime_t remaining;
 
+       remaining = hrtimer_expires_remaining(&ctx->tmr);
        return remaining.tv64 < 0 ? ktime_set(0, 0): remaining;
 }
 
@@ -74,7 +73,7 @@ static void timerfd_setup(struct timerfd_ctx *ctx, int flags,
        ctx->ticks = 0;
        ctx->tintv = timespec_to_ktime(ktmr->it_interval);
        hrtimer_init(&ctx->tmr, ctx->clockid, htmode);
-       ctx->tmr.expires = texp;
+       hrtimer_set_expires(&ctx->tmr, texp);
        ctx->tmr.function = timerfd_tmrproc;
        if (texp.tv64 != 0)
                hrtimer_start(&ctx->tmr, texp, htmode);
@@ -111,31 +110,14 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
        struct timerfd_ctx *ctx = file->private_data;
        ssize_t res;
        u64 ticks = 0;
-       DECLARE_WAITQUEUE(wait, current);
 
        if (count < sizeof(ticks))
                return -EINVAL;
        spin_lock_irq(&ctx->wqh.lock);
-       res = -EAGAIN;
-       if (!ctx->ticks && !(file->f_flags & O_NONBLOCK)) {
-               __add_wait_queue(&ctx->wqh, &wait);
-               for (res = 0;;) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       if (ctx->ticks) {
-                               res = 0;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               res = -ERESTARTSYS;
-                               break;
-                       }
-                       spin_unlock_irq(&ctx->wqh.lock);
-                       schedule();
-                       spin_lock_irq(&ctx->wqh.lock);
-               }
-               __remove_wait_queue(&ctx->wqh, &wait);
-               __set_current_state(TASK_RUNNING);
-       }
+       if (file->f_flags & O_NONBLOCK)
+               res = -EAGAIN;
+       else
+               res = wait_event_interruptible_locked_irq(ctx->wqh, ctx->ticks);
        if (ctx->ticks) {
                ticks = ctx->ticks;
                if (ctx->expired && ctx->tintv.tv64) {
@@ -162,6 +144,7 @@ static const struct file_operations timerfd_fops = {
        .release        = timerfd_release,
        .poll           = timerfd_poll,
        .read           = timerfd_read,
+       .llseek         = noop_llseek,
 };
 
 static struct file *timerfd_fget(int fd)
@@ -179,15 +162,18 @@ static struct file *timerfd_fget(int fd)
        return file;
 }
 
-asmlinkage long sys_timerfd_create(int clockid, int flags)
+SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
 {
        int ufd;
        struct timerfd_ctx *ctx;
 
-       if (flags)
-               return -EINVAL;
-       if (clockid != CLOCK_MONOTONIC &&
-           clockid != CLOCK_REALTIME)
+       /* Check the TFD_* constants for consistency.  */
+       BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
+       BUILD_BUG_ON(TFD_NONBLOCK != O_NONBLOCK);
+
+       if ((flags & ~TFD_CREATE_FLAGS) ||
+           (clockid != CLOCK_MONOTONIC &&
+            clockid != CLOCK_REALTIME))
                return -EINVAL;
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -198,16 +184,17 @@ asmlinkage long sys_timerfd_create(int clockid, int flags)
        ctx->clockid = clockid;
        hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
 
-       ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx, 0);
+       ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
+                              O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));
        if (ufd < 0)
                kfree(ctx);
 
        return ufd;
 }
 
-asmlinkage long sys_timerfd_settime(int ufd, int flags,
-                                   const struct itimerspec __user *utmr,
-                                   struct itimerspec __user *otmr)
+SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
+               const struct itimerspec __user *, utmr,
+               struct itimerspec __user *, otmr)
 {
        struct file *file;
        struct timerfd_ctx *ctx;
@@ -216,7 +203,8 @@ asmlinkage long sys_timerfd_settime(int ufd, int flags,
        if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
                return -EFAULT;
 
-       if (!timespec_valid(&ktmr.it_value) ||
+       if ((flags & ~TFD_SETTIME_FLAGS) ||
+           !timespec_valid(&ktmr.it_value) ||
            !timespec_valid(&ktmr.it_interval))
                return -EINVAL;
 
@@ -262,7 +250,7 @@ asmlinkage long sys_timerfd_settime(int ufd, int flags,
        return 0;
 }
 
-asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr)
+SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr)
 {
        struct file *file;
        struct timerfd_ctx *ctx;