[PATCH] fix of unnecessary clocksource change after exiting from KDB console
Konstantin Baydarov <[email protected]>
| Newsgroups | gmane.linux.kernel.debugging |
|---|---|
| Message-ID | <[email protected]> |
When I spend more that 10 seconds in KDB console and then exit from KDB, Kernel think that current clocksource is unstable and change it. I'm using 2.6.22-rc7 kdb on SMP i386 system. Here is log: Before doing sync, I've set breakpoint to do_sync(). [email protected]:~# [email protected]:~# cat /sys/devices/system/clocksource/clocksource0/current_clocksource tsc [email protected]:~# sync Instruction(i) breakpoint #0 at 0xc017b64a (adjusted) 0xc017b64a do_sync: int3 Entering kdb (current=0xc16f3a50, pid 2983) on processor 0 due to Breakpoint @ 0xc017b64a [0]kdb> go Clocksource tsc unstable (delta = 14060902198 ns) [email protected]:~# Time: acpi_pm clocksource has been installed. [email protected]:~# [email protected]:~# cat /sys/devices/system/clocksource/clocksource0/current_clocksource acpi_pm [email protected]:~# [email protected]:~# Issue: tsc clocksource was replaced by acpi_pm. The reason of issue: Current clocksource(tsc) in kernel have a watchdog - another clocksource(acpi_pm). clocksource_watchdog() that updates watchdog_last timestamp runs with help of kernel timer that is disabled when kernel enters kdb. So watchdog clocksource(acpi_pm) can overflow and when kernel exits kdb, watchdog clocksource can report wrong time delta - that's why kernel can think that current clocksource is unstable and change it. How solved: I suspend/resume timekeeping when we enter/exit kdb. Suspend/resume of timekeeping suspends/resumes current clocksource and watchdog clocksource. Also patch prevents potential softlockup warnings that appear in earlier kernels. Thanks. Signed-off-by: Konstantin Baydarov <[email protected]> kdb/kdbmain.c | 17 +++++++++++++++++ kernel/time/timekeeping.c | 27 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) Index: linux-2.6.22-rc7/kdb/kdbmain.c =================================================================== --- linux-2.6.22-rc7.orig/kdb/kdbmain.c +++ linux-2.6.22-rc7/kdb/kdbmain.c @@ -47,6 +47,9 @@ #include <asm/system.h> #include <asm/kdebug.h> +int kdb_timekeeping_suspend(void); +int kdb_timekeeping_resume(void); + /* * Kernel debugger state flags */ @@ -60,6 +63,7 @@ atomic_t kdb_8250; */ static DEFINE_SPINLOCK(kdb_lock); volatile int kdb_initial_cpu = -1; /* cpu number that owns kdb */ +volatile int kdb_initial_cpu_save = -1; /* cpu number that owns kdb */ int kdb_seqno = 2; /* how many times kdb has been entered */ volatile int kdb_nextline = 1; @@ -1998,6 +2002,11 @@ kdb(kdb_reason_t reason, int error, stru smp_kdb_stop(); KDB_DEBUG_STATE("kdb 8", reason); } + /* Suspend clocksource, when entering kdb, to prevent + * false soft lockup warnings and switching to another + * clocksource. + */ + kdb_timekeeping_suspend(); } if (KDB_STATE(GO1)) { @@ -2020,6 +2029,7 @@ kdb(kdb_reason_t reason, int error, stru if (result == KDB_CMD_GO && KDB_STATE(SSBPT)) KDB_STATE_SET(GO1); + kdb_initial_cpu_save = kdb_initial_cpu; if (smp_processor_id() == kdb_initial_cpu && !KDB_STATE(DOING_SS) && !KDB_STATE(RECURSE)) { @@ -2055,6 +2065,13 @@ kdb(kdb_reason_t reason, int error, stru } } + /* Only do this work if we are really leaving kdb */ + if (!(KDB_STATE(DOING_SS) || KDB_STATE(SSBPT) || KDB_STATE(RECURSE))) { + if(smp_processor_id() == kdb_initial_cpu_save) + /* Resume clocksource when initial cpu leaves kdb */ + kdb_timekeeping_resume(); + } + KDB_DEBUG_STATE("kdb 14", result); kdba_restoreint(&int_state); #ifdef CONFIG_CPU_XSCALE Index: linux-2.6.22-rc7/kernel/time/timekeeping.c =================================================================== --- linux-2.6.22-rc7.orig/kernel/time/timekeeping.c +++ linux-2.6.22-rc7/kernel/time/timekeeping.c @@ -299,6 +299,19 @@ static int timekeeping_resume(struct sys return 0; } +#if defined(CONFIG_KDB) || defined(CONFIG_KDB_MODULE) +int kdb_timekeeping_resume(void) +{ + int ret; + struct sys_device dev; + + ret = timekeeping_resume(&dev); + + return ret; +} +EXPORT_SYMBOL(kdb_timekeeping_resume); +#endif + static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) { unsigned long flags; @@ -313,6 +326,20 @@ static int timekeeping_suspend(struct sy return 0; } +#if defined(CONFIG_KDB) || defined(CONFIG_KDB_MODULE) +int kdb_timekeeping_suspend(void) +{ + int ret; + struct sys_device dev; + pm_message_t state; + + ret = timekeeping_suspend(&dev, state); + + return ret; +} +EXPORT_SYMBOL(kdb_timekeeping_suspend); +#endif + /* sysfs resume/suspend bits for timekeeping */ static struct sysdev_class timekeeping_sysclass = { .resume = timekeeping_resume, --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe.