debugfs ABI in progress
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 24 Nov 2010 03:39:08 +0000 (22:39 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 24 Nov 2010 03:39:08 +0000 (22:39 -0500)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
ltt-debugfs-abi.c [new file with mode: 0644]
ltt-events.c
ltt-events.h

diff --git a/ltt-debugfs-abi.c b/ltt-debugfs-abi.c
new file mode 100644 (file)
index 0000000..7ee2eca
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * ltt-debugfs-abi.c
+ *
+ * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 <linux/debugfs.h>
+
+/*
+ * 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]",
+                                         &lttng_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]",
+                                      &lttng_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);
+}
index 21c6d29e2a2d5d5ba592e9a5aacf40a49f4308d1..f22351fcb0f92fc83070f3a0b90009ee3adba7ab 100644 (file)
@@ -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);
 }
index 99edb4b12801bd3d1301f3eb7743ced4ad7a4012..165e616ac8306f20992f4e494da045441bfb97a4 100644 (file)
 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,
This page took 0.036529 seconds and 4 git commands to generate.