[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.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.