[PATCH V7 1/8] ntp: add ADJ_SETOFFSET mode bit
From: Richard Cochran <hidden>
Date: 2010-12-16 15:42:10
Also in:
lkml, netdev
Subsystem:
the rest, timekeeping, clocksource core, ntp, alarmtimer · Maintainers:
Linus Torvalds, John Stultz, Thomas Gleixner
This patch adds a new mode bit into the timex structure. When set, the bit instructs the kernel to add the given time value to the current time. Signed-off-by: Richard Cochran <richard.cochran-3mrvs1K0uXizZXS1Dc/lvw@public.gmane.org> --- include/linux/timex.h | 3 ++- kernel/time/ntp.c | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletions(-)
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 32d852f..82d4b24 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h@@ -73,7 +73,7 @@ struct timex { long tolerance; /* clock frequency tolerance (ppm) * (read only) */ - struct timeval time; /* (read only) */ + struct timeval time; /* (read only, except for ADJ_SETOFFSET) */ long tick; /* (modified) usecs between clock ticks */ long ppsfreq; /* pps frequency (scaled ppm) (ro) */
@@ -101,6 +101,7 @@ struct timex { #define ADJ_ESTERROR 0x0008 /* estimated time error */ #define ADJ_STATUS 0x0010 /* clock status */ #define ADJ_TIMECONST 0x0020 /* pll time constant */ +#define ADJ_SETOFFSET 0x0040 /* add 'time' to current time */ #define ADJ_TAI 0x0080 /* set TAI offset */ #define ADJ_MICRO 0x1000 /* select microsecond resolution */ #define ADJ_NANO 0x2000 /* select nanosecond resolution */
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index d232189..e9e3915 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c@@ -454,6 +454,7 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts int do_adjtimex(struct timex *txc) { struct timespec ts; + ktime_t delta, kt; int result; /* Validate the data before disabling interrupts */
@@ -482,8 +483,33 @@ int do_adjtimex(struct timex *txc) hrtimer_cancel(&leap_timer); } + if (txc->modes & ADJ_SETOFFSET) { + /* Validate the delta value. */ + if (txc->time.tv_sec && txc->time.tv_usec < 0) + return -EINVAL; + + if (txc->modes & ADJ_NANO) { + struct timespec tmp; + tmp.tv_sec = txc->time.tv_sec; + tmp.tv_nsec = txc->time.tv_usec; + delta = timespec_to_ktime(tmp); + } else + delta = timeval_to_ktime(txc->time); + + /* Adding the delta should be an "atomic" operation. */ + local_irq_disable(); + } + getnstimeofday(&ts); + if (txc->modes & ADJ_SETOFFSET) { + kt = timespec_to_ktime(ts); + kt = ktime_add(kt, delta); + ts = ktime_to_timespec(kt); + do_settimeofday(&ts); + local_irq_enable(); + } + write_seqlock_irq(&xtime_lock); if (txc->modes & ADJ_ADJTIME) {
--
1.7.0.4