[PATCH] Track live engines and their refcounts

Ananth N Mavinakayanahalli ananth at in.ibm.com
Thu Jan 29 16:32:34 UTC 2009


Here is a patch that will track live engines and expose them via debugfs.
This will show if there are stale engines and their refcounts, also to
determine if there are any engine slab leaks.

This is just for debug purposes. Needs tweaking if this needs to be
part of the core patch (ifdefs, etc).

Applies atop the rcu removal patch sent last week:
https://www.redhat.com/archives/utrace-devel/2009-January/msg00075.html

Signed-off-by: Ananth N Mavinakayanahalli <ananth at in.ibm.com>
---
 include/linux/utrace.h |    1 
 kernel/utrace.c        |   99 ++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 99 insertions(+), 1 deletion(-)

Index: utrace-20jan/include/linux/utrace.h
===================================================================
--- utrace-20jan.orig/include/linux/utrace.h
+++ utrace-20jan/include/linux/utrace.h
@@ -317,6 +317,7 @@ struct utrace_attached_engine {
 /* private: */
 	struct kref kref;
 	struct list_head entry;
+	struct list_head live;
 
 /* public: */
 	const struct utrace_engine_ops *ops;
Index: utrace-20jan/kernel/utrace.c
===================================================================
--- utrace-20jan.orig/kernel/utrace.c
+++ utrace-20jan/kernel/utrace.c
@@ -21,8 +21,10 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
+#include <linux/debugfs.h>
 #include <linux/utrace.h>
 
+#include <asm/atomic.h>
 
 /*
  * struct utrace, defined in utrace.h is private to this file. Its
@@ -50,11 +52,16 @@
  * callbacks seen.
  */
 
+static spinlock_t live_lock;
+static struct list_head live_engines;
+
 static struct kmem_cache *utrace_engine_cachep;
 static const struct utrace_engine_ops utrace_detached_ops; /* forward decl */
 
 static int __init utrace_init(void)
 {
+	INIT_LIST_HEAD(&live_engines);
+	spin_lock_init(&live_lock);
 	utrace_engine_cachep = KMEM_CACHE(utrace_attached_engine, SLAB_PANIC);
 	return 0;
 }
@@ -79,6 +86,9 @@ void __utrace_engine_release(struct kref
 	struct utrace_attached_engine *engine =
 		container_of(kref, struct utrace_attached_engine, kref);
 	BUG_ON(!list_empty(&engine->entry));
+	spin_lock(&live_lock);
+	list_del(&engine->live);
+	spin_unlock(&live_lock);
 	kmem_cache_free(utrace_engine_cachep, engine);
 }
 EXPORT_SYMBOL_GPL(__utrace_engine_release);
@@ -322,6 +332,7 @@ restart:
 	engine->flags = 0;
 	engine->ops = ops;
 	engine->data = data;
+	INIT_LIST_HEAD(&engine->live);
 
 	if ((ret == 0) && (list_empty(&utrace->attached))) {
 		/* First time here, set engines up */
@@ -338,8 +349,12 @@ restart:
 			goto restart;
 		}
 		engine = ERR_PTR(ret);
+	} else {
+		/* Debugging... engine leaks */
+		spin_lock(&live_lock);
+		list_add(&engine->live, &live_engines);
+		spin_unlock(&live_lock);
 	}
-
 	return engine;
 }
 EXPORT_SYMBOL_GPL(utrace_attach_task);
@@ -2431,3 +2446,85 @@ void task_utrace_proc_status(struct seq_
 		   utrace->report ? " (report)" : "",
 		   utrace->interrupt ? " (interrupt)" : "");
 }
+
+#ifdef CONFIG_DEBUG_FS
+/* Similar what's in to net/core/sock.c */
+static void *ut_eng_seq_start(struct seq_file *s, loff_t *pos)
+{
+	rcu_read_lock();
+	spin_lock(&live_lock);
+
+	return seq_list_start_head(&live_engines, *pos);
+}
+
+static void *ut_eng_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	return seq_list_next(v, &live_engines, pos);
+}
+
+static void ut_eng_seq_stop(struct seq_file *s, void *v)
+{
+	spin_unlock(&live_lock);
+	rcu_read_unlock();
+}
+
+void ut_eng_seq_printf(struct seq_file *seq,
+		struct utrace_attached_engine *engine)
+{
+	seq_printf(seq, "%p		%d\n",
+			engine, atomic_read(&engine->kref.refcount));
+}
+
+static int ut_eng_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == &live_engines)
+		seq_printf(seq, "engine			ref_cnt\n");
+	else
+		ut_eng_seq_printf(seq, list_entry(v,
+					struct utrace_attached_engine,
+					live));
+	return 0;
+}
+
+static const struct seq_operations ut_eng_seq_ops = {
+	.start = ut_eng_seq_start,
+	.next = ut_eng_seq_next,
+	.stop = ut_eng_seq_stop,
+	.show = ut_eng_seq_show
+};
+
+static int utrace_eng_open(struct inode *inode, struct file *filp)
+{
+	return seq_open(filp, &ut_eng_seq_ops);
+}
+
+struct file_operations debugfs_utrace_ops = {
+	.open		= utrace_eng_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int debugfs_utrace_init(void)
+{
+	struct dentry *dir, *file;
+
+	dir = debugfs_create_dir("utrace", NULL);
+	if (!dir) {
+		printk(KERN_INFO "Unable to create utrace dir\n");
+		return -ENOMEM;
+	}
+
+	file = debugfs_create_file("engines", 0440, dir, NULL,
+			&debugfs_utrace_ops);
+	if (!file) {
+		printk(KERN_INFO "Unable to create engines file\n");
+		debugfs_remove(dir);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+late_initcall(debugfs_utrace_init);
+
+#endif /* CONFIG_DEBUG_FS */




More information about the utrace-devel mailing list