All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
To: Linus Torvalds <torvalds@linux-foundation.org>,
	Ingo Molnar <mingo@elte.hu>,
	linux-kernel@vger.kernel.org,
	Andrew Morton <akpm@linux-foundation.org>,
	Steven Rostedt <rostedt@goodmis.org>,
	ltt-dev@lists.casi.polymtl.ca,
	Peter Zijlstra <peterz@infradead.org>,
	Frederic Weisbecker <fweisbec@gmail.com>,
	Arjan van de Ven <arjan@infradead.org>,
	Pekka Paalanen <pq@iki.fi>,
	Arnaldo Carvalho de Melo <acme@redhat.com>,
	"H. Peter Anvin" <hpa@zytor.com>,
	Martin Bligh <mbligh@google.com>,
	"Frank Ch. Eigler" <fche@redhat.com>,
	Tom Zanussi <tzanussi@gmail.com>,
	Masami Hiramatsu <mhiramat@redhat.com>,
	KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>,
	Jason Baron <jbaron@redhat.com>,
	Christoph Hellwig <hch@infradead.org>,
	Jiaying Zhang <jiayingz@google.com>,
	Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>,
	mrubin@google.com, md@google.com
Cc: Zhao Lei <zhaolei@cn.fujitsu.com>,
	Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Subject: [RFC patch 28/41] LTT trace control
Date: Thu, 05 Mar 2009 17:47:56 -0500	[thread overview]
Message-ID: <20090305225517.925220169@polymtl.ca> (raw)
In-Reply-To: 20090305224728.947235917@polymtl.ca

[-- Attachment #1: ltt-trace-control.patch --]
[-- Type: text/plain, Size: 25898 bytes --]

ltt-trace-control is used to control ltt's traces.
It exports the tracing control through a debugfs interface.

From: Zhao Lei <zhaolei@cn.fujitsu.com>
Signed-off-by: Zhao Lei <zhaolei@cn.fujitsu.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
---
 ltt/ltt-trace-control.c | 1061 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1061 insertions(+)
 create mode 100644 ltt/ltt-trace-control.c

Index: linux-2.6-lttng/ltt/ltt-trace-control.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/ltt/ltt-trace-control.c	2009-03-05 15:46:27.000000000 -0500
@@ -0,0 +1,1061 @@
+/*
+ * LTT trace control module over debugfs.
+ *
+ * Copyright 2008 - Zhaolei <zhaolei@cn.fujitsu.com>
+ *
+ * Copyright 2009 - Gui Jianfeng <guijianfeng@cn.fujitsu.com>
+ *                  Make mark-control work in debugfs
+ */
+
+/*
+ * Todo:
+ *   Impl read operations for control file to read attributes
+ *   Create a README file in ltt control dir, for display help info
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/ltt-tracer.h>
+#include <linux/notifier.h>
+
+#define LTT_CONTROL_DIR "control"
+#define MARKERS_CONTROL_DIR "markers"
+#define LTT_SETUP_TRACE_FILE "setup_trace"
+#define LTT_DESTROY_TRACE_FILE "destroy_trace"
+
+#define LTT_WRITE_MAXLEN	(128)
+
+struct dentry *ltt_control_dir, *ltt_setup_trace_file, *ltt_destroy_trace_file,
+	*markers_control_dir;
+
+/*
+ * the traces_lock nests inside control_lock.
+ */
+static DEFINE_MUTEX(control_lock);
+
+/*
+ * lookup a file/dir in parent dir.
+ * only designed to work well for debugfs.
+ * (although it maybe ok for other fs)
+ *
+ * return:
+ *	file/dir's dentry on success
+ *	NULL on failure
+ */
+static struct dentry *dir_lookup(struct dentry *parent, const char *name)
+{
+	struct qstr q;
+	struct dentry *d;
+
+	q.name = name;
+	q.len = strlen(name);
+	q.hash = full_name_hash(q.name, q.len);
+
+	d = d_lookup(parent, &q);
+	if (d)
+		dput(d);
+
+	return d;
+}
+
+
+static ssize_t alloc_write(struct file *file, const char __user *user_buf,
+		size_t count, loff_t *ppos)
+{
+	int err = 0;
+	char buf[NAME_MAX];
+	int buf_size;
+	char cmd[NAME_MAX];
+
+	buf_size = min(count, sizeof(buf) - 1);
+	err = copy_from_user(buf, user_buf, buf_size);
+	if (err)
+		goto err_copy_from_user;
+	buf[buf_size] = 0;
+
+	if (sscanf(buf, "%s", cmd) != 1) {
+		err = -EPERM;
+		goto err_get_cmd;
+	}
+
+	if ((cmd[0] != 'Y' && cmd[0] != 'y' && cmd[0] != '1') || cmd[1]) {
+		err = -EPERM;
+		goto err_bad_cmd;
+	}
+
+	err = ltt_trace_alloc(file->f_dentry->d_parent->d_name.name);
+	if (IS_ERR_VALUE(err)) {
+		printk(KERN_ERR "alloc_write: ltt_trace_alloc failed: %d\n",
+			err);
+		goto err_alloc_trace;
+	}
+
+	return count;
+
+err_alloc_trace:
+err_bad_cmd:
+err_get_cmd:
+err_copy_from_user:
+	return err;
+}
+
+static const struct file_operations ltt_alloc_operations = {
+	.write = alloc_write,
+};
+
+
+static ssize_t enabled_write(struct file *file, const char __user *user_buf,
+		size_t count, loff_t *ppos)
+{
+	int err = 0;
+	char buf[NAME_MAX];
+	int buf_size;
+	char cmd[NAME_MAX];
+
+	buf_size = min(count, sizeof(buf) - 1);
+	err = copy_from_user(buf, user_buf, buf_size);
+	if (err)
+		goto err_copy_from_user;
+	buf[buf_size] = 0;
+
+	if (sscanf(buf, "%s", cmd) != 1) {
+		err = -EPERM;
+		goto err_get_cmd;
+	}
+
+	if (cmd[1]) {
+		err = -EPERM;
+		goto err_bad_cmd;
+	}
+
+	switch (cmd[0]) {
+	case 'Y':
+	case 'y':
+	case '1':
+		err = ltt_trace_start(file->f_dentry->d_parent->d_name.name);
+		if (IS_ERR_VALUE(err)) {
+			printk(KERN_ERR
+				"enabled_write: ltt_trace_start failed: %d\n",
+				err);
+			err = -EPERM;
+			goto err_start_trace;
+		}
+		break;
+	case 'N':
+	case 'n':
+	case '0':
+		err = ltt_trace_stop(file->f_dentry->d_parent->d_name.name);
+		if (IS_ERR_VALUE(err)) {
+			printk(KERN_ERR
+				"enabled_write: ltt_trace_stop failed: %d\n",
+				err);
+			err = -EPERM;
+			goto err_stop_trace;
+		}
+		break;
+	default:
+		err = -EPERM;
+		goto err_bad_cmd;
+	}
+
+	return count;
+
+err_stop_trace:
+err_start_trace:
+err_bad_cmd:
+err_get_cmd:
+err_copy_from_user:
+	return err;
+}
+
+static const struct file_operations ltt_enabled_operations = {
+	.write = enabled_write,
+};
+
+
+static ssize_t trans_write(struct file *file, const char __user *user_buf,
+		size_t count, loff_t *ppos)
+{
+	int err = 0;
+	char buf[NAME_MAX];
+	int buf_size;
+	char trans_name[NAME_MAX];
+
+	buf_size = min(count, sizeof(buf) - 1);
+	err = copy_from_user(buf, user_buf, buf_size);
+	if (err)
+		goto err_copy_from_user;
+	buf[buf_size] = 0;
+
+	if (sscanf(buf, "%s", trans_name) != 1) {
+		err = -EPERM;
+		goto err_get_transname;
+	}
+
+	err = ltt_trace_set_type(file->f_dentry->d_parent->d_name.name,
+		trans_name);
+	if (IS_ERR_VALUE(err)) {
+		printk(KERN_ERR "trans_write: ltt_trace_set_type failed: %d\n",
+			err);
+		goto err_set_trans;
+	}
+
+	return count;
+
+err_set_trans:
+err_get_transname:
+err_copy_from_user:
+	return err;
+}
+
+static const struct file_operations ltt_trans_operations = {
+	.write = trans_write,
+};
+
+
+static ssize_t channel_subbuf_num_write(struct file *file,
+		const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int err = 0;
+	char buf[NAME_MAX];
+	int buf_size;
+	unsigned int num;
+	const char *channel_name;
+	const char *trace_name;
+
+	buf_size = min(count, sizeof(buf) - 1);
+	err = copy_from_user(buf, user_buf, buf_size);
+	if (err)
+		goto err_copy_from_user;
+	buf[buf_size] = 0;
+
+	if (sscanf(buf, "%u", &num) != 1) {
+		err = -EPERM;
+		goto err_get_number;
+	}
+
+	channel_name = file->f_dentry->d_parent->d_name.name;
+	trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
+
+	err = ltt_trace_set_channel_subbufcount(trace_name, channel_name, num);
+	if (IS_ERR_VALUE(err)) {
+		printk(KERN_ERR "channel_subbuf_num_write: "
+			"ltt_trace_set_channel_subbufcount failed: %d\n", err);
+		goto err_set_subbufcount;
+	}
+
+	return count;
+
+err_set_subbufcount:
+err_get_number:
+err_copy_from_user:
+	return err;
+}
+
+static const struct file_operations ltt_channel_subbuf_num_operations = {
+	.write = channel_subbuf_num_write,
+};
+
+
+static ssize_t channel_subbuf_size_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int err = 0;
+	char buf[NAME_MAX];
+	int buf_size;
+	unsigned int num;
+	const char *channel_name;
+	const char *trace_name;
+
+	buf_size = min(count, sizeof(buf) - 1);
+	err = copy_from_user(buf, user_buf, buf_size);
+	if (err)
+		goto err_copy_from_user;
+	buf[buf_size] = 0;
+
+	if (sscanf(buf, "%u", &num) != 1) {
+		err = -EPERM;
+		goto err_get_number;
+	}
+
+	channel_name = file->f_dentry->d_parent->d_name.name;
+	trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
+
+	err = ltt_trace_set_channel_subbufsize(trace_name, channel_name, num);
+	if (IS_ERR_VALUE(err)) {
+		printk(KERN_ERR "channel_subbuf_size_write: "
+		"ltt_trace_set_channel_subbufsize failed: %d\n", err);
+		goto err_set_subbufsize;
+	}
+
+	return count;
+
+err_set_subbufsize:
+err_get_number:
+err_copy_from_user:
+	return err;
+}
+
+static const struct file_operations ltt_channel_subbuf_size_operations = {
+	.write = channel_subbuf_size_write,
+};
+
+
+static ssize_t channel_overwrite_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int err = 0;
+	char buf[NAME_MAX];
+	int buf_size;
+	char cmd[NAME_MAX];
+	const char *channel_name;
+	const char *trace_name;
+
+	buf_size = min(count, sizeof(buf) - 1);
+	err = copy_from_user(buf, user_buf, buf_size);
+	if (err)
+		goto err_copy_from_user;
+	buf[buf_size] = 0;
+
+	if (sscanf(buf, "%s", cmd) != 1) {
+		err = -EPERM;
+		goto err_get_cmd;
+	}
+
+	if (cmd[1]) {
+		err = -EPERM;
+		goto err_bad_cmd;
+	}
+
+	channel_name = file->f_dentry->d_parent->d_name.name;
+	trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
+
+	switch (cmd[0]) {
+	case 'Y':
+	case 'y':
+	case '1':
+		err = ltt_trace_set_channel_overwrite(trace_name, channel_name,
+			1);
+		if (IS_ERR_VALUE(err)) {
+			printk(KERN_ERR "channel_overwrite_write: "
+			"ltt_trace_set_channel_overwrite failed: %d\n", err);
+			goto err_set_subbufsize;
+		}
+		break;
+	case 'N':
+	case 'n':
+	case '0':
+		err = ltt_trace_set_channel_overwrite(trace_name, channel_name,
+			0);
+		if (IS_ERR_VALUE(err)) {
+			printk(KERN_ERR "channel_overwrite_write: "
+			"ltt_trace_set_channel_overwrite failed: %d\n", err);
+			goto err_set_subbufsize;
+		}
+		break;
+	default:
+		err = -EPERM;
+		goto err_bad_cmd;
+	}
+
+	return count;
+
+err_set_subbufsize:
+err_bad_cmd:
+err_get_cmd:
+err_copy_from_user:
+	return err;
+}
+
+static const struct file_operations ltt_channel_overwrite_operations = {
+	.write = channel_overwrite_write,
+};
+
+
+static ssize_t channel_enable_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int err = 0;
+	char buf[NAME_MAX];
+	int buf_size;
+	char cmd[NAME_MAX];
+	const char *channel_name;
+	const char *trace_name;
+
+	buf_size = min(count, sizeof(buf) - 1);
+	err = copy_from_user(buf, user_buf, buf_size);
+	if (err)
+		goto err_copy_from_user;
+	buf[buf_size] = 0;
+
+	if (sscanf(buf, "%s", cmd) != 1) {
+		err = -EPERM;
+		goto err_get_cmd;
+	}
+
+	if (cmd[1]) {
+		err = -EPERM;
+		goto err_bad_cmd;
+	}
+
+	channel_name = file->f_dentry->d_parent->d_name.name;
+	trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
+
+	switch (cmd[0]) {
+	case 'Y':
+	case 'y':
+	case '1':
+		err = ltt_trace_set_channel_enable(trace_name, channel_name,
+			1);
+		if (IS_ERR_VALUE(err)) {
+			printk(KERN_ERR "channel_enable_write: "
+			"ltt_trace_set_channel_enable failed: %d\n", err);
+			goto err_set_subbufsize;
+		}
+		break;
+	case 'N':
+	case 'n':
+	case '0':
+		err = ltt_trace_set_channel_enable(trace_name, channel_name,
+			0);
+		if (IS_ERR_VALUE(err)) {
+			printk(KERN_ERR "channel_enable_write: "
+			"ltt_trace_set_channel_enable failed: %d\n", err);
+			goto err_set_subbufsize;
+		}
+		break;
+	default:
+		err = -EPERM;
+		goto err_bad_cmd;
+	}
+
+	return count;
+
+err_set_subbufsize:
+err_bad_cmd:
+err_get_cmd:
+err_copy_from_user:
+	return err;
+}
+
+static const struct file_operations ltt_channel_enable_operations = {
+	.write = channel_enable_write,
+};
+
+
+static int _create_trace_control_dir(const char *trace_name,
+				     struct ltt_trace_struct *trace)
+{
+	int err;
+	struct dentry *trace_root, *channel_root;
+	struct dentry *tmp_den;
+	int i;
+
+	/* debugfs/control/trace_name */
+	trace_root = debugfs_create_dir(trace_name, ltt_control_dir);
+	if (IS_ERR(trace_root) || !trace_root) {
+		printk(KERN_ERR "_create_trace_control_dir: "
+			"create control root dir of %s failed\n", trace_name);
+		err = -ENOMEM;
+		goto err_create_trace_root;
+	}
+
+	/* debugfs/control/trace_name/alloc */
+	tmp_den = debugfs_create_file("alloc", S_IWUSR, trace_root, NULL,
+		&ltt_alloc_operations);
+	if (IS_ERR(tmp_den) || !tmp_den) {
+		printk(KERN_ERR "_create_trace_control_dir: "
+			"create file of alloc failed\n");
+		err = -ENOMEM;
+		goto err_create_subdir;
+	}
+
+	/* debugfs/control/trace_name/trans */
+	tmp_den = debugfs_create_file("trans", S_IWUSR, trace_root, NULL,
+		&ltt_trans_operations);
+	if (IS_ERR(tmp_den) || !tmp_den) {
+		printk(KERN_ERR "_create_trace_control_dir: "
+			"create file of trans failed\n");
+		err = -ENOMEM;
+		goto err_create_subdir;
+	}
+
+	/* debugfs/control/trace_name/enabled */
+	tmp_den = debugfs_create_file("enabled", S_IWUSR, trace_root, NULL,
+		&ltt_enabled_operations);
+	if (IS_ERR(tmp_den) || !tmp_den) {
+		printk(KERN_ERR "_create_trace_control_dir: "
+			"create file of enabled failed\n");
+		err = -ENOMEM;
+		goto err_create_subdir;
+	}
+
+	/* debugfs/control/trace_name/channel/ */
+	channel_root = debugfs_create_dir("channel", trace_root);
+	if (IS_ERR(channel_root) || !channel_root) {
+		printk(KERN_ERR "_create_trace_control_dir: "
+			"create dir of channel failed\n");
+		err = -ENOMEM;
+		goto err_create_subdir;
+	}
+
+	/*
+	 * Create dir and files in debugfs/ltt/control/trace_name/channel/
+	 * Following things(without <>) will be created:
+	 * `-- <control>
+	 *     `-- <trace_name>
+	 *         `-- <channel>
+	 *             |-- <channel_name>
+	 *             |   |-- enable
+	 *             |   |-- overwrite
+	 *             |   |-- subbuf_num
+	 *             |   `-- subbuf_size
+	 *             `-- ...
+	 */
+
+	for (i = 0; i < trace->nr_channels; i++) {
+		struct dentry *channel_den;
+		struct ltt_channel_struct *channel;
+
+		channel = &trace->channels[i];
+		if (!channel->active)
+			continue;
+		channel_den = debugfs_create_dir(channel->channel_name,
+						 channel_root);
+		if (IS_ERR(channel_den) || !channel_den) {
+			printk(KERN_ERR "_create_trace_control_dir: "
+				"create channel dir of %s failed\n",
+				channel->channel_name);
+			err = -ENOMEM;
+			goto err_create_subdir;
+		}
+
+		tmp_den = debugfs_create_file("subbuf_num", S_IWUSR,
+			channel_den, NULL, &ltt_channel_subbuf_num_operations);
+		if (IS_ERR(tmp_den) || !tmp_den) {
+			printk(KERN_ERR "_create_trace_control_dir: "
+				"create subbuf_num in %s failed\n",
+				channel->channel_name);
+			err = -ENOMEM;
+			goto err_create_subdir;
+		}
+
+		tmp_den = debugfs_create_file("subbuf_size", S_IWUSR,
+			channel_den, NULL, &ltt_channel_subbuf_size_operations);
+		if (IS_ERR(tmp_den) || !tmp_den) {
+			printk(KERN_ERR "_create_trace_control_dir: "
+				"create subbuf_size in %s failed\n",
+				channel->channel_name);
+			err = -ENOMEM;
+			goto err_create_subdir;
+		}
+
+		tmp_den = debugfs_create_file("enable", S_IWUSR, channel_den,
+			NULL, &ltt_channel_enable_operations);
+		if (IS_ERR(tmp_den) || !tmp_den) {
+			printk(KERN_ERR "_create_trace_control_dir: "
+				"create enable in %s failed\n",
+				channel->channel_name);
+			err = -ENOMEM;
+			goto err_create_subdir;
+		}
+
+		tmp_den = debugfs_create_file("overwrite", S_IWUSR, channel_den,
+			NULL, &ltt_channel_overwrite_operations);
+		if (IS_ERR(tmp_den) || !tmp_den) {
+			printk(KERN_ERR "_create_trace_control_dir: "
+				"create overwrite in %s failed\n",
+				channel->channel_name);
+			err = -ENOMEM;
+			goto err_create_subdir;
+		}
+	}
+
+	return 0;
+
+err_create_subdir:
+	debugfs_remove_recursive(trace_root);
+err_create_trace_root:
+	return err;
+}
+
+static ssize_t setup_trace_write(struct file *file, const char __user *user_buf,
+		size_t count, loff_t *ppos)
+{
+	int err = 0;
+	char buf[NAME_MAX];
+	int buf_size;
+	char trace_name[NAME_MAX];
+	struct ltt_trace_struct *trace;
+
+	buf_size = min(count, sizeof(buf) - 1);
+	err = copy_from_user(buf, user_buf, buf_size);
+	if (err)
+		goto err_copy_from_user;
+	buf[buf_size] = 0;
+
+	if (sscanf(buf, "%s", trace_name) != 1) {
+		err = -EPERM;
+		goto err_get_tracename;
+	}
+
+	mutex_lock(&control_lock);
+	ltt_lock_traces();
+
+	err = _ltt_trace_setup(trace_name);
+	if (IS_ERR_VALUE(err)) {
+		printk(KERN_ERR
+			"setup_trace_write: ltt_trace_setup failed: %d\n", err);
+		goto err_setup_trace;
+	}
+	trace = _ltt_trace_find_setup(trace_name);
+	BUG_ON(!trace);
+	err = _create_trace_control_dir(trace_name, trace);
+	if (IS_ERR_VALUE(err)) {
+		printk(KERN_ERR "setup_trace_write: "
+			"_create_trace_control_dir failed: %d\n", err);
+		goto err_create_trace_control_dir;
+	}
+
+	ltt_unlock_traces();
+	mutex_unlock(&control_lock);
+
+	return count;
+
+err_create_trace_control_dir:
+	ltt_trace_destroy(trace_name);
+err_setup_trace:
+	ltt_unlock_traces();
+	mutex_unlock(&control_lock);
+err_get_tracename:
+err_copy_from_user:
+	return err;
+}
+
+static const struct file_operations ltt_setup_trace_operations = {
+	.write = setup_trace_write,
+};
+
+static ssize_t destroy_trace_write(struct file *file,
+		const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int err = 0;
+	char buf[NAME_MAX];
+	int buf_size;
+	char trace_name[NAME_MAX];
+	struct dentry *trace_den;
+
+
+	buf_size = min(count, sizeof(buf) - 1);
+	err = copy_from_user(buf, user_buf, buf_size);
+	if (err)
+		goto err_copy_from_user;
+	buf[buf_size] = 0;
+
+	if (sscanf(buf, "%s", trace_name) != 1) {
+		err = -EPERM;
+		goto err_get_tracename;
+	}
+
+	mutex_lock(&control_lock);
+
+	err = ltt_trace_destroy(trace_name);
+	if (IS_ERR_VALUE(err)) {
+		printk(KERN_ERR
+			"destroy_trace_write: ltt_trace_destroy failed: %d\n",
+			err);
+		err = -EPERM;
+		goto err_destroy_trace;
+	}
+
+	trace_den = dir_lookup(ltt_control_dir, trace_name);
+	if (!trace_den) {
+		printk(KERN_ERR
+			"destroy_trace_write: lookup for %s's dentry failed\n",
+			trace_name);
+		err = -ENOENT;
+		goto err_get_dentry;
+	}
+
+	debugfs_remove_recursive(trace_den);
+
+	mutex_unlock(&control_lock);
+
+	return count;
+
+err_get_dentry:
+err_destroy_trace:
+	mutex_unlock(&control_lock);
+err_get_tracename:
+err_copy_from_user:
+	return err;
+}
+
+static const struct file_operations ltt_destroy_trace_operations = {
+	.write = destroy_trace_write,
+};
+
+static int marker_enable_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t marker_enable_read(struct file *filp, char __user *ubuf,
+			    size_t cnt, loff_t *ppos)
+{
+	struct marker *marker;
+	char *buf;
+	int len;
+
+	marker = (struct marker *)filp->private_data;
+	buf = kmalloc(1024, GFP_KERNEL);
+
+	len = sprintf(buf, "%d\n", _imv_read(marker->state));
+
+	len = simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
+	kfree(buf);
+
+	return len;
+}
+
+static ssize_t marker_enable_write(struct file *filp, const char __user *ubuf,
+				size_t cnt, loff_t *ppos)
+{
+	char buf[NAME_MAX];
+	int buf_size;
+	int err = 0;
+	struct marker *marker;
+
+	marker = (struct marker *)filp->private_data;
+	buf_size = min(cnt, sizeof(buf) - 1);
+	err = copy_from_user(buf, ubuf, buf_size);
+	if (err)
+		return err;
+
+	buf[buf_size] = 0;
+
+	switch (buf[0]) {
+	case 'Y':
+	case 'y':
+	case '1':
+		err = ltt_marker_connect(marker->channel, marker->name,
+					 "default");
+		if (err)
+			return err;
+		break;
+	case 'N':
+	case 'n':
+	case '0':
+		err = ltt_marker_disconnect(marker->channel, marker->name,
+					    "default");
+		if (err)
+			return err;
+		break;
+	default:
+		return -EPERM;
+	}
+
+	return cnt;
+}
+
+static const struct file_operations enable_fops = {
+	.open = marker_enable_open,
+	.read = marker_enable_read,
+	.write = marker_enable_write,
+};
+
+static int marker_info_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t marker_info_read(struct file *filp, char __user *ubuf,
+			    size_t cnt, loff_t *ppos)
+{
+	struct marker *marker;
+	char *buf;
+	int len;
+
+	marker = (struct marker *)filp->private_data;
+	buf = kmalloc(1024, GFP_KERNEL);
+
+	len = sprintf(buf, "format: \"%s\"\nstate: %d\n"
+		      "event_id: %hu\n"
+		      "call: 0x%p\n"
+		      "probe %s : 0x%p\n",
+		      marker->format, _imv_read(marker->state),
+		      marker->event_id, marker->call, marker->ptype ?
+		      "multi" : "single", marker->ptype ?
+		      (void *)marker->multi : (void *)marker->single.func);
+
+	len = simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
+	kfree(buf);
+
+	return len;
+}
+
+static const struct file_operations info_fops = {
+	.open = marker_info_open,
+	.read = marker_info_read,
+};
+
+static int build_marker_file(struct marker *marker)
+{
+	struct dentry *channel_d, *marker_d, *enable_d, *info_d;
+	int err;
+
+	channel_d = dir_lookup(markers_control_dir, marker->channel);
+	if (!channel_d) {
+		channel_d = debugfs_create_dir(marker->channel,
+					       markers_control_dir);
+		if (IS_ERR(channel_d) || !channel_d) {
+			printk(KERN_ERR
+			       "%s: build channel dir of %s failed\n",
+			       __func__, marker->channel);
+			err = -ENOMEM;
+			goto err_build_fail;
+		}
+	}
+
+	marker_d  = dir_lookup(channel_d, marker->name);
+	if (!marker_d) {
+		marker_d = debugfs_create_dir(marker->name, channel_d);
+		if (IS_ERR(marker_d) || !marker_d) {
+			printk(KERN_ERR
+			       "%s: marker dir of %s failed\n",
+			       __func__, marker->name);
+			err = -ENOMEM;
+			goto err_build_fail;
+		}
+	}
+
+	enable_d = dir_lookup(marker_d, "enable");
+	if (!enable_d) {
+		enable_d = debugfs_create_file("enable", 0644, marker_d,
+						marker, &enable_fops);
+		if (IS_ERR(enable_d) || !enable_d) {
+			printk(KERN_ERR
+			       "%s: create file of %s failed\n",
+			       __func__, "enable");
+			err = -ENOMEM;
+			goto err_build_fail;
+		}
+	}
+
+	info_d = dir_lookup(marker_d, "info");
+	if (!info_d) {
+		info_d = debugfs_create_file("info", 0444, marker_d,
+						marker, &info_fops);
+		if (IS_ERR(info_d) || !info_d) {
+			printk(KERN_ERR
+			       "%s: create file of %s failed\n",
+			       __func__, "enable");
+			err = -ENOMEM;
+			goto err_build_fail;
+		}
+	}
+
+	return 0;
+
+err_build_fail:
+	return err;
+}
+
+static int build_marker_control_files(void)
+{
+	struct marker_iter iter;
+	int err;
+
+	err = 0;
+	if (!markers_control_dir)
+		return -EEXIST;
+
+	marker_iter_reset(&iter);
+	marker_iter_start(&iter);
+	for (; iter.marker != NULL; marker_iter_next(&iter)) {
+		err = build_marker_file(iter.marker);
+		if (err)
+			goto err_build_fail;
+	}
+	marker_iter_stop(&iter);
+	return 0;
+
+err_build_fail:
+	return err;
+}
+
+static int remove_marker_control_dir(struct marker *marker)
+{
+	struct dentry *channel_d, *marker_d;
+
+	channel_d = dir_lookup(markers_control_dir, marker->channel);
+	if (!channel_d)
+		return -ENOENT;
+
+	marker_d = dir_lookup(channel_d, marker->name);
+	if (!marker_d)
+		return -ENOENT;
+
+	debugfs_remove_recursive(marker_d);
+	if (list_empty(&channel_d->d_subdirs))
+		debugfs_remove(channel_d);
+
+	return 0;
+}
+
+static void cleanup_control_dir(struct marker *begin, struct marker *end)
+{
+	struct marker *iter;
+
+	if (!markers_control_dir)
+		return;
+
+	for (iter = begin; iter < end; iter++)
+		remove_marker_control_dir(iter);
+
+	return;
+}
+
+static void build_control_dir(struct marker *begin, struct marker *end)
+{
+	struct marker *iter;
+	int err;
+
+	err = 0;
+	if (!markers_control_dir)
+		return;
+
+	for (iter = begin; iter < end; iter++) {
+		err = build_marker_file(iter);
+		if (err)
+			goto err_build_fail;
+	}
+
+	return;
+err_build_fail:
+	cleanup_control_dir(begin, end);
+}
+
+static int module_notify(struct notifier_block *self,
+		  unsigned long val, void *data)
+{
+	struct module *mod = data;
+
+	switch (val) {
+	case MODULE_STATE_COMING:
+		build_control_dir(mod->markers,
+				  mod->markers + mod->num_markers);
+		break;
+	case MODULE_STATE_GOING:
+		cleanup_control_dir(mod->markers,
+				    mod->markers + mod->num_markers);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block module_nb = {
+	.notifier_call = module_notify,
+};
+
+static int __init ltt_trace_control_init(void)
+{
+	int err = 0;
+	struct dentry *ltt_root_dentry;
+
+	ltt_root_dentry = get_ltt_root();
+	if (!ltt_root_dentry) {
+		err = -ENOENT;
+		goto err_no_root;
+	}
+
+	ltt_control_dir = debugfs_create_dir(LTT_CONTROL_DIR, ltt_root_dentry);
+	if (IS_ERR(ltt_control_dir) || !ltt_control_dir) {
+		printk(KERN_ERR
+			"ltt_channel_control_init: create dir of %s failed\n",
+			LTT_CONTROL_DIR);
+		err = -ENOMEM;
+		goto err_create_control_dir;
+	}
+
+	ltt_setup_trace_file = debugfs_create_file(LTT_SETUP_TRACE_FILE,
+		S_IWUSR, ltt_root_dentry, NULL, &ltt_setup_trace_operations);
+	if (IS_ERR(ltt_setup_trace_file) || !ltt_setup_trace_file) {
+		printk(KERN_ERR
+			"ltt_channel_control_init: create file of %s failed\n",
+			LTT_SETUP_TRACE_FILE);
+		err = -ENOMEM;
+		goto err_create_setup_trace_file;
+	}
+
+	ltt_destroy_trace_file = debugfs_create_file(LTT_DESTROY_TRACE_FILE,
+		S_IWUSR, ltt_root_dentry, NULL, &ltt_destroy_trace_operations);
+	if (IS_ERR(ltt_destroy_trace_file) || !ltt_destroy_trace_file) {
+		printk(KERN_ERR
+			"ltt_channel_control_init: create file of %s failed\n",
+			LTT_DESTROY_TRACE_FILE);
+		err = -ENOMEM;
+		goto err_create_destroy_trace_file;
+	}
+
+	markers_control_dir = debugfs_create_dir(MARKERS_CONTROL_DIR,
+						 ltt_root_dentry);
+	if (IS_ERR(markers_control_dir) || !markers_control_dir) {
+		printk(KERN_ERR
+			"ltt_channel_control_init: create dir of %s failed\n",
+			MARKERS_CONTROL_DIR);
+		err = -ENOMEM;
+		goto err_create_marker_control_dir;
+	}
+
+	if (build_marker_control_files())
+		goto err_build_fail;
+
+	if (!register_module_notifier(&module_nb))
+		return 0;
+
+err_build_fail:
+	debugfs_remove_recursive(markers_control_dir);
+	markers_control_dir = NULL;
+err_create_marker_control_dir:
+	debugfs_remove(ltt_destroy_trace_file);
+err_create_destroy_trace_file:
+	debugfs_remove(ltt_setup_trace_file);
+err_create_setup_trace_file:
+	debugfs_remove(ltt_control_dir);
+err_create_control_dir:
+err_no_root:
+	return err;
+}
+
+static void __exit ltt_trace_control_exit(void)
+{
+	struct dentry *trace_dir;
+
+	/* destory all traces */
+	list_for_each_entry(trace_dir, &ltt_control_dir->d_subdirs,
+		d_u.d_child) {
+		ltt_trace_stop(trace_dir->d_name.name);
+		ltt_trace_destroy(trace_dir->d_name.name);
+	}
+
+	/* clean dirs in debugfs */
+	debugfs_remove(ltt_setup_trace_file);
+	debugfs_remove(ltt_destroy_trace_file);
+	debugfs_remove_recursive(ltt_control_dir);
+	debugfs_remove_recursive(markers_control_dir);
+	unregister_module_notifier(&module_nb);
+	put_ltt_root();
+}
+
+module_init(ltt_trace_control_init);
+module_exit(ltt_trace_control_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Zhao Lei <zhaolei@cn.fujitsu.com>");
+MODULE_DESCRIPTION("Linux Trace Toolkit Trace Controller");
+

-- 
Mathieu Desnoyers
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68

  parent reply	other threads:[~2009-03-05 23:35 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-03-05 22:47 [RFC patch 00/41] LTTng 0.105 core for Linux 2.6.27-rc9 Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 01/41] LTTng - core header Mathieu Desnoyers
2009-03-06 18:37   ` Steven Rostedt
2009-03-05 22:47 ` [RFC patch 02/41] LTTng - core data structures Mathieu Desnoyers
2009-03-06 18:41   ` Steven Rostedt
2009-03-05 22:47 ` [RFC patch 03/41] LTTng core x86 Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 04/41] LTTng core powerpc Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 05/41] LTTng relay buffer allocation, read, write Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 06/41] LTTng optimize write to page function Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 07/41] LTTng dynamic channels Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 08/41] LTTng - tracer header Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 09/41] LTTng optimize write to page function deal with unaligned access Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 10/41] lttng-optimize-write-to-page-function-remove-some-memcpy-calls Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 11/41] ltt-relay: cache pages address Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 12/41] x86 : export vmalloc_sync_all() Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 13/41] LTTng - tracer code Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 14/41] Splice and pipe : export pipe buf operations for GPL modules Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 15/41] Poll : add poll_wait_set_exclusive Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 16/41] LTTng Transport Locked Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 17/41] LTTng - serialization Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 18/41] Seq_file add support for sorted list Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 19/41] Sort module list by pointer address to get coherent sleepable seq_file iterators Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 20/41] Linux Kernel Markers - Iterator Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 21/41] LTTng probes specialized tracepoints Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 22/41] LTTng marker control Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 23/41] Immediate Values Stub header Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 24/41] Linux Kernel Markers - Use Immediate Values Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 25/41] Markers Support for Proprierary Modules Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 26/41] Marers remove old comment Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 27/41] Markers use dynamic channels Mathieu Desnoyers
2009-03-05 22:47 ` Mathieu Desnoyers [this message]
2009-03-05 22:47 ` [RFC patch 29/41] LTTng menus Mathieu Desnoyers
2009-03-05 23:35   ` Randy Dunlap
2009-03-05 23:47     ` Mathieu Desnoyers
2009-03-05 23:51       ` Randy Dunlap
2009-03-06  0:01         ` [ltt-dev] " Mathieu Desnoyers
2009-03-06  0:12           ` Randy Dunlap
2009-03-05 22:47 ` [RFC patch 30/41] LTTng build Mathieu Desnoyers
2009-03-05 22:47 ` [RFC patch 31/41] LTTng userspace event v2 Mathieu Desnoyers
2009-03-05 22:48 ` [RFC patch 32/41] LTTng filter Mathieu Desnoyers
2009-03-05 22:48 ` [RFC patch 33/41] LTTng dynamic tracing support with kprobes Mathieu Desnoyers
2009-03-05 22:48 ` [RFC patch 34/41] Marker header API update Mathieu Desnoyers
2009-03-05 22:48 ` [RFC patch 35/41] Marker " Mathieu Desnoyers
2009-03-05 22:48 ` [RFC patch 36/41] kvm markers " Mathieu Desnoyers
2009-03-05 22:48 ` [RFC patch 37/41] Markers : multi-probes test Mathieu Desnoyers
2009-03-05 22:48 ` [RFC patch 38/41] Markers examples API update Mathieu Desnoyers
2009-03-05 22:48 ` [RFC patch 39/41] SPUFS markers " Mathieu Desnoyers
2009-03-05 22:48 ` [RFC patch 40/41] EXT4: instrumentation with tracepoints Mathieu Desnoyers
2009-03-05 22:48   ` Mathieu Desnoyers
2009-03-05 22:48 ` [RFC patch 41/41] JBD2: use tracepoints for instrumentation Mathieu Desnoyers
2009-03-05 22:48   ` Mathieu Desnoyers
2009-03-06 10:11 ` [RFC patch 00/41] LTTng 0.105 core for Linux 2.6.27-rc9 Ingo Molnar
2009-03-06 19:02   ` Mathieu Desnoyers
2009-03-11 18:32     ` Ingo Molnar
2009-03-13 16:18       ` Mathieu Desnoyers
2009-03-14 16:43         ` Ingo Molnar
2009-03-14 16:59           ` [ltt-dev] " Mathieu Desnoyers
2009-03-06 18:34 ` Steven Rostedt
2009-03-06 19:01   ` Frederic Weisbecker

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=20090305225517.925220169@polymtl.ca \
    --to=mathieu.desnoyers@polymtl.ca \
    --cc=acme@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=arjan@infradead.org \
    --cc=eduard.munteanu@linux360.ro \
    --cc=fche@redhat.com \
    --cc=fweisbec@gmail.com \
    --cc=hch@infradead.org \
    --cc=hpa@zytor.com \
    --cc=jbaron@redhat.com \
    --cc=jiayingz@google.com \
    --cc=kosaki.motohiro@jp.fujitsu.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ltt-dev@lists.casi.polymtl.ca \
    --cc=mbligh@google.com \
    --cc=md@google.com \
    --cc=mhiramat@redhat.com \
    --cc=mingo@elte.hu \
    --cc=mrubin@google.com \
    --cc=peterz@infradead.org \
    --cc=pq@iki.fi \
    --cc=rostedt@goodmis.org \
    --cc=torvalds@linux-foundation.org \
    --cc=tzanussi@gmail.com \
    --cc=zhaolei@cn.fujitsu.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.