diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-12-22 23:05:28 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-18 10:35:28 -0800 |
commit | 7d75e838bb5a3b2ec427b4121d4404f6b5689aae (patch) | |
tree | dd214a68520cbc4f64b465bac67b75e8c684c6d8 | |
parent | a79fdfe90a3795eabf04430400ecb4711d939c5f (diff) | |
download | linux-stable-7d75e838bb5a3b2ec427b4121d4404f6b5689aae.tar.gz linux-stable-7d75e838bb5a3b2ec427b4121d4404f6b5689aae.tar.bz2 linux-stable-7d75e838bb5a3b2ec427b4121d4404f6b5689aae.zip |
sched_clock: prevent scd->clock from moving backwards, take #2
commit 1c5745aa380efb6417b5681104b007c8612fb496 upstream.
Redo:
5b7dba4: sched_clock: prevent scd->clock from moving backwards
which had to be reverted due to s2ram hangs:
ca7e716: Revert "sched_clock: prevent scd->clock from moving backwards"
... this time with resume restoring GTOD later in the sequence
taken into account as well.
The "timekeeping_suspended" flag is not very nice but we cannot call into
GTOD before it has been properly resumed and the scheduler will run very
early in the resume sequence.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | include/linux/time.h | 1 | ||||
-rw-r--r-- | kernel/sched_clock.c | 5 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 7 |
3 files changed, 10 insertions, 3 deletions
diff --git a/include/linux/time.h b/include/linux/time.h index e15206a7e82e..0095ad11d7e2 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -99,6 +99,7 @@ extern unsigned long read_persistent_clock(void); extern int update_persistent_clock(struct timespec now); extern int no_sync_cmos_clock __read_mostly; void timekeeping_init(void); +extern int timekeeping_suspended; unsigned long get_seconds(void); struct timespec current_kernel_time(void); diff --git a/kernel/sched_clock.c b/kernel/sched_clock.c index e8ab096ddfe3..a0b0852414cc 100644 --- a/kernel/sched_clock.c +++ b/kernel/sched_clock.c @@ -124,7 +124,7 @@ static u64 __update_sched_clock(struct sched_clock_data *scd, u64 now) clock = scd->tick_gtod + delta; min_clock = wrap_max(scd->tick_gtod, scd->clock); - max_clock = scd->tick_gtod + TICK_NSEC; + max_clock = wrap_max(scd->clock, scd->tick_gtod + TICK_NSEC); clock = wrap_max(clock, min_clock); clock = wrap_min(clock, max_clock); @@ -227,6 +227,9 @@ EXPORT_SYMBOL_GPL(sched_clock_idle_sleep_event); */ void sched_clock_idle_wakeup_event(u64 delta_ns) { + if (timekeeping_suspended) + return; + sched_clock_tick(); touch_softlockup_watchdog(); } diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index e91c29f961c9..4220a2e1faab 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -46,6 +46,9 @@ struct timespec xtime __attribute__ ((aligned (16))); struct timespec wall_to_monotonic __attribute__ ((aligned (16))); static unsigned long total_sleep_time; /* seconds */ +/* flag for if timekeeping is suspended */ +int __read_mostly timekeeping_suspended; + static struct timespec xtime_cache __attribute__ ((aligned (16))); void update_xtime_cache(u64 nsec) { @@ -92,6 +95,8 @@ void getnstimeofday(struct timespec *ts) unsigned long seq; s64 nsecs; + WARN_ON(timekeeping_suspended); + do { seq = read_seqbegin(&xtime_lock); @@ -261,8 +266,6 @@ void __init timekeeping_init(void) write_sequnlock_irqrestore(&xtime_lock, flags); } -/* flag for if timekeeping is suspended */ -static int timekeeping_suspended; /* time in seconds when suspend began */ static unsigned long timekeeping_suspend_time; /* xtime offset when we went into suspend */ |