diff mbox

[RFC,v5] timekeeping: Ignore the bogus sleep time if pm_trace is enabled

Message ID alpine.DEB.2.20.1609091551110.5679@nanos (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Thomas Gleixner Sept. 9, 2016, 2:33 p.m. UTC
On Fri, 9 Sep 2016, Chen Yu wrote:
> > I really have no idea why this is burried in x86 land. The pm_trace hackery
> > issues mc146818_set_time() to fiddle with the RTC. So any implementation of
> > this is affected.
> OK, I've changed this patch according to this suggestion.

No you did not! You still have that silly x86 hackery in place.
 
> OK. I've moved most of the logic into the pm_trace component,
> Once the mc146818_set_time has modified the RTC by pm_trace,
> related flags will be set which indicates the unusable of RTC.
> And timekeeping system is able to query these flags to decide whether
> it should inject the sleep time. (We tried to make this patch as
> simple as possible, but it looks like we have to deal with persistent
> clock for x86, which makes this patch a little more complicated).
> Here's the trial version of it, any suggestion would be appreciated:

It's overengineered and horrible.
 
> +unsigned int timekeeping_tainted;

It does not taint timekeeping. It just wreckages the RTC.

> +void pm_trace_taint_timekeeping(void)
> +{
> +	if (pm_trace_is_enabled()) {
> +		timekeeping_tainted |= TIMEKEEPING_RTC_TAINTED;
> +		if (arch_pm_trace_taint_pclock())
> +			timekeeping_tainted |= TIMEKEEPING_PERSISTENT_CLOCK_TAINTED;
> +	}

Why would you need all these flags?

> +static inline int pm_trace_rtc_is_tainted(void)
> +{
> +	return (timekeeping_tainted & TIMEKEEPING_RTC_TAINTED) ?
> +		1 : 0;

ever heard about bool?

> +}
> +

> +extern void pm_trace_untaint_timekeeping(void);

And how exactly do you untaint it? Just by clearing the flags. That makes
the RTC time magically correct again?

> +int arch_pm_trace_taint_pclock(void)
> +{
> +	return (x86_platform.get_wallclock == mach_get_cmos_time);
> +}

Groan. I told you to do it in the mc14xxx related places. There are not
that many in the kernel

Here is a completely uncompiled/untested patch which should address the
issue in a halfways clean way.

Thanks,

	tglx

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Chen Yu Sept. 10, 2016, 9:40 a.m. UTC | #1
Hi,
On Fri, Sep 09, 2016 at 04:33:59PM +0200, Thomas Gleixner wrote:
> On Fri, 9 Sep 2016, Chen Yu wrote:
>
> > +extern void pm_trace_untaint_timekeeping(void);
> 
> And how exactly do you untaint it? Just by clearing the flags. That makes
> the RTC time magically correct again?
> 
> > +int arch_pm_trace_taint_pclock(void)
> > +{
> > +	return (x86_platform.get_wallclock == mach_get_cmos_time);
> > +}
> 
> Groan. I told you to do it in the mc14xxx related places. There are not
> that many in the kernel
> 
> Here is a completely uncompiled/untested patch which should address the
> issue in a halfways clean way.
> 
> Thanks,
> 
> 	tglx
> 
OK, I made some small adjustment to make it compiled without pm_trace
configured, and this version is absolutely more professional than
my previous one. I'll do some testing based on it.
Besides I have another question related to the untain
of the pm_trace_rtc_abused flag: after resume back, if the user disabled
the pm_trace, then the following suspend/resume sleep time should become
valid again IMO, because we use the delta rather than the RTC itself for
suspend/resume. So in this version it disable the injection of sleep time
once pm_trace has been used? 

Thanks,
Yu
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

--- a/arch/x86/kernel/rtc.c
+++ b/arch/x86/kernel/rtc.c
@@ -64,6 +64,15 @@  void mach_get_cmos_time(struct timespec
 	unsigned int status, year, mon, day, hour, min, sec, century = 0;
 	unsigned long flags;
 
+	/*
+	 * If pm trace abused the RTC as storage set the timespec to 0
+	 * which tells the caller that this RTC value is bogus.
+	 */
+	if (!pm_trace_rtc_valid()) {
+		now->tv_sec = now->tv_nsec = 0;
+		return;
+	}
+
 	spin_lock_irqsave(&rtc_lock, flags);
 
 	/*
--- a/drivers/base/power/trace.c
+++ b/drivers/base/power/trace.c
@@ -74,6 +74,7 @@ 
 
 #define DEVSEED (7919)
 
+bool pm_trace_rtc_abused __read_mostly;
 static unsigned int dev_hash_value;
 
 static int set_magic_time(unsigned int user, unsigned int file, unsigned int device)
@@ -104,6 +105,7 @@  static int set_magic_time(unsigned int u
 	time.tm_min = (n % 20) * 3;
 	n /= 20;
 	mc146818_set_time(&time);
+	pm_trace_rtc_abused = true;
 	return n ? -1 : 0;
 }
 
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -189,6 +189,13 @@  static inline void cmos_write_bank2(unsi
 
 static int cmos_read_time(struct device *dev, struct rtc_time *t)
 {
+	/*
+	 * If pmtrace abused the RTC for storage tell the caller that it is
+	 * unusable.
+	 */
+	if (!pm_trace_rtc_valid())
+		return -EIO;
+
 	/* REVISIT:  if the clock has a "century" register, use
 	 * that instead of the heuristic in mc146818_get_time().
 	 * That'll make Y3K compatility (year > 2070) easy!
--- a/include/linux/mc146818rtc.h
+++ b/include/linux/mc146818rtc.h
@@ -16,6 +16,7 @@ 
 #include <asm/mc146818rtc.h>		/* register access macros */
 #include <linux/bcd.h>
 #include <linux/delay.h>
+#include <linux/pm-trace.h>
 
 #ifdef __KERNEL__
 #include <linux/spinlock.h>		/* spinlock_t */
--- a/include/linux/pm-trace.h
+++ b/include/linux/pm-trace.h
@@ -6,6 +6,12 @@ 
 #include <linux/types.h>
 
 extern int pm_trace_enabled;
+extern bool pm_trace_rtc_abused;
+
+static inline bool pm_trace_rtc_valid(void)
+{
+	return !pm_trace_rtc_abused;
+}
 
 static inline int pm_trace_is_enabled(void)
 {
@@ -24,6 +30,7 @@  extern int show_trace_dev_match(char *bu
 
 #else
 
+static inline bool pm_trace_rtc_valid(void) { return true; }
 static inline int pm_trace_is_enabled(void) { return 0; }
 
 #define TRACE_DEVICE(dev) do { } while (0)