From baf2099544522f85e52c830b13aa45601ff15204 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 23 Nov 2010 22:39:08 -0500 Subject: [PATCH] debugfs ABI in progress Signed-off-by: Mathieu Desnoyers --- ltt-debugfs-abi.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++ ltt-events.c | 36 +++++---- ltt-events.h | 10 ++- 3 files changed, 218 insertions(+), 16 deletions(-) create mode 100644 ltt-debugfs-abi.c diff --git a/ltt-debugfs-abi.c b/ltt-debugfs-abi.c new file mode 100644 index 00000000..7ee2eca5 --- /dev/null +++ b/ltt-debugfs-abi.c @@ -0,0 +1,188 @@ +/* + * ltt-debugfs-abi.c + * + * Copyright 2010 (c) - Mathieu Desnoyers + * + * LTTng debugfs ABI + * + * Mimic system calls for: + * - session creation, returns a file descriptor or failure. + * - channel creation, returns a file descriptor or failure. + * - Takes a session file descriptor parameter + * - Takes all channel options as parameters. + * - event creation, returns a file descriptor or failure. + * - Takes an event name as parameter + * - Takes an instrumentation source as parameter + * - e.g. tracepoints, dynamic_probes... + * - Takes instrumentation source specific arguments. + */ + +#include + +/* + * This is LTTng's own personal way to create a system call as an external + * module. We use ioctl() on /sys/kernel/debug/lttng. + */ + +static struct dentry *lttng_dentry; + +/* + * LTTng DebugFS ABI structures. + */ + +struct lttng_channel { + int session; /* Session file descriptor */ + int overwrite; /* 1: overwrite, 0: discard */ + u64 subbuf_size; + u64 num_subbuf; + unsigned int switch_timer_interval; + unsigned int read_timer_interval; +}; + +struct lttng_event { + int channel; /* Channel file descriptor */ + enum instrum_type itype; + char name[]; +}; + +int lttng_abi_create_session(void) +{ + struct ltt_session *session; + struct file *session_file; + int session_fd; + + session = ltt_session_create() + if (!session) + return -ENOMEM; + session_fd = get_unused_fd_flags(O_RDWR); + if (session_fd < 0) { + ret = session_fd; + goto fd_error; + } + session_file = anon_inode_getfile("[lttng_session]", + <tng_fops, + session, O_RDWR); + if (IS_ERR(session_file)) { + ret = PTR_ERR(session_file); + goto file_error; + } + return session_fd; + +file_error: + put_unused_fd(session_fd); +fd_error: + ltt_session_destroy(session); + return ret; +} + +int lttng_abi_create_channel(struct lttng_channel __user *uchan_param) +{ + struct ltt_channel *chan; + struct file *chan_file; + struct lttng_channel chan_param; + int chan_fd; + + if (copy_from_user(&chan_param, ucham_param, sizeof(chan_param))) + return -EFAULT; + /* TODO: fetch session pointer from file descriptor */ + chan = ltt_channel_create(); + if (!chan) + return -ENOMEM; + chan_fd = get_unused_fd_flags(O_RDWR); + if (chan_fd < 0) { + ret = chan_fd; + goto fd_error; + } + chan_file = anon_inode_getfile("[lttng_channel]", + <tng_fops, + chan, O_RDWR); + if (IS_ERR(chan_file)) { + ret = PTR_ERR(chan_file); + goto file_error; + } + return chan_fd; + +file_error: + put_unused_fd(chan_fd); +fd_error: + ltt_channel_destroy(chan); + return ret; +} + +/** + * lttng_ioctl - lttng syscall through ioctl + * + * @filp: the file + * @cmd: the command + * @arg: command arg + * + * This ioctl implements lttng commands: + * LTTNG_SESSION + * Returns a LTTng trace session file descriptor + * LTTNG_CHANNEL + * Returns a LTTng channel file descriptor + * LTTNG_EVENT + * Returns a file descriptor or failure. + * + * The returned session will be deleted when its file descriptor is closed. + * Channel and event file descriptors also hold a reference on the session. + */ +long lttng_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = filp->f_dentry->d_inode; + + switch (cmd) { + case LTTNG_SESSION: + return lttng_abi_create_session(); + case LTTNG_CHANNEL: + return lttng_abi_create_channel((struct lttng_channel __user *)arg); + case LTTNG_EVENT: + return lttng_abi_create_event((struct lttng_event __user *)arg); + default: + return -ENOIOCTLCMD; + } +} + +#ifdef CONFIG_COMPAT +long lttng_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = filp->f_dentry->d_inode; + + switch (cmd) { + case LTTNG_SESSION: + return lttng_abi_create_session(); + case LTTNG_CHANNEL: + return lttng_abi_create_channel((struct lttng_channel __user *)arg); + case LTTNG_EVENT: + return lttng_abi_create_event((struct lttng_event __user *)arg); + default: + return -ENOIOCTLCMD; + } +} +#endif + +const struct file_operations lttng_file_operations = { + .unlocked_ioctl = lttng_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = lttng_compat_ioctl, +#endif +} + +static int __init ltt_debugfs_abi_init(void) +{ + int ret = 0; + + lttng_dentry = debugfs_create_file("lttng", NULL); + if (IS_ERR(lttng_dentry) || !lttng_dentry) + printk(KERN_ERR "Error creating LTTng control file\n"); + ret = -ENOMEM; + goto error; + } +error: + return ret; +} + +static void __exit ltt_debugfs_abi_exit(void) +{ + debugfs_remote(lttng_dentry); +} diff --git a/ltt-events.c b/ltt-events.c index 21c6d29e..f22351fc 100644 --- a/ltt-events.c +++ b/ltt-events.c @@ -21,18 +21,14 @@ static void synchronize_trace(void) #endif } -struct ltt_session *ltt_session_create(char *name) +struct ltt_session *ltt_session_create(void) { struct ltt_session *session; mutex_lock(&sessions_mutex); - list_for_each_entry(session, &sessions, list) - if (!strcmp(session->name, name)) - goto exist; - session = kmalloc(sizeof(struct ltt_session) + strlen(name) + 1); + session = kmalloc(sizeof(struct ltt_session)); if (!session) return NULL; - strcpy(session->name, name); INIT_LIST_HEAD(&session->chan); list_add(&session->list, &sessions); mutex_unlock(&sessions_mutex); @@ -60,7 +56,7 @@ int ltt_session_destroy(struct ltt_session *session) kfree(session); } -struct ltt_channel *ltt_channel_create(struct ltt_session *session, char *name, +struct ltt_channel *ltt_channel_create(struct ltt_session *session, int overwrite, void *buf_addr, size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, @@ -71,13 +67,9 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, char *name, mutex_lock(&sessions_mutex); if (session->active) goto active; /* Refuse to add channel to active session */ - list_for_each_entry(chan, &session->chan, list) - if (!strcmp(chan->name, name)) - goto exist; - chan = kmalloc(sizeof(struct ltt_channel) + strlen(name) + 1, GFP_KERNEL); + chan = kmalloc(sizeof(struct ltt_channel), GFP_KERNEL); if (!chan) return NULL; - strcpy(chan->name, name); chan->session = session; /* TODO: create rb channel */ @@ -105,7 +97,8 @@ int _ltt_channel_destroy(struct ltt_channel *chan) * Supports event creation while tracing session is active. */ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, - void *filter) + enum instrum_type itype, + void *probe, void *filter) { struct ltt_event *event; int ret; @@ -128,11 +121,20 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, goto error; strcpy(event->name, name); event->chan = chan; + event->probe = probe; event->filter = filter; event->id = chan->free_event_id++; + event->itype = itype; mutex_unlock(&sessions_mutex); /* Populate ltt_event structure before tracepoint registration. */ smp_wmb(); + switch (itype) { + case INSTRUM_TRACEPOINTS: + ret = tracepoint_probe_register(name, probe, event); + break; + default: + WARN_ON_ONCE(1); + } return event; error: @@ -149,7 +151,13 @@ full: */ int _ltt_event_destroy(struct ltt_event *event) { - /* TODO unregister from tracepoint */ + switch (event->itype) { + case INSTRUM_TRACEPOINTS: + ret = tracepoint_probe_unregister(name, event->probe, event); + break; + default: + WARN_ON_ONCE(1); + } kfree(event->name); kmem_cache_free(event); } diff --git a/ltt-events.h b/ltt-events.h index 99edb4b1..165e616a 100644 --- a/ltt-events.h +++ b/ltt-events.h @@ -11,6 +11,10 @@ struct ltt_channel; struct ltt_session; +enum instrum_type itype { + INSTRUM_TRACEPOINTS, +}; + /* * ltt_event structure is referred to by the tracing fast path. It must be * kept small. @@ -18,8 +22,10 @@ struct ltt_session; struct ltt_event { unsigned int id; struct ltt_channel *chan; + void *probe; void *filter; char *name; + enum instrum_type itype; struct list_head list; /* Event list */ }; @@ -40,10 +46,10 @@ struct ltt_session { char name[PATH_MAX]; }; -struct ltt_session *ltt_session_create(char *name); +struct ltt_session *ltt_session_create(void); int ltt_session_destroy(struct ltt_session *session); -struct ltt_channel *ltt_channel_create(struct ltt_session *session, char *name, +struct ltt_channel *ltt_channel_create(struct ltt_session *session, int overwrite, void *buf_addr, size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, -- 2.34.1