[lttng-dev] [PATCH] Create kernel events by writing to proc file

Francis Giraldeau francis.giraldeau at gmail.com
Wed May 9 13:31:28 EDT 2012


This feature allow to write events in the kernel trace stream by writing to the
file /proc/lttng_user_event. The content is written unmodified to the trace as
string type. The maximum string length saved per event is 256 bytes. The event
type and the proc file are accessibles when the module lttng-user-event is
loaded.

This is a prototype implementation. The final implementation should avoid the
temp copy of the string on the kernel stack.
---
 Makefile                                    |    1 +
 instrumentation/events/lttng-module/lttng.h |   19 +++
 probes/Makefile                             |    1 +
 probes/lttng-user-event.c                   |  159 +++++++++++++++++++++++++++
 4 files changed, 180 insertions(+), 0 deletions(-)
 create mode 100644 probes/lttng-user-event.c

diff --git a/Makefile b/Makefile
index dfa0792..6bd203d 100644
--- a/Makefile
+++ b/Makefile
@@ -24,6 +24,7 @@ lttng-tracer-objs :=  lttng-events.o lttng-abi.o \
 
 obj-m += lttng-statedump.o
 lttng-statedump-objs := lttng-statedump-impl.o wrapper/irqdesc.o
+lttng-user-event-objs := lttng-user-event.o
 
 ifneq ($(CONFIG_HAVE_SYSCALL_TRACEPOINTS),)
 lttng-tracer-objs += lttng-syscalls.o
diff --git a/instrumentation/events/lttng-module/lttng.h b/instrumentation/events/lttng-module/lttng.h
index 6f3d6d1..9da3c7e 100644
--- a/instrumentation/events/lttng-module/lttng.h
+++ b/instrumentation/events/lttng-module/lttng.h
@@ -6,6 +6,8 @@
 
 #include <linux/tracepoint.h>
 
+#define LTTNG_UEVENT_SIZE 256
+
 TRACE_EVENT(lttng_metadata,
 
 	TP_PROTO(const char *str),
@@ -28,6 +30,23 @@ TRACE_EVENT(lttng_metadata,
 	TP_printk("")
 )
 
+TRACE_EVENT(lttng_uevent,
+
+	TP_PROTO(char *str),
+
+	TP_ARGS(str),
+
+	TP_STRUCT__entry(
+		__array_text(	char,	text,	LTTNG_UEVENT_SIZE	)
+	),
+
+	TP_fast_assign(
+		tp_memcpy(text, str, LTTNG_UEVENT_SIZE)
+	),
+
+	TP_printk("text=%s", __entry->text)
+)
+
 #endif /*  _TRACE_LTTNG_H */
 
 /* This part must be outside protection */
diff --git a/probes/Makefile b/probes/Makefile
index 698a9c9..31ac769 100644
--- a/probes/Makefile
+++ b/probes/Makefile
@@ -14,6 +14,7 @@ obj-m += lttng-probe-sched.o
 obj-m += lttng-probe-irq.o
 obj-m += lttng-probe-signal.o
 obj-m += lttng-probe-timer.o
+obj-m += lttng-user-event.o
 
 obj-m += lttng-probe-statedump.o
 
diff --git a/probes/lttng-user-event.c b/probes/lttng-user-event.c
new file mode 100644
index 0000000..d3b66e6
--- /dev/null
+++ b/probes/lttng-user-event.c
@@ -0,0 +1,159 @@
+/*
+ * lttng-user-event.c
+ *
+ * Copyright (C) 2006 Mathieu Desnoyers <mathieu.desnoyers at efficios.com>
+ *
+ * 2012-05-08 Ported to lttng 2 by Francis Giraldeau
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; only
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* is there a prefered include order? */
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/highmem.h>
+#include <linux/sched.h>
+#include <linux/gfp.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/irqflags.h>
+
+#include "../instrumentation/events/lttng-module/lttng.h"
+
+DEFINE_TRACE(lttng_uevent);
+
+#define LTTNG_UEVENT_FILE	"lttng_user_event"
+
+struct proc_dir_entry *lttng_root;
+static struct proc_dir_entry *write_file;
+
+/**
+ * write_event - write a userspace string into the trace system
+ * @file: file pointer
+ * @user_buf: user string
+ * @count: length to copy, including the final NULL
+ * @ppos: unused
+ *
+ * Copy a string into a trace event "user_event". Pins pages in memory to avoid
+ * intermediate copy.
+ *
+ * On success, returns the number of bytes copied from the source.
+ *
+ * Inspired from tracing_mark_write implementation from Steven Rostedt and
+ * Ingo Molnar.
+ */
+static
+ssize_t write_event(struct file *file, const char __user *user_buf,
+		    size_t count, loff_t *fpos)
+{
+	char tmp[LTTNG_UEVENT_SIZE];
+	unsigned long addr = (unsigned long)user_buf;
+	struct page *pages[2];
+	int nr_pages = 1;
+	void *page1, *page2;
+	ssize_t written;
+	int offset, ret, len;
+
+	if (count >= LTTNG_UEVENT_SIZE)
+		count = LTTNG_UEVENT_SIZE - 1;
+
+	BUILD_BUG_ON(LTTNG_UEVENT_SIZE >= PAGE_SIZE);
+
+	if ((addr & PAGE_MASK) != ((addr + count) & PAGE_MASK))
+		nr_pages = 2;
+
+	offset = addr & (PAGE_SIZE - 1);
+	addr &= PAGE_MASK;
+
+	ret = get_user_pages_fast(addr, nr_pages, 0, pages);
+	if (ret < nr_pages) {
+		while (--ret >= 0)
+			put_page(pages[ret]);
+		written = -EFAULT;
+		goto out;
+	}
+
+	page1 = kmap_atomic(pages[0]);
+	if (nr_pages == 2)
+		page2 = kmap_atomic(pages[1]);
+
+	if (nr_pages == 2) {
+		len = PAGE_SIZE - offset;
+		memcpy(tmp, page1 + offset, len);
+		memcpy(tmp + len, page2, count - len);
+	} else
+		memcpy(tmp, page1 + offset, count);
+
+	/* make sure the string is null terminated */
+	tmp[count] = '\0';
+	trace_lttng_uevent(tmp);
+	written = count;
+
+	if (nr_pages == 2)
+		kunmap_atomic(page2);
+	kunmap_atomic(page1);
+	while (nr_pages > 0)
+		put_page(pages[--nr_pages]);
+ out:
+	return written;
+}
+
+static const struct file_operations write_file_ops = {
+	.owner = THIS_MODULE,
+	.write = write_event
+};
+
+static int __init lttng_user_event_init(void)
+{
+	int err = 0;
+
+	/* lttng is already a file with the current abi, not a directory */
+	/*
+	lttng_root = proc_mkdir("lttng", NULL);
+	if (lttng_root == NULL)
+		return -ENOMEM;
+	*/
+	write_file = create_proc_entry(LTTNG_UEVENT_FILE, 0644, lttng_root);
+	if (!write_file) {
+		err = -ENOENT;
+		goto err_procfs;
+	}
+	write_file->proc_fops = &write_file_ops;
+	write_file->mode = S_IFREG | S_IWUGO;
+	write_file->uid = 0;
+	write_file->gid = 0;
+	return err;
+
+err_procfs:
+	remove_proc_entry(LTTNG_UEVENT_FILE, lttng_root);
+	return err;
+}
+
+static void __exit lttng_user_event_exit(void)
+{
+	remove_proc_entry(LTTNG_UEVENT_FILE, lttng_root);
+	printk(KERN_INFO "/proc/%s removed\n", LTTNG_UEVENT_FILE);
+}
+
+module_init(lttng_user_event_init);
+module_exit(lttng_user_event_exit);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Francis Giraldeau <francis.giraldeau at polymtl.ca>");
+MODULE_DESCRIPTION("Append custom events to kernel trace from userspace");
-- 
1.7.5.4




More information about the lttng-dev mailing list