[ltt-dev] [PATCH] LTTNG: Make marker enabled in advance
Gui Jianfeng
guijianfeng at cn.fujitsu.com
Mon Mar 2 21:56:55 EST 2009
Hi Mathieu,
This patch makes marker enabled in advance.
IOW, even if the marker isn't present for the moment,
you can still enable it for future use.
As soon as the marker is inserted into kernel, tracing
work can be started immediately.
Here is an example for using the user interface:
This patch assumes the marker control patch is applied.
[root at localhost markers]# cd /mnt/debugfs/ltt/markers
[root at localhost markers]# mkdir fs
[root at localhost markers]# cd fs
[root at localhost fs]# mkdir close
[root at localhost fs]# cd close/
[root at localhost close]# ls
enable info
[root at localhost close]# echo 1 > enable
[root at localhost close]# cat enable
2
[root at localhost close]# cat info
marker is not present now!
[root at localhost close]# modprobe fs_trace
[root at localhost close]# cat enable
1
[root at localhost close]# cat info
format: "fd %u"
state: 1
event_id: 1
call: 0xc0468167
probe single : 0xc0520cdc
Signed-off-by: Gui Jianfeng <guijianfeng at cn.fujitsu.com>
---
ltt/ltt-trace-control.c | 357 ++++++++++++++++++++++++++++++++---------------
1 files changed, 247 insertions(+), 110 deletions(-)
diff --git a/ltt/ltt-trace-control.c b/ltt/ltt-trace-control.c
index 128db4e..7e1c32e 100644
--- a/ltt/ltt-trace-control.c
+++ b/ltt/ltt-trace-control.c
@@ -19,6 +19,7 @@
#include <linux/debugfs.h>
#include <linux/ltt-tracer.h>
#include <linux/notifier.h>
+#include <linux/mutex.h>
#define LTT_CONTROL_DIR "control"
#define MARKERS_CONTROL_DIR "markers"
@@ -27,9 +28,240 @@
#define LTT_WRITE_MAXLEN (128)
+#define MARKER_ENABLE_MASK 0x7UL
+
+static DEFINE_MUTEX(unload_mutex);
+
struct dentry *ltt_control_dir, *ltt_setup_trace_file, *ltt_destroy_trace_file,
*markers_control_dir;
+#define get_marker_addr(p) \
+ ((struct marker *)((unsigned long)p & ~MARKER_ENABLE_MASK))
+#define is_pre_enabled(p) ((unsigned long)p & MARKER_ENABLE_MASK)
+
+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 = get_marker_addr(filp->private_data);
+ buf = kmalloc(1024, GFP_KERNEL);
+
+ if (marker)
+ len = sprintf(buf, "%d\n", _imv_read(marker->state));
+ else {
+ if (is_pre_enabled(filp->private_data))
+ len = sprintf(buf, "%d\n", 2);
+ else
+ len = sprintf(buf, "%d\n", 0);
+ }
+ 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;
+ const char *channel_name, *marker_name;
+
+ marker = get_marker_addr(filp->private_data);
+ if (marker) {
+ marker_name = marker->name;
+ channel_name = marker->channel;
+ } else {
+ marker_name = filp->f_dentry->d_parent->d_name.name;
+ channel_name = filp->f_dentry->d_parent->d_parent->d_name.name;
+ filp->f_dentry->d_inode->i_private = (void *)1;
+ }
+
+ 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(channel_name, marker_name,
+ "default");
+ if (err)
+ return err;
+ break;
+ case 'N':
+ case 'n':
+ case '0':
+ err = ltt_marker_disconnect(channel_name,
+ 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 = get_marker_addr(filp->private_data);
+ buf = kmalloc(1024, GFP_KERNEL);
+
+ if (marker)
+ 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);
+ else
+ len = sprintf(buf, "marker is not present now!\n");
+
+ 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,
+};
+
+void init_marker_dir(struct dentry *dentry, const struct inode_operations *opt)
+{
+ dentry->d_inode->i_op = opt;
+}
+
+static int marker_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ struct dentry *marker_d, *enable_d, *info_d, *channel_d;
+ int ret;
+
+ ret = 0;
+ channel_d = (struct dentry *)dir->i_private;
+ mutex_unlock(&dir->i_mutex);
+
+ /*
+ * Prevent from removing files
+ */
+ mutex_lock(&unload_mutex);
+
+ marker_d = debugfs_create_dir(dentry->d_name.name,
+ channel_d);
+ if (IS_ERR(marker_d)) {
+ ret = PTR_ERR(marker_d);
+ goto out;
+ }
+
+ enable_d = debugfs_create_file("enable", 0644, marker_d,
+ NULL, &enable_fops);
+ if (IS_ERR(enable_d) || !enable_d) {
+ printk(KERN_ERR
+ "%s: create file of %s failed\n",
+ __func__, "enable");
+ ret = -ENOMEM;
+ goto remove_marker_dir;
+ }
+
+ info_d = debugfs_create_file("info", 0644, marker_d,
+ NULL, &info_fops);
+ if (IS_ERR(info_d) || !info_d) {
+ printk(KERN_ERR
+ "%s: create file of %s failed\n",
+ __func__, "info");
+ ret = -ENOMEM;
+ goto remove_enable_dir;
+ }
+
+ goto out;
+
+remove_enable_dir:
+ debugfs_remove(enable_d);
+remove_marker_dir:
+ debugfs_remove(marker_d);
+out:
+ mutex_unlock(&unload_mutex);
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+ return ret;
+}
+
+const struct inode_operations channel_dir_opt = {
+ .lookup = simple_lookup,
+ .mkdir = marker_mkdir,
+};
+
+static int channel_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ struct dentry *channel_d;
+ int ret;
+
+ ret = 0;
+ mutex_unlock(&dir->i_mutex);
+
+ /*
+ * Prevent from removing files
+ */
+ mutex_lock(&unload_mutex);
+
+ channel_d = debugfs_create_dir(dentry->d_name.name,
+ markers_control_dir);
+ if (IS_ERR(channel_d)) {
+ ret = PTR_ERR(channel_d);
+ goto out;
+ }
+
+ channel_d->d_inode->i_private = (void *)channel_d;
+ init_marker_dir(channel_d, &channel_dir_opt);
+
+out:
+ mutex_unlock(&unload_mutex);
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+ return ret;
+}
+
+const struct inode_operations marker_control_root_dir_opt = {
+ .lookup = simple_lookup,
+ .mkdir = channel_mkdir,
+};
+
/*
* the traces_lock nests inside control_lock.
*/
@@ -697,112 +929,6 @@ static 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;
@@ -820,8 +946,10 @@ static int build_marker_file(struct marker *marker)
goto err_build_fail;
}
}
+ channel_d->d_inode->i_private = (void *)channel_d;
+ init_marker_dir(channel_d, &channel_dir_opt);
- marker_d = dir_lookup(channel_d, marker->name);
+ 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) {
@@ -832,6 +960,7 @@ static int build_marker_file(struct marker *marker)
goto err_build_fail;
}
}
+ marker_d->d_inode->i_private = (void *)marker_d;
enable_d = dir_lookup(marker_d, "enable");
if (!enable_d) {
@@ -844,7 +973,8 @@ static int build_marker_file(struct marker *marker)
err = -ENOMEM;
goto err_build_fail;
}
- }
+ } else
+ enable_d->d_inode->i_private = (void *)marker;
info_d = dir_lookup(marker_d, "info");
if (!info_d) {
@@ -857,7 +987,8 @@ static int build_marker_file(struct marker *marker)
err = -ENOMEM;
goto err_build_fail;
}
- }
+ } else
+ info_d->d_inode->i_private = (void *)marker;
return 0;
@@ -892,6 +1023,7 @@ static int remove_marker_control_dir(struct marker *marker)
{
struct dentry *channel_d, *marker_d;
+ mutex_lock(&unload_mutex);
channel_d = dir_lookup(markers_control_dir, marker->channel);
if (!channel_d)
return -ENOENT;
@@ -904,6 +1036,7 @@ static int remove_marker_control_dir(struct marker *marker)
if (list_empty(&channel_d->d_subdirs))
debugfs_remove(channel_d);
+ mutex_unlock(&unload_mutex);
return 0;
}
@@ -1012,6 +1145,8 @@ static int __init ltt_trace_control_init(void)
goto err_create_marker_control_dir;
}
+ init_marker_dir(markers_control_dir, &marker_control_root_dir_opt);
+
if (build_marker_control_files())
goto err_build_fail;
@@ -1036,6 +1171,7 @@ static void __exit ltt_trace_control_exit(void)
{
struct dentry *trace_dir;
+ mutex_lock(&unload_mutex);
/* destory all traces */
list_for_each_entry(trace_dir, <t_control_dir->d_subdirs,
d_u.d_child) {
@@ -1046,9 +1182,10 @@ static void __exit ltt_trace_control_exit(void)
/* 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);
+ debugfs_remove_recursive(ltt_control_dir);
unregister_module_notifier(&module_nb);
+ mutex_unlock(&unload_mutex);
}
module_init(ltt_trace_control_init);
--
1.5.4.rc3
More information about the lttng-dev
mailing list