Re: [GIT pull] printk updates for 4.15

From: Thomas Gleixner
Date: Fri Nov 17 2017 - 19:26:24 EST


On Thu, 16 Nov 2017, Thomas Gleixner wrote:
> I hope that I can find a few spare cycles to whip up a POC patch which does
> not make stuff fall apart immediately.

Here you go. It survived suspend resume in a VM.

Thanks,

tglx

8<------------------------
Subject: timekeeping: Make monotonic behave like boottime
From: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Date: Fri, 17 Nov 2017 11:46:48 +0100

Clock MONOTONIC is not fast forwarded by the time spent in suspend on
resume. This is only done for BOOTTIME.

It would be desired to get rid of that difference, but the difference
between clock MONOTONIC and clock BOOTTIME is well documented so there
might be applications which depend on that behaviour.

Implement it for testing purposes.

This requires to prevent that jiffies advance, which are coupled at clock
MONOTONIC as well in the current implementation. This is achieved by
forwarding the variables which are used for the jiffies update after resume
before the tick is restarted,

In timekeeping resume, the change is rather simple. Instead of updating the
offset between clock MONOTONIC and clock REALTIME/BOOTTIME, advance the
time keeper base for the MONOTONIC and the MONOTONIC_RAW clock by the time
spent in suspend.

So MONOTONIC is now the same as BOOTTIME and the offset between clock
REALTIME and clock MONOTONIC is the same as before suspend.

WARNING:

Use this with caution. Following prerequisites are required before booting
into a kernel with this patch applied:

- Backup of important data like the nude pictures you did not send to
facebook yet

- Functional fire estinguisher

- Vaccum cleaner to deal with the fallout

You've been warned and you're responsible for any damage which might result.

NOT-Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
---
kernel/time/tick-common.c | 15 +++++++++++++++
kernel/time/tick-internal.h | 6 ++++++
kernel/time/tick-sched.c | 9 +++++++++
kernel/time/timekeeping.c | 9 +++++++--
4 files changed, 37 insertions(+), 2 deletions(-)

--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -419,6 +419,19 @@ void tick_suspend_local(void)
clockevents_shutdown(td->evtdev);
}

+static void tick_forward_next_period(void)
+{
+ ktime_t delta, now = ktime_get();
+ u64 n;
+
+ delta = ktime_sub(now, tick_next_period);
+ n = ktime_divns(delta, tick_period);
+ tick_next_period += n * tick_period;
+ if (tick_next_period < now)
+ tick_next_period += tick_period;
+ tick_sched_forward_next_period();
+}
+
/**
* tick_resume_local - Resume the local tick device
*
@@ -431,6 +444,8 @@ void tick_resume_local(void)
struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
bool broadcast = tick_resume_check_broadcast();

+ tick_forward_next_period();
+
clockevents_tick_resume(td->evtdev);
if (!broadcast) {
if (td->mode == TICKDEV_MODE_PERIODIC)
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -141,6 +141,12 @@ static inline void tick_check_oneshot_br
static inline bool tick_broadcast_oneshot_available(void) { return tick_oneshot_possible(); }
#endif /* !(BROADCAST && ONESHOT) */

+#if defined(CONFIG_NO_HZ_COMMON) || defined(CONFIG_HIGH_RES_TIMERS)
+extern void tick_sched_forward_next_period(void);
+#else
+static inline void tick_sched_forward_next_period(void) { }
+#endif
+
/* NO_HZ_FULL internal */
#ifdef CONFIG_NO_HZ_FULL
extern void tick_nohz_init(void);
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -52,6 +52,15 @@ struct tick_sched *tick_get_tick_sched(i
static ktime_t last_jiffies_update;

/*
+ * Called after resume. Make sure that jiffies are not fast forwarded due to
+ * clock monotonic being forwarded by the suspended time.
+ */
+void tick_sched_forward_next_period(void)
+{
+ last_jiffies_update = tick_next_period;
+}
+
+/*
* Must be called with interrupts disabled !
*/
static void tick_do_update_jiffies64(ktime_t now)
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -138,7 +138,13 @@ static void tk_set_wall_to_mono(struct t

static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
{
- tk->offs_boot = ktime_add(tk->offs_boot, delta);
+ /*
+ * Update both bases so mono and raw stay coupled. Not strictly the
+ * same as the old code which did not adjust clock monotonic after
+ * resume, so dragons might be lurking somewhere.
+ */
+ tk->tkr_mono.base += delta;
+ tk->tkr_raw.base += delta;
}

/*
@@ -1624,7 +1630,6 @@ static void __timekeeping_inject_sleepti
return;
}
tk_xtime_add(tk, delta);
- tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, *delta));
tk_update_sleep_time(tk, timespec64_to_ktime(*delta));
tk_debug_account_sleep_time(delta);
}