From: Richard Cochran <richardcochran@gmail.com>
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.
CC: Thomas Gleixner <tglx@linutronix.de>
LKML-Reference: <880d82bb8120f73973db27e0c48e949014b1a106.1292512461.git.richard.cochran@omicron.at>
Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
Signed-off-by: John Stultz <john.stultz@linaro.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);
}
...I came up with this simple solution: "Just use ADJ_OFFSET as usual,
but don't forget to disable the kernel PLL."
Here's my (untested) patch.
---
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index c631168..d492887 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -119,14 +119,21 @@
return div_s64(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs);
}
-static void ntp_update_offset(long offset)
+static void ntp_update_offset(long offset, struct timespec *ts)
{
s64 freq_adj;
s64 offset64;
long secs;
- if (!(time_status & STA_PLL))
+ if (!(time_status & STA_PLL)) {
+ offset64 = (s64)offset;
+ if (!(time_status & STA_NANO))
+ offset64 *= NSEC_PER_USEC;
+
+ set_normalized_timespec(ts, ts->tv_sec, offset64 + ts->tv_nsec);
+
return;
+ }
if (!(time_status & STA_NANO))
offset *= NSEC_PER_USEC;
@@ -430,7 +437,7 @@
time_tai = txc->constant;
if (txc->modes & ADJ_OFFSET)
- ntp_update_offset(txc->offset);
+ ntp_update_offset(txc->offset, ts);
if (txc->modes & ADJ_TICK)
tick_usec = txc->tick;
@@ -526,6 +533,9 @@
write_sequnlock_irq(&xtime_lock);
+ if ((txc->modes & ADJ_OFFSET) && !(time_status & STA_PLL))
+ do_settimeofday(&ts);
+
txc->time.tv_sec = ts.tv_sec;
txc->time.tv_usec = ts.tv_nsec;
if (!(time_status & STA_NANO))
--
--
Again, this seems to be trying to add new functionality into a corner case of a existing mode. I don't like this because it makes testing and validating that the code is correct for its uses difficult. Especially given that a number of combinations of modes might be set at once. What happens to freq adjustments done at the same time as an ADJ_OFFSET - STA_PLL? Personally, I see the adjtimex call as too flexible, as I'd prefer to have the modes be exclusive (adjusting one thing per call). As it is now, the kernel doesn't throw out enough invalid to invalid-ish cases. ie: MOD_NANO|MOD_MICRO: totally cool! We should fix these and make the input checking more strict, but in my mind moving to mode-numbers rather then mode-flags would be much nicer (and more extendable). Richard: Maybe this is a good thing to think about for clock_adjtime? If we are adding a new syscall, maybe we should make sure we clean up some of the old syscalls issues? It does add a good bit of complexity, as the idea of clock_adjtime being a multiplexing adjtimex was nice and simple. We'd also have to review the mode usage to see if multi-mode adjustments in a single call are all that common or not. Kuwahara: Maybe could you maybe better explain your passion against using a new mode-flag for this new functionality? You seem dead set against it, but have not expressed your rational well. thanks -john --
Where are the mode bits and their combinations documented, anyhow? There are lot of papers on NTP, and I have not read them all, but I don't recall having seen a precise and succinct decription of the ntp_adjtime interface anywhere. Thanks, Richard --
You can find the original ntp_adjtime description here: Page 22 of: http://www.eecis.udel.edu/~mills/database/rfc/rfc1589.txt This pre-dates the nanotime kernel paper, which added MOD_NANO. thanks -john --
So, is the NTP source code the documentation of the kernel interface? Thanks, Richard --
Yea. adjtimex is a combination of ntp_adjtime and the older adjtime interfaces. So its not identical to David Mill's design, but it is compatible. In fact, it wasn't until somewhat recently that it picked up the ntpv4 changes and MOD/ADJ_NANO. By the way, I'm not saying we should switch from using mode flags to mode numbers for the new interface as I'm not sure if it would confuse users moving to it (being very similar, but slightly different can be worse then being totally different). But I figure it warrants some consideration. We do still have 4 unused bits in the modes flags after your patch, so this may be a premature worry. thanks -john --
