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

Mathieu Desnoyers mathieu.desnoyers at efficios.com
Wed May 9 14:04:24 EDT 2012


* Francis Giraldeau (francis.giraldeau at gmail.com) wrote:
> 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)

FYI, we have __string_from_user and tp_copy_string_from_user for that
(you won't have to do the copy).

> +	),
> +
> +	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 file should be GPLv2, as below one function states that it is
inspired from tracing_mark_write in the Linux kernel, which is licensed
GPLv2. Or simply reimplement write_event: it will become _trivial_ with
the proper zero-copy approach hinted at above.

> + *
> + * 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? */

nope

> +#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.

> +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);

why do you mkdir lttng ? It conflicts with /proc/lttng.

Thanks,

Mathieu

> +	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
> 
> 
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev

-- 
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com



More information about the lttng-dev mailing list