[lttng-dev] [PATCH] Expose kernel tracer to user-space

Mathieu Desnoyers mathieu.desnoyers at efficios.com
Tue Jun 26 02:40:16 EDT 2012


* Francis Giraldeau (francis.giraldeau at gmail.com) wrote:
> By writing to the file /proc/lttng, a user-space application creates a
> kernel event. The event's payload is by default UTF-8 text, but any data
> can be written, up to 1024 bytes. Null-character is optional and is not
> enforced. The event uses sequence for space efficiency and to store any
> data as payload.
> 
> Update: split the probe code into it's own module and make it an optional
> feature of lttng-abi. The feature is enabled when the module is loaded. The
> lttng-abi module exports a register function and includes a wrapper for
> lttng_fops write. This is required since struct file_operations must be const.
> Since the module dependency is reversed, unloading the lttng-uevent module is
> done only when it's not used anymore. This is done with rwlock synchronisation.
> The synchronisation doesn't prevent starvation, but this situation is unlikely
> and can be prevented by stop active tracing sessions.
> 
> Signed-off-by: Francis Giraldeau <francis.giraldeau at gmail.com>
> ---
>  instrumentation/events/lttng-module/uevent.h |   33 +++++++++++++++
>  lttng-abi.c                                  |   42 +++++++++++++++++++
>  lttng-abi.h                                  |    3 ++
>  probes/Makefile                              |    2 +
>  probes/lttng-probe-uevent.c                  |   36 ++++++++++++++++
>  probes/lttng-uevent.c                        |   58 ++++++++++++++++++++++++++
>  6 files changed, 174 insertions(+)
>  create mode 100644 instrumentation/events/lttng-module/uevent.h
>  create mode 100644 probes/lttng-probe-uevent.c
>  create mode 100644 probes/lttng-uevent.c
> 
> diff --git a/instrumentation/events/lttng-module/uevent.h b/instrumentation/events/lttng-module/uevent.h
> new file mode 100644
> index 0000000..f67d901
> --- /dev/null
> +++ b/instrumentation/events/lttng-module/uevent.h
> @@ -0,0 +1,33 @@
> +#undef TRACE_SYSTEM
> +#define TRACE_SYSTEM uevent
> +
> +#if !defined(UEVENT_H_) || defined(TRACE_HEADER_MULTI_READ)
> +#define UEVENT_H_
> +
> +#include <linux/tracepoint.h>
> +
> +TRACE_EVENT(lttng_uevent,
> +
> +	TP_PROTO(const char *str, size_t len),
> +
> +	TP_ARGS(str, len),
> +
> +	/*
> +	 * Uses sequence to hold variable size data, by default considered
> +	 * as text. Null-terminal character is optional and is not enforced.
> +	 */
> +	TP_STRUCT__entry(
> +		__dynamic_array_text(char, text, len)
> +	),
> +
> +	TP_fast_assign(
> +		tp_memcpy_dyn_from_user(text, str)
> +	),
> +
> +	TP_printk("")
> +)
> +
> +#endif /* UEVENT_H_ */
> +
> +/* This part must be outside protection */
> +#include "../../../probes/define_trace.h"
> diff --git a/lttng-abi.c b/lttng-abi.c
> index 26a02ed..b8e6b57 100644
> --- a/lttng-abi.c
> +++ b/lttng-abi.c
> @@ -51,6 +51,12 @@
>  #include "lttng-tracer.h"
>  
>  /*
> + * Required data structures to support lttng-probe-uevent
> + */
> +DEFINE_RWLOCK(uevent_rwlock);

Not required.

> +write_ops_t lttng_uevent_handler;

this should be static.

> +
> +/*
>   * This is LTTng's own personal way to create a system call as an external
>   * module. We use ioctl() on /proc/lttng.
>   */
> @@ -252,9 +258,45 @@ long lttng_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>  	}
>  }
>  
> +/*
> + * lttng_uevent_set_handler - set handler functions for uevent
> + *
> + * Access to handler code is protected with rwlock in order to
> + * prevent the optional module to be removed while in use.
> + */
> +
> +void lttng_uevent_set_handler(write_ops_t handler)
> +{
> +	write_lock(&uevent_rwlock);

write lock not necessary.

if (!lttng_uevent_set_handler)
  release refcount in prior handler's module.

then:
take a refcount on the module that contains the handler address.
(explicit)

> +	lttng_uevent_handler = handler;

Just declare the lttng_uevent_handler as "volatile".

> +	write_unlock(&uevent_rwlock);
> +}
> +EXPORT_SYMBOL_GPL(lttng_uevent_set_handler);
> +
> +/*
> + * lttng_write_uevent - expose kernel tracer to user-space
> + */
> +
> +static
> +ssize_t lttng_write_uevent(struct file *file, const char __user *ubuf,
> +		size_t count, loff_t *fpos)
> +{
> +	int ret;
> +
> +	read_lock(&uevent_rwlock);
> +	if (unlikely(lttng_uevent_handler == NULL)) {
> +		read_unlock(&uevent_rwlock);
> +		return -ENOSYS;

instead of read_lock, please do:

write_ops_t uev_handler;

uev_handler = ACCESS_ONCE(lttng_uevent_handler);
if (!uev_handler)
  return -ENOSYS;
return uev_handler(file, ubuf, count, fpos);

Thanks,

Mathieu


> +	}
> +	ret = (*lttng_uevent_handler)(file, ubuf, count, fpos);
> +	read_unlock(&uevent_rwlock);
> +	return ret;
> +}
> +
>  static const struct file_operations lttng_fops = {
>  	.owner = THIS_MODULE,

The THIS_MODULE owner protects the module that contains lttng-abi.c from
unloading when the handling is running. (keeps a refcount) However, it
does not protect the handler probe module from unloading. This is why we
need a refcount.

>  	.unlocked_ioctl = lttng_ioctl,
> +	.write = lttng_write_uevent,
>  #ifdef CONFIG_COMPAT
>  	.compat_ioctl = lttng_ioctl,
>  #endif
> diff --git a/lttng-abi.h b/lttng-abi.h
> index dc230d8..f4a8c0c 100644
> --- a/lttng-abi.h
> +++ b/lttng-abi.h
> @@ -27,6 +27,9 @@
>  
>  #define LTTNG_KERNEL_SYM_NAME_LEN	256
>  
> +typedef	ssize_t (*write_ops_t) (struct file *, const char __user *, size_t, loff_t *);
> +void lttng_uevent_set_handler(write_ops_t handler);
> +
>  enum lttng_kernel_instrumentation {
>  	LTTNG_KERNEL_TRACEPOINT	= 0,
>  	LTTNG_KERNEL_KPROBE	= 1,
> diff --git a/probes/Makefile b/probes/Makefile
> index 698a9c9..a895e60 100644
> --- a/probes/Makefile
> +++ b/probes/Makefile
> @@ -14,6 +14,8 @@ 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-probe-uevent.o
> +obj-m += lttng-uevent.o
>  
>  obj-m += lttng-probe-statedump.o
>  
> diff --git a/probes/lttng-probe-uevent.c b/probes/lttng-probe-uevent.c
> new file mode 100644
> index 0000000..90abb5e
> --- /dev/null
> +++ b/probes/lttng-probe-uevent.c
> @@ -0,0 +1,36 @@
> +/*
> + * probes/lttng-probe-uevent.c
> + *
> + * Expose kernel tracer to user-space through /proc/lttng
> + *
> + * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers at efficios.com>
> + *
> + * 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
> + */
> +
> +#include <linux/module.h>
> +
> +/*
> + * Create lttng_uevent tracepoint probes.
> + */
> +#define LTTNG_PACKAGE_BUILD
> +#define CREATE_TRACE_POINTS
> +#define TRACE_INCLUDE_PATH ../instrumentation/events/lttng-module
> +
> +#include "../instrumentation/events/lttng-module/uevent.h"
> +
> +MODULE_LICENSE("GPL and additional rights");
> +MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers at efficios.com>");
> +MODULE_DESCRIPTION("LTTng uevent probes");
> diff --git a/probes/lttng-uevent.c b/probes/lttng-uevent.c
> new file mode 100644
> index 0000000..7b4bffc
> --- /dev/null
> +++ b/probes/lttng-uevent.c
> @@ -0,0 +1,58 @@
> +/*
> + * probes/lttng-uevent.c
> + *
> + * Expose kernel tracer to user-space through /proc/lttng
> + *
> + * Copyright (C) 2012 Mathieu Desnoyers <mathieu.desnoyers at efficios.com>
> + *
> + * 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
> + */
> +
> +#include <linux/module.h>
> +#include "../lttng-abi.h"
> +
> +/* include our own uevent tracepoint */
> +#include "../instrumentation/events/lttng-module/uevent.h"
> +DEFINE_TRACE(lttng_uevent);
> +
> +#define LTTNG_UEVENT_SIZE 1024
> +
> +ssize_t uevent_write_handler(struct file *file, const char __user *ubuf,
> +		size_t count, loff_t *fpos)
> +{
> +	if (count > LTTNG_UEVENT_SIZE)
> +		count = LTTNG_UEVENT_SIZE;
> +
> +	trace_lttng_uevent(ubuf, count);
> +	return count;
> +}
> +
> +static int __init lttng_probe_uevent_init(void)
> +{
> +	lttng_uevent_set_handler(uevent_write_handler);
> +	return 0;
> +}
> +
> +static void __exit lttng_probe_uevent_exit(void)
> +{
> +	lttng_uevent_set_handler(NULL);
> +}
> +
> +module_init(lttng_probe_uevent_init);
> +module_exit(lttng_probe_uevent_exit);
> +
> +MODULE_LICENSE("GPL and additional rights");
> +MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers at efficios.com>");
> +MODULE_DESCRIPTION("LTTng kernel event from user-space");
> -- 
> 1.7.9.5
> 
> 
> _______________________________________________
> 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