diff options
| author | Pavel Tatashin <pasha.tatashin@oracle.com> | 2018-07-19 16:55:34 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2018-07-19 18:02:40 -0400 |
| commit | 3eca993740b8eb40f514b90b1877a4dbcf0a6710 (patch) | |
| tree | a34720fb82704a1258c84ae0d8255091d36310f7 /kernel/time | |
| parent | be2e0e4257678408b0ab00ea9e743b9094e393e8 (diff) | |
timekeeping: Replace read_boot_clock64() with read_persistent_wall_and_boot_offset()
If architecture does not support exact boot time, it is challenging to
estimate boot time without having a reference to the current persistent
clock value. Yet, it cannot read the persistent clock time again, because
this may lead to math discrepancies with the caller of read_boot_clock64()
who have read the persistent clock at a different time.
This is why it is better to provide two values simultaneously: the
persistent clock value, and the boot time.
Replace read_boot_clock64() with:
read_persistent_wall_and_boot_offset(wall_time, boot_offset)
Where wall_time is returned by read_persistent_clock() And boot_offset is
wall_time - boot time, which defaults to 0.
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: steven.sistare@oracle.com
Cc: daniel.m.jordan@oracle.com
Cc: linux@armlinux.org.uk
Cc: schwidefsky@de.ibm.com
Cc: heiko.carstens@de.ibm.com
Cc: john.stultz@linaro.org
Cc: sboyd@codeaurora.org
Cc: hpa@zytor.com
Cc: douly.fnst@cn.fujitsu.com
Cc: peterz@infradead.org
Cc: prarit@redhat.com
Cc: feng.tang@intel.com
Cc: pmladek@suse.com
Cc: gnomes@lxorguk.ukuu.org.uk
Cc: linux-s390@vger.kernel.org
Cc: boris.ostrovsky@oracle.com
Cc: jgross@suse.com
Cc: pbonzini@redhat.com
Link: https://lkml.kernel.org/r/20180719205545.16512-16-pasha.tatashin@oracle.com
Diffstat (limited to 'kernel/time')
| -rw-r--r-- | kernel/time/timekeeping.c | 59 |
1 files changed, 30 insertions, 29 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 4786df904c22..cb738f825c12 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/nmi.h> | 17 | #include <linux/nmi.h> |
| 18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
| 19 | #include <linux/sched/loadavg.h> | 19 | #include <linux/sched/loadavg.h> |
| 20 | #include <linux/sched/clock.h> | ||
| 20 | #include <linux/syscore_ops.h> | 21 | #include <linux/syscore_ops.h> |
| 21 | #include <linux/clocksource.h> | 22 | #include <linux/clocksource.h> |
| 22 | #include <linux/jiffies.h> | 23 | #include <linux/jiffies.h> |
| @@ -1496,18 +1497,20 @@ void __weak read_persistent_clock64(struct timespec64 *ts64) | |||
| 1496 | } | 1497 | } |
| 1497 | 1498 | ||
| 1498 | /** | 1499 | /** |
| 1499 | * read_boot_clock64 - Return time of the system start. | 1500 | * read_persistent_wall_and_boot_offset - Read persistent clock, and also offset |
| 1501 | * from the boot. | ||
| 1500 | * | 1502 | * |
| 1501 | * Weak dummy function for arches that do not yet support it. | 1503 | * Weak dummy function for arches that do not yet support it. |
| 1502 | * Function to read the exact time the system has been started. | 1504 | * wall_time - current time as returned by persistent clock |
| 1503 | * Returns a timespec64 with tv_sec=0 and tv_nsec=0 if unsupported. | 1505 | * boot_offset - offset that is defined as wall_time - boot_time |
| 1504 | * | 1506 | * default to 0. |
| 1505 | * XXX - Do be sure to remove it once all arches implement it. | ||
| 1506 | */ | 1507 | */ |
| 1507 | void __weak read_boot_clock64(struct timespec64 *ts) | 1508 | void __weak __init |
| 1509 | read_persistent_wall_and_boot_offset(struct timespec64 *wall_time, | ||
| 1510 | struct timespec64 *boot_offset) | ||
| 1508 | { | 1511 | { |
| 1509 | ts->tv_sec = 0; | 1512 | read_persistent_clock64(wall_time); |
| 1510 | ts->tv_nsec = 0; | 1513 | *boot_offset = (struct timespec64){0}; |
| 1511 | } | 1514 | } |
| 1512 | 1515 | ||
| 1513 | /* Flag for if timekeeping_resume() has injected sleeptime */ | 1516 | /* Flag for if timekeeping_resume() has injected sleeptime */ |
| @@ -1521,28 +1524,29 @@ static bool persistent_clock_exists; | |||
| 1521 | */ | 1524 | */ |
| 1522 | void __init timekeeping_init(void) | 1525 | void __init timekeeping_init(void) |
| 1523 | { | 1526 | { |
| 1527 | struct timespec64 wall_time, boot_offset, wall_to_mono; | ||
| 1524 | struct timekeeper *tk = &tk_core.timekeeper; | 1528 | struct timekeeper *tk = &tk_core.timekeeper; |
| 1525 | struct clocksource *clock; | 1529 | struct clocksource *clock; |
| 1526 | unsigned long flags; | 1530 | unsigned long flags; |
| 1527 | struct timespec64 now, boot, tmp; | ||
| 1528 | |||
| 1529 | read_persistent_clock64(&now); | ||
| 1530 | if (!timespec64_valid_strict(&now)) { | ||
| 1531 | pr_warn("WARNING: Persistent clock returned invalid value!\n" | ||
| 1532 | " Check your CMOS/BIOS settings.\n"); | ||
| 1533 | now.tv_sec = 0; | ||
| 1534 | now.tv_nsec = 0; | ||
| 1535 | } else if (now.tv_sec || now.tv_nsec) | ||
| 1536 | persistent_clock_exists = true; | ||
| 1537 | 1531 | ||
| 1538 | read_boot_clock64(&boot); | 1532 | read_persistent_wall_and_boot_offset(&wall_time, &boot_offset); |
| 1539 | if (!timespec64_valid_strict(&boot)) { | 1533 | if (timespec64_valid_strict(&wall_time) && |
| 1540 | pr_warn("WARNING: Boot clock returned invalid value!\n" | 1534 | timespec64_to_ns(&wall_time) > 0) { |
| 1541 | " Check your CMOS/BIOS settings.\n"); | 1535 | persistent_clock_exists = true; |
| 1542 | boot.tv_sec = 0; | 1536 | } else { |
| 1543 | boot.tv_nsec = 0; | 1537 | pr_warn("Persistent clock returned invalid value"); |
| 1538 | wall_time = (struct timespec64){0}; | ||
| 1544 | } | 1539 | } |
| 1545 | 1540 | ||
| 1541 | if (timespec64_compare(&wall_time, &boot_offset) < 0) | ||
| 1542 | boot_offset = (struct timespec64){0}; | ||
| 1543 | |||
| 1544 | /* | ||
| 1545 | * We want set wall_to_mono, so the following is true: | ||
| 1546 | * wall time + wall_to_mono = boot time | ||
| 1547 | */ | ||
| 1548 | wall_to_mono = timespec64_sub(boot_offset, wall_time); | ||
| 1549 | |||
| 1546 | raw_spin_lock_irqsave(&timekeeper_lock, flags); | 1550 | raw_spin_lock_irqsave(&timekeeper_lock, flags); |
| 1547 | write_seqcount_begin(&tk_core.seq); | 1551 | write_seqcount_begin(&tk_core.seq); |
| 1548 | ntp_init(); | 1552 | ntp_init(); |
| @@ -1552,13 +1556,10 @@ void __init timekeeping_init(void) | |||
| 1552 | clock->enable(clock); | 1556 | clock->enable(clock); |
| 1553 | tk_setup_internals(tk, clock); | 1557 | tk_setup_internals(tk, clock); |
| 1554 | 1558 | ||
| 1555 | tk_set_xtime(tk, &now); | 1559 | tk_set_xtime(tk, &wall_time); |
| 1556 | tk->raw_sec = 0; | 1560 | tk->raw_sec = 0; |
| 1557 | if (boot.tv_sec == 0 && boot.tv_nsec == 0) | ||
| 1558 | boot = tk_xtime(tk); | ||
| 1559 | 1561 | ||
| 1560 | set_normalized_timespec64(&tmp, -boot.tv_sec, -boot.tv_nsec); | 1562 | tk_set_wall_to_mono(tk, wall_to_mono); |
| 1561 | tk_set_wall_to_mono(tk, tmp); | ||
| 1562 | 1563 | ||
| 1563 | timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); | 1564 | timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); |
| 1564 | 1565 | ||
