]> Pileus Git - ~andy/linux/blobdiff - fs/timerfd.c
switch timerfd compat syscalls to COMPAT_SYSCALL_DEFINE
[~andy/linux] / fs / timerfd.c
index d03822bbf1909080ff201acc372de185d10d50d5..0e606b12a59df966b5509e87016d6782034ee473 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/anon_inodes.h>
 #include <linux/timerfd.h>
 #include <linux/syscalls.h>
+#include <linux/compat.h>
 #include <linux/rcupdate.h>
 
 struct timerfd_ctx {
@@ -278,21 +279,17 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
        return ufd;
 }
 
-SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
-               const struct itimerspec __user *, utmr,
-               struct itimerspec __user *, otmr)
+static int do_timerfd_settime(int ufd, int flags, 
+               const struct itimerspec *new,
+               struct itimerspec *old)
 {
        struct fd f;
        struct timerfd_ctx *ctx;
-       struct itimerspec ktmr, kotmr;
        int ret;
 
-       if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
-               return -EFAULT;
-
        if ((flags & ~TFD_SETTIME_FLAGS) ||
-           !timespec_valid(&ktmr.it_value) ||
-           !timespec_valid(&ktmr.it_interval))
+           !timespec_valid(&new->it_value) ||
+           !timespec_valid(&new->it_interval))
                return -EINVAL;
 
        ret = timerfd_fget(ufd, &f);
@@ -323,27 +320,23 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
        if (ctx->expired && ctx->tintv.tv64)
                hrtimer_forward_now(&ctx->tmr, ctx->tintv);
 
-       kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
-       kotmr.it_interval = ktime_to_timespec(ctx->tintv);
+       old->it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
+       old->it_interval = ktime_to_timespec(ctx->tintv);
 
        /*
         * Re-program the timer to the new value ...
         */
-       ret = timerfd_setup(ctx, flags, &ktmr);
+       ret = timerfd_setup(ctx, flags, new);
 
        spin_unlock_irq(&ctx->wqh.lock);
        fdput(f);
-       if (otmr && copy_to_user(otmr, &kotmr, sizeof(kotmr)))
-               return -EFAULT;
-
        return ret;
 }
 
-SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr)
+static int do_timerfd_gettime(int ufd, struct itimerspec *t)
 {
        struct fd f;
        struct timerfd_ctx *ctx;
-       struct itimerspec kotmr;
        int ret = timerfd_fget(ufd, &f);
        if (ret)
                return ret;
@@ -356,11 +349,65 @@ SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr)
                        hrtimer_forward_now(&ctx->tmr, ctx->tintv) - 1;
                hrtimer_restart(&ctx->tmr);
        }
-       kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
-       kotmr.it_interval = ktime_to_timespec(ctx->tintv);
+       t->it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
+       t->it_interval = ktime_to_timespec(ctx->tintv);
        spin_unlock_irq(&ctx->wqh.lock);
        fdput(f);
+       return 0;
+}
+
+SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
+               const struct itimerspec __user *, utmr,
+               struct itimerspec __user *, otmr)
+{
+       struct itimerspec new, old;
+       int ret;
+
+       if (copy_from_user(&new, utmr, sizeof(new)))
+               return -EFAULT;
+       ret = do_timerfd_settime(ufd, flags, &new, &old);
+       if (ret)
+               return ret;
+       if (otmr && copy_to_user(otmr, &old, sizeof(old)))
+               return -EFAULT;
+
+       return ret;
+}
 
+SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr)
+{
+       struct itimerspec kotmr;
+       int ret = do_timerfd_gettime(ufd, &kotmr);
+       if (ret)
+               return ret;
        return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0;
 }
 
+#ifdef COMPAT
+COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
+               const struct itimerspec __user *, utmr,
+               struct itimerspec __user *, otmr)
+{
+       struct itimerspec new, old;
+       int ret;
+
+       if (get_compat_itimerspec(&new, utmr))
+               return -EFAULT;
+       ret = do_timerfd_settime(ufd, flags, &new, &old);
+       if (ret)
+               return ret;
+       if (otmr && put_compat_itimerspec(otmr, &old))
+               return -EFAULT;
+       return ret;
+}
+
+COMPAT_SYSCALL_DEFINE2(timerfd_gettime, int, ufd,
+               struct itimerspec __user *, otmr)
+{
+       struct itimerspec kotmr;
+       int ret = do_timerfd_gettime(ufd, &kotmr);
+       if (ret)
+               return ret;
+       return put_compat_itimerspec(otmr, &t) ? -EFAULT: 0;
+}
+#endif