[ltt-dev] [PATCH v4] LTTNG: Make marker enabled in advance

Gui Jianfeng guijianfeng at cn.fujitsu.com
Fri Apr 3 04:11:02 EDT 2009


Hi Mathieu,

Sorry for the later, i'm a little busy these days.

v3 -> v4 changes:
- export _is_marker_present and _is_marker_enabled
- hold markers_mutex around _is_marker_present and _is_marker_enabled
- fix a typo

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]# echo 1 > enable
[root at localhost close]# cat enable
2
[root at localhost close]# cat info
Marker Pre-enabled
[root at localhost close]# modprobe fs-trace
[root at localhost close]# cat enable
1
[root at localhost close]# cat info
Location: fs_trace
format: "fd %u"
state: 1
event_id: 0
call: 0xc0468192
probe single : 0xc0520ed8

You can also remove a marker directory by "rmdir" if there
is no actual marker backed and isn't enabled in advance. 
A channel directory can be remove if there are not any marker
directories in it.

Signed-off-by: Gui Jianfeng <guijianfeng at cn.fujitsu.com>
---
 include/linux/marker.h  |    3
 kernel/marker.c         |   75 ++++++++++++++++++-
 ltt/ltt-trace-control.c |  189 +++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 255 insertions(+), 12 deletions(-)

diff --git a/include/linux/marker.h b/include/linux/marker.h
index 2d78113..d185235 100644
--- a/include/linux/marker.h
+++ b/include/linux/marker.h
@@ -260,6 +260,9 @@ extern void marker_iter_stop(struct marker_iter *iter);
 extern void marker_iter_reset(struct marker_iter *iter);
 extern int marker_get_iter_range(struct marker **marker, struct marker *begin,
 	struct marker *end);
+extern int _is_marker_enabled(const char *channel, const char *name);
 extern int is_marker_enabled(const char *channel, const char *name);
+extern int _is_marker_present(const char *channel, const char *name);
+extern int is_marker_present(const char *channel, const char *name);
 
 #endif
diff --git a/kernel/marker.c b/kernel/marker.c
index 93ffa8e..bb35db2 100644
--- a/kernel/marker.c
+++ b/kernel/marker.c
@@ -653,22 +653,89 @@ static void disable_marker(struct marker *elem)
 }
 
 /*
- * is_marker_enabled - Check if a marker is enabled
+ * _is_marker_present - Check if a marker is present in kernel must be called
+ *                      with markers_mutex held.
+ * @channel: channel name
+ * @name: marker name
+ *
+ * Returns 1 if the marker is present, 0 if not.
+ */
+int _is_marker_present(const char *channel, const char *name)
+{
+	int ret;
+	struct marker_iter iter;
+
+	ret = 0;
+
+	marker_iter_reset(&iter);
+	marker_iter_start(&iter);
+	for (; iter.marker != NULL; marker_iter_next(&iter)) {
+		if (!strcmp(iter.marker->channel, channel) &&
+		    !strcmp(iter.marker->name, name)) {
+			ret = 1;
+			goto end;
+		}
+	}
+end:
+	marker_iter_stop(&iter);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(_is_marker_present);
+
+/*
+ * is_marker_present - the wrapper of _is_marker_present
+ * @channel: channel name
+ * @name: marker name
+ *
+ * Returns 1 if the marker is present, 0 if not.
+ */
+int is_marker_present(const char *channel, const char *name)
+{
+	int ret;
+
+	lock_markers();
+	ret = _is_marker_present(channel, name);
+	unlock_markers();
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(is_marker_present);
+
+/*
+ * _is_marker_enabled - Check if a marker is enabled, must be called with
+ *                      markers_mutex held.
  * @channel: channel name
  * @name: marker name
  *
  * Returns 1 if the marker is enabled, 0 if disabled.
  */
-int is_marker_enabled(const char *channel, const char *name)
+int _is_marker_enabled(const char *channel, const char *name)
 {
 	struct marker_entry *entry;
 
-	mutex_lock(&markers_mutex);
 	entry = get_marker(channel, name);
-	mutex_unlock(&markers_mutex);
 
 	return entry && !!entry->refcount;
 }
+EXPORT_SYMBOL_GPL(_is_marker_enabled);
+
+/*
+ * is_marker_enabled - the wrapper of _is_marker_enabled
+ * @channel: channel name
+ * @name: marker name
+ *
+ * Returns 1 if the marker is enabled, 0 if disabled.
+ */
+int is_marker_enabled(const char *channel, const char *name)
+{
+	int ret;
+
+	lock_markers();
+	ret = _is_marker_enabled(channel, name);
+	unlock_markers();
+
+	return ret;
+}
 EXPORT_SYMBOL_GPL(is_marker_enabled);
 
 /**
diff --git a/ltt/ltt-trace-control.c b/ltt/ltt-trace-control.c
index 63cbb29..35ef759 100644
--- a/ltt/ltt-trace-control.c
+++ b/ltt/ltt-trace-control.c
@@ -756,12 +756,18 @@ static const struct file_operations ltt_destroy_trace_operations = {
 	.write = destroy_trace_write,
 };
 
+static void init_marker_dir(struct dentry *dentry,
+			    const struct inode_operations *opt)
+{
+	dentry->d_inode->i_op = opt;
+}
+
 static ssize_t marker_enable_read(struct file *filp, char __user *ubuf,
 			    size_t cnt, loff_t *ppos)
 {
 	char *buf;
 	const char *channel, *marker;
-	int len;
+	int len, enabled, present;
 
 	marker = filp->f_dentry->d_parent->d_name.name;
 	channel = filp->f_dentry->d_parent->d_parent->d_name.name;
@@ -769,10 +775,21 @@ static ssize_t marker_enable_read(struct file *filp, char __user *ubuf,
 	len = 0;
 	buf = (char *)__get_free_page(GFP_KERNEL);
 
-	if (is_marker_enabled(channel, marker))
+	lock_markers();
+
+	enabled = _is_marker_enabled(channel, marker);
+	present = _is_marker_present(channel, marker);
+
+	unlock_markers();
+
+	if (enabled && present)
 		len = snprintf(buf, PAGE_SIZE, "%d\n", 1);
+	else if (enabled && !present)
+		len = snprintf(buf, PAGE_SIZE, "%d\n", 2);
 	else
 		len = snprintf(buf, PAGE_SIZE, "%d\n", 0);
+
+
 	if (len >= PAGE_SIZE) {
 		len = PAGE_SIZE;
 		buf[PAGE_SIZE] = '\0';
@@ -848,6 +865,13 @@ static ssize_t marker_info_read(struct file *filp, char __user *ubuf,
 
 	lock_markers();
 
+	if (_is_marker_enabled(channel, marker) &&
+	    !_is_marker_present(channel, marker)) {
+		len += snprintf(buf + len, PAGE_SIZE - len,
+				"Marker Pre-enabled\n");
+		goto out;
+	}
+
 	marker_iter_reset(&iter);
 	marker_iter_start(&iter);
 	for (; iter.marker != NULL; marker_iter_next(&iter)) {
@@ -874,8 +898,8 @@ static ssize_t marker_info_read(struct file *filp, char __user *ubuf,
 	}
 	marker_iter_stop(&iter);
 
+out:
 	unlock_markers();
-
 	if (len >= PAGE_SIZE) {
 		len = PAGE_SIZE;
 		buf[PAGE_SIZE] = '\0';
@@ -891,6 +915,154 @@ static const struct file_operations info_fops = {
 	.read = marker_info_read,
 };
 
+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);
+
+	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_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+	return ret;
+}
+
+static int marker_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	struct dentry *marker_d, *channel_d;
+	const char *channel, *name;
+	int ret, enabled, present;
+
+	ret = 0;
+
+	channel_d = (struct dentry *)dir->i_private;
+	channel = channel_d->d_name.name;
+
+	marker_d = dir_lookup(channel_d, dentry->d_name.name);
+
+	if (!marker_d) {
+		ret = -ENOENT;
+		goto out;
+	}
+
+	name = marker_d->d_name.name;
+
+	lock_markers();
+
+	enabled = _is_marker_enabled(channel, name);
+	present = _is_marker_present(channel, name);
+
+	unlock_markers();
+
+	if (present || (!present && enabled)) {
+		ret = -EPERM;
+		goto out;
+	}
+
+	mutex_unlock(&dir->i_mutex);
+	mutex_unlock(&dentry->d_inode->i_mutex);
+	debugfs_remove_recursive(marker_d);
+	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+	mutex_lock(&dentry->d_inode->i_mutex);
+out:
+	return ret;
+}
+
+const struct inode_operations channel_dir_opt = {
+	.lookup = simple_lookup,
+	.mkdir = marker_mkdir,
+	.rmdir = marker_rmdir,
+};
+
+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);
+
+	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_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+	return ret;
+}
+
+static int channel_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	struct dentry *channel_d;
+	int ret;
+
+	ret = 0;
+
+	channel_d = dir_lookup(markers_control_dir, dentry->d_name.name);
+	if (!channel_d) {
+		ret = -ENOENT;
+		goto out;
+	}
+
+	if (list_empty(&channel_d->d_subdirs)) {
+		mutex_unlock(&dir->i_mutex);
+		mutex_unlock(&dentry->d_inode->i_mutex);
+		debugfs_remove(channel_d);
+		mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+		mutex_lock(&dentry->d_inode->i_mutex);
+	} else
+		ret = -EPERM;
+
+out:
+	return ret;
+}
+
+const struct inode_operations root_dir_opt = {
+	.lookup = simple_lookup,
+	.mkdir = channel_mkdir,
+	.rmdir = channel_rmdir
+};
+
 static int build_marker_file(struct marker *marker)
 {
 	struct dentry *channel_d, *marker_d, *enable_d, *info_d;
@@ -907,6 +1079,8 @@ static int build_marker_file(struct marker *marker)
 			err = -ENOMEM;
 			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);
@@ -969,15 +1143,12 @@ static int build_marker_control_files(void)
 	for (; iter.marker != NULL; marker_iter_next(&iter)) {
 		err = build_marker_file(iter.marker);
 		if (err)
-			goto err_build_fail;
+			goto out;
 	}
 	marker_iter_stop(&iter);
 
+out:
 	unlock_markers();
-
-	return 0;
-
-err_build_fail:
 	return err;
 }
 
@@ -1130,6 +1301,8 @@ static int __init ltt_trace_control_init(void)
 		goto err_create_marker_control_dir;
 	}
 
+	init_marker_dir(markers_control_dir, &root_dir_opt);
+
 	if (build_marker_control_files())
 		goto err_build_fail;
 





More information about the lttng-dev mailing list