[PATCH] fix of unnecessary clocksource change after exiting from KDB console

Konstantin Baydarov kbaidarov at ru.mvista.com
Mon Jul 9 08:39:16 PDT 2007


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().
root at 192.168.40.10:~#
root at 192.168.40.10:~# cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc
root at 192.168.40.10:~# 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)
root at 192.168.40.10:~# Time: acpi_pm clocksource has been installed.

root at 192.168.40.10:~#
root at 192.168.40.10:~# cat /sys/devices/system/clocksource/clocksource0/current_clocksource
acpi_pm
root at 192.168.40.10:~#
root at 192.168.40.10:~#

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 <kbaidarov at ru.mvista.com>

 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.


More information about the kdb mailing list