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 1ad46f3df6e..8ff15e5d486 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; |
