diff options
Diffstat (limited to 'kernel/time/ntp.c')
-rw-r--r-- | kernel/time/ntp.c | 96 |
1 files changed, 49 insertions, 47 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 1ad46f3df6e7..8ff15e5d486b 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
@@ -10,13 +10,13 @@ | |||
10 | 10 | ||
11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
13 | #include <linux/timer.h> | ||
14 | #include <linux/timex.h> | 13 | #include <linux/timex.h> |
15 | #include <linux/jiffies.h> | 14 | #include <linux/jiffies.h> |
16 | #include <linux/hrtimer.h> | 15 | #include <linux/hrtimer.h> |
17 | #include <linux/capability.h> | 16 | #include <linux/capability.h> |
18 | #include <linux/math64.h> | 17 | #include <linux/math64.h> |
19 | #include <linux/clocksource.h> | 18 | #include <linux/clocksource.h> |
19 | #include <linux/workqueue.h> | ||
20 | #include <asm/timex.h> | 20 | #include <asm/timex.h> |
21 | 21 | ||
22 | /* | 22 | /* |
@@ -142,8 +142,7 @@ static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer) | |||
142 | time_state = TIME_OOP; | 142 | time_state = TIME_OOP; |
143 | printk(KERN_NOTICE "Clock: " | 143 | printk(KERN_NOTICE "Clock: " |
144 | "inserting leap second 23:59:60 UTC\n"); | 144 | "inserting leap second 23:59:60 UTC\n"); |
145 | leap_timer.expires = ktime_add_ns(leap_timer.expires, | 145 | hrtimer_add_expires_ns(&leap_timer, NSEC_PER_SEC); |
146 | NSEC_PER_SEC); | ||
147 | res = HRTIMER_RESTART; | 146 | res = HRTIMER_RESTART; |
148 | break; | 147 | break; |
149 | case TIME_DEL: | 148 | case TIME_DEL: |
@@ -218,11 +217,11 @@ void second_overflow(void) | |||
218 | /* Disable the cmos update - used by virtualization and embedded */ | 217 | /* Disable the cmos update - used by virtualization and embedded */ |
219 | int no_sync_cmos_clock __read_mostly; | 218 | int no_sync_cmos_clock __read_mostly; |
220 | 219 | ||
221 | static void sync_cmos_clock(unsigned long dummy); | 220 | static void sync_cmos_clock(struct work_struct *work); |
222 | 221 | ||
223 | static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); | 222 | static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock); |
224 | 223 | ||
225 | static void sync_cmos_clock(unsigned long dummy) | 224 | static void sync_cmos_clock(struct work_struct *work) |
226 | { | 225 | { |
227 | struct timespec now, next; | 226 | struct timespec now, next; |
228 | int fail = 1; | 227 | int fail = 1; |
@@ -258,13 +257,13 @@ static void sync_cmos_clock(unsigned long dummy) | |||
258 | next.tv_sec++; | 257 | next.tv_sec++; |
259 | next.tv_nsec -= NSEC_PER_SEC; | 258 | next.tv_nsec -= NSEC_PER_SEC; |
260 | } | 259 | } |
261 | mod_timer(&sync_cmos_timer, jiffies + timespec_to_jiffies(&next)); | 260 | schedule_delayed_work(&sync_cmos_work, timespec_to_jiffies(&next)); |
262 | } | 261 | } |
263 | 262 | ||
264 | static void notify_cmos_timer(void) | 263 | static void notify_cmos_timer(void) |
265 | { | 264 | { |
266 | if (!no_sync_cmos_clock) | 265 | if (!no_sync_cmos_clock) |
267 | mod_timer(&sync_cmos_timer, jiffies + 1); | 266 | schedule_delayed_work(&sync_cmos_work, 0); |
268 | } | 267 | } |
269 | 268 | ||
270 | #else | 269 | #else |
@@ -277,38 +276,50 @@ static inline void notify_cmos_timer(void) { } | |||
277 | int do_adjtimex(struct timex *txc) | 276 | int do_adjtimex(struct timex *txc) |
278 | { | 277 | { |
279 | struct timespec ts; | 278 | struct timespec ts; |
280 | long save_adjust, sec; | ||
281 | int result; | 279 | int result; |
282 | 280 | ||
283 | /* In order to modify anything, you gotta be super-user! */ | 281 | /* Validate the data before disabling interrupts */ |
284 | if (txc->modes && !capable(CAP_SYS_TIME)) | 282 | if (txc->modes & ADJ_ADJTIME) { |
285 | return -EPERM; | ||
286 | |||
287 | /* Now we validate the data before disabling interrupts */ | ||
288 | |||
289 | if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) { | ||
290 | /* singleshot must not be used with any other mode bits */ | 283 | /* singleshot must not be used with any other mode bits */ |
291 | if (txc->modes & ~ADJ_OFFSET_SS_READ) | 284 | if (!(txc->modes & ADJ_OFFSET_SINGLESHOT)) |
292 | return -EINVAL; | 285 | return -EINVAL; |
286 | if (!(txc->modes & ADJ_OFFSET_READONLY) && | ||
287 | !capable(CAP_SYS_TIME)) | ||
288 | return -EPERM; | ||
289 | } else { | ||
290 | /* In order to modify anything, you gotta be super-user! */ | ||
291 | if (txc->modes && !capable(CAP_SYS_TIME)) | ||
292 | return -EPERM; | ||
293 | |||
294 | /* if the quartz is off by more than 10% something is VERY wrong! */ | ||
295 | if (txc->modes & ADJ_TICK && | ||
296 | (txc->tick < 900000/USER_HZ || | ||
297 | txc->tick > 1100000/USER_HZ)) | ||
298 | return -EINVAL; | ||
299 | |||
300 | if (txc->modes & ADJ_STATUS && time_state != TIME_OK) | ||
301 | hrtimer_cancel(&leap_timer); | ||
293 | } | 302 | } |
294 | 303 | ||
295 | /* if the quartz is off by more than 10% something is VERY wrong ! */ | ||
296 | if (txc->modes & ADJ_TICK) | ||
297 | if (txc->tick < 900000/USER_HZ || | ||
298 | txc->tick > 1100000/USER_HZ) | ||
299 | return -EINVAL; | ||
300 | |||
301 | if (time_state != TIME_OK && txc->modes & ADJ_STATUS) | ||
302 | hrtimer_cancel(&leap_timer); | ||
303 | getnstimeofday(&ts); | 304 | getnstimeofday(&ts); |
304 | 305 | ||
305 | write_seqlock_irq(&xtime_lock); | 306 | write_seqlock_irq(&xtime_lock); |
306 | 307 | ||
307 | /* Save for later - semantics of adjtime is to return old value */ | ||
308 | save_adjust = time_adjust; | ||
309 | |||
310 | /* If there are input parameters, then process them */ | 308 | /* If there are input parameters, then process them */ |
309 | if (txc->modes & ADJ_ADJTIME) { | ||
310 | long save_adjust = time_adjust; | ||
311 | |||
312 | if (!(txc->modes & ADJ_OFFSET_READONLY)) { | ||
313 | /* adjtime() is independent from ntp_adjtime() */ | ||
314 | time_adjust = txc->offset; | ||
315 | ntp_update_frequency(); | ||
316 | } | ||
317 | txc->offset = save_adjust; | ||
318 | goto adj_done; | ||
319 | } | ||
311 | if (txc->modes) { | 320 | if (txc->modes) { |
321 | long sec; | ||
322 | |||
312 | if (txc->modes & ADJ_STATUS) { | 323 | if (txc->modes & ADJ_STATUS) { |
313 | if ((time_status & STA_PLL) && | 324 | if ((time_status & STA_PLL) && |
314 | !(txc->status & STA_PLL)) { | 325 | !(txc->status & STA_PLL)) { |
@@ -375,13 +386,8 @@ int do_adjtimex(struct timex *txc) | |||
375 | if (txc->modes & ADJ_TAI && txc->constant > 0) | 386 | if (txc->modes & ADJ_TAI && txc->constant > 0) |
376 | time_tai = txc->constant; | 387 | time_tai = txc->constant; |
377 | 388 | ||
378 | if (txc->modes & ADJ_OFFSET) { | 389 | if (txc->modes & ADJ_OFFSET) |
379 | if (txc->modes == ADJ_OFFSET_SINGLESHOT) | 390 | ntp_update_offset(txc->offset); |
380 | /* adjtime() is independent from ntp_adjtime() */ | ||
381 | time_adjust = txc->offset; | ||
382 | else | ||
383 | ntp_update_offset(txc->offset); | ||
384 | } | ||
385 | if (txc->modes & ADJ_TICK) | 391 | if (txc->modes & ADJ_TICK) |
386 | tick_usec = txc->tick; | 392 | tick_usec = txc->tick; |
387 | 393 | ||
@@ -389,22 +395,18 @@ int do_adjtimex(struct timex *txc) | |||
389 | ntp_update_frequency(); | 395 | ntp_update_frequency(); |
390 | } | 396 | } |
391 | 397 | ||
398 | txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, | ||
399 | NTP_SCALE_SHIFT); | ||
400 | if (!(time_status & STA_NANO)) | ||
401 | txc->offset /= NSEC_PER_USEC; | ||
402 | |||
403 | adj_done: | ||
392 | result = time_state; /* mostly `TIME_OK' */ | 404 | result = time_state; /* mostly `TIME_OK' */ |
393 | if (time_status & (STA_UNSYNC|STA_CLOCKERR)) | 405 | if (time_status & (STA_UNSYNC|STA_CLOCKERR)) |
394 | result = TIME_ERROR; | 406 | result = TIME_ERROR; |
395 | 407 | ||
396 | if ((txc->modes == ADJ_OFFSET_SINGLESHOT) || | 408 | txc->freq = shift_right((time_freq >> PPM_SCALE_INV_SHIFT) * |
397 | (txc->modes == ADJ_OFFSET_SS_READ)) | 409 | (s64)PPM_SCALE_INV, NTP_SCALE_SHIFT); |
398 | txc->offset = save_adjust; | ||
399 | else { | ||
400 | txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, | ||
401 | NTP_SCALE_SHIFT); | ||
402 | if (!(time_status & STA_NANO)) | ||
403 | txc->offset /= NSEC_PER_USEC; | ||
404 | } | ||
405 | txc->freq = shift_right((s32)(time_freq >> PPM_SCALE_INV_SHIFT) * | ||
406 | (s64)PPM_SCALE_INV, | ||
407 | NTP_SCALE_SHIFT); | ||
408 | txc->maxerror = time_maxerror; | 410 | txc->maxerror = time_maxerror; |
409 | txc->esterror = time_esterror; | 411 | txc->esterror = time_esterror; |
410 | txc->status = time_status; | 412 | txc->status = time_status; |