Avoid the intermediate step going from timeval to timespec64 to
ktime_t and back by using ktime_t throughout the code.

I was going back and forth between the two implementations.
This patch is optional: if we want it, it could be folded into
the patch converting to itimerspec64.

On an arm32 build, this version actually produces 10% larger
code than the timespec64 version, while on x86-64 it's the
same as before, and the number of source lines stays the
same as well.

Signed-off-by: Arnd Bergmann <[email protected]>
---
 include/trace/events/timer.h |  29 ++---
 kernel/time/itimer.c         | 229 ++++++++++++++++++-----------------
 2 files changed, 129 insertions(+), 129 deletions(-)

diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h
index 939cbfc80015..021733a49f10 100644
--- a/include/trace/events/timer.h
+++ b/include/trace/events/timer.h
@@ -297,39 +297,36 @@ DEFINE_EVENT(hrtimer_class, hrtimer_cancel,
 /**
  * itimer_state - called when itimer is started or canceled
  * @which:     name of the interval timer
- * @value:     the itimers value, itimer is canceled if value->it_value is
- *             zero, otherwise it is started
+ * @interval:  the itimers value
+ * @interval:  the itimers interval
  * @expires:   the itimers expiry time
  */
 TRACE_EVENT(itimer_state,
 
-       TP_PROTO(int which, const struct itimerspec64 *const value,
-                unsigned long long expires),
+       TP_PROTO(int which, ktime_t value, ktime_t interval, unsigned long long 
expires),
 
-       TP_ARGS(which, value, expires),
+       TP_ARGS(which, value, interval, expires),
 
        TP_STRUCT__entry(
                __field(        int,                    which           )
                __field(        unsigned long long,     expires         )
-               __field(        long,                   value_sec       )
-               __field(        long,                   value_usec      )
-               __field(        long,                   interval_sec    )
-               __field(        long,                   interval_usec   )
+               __field(        time64_t,               value_sec       )
+               __field(        u32,                    value_nsec      )
+               __field(        time64_t,               interval_sec    )
+               __field(        u32,                    interval_nsec   )
        ),
 
        TP_fast_assign(
                __entry->which          = which;
                __entry->expires        = expires;
-               __entry->value_sec      = value->it_value.tv_sec;
-               __entry->value_usec     = value->it_value.tv_nsec / 
NSEC_PER_USEC;
-               __entry->interval_sec   = value->it_interval.tv_sec;
-               __entry->interval_usec  = value->it_interval.tv_nsec / 
NSEC_PER_USEC;
+               __entry->value_sec      = div_u64_rem(value, NSEC_PER_SEC, 
&__entry->value_nsec);
+               __entry->interval_sec   = div_u64_rem(interval, NSEC_PER_SEC, 
&__entry->interval_nsec);
        ),
 
-       TP_printk("which=%d expires=%llu it_value=%ld.%06ld 
it_interval=%ld.%06ld",
+       TP_printk("which=%d expires=%llu it_value=%lld.%09d 
it_interval=%lld.%09d",
                  __entry->which, __entry->expires,
-                 __entry->value_sec, __entry->value_usec,
-                 __entry->interval_sec, __entry->interval_usec)
+                 __entry->value_sec, __entry->value_nsec,
+                 __entry->interval_sec, __entry->interval_nsec)
 );
 
 /**
diff --git a/kernel/time/itimer.c b/kernel/time/itimer.c
index 5872db9bd5f7..707f73054d76 100644
--- a/kernel/time/itimer.c
+++ b/kernel/time/itimer.c
@@ -26,7 +26,7 @@
  * Returns the delta between the expiry time and now, which can be
  * less than zero or 1usec for an pending expired timer
  */
-static struct timespec64 itimer_get_remtime(struct hrtimer *timer)
+static ktime_t itimer_get_remtime(struct hrtimer *timer)
 {
        ktime_t rem = __hrtimer_get_remaining(timer, true);
 
@@ -41,11 +41,11 @@ static struct timespec64 itimer_get_remtime(struct hrtimer 
*timer)
        } else
                rem = 0;
 
-       return ktime_to_timespec64(rem);
+       return rem;
 }
 
 static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
-                          struct itimerspec64 *const value)
+                          ktime_t *ovalue, ktime_t *ointerval)
 {
        u64 val, interval;
        struct cpu_itimer *it = &tsk->signal->it[clock_id];
@@ -69,27 +69,26 @@ static void get_cpu_itimer(struct task_struct *tsk, 
unsigned int clock_id,
 
        spin_unlock_irq(&tsk->sighand->siglock);
 
-       value->it_value = ns_to_timespec64(val);
-       value->it_interval = ns_to_timespec64(interval);
+       *ovalue = ns_to_ktime(val);
+       *ointerval = ns_to_ktime(interval);
 }
 
-static int do_getitimer(int which, struct itimerspec64 *value)
+static int do_getitimer(int which, ktime_t *value, ktime_t *interval)
 {
        struct task_struct *tsk = current;
 
        switch (which) {
        case ITIMER_REAL:
                spin_lock_irq(&tsk->sighand->siglock);
-               value->it_value = itimer_get_remtime(&tsk->signal->real_timer);
-               value->it_interval =
-                       ktime_to_timespec64(tsk->signal->it_real_incr);
+               *value = itimer_get_remtime(&tsk->signal->real_timer);
+               *interval = tsk->signal->it_real_incr;
                spin_unlock_irq(&tsk->sighand->siglock);
                break;
        case ITIMER_VIRTUAL:
-               get_cpu_itimer(tsk, CPUCLOCK_VIRT, value);
+               get_cpu_itimer(tsk, CPUCLOCK_VIRT, value, interval);
                break;
        case ITIMER_PROF:
-               get_cpu_itimer(tsk, CPUCLOCK_PROF, value);
+               get_cpu_itimer(tsk, CPUCLOCK_PROF, value, interval);
                break;
        default:
                return(-EINVAL);
@@ -98,26 +97,31 @@ static int do_getitimer(int which, struct itimerspec64 
*value)
 }
 
 static int put_itimerval(struct itimerval __user *o,
-                        const struct itimerspec64 *i)
+                        ktime_t value, ktime_t interval)
 {
        struct itimerval v;
-
-       v.it_interval.tv_sec = i->it_interval.tv_sec;
-       v.it_interval.tv_usec = i->it_interval.tv_nsec / NSEC_PER_USEC;
-       v.it_value.tv_sec = i->it_value.tv_sec;
-       v.it_value.tv_usec = i->it_value.tv_nsec / NSEC_PER_USEC;
+       struct timespec64 ts;
+
+       ts = ktime_to_timespec64(interval);
+       v.it_interval.tv_sec = ts.tv_sec;
+       v.it_interval.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+       ts = ktime_to_timespec64(value);
+       v.it_value.tv_sec = ts.tv_sec;
+       v.it_value.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
        return copy_to_user(o, &v, sizeof(struct itimerval)) ? -EFAULT : 0;
 }
 
 
-SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value)
+SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, it)
 {
-       struct itimerspec64 get_buffer;
-       int error = do_getitimer(which, &get_buffer);
+       ktime_t value, interval;
+       int error;
+
+       error = do_getitimer(which, &value, &interval);
+       if (error)
+               return error;
 
-       if (!error && put_itimerval(value, &get_buffer))
-               error = -EFAULT;
-       return error;
+       return put_itimerval(it, value, interval);
 }
 
 #if defined(CONFIG_COMPAT) || defined(CONFIG_ALPHA)
@@ -127,26 +131,31 @@ struct old_itimerval32 {
 };
 
 static int put_old_itimerval32(struct old_itimerval32 __user *o,
-                              const struct itimerspec64 *i)
+                              ktime_t value, ktime_t interval)
 {
        struct old_itimerval32 v32;
-
-       v32.it_interval.tv_sec = i->it_interval.tv_sec;
-       v32.it_interval.tv_usec = i->it_interval.tv_nsec / NSEC_PER_USEC;
-       v32.it_value.tv_sec = i->it_value.tv_sec;
-       v32.it_value.tv_usec = i->it_value.tv_nsec / NSEC_PER_USEC;
+       struct timespec64 ts;
+
+       ts = ktime_to_timespec64(interval);
+       v32.it_interval.tv_sec = ts.tv_sec;
+       v32.it_interval.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+       ts = ktime_to_timespec64(value);
+       v32.it_value.tv_sec = ts.tv_sec;
+       v32.it_value.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
        return copy_to_user(o, &v32, sizeof(struct old_itimerval32)) ? -EFAULT 
: 0;
 }
 
 COMPAT_SYSCALL_DEFINE2(getitimer, int, which,
-                      struct old_itimerval32 __user *, value)
+                      struct old_itimerval32 __user *, it)
 {
-       struct itimerspec64 get_buffer;
-       int error = do_getitimer(which, &get_buffer);
+       ktime_t value, interval;
+       int error;
 
-       if (!error && put_old_itimerval32(value, &get_buffer))
-               error = -EFAULT;
-       return error;
+       error = do_getitimer(which, &value, &interval);
+       if (error)
+               return error;
+
+       return put_old_itimerval32(it, value, interval);
 }
 #endif
 
@@ -166,86 +175,78 @@ enum hrtimer_restart it_real_fn(struct hrtimer *timer)
 }
 
 static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
-                          const struct itimerspec64 *const value,
-                          struct itimerspec64 *const ovalue)
+                          ktime_t value, ktime_t interval,
+                          ktime_t *ovalue, ktime_t *ointerval)
 {
-       u64 oval, nval, ointerval, ninterval;
+       u64 oval, nval;
        struct cpu_itimer *it = &tsk->signal->it[clock_id];
 
-       /*
-        * Use the to_ktime conversion because that clamps the maximum
-        * value to KTIME_MAX and avoid multiplication overflows.
-        */
-       nval = timespec64_to_ns(&value->it_value);
-       ninterval = timespec64_to_ns(&value->it_interval);
+       nval = value;
 
        spin_lock_irq(&tsk->sighand->siglock);
 
        oval = it->expires;
-       ointerval = it->incr;
+       if (ointerval)
+               *ointerval = it->incr;
+
        if (oval || nval) {
                if (nval > 0)
                        nval += TICK_NSEC;
                set_process_cpu_timer(tsk, clock_id, &nval, &oval);
        }
+
        it->expires = nval;
-       it->incr = ninterval;
+       it->incr = interval;
+
        trace_itimer_state(clock_id == CPUCLOCK_VIRT ?
-                          ITIMER_VIRTUAL : ITIMER_PROF, value, nval);
+                          ITIMER_VIRTUAL : ITIMER_PROF, value, interval, nval);
 
        spin_unlock_irq(&tsk->sighand->siglock);
 
-       if (ovalue) {
-               ovalue->it_value = ns_to_timespec64(oval);
-               ovalue->it_interval = ns_to_timespec64(ointerval);
-       }
+       if (ovalue)
+               *ovalue = oval;
 }
 
-/*
- * Returns true if the timeval is in canonical form
- */
 #define timeval_valid(t) \
        (((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC))
 
-static int do_setitimer(int which, struct itimerspec64 *value,
-                       struct itimerspec64 *ovalue)
+static int do_setitimer(int which, ktime_t value, ktime_t interval,
+                       ktime_t *ovalue, ktime_t *ointerval)
 {
        struct task_struct *tsk = current;
        struct hrtimer *timer;
-       ktime_t expires;
 
        switch (which) {
        case ITIMER_REAL:
 again:
                spin_lock_irq(&tsk->sighand->siglock);
                timer = &tsk->signal->real_timer;
-               if (ovalue) {
-                       ovalue->it_value = itimer_get_remtime(timer);
-                       ovalue->it_interval
-                               = 
ktime_to_timespec64(tsk->signal->it_real_incr);
-               }
+               if (ovalue)
+                       *ovalue = itimer_get_remtime(timer);
+               if (ointerval)
+                       *ointerval = tsk->signal->it_real_incr;
                /* We are sharing ->siglock with it_real_fn() */
                if (hrtimer_try_to_cancel(timer) < 0) {
                        spin_unlock_irq(&tsk->sighand->siglock);
                        hrtimer_cancel_wait_running(timer);
                        goto again;
                }
-               expires = timespec64_to_ktime(value->it_value);
-               if (expires != 0) {
-                       tsk->signal->it_real_incr =
-                               timespec64_to_ktime(value->it_interval);
-                       hrtimer_start(timer, expires, HRTIMER_MODE_REL);
+               if (value != 0) {
+                       tsk->signal->it_real_incr = interval;
+                       hrtimer_start(timer, value, HRTIMER_MODE_REL);
                } else
                        tsk->signal->it_real_incr = 0;
 
-               trace_itimer_state(ITIMER_REAL, value, 0);
+               trace_itimer_state(ITIMER_REAL, value, interval, 0);
                spin_unlock_irq(&tsk->sighand->siglock);
                break;
        case ITIMER_VIRTUAL:
-               set_cpu_itimer(tsk, CPUCLOCK_VIRT, value, ovalue);
+               set_cpu_itimer(tsk, CPUCLOCK_VIRT, value, interval,
+                              ovalue, ointerval);
                break;
        case ITIMER_PROF:
-               set_cpu_itimer(tsk, CPUCLOCK_PROF, value, ovalue);
+               set_cpu_itimer(tsk, CPUCLOCK_PROF, value, interval,
+                              ovalue, ointerval);
                break;
        default:
                return -EINVAL;
@@ -256,11 +257,10 @@ static int do_setitimer(int which, struct itimerspec64 
*value,
 #ifdef CONFIG_SECURITY_SELINUX
 void clear_itimer(void)
 {
-       struct itimerspec64 v = {};
        int i;
 
        for (i = 0; i < 3; i++)
-               do_setitimer(i, &v, NULL);
+               do_setitimer(i, 0, 0, NULL, NULL);
 }
 #endif
 
@@ -280,27 +280,23 @@ void clear_itimer(void)
  */
 static unsigned int alarm_setitimer(unsigned int seconds)
 {
-       struct itimerspec64 it_new, it_old;
+       ktime_t old;
 
 #if BITS_PER_LONG < 64
        if (seconds > INT_MAX)
                seconds = INT_MAX;
 #endif
-       it_new.it_value.tv_sec = seconds;
-       it_new.it_value.tv_nsec = 0;
-       it_new.it_interval.tv_sec = it_new.it_interval.tv_nsec = 0;
 
-       do_setitimer(ITIMER_REAL, &it_new, &it_old);
+       do_setitimer(ITIMER_REAL, ktime_set(seconds, 0), 0, &old, NULL);
 
        /*
         * We can't return 0 if we have an alarm pending ...  And we'd
         * better return too much than too little anyway
         */
-       if ((!it_old.it_value.tv_sec && it_old.it_value.tv_nsec) ||
-             it_old.it_value.tv_nsec >= 500000)
-               it_old.it_value.tv_sec++;
+       if (old > 0 && old < NSEC_PER_SEC)
+               return 1;
 
-       return it_old.it_value.tv_sec;
+       return div_u64(old + (NSEC_PER_SEC / 2), NSEC_PER_SEC);
 }
 
 /*
@@ -314,7 +310,8 @@ SYSCALL_DEFINE1(alarm, unsigned int, seconds)
 
 #endif
 
-static int get_itimerval(struct itimerspec64 *o, const struct itimerval __user 
*i)
+static int get_itimerval(ktime_t *value, ktime_t *interval,
+                               const struct itimerval __user *i)
 {
        struct itimerval v;
 
@@ -326,41 +323,45 @@ static int get_itimerval(struct itimerspec64 *o, const 
struct itimerval __user *
            !timeval_valid(&v.it_interval))
                return -EINVAL;
 
-       o->it_interval.tv_sec = v.it_interval.tv_sec;
-       o->it_interval.tv_nsec = v.it_interval.tv_usec * NSEC_PER_USEC;
-       o->it_value.tv_sec = v.it_value.tv_sec;
-       o->it_value.tv_nsec = v.it_value.tv_usec * NSEC_PER_USEC;
+       *interval = ktime_set(v.it_interval.tv_sec,
+                             v.it_interval.tv_usec * NSEC_PER_USEC);
+       *value = ktime_set(v.it_value.tv_sec,
+                          v.it_value.tv_usec * NSEC_PER_USEC);
+
        return 0;
 }
 
-SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value,
-               struct itimerval __user *, ovalue)
+
+SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, in,
+               struct itimerval __user *, out)
 {
-       struct itimerspec64 set_buffer, get_buffer;
+       ktime_t value = 0, interval = 0;
+       ktime_t ovalue, ointerval;
        int error;
 
-       if (value) {
-               error = get_itimerval(&set_buffer, value);
+       if (in) {
+               error = get_itimerval(&value, &interval, in);
                if (error)
                        return error;
        } else {
-               memset(&set_buffer, 0, sizeof(set_buffer));
                printk_once(KERN_WARNING "%s calls setitimer() with new_value 
NULL pointer."
                            " Misfeature support will be removed\n",
                            current->comm);
        }
 
-       error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
-       if (error || !ovalue)
+       if (!out)
+               return do_setitimer(which, value, interval, NULL, NULL);
+
+       error = do_setitimer(which, value, interval, &ovalue, &ointerval);
+       if (error)
                return error;
 
-       if (put_itimerval(ovalue, &get_buffer))
-               return -EFAULT;
-       return 0;
+       return put_itimerval(out, ovalue, ointerval);
 }
 
 #if defined(CONFIG_COMPAT) || defined(CONFIG_ALPHA)
-static int get_old_itimerval32(struct itimerspec64 *o, const struct 
old_itimerval32 __user *i)
+static int get_old_itimerval32(ktime_t *value, ktime_t *interval,
+                               const struct old_itimerval32 __user *i)
 {
        struct old_itimerval32 v32;
 
@@ -372,36 +373,38 @@ static int get_old_itimerval32(struct itimerspec64 *o, 
const struct old_itimerva
            !timeval_valid(&v32.it_interval))
                return -EINVAL;
 
-       o->it_interval.tv_sec = v32.it_interval.tv_sec;
-       o->it_interval.tv_nsec = v32.it_interval.tv_usec * NSEC_PER_USEC;
-       o->it_value.tv_sec = v32.it_value.tv_sec;
-       o->it_value.tv_nsec = v32.it_value.tv_usec * NSEC_PER_USEC;
+       *interval = ktime_set(v32.it_interval.tv_sec,
+                             v32.it_interval.tv_usec * NSEC_PER_USEC);
+       *value = ktime_set(v32.it_value.tv_sec,
+                          v32.it_value.tv_usec * NSEC_PER_USEC);
+
        return 0;
 }
 
 COMPAT_SYSCALL_DEFINE3(setitimer, int, which,
-                      struct old_itimerval32 __user *, value,
-                      struct old_itimerval32 __user *, ovalue)
+                      struct old_itimerval32 __user *, in,
+                      struct old_itimerval32 __user *, out)
 {
-       struct itimerspec64 set_buffer, get_buffer;
+       ktime_t value = 0, interval = 0;
+       ktime_t ovalue, ointerval;
        int error;
 
-       if (value) {
-               error = get_old_itimerval32(&set_buffer, value);
+       if (in) {
+               error = get_old_itimerval32(&value, &interval, in);
                if (error)
                        return error;
        } else {
-               memset(&set_buffer, 0, sizeof(set_buffer));
                printk_once(KERN_WARNING "%s calls setitimer() with new_value 
NULL pointer."
                            " Misfeature support will be removed\n",
                            current->comm);
        }
 
-       error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
-       if (error || !ovalue)
+       if (!out)
+               return do_setitimer(which, value, interval, NULL, NULL);
+
+       error = do_setitimer(which, value, interval, &ovalue, &ointerval);
+       if (error)
                return error;
-       if (put_old_itimerval32(ovalue, &get_buffer))
-               return -EFAULT;
-       return 0;
+       return put_old_itimerval32(out, ovalue, ointerval);
 }
 #endif
-- 
2.20.0

_______________________________________________
Y2038 mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/y2038

Reply via email to