linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: LKML <linux-kernel@vger.kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	Ingo Molnar <mingo@elte.hu>, Greg KH <greg@kroah.com>
Subject: [patch 2/2] add timer specific object debugging code
Date: Sat, 01 Mar 2008 10:25:00 -0000	[thread overview]
Message-ID: <20080301100325.632812903@linutronix.de> (raw)
In-Reply-To: 20080301100019.640027768@linutronix.de

[-- Attachment #1: timer-debugging.patch --]
[-- Type: text/plain, Size: 7033 bytes --]

Add calls to the generic object debugging infrastructure and provide a
fixup function which allows to keep the system alive when recoverable
problems have been detected by the object debugging core code. Add a
selftest, which covers the two possible mistakes: free/init of an
active timer.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/debugobjects.h |    1 
 include/linux/timer.h        |   22 +++++++++++
 kernel/timer.c               |   85 +++++++++++++++++++++++++++++++++++++++++++
 lib/Kconfig.debug            |    7 +++
 lib/debugobjects.c           |   18 ++++++++-
 5 files changed, 131 insertions(+), 2 deletions(-)

Index: linux-2.6/include/linux/debugobjects.h
===================================================================
--- linux-2.6.orig/include/linux/debugobjects.h
+++ linux-2.6/include/linux/debugobjects.h
@@ -14,6 +14,7 @@ enum debug_obj_op {
 
 enum {
 	ODEBUG_TYPE_UNKNOWN,
+	ODEBUG_TYPE_TIMER,
 	ODEBUG_MAX_TYPES
 };
 
Index: linux-2.6/include/linux/timer.h
===================================================================
--- linux-2.6.orig/include/linux/timer.h
+++ linux-2.6/include/linux/timer.h
@@ -4,6 +4,7 @@
 #include <linux/list.h>
 #include <linux/ktime.h>
 #include <linux/stddef.h>
+#include <linux/debugobjects.h>
 
 struct tvec_base;
 
@@ -20,6 +21,9 @@ struct timer_list {
 	char start_comm[16];
 	int start_pid;
 #endif
+#ifdef CONFIG_DEBUG_OBJECT_TIMERS
+	struct debug_obj dobj;
+#endif
 };
 
 extern struct tvec_base boot_tvec_bases;
@@ -164,5 +168,23 @@ unsigned long __round_jiffies_relative(u
 unsigned long round_jiffies(unsigned long j);
 unsigned long round_jiffies_relative(unsigned long j);
 
+#ifdef CONFIG_DEBUG_OBJECT_TIMERS
+static inline void
+debug_timer_object_op(struct timer_list *timer, enum debug_obj_op mode)
+{
+	timer->dobj.type = ODEBUG_TYPE_TIMER;
+	debug_object_op(&timer->dobj, mode);
+}
+extern int timer_fixup_object(struct debug_obj *obj, enum debug_obj_op mode);
+extern int timer_debug_object_selftest(void);
+#else
+static inline void
+debug_timer_object_op(struct timer_list *timer, enum debug_obj_op mode)
+{
+}
+# define timer_fixup_object NULL
+static inline int timer_debug_object_selftest(void) { return 0; }
+#endif
+
 
 #endif
Index: linux-2.6/kernel/timer.c
===================================================================
--- linux-2.6.orig/kernel/timer.c
+++ linux-2.6/kernel/timer.c
@@ -320,6 +320,84 @@ static void timer_stats_account_timer(st
 static void timer_stats_account_timer(struct timer_list *timer) {}
 #endif
 
+#ifdef CONFIG_DEBUG_OBJECT_TIMERS
+
+static int timer_fixup_done __read_mostly;
+
+int timer_fixup_object(struct debug_obj *obj, enum debug_obj_op op)
+{
+	struct timer_list *timer = container_of(obj, struct timer_list, dobj);
+
+	switch (op) {
+	case ODEBUG_INIT:
+	case ODEBUG_FREE:
+		del_timer_sync(timer);
+		timer_fixup_done++;
+		return 0;
+	/*
+	 * These are fatal timer.c internal errors. No real way to
+	 * survive:
+	 */
+	case ODEBUG_ADD:
+	case ODEBUG_DEL:
+		return -1;
+	default:
+		return -1;
+	}
+}
+
+/*
+ * Test the two popular bugs:
+ *
+ * - reinit a timer which is enqueued
+ * - free a datastructure which contains an enqueued timer
+ */
+
+static void __init timer_debug_selftest_fn(unsigned long arg)
+{
+}
+
+int __init timer_debug_object_selftest(void)
+{
+	struct timer_list *timer;
+	int fixup_cnt = timer_fixup_done;
+
+	timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
+	if (!timer)
+		return -ENOMEM;
+
+	setup_timer(timer, timer_debug_selftest_fn, 0);
+
+	timer->expires = jiffies + HZ;
+	add_timer(timer);
+
+	setup_timer(timer, timer_debug_selftest_fn, 0);
+	if (fixup_cnt == timer_fixup_done)
+		goto err;
+
+#ifdef CONFIG_DEBUG_OBJECTS_FREE
+	timer->expires = jiffies + HZ;
+	add_timer(timer);
+
+	fixup_cnt = timer_fixup_done;
+	kfree(timer);
+	timer = NULL;
+
+	if (fixup_cnt == timer_fixup_done)
+		goto err;
+#else
+	kfree(timer);
+#endif
+	return 0;
+
+err:
+	printk(KERN_ERR "TIMER: ODEBUG selftest failed\n");
+	kfree(timer);
+	return -1;
+}
+
+#endif
+
 /**
  * init_timer - initialize a timer.
  * @timer: the timer to be initialized
@@ -329,6 +407,8 @@ static void timer_stats_account_timer(st
  */
 void init_timer(struct timer_list *timer)
 {
+	debug_timer_object_op(timer, ODEBUG_INIT);
+
 	timer->entry.next = NULL;
 	timer->base = __raw_get_cpu_var(tvec_bases);
 #ifdef CONFIG_TIMER_STATS
@@ -351,6 +431,8 @@ static inline void detach_timer(struct t
 {
 	struct list_head *entry = &timer->entry;
 
+	debug_timer_object_op(timer, ODEBUG_DEL);
+
 	__list_del(entry->prev, entry->next);
 	if (clear_pending)
 		entry->next = NULL;
@@ -405,6 +487,8 @@ int __mod_timer(struct timer_list *timer
 		ret = 1;
 	}
 
+	debug_timer_object_op(timer, ODEBUG_ADD);
+
 	new_base = __get_cpu_var(tvec_bases);
 
 	if (base != new_base) {
@@ -450,6 +534,7 @@ void add_timer_on(struct timer_list *tim
 	BUG_ON(timer_pending(timer) || !timer->function);
 	spin_lock_irqsave(&base->lock, flags);
 	timer_set_base(timer, base);
+	debug_timer_object_op(timer, ODEBUG_ADD);
 	internal_add_timer(base, timer);
 	spin_unlock_irqrestore(&base->lock, flags);
 }
Index: linux-2.6/lib/Kconfig.debug
===================================================================
--- linux-2.6.orig/lib/Kconfig.debug
+++ linux-2.6/lib/Kconfig.debug
@@ -199,6 +199,13 @@ config DEBUG_OBJECT_FREE
 	 properly.  This can make kmalloc/kfree-intensive workloads
 	 much slower.
 
+config DEBUG_OBJECT_TIMERS
+	bool "Debug timer objects"
+       	depends on DEBUG_OBJECT_OPS
+       	help
+	  If you say Y here, additional code will be inserted into the
+	  timer routines to validate the timer operations.
+
 config DEBUG_SLAB
 	bool "Debug slab memory allocations"
 	depends on DEBUG_KERNEL && SLAB
Index: linux-2.6/lib/debugobjects.c
===================================================================
--- linux-2.6.orig/lib/debugobjects.c
+++ linux-2.6/lib/debugobjects.c
@@ -12,6 +12,7 @@
 #include <linux/debugfs.h>
 #include <linux/debugobjects.h>
 #include <linux/seq_file.h>
+#include <linux/timer.h>
 
 #define ODEBUG_HASH_SIZE	4096
 #define ODEBUG_HASH_MASK	(ODEBUG_HASH_SIZE - 1)
@@ -48,11 +49,13 @@ static struct odebug *object_get_hash(un
 }
 
 static const void * const debug_fixup[ODEBUG_MAX_TYPES] = {
+	[ODEBUG_TYPE_TIMER] = timer_fixup_object,
 };
 
 static const char * const obj_types[ODEBUG_MAX_TYPES] = {
 
 	[ODEBUG_TYPE_UNKNOWN] = "unknown type",
+	[ODEBUG_TYPE_TIMER] = "timer_list",
 };
 
 static void debug_print_object(struct debug_obj *obj, char *msg)
@@ -246,11 +249,22 @@ void __init debug_objects_init(void)
 
 int __init debug_objects_do_selftest(void)
 {
+	int res;
+
 	if (!debug_objects_enabled)
 		return 0;
 
 	debug_objects_init_debugfs();
-	printk(KERN_INFO "ODEBUG: Selftest pass\n");
-	return 0;
+
+	debug_objects_selftest = 1;
+
+	res = timer_debug_object_selftest();
+
+	debug_objects_selftest = 0;
+
+	if (!res)
+		printk(KERN_INFO "ODEBUG: Selftest pass\n");
+
+	return res;
 }
 __initcall(debug_objects_do_selftest);

-- 


  parent reply	other threads:[~2008-03-01 10:26 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-03-01 10:24 [patch 0/2] object debugging infrastructure Thomas Gleixner
2008-03-01 10:24 ` [patch 1/2] infrastructure to debug (dynamic) objects Thomas Gleixner
2008-03-01 10:51   ` Andrew Morton
2008-03-01 11:44     ` Thomas Gleixner
2008-03-01 22:42       ` Peter Zijlstra
2008-03-02 10:06         ` Thomas Gleixner
2008-03-01 10:25 ` Thomas Gleixner [this message]
2008-03-02  5:20 ` [patch 0/2] object debugging infrastructure Greg KH
2008-03-02  9:54   ` Thomas Gleixner
2008-03-03 12:42 ` Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080301100325.632812903@linutronix.de \
    --to=tglx@linutronix.de \
    --cc=akpm@linux-foundation.org \
    --cc=greg@kroah.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).