Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Kernel v2.6.24-rc7 /kernel/hrtimer.c

Filename:/kernel/hrtimer.c
Lines Added:51
Lines Deleted:16
Also changed in: (Previous) 2.6.24-rc6  2.6.24-rc5  2.6.24-rc4-git7  2.6.24-rc4-git6  2.6.24-rc4  2.6.24-rc3 
(Following) 2.6.24-rc8  2.6.24-rc8-git5  2.6.24-rc8-git6  2.6.24-rc8-git7  2.6.24-rc8-git8  2.6.24 

Location
[  2.6.24-rc7
  [  kernel
     o  hrtimer.c

Patch

diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index c21ca6b..e65dd0b 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -277,6 +277,30 @@ ktime_t ktime_add_ns(const ktime_t kt, u64 nsec)
 }
 
 EXPORT_SYMBOL_GPL(ktime_add_ns);
+
+/**
+ * ktime_sub_ns - Subtract a scalar nanoseconds value from a ktime_t variable
+ * @kt:      minuend
+ * @nsec:   the scalar nsec value to subtract
+ *
+ * Returns the subtraction of @nsec from @kt in ktime_t format
+ */
+ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec)
+{
+   ktime_t tmp;
+
+   if (likely(nsec < NSEC_PER_SEC)) {
+      tmp.tv64 = nsec;
+   } else {
+      unsigned long rem = do_div(nsec, NSEC_PER_SEC);
+
+      tmp = ktime_set((long)nsec, rem);
+   }
+
+   return ktime_sub(kt, tmp);
+}
+
+EXPORT_SYMBOL_GPL(ktime_sub_ns);
 # endif /* !CONFIG_KTIME_SCALAR */
 
 /*
@@ -388,7 +412,7 @@ static int hrtimer_reprogram(struct hrtimer *timer,
    /*
     * When the callback is running, we do not reprogram the clock event
     * device. The timer callback is either running on a different CPU or
-    * the callback is executed in the hrtimer_interupt context. The
+    * the callback is executed in the hrtimer_interrupt context. The
     * reprogramming is handled either by the softirq, which called the
     * callback or at the end of the hrtimer_interrupt.
     */
@@ -578,7 +602,7 @@ static int hrtimer_switch_to_hres(void)
    /* "Retrigger" the interrupt to get things going */
    retrigger_next_event(NULL);
    local_irq_restore(flags);
-   printk(KERN_INFO "Switched to high resolution mode on CPU %d\n",
+   printk(KERN_DEBUG "Switched to high resolution mode on CPU %d\n",
           smp_processor_id());
    return 1;
 }
@@ -614,7 +638,7 @@ void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer, void *addr)
 #endif
 
 /*
- * Counterpart to lock_timer_base above:
+ * Counterpart to lock_hrtimer_base above:
  */
 static inline
 void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
@@ -826,6 +850,14 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
 #ifdef CONFIG_TIME_LOW_RES
       tim = ktime_add(tim, base->resolution);
 #endif
+      /*
+       * Careful here: User space might have asked for a
+       * very long sleep, so the add above might result in a
+       * negative number, which enqueues the timer in front
+       * of the queue.
+       */
+      if (tim.tv64 < 0)
+         tim.tv64 = KTIME_MAX;
    }
    timer->expires = tim;
 
@@ -1262,8 +1294,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
 long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
 {
    struct hrtimer_sleeper t;
-   struct timespec __user *rmtp;
-   struct timespec tu;
+   struct timespec *rmtp;
    ktime_t time;
 
    restart->fn = do_no_restart_syscall;
@@ -1274,14 +1305,12 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
    if (do_nanosleep(&t, HRTIMER_MODE_ABS))
       return 0;
 
-   rmtp = (struct timespec __user *) restart->arg1;
+   rmtp = (struct timespec *)restart->arg1;
    if (rmtp) {
       time = ktime_sub(t.timer.expires, t.timer.base->get_time());
       if (time.tv64 <= 0)
          return 0;
-      tu = ktime_to_timespec(time);
-      if (copy_to_user(rmtp, &tu, sizeof(tu)))
-         return -EFAULT;
+      *rmtp = ktime_to_timespec(time);
    }
 
    restart->fn = hrtimer_nanosleep_restart;
@@ -1290,12 +1319,11 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
    return -ERESTART_RESTARTBLOCK;
 }
 
-long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
+long hrtimer_nanosleep(struct timespec *rqtp, struct timespec *rmtp,
              const enum hrtimer_mode mode, const clockid_t clockid)
 {
    struct restart_block *restart;
    struct hrtimer_sleeper t;
-   struct timespec tu;
    ktime_t rem;
 
    hrtimer_init(&t.timer, clockid, mode);
@@ -1311,9 +1339,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
       rem = ktime_sub(t.timer.expires, t.timer.base->get_time());
       if (rem.tv64 <= 0)
          return 0;
-      tu = ktime_to_timespec(rem);
-      if (copy_to_user(rmtp, &tu, sizeof(tu)))
-         return -EFAULT;
+      *rmtp = ktime_to_timespec(rem);
    }
 
    restart = ¤t_thread_info()->restart_block;
@@ -1329,7 +1355,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
 asmlinkage long
 sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
 {
-   struct timespec tu;
+   struct timespec tu, rmt;
+   int ret;
 
    if (copy_from_user(&tu, rqtp, sizeof(tu)))
       return -EFAULT;
@@ -1337,7 +1364,15 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
    if (!timespec_valid(&tu))
       return -EINVAL;
 
-   return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+   ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL,
+            CLOCK_MONOTONIC);
+
+   if (ret && rmtp) {
+      if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
+         return -EFAULT;
+   }
+
+   return ret;
 }
 
 /*


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.