LTTng modules now builds again
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 7 Dec 2010 22:22:20 +0000 (17:22 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 7 Dec 2010 22:22:20 +0000 (17:22 -0500)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
22 files changed:
Makefile
discard/ltt-ascii.c [new file with mode: 0644]
discard/ltt-channels.c [new file with mode: 0644]
discard/ltt-channels.h [new file with mode: 0644]
discard/ltt-marker-control.c [new file with mode: 0644]
discard/ltt-serialize.c [new file with mode: 0644]
discard/ltt-tracer.c [new file with mode: 0644]
discard/ltt-type-serializer.c [new file with mode: 0644]
discard/ltt-type-serializer.h [new file with mode: 0644]
ltt-core.c
ltt-debugfs-abi.c
ltt-event-header.c
ltt-events.c
ltt-events.h
ltt-marker-control.c [deleted file]
ltt-ring-buffer-client.h
ltt-serialize.c [deleted file]
ltt-tracer-core.h
ltt-tracer.c [deleted file]
ltt-tracer.h
ltt-type-serializer.c [deleted file]
ltt-type-serializer.h [deleted file]

index 6e4da6c94cfd8140bf31d0f23ba0929bb40503c8..109b8060498b5cc57e860184f465614933357610 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,14 +6,14 @@ ifneq ($(KERNELRELEASE),)
 ifneq ($(CONFIG_TRACEPOINTS),)
 
 obj-m += ltt-core.o
-obj-m += ltt-debugfs-abi.o
-obj-m += ltt-events.o
 obj-m += ltt-ring-buffer-client-discard.o
 obj-m += ltt-ring-buffer-client-overwrite.o
 
 obj-m += ltt-relay.o
-ltt-relay-objs :=  ltt-event-header.o ltt-serialize.o ltt-type-serializer.o
+ltt-relay-objs :=  ltt-events.o ltt-event-header.o ltt-debugfs-abi.o
 
+#ltt-type-serializer.o
+#ltt-serialize.o
 #obj-m += ltt-marker-control.o
 #obj-m += ltt-trace-control.o
 #ltt-ascii.o
diff --git a/discard/ltt-ascii.c b/discard/ltt-ascii.c
new file mode 100644 (file)
index 0000000..b020fed
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ * LTT ascii binary buffer to ascii converter.
+ *
+ * Copyright       2008 - 2009   Lai Jiangshan (laijs@cn.fujitsu.com)
+ * Copyright       2009 -        Mathieu Desnoyers mathieu.desnoyers@polymtl.ca
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+/*
+ * TODO
+ *
+ * Move to new switch behavior: Wait for data for the duration of the
+ * timer interval + safety, if none is coming, consider that no activity occured
+ * in the buffer.
+ *
+ * Fix case when having a text file open and destroying trace.
+ *
+ * - Automate periodical switch:
+ *
+ * The debugfs file "switch_timer" receives a timer period as parameter
+ * (e.g. echo 100 > switch_timer) to activate the timer per channel. This can
+ * also be accessed through the internal API _before the trace session starts_.
+ * This timer will insure that we periodically have subbuffers to read, and
+ * therefore that the merge-sort does not wait endlessly for a subbuffer.
+ *
+ * - If a channel is switched and read without data, make sure it is still
+ * considered afterward (not removed from the queue).
+ *
+ * - Create a ascii/tracename/ALL file to merge-sort all active channels.
+ * - Create a ascii/tracename/README file to contain the text output legend.
+ * - Remove leading zeroes from timestamps.
+ * - Enhance pretty-printing to make sure all types used for addesses output in
+ * the form 0xAB00000000 (not decimal). This is true for %p and 0x%...X.
+ * - Hotplug support
+ */
+
+
+
+
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/fs.h>
+
+#include "ltt-tracer.h"
+#include "ltt-relay.h"
+#include "ltt-relay-lockless.h"
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt , a...)
+#endif
+
+struct dentry *ltt_ascii_dir_dentry;
+EXPORT_SYMBOL_GPL(ltt_ascii_dir_dentry);
+
+struct ltt_relay_iter;
+
+struct ltt_relay_cpu_iter {
+       /* cpu buffer information */
+       struct ltt_chanbuf *buf;
+       struct ltt_relay_iter *iter;
+       int sb_ref;             /* holding a reference to a subbuffer */
+       long read_sb_offset;    /* offset of the subbuffer read */
+
+       /* current event information */
+       struct ltt_subbuffer_header *header;
+       long hdr_offset;        /* event header offset */
+       long payload_offset;    /* event payload offset */
+       u64 tsc;        /* full 64-bits timestamp value */
+       u32 data_size;
+       u16 chID;       /* channel ID, const */
+       u16 eID;
+};
+
+struct ltt_relay_iter {
+       struct ltt_relay_cpu_iter iter_cpu[NR_CPUS];
+       struct ltt_chan *chan;
+       loff_t pos;
+       int cpu;
+       int nr_refs;
+};
+
+/*
+ * offset of 0 in subbuffer means "subbuf size" (filled subbuffer).
+ */
+static int is_subbuffer_offset_end(struct ltt_relay_cpu_iter *citer,
+                                  long offset)
+{
+       struct ltt_chan *chan = container_of(citer->buf->a.chan,
+                                            struct ltt_chan, a);
+       long sub_offset = SUBBUF_OFFSET(offset - 1, chan) + 1;
+
+       return (sub_offset <= citer->header->data_size);
+}
+
+static u64 calculate_tsc(u64 pre_tsc, u64 read_tsc, unsigned int rflags)
+{
+       u64 new_tsc = read_tsc;
+
+       if (rflags != LTT_RFLAG_ID_SIZE_TSC) {
+               BUG_ON(read_tsc >> LTT_TSC_BITS);
+
+               new_tsc = (pre_tsc & ~LTT_TSC_MASK) + read_tsc;
+               if (read_tsc < (pre_tsc & LTT_TSC_MASK))
+                       new_tsc += 1UL << LTT_TSC_BITS;
+       }
+
+       return new_tsc;
+}
+
+/*
+ * calculate payload offset */
+static inline long calculate_payload_offset(long offset, u16 chID, u16 eID)
+{
+       const char *fmt;
+
+       if (!ltt_get_alignment())
+               return offset;
+
+       fmt = marker_get_fmt_from_id(chID, eID);
+       BUG_ON(!fmt);
+
+       return offset + ltt_fmt_largest_align(offset, fmt);
+}
+
+static void update_new_event(struct ltt_relay_cpu_iter *citer, long hdr_offset)
+{
+       u64 read_tsc;
+       unsigned int rflags;
+       long tmp_offset;
+
+       WARN_ON_ONCE(hdr_offset != citer->hdr_offset);
+
+       tmp_offset = ltt_read_event_header(&citer->buf->a, hdr_offset,
+                                          &read_tsc, &citer->data_size,
+                                          &citer->eID, &rflags);
+       citer->payload_offset = calculate_payload_offset(tmp_offset,
+                                                        citer->chID,
+                                                        citer->eID);
+
+       citer->tsc = calculate_tsc(citer->tsc, read_tsc, rflags);
+}
+
+static void update_event_size(struct ltt_relay_cpu_iter *citer, long hdr_offset)
+{
+       char output[1];
+       const char *fmt;
+       size_t data_size;
+
+       if (citer->data_size != INT_MAX)
+               return;
+
+       fmt = marker_get_fmt_from_id(citer->chID, citer->eID);
+       BUG_ON(!fmt);
+       ltt_serialize_printf(citer->buf, citer->payload_offset,
+                            &data_size, output, 0, fmt);
+       citer->data_size = data_size;
+}
+
+static void update_cpu_iter(struct ltt_relay_cpu_iter *citer, long hdr_offset)
+{
+       if (unlikely((!citer->sb_ref)
+                    || is_subbuffer_offset_end(citer, hdr_offset))) {
+               citer->header = NULL;
+               return;
+       }
+       update_new_event(citer, hdr_offset);
+       update_event_size(citer, hdr_offset);
+}
+
+/*
+ * returns 0 if we get a subbuffer reference.
+ * else, the buffer has not available data, try again later.
+ */
+static int subbuffer_start(struct ltt_relay_cpu_iter *citer, long *offset)
+{
+       int ret;
+       struct ltt_relay_iter *iter = citer->iter;
+
+       ret = ltt_chanbuf_get_subbuf(citer->buf, offset);
+       if (!ret) {
+               citer->header = ltt_relay_read_offset_address(&citer->buf->a,
+                                                             *offset);
+               citer->hdr_offset = (*offset) + ltt_sb_header_size();
+               citer->tsc = citer->header->cycle_count_begin;
+               iter->nr_refs++;
+               citer->sb_ref = 1;
+               return 0;
+       } else {
+               if (ltt_chanbuf_is_finalized(citer->buf))
+                       return -ENODATA;
+               else
+                       return -EAGAIN;
+       }
+}
+
+static void subbuffer_stop(struct ltt_relay_cpu_iter *citer,
+                          long offset)
+{
+       int ret;
+       struct ltt_relay_iter *iter = citer->iter;
+
+       WARN_ON_ONCE(!citer->sb_ref);
+       ret = ltt_chanbuf_put_subbuf(citer->buf, offset);
+       WARN_ON_ONCE(ret);
+       citer->sb_ref = 0;
+       iter->nr_refs--;
+}
+
+static void ltt_relay_advance_cpu_iter(struct ltt_relay_cpu_iter *citer)
+{
+       long old_offset = citer->payload_offset;
+       long new_offset = citer->payload_offset;
+       int ret;
+
+       /* find that whether we read all data in this subbuffer */
+       if (unlikely(is_subbuffer_offset_end(citer,
+                                            old_offset + citer->data_size))) {
+               DEBUGP(KERN_DEBUG "LTT ASCII stop cpu %d offset %lX\n",
+                      citer->buf->a.cpu, citer->read_sb_offset);
+               subbuffer_stop(citer, citer->read_sb_offset);
+               for (;;) {
+                       ret = subbuffer_start(citer, &citer->read_sb_offset);
+                       DEBUGP(KERN_DEBUG
+                              "LTT ASCII start cpu %d ret %d offset %lX\n",
+                              citer->buf->a.cpu, ret, citer->read_sb_offset);
+                       if (!ret || ret == -ENODATA) {
+                               break;  /* got data, or finalized */
+                       } else {        /* -EAGAIN */
+                               if (signal_pending(current))
+                                       break;
+                               schedule_timeout_interruptible(1);
+                               //TODO: check for no-data delay. take ref. break
+                       }
+               }
+       } else {
+               new_offset += citer->data_size;
+               citer->hdr_offset = new_offset + ltt_align(new_offset, sizeof(struct ltt_event_header));
+               DEBUGP(KERN_DEBUG
+                      "LTT ASCII old_offset %lX new_offset %lX cpu %d\n",
+                      old_offset, new_offset, citer->buf->a.cpu);
+       }
+
+       update_cpu_iter(citer, citer->hdr_offset);
+}
+
+static int cpu_iter_eof(struct ltt_relay_cpu_iter *citer)
+{
+       return !citer->sb_ref;
+}
+
+static int ltt_relay_iter_eof(struct ltt_relay_iter *iter)
+{
+       return iter->nr_refs == 0;
+}
+
+static void ltt_relay_advance_iter(struct ltt_relay_iter *iter)
+{
+       int i;
+       struct ltt_relay_cpu_iter *curr, *min = NULL;
+       iter->cpu = -1;
+
+       /*
+        * find the event with the minimum tsc.
+        * TODO: use min-heep for 4096CPUS
+        */
+       for_each_possible_cpu(i) {
+               curr = &iter->iter_cpu[i];
+
+               if (!curr->buf->a.allocated || !curr->header)
+                       continue;
+
+               if (cpu_iter_eof(curr))
+                       continue;
+
+               if (!min || curr->tsc < min->tsc) {
+                       min = curr;
+                       iter->cpu = i;
+               }
+       }
+
+       /* update cpu_iter for next ltt_relay_advance_iter() */
+       if (min)
+               ltt_relay_advance_cpu_iter(min);
+}
+
+static void *ascii_next(struct seq_file *m, void *v, loff_t *ppos)
+{
+       struct ltt_relay_iter *iter = m->private;
+
+       WARN_ON_ONCE(!iter->nr_refs);
+       BUG_ON(v != iter);
+
+       ltt_relay_advance_iter(iter);
+       return (ltt_relay_iter_eof(iter) || signal_pending(current))
+               ? NULL : iter;
+}
+
+static void *ascii_start(struct seq_file *m, loff_t *ppos)
+{
+       struct ltt_relay_iter *iter = m->private;
+
+       ltt_relay_advance_iter(iter);
+       return (ltt_relay_iter_eof(iter) || signal_pending(current))
+               ? NULL : iter;
+}
+
+static void ascii_stop(struct seq_file *m, void *v)
+{
+}
+
+static
+int seq_serialize(struct seq_file *m, struct ltt_chanbuf *buf,
+                 size_t buf_offset, const char *fmt, size_t *data_size)
+{
+       int len;
+
+       if (m->count < m->size) {
+               len = ltt_serialize_printf(buf, buf_offset, data_size,
+                                          m->buf + m->count,
+                                          m->size - m->count, fmt);
+               if (m->count + len < m->size) {
+                       m->count += len;
+                       return 0;
+               }
+       }
+
+       m->count = m->size;
+       return -1;
+}
+
+static int ascii_show(struct seq_file *m, void *v)
+{
+       struct ltt_relay_iter *iter = v;
+       struct ltt_relay_cpu_iter *citer;
+       const char *name;
+       const char *fmt;
+       unsigned long long tsc;
+       size_t data_size;
+
+       if (iter->cpu == -1)
+               return 0;
+
+       citer = &iter->iter_cpu[iter->cpu];
+       WARN_ON_ONCE(!citer->sb_ref);
+       /*
+        * Nothing to show, we are at the end of the last subbuffer currently
+        * having data.
+        */
+       if (!citer->header)
+               return 0;
+
+       tsc = citer->tsc;
+       name = marker_get_name_from_id(citer->chID, citer->eID);
+       fmt = marker_get_fmt_from_id(citer->chID, citer->eID);
+
+       if (!name || !fmt)
+               return 0;
+
+       seq_printf(m, "event:%16.16s: cpu:%2d time:%20.20llu ",
+                  name, iter->cpu, tsc);
+       seq_serialize(m, citer->buf, citer->payload_offset, fmt, &data_size);
+       seq_puts(m, "\n");
+       if (citer->data_size == INT_MAX)
+               citer->data_size = data_size;
+
+       return 0;
+}
+
+static struct seq_operations ascii_seq_ops = {
+       .start          = ascii_start,
+       .next           = ascii_next,
+       .stop           = ascii_stop,
+       .show           = ascii_show,
+};
+
+/* FIXME : cpu hotplug support */
+static int ltt_relay_iter_open_channel(struct ltt_relay_iter *iter,
+                                      struct ltt_chan *chan)
+{
+       int i, ret;
+       u16 chID = ltt_channels_get_index_from_name(chan->a.filename);
+
+       /* we don't need lock relay_channels_mutex */
+       for_each_possible_cpu(i) {
+               struct ltt_relay_cpu_iter *citer = &iter->iter_cpu[i];
+
+               citer->buf = per_cpu_ptr(chan->a.buf, i);
+               if (!citer->buf->a.allocated)
+                       continue;
+
+               citer->iter = iter;     /* easy lazy parent info */
+               citer->chID = chID;
+
+               ret = ltt_chanbuf_open_read(citer->buf);
+               if (ret) {
+                       /* Failed to open a percpu buffer, close everything. */
+                       citer->buf = NULL;
+                       goto error;
+               }
+
+               for (;;) {
+                       ret = subbuffer_start(citer,
+                                             &citer->read_sb_offset);
+                       DEBUGP(KERN_DEBUG
+                               "LTT ASCII open start "
+                               "cpu %d ret %d offset %lX\n",
+                               citer->buf->a.cpu, ret, citer->read_sb_offset);
+                       if (!ret || ret == -ENODATA) {
+                               break;  /* got data, or finalized */
+                       } else {        /* -EAGAIN */
+                               if (signal_pending(current))
+                                       break;
+                               schedule_timeout_interruptible(1);
+                       }
+               }
+               update_cpu_iter(citer, citer->hdr_offset);
+       }
+       if (!iter->nr_refs) {
+               ret = -ENODATA;
+               goto error;
+       }
+
+       return 0;
+
+error:
+       for_each_possible_cpu(i) {
+               struct ltt_relay_cpu_iter *citer = &iter->iter_cpu[i];
+
+               if (!citer->buf)
+                       break;
+
+               if (citer->buf->a.allocated)
+                       ltt_chanbuf_release_read(citer->buf);
+       }
+       return ret;
+}
+
+/* FIXME : cpu hotplug support */
+static int ltt_relay_iter_release_channel(struct ltt_relay_iter *iter)
+{
+       int i;
+
+       for_each_possible_cpu(i) {
+               struct ltt_relay_cpu_iter *citer = &iter->iter_cpu[i];
+
+               if (citer->sb_ref) {
+                       WARN_ON_ONCE(!citer->buf->a.allocated);
+                       DEBUGP(KERN_DEBUG
+                               "LTT ASCII release stop cpu %d offset %lX\n",
+                               citer->buf->a.cpu, citer->read_sb_offset);
+                       subbuffer_stop(&iter->iter_cpu[i],
+                                      citer->read_sb_offset);
+               }
+               if (citer->buf->a.allocated)
+                       ltt_chanbuf_release_read(citer->buf);
+       }
+       WARN_ON_ONCE(iter->nr_refs);
+       return 0;
+}
+
+static int ltt_relay_ascii_open(struct inode *inode, struct file *file)
+{
+       int ret;
+       struct ltt_chan *chan = inode->i_private;
+       struct ltt_relay_iter *iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+       if (!iter)
+               return -ENOMEM;
+
+       iter->chan = chan;
+       ret = ltt_relay_iter_open_channel(iter, chan);
+       if (ret)
+               goto error_free_alloc;
+
+       ret = seq_open(file, &ascii_seq_ops);
+       if (ret)
+               goto error_release_channel;
+       ((struct seq_file *)file->private_data)->private = iter;
+       return 0;
+
+error_release_channel:
+       ltt_relay_iter_release_channel(iter);
+error_free_alloc:
+       kfree(iter);
+       return ret;
+}
+
+static int ltt_relay_ascii_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq = file->private_data;
+       struct ltt_relay_iter *iter = seq->private;
+
+       ltt_relay_iter_release_channel(iter);
+       kfree(iter);
+       return 0;
+}
+
+static struct file_operations ltt_ascii_fops =
+{
+       .read = seq_read,
+       .open = ltt_relay_ascii_open,
+       .release = ltt_relay_ascii_release,
+       .llseek = no_llseek,
+       .owner = THIS_MODULE,
+};
+
+int ltt_ascii_create(struct ltt_chan *chan)
+{
+       struct dentry *dentry;
+
+       dentry = debugfs_create_file(chan->a.filename,
+                                    S_IRUSR | S_IRGRP,
+                                    chan->a.trace->dentry.ascii_root,
+                                    chan, &ltt_ascii_fops);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+
+       if (!dentry)
+               return -EEXIST;
+
+       chan->a.ascii_dentry = dentry;
+       dentry->d_inode->i_private = chan;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ltt_ascii_create);
+
+void ltt_ascii_remove(struct ltt_chan *chan)
+{
+       struct dentry *dentry;
+
+       dentry = dget(chan->a.ascii_dentry);
+       debugfs_remove(dentry);
+       /* TODO: wait / wakeup instead */
+       /*
+        * Wait for every reference to the dentry to be gone,
+        * except us.
+        */
+       while (atomic_read(&dentry->d_count) != 1)
+               msleep(100);
+       dput(dentry);
+}
+EXPORT_SYMBOL_GPL(ltt_ascii_remove);
+
+int ltt_ascii_create_dir(struct ltt_trace *new_trace)
+{
+       new_trace->dentry.ascii_root = debugfs_create_dir(new_trace->trace_name,
+                                                         ltt_ascii_dir_dentry);
+       if (!new_trace->dentry.ascii_root)
+               return -EEXIST;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ltt_ascii_create_dir);
+
+void ltt_ascii_remove_dir(struct ltt_trace *trace)
+{
+       debugfs_remove(trace->dentry.ascii_root);
+}
+EXPORT_SYMBOL_GPL(ltt_ascii_remove_dir);
+
+__init int ltt_ascii_init(void)
+{
+       ltt_ascii_dir_dentry = debugfs_create_dir(LTT_ASCII, get_ltt_root());
+
+       return ltt_ascii_dir_dentry ? 0 : -EFAULT;
+}
+
+__exit void ltt_ascii_exit(void)
+{
+       debugfs_remove(ltt_ascii_dir_dentry);
+       put_ltt_root();
+}
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Lai Jiangshan@FNST and Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Ascii Converter");
diff --git a/discard/ltt-channels.c b/discard/ltt-channels.c
new file mode 100644 (file)
index 0000000..962c81a
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * ltt/ltt-channels.c
+ *
+ * (C) Copyright 2008 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * LTTng channel management.
+ *
+ * Author:
+ *     Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include "ltt-channels.h"
+
+/*
+ * ltt_channel_mutex may be nested inside the LTT trace mutex.
+ * ltt_channel_mutex mutex may be nested inside markers mutex.
+ */
+static DEFINE_MUTEX(ltt_channel_mutex);
+static LIST_HEAD(ltt_channels);
+/*
+ * Index of next channel in array. Makes sure that as long as a trace channel is
+ * allocated, no array index will be re-used when a channel is freed and then
+ * another channel is allocated. This index is cleared and the array indexeds
+ * get reassigned when the index_kref goes back to 0, which indicates that no
+ * more trace channels are allocated.
+ */
+static unsigned int free_index;
+/* index_kref is protected by both ltt_channel_mutex and lock_markers */
+static struct kref index_kref; /* Keeps track of allocated trace channels */
+
+static struct ltt_channel_setting *lookup_channel(const char *name)
+{
+       struct ltt_channel_setting *iter;
+
+       list_for_each_entry(iter, &ltt_channels, list)
+               if (strcmp(name, iter->name) == 0)
+                       return iter;
+       return NULL;
+}
+
+/*
+ * Must be called when channel refcount falls to 0 _and_ also when the last
+ * trace is freed. This function is responsible for compacting the channel and
+ * event IDs when no users are active.
+ *
+ * Called with lock_markers() and channels mutex held.
+ */
+static void release_channel_setting(struct kref *kref)
+{
+       struct ltt_channel_setting *setting = container_of(kref,
+               struct ltt_channel_setting, kref);
+       struct ltt_channel_setting *iter;
+
+       if (atomic_read(&index_kref.refcount) == 0
+           && atomic_read(&setting->kref.refcount) == 0) {
+               list_del(&setting->list);
+               kfree(setting);
+
+               free_index = 0;
+               list_for_each_entry(iter, &ltt_channels, list) {
+                       iter->index = free_index++;
+                       iter->free_event_id = 0;
+               }
+       }
+}
+
+/*
+ * Perform channel index compaction when the last trace channel is freed.
+ *
+ * Called with lock_markers() and channels mutex held.
+ */
+static void release_trace_channel(struct kref *kref)
+{
+       struct ltt_channel_setting *iter, *n;
+
+       list_for_each_entry_safe(iter, n, &ltt_channels, list)
+               release_channel_setting(&iter->kref);
+       if (atomic_read(&index_kref.refcount) == 0)
+               markers_compact_event_ids();
+}
+
+/*
+ * ltt_channel_trace_ref :  Is there an existing trace session ?
+ *
+ * Must be called with lock_markers() held.
+ */
+int ltt_channels_trace_ref(void)
+{
+       return !!atomic_read(&index_kref.refcount);
+}
+EXPORT_SYMBOL_GPL(ltt_channels_trace_ref);
+
+/**
+ * ltt_channels_register - Register a trace channel.
+ * @name: channel name
+ *
+ * Uses refcounting.
+ */
+int ltt_channels_register(const char *name)
+{
+       struct ltt_channel_setting *setting;
+       int ret = 0;
+
+       mutex_lock(&ltt_channel_mutex);
+       setting = lookup_channel(name);
+       if (setting) {
+               if (atomic_read(&setting->kref.refcount) == 0)
+                       goto init_kref;
+               else {
+                       kref_get(&setting->kref);
+                       goto end;
+               }
+       }
+       setting = kzalloc(sizeof(*setting), GFP_KERNEL);
+       if (!setting) {
+               ret = -ENOMEM;
+               goto end;
+       }
+       list_add(&setting->list, &ltt_channels);
+       strncpy(setting->name, name, PATH_MAX-1);
+       setting->index = free_index++;
+init_kref:
+       kref_init(&setting->kref);
+end:
+       mutex_unlock(&ltt_channel_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ltt_channels_register);
+
+/**
+ * ltt_channels_unregister - Unregister a trace channel.
+ * @name: channel name
+ * @compacting: performing compaction
+ *
+ * Must be called with markers mutex held.
+ */
+int ltt_channels_unregister(const char *name, int compacting)
+{
+       struct ltt_channel_setting *setting;
+       int ret = 0;
+
+       if (!compacting)
+               mutex_lock(&ltt_channel_mutex);
+       setting = lookup_channel(name);
+       if (!setting || atomic_read(&setting->kref.refcount) == 0) {
+               ret = -ENOENT;
+               goto end;
+       }
+       kref_put(&setting->kref, release_channel_setting);
+       if (!compacting && atomic_read(&index_kref.refcount) == 0)
+                       markers_compact_event_ids();
+end:
+       if (!compacting)
+               mutex_unlock(&ltt_channel_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ltt_channels_unregister);
+
+/**
+ * ltt_channels_set_default - Set channel default behavior.
+ * @name: default channel name
+ * @sb_size: size of the subbuffers
+ * @n_sb: number of subbuffers
+ */
+int ltt_channels_set_default(const char *name,
+                            unsigned int sb_size,
+                            unsigned int n_sb)
+{
+       struct ltt_channel_setting *setting;
+       int ret = 0;
+
+       mutex_lock(&ltt_channel_mutex);
+       setting = lookup_channel(name);
+       if (!setting || atomic_read(&setting->kref.refcount) == 0) {
+               ret = -ENOENT;
+               goto end;
+       }
+       setting->sb_size = sb_size;
+       setting->n_sb = n_sb;
+end:
+       mutex_unlock(&ltt_channel_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ltt_channels_set_default);
+
+/**
+ * ltt_channels_get_name_from_index - get channel name from channel index
+ * @index: channel index
+ *
+ * Allows to lookup the channel name given its index. Done to keep the name
+ * information outside of each trace channel instance.
+ */
+const char *ltt_channels_get_name_from_index(unsigned int index)
+{
+       struct ltt_channel_setting *iter;
+
+       list_for_each_entry(iter, &ltt_channels, list)
+               if (iter->index == index && atomic_read(&iter->kref.refcount))
+                       return iter->name;
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(ltt_channels_get_name_from_index);
+
+static struct ltt_channel_setting *
+ltt_channels_get_setting_from_name(const char *name)
+{
+       struct ltt_channel_setting *iter;
+
+       list_for_each_entry(iter, &ltt_channels, list)
+               if (!strcmp(iter->name, name)
+                   && atomic_read(&iter->kref.refcount))
+                       return iter;
+       return NULL;
+}
+
+/**
+ * ltt_channels_get_index_from_name - get channel index from channel name
+ * @name: channel name
+ *
+ * Allows to lookup the channel index given its name. Done to keep the name
+ * information outside of each trace channel instance.
+ * Returns -1 if not found.
+ */
+int ltt_channels_get_index_from_name(const char *name)
+{
+       struct ltt_channel_setting *setting;
+
+       setting = ltt_channels_get_setting_from_name(name);
+       if (setting)
+               return setting->index;
+       else
+               return -1;
+}
+EXPORT_SYMBOL_GPL(ltt_channels_get_index_from_name);
+
+/**
+ * ltt_channels_trace_alloc - Allocate channel structures for a trace
+ *
+ * Use the current channel list to allocate the channels for a trace.
+ * Called with trace lock held. Does not perform the trace buffer allocation,
+ * because we must let the user overwrite specific channel sizes.
+ */
+int ltt_channels_trace_alloc(struct ltt_trace *trace, int overwrite)
+{
+       struct channel **chan = NULL;
+       struct ltt_channel_setting *chans, *iter;
+       int ret = 0;
+
+       lock_markers();
+       mutex_lock(&ltt_channel_mutex);
+       if (!free_index)
+               goto end;
+       if (!atomic_read(&index_kref.refcount))
+               kref_init(&index_kref);
+       else
+               kref_get(&index_kref);
+       trace->nr_channels = free_index;
+       chan = kzalloc(sizeof(struct channel *) * free_index, GFP_KERNEL);
+       if (!chan)
+               goto end;
+       chans = kzalloc(sizeof(struct ltt_channel_setting) * free_index,
+                       GFP_KERNEL);
+       if (!chan_settings)
+               goto free_chan;
+       list_for_each_entry(iter, &ltt_channels, list) {
+               if (!atomic_read(&iter->kref.refcount))
+                       continue;
+               chans[iter->index].sb_size = iter->sb_size;
+               chans[iter->index].n_sb = iter->n_sb;
+               chans[iter->index].overwrite = overwrite;
+               strncpy(chans[iter->index].filename, iter->name,
+                       NAME_MAX - 1);
+               chans[iter->index].switch_timer_interval = 0;
+               chans[iter->index].read_timer_interval = LTT_READ_TIMER_INTERVAL;
+       }
+       trace->channels = chan;
+       trace->settings = chans;
+end:
+       mutex_unlock(&ltt_channel_mutex);
+       unlock_markers();
+       return ret;
+
+free_chan:
+       kfree(chan);
+       ret = -ENOMEM;
+       goto end;
+}
+EXPORT_SYMBOL_GPL(ltt_channels_trace_alloc);
+
+/**
+ * ltt_channels_trace_free - Free one trace's channels
+ * @channels: channels to free
+ *
+ * Called with trace lock held. The actual channel buffers must be freed before
+ * this function is called.
+ */
+void ltt_channels_trace_free(struct ltt_trace *trace)
+{
+       lock_markers();
+       mutex_lock(&ltt_channel_mutex);
+       kfree(trace->settings);
+       kfree(trace->channels);
+       kref_put(&index_kref, release_trace_channel);
+       mutex_unlock(&ltt_channel_mutex);
+       unlock_markers();
+       marker_update_probes();
+}
+EXPORT_SYMBOL_GPL(ltt_channels_trace_free);
+
+/**
+ * ltt_channels_trace_set_timer - set switch timer
+ * @channel: channel
+ * @interval: interval of timer interrupt, in jiffies. 0 inhibits timer.
+ */
+
+void ltt_channels_trace_set_timer(struct ltt_chan *chan,
+                                 unsigned long interval)
+{
+       chan->switch_timer_interval = interval;
+}
+EXPORT_SYMBOL_GPL(ltt_channels_trace_set_timer);
+
+/**
+ * _ltt_channels_get_event_id - get next event ID for a marker
+ * @channel: channel name
+ * @name: event name
+ *
+ * Returns a unique event ID (for this channel) or < 0 on error.
+ * Must be called with channels mutex held.
+ */
+int _ltt_channels_get_event_id(const char *channel, const char *name)
+{
+       struct ltt_channel_setting *setting;
+       int ret;
+
+       setting = ltt_channels_get_setting_from_name(channel);
+       if (!setting) {
+               ret = -ENOENT;
+               goto end;
+       }
+       if (strcmp(channel, "metadata") == 0) {
+               if (strcmp(name, "core_marker_id") == 0)
+                       ret = 0;
+               else if (strcmp(name, "core_marker_format") == 0)
+                       ret = 1;
+               else
+                       ret = -ENOENT;
+               goto end;
+       }
+       if (setting->free_event_id == EVENTS_PER_CHANNEL - 1) {
+               ret = -ENOSPC;
+               goto end;
+       }
+       ret = setting->free_event_id++;
+end:
+       return ret;
+}
+
+/**
+ * ltt_channels_get_event_id - get next event ID for a marker
+ * @channel: channel name
+ * @name: event name
+ *
+ * Returns a unique event ID (for this channel) or < 0 on error.
+ */
+int ltt_channels_get_event_id(const char *channel, const char *name)
+{
+       int ret;
+
+       mutex_lock(&ltt_channel_mutex);
+       ret = _ltt_channels_get_event_id(channel, name);
+       mutex_unlock(&ltt_channel_mutex);
+       return ret;
+}
+
+/**
+ * ltt_channels_reset_event_ids - reset event IDs at compaction
+ *
+ * Called with lock marker and channel mutex held.
+ */
+void _ltt_channels_reset_event_ids(void)
+{
+       struct ltt_channel_setting *iter;
+
+       list_for_each_entry(iter, &ltt_channels, list)
+               iter->free_event_id = 0;
+}
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Channel Management");
diff --git a/discard/ltt-channels.h b/discard/ltt-channels.h
new file mode 100644 (file)
index 0000000..9eb604b
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef _LTT_CHANNELS_H
+#define _LTT_CHANNELS_H
+
+/*
+ * Copyright (C) 2008 Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * Dynamic tracer channel allocation.
+
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#include <linux/limits.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/ltt-core.h>
+
+#define EVENTS_PER_CHANNEL             65536
+
+#define LTT_READ_TIMER_INTERVAL                10000 /* us */
+
+/*
+ * Forward declaration of locking-specific per-cpu buffer structure.
+ */
+struct ltt_trace;
+struct ltt_serialize_closure;
+struct ltt_probe_private_data;
+
+/* Serialization callback '%k' */
+typedef size_t (*ltt_serialize_cb)(struct ltt_chanbuf *buf, size_t buf_offset,
+                                  struct ltt_serialize_closure *closure,
+                                  void *serialize_private,
+                                  unsigned int stack_pos_ctx,
+                                  int *largest_align,
+                                  const char *fmt, va_list *args);
+
+struct ltt_probe_private_data {
+       struct ltt_trace *trace;        /*
+                                        * Target trace, for metadata
+                                        * or statedump.
+                                        */
+       ltt_serialize_cb serializer;    /*
+                                        * Serialization function override.
+                                        */
+       void *serialize_private;        /*
+                                        * Private data for serialization
+                                        * functions.
+                                        */
+};
+
+struct ltt_channel_setting {
+       unsigned int sb_size;
+       unsigned int n_sb;
+       int overwrite;
+       unsigned long switch_timer_interval;
+       unsigned long read_timer_interval;
+       struct kref kref;       /* Number of references to structure content */
+       struct list_head list;
+       unsigned int index;     /* index of channel in trace channel array */
+       u16 free_event_id;      /* Next event ID to allocate */
+       char name[PATH_MAX];
+};
+
+int ltt_channels_register(const char *name);
+int ltt_channels_unregister(const char *name, int compacting);
+int ltt_channels_set_default(const char *name,
+                            unsigned int subbuf_size,
+                            unsigned int subbuf_cnt);
+const char *ltt_channels_get_name_from_index(unsigned int index);
+int ltt_channels_get_index_from_name(const char *name);
+int ltt_channels_trace_ref(void);
+struct ltt_chan *ltt_channels_trace_alloc(unsigned int *nr_channels,
+                                         int overwrite, int active);
+void ltt_channels_trace_free(struct ltt_chan *channels,
+                            unsigned int nr_channels);
+void ltt_channels_trace_set_timer(struct ltt_channel_setting *chan,
+                                 unsigned long interval);
+
+int _ltt_channels_get_event_id(const char *channel, const char *name);
+int ltt_channels_get_event_id(const char *channel, const char *name);
+void _ltt_channels_reset_event_ids(void);
+
+#endif /* _LTT_CHANNELS_H */
diff --git a/discard/ltt-marker-control.c b/discard/ltt-marker-control.c
new file mode 100644 (file)
index 0000000..2db5c4e
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2007 Mathieu Desnoyers
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#include <linux/module.h>
+#include <linux/stat.h>
+#include <linux/vmalloc.h>
+#include <linux/marker.h>
+#include <linux/uaccess.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+
+#include "ltt-tracer.h"
+
+#define DEFAULT_CHANNEL "cpu"
+#define DEFAULT_PROBE "default"
+
+LIST_HEAD(probes_list);
+
+/*
+ * Mutex protecting the probe slab cache.
+ * Nests inside the traces mutex.
+ */
+DEFINE_MUTEX(probes_mutex);
+
+struct ltt_available_probe default_probe = {
+       .name = "default",
+       .format = NULL,
+       .probe_func = ltt_vtrace,
+       .callbacks[0] = ltt_serialize_data,
+};
+
+static struct kmem_cache *markers_loaded_cachep;
+static LIST_HEAD(markers_loaded_list);
+/*
+ * List sorted by name strcmp order.
+ */
+static LIST_HEAD(probes_registered_list);
+
+static struct ltt_available_probe *get_probe_from_name(const char *pname)
+{
+       struct ltt_available_probe *iter;
+       int comparison, found = 0;
+
+       if (!pname)
+               pname = DEFAULT_PROBE;
+       list_for_each_entry(iter, &probes_registered_list, node) {
+               comparison = strcmp(pname, iter->name);
+               if (!comparison)
+                       found = 1;
+               if (comparison <= 0)
+                       break;
+       }
+       if (found)
+               return iter;
+       else
+               return NULL;
+}
+
+int ltt_probe_register(struct ltt_available_probe *pdata)
+{
+       int ret = 0;
+       int comparison;
+       struct ltt_available_probe *iter;
+
+       mutex_lock(&probes_mutex);
+       list_for_each_entry_reverse(iter, &probes_registered_list, node) {
+               comparison = strcmp(pdata->name, iter->name);
+               if (!comparison) {
+                       ret = -EBUSY;
+                       goto end;
+               } else if (comparison > 0) {
+                       /* We belong to the location right after iter. */
+                       list_add(&pdata->node, &iter->node);
+                       goto end;
+               }
+       }
+       /* Should be added at the head of the list */
+       list_add(&pdata->node, &probes_registered_list);
+end:
+       mutex_unlock(&probes_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ltt_probe_register);
+
+/*
+ * Called when a probe does not want to be called anymore.
+ */
+int ltt_probe_unregister(struct ltt_available_probe *pdata)
+{
+       int ret = 0;
+       struct ltt_active_marker *amark, *tmp;
+
+       mutex_lock(&probes_mutex);
+       list_for_each_entry_safe(amark, tmp, &markers_loaded_list, node) {
+               if (amark->probe == pdata) {
+                       ret = marker_probe_unregister_private_data(
+                               pdata->probe_func, amark);
+                       if (ret)
+                               goto end;
+                       list_del(&amark->node);
+                       kmem_cache_free(markers_loaded_cachep, amark);
+               }
+       }
+       list_del(&pdata->node);
+end:
+       mutex_unlock(&probes_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ltt_probe_unregister);
+
+/*
+ * Connect marker "mname" to probe "pname".
+ * Only allow _only_ probe instance to be connected to a marker.
+ */
+int ltt_marker_connect(const char *channel, const char *mname,
+                      const char *pname)
+{
+       int ret;
+       struct ltt_active_marker *pdata;
+       struct ltt_available_probe *probe;
+
+       ltt_lock_traces();
+       mutex_lock(&probes_mutex);
+       probe = get_probe_from_name(pname);
+       if (!probe) {
+               ret = -ENOENT;
+               goto end;
+       }
+       pdata = marker_get_private_data(channel, mname, probe->probe_func, 0);
+       if (pdata && !IS_ERR(pdata)) {
+               ret = -EEXIST;
+               goto end;
+       }
+       pdata = kmem_cache_zalloc(markers_loaded_cachep, GFP_KERNEL);
+       if (!pdata) {
+               ret = -ENOMEM;
+               goto end;
+       }
+       pdata->probe = probe;
+       /*
+        * ID has priority over channel in case of conflict.
+        */
+       ret = marker_probe_register(channel, mname, NULL,
+               probe->probe_func, pdata);
+       if (ret)
+               kmem_cache_free(markers_loaded_cachep, pdata);
+       else
+               list_add(&pdata->node, &markers_loaded_list);
+end:
+       mutex_unlock(&probes_mutex);
+       ltt_unlock_traces();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ltt_marker_connect);
+
+/*
+ * Disconnect marker "mname", probe "pname".
+ */
+int ltt_marker_disconnect(const char *channel, const char *mname,
+                         const char *pname)
+{
+       struct ltt_active_marker *pdata;
+       struct ltt_available_probe *probe;
+       int ret = 0;
+
+       mutex_lock(&probes_mutex);
+       probe = get_probe_from_name(pname);
+       if (!probe) {
+               ret = -ENOENT;
+               goto end;
+       }
+       pdata = marker_get_private_data(channel, mname, probe->probe_func, 0);
+       if (IS_ERR(pdata)) {
+               ret = PTR_ERR(pdata);
+               goto end;
+       } else if (!pdata) {
+               /*
+                * Not registered by us.
+                */
+               ret = -EPERM;
+               goto end;
+       }
+       ret = marker_probe_unregister(channel, mname, probe->probe_func, pdata);
+       if (ret)
+               goto end;
+       else {
+               list_del(&pdata->node);
+               kmem_cache_free(markers_loaded_cachep, pdata);
+       }
+end:
+       mutex_unlock(&probes_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ltt_marker_disconnect);
+
+static void disconnect_all_markers(void)
+{
+       struct ltt_active_marker *pdata, *tmp;
+
+       list_for_each_entry_safe(pdata, tmp, &markers_loaded_list, node) {
+               marker_probe_unregister_private_data(pdata->probe->probe_func,
+                       pdata);
+               list_del(&pdata->node);
+               kmem_cache_free(markers_loaded_cachep, pdata);
+       }
+}
+
+static int __init marker_control_init(void)
+{
+       int ret;
+
+       markers_loaded_cachep = KMEM_CACHE(ltt_active_marker, 0);
+
+       ret = ltt_probe_register(&default_probe);
+       BUG_ON(ret);
+       ret = ltt_marker_connect("metadata", "core_marker_format",
+                                DEFAULT_PROBE);
+       BUG_ON(ret);
+       ret = ltt_marker_connect("metadata", "core_marker_id", DEFAULT_PROBE);
+       BUG_ON(ret);
+
+       return 0;
+}
+module_init(marker_control_init);
+
+static void __exit marker_control_exit(void)
+{
+       int ret;
+
+       ret = ltt_marker_disconnect("metadata", "core_marker_format",
+                                   DEFAULT_PROBE);
+       BUG_ON(ret);
+       ret = ltt_marker_disconnect("metadata", "core_marker_id",
+                                   DEFAULT_PROBE);
+       BUG_ON(ret);
+       ret = ltt_probe_unregister(&default_probe);
+       BUG_ON(ret);
+       disconnect_all_markers();
+       kmem_cache_destroy(markers_loaded_cachep);
+       marker_synchronize_unregister();
+}
+module_exit(marker_control_exit);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Marker Control");
diff --git a/discard/ltt-serialize.c b/discard/ltt-serialize.c
new file mode 100644 (file)
index 0000000..50d7132
--- /dev/null
@@ -0,0 +1,968 @@
+/*
+ * LTTng serializing code.
+ *
+ * Copyright Mathieu Desnoyers, March 2007.
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ *
+ * See this discussion about weirdness about passing va_list and then va_list to
+ * functions. (related to array argument passing). va_list seems to be
+ * implemented as an array on x86_64, but not on i386... This is why we pass a
+ * va_list * to ltt_vtrace.
+ */
+
+#include <stdarg.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#include "ltt-tracer.h"
+
+enum ltt_type {
+       LTT_TYPE_SIGNED_INT,
+       LTT_TYPE_UNSIGNED_INT,
+       LTT_TYPE_STRING,
+       LTT_TYPE_NONE,
+};
+
+#define LTT_ATTRIBUTE_NETWORK_BYTE_ORDER (1<<1)
+
+/*
+ * Stack used to keep track of string length at size calculation, passed to
+ * string copy to handle racy input string updates.
+ * Can be used by any context; this is ensured by putting the stack position
+ * back to its original position after using it.
+ */
+#define TRACER_STACK_LEN       (PAGE_SIZE / sizeof(unsigned long))
+static DEFINE_PER_CPU(unsigned long [TRACER_STACK_LEN],
+                     tracer_stack);
+static DEFINE_PER_CPU(unsigned int, tracer_stack_pos);
+
+/*
+ * Inspired from vsnprintf
+ *
+ * The serialization format string supports the basic printf format strings.
+ * In addition, it defines new formats that can be used to serialize more
+ * complex/non portable data structures.
+ *
+ * Typical use:
+ *
+ * field_name %ctype
+ * field_name #tracetype %ctype
+ * field_name #tracetype %ctype1 %ctype2 ...
+ *
+ * A conversion is performed between format string types supported by GCC and
+ * the trace type requested. GCC type is used to perform type checking on format
+ * strings. Trace type is used to specify the exact binary representation
+ * in the trace. A mapping is done between one or more GCC types to one trace
+ * type. Sign extension, if required by the conversion, is performed following
+ * the trace type.
+ *
+ * If a gcc format is not declared with a trace format, the gcc format is
+ * also used as binary representation in the trace.
+ *
+ * Strings are supported with %s.
+ * A single tracetype (sequence) can take multiple c types as parameter.
+ *
+ * c types:
+ *
+ * see printf(3).
+ *
+ * Note: to write a uint32_t in a trace, the following expression is recommended
+ * si it can be portable:
+ *
+ * ("#4u%lu", (unsigned long)var)
+ *
+ * trace types:
+ *
+ * Serialization specific formats :
+ *
+ * Fixed size integers
+ * #1u     writes uint8_t
+ * #2u     writes uint16_t
+ * #4u     writes uint32_t
+ * #8u     writes uint64_t
+ * #1d     writes int8_t
+ * #2d     writes int16_t
+ * #4d     writes int32_t
+ * #8d     writes int64_t
+ * i.e.:
+ * #1u%lu #2u%lu #4d%lu #8d%lu #llu%hu #d%lu
+ *
+ * * Attributes:
+ *
+ * n:  (for network byte order)
+ * #ntracetype%ctype
+ *            is written in the trace in network byte order.
+ *
+ * i.e.: #bn4u%lu, #n%lu, #b%u
+ *
+ * TODO (eventually)
+ * Variable length sequence
+ * #a #tracetype1 #tracetype2 %array_ptr %elem_size %num_elems
+ *            In the trace:
+ *            #a specifies that this is a sequence
+ *            #tracetype1 is the type of elements in the sequence
+ *            #tracetype2 is the type of the element count
+ *            GCC input:
+ *            array_ptr is a pointer to an array that contains members of size
+ *            elem_size.
+ *            num_elems is the number of elements in the array.
+ * i.e.: #a #lu #lu %p %lu %u
+ *
+ * Callback
+ * #k         callback (taken from the probe data)
+ *            The following % arguments are exepected by the callback
+ *
+ * i.e.: #a #lu #lu #k %p
+ *
+ * Note: No conversion is done from floats to integers, nor from integers to
+ * floats between c types and trace types. float conversion from double to float
+ * or from float to double is also not supported.
+ *
+ * REMOVE
+ * %*b     expects sizeof(data), data
+ *         where sizeof(data) is 1, 2, 4 or 8
+ *
+ * Fixed length struct, union or array.
+ * FIXME: unable to extract those sizes statically.
+ * %*r     expects sizeof(*ptr), ptr
+ * %*.*r   expects sizeof(*ptr), __alignof__(*ptr), ptr
+ * struct and unions removed.
+ * Fixed length array:
+ * [%p]#a[len #tracetype]
+ * i.e.: [%p]#a[12 #lu]
+ *
+ * Variable length sequence
+ * %*.*:*v expects sizeof(*ptr), __alignof__(*ptr), elem_num, ptr
+ *         where elem_num is the number of elements in the sequence
+ */
+static inline
+const char *parse_trace_type(const char *fmt, char *trace_size,
+                            enum ltt_type *trace_type,
+                            unsigned long *attributes)
+{
+       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+                               /* 'z' support added 23/7/1999 S.H.    */
+                               /* 'z' changed to 'Z' --davidm 1/25/99 */
+                               /* 't' added for ptrdiff_t */
+
+       /* parse attributes. */
+repeat:
+       switch (*fmt) {
+       case 'n':
+               *attributes |= LTT_ATTRIBUTE_NETWORK_BYTE_ORDER;
+               ++fmt;
+               goto repeat;
+       }
+
+       /* get the conversion qualifier */
+       qualifier = -1;
+       if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+           *fmt == 'Z' || *fmt == 'z' || *fmt == 't' ||
+           *fmt == 'S' || *fmt == '1' || *fmt == '2' ||
+           *fmt == '4' || *fmt == 8) {
+               qualifier = *fmt;
+               ++fmt;
+               if (qualifier == 'l' && *fmt == 'l') {
+                       qualifier = 'L';
+                       ++fmt;
+               }
+       }
+
+       switch (*fmt) {
+       case 'c':
+               *trace_type = LTT_TYPE_UNSIGNED_INT;
+               *trace_size = sizeof(unsigned char);
+               goto parse_end;
+       case 's':
+               *trace_type = LTT_TYPE_STRING;
+               goto parse_end;
+       case 'p':
+               *trace_type = LTT_TYPE_UNSIGNED_INT;
+               *trace_size = sizeof(void *);
+               goto parse_end;
+       case 'd':
+       case 'i':
+               *trace_type = LTT_TYPE_SIGNED_INT;
+               break;
+       case 'o':
+       case 'u':
+       case 'x':
+       case 'X':
+               *trace_type = LTT_TYPE_UNSIGNED_INT;
+               break;
+       default:
+               if (!*fmt)
+                       --fmt;
+               goto parse_end;
+       }
+       switch (qualifier) {
+       case 'L':
+               *trace_size = sizeof(long long);
+               break;
+       case 'l':
+               *trace_size = sizeof(long);
+               break;
+       case 'Z':
+       case 'z':
+               *trace_size = sizeof(size_t);
+               break;
+       case 't':
+               *trace_size = sizeof(ptrdiff_t);
+               break;
+       case 'h':
+               *trace_size = sizeof(short);
+               break;
+       case '1':
+               *trace_size = sizeof(uint8_t);
+               break;
+       case '2':
+               *trace_size = sizeof(uint16_t);
+               break;
+       case '4':
+               *trace_size = sizeof(uint32_t);
+               break;
+       case '8':
+               *trace_size = sizeof(uint64_t);
+               break;
+       default:
+               *trace_size = sizeof(int);
+       }
+
+parse_end:
+       return fmt;
+}
+
+/*
+ * Restrictions:
+ * Field width and precision are *not* supported.
+ * %n not supported.
+ */
+static inline
+const char *parse_c_type(const char *fmt, char *c_size, enum ltt_type *c_type,
+                        char *outfmt)
+{
+       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+                               /* 'z' support added 23/7/1999 S.H.    */
+                               /* 'z' changed to 'Z' --davidm 1/25/99 */
+                               /* 't' added for ptrdiff_t */
+
+       /* process flags : ignore standard print formats for now. */
+repeat:
+       switch (*fmt) {
+       case '-':
+       case '+':
+       case ' ':
+       case '#':
+       case '0':
+               ++fmt;
+               goto repeat;
+       }
+
+       /* get the conversion qualifier */
+       qualifier = -1;
+       if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+           *fmt == 'Z' || *fmt == 'z' || *fmt == 't' ||
+           *fmt == 'S') {
+               qualifier = *fmt;
+               ++fmt;
+               if (qualifier == 'l' && *fmt == 'l') {
+                       qualifier = 'L';
+                       ++fmt;
+               }
+       }
+
+       if (outfmt) {
+               if (qualifier != -1)
+                       *outfmt++ = (char)qualifier;
+               *outfmt++ = *fmt;
+               *outfmt = 0;
+       }
+
+       switch (*fmt) {
+       case 'c':
+               *c_type = LTT_TYPE_UNSIGNED_INT;
+               *c_size = sizeof(unsigned char);
+               goto parse_end;
+       case 's':
+               *c_type = LTT_TYPE_STRING;
+               goto parse_end;
+       case 'p':
+               *c_type = LTT_TYPE_UNSIGNED_INT;
+               *c_size = sizeof(void *);
+               goto parse_end;
+       case 'd':
+       case 'i':
+               *c_type = LTT_TYPE_SIGNED_INT;
+               break;
+       case 'o':
+       case 'u':
+       case 'x':
+       case 'X':
+               *c_type = LTT_TYPE_UNSIGNED_INT;
+               break;
+       default:
+               if (!*fmt)
+                       --fmt;
+               goto parse_end;
+       }
+       switch (qualifier) {
+       case 'L':
+               *c_size = sizeof(long long);
+               break;
+       case 'l':
+               *c_size = sizeof(long);
+               break;
+       case 'Z':
+       case 'z':
+               *c_size = sizeof(size_t);
+               break;
+       case 't':
+               *c_size = sizeof(ptrdiff_t);
+               break;
+       case 'h':
+               *c_size = sizeof(short);
+               break;
+       default:
+               *c_size = sizeof(int);
+       }
+
+parse_end:
+       return fmt;
+}
+
+static inline
+size_t serialize_trace_data(struct ltt_chanbuf *buf, size_t buf_offset,
+                           char trace_size, enum ltt_type trace_type,
+                           char c_size, enum ltt_type c_type,
+                           unsigned int *stack_pos_ctx,
+                           int *largest_align,
+                           va_list *args)
+{
+       union {
+               unsigned long v_ulong;
+               uint64_t v_uint64;
+               struct {
+                       const char *s;
+                       size_t len;
+               } v_string;
+       } tmp;
+
+       /*
+        * Be careful about sign extension here.
+        * Sign extension is done with the destination (trace) type.
+        */
+       switch (trace_type) {
+       case LTT_TYPE_SIGNED_INT:
+               switch (c_size) {
+               case 1:
+                       tmp.v_ulong = (long)(int8_t)va_arg(*args, int);
+                       break;
+               case 2:
+                       tmp.v_ulong = (long)(int16_t)va_arg(*args, int);
+                       break;
+               case 4:
+                       tmp.v_ulong = (long)(int32_t)va_arg(*args, int);
+                       break;
+               case 8:
+                       tmp.v_uint64 = va_arg(*args, int64_t);
+                       break;
+               default:
+                       BUG();
+               }
+               break;
+       case LTT_TYPE_UNSIGNED_INT:
+               switch (c_size) {
+               case 1:
+                       tmp.v_ulong = (unsigned long)(uint8_t)va_arg(*args, unsigned int);
+                       break;
+               case 2:
+                       tmp.v_ulong = (unsigned long)(uint16_t)va_arg(*args, unsigned int);
+                       break;
+               case 4:
+                       tmp.v_ulong = (unsigned long)(uint32_t)va_arg(*args, unsigned int);
+                       break;
+               case 8:
+                       tmp.v_uint64 = va_arg(*args, uint64_t);
+                       break;
+               default:
+                       BUG();
+               }
+               break;
+       case LTT_TYPE_STRING:
+               tmp.v_string.s = va_arg(*args, const char *);
+               if ((unsigned long)tmp.v_string.s < PAGE_SIZE)
+                       tmp.v_string.s = "<NULL>";
+               if (!buf) {
+                       /*
+                        * Reserve tracer stack entry.
+                        */
+                       __get_cpu_var(tracer_stack_pos)++;
+                       WARN_ON_ONCE(__get_cpu_var(tracer_stack_pos)
+                                    > TRACER_STACK_LEN);
+                       barrier();
+                       __get_cpu_var(tracer_stack)[*stack_pos_ctx] =
+                                       strlen(tmp.v_string.s) + 1;
+               }
+               tmp.v_string.len = __get_cpu_var(tracer_stack)
+                                       [(*stack_pos_ctx)++];
+               if (buf)
+                       ltt_relay_strncpy(&buf->a, buf->a.chan, buf_offset,
+                                         tmp.v_string.s, tmp.v_string.len);
+               buf_offset += tmp.v_string.len;
+               goto copydone;
+       default:
+               BUG();
+       }
+
+       /*
+        * If trace_size is lower or equal to 4 bytes, there is no sign
+        * extension to do because we are already encoded in a long. Therefore,
+        * we can combine signed and unsigned ops. 4 bytes float also works
+        * with this, because we do a simple copy of 4 bytes into 4 bytes
+        * without manipulation (and we do not support conversion from integers
+        * to floats).
+        * It is also the case if c_size is 8 bytes, which is the largest
+        * possible integer.
+        */
+       if (ltt_get_alignment()) {
+               buf_offset += ltt_align(buf_offset, trace_size);
+               if (largest_align)
+                       *largest_align = max_t(int, *largest_align, trace_size);
+       }
+       if (trace_size <= 4 || c_size == 8) {
+               if (buf) {
+                       switch (trace_size) {
+                       case 1:
+                               if (c_size == 8)
+                                       ltt_relay_write(&buf->a, buf->a.chan,
+                                       buf_offset,
+                                       (uint8_t[]){ (uint8_t)tmp.v_uint64 },
+                                       sizeof(uint8_t));
+                               else
+                                       ltt_relay_write(&buf->a, buf->a.chan,
+                                       buf_offset,
+                                       (uint8_t[]){ (uint8_t)tmp.v_ulong },
+                                       sizeof(uint8_t));
+                               break;
+                       case 2:
+                               if (c_size == 8)
+                                       ltt_relay_write(&buf->a, buf->a.chan,
+                                       buf_offset,
+                                       (uint16_t[]){ (uint16_t)tmp.v_uint64 },
+                                       sizeof(uint16_t));
+                               else
+                                       ltt_relay_write(&buf->a, buf->a.chan,
+                                       buf_offset,
+                                       (uint16_t[]){ (uint16_t)tmp.v_ulong },
+                                       sizeof(uint16_t));
+                               break;
+                       case 4:
+                               if (c_size == 8)
+                                       ltt_relay_write(&buf->a, buf->a.chan,
+                                       buf_offset,
+                                       (uint32_t[]){ (uint32_t)tmp.v_uint64 },
+                                       sizeof(uint32_t));
+                               else
+                                       ltt_relay_write(&buf->a, buf->a.chan,
+                                       buf_offset,
+                                       (uint32_t[]){ (uint32_t)tmp.v_ulong },
+                                       sizeof(uint32_t));
+                               break;
+                       case 8:
+                               /*
+                                * c_size cannot be other than 8 here because
+                                * trace_size > 4.
+                                */
+                               ltt_relay_write(&buf->a, buf->a.chan, buf_offset,
+                               (uint64_t[]){ (uint64_t)tmp.v_uint64 },
+                               sizeof(uint64_t));
+                               break;
+                       default:
+                               BUG();
+                       }
+               }
+               buf_offset += trace_size;
+               goto copydone;
+       } else {
+               /*
+                * Perform sign extension.
+                */
+               if (buf) {
+                       switch (trace_type) {
+                       case LTT_TYPE_SIGNED_INT:
+                               ltt_relay_write(&buf->a, buf->a.chan, buf_offset,
+                                       (int64_t[]){ (int64_t)tmp.v_ulong },
+                                       sizeof(int64_t));
+                               break;
+                       case LTT_TYPE_UNSIGNED_INT:
+                               ltt_relay_write(&buf->a, buf->a.chan, buf_offset,
+                                       (uint64_t[]){ (uint64_t)tmp.v_ulong },
+                                       sizeof(uint64_t));
+                               break;
+                       default:
+                               BUG();
+                       }
+               }
+               buf_offset += trace_size;
+               goto copydone;
+       }
+
+copydone:
+       return buf_offset;
+}
+
+notrace size_t
+ltt_serialize_data(struct ltt_chanbuf *buf, size_t buf_offset,
+                  struct ltt_serialize_closure *closure,
+                  void *serialize_private, unsigned int stack_pos_ctx,
+                  int *largest_align, const char *fmt, va_list *args)
+{
+       char trace_size = 0, c_size = 0;        /*
+                                                * 0 (unset), 1, 2, 4, 8 bytes.
+                                                */
+       enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE;
+       unsigned long attributes = 0;
+
+       for (; *fmt ; ++fmt) {
+               switch (*fmt) {
+               case '#':
+                       /* tracetypes (#) */
+                       ++fmt;                  /* skip first '#' */
+                       if (*fmt == '#')        /* Escaped ## */
+                               break;
+                       attributes = 0;
+                       fmt = parse_trace_type(fmt, &trace_size, &trace_type,
+                                              &attributes);
+                       break;
+               case '%':
+                       /* c types (%) */
+                       ++fmt;                  /* skip first '%' */
+                       if (*fmt == '%')        /* Escaped %% */
+                               break;
+                       fmt = parse_c_type(fmt, &c_size, &c_type, NULL);
+                       /*
+                        * Output c types if no trace types has been
+                        * specified.
+                        */
+                       if (!trace_size)
+                               trace_size = c_size;
+                       if (trace_type == LTT_TYPE_NONE)
+                               trace_type = c_type;
+                       if (c_type == LTT_TYPE_STRING)
+                               trace_type = LTT_TYPE_STRING;
+                       /* perform trace write */
+                       buf_offset = serialize_trace_data(buf, buf_offset,
+                                                         trace_size,
+                                                         trace_type, c_size,
+                                                         c_type,
+                                                         &stack_pos_ctx,
+                                                         largest_align,
+                                                         args);
+                       trace_size = 0;
+                       c_size = 0;
+                       trace_type = LTT_TYPE_NONE;
+                       c_size = LTT_TYPE_NONE;
+                       attributes = 0;
+                       break;
+                       /* default is to skip the text, doing nothing */
+               }
+       }
+       return buf_offset;
+}
+EXPORT_SYMBOL_GPL(ltt_serialize_data);
+
+static inline
+uint64_t unserialize_base_type(struct ltt_chanbuf *buf,
+                              size_t *ppos, char trace_size,
+                              enum ltt_type trace_type)
+{
+       uint64_t tmp;
+
+       *ppos += ltt_align(*ppos, trace_size);
+       ltt_relay_read(&buf->a, *ppos, &tmp, trace_size);
+       *ppos += trace_size;
+
+       switch (trace_type) {
+       case LTT_TYPE_SIGNED_INT:
+               switch (trace_size) {
+               case 1:
+                       return (uint64_t)*(int8_t *)&tmp;
+               case 2:
+                       return (uint64_t)*(int16_t *)&tmp;
+               case 4:
+                       return (uint64_t)*(int32_t *)&tmp;
+               case 8:
+                       return tmp;
+               }
+               break;
+       case LTT_TYPE_UNSIGNED_INT:
+               switch (trace_size) {
+               case 1:
+                       return (uint64_t)*(uint8_t *)&tmp;
+               case 2:
+                       return (uint64_t)*(uint16_t *)&tmp;
+               case 4:
+                       return (uint64_t)*(uint32_t *)&tmp;
+               case 8:
+                       return tmp;
+               }
+               break;
+       default:
+               break;
+       }
+
+       BUG();
+       return 0;
+}
+
+static
+int serialize_printf_data(struct ltt_chanbuf *buf, size_t *ppos,
+                         char trace_size, enum ltt_type trace_type,
+                         char c_size, enum ltt_type c_type, char *output,
+                         ssize_t outlen, const char *outfmt)
+{
+       u64 value;
+       outlen = outlen < 0 ? 0 : outlen;
+
+       if (trace_type == LTT_TYPE_STRING) {
+               size_t len = ltt_relay_read_cstr(&buf->a, *ppos, output,
+                                                outlen);
+               *ppos += len + 1;
+               return len;
+       }
+
+       value = unserialize_base_type(buf, ppos, trace_size, trace_type);
+
+       if (c_size == 8)
+               return snprintf(output, outlen, outfmt, value);
+       else
+               return snprintf(output, outlen, outfmt, (unsigned int)value);
+}
+
+/**
+ * ltt_serialize_printf - Format a string and place it in a buffer
+ * @buf: The ltt-relay buffer that store binary data
+ * @buf_offset: binary data's offset in @buf (should be masked to use as offset)
+ * @msg_size: return message's length
+ * @output: The buffer to place the result into
+ * @outlen: The size of the buffer, including the trailing '\0'
+ * @fmt: The format string to use
+ *
+ * The return value is the number of characters which would
+ * be generated for the given input, excluding the trailing
+ * '\0', as per ISO C99. If the return is greater than or equal to @outlen,
+ * the resulting string is truncated.
+ */
+size_t ltt_serialize_printf(struct ltt_chanbuf *buf, unsigned long buf_offset,
+                           size_t *msg_size, char *output, size_t outlen,
+                           const char *fmt)
+{
+       char trace_size = 0, c_size = 0;        /*
+                                                * 0 (unset), 1, 2, 4, 8 bytes.
+                                                */
+       enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE;
+       unsigned long attributes = 0;
+       char outfmt[4] = "%";
+       size_t outpos = 0;
+       size_t len;
+       size_t msgpos = buf_offset;
+
+       for (; *fmt ; ++fmt) {
+               switch (*fmt) {
+               case '#':
+                       /* tracetypes (#) */
+                       ++fmt;                  /* skip first '#' */
+                       if (*fmt == '#') {      /* Escaped ## */
+                               if (outpos < outlen)
+                                       output[outpos] = '#';
+                               outpos++;
+                               break;
+                       }
+                       attributes = 0;
+                       fmt = parse_trace_type(fmt, &trace_size, &trace_type,
+                                              &attributes);
+                       break;
+               case '%':
+                       /* c types (%) */
+                       ++fmt;                  /* skip first '%' */
+                       if (*fmt == '%') {      /* Escaped %% */
+                               if (outpos < outlen)
+                                       output[outpos] = '%';
+                               outpos++;
+                               break;
+                       }
+                       fmt = parse_c_type(fmt, &c_size, &c_type, outfmt + 1);
+                       /*
+                        * Output c types if no trace types has been
+                        * specified.
+                        */
+                       if (!trace_size)
+                               trace_size = c_size;
+                       if (trace_type == LTT_TYPE_NONE)
+                               trace_type = c_type;
+                       if (c_type == LTT_TYPE_STRING)
+                               trace_type = LTT_TYPE_STRING;
+
+                       /* perform trace printf */
+                       len = serialize_printf_data(buf, &msgpos, trace_size,
+                                                   trace_type, c_size, c_type,
+                                                   output + outpos,
+                                                   outlen - outpos, outfmt);
+                       outpos += len;
+                       trace_size = 0;
+                       c_size = 0;
+                       trace_type = LTT_TYPE_NONE;
+                       c_size = LTT_TYPE_NONE;
+                       attributes = 0;
+                       break;
+               default:
+                       if (outpos < outlen)
+                               output[outpos] = *fmt;
+                       outpos++;
+                       break;
+               }
+       }
+       if (msg_size)
+               *msg_size = (size_t)(msgpos - buf_offset);
+       /*
+        * Make sure we end output with terminating \0 when truncated.
+        */
+       if (outpos >= outlen + 1)
+               output[outlen] = '\0';
+       return outpos;
+}
+EXPORT_SYMBOL_GPL(ltt_serialize_printf);
+
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+
+unsigned int ltt_fmt_largest_align(size_t align_drift, const char *fmt)
+{
+       char trace_size = 0, c_size = 0;
+       enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE;
+       unsigned long attributes = 0;
+       int largest_align = 1;
+
+       for (; *fmt ; ++fmt) {
+               switch (*fmt) {
+               case '#':
+                       /* tracetypes (#) */
+                       ++fmt;                  /* skip first '#' */
+                       if (*fmt == '#')        /* Escaped ## */
+                               break;
+                       attributes = 0;
+                       fmt = parse_trace_type(fmt, &trace_size, &trace_type,
+                                              &attributes);
+
+                       largest_align = max_t(int, largest_align, trace_size);
+                       if (largest_align >= ltt_get_alignment())
+                               goto exit;
+                       break;
+               case '%':
+                       /* c types (%) */
+                       ++fmt;                  /* skip first '%' */
+                       if (*fmt == '%')        /* Escaped %% */
+                               break;
+                       fmt = parse_c_type(fmt, &c_size, &c_type, NULL);
+                       /*
+                        * Output c types if no trace types has been
+                        * specified.
+                        */
+                       if (!trace_size)
+                               trace_size = c_size;
+                       if (trace_type == LTT_TYPE_NONE)
+                               trace_type = c_type;
+                       if (c_type == LTT_TYPE_STRING)
+                               trace_type = LTT_TYPE_STRING;
+
+                       largest_align = max_t(int, largest_align, trace_size);
+                       if (largest_align >= ltt_get_alignment())
+                               goto exit;
+
+                       trace_size = 0;
+                       c_size = 0;
+                       trace_type = LTT_TYPE_NONE;
+                       c_size = LTT_TYPE_NONE;
+                       break;
+               }
+       }
+
+exit:
+       largest_align = min_t(int, largest_align, ltt_get_alignment());
+       return (largest_align - align_drift) & (largest_align - 1);
+}
+EXPORT_SYMBOL_GPL(ltt_fmt_largest_align);
+
+#endif
+
+/*
+ * Calculate data size
+ * Assume that the padding for alignment starts at a sizeof(void *) address.
+ */
+static notrace
+size_t ltt_get_data_size(struct ltt_serialize_closure *closure,
+                        void *serialize_private, unsigned int stack_pos_ctx,
+                        int *largest_align, const char *fmt, va_list *args)
+{
+       ltt_serialize_cb cb = closure->callbacks[0];
+       closure->cb_idx = 0;
+       return (size_t)cb(NULL, 0, closure, serialize_private, stack_pos_ctx,
+                         largest_align, fmt, args);
+}
+
+static notrace
+void ltt_write_event_data(struct ltt_chanbuf *buf, size_t buf_offset,
+                         struct ltt_serialize_closure *closure,
+                         void *serialize_private, unsigned int stack_pos_ctx,
+                         int largest_align, const char *fmt, va_list *args)
+{
+       ltt_serialize_cb cb = closure->callbacks[0];
+       closure->cb_idx = 0;
+       buf_offset += ltt_align(buf_offset, largest_align);
+       cb(buf, buf_offset, closure, serialize_private, stack_pos_ctx, NULL,
+          fmt, args);
+}
+
+
+notrace
+void ltt_vtrace(const struct marker *mdata, void *probe_data, void *call_data,
+               const char *fmt, va_list *args)
+{
+       int largest_align, ret;
+       struct ltt_active_marker *pdata;
+       uint16_t eID;
+       size_t data_size, slot_size;
+       unsigned int chan_index;
+       struct ltt_chanbuf *buf;
+       struct ltt_chan *chan;
+       struct ltt_trace *trace, *dest_trace = NULL;
+       uint64_t tsc;
+       long buf_offset;
+       va_list args_copy;
+       struct ltt_serialize_closure closure;
+       struct ltt_probe_private_data *private_data = call_data;
+       void *serialize_private = NULL;
+       int cpu;
+       unsigned int rflags;
+       unsigned int stack_pos_ctx;
+
+       /*
+        * This test is useful for quickly exiting static tracing when no trace
+        * is active. We expect to have an active trace when we get here.
+        */
+       if (unlikely(ltt_traces.num_active_traces == 0))
+               return;
+
+       rcu_read_lock_sched_notrace();
+       cpu = smp_processor_id();
+       __get_cpu_var(ltt_nesting)++;
+       stack_pos_ctx = __get_cpu_var(tracer_stack_pos);
+       /*
+        * asm volatile and "memory" clobber prevent the compiler from moving
+        * instructions out of the ltt nesting count. This is required to ensure
+        * that probe side-effects which can cause recursion (e.g. unforeseen
+        * traps, divisions by 0, ...) are triggered within the incremented
+        * nesting count section.
+        */
+       barrier();
+       pdata = (struct ltt_active_marker *)probe_data;
+       eID = mdata->event_id;
+       chan_index = mdata->channel_id;
+       closure.callbacks = pdata->probe->callbacks;
+
+       if (unlikely(private_data)) {
+               dest_trace = private_data->trace;
+               if (private_data->serializer)
+                       closure.callbacks = &private_data->serializer;
+               serialize_private = private_data->serialize_private;
+       }
+
+       va_copy(args_copy, *args);
+       /*
+        * Assumes event payload to start on largest_align alignment.
+        */
+       largest_align = 1;      /* must be non-zero for ltt_align */
+       data_size = ltt_get_data_size(&closure, serialize_private,
+                                     stack_pos_ctx, &largest_align,
+                                     fmt, &args_copy);
+       largest_align = min_t(int, largest_align, sizeof(void *));
+       va_end(args_copy);
+
+       /* Iterate on each trace */
+       list_for_each_entry_rcu(trace, &ltt_traces.head, list) {
+               /*
+                * Expect the filter to filter out events. If we get here,
+                * we went through tracepoint activation as a first step.
+                */
+               if (unlikely(dest_trace && trace != dest_trace))
+                       continue;
+               if (unlikely(!trace->active))
+                       continue;
+               if (unlikely(!ltt_run_filter(trace, eID)))
+                       continue;
+#ifdef LTT_DEBUG_EVENT_SIZE
+               rflags = LTT_RFLAG_ID_SIZE;
+#else
+               if (unlikely(eID >= LTT_FREE_EVENTS))
+                       rflags = LTT_RFLAG_ID;
+               else
+                       rflags = 0;
+#endif
+               /*
+                * Skip channels added after trace creation.
+                */
+               if (unlikely(chan_index >= trace->nr_channels))
+                       continue;
+               chan = &trace->channels[chan_index];
+               if (!chan->active)
+                       continue;
+
+               /* reserve space : header and data */
+               ret = ltt_reserve_slot(chan, trace, data_size, largest_align,
+                                      cpu, &buf, &slot_size, &buf_offset,
+                                      &tsc, &rflags);
+               if (unlikely(ret < 0))
+                       continue; /* buffer full */
+
+               va_copy(args_copy, *args);
+               /* Out-of-order write : header and data */
+               buf_offset = ltt_write_event_header(&buf->a, &chan->a,
+                                                   buf_offset, eID, data_size,
+                                                   tsc, rflags);
+               ltt_write_event_data(buf, buf_offset, &closure,
+                                    serialize_private, stack_pos_ctx,
+                                    largest_align, fmt, &args_copy);
+               va_end(args_copy);
+               /* Out-of-order commit */
+               ltt_commit_slot(buf, chan, buf_offset, data_size, slot_size);
+       }
+       /*
+        * asm volatile and "memory" clobber prevent the compiler from moving
+        * instructions out of the ltt nesting count. This is required to ensure
+        * that probe side-effects which can cause recursion (e.g. unforeseen
+        * traps, divisions by 0, ...) are triggered within the incremented
+        * nesting count section.
+        */
+       barrier();
+       __get_cpu_var(tracer_stack_pos) = stack_pos_ctx;
+       __get_cpu_var(ltt_nesting)--;
+       rcu_read_unlock_sched_notrace();
+}
+EXPORT_SYMBOL_GPL(ltt_vtrace);
+
+notrace
+void ltt_trace(const struct marker *mdata, void *probe_data, void *call_data,
+              const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       ltt_vtrace(mdata, probe_data, call_data, fmt, &args);
+       va_end(args);
+}
+EXPORT_SYMBOL_GPL(ltt_trace);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Serializer");
diff --git a/discard/ltt-tracer.c b/discard/ltt-tracer.c
new file mode 100644 (file)
index 0000000..5cdea93
--- /dev/null
@@ -0,0 +1,1112 @@
+/*
+ * ltt/ltt-tracer.c
+ *
+ * Copyright (c) 2005-2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Tracing management internal kernel API. Trace buffer allocation/free, tracing
+ * start/stop.
+ *
+ * Author:
+ *     Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Inspired from LTT :
+ *  Karim Yaghmour (karim@opersys.com)
+ *  Tom Zanussi (zanussi@us.ibm.com)
+ *  Bob Wisniewski (bob@watson.ibm.com)
+ * And from K42 :
+ *  Bob Wisniewski (bob@watson.ibm.com)
+ *
+ * Changelog:
+ *  22/09/06, Move to the marker/probes mechanism.
+ *  19/10/05, Complete lockless mechanism.
+ *  27/05/05, Modular redesign and rewrite.
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#include <linux/time.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/rcupdate.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+#include <linux/cpu.h>
+#include <linux/kref.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <asm/atomic.h>
+
+#include "ltt-tracer.h"
+
+static void synchronize_trace(void)
+{
+       synchronize_sched();
+#ifdef CONFIG_PREEMPT_RT
+       synchronize_rcu();
+#endif
+}
+
+static void async_wakeup(unsigned long data);
+
+static DEFINE_TIMER(ltt_async_wakeup_timer, async_wakeup, 0, 0);
+
+/* Default callbacks for modules */
+notrace
+int ltt_filter_control_default(enum ltt_filter_control_msg msg,
+                              struct ltt_trace *trace)
+{
+       return 0;
+}
+
+int ltt_statedump_default(struct ltt_trace *trace)
+{
+       return 0;
+}
+
+/* Callbacks for registered modules */
+
+int (*ltt_filter_control_functor)
+       (enum ltt_filter_control_msg msg, struct ltt_trace *trace) =
+                                       ltt_filter_control_default;
+struct module *ltt_filter_control_owner;
+
+/* These function pointers are protected by a trace activation check */
+struct module *ltt_run_filter_owner;
+int (*ltt_statedump_functor)(struct ltt_trace *trace) = ltt_statedump_default;
+struct module *ltt_statedump_owner;
+
+struct chan_info_struct {
+       const char *name;
+       unsigned int def_sb_size;
+       unsigned int def_n_sb;
+} chan_infos[] = {
+       [LTT_CHANNEL_METADATA] = {
+               LTT_METADATA_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_FD_STATE] = {
+               LTT_FD_STATE_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_GLOBAL_STATE] = {
+               LTT_GLOBAL_STATE_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_IRQ_STATE] = {
+               LTT_IRQ_STATE_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_MODULE_STATE] = {
+               LTT_MODULE_STATE_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_NETIF_STATE] = {
+               LTT_NETIF_STATE_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_SOFTIRQ_STATE] = {
+               LTT_SOFTIRQ_STATE_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_SWAP_STATE] = {
+               LTT_SWAP_STATE_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_SYSCALL_STATE] = {
+               LTT_SYSCALL_STATE_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_TASK_STATE] = {
+               LTT_TASK_STATE_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_VM_STATE] = {
+               LTT_VM_STATE_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_MED,
+               LTT_DEFAULT_N_SUBBUFS_MED,
+       },
+       [LTT_CHANNEL_FS] = {
+               LTT_FS_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_MED,
+               LTT_DEFAULT_N_SUBBUFS_MED,
+       },
+       [LTT_CHANNEL_INPUT] = {
+               LTT_INPUT_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_IPC] = {
+               LTT_IPC_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_LOW,
+               LTT_DEFAULT_N_SUBBUFS_LOW,
+       },
+       [LTT_CHANNEL_KERNEL] = {
+               LTT_KERNEL_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_HIGH,
+               LTT_DEFAULT_N_SUBBUFS_HIGH,
+       },
+       [LTT_CHANNEL_MM] = {
+               LTT_MM_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_MED,
+               LTT_DEFAULT_N_SUBBUFS_MED,
+       },
+       [LTT_CHANNEL_RCU] = {
+               LTT_RCU_CHANNEL,
+               LTT_DEFAULT_SUBBUF_SIZE_MED,
+               LTT_DEFAULT_N_SUBBUFS_MED,
+       },
+       [LTT_CHANNEL_DEFAULT] = {
+               NULL,
+               LTT_DEFAULT_SUBBUF_SIZE_MED,
+               LTT_DEFAULT_N_SUBBUFS_MED,
+       },
+};
+
+static enum ltt_channels get_channel_type_from_name(const char *name)
+{
+       int i;
+
+       if (!name)
+               return LTT_CHANNEL_DEFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(chan_infos); i++)
+               if (chan_infos[i].name && !strcmp(name, chan_infos[i].name))
+                       return (enum ltt_channels)i;
+
+       return LTT_CHANNEL_DEFAULT;
+}
+
+/**
+ * ltt_module_register - LTT module registration
+ * @name: module type
+ * @function: callback to register
+ * @owner: module which owns the callback
+ *
+ * The module calling this registration function must ensure that no
+ * trap-inducing code will be executed by "function". E.g. vmalloc_sync_all()
+ * must be called between a vmalloc and the moment the memory is made visible to
+ * "function". This registration acts as a vmalloc_sync_all. Therefore, only if
+ * the module allocates virtual memory after its registration must it
+ * synchronize the TLBs.
+ */
+int ltt_module_register(enum ltt_module_function name, void *function,
+                       struct module *owner)
+{
+       int ret = 0;
+
+       /*
+        * Make sure no page fault can be triggered by the module about to be
+        * registered. We deal with this here so we don't have to call
+        * vmalloc_sync_all() in each module's init.
+        */
+       vmalloc_sync_all();
+
+       switch (name) {
+       case LTT_FUNCTION_RUN_FILTER:
+               if (ltt_run_filter_owner != NULL) {
+                       ret = -EEXIST;
+                       goto end;
+               }
+               ltt_filter_register((ltt_run_filter_functor)function);
+               ltt_run_filter_owner = owner;
+               break;
+       case LTT_FUNCTION_FILTER_CONTROL:
+               if (ltt_filter_control_owner != NULL) {
+                       ret = -EEXIST;
+                       goto end;
+               }
+               ltt_filter_control_functor =
+                       (int (*)(enum ltt_filter_control_msg,
+                       struct ltt_trace *))function;
+               ltt_filter_control_owner = owner;
+               break;
+       case LTT_FUNCTION_STATEDUMP:
+               if (ltt_statedump_owner != NULL) {
+                       ret = -EEXIST;
+                       goto end;
+               }
+               ltt_statedump_functor =
+                       (int (*)(struct ltt_trace *))function;
+               ltt_statedump_owner = owner;
+               break;
+       }
+end:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ltt_module_register);
+
+/**
+ * ltt_module_unregister - LTT module unregistration
+ * @name: module type
+ */
+void ltt_module_unregister(enum ltt_module_function name)
+{
+       switch (name) {
+       case LTT_FUNCTION_RUN_FILTER:
+               ltt_filter_unregister();
+               ltt_run_filter_owner = NULL;
+               /* Wait for preempt sections to finish */
+               synchronize_trace();
+               break;
+       case LTT_FUNCTION_FILTER_CONTROL:
+               ltt_filter_control_functor = ltt_filter_control_default;
+               ltt_filter_control_owner = NULL;
+               break;
+       case LTT_FUNCTION_STATEDUMP:
+               ltt_statedump_functor = ltt_statedump_default;
+               ltt_statedump_owner = NULL;
+               break;
+       }
+
+}
+EXPORT_SYMBOL_GPL(ltt_module_unregister);
+
+static LIST_HEAD(ltt_transport_list);
+
+/**
+ * ltt_transport_register - LTT transport registration
+ * @transport: transport structure
+ *
+ * Registers a transport which can be used as output to extract the data out of
+ * LTTng. The module calling this registration function must ensure that no
+ * trap-inducing code will be executed by the transport functions. E.g.
+ * vmalloc_sync_all() must be called between a vmalloc and the moment the memory
+ * is made visible to the transport function. This registration acts as a
+ * vmalloc_sync_all. Therefore, only if the module allocates virtual memory
+ * after its registration must it synchronize the TLBs.
+ */
+void ltt_transport_register(struct ltt_transport *transport)
+{
+       /*
+        * Make sure no page fault can be triggered by the module about to be
+        * registered. We deal with this here so we don't have to call
+        * vmalloc_sync_all() in each module's init.
+        */
+       vmalloc_sync_all();
+
+       ltt_lock_traces();
+       list_add_tail(&transport->node, &ltt_transport_list);
+       ltt_unlock_traces();
+}
+EXPORT_SYMBOL_GPL(ltt_transport_register);
+
+/**
+ * ltt_transport_unregister - LTT transport unregistration
+ * @transport: transport structure
+ */
+void ltt_transport_unregister(struct ltt_transport *transport)
+{
+       ltt_lock_traces();
+       list_del(&transport->node);
+       ltt_unlock_traces();
+}
+EXPORT_SYMBOL_GPL(ltt_transport_unregister);
+
+static inline
+int is_channel_overwrite(enum ltt_channels chan, enum trace_mode mode)
+{
+       switch (mode) {
+       case LTT_TRACE_NORMAL:
+               return 0;
+       case LTT_TRACE_FLIGHT:
+               switch (chan) {
+               case LTT_CHANNEL_METADATA:
+                       return 0;
+               default:
+                       return 1;
+               }
+       case LTT_TRACE_HYBRID:
+               switch (chan) {
+               case LTT_CHANNEL_KERNEL:
+               case LTT_CHANNEL_FS:
+               case LTT_CHANNEL_MM:
+               case LTT_CHANNEL_RCU:
+               case LTT_CHANNEL_IPC:
+               case LTT_CHANNEL_INPUT:
+                       return 1;
+               default:
+                       return 0;
+               }
+       default:
+               return 0;
+       }
+}
+
+/**
+ * _ltt_trace_find - find a trace by given name.
+ * trace_name: trace name
+ *
+ * Returns a pointer to the trace structure, NULL if not found.
+ */
+static struct ltt_trace *_ltt_trace_find(const char *trace_name)
+{
+       struct ltt_trace *trace;
+
+       list_for_each_entry(trace, &ltt_traces.head, list)
+               if (!strncmp(trace->trace_name, trace_name, NAME_MAX))
+                       return trace;
+
+       return NULL;
+}
+
+/* _ltt_trace_find_setup :
+ * find a trace in setup list by given name.
+ *
+ * Returns a pointer to the trace structure, NULL if not found.
+ */
+struct ltt_trace *_ltt_trace_find_setup(const char *trace_name)
+{
+       struct ltt_trace *trace;
+
+       list_for_each_entry(trace, &ltt_traces.setup_head, list)
+               if (!strncmp(trace->trace_name, trace_name, NAME_MAX))
+                       return trace;
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(_ltt_trace_find_setup);
+
+/**
+ * ltt_release_trace - Release a LTT trace
+ * @kref : reference count on the trace
+ */
+void ltt_release_trace(struct kref *kref)
+{
+       struct ltt_trace *trace = container_of(kref, struct ltt_trace, kref);
+
+       trace->ops->remove_dirs(trace);
+       module_put(trace->transport->owner);
+       ltt_channels_trace_free(trace);
+       kfree(trace);
+}
+EXPORT_SYMBOL_GPL(ltt_release_trace);
+
+static inline void prepare_chan_size_num(unsigned int *subbuf_size,
+                                        unsigned int *n_subbufs)
+{
+       /* Make sure the subbuffer size is larger than a page */
+       *subbuf_size = max_t(unsigned int, *subbuf_size, PAGE_SIZE);
+
+       /* round to next power of 2 */
+       *subbuf_size = 1 << get_count_order(*subbuf_size);
+       *n_subbufs = 1 << get_count_order(*n_subbufs);
+
+       /* Subbuf size and number must both be power of two */
+       WARN_ON(hweight32(*subbuf_size) != 1);
+       WARN_ON(hweight32(*n_subbufs) != 1);
+}
+
+int _ltt_trace_setup(const char *trace_name)
+{
+       int err = 0;
+       struct ltt_trace *new_trace = NULL;
+       int metadata_index;
+       unsigned int chan;
+       enum ltt_channels chantype;
+
+       if (_ltt_trace_find_setup(trace_name)) {
+               printk(KERN_ERR "LTT : Trace name %s already used.\n",
+                               trace_name);
+               err = -EEXIST;
+               goto traces_error;
+       }
+
+       if (_ltt_trace_find(trace_name)) {
+               printk(KERN_ERR "LTT : Trace name %s already used.\n",
+                               trace_name);
+               err = -EEXIST;
+               goto traces_error;
+       }
+
+       new_trace = kzalloc(sizeof(struct ltt_trace), GFP_KERNEL);
+       if (!new_trace) {
+               printk(KERN_ERR
+                       "LTT : Unable to allocate memory for trace %s\n",
+                       trace_name);
+               err = -ENOMEM;
+               goto traces_error;
+       }
+       strncpy(new_trace->trace_name, trace_name, NAME_MAX);
+       if (ltt_channels_trace_alloc(&new_trace->nr_channels, 0)) {
+               printk(KERN_ERR
+                       "LTT : Unable to allocate memory for chaninfo  %s\n",
+                       trace_name);
+               err = -ENOMEM;
+               goto trace_free;
+       }
+
+       /*
+        * Force metadata channel to no overwrite.
+        */
+       metadata_index = ltt_channels_get_index_from_name("metadata");
+       WARN_ON(metadata_index < 0);
+       new_trace->settings[metadata_index].overwrite = 0;
+
+       /*
+        * Set hardcoded tracer defaults for some channels
+        */
+       for (chan = 0; chan < new_trace->nr_channels; chan++) {
+               chantype = get_channel_type_from_name(
+                       ltt_channels_get_name_from_index(chan));
+               new_trace->settings[chan].sb_size =
+                       chan_infos[chantype].def_sb_size;
+               new_trace->settings[chan].n_sb =
+                       chan_infos[chantype].def_n_sb;
+       }
+
+       list_add(&new_trace->list, &ltt_traces.setup_head);
+       return 0;
+
+trace_free:
+       kfree(new_trace);
+traces_error:
+       return err;
+}
+EXPORT_SYMBOL_GPL(_ltt_trace_setup);
+
+
+int ltt_trace_setup(const char *trace_name)
+{
+       int ret;
+       ltt_lock_traces();
+       ret = _ltt_trace_setup(trace_name);
+       ltt_unlock_traces();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ltt_trace_setup);
+
+/* must be called from within a traces lock. */
+static void _ltt_trace_free(struct ltt_trace *trace)
+{
+       list_del(&trace->list);
+       kfree(trace);
+}
+
+int ltt_trace_set_type(const char *trace_name, const char *trace_type)
+{
+       int err = 0;
+       struct ltt_trace *trace;
+       struct ltt_transport *tran_iter, *transport = NULL;
+
+       ltt_lock_traces();
+
+       trace = _ltt_trace_find_setup(trace_name);
+       if (!trace) {
+               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
+               err = -ENOENT;
+               goto traces_error;
+       }
+
+       list_for_each_entry(tran_iter, &ltt_transport_list, node) {
+               if (!strcmp(tran_iter->name, trace_type)) {
+                       transport = tran_iter;
+                       break;
+               }
+       }
+       if (!transport) {
+               printk(KERN_ERR "LTT : Transport %s is not present.\n",
+                       trace_type);
+               err = -EINVAL;
+               goto traces_error;
+       }
+
+       trace->transport = transport;
+
+traces_error:
+       ltt_unlock_traces();
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_trace_set_type);
+
+int ltt_trace_set_channel_subbufsize(const char *trace_name,
+                                    const char *channel_name,
+                                    unsigned int size)
+{
+       int err = 0;
+       struct ltt_trace *trace;
+       int index;
+
+       ltt_lock_traces();
+
+       trace = _ltt_trace_find_setup(trace_name);
+       if (!trace) {
+               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
+               err = -ENOENT;
+               goto traces_error;
+       }
+
+       index = ltt_channels_get_index_from_name(channel_name);
+       if (index < 0) {
+               printk(KERN_ERR "LTT : Channel %s not found\n", channel_name);
+               err = -ENOENT;
+               goto traces_error;
+       }
+       trace->settings[index].sb_size = size;
+
+traces_error:
+       ltt_unlock_traces();
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_trace_set_channel_subbufsize);
+
+int ltt_trace_set_channel_subbufcount(const char *trace_name,
+                                     const char *channel_name,
+                                     unsigned int cnt)
+{
+       int err = 0;
+       struct ltt_trace *trace;
+       int index;
+
+       ltt_lock_traces();
+
+       trace = _ltt_trace_find_setup(trace_name);
+       if (!trace) {
+               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
+               err = -ENOENT;
+               goto traces_error;
+       }
+
+       index = ltt_channels_get_index_from_name(channel_name);
+       if (index < 0) {
+               printk(KERN_ERR "LTT : Channel %s not found\n", channel_name);
+               err = -ENOENT;
+               goto traces_error;
+       }
+       trace->settings[index].n_sb = cnt;
+
+traces_error:
+       ltt_unlock_traces();
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_trace_set_channel_subbufcount);
+
+int ltt_trace_set_channel_switch_timer(const char *trace_name,
+                                      const char *channel_name,
+                                      unsigned long interval)
+{
+       int err = 0;
+       struct ltt_trace *trace;
+       int index;
+
+       ltt_lock_traces();
+
+       trace = _ltt_trace_find_setup(trace_name);
+       if (!trace) {
+               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
+               err = -ENOENT;
+               goto traces_error;
+       }
+
+       index = ltt_channels_get_index_from_name(channel_name);
+       if (index < 0) {
+               printk(KERN_ERR "LTT : Channel %s not found\n", channel_name);
+               err = -ENOENT;
+               goto traces_error;
+       }
+       ltt_channels_trace_set_timer(&trace->settings[index], interval);
+
+traces_error:
+       ltt_unlock_traces();
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_trace_set_channel_switch_timer);
+
+int ltt_trace_set_channel_overwrite(const char *trace_name,
+                                   const char *channel_name,
+                                   unsigned int overwrite)
+{
+       int err = 0;
+       struct ltt_trace *trace;
+       int index;
+
+       ltt_lock_traces();
+
+       trace = _ltt_trace_find_setup(trace_name);
+       if (!trace) {
+               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
+               err = -ENOENT;
+               goto traces_error;
+       }
+
+       /*
+        * Always put the metadata channel in non-overwrite mode :
+        * This is a very low traffic channel and it can't afford to have its
+        * data overwritten : this data (marker info) is necessary to be
+        * able to read the trace.
+        */
+       if (overwrite && !strcmp(channel_name, "metadata")) {
+               printk(KERN_ERR "LTT : Trying to set metadata channel to "
+                               "overwrite mode\n");
+               err = -EINVAL;
+               goto traces_error;
+       }
+
+       index = ltt_channels_get_index_from_name(channel_name);
+       if (index < 0) {
+               printk(KERN_ERR "LTT : Channel %s not found\n", channel_name);
+               err = -ENOENT;
+               goto traces_error;
+       }
+
+       trace->settings[index].overwrite = overwrite;
+
+traces_error:
+       ltt_unlock_traces();
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_trace_set_channel_overwrite);
+
+int ltt_trace_alloc(const char *trace_name)
+{
+       int err = 0;
+       struct ltt_trace *trace;
+       int sb_size, n_sb;
+       unsigned long flags;
+       int chan;
+       const char *channel_name;
+
+       ltt_lock_traces();
+
+       trace = _ltt_trace_find_setup(trace_name);
+       if (!trace) {
+               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
+               err = -ENOENT;
+               goto traces_error;
+       }
+
+       kref_init(&trace->kref);
+       init_waitqueue_head(&trace->kref_wq);
+       trace->active = 0;
+       get_trace_clock();
+       trace->freq_scale = trace_clock_freq_scale();
+
+       if (!trace->transport) {
+               printk(KERN_ERR "LTT : Transport is not set.\n");
+               err = -EINVAL;
+               goto transport_error;
+       }
+       if (!try_module_get(trace->transport->owner)) {
+               printk(KERN_ERR "LTT : Can't lock transport module.\n");
+               err = -ENODEV;
+               goto transport_error;
+       }
+       trace->ops = &trace->transport->ops;
+
+       err = trace->ops->create_dirs(trace);
+       if (err) {
+               printk(KERN_ERR "LTT : Can't create dir for trace %s.\n",
+                       trace_name);
+               goto dirs_error;
+       }
+
+       local_irq_save(flags);
+       trace->start_freq = trace_clock_frequency();
+       trace->start_tsc = trace_clock_read64();
+       do_gettimeofday(&trace->start_time);
+       local_irq_restore(flags);
+
+       for (chan = 0; chan < trace->nr_channels; chan++) {
+               channel_name = ltt_channels_get_name_from_index(chan);
+               WARN_ON(!channel_name);
+               /*
+                * note: sb_size and n_sb will be overwritten with updated
+                * values by channel creation.
+                */
+               sb_size = trace->settings[chan].sb_size;
+               n_sb = trace->settings[chan].n_sb;
+               prepare_chan_size_num(&sb_size, &n_sb);
+               trace->channels[chan] = ltt_create_channel(channel_name,
+                                             trace, NULL, sb_size, n_sb,
+                                             trace->settings[chan].overwrite,
+                                             trace->settings[chan].switch_timer_interval,
+                                             trace->settings[chan].read_timer_interval);
+               if (err != 0) {
+                       printk(KERN_ERR "LTT : Can't create channel %s.\n",
+                               channel_name);
+                       goto create_channel_error;
+               }
+       }
+
+       list_del(&trace->list);
+       if (list_empty(&ltt_traces.head))
+               set_kernel_trace_flag_all_tasks();
+       list_add_rcu(&trace->list, &ltt_traces.head);
+       synchronize_trace();
+
+       ltt_unlock_traces();
+
+       return 0;
+
+create_channel_error:
+       for (chan--; chan >= 0; chan--)
+               ltt_channel_destroy(trace->channels[chan]);
+       trace->ops->remove_dirs(trace);
+
+dirs_error:
+       module_put(trace->transport->owner);
+transport_error:
+       put_trace_clock();
+traces_error:
+       ltt_unlock_traces();
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_trace_alloc);
+
+/*
+ * It is worked as a wrapper for current version of ltt_control.ko.
+ * We will make a new ltt_control based on debugfs, and control each channel's
+ * buffer.
+ */
+static
+int ltt_trace_create(const char *trace_name, const char *trace_type,
+                    enum trace_mode mode,
+                    unsigned int subbuf_size_low, unsigned int n_subbufs_low,
+                    unsigned int subbuf_size_med, unsigned int n_subbufs_med,
+                    unsigned int subbuf_size_high, unsigned int n_subbufs_high)
+{
+       int err = 0;
+
+       err = ltt_trace_setup(trace_name);
+       if (IS_ERR_VALUE(err))
+               return err;
+
+       err = ltt_trace_set_type(trace_name, trace_type);
+       if (IS_ERR_VALUE(err))
+               return err;
+
+       err = ltt_trace_alloc(trace_name);
+       if (IS_ERR_VALUE(err))
+               return err;
+
+       return err;
+}
+
+/* Must be called while sure that trace is in the list. */
+static int _ltt_trace_destroy(struct ltt_trace *trace)
+{
+       int err = -EPERM;
+
+       if (trace == NULL) {
+               err = -ENOENT;
+               goto traces_error;
+       }
+       if (trace->active) {
+               printk(KERN_ERR
+                       "LTT : Can't destroy trace %s : tracer is active\n",
+                       trace->trace_name);
+               err = -EBUSY;
+               goto active_error;
+       }
+       /* Everything went fine */
+       list_del_rcu(&trace->list);
+       synchronize_trace();
+       if (list_empty(&ltt_traces.head)) {
+               clear_kernel_trace_flag_all_tasks();
+       }
+       return 0;
+
+       /* error handling */
+active_error:
+traces_error:
+       return err;
+}
+
+/* Sleepable part of the destroy */
+static void __ltt_trace_destroy(struct ltt_trace *trace)
+{
+       int i;
+
+       for (i = 0; i < trace->nr_channels; i++)
+               ltt_channel_destroy(trace->channels[i]);
+       kref_put(&trace->kref, ltt_release_trace);
+}
+
+int ltt_trace_destroy(const char *trace_name)
+{
+       int err = 0;
+       struct ltt_trace *trace;
+
+       ltt_lock_traces();
+
+       trace = _ltt_trace_find(trace_name);
+       if (trace) {
+               err = _ltt_trace_destroy(trace);
+               if (err)
+                       goto error;
+
+               __ltt_trace_destroy(trace);
+               ltt_unlock_traces();
+               put_trace_clock();
+
+               return 0;
+       }
+
+       trace = _ltt_trace_find_setup(trace_name);
+       if (trace) {
+               _ltt_trace_free(trace);
+               ltt_unlock_traces();
+               return 0;
+       }
+
+       err = -ENOENT;
+
+       /* Error handling */
+error:
+       ltt_unlock_traces();
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_trace_destroy);
+
+/* must be called from within a traces lock. */
+static int _ltt_trace_start(struct ltt_trace *trace)
+{
+       int err = 0;
+
+       if (trace == NULL) {
+               err = -ENOENT;
+               goto traces_error;
+       }
+       if (trace->active)
+               printk(KERN_INFO "LTT : Tracing already active for trace %s\n",
+                               trace->trace_name);
+       if (!try_module_get(ltt_run_filter_owner)) {
+               err = -ENODEV;
+               printk(KERN_ERR "LTT : Can't lock filter module.\n");
+               goto get_ltt_run_filter_error;
+       }
+       trace->active = 1;
+       /* Read by trace points without protection : be careful */
+       ltt_traces.num_active_traces++;
+       return err;
+
+       /* error handling */
+get_ltt_run_filter_error:
+traces_error:
+       return err;
+}
+
+int ltt_trace_start(const char *trace_name)
+{
+       int err = 0;
+       struct ltt_trace *trace;
+
+       ltt_lock_traces();
+
+       trace = _ltt_trace_find(trace_name);
+       err = _ltt_trace_start(trace);
+       if (err)
+               goto no_trace;
+
+       ltt_unlock_traces();
+
+       /*
+        * Call the kernel state dump.
+        * Events will be mixed with real kernel events, it's ok.
+        * Notice that there is no protection on the trace : that's exactly
+        * why we iterate on the list and check for trace equality instead of
+        * directly using this trace handle inside the logging function.
+        */
+
+       ltt_dump_marker_state(trace);
+
+       if (!try_module_get(ltt_statedump_owner)) {
+               err = -ENODEV;
+               printk(KERN_ERR
+                       "LTT : Can't lock state dump module.\n");
+       } else {
+               ltt_statedump_functor(trace);
+               module_put(ltt_statedump_owner);
+       }
+
+       return err;
+
+       /* Error handling */
+no_trace:
+       ltt_unlock_traces();
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_trace_start);
+
+/* must be called from within traces lock */
+static int _ltt_trace_stop(struct ltt_trace *trace)
+{
+       int err = -EPERM;
+
+       if (trace == NULL) {
+               err = -ENOENT;
+               goto traces_error;
+       }
+       if (!trace->active)
+               printk(KERN_INFO "LTT : Tracing not active for trace %s\n",
+                               trace->trace_name);
+       if (trace->active) {
+               trace->active = 0;
+               ltt_traces.num_active_traces--;
+               synchronize_trace(); /* Wait for each tracing to be finished */
+       }
+       module_put(ltt_run_filter_owner);
+       /* Everything went fine */
+       return 0;
+
+       /* Error handling */
+traces_error:
+       return err;
+}
+
+int ltt_trace_stop(const char *trace_name)
+{
+       int err = 0;
+       struct ltt_trace *trace;
+
+       ltt_lock_traces();
+       trace = _ltt_trace_find(trace_name);
+       err = _ltt_trace_stop(trace);
+       ltt_unlock_traces();
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_trace_stop);
+
+/**
+ * ltt_control - Trace control in-kernel API
+ * @msg: Action to perform
+ * @trace_name: Trace on which the action must be done
+ * @trace_type: Type of trace (normal, flight, hybrid)
+ * @args: Arguments specific to the action
+ */
+int ltt_control(enum ltt_control_msg msg, const char *trace_name,
+               const char *trace_type, union ltt_control_args args)
+{
+       int err = -EPERM;
+
+       printk(KERN_ALERT "ltt_control : trace %s\n", trace_name);
+       switch (msg) {
+       case LTT_CONTROL_START:
+               printk(KERN_DEBUG "Start tracing %s\n", trace_name);
+               err = ltt_trace_start(trace_name);
+               break;
+       case LTT_CONTROL_STOP:
+               printk(KERN_DEBUG "Stop tracing %s\n", trace_name);
+               err = ltt_trace_stop(trace_name);
+               break;
+       case LTT_CONTROL_CREATE_TRACE:
+               printk(KERN_DEBUG "Creating trace %s\n", trace_name);
+               err = ltt_trace_create(trace_name, trace_type,
+                       args.new_trace.mode,
+                       args.new_trace.subbuf_size_low,
+                       args.new_trace.n_subbufs_low,
+                       args.new_trace.subbuf_size_med,
+                       args.new_trace.n_subbufs_med,
+                       args.new_trace.subbuf_size_high,
+                       args.new_trace.n_subbufs_high);
+               break;
+       case LTT_CONTROL_DESTROY_TRACE:
+               printk(KERN_DEBUG "Destroying trace %s\n", trace_name);
+               err = ltt_trace_destroy(trace_name);
+               break;
+       }
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_control);
+
+/**
+ * ltt_filter_control - Trace filter control in-kernel API
+ * @msg: Action to perform on the filter
+ * @trace_name: Trace on which the action must be done
+ */
+int ltt_filter_control(enum ltt_filter_control_msg msg, const char *trace_name)
+{
+       int err;
+       struct ltt_trace *trace;
+
+       printk(KERN_DEBUG "ltt_filter_control : trace %s\n", trace_name);
+       ltt_lock_traces();
+       trace = _ltt_trace_find(trace_name);
+       if (trace == NULL) {
+               printk(KERN_ALERT
+                       "Trace does not exist. Cannot proxy control request\n");
+               err = -ENOENT;
+               goto trace_error;
+       }
+       if (!try_module_get(ltt_filter_control_owner)) {
+               err = -ENODEV;
+               goto get_module_error;
+       }
+       switch (msg) {
+       case LTT_FILTER_DEFAULT_ACCEPT:
+               printk(KERN_DEBUG
+                       "Proxy filter default accept %s\n", trace_name);
+               err = (*ltt_filter_control_functor)(msg, trace);
+               break;
+       case LTT_FILTER_DEFAULT_REJECT:
+               printk(KERN_DEBUG
+                       "Proxy filter default reject %s\n", trace_name);
+               err = (*ltt_filter_control_functor)(msg, trace);
+               break;
+       default:
+               err = -EPERM;
+       }
+       module_put(ltt_filter_control_owner);
+
+get_module_error:
+trace_error:
+       ltt_unlock_traces();
+       return err;
+}
+EXPORT_SYMBOL_GPL(ltt_filter_control);
+
+int __init ltt_init(void)
+{
+       /* Make sure no page fault can be triggered by this module */
+       vmalloc_sync_all();
+       init_timer_deferrable(&ltt_async_wakeup_timer);
+       return 0;
+}
+
+module_init(ltt_init)
+
+static void __exit ltt_exit(void)
+{
+       struct ltt_trace *trace;
+       struct list_head *pos, *n;
+
+       ltt_lock_traces();
+       /* Stop each trace, currently being read by RCU read-side */
+       list_for_each_entry_rcu(trace, &ltt_traces.head, list)
+               _ltt_trace_stop(trace);
+       /* Wait for quiescent state. Readers have preemption disabled. */
+       synchronize_trace();
+       /* Safe iteration is now permitted. It does not have to be RCU-safe
+        * because no readers are left. */
+       list_for_each_safe(pos, n, &ltt_traces.head) {
+               trace = container_of(pos, struct ltt_trace, list);
+               /* _ltt_trace_destroy does a synchronize_trace() */
+               _ltt_trace_destroy(trace);
+               __ltt_trace_destroy(trace);
+       }
+       /* free traces in pre-alloc status */
+       list_for_each_safe(pos, n, &ltt_traces.setup_head) {
+               trace = container_of(pos, struct ltt_trace, list);
+               _ltt_trace_free(trace);
+       }
+
+       ltt_unlock_traces();
+}
+
+module_exit(ltt_exit)
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Tracer Kernel API");
diff --git a/discard/ltt-type-serializer.c b/discard/ltt-type-serializer.c
new file mode 100644 (file)
index 0000000..ed589c7
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+ * ltt-type-serializer.c
+ *
+ * LTTng specialized type serializer.
+ *
+ * Copyright Mathieu Desnoyers, 2008.
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+#include <linux/module.h>
+
+#include "ltt-type-serializer.h"
+#include "ltt-relay-lockless.h"
+
+notrace
+void _ltt_specialized_trace(void *probe_data,
+               void *serialize_private, unsigned int data_size,
+               unsigned int largest_align)
+{
+       struct ltt_event *event = probe_data;
+       int ret;
+       uint16_t eID;
+       size_t slot_size;
+       struct ltt_chanbuf *buf;
+       struct ltt_channel *chan;
+       struct ltt_session *session;
+       uint64_t tsc;
+       long buf_offset;
+       int cpu;
+       unsigned int rflags;
+
+       /* disabled from tracepoints rcu_read_lock_sched_notrace(); */
+       cpu = smp_processor_id();
+       __get_cpu_var(ltt_nesting)++;
+       /*
+        * asm volatile and "memory" clobber prevent the compiler from moving
+        * instructions out of the ltt nesting count. This is required to ensure
+        * that probe side-effects which can cause recursion (e.g. unforeseen
+        * traps, divisions by 0, ...) are triggered within the incremented
+        * nesting count section.
+        */
+       barrier();
+       eID = event->id;
+       chan = event->chan;
+       session = chan->session;
+
+       if (unlikely(!session->active))
+               goto skip;
+       if (unlikely(!ltt_run_filter(session, chan, event)))
+               goto skip;
+#ifdef LTT_DEBUG_EVENT_SIZE
+       rflags = LTT_RFLAG_ID_SIZE;
+#else
+       if (unlikely(eID >= LTT_FREE_EVENTS))
+               rflags = LTT_RFLAG_ID;
+       else
+               rflags = 0;
+#endif
+       /* reserve space : header and data */
+       ret = ltt_reserve_slot(chan, trace, data_size, largest_align,
+                              cpu, &buf, &slot_size, &buf_offset, &tsc,
+                              &rflags);
+       if (unlikely(ret < 0))
+               goto skip; /* buffer full */
+
+       /* Out-of-order write : header and data */
+       buf_offset = ltt_write_event_header(&buf->a, &chan->a,
+                                           buf_offset, eID, data_size,
+                                           tsc, rflags);
+       if (data_size) {
+               buf_offset += ltt_align(buf_offset, largest_align);
+               ltt_relay_write(&buf->a, &chan->a, buf_offset,
+                               serialize_private, data_size);
+               buf_offset += data_size;
+       }
+       /* Out-of-order commit */
+       ltt_commit_slot(buf, chan, buf_offset, data_size, slot_size);
+skip:
+       /*
+        * asm volatile and "memory" clobber prevent the compiler from moving
+        * instructions out of the ltt nesting count. This is required to ensure
+        * that probe side-effects which can cause recursion (e.g. unforeseen
+        * traps, divisions by 0, ...) are triggered within the incremented
+        * nesting count section.
+        */
+       barrier();
+       __get_cpu_var(ltt_nesting)--;
+       /* disabled from tracepoints rcu_read_unlock_sched_notrace(); */
+}
+EXPORT_SYMBOL_GPL(_ltt_specialized_trace);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("LTT type serializer");
diff --git a/discard/ltt-type-serializer.h b/discard/ltt-type-serializer.h
new file mode 100644 (file)
index 0000000..fb870c8
--- /dev/null
@@ -0,0 +1,186 @@
+#ifndef _LTT_TYPE_SERIALIZER_H
+#define _LTT_TYPE_SERIALIZER_H
+
+#include <linux/if.h>  /* For IFNAMSIZ */
+
+#include "ltt-tracer.h"
+
+/*
+ * largest_align must be non-zero, equal to the minimum between the largest type
+ * and sizeof(void *).
+ */
+extern void _ltt_specialized_trace(void *probe_data,
+               void *serialize_private, unsigned int data_size,
+               unsigned int largest_align);
+
+/*
+ * Statically check that 0 < largest_align < sizeof(void *) to make sure it is
+ * dumb-proof. It will make sure 0 is changed into 1 and unsigned long long is
+ * changed into sizeof(void *) on 32-bit architectures.
+ */
+static inline void ltt_specialized_trace(void *probe_data,
+               void *serialize_private, unsigned int data_size,
+               unsigned int largest_align)
+{
+       largest_align = min_t(unsigned int, largest_align, sizeof(void *));
+       largest_align = max_t(unsigned int, largest_align, 1);
+       _ltt_specialized_trace(probe_data, serialize_private, data_size,
+               largest_align);
+}
+
+/*
+ * Type serializer definitions.
+ */
+
+/*
+ * Return size of structure without end-of-structure padding.
+ */
+#define serialize_sizeof(type) offsetof(typeof(type), end_field)
+
+struct serialize_long_int {
+       unsigned long f1;
+       unsigned int f2;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_int_int_long {
+       unsigned int f1;
+       unsigned int f2;
+       unsigned long f3;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_int_int_short {
+       unsigned int f1;
+       unsigned int f2;
+       unsigned short f3;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_long_long_long {
+       unsigned long f1;
+       unsigned long f2;
+       unsigned long f3;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_long_long_int {
+       unsigned long f1;
+       unsigned long f2;
+       unsigned int f3;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_long_long_short_char {
+       unsigned long f1;
+       unsigned long f2;
+       unsigned short f3;
+       unsigned char f4;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_long_long_short {
+       unsigned long f1;
+       unsigned long f2;
+       unsigned short f3;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_long_short_char {
+       unsigned long f1;
+       unsigned short f2;
+       unsigned char f3;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_long_short {
+       unsigned long f1;
+       unsigned short f2;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_long_char {
+       unsigned long f1;
+       unsigned char f2;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_long_ifname {
+       unsigned long f1;
+       unsigned char f2[IFNAMSIZ];
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_sizet_int {
+       size_t f1;
+       unsigned int f2;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_long_long_sizet_int {
+       unsigned long f1;
+       unsigned long f2;
+       size_t f3;
+       unsigned int f4;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_long_long_sizet_int_int {
+       unsigned long f1;
+       unsigned long f2;
+       size_t f3;
+       unsigned int f4;
+       unsigned int f5;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_l4421224411111 {
+       unsigned long f1;
+       uint32_t f2;
+       uint32_t f3;
+       uint16_t f4;
+       uint8_t f5;
+       uint16_t f6;
+       uint16_t f7;
+       uint32_t f8;
+       uint32_t f9;
+       uint8_t f10;
+       uint8_t f11;
+       uint8_t f12;
+       uint8_t f13;
+       uint8_t f14;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_l214421224411111 {
+       unsigned long f1;
+       uint16_t f2;
+       uint8_t f3;
+       uint32_t f4;
+       uint32_t f5;
+       uint16_t f6;
+       uint8_t f7;
+       uint16_t f8;
+       uint16_t f9;
+       uint32_t f10;
+       uint32_t f11;
+       uint8_t f12;
+       uint8_t f13;
+       uint8_t f14;
+       uint8_t f15;
+       uint8_t f16;
+       uint8_t end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+
+struct serialize_l4412228 {
+       unsigned long f1;
+       uint32_t f2;
+       uint32_t f3;
+       uint8_t f4;
+       uint16_t f5;
+       uint16_t f6;
+       uint16_t f7;
+       uint64_t f8;
+       unsigned char end_field[0];
+} RING_BUFFER_ALIGN_ATTR;
+#endif /* _LTT_TYPE_SERIALIZER_H */
index 1a0424e95c39bf6ea385662a7dd85f199cc0ea59..fc55bdfffc1d2b2651c4b1fb48469f8c0fa50d13 100644 (file)
 
 #include "ltt-tracer-core.h"
 
-/* Traces structures */
-struct ltt_traces ltt_traces = {
-       .setup_head = LIST_HEAD_INIT(ltt_traces.setup_head),
-       .head = LIST_HEAD_INIT(ltt_traces.head),
-};
-EXPORT_SYMBOL(ltt_traces);
-
-/* Traces list writer locking */
-static DEFINE_MUTEX(ltt_traces_mutex);
-
-/* root dentry mutex */
-static DEFINE_MUTEX(ltt_root_mutex);
-/* dentry of ltt's root dir */
-static struct dentry *ltt_root_dentry;
-static struct kref ltt_root_kref = {
-       .refcount = ATOMIC_INIT(0),
-};
-
-static void ltt_root_release(struct kref *ref)
-{
-       debugfs_remove(ltt_root_dentry);
-       ltt_root_dentry = NULL;
-}
-
-void put_ltt_root(void)
-{
-       mutex_lock(&ltt_root_mutex);
-       if (ltt_root_dentry)
-               kref_put(&ltt_root_kref, ltt_root_release);
-       mutex_unlock(&ltt_root_mutex);
-}
-EXPORT_SYMBOL_GPL(put_ltt_root);
-
-struct dentry *get_ltt_root(void)
-{
-       mutex_lock(&ltt_root_mutex);
-       if (!ltt_root_dentry) {
-               ltt_root_dentry = debugfs_create_dir(LTT_ROOT, NULL);
-               if (!ltt_root_dentry) {
-                       printk(KERN_ERR "LTT : create ltt root dir failed\n");
-                       goto out;
-               }
-               kref_init(&ltt_root_kref);
-               goto out;
-       }
-       kref_get(&ltt_root_kref);
-out:
-       mutex_unlock(&ltt_root_mutex);
-       return ltt_root_dentry;
-}
-EXPORT_SYMBOL_GPL(get_ltt_root);
-
-/*
- * ltt_lock_traces/ltt_unlock_traces also disables cpu hotplug.
- */
-void ltt_lock_traces(void)
-{
-       mutex_lock(&ltt_traces_mutex);
-       get_online_cpus();
-}
-EXPORT_SYMBOL_GPL(ltt_lock_traces);
-
-void ltt_unlock_traces(void)
-{
-       put_online_cpus();
-       mutex_unlock(&ltt_traces_mutex);
-}
-EXPORT_SYMBOL_GPL(ltt_unlock_traces);
-
-DEFINE_PER_CPU(unsigned int, ltt_nesting);
-EXPORT_PER_CPU_SYMBOL(ltt_nesting);
-
-int ltt_run_filter_default(void *trace, uint16_t eID)
+int ltt_run_filter_default(struct ltt_session *session,
+                          struct ltt_channel *chan,
+                          struct ltt_event *event)
 {
        return 1;
 }
index a10236134a287a47207825fbb3bd49d831168600..7fb7339205d5c99ff413d081ec50549606a526c6 100644 (file)
@@ -53,7 +53,7 @@ int lttng_abi_create_session(void)
        session = ltt_session_create();
        if (!session)
                return -ENOMEM;
-       session_fd = get_unused_fd_flags(O_RDWR);
+       session_fd = get_unused_fd();
        if (session_fd < 0) {
                ret = session_fd;
                goto fd_error;
@@ -119,7 +119,7 @@ int lttng_abi_create_channel(struct file *session_file,
 
        if (copy_from_user(&chan_param, uchan_param, sizeof(chan_param)))
                return -EFAULT;
-       chan_fd = get_unused_fd_flags(O_RDWR);
+       chan_fd = get_unused_fd();
        if (chan_fd < 0) {
                ret = chan_fd;
                goto fd_error;
@@ -226,7 +226,7 @@ int lttng_abi_open_stream(struct file *channel_file)
        if (!buf)
                return -ENOENT;
 
-       stream_fd = get_unused_fd_flags(O_RDWR);
+       stream_fd = get_unused_fd();
        if (stream_fd < 0) {
                ret = stream_fd;
                goto fd_error;
@@ -271,7 +271,7 @@ int lttng_abi_create_event(struct file *channel_file,
                goto name_error;
        }
        event_name[PATH_MAX - 1] = '\0';
-       event_fd = get_unused_fd_flags(O_RDWR);
+       event_fd = get_unused_fd();
        if (event_fd < 0) {
                ret = event_fd;
                goto fd_error;
@@ -401,7 +401,7 @@ static const struct file_operations lttng_event_fops = {
        .release = lttng_event_release,
 };
 
-static int __init ltt_debugfs_abi_init(void)
+int __init ltt_debugfs_abi_init(void)
 {
        int ret = 0;
 
@@ -416,15 +416,7 @@ error:
        return ret;
 }
 
-module_init(ltt_debugfs_abi_init);
-
-static void __exit ltt_debugfs_abi_exit(void)
+void __exit ltt_debugfs_abi_exit(void)
 {
        debugfs_remove(lttng_dentry);
 }
-
-module_exit(ltt_debugfs_abi_exit);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers");
-MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation DebugFS ABI");
index 94e29cbc3402492fcb1196951159608694847479..d2739fcbdfec28108bb67700adb5bdc8b44ea514 100644 (file)
 #include <linux/module.h>
 #include "ltt-tracer.h"
 
-size_t ltt_write_event_header_slow(const struct lib_ring_buffer_config *config,
+void ltt_write_event_header_slow(const struct lib_ring_buffer_config *config,
                                   struct lib_ring_buffer_ctx *ctx,
                                   u16 eID, u32 event_size)
 {
        struct event_header header;
        u16 small_size;
 
-       switch (rflags) {
+       switch (ctx->rflags) {
        case LTT_RFLAG_ID_SIZE_TSC:
                header.id_time = 29 << LTT_TSC_BITS;
                break;
@@ -36,10 +36,10 @@ size_t ltt_write_event_header_slow(const struct lib_ring_buffer_config *config,
                header.id_time = 0;
        }
 
-       header.id_time |= (u32)tsc & LTT_TSC_MASK;
+       header.id_time |= (u32)ctx->tsc & LTT_TSC_MASK;
        lib_ring_buffer_write(config, ctx, &header, sizeof(header));
 
-       switch (rflags) {
+       switch (ctx->rflags) {
        case LTT_RFLAG_ID_SIZE_TSC:
                small_size = (u16)min_t(u32, event_size, LTT_MAX_SMALL_SIZE);
                lib_ring_buffer_write(config, ctx, &eID, sizeof(u16));
@@ -64,7 +64,3 @@ size_t ltt_write_event_header_slow(const struct lib_ring_buffer_config *config,
        }
 }
 EXPORT_SYMBOL_GPL(ltt_write_event_header_slow);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers");
-MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Event Header");
index 7c7cda6525a4250379521ddf40b4a4bcce389dc2..f3f7ab78152bb31ac624cbe0f3553d2c292d92a5 100644 (file)
@@ -263,10 +263,18 @@ EXPORT_SYMBOL_GPL(ltt_transport_unregister);
 
 static int __init ltt_events_init(void)
 {
+       int ret;
+
        event_cache = KMEM_CACHE(ltt_event, 0);
        if (!event_cache)
                return -ENOMEM;
+       ret = ltt_debugfs_abi_init();
+       if (ret)
+               goto error;
        return 0;
+error:
+       kmem_cache_destroy(event_cache);
+       return ret;
 }
 
 module_init(ltt_events_init);
@@ -275,6 +283,7 @@ static void __exit ltt_events_exit(void)
 {
        struct ltt_session *session, *tmpsession;
 
+       ltt_debugfs_abi_exit();
        list_for_each_entry_safe(session, tmpsession, &sessions, list)
                ltt_session_destroy(session);
        kmem_cache_destroy(event_cache);
index 6711341c86f60ac7d13eb952d706a0174b9a062e..0d68e16ae4111c15b190dd75d7360cd34aa01d0e 100644 (file)
@@ -14,6 +14,7 @@
 
 struct ltt_channel;
 struct ltt_session;
+struct lib_ring_buffer_ctx;
 
 /*
  * ltt_event structure is referred to by the tracing fast path. It must be
@@ -38,7 +39,9 @@ struct ltt_channel_ops {
                                unsigned int read_timer_interval);
        void (*channel_destroy)(struct channel *chan);
        struct lib_ring_buffer *(*buffer_read_open)(struct channel *chan);
-       struct lib_ring_buffer *(*buffer_read_close)(struct lib_ring_buffer *buf);
+       void (*buffer_read_close)(struct lib_ring_buffer *buf);
+       int (*event_reserve)(struct lib_ring_buffer_ctx *ctx);
+       void (*event_commit)(struct lib_ring_buffer_ctx *ctx);
 };
 
 struct ltt_channel {
@@ -88,4 +91,7 @@ int _ltt_event_destroy(struct ltt_event *event);
 void ltt_transport_register(struct ltt_transport *transport);
 void ltt_transport_unregister(struct ltt_transport *transport);
 
+int ltt_debugfs_abi_init(void);
+void ltt_debugfs_abi_exit(void);
+
 #endif /* _LTT_EVENTS_H */
diff --git a/ltt-marker-control.c b/ltt-marker-control.c
deleted file mode 100644 (file)
index 6142430..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2007 Mathieu Desnoyers
- *
- * Dual LGPL v2.1/GPL v2 license.
- */
-
-#include <linux/module.h>
-#include <linux/stat.h>
-#include <linux/vmalloc.h>
-#include <linux/marker.h>
-#include <linux/uaccess.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-
-#include "ltt-tracer.h"
-
-#define DEFAULT_CHANNEL "cpu"
-#define DEFAULT_PROBE "default"
-
-LIST_HEAD(probes_list);
-
-/*
- * Mutex protecting the probe slab cache.
- * Nests inside the traces mutex.
- */
-DEFINE_MUTEX(probes_mutex);
-
-struct ltt_available_probe default_probe = {
-       .name = "default",
-       .format = NULL,
-       .probe_func = ltt_vtrace,
-       .callbacks[0] = ltt_serialize_data,
-};
-
-static struct kmem_cache *markers_loaded_cachep;
-static LIST_HEAD(markers_loaded_list);
-/*
- * List sorted by name strcmp order.
- */
-static LIST_HEAD(probes_registered_list);
-
-static struct ltt_available_probe *get_probe_from_name(const char *pname)
-{
-       struct ltt_available_probe *iter;
-       int comparison, found = 0;
-
-       if (!pname)
-               pname = DEFAULT_PROBE;
-       list_for_each_entry(iter, &probes_registered_list, node) {
-               comparison = strcmp(pname, iter->name);
-               if (!comparison)
-                       found = 1;
-               if (comparison <= 0)
-                       break;
-       }
-       if (found)
-               return iter;
-       else
-               return NULL;
-}
-
-int ltt_probe_register(struct ltt_available_probe *pdata)
-{
-       int ret = 0;
-       int comparison;
-       struct ltt_available_probe *iter;
-
-       mutex_lock(&probes_mutex);
-       list_for_each_entry_reverse(iter, &probes_registered_list, node) {
-               comparison = strcmp(pdata->name, iter->name);
-               if (!comparison) {
-                       ret = -EBUSY;
-                       goto end;
-               } else if (comparison > 0) {
-                       /* We belong to the location right after iter. */
-                       list_add(&pdata->node, &iter->node);
-                       goto end;
-               }
-       }
-       /* Should be added at the head of the list */
-       list_add(&pdata->node, &probes_registered_list);
-end:
-       mutex_unlock(&probes_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(ltt_probe_register);
-
-/*
- * Called when a probe does not want to be called anymore.
- */
-int ltt_probe_unregister(struct ltt_available_probe *pdata)
-{
-       int ret = 0;
-       struct ltt_active_marker *amark, *tmp;
-
-       mutex_lock(&probes_mutex);
-       list_for_each_entry_safe(amark, tmp, &markers_loaded_list, node) {
-               if (amark->probe == pdata) {
-                       ret = marker_probe_unregister_private_data(
-                               pdata->probe_func, amark);
-                       if (ret)
-                               goto end;
-                       list_del(&amark->node);
-                       kmem_cache_free(markers_loaded_cachep, amark);
-               }
-       }
-       list_del(&pdata->node);
-end:
-       mutex_unlock(&probes_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(ltt_probe_unregister);
-
-/*
- * Connect marker "mname" to probe "pname".
- * Only allow _only_ probe instance to be connected to a marker.
- */
-int ltt_marker_connect(const char *channel, const char *mname,
-                      const char *pname)
-
-{
-       int ret;
-       struct ltt_active_marker *pdata;
-       struct ltt_available_probe *probe;
-
-       ltt_lock_traces();
-       mutex_lock(&probes_mutex);
-       probe = get_probe_from_name(pname);
-       if (!probe) {
-               ret = -ENOENT;
-               goto end;
-       }
-       pdata = marker_get_private_data(channel, mname, probe->probe_func, 0);
-       if (pdata && !IS_ERR(pdata)) {
-               ret = -EEXIST;
-               goto end;
-       }
-       pdata = kmem_cache_zalloc(markers_loaded_cachep, GFP_KERNEL);
-       if (!pdata) {
-               ret = -ENOMEM;
-               goto end;
-       }
-       pdata->probe = probe;
-       /*
-        * ID has priority over channel in case of conflict.
-        */
-       ret = marker_probe_register(channel, mname, NULL,
-               probe->probe_func, pdata);
-       if (ret)
-               kmem_cache_free(markers_loaded_cachep, pdata);
-       else
-               list_add(&pdata->node, &markers_loaded_list);
-end:
-       mutex_unlock(&probes_mutex);
-       ltt_unlock_traces();
-       return ret;
-}
-EXPORT_SYMBOL_GPL(ltt_marker_connect);
-
-/*
- * Disconnect marker "mname", probe "pname".
- */
-int ltt_marker_disconnect(const char *channel, const char *mname,
-                         const char *pname)
-{
-       struct ltt_active_marker *pdata;
-       struct ltt_available_probe *probe;
-       int ret = 0;
-
-       mutex_lock(&probes_mutex);
-       probe = get_probe_from_name(pname);
-       if (!probe) {
-               ret = -ENOENT;
-               goto end;
-       }
-       pdata = marker_get_private_data(channel, mname, probe->probe_func, 0);
-       if (IS_ERR(pdata)) {
-               ret = PTR_ERR(pdata);
-               goto end;
-       } else if (!pdata) {
-               /*
-                * Not registered by us.
-                */
-               ret = -EPERM;
-               goto end;
-       }
-       ret = marker_probe_unregister(channel, mname, probe->probe_func, pdata);
-       if (ret)
-               goto end;
-       else {
-               list_del(&pdata->node);
-               kmem_cache_free(markers_loaded_cachep, pdata);
-       }
-end:
-       mutex_unlock(&probes_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(ltt_marker_disconnect);
-
-static void disconnect_all_markers(void)
-{
-       struct ltt_active_marker *pdata, *tmp;
-
-       list_for_each_entry_safe(pdata, tmp, &markers_loaded_list, node) {
-               marker_probe_unregister_private_data(pdata->probe->probe_func,
-                       pdata);
-               list_del(&pdata->node);
-               kmem_cache_free(markers_loaded_cachep, pdata);
-       }
-}
-
-static int __init marker_control_init(void)
-{
-       int ret;
-
-       markers_loaded_cachep = KMEM_CACHE(ltt_active_marker, 0);
-
-       ret = ltt_probe_register(&default_probe);
-       BUG_ON(ret);
-       ret = ltt_marker_connect("metadata", "core_marker_format",
-                                DEFAULT_PROBE);
-       BUG_ON(ret);
-       ret = ltt_marker_connect("metadata", "core_marker_id", DEFAULT_PROBE);
-       BUG_ON(ret);
-
-       return 0;
-}
-module_init(marker_control_init);
-
-static void __exit marker_control_exit(void)
-{
-       int ret;
-
-       ret = ltt_marker_disconnect("metadata", "core_marker_format",
-                                   DEFAULT_PROBE);
-       BUG_ON(ret);
-       ret = ltt_marker_disconnect("metadata", "core_marker_id",
-                                   DEFAULT_PROBE);
-       BUG_ON(ret);
-       ret = ltt_probe_unregister(&default_probe);
-       BUG_ON(ret);
-       disconnect_all_markers();
-       kmem_cache_destroy(markers_loaded_cachep);
-       marker_synchronize_unregister();
-}
-module_exit(marker_control_exit);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers");
-MODULE_DESCRIPTION("Linux Trace Toolkit Marker Control");
index 93c793ff0218de72acd8b5154acfe78875c0fe62..229c06aab31fde8f7daae1b9bab283e6fb364fb2 100644 (file)
@@ -34,29 +34,29 @@ size_t client_record_header_size(const struct lib_ring_buffer_config *config,
 }
 
 /**
- * client_subbuffer_header_size - called on buffer-switch to a new sub-buffer
+ * client_packet_header_size - called on buffer-switch to a new sub-buffer
  *
  * Return header size without padding after the structure. Don't use packed
  * structure because gcc generates inefficient code on some architectures
  * (powerpc, mips..)
  */
-static size_t client_subbuffer_header_size(void)
+static size_t client_packet_header_size(void)
 {
-       return offsetof(struct subbuffer_header, header_end);
+       return offsetof(struct packet_header, header_end);
 }
 
 static void client_buffer_begin(struct lib_ring_buffer *buf, u64 tsc,
                                unsigned int subbuf_idx)
 {
        struct channel *chan = buf->backend.chan;
-       struct subbuffer_header *header =
-               (struct subbuffer_header *)
+       struct packet_header *header =
+               (struct packet_header *)
                        lib_ring_buffer_offset_address(&buf->backend,
                                subbuf_idx * chan->backend.subbuf_size);
 
-       header->cycle_count_begin = tsc;
-       header->data_size = 0xFFFFFFFF; /* for debugging */
-       write_trace_header(chan->backend.priv, header);
+       header->timestamp_begin = tsc;
+       header->content_size = 0xFFFFFFFF; /* for debugging */
+       write_trace_header(&client_config, header);
 }
 
 /*
@@ -67,25 +67,25 @@ static void client_buffer_end(struct lib_ring_buffer *buf, u64 tsc,
                              unsigned int subbuf_idx, unsigned long data_size)
 {
        struct channel *chan = buf->backend.chan;
-       struct subbuffer_header *header =
-               (struct subbuffer_header *)
+       struct packet_header *header =
+               (struct packet_header *)
                        lib_ring_buffer_offset_address(&buf->backend,
                                subbuf_idx * chan->backend.subbuf_size);
        unsigned long records_lost = 0;
 
-       header->data_size = data_size;
-       header->subbuf_size = PAGE_ALIGN(data_size);
-       header->cycle_count_end = tsc;
+       header->content_size = data_size;
+       header->packet_size = PAGE_ALIGN(data_size);
+       header->timestamp_end = tsc;
        records_lost += lib_ring_buffer_get_records_lost_full(&client_config, buf);
        records_lost += lib_ring_buffer_get_records_lost_wrap(&client_config, buf);
        records_lost += lib_ring_buffer_get_records_lost_big(&client_config, buf);
        header->events_lost = records_lost;
-       header->subbuf_corrupt = 0;     /* deprecated */
 }
 
 static int client_buffer_create(struct lib_ring_buffer *buf, void *priv,
                                int cpu, const char *name)
 {
+       return 0;
 }
 
 static void client_buffer_finalize(struct lib_ring_buffer *buf, void *priv, int cpu)
@@ -95,7 +95,7 @@ static void client_buffer_finalize(struct lib_ring_buffer *buf, void *priv, int
 static const struct lib_ring_buffer_config client_config = {
        .cb.ring_buffer_clock_read = client_ring_buffer_clock_read,
        .cb.record_header_size = client_record_header_size,
-       .cb.subbuffer_header_size = client_subbuffer_header_size,
+       .cb.subbuffer_header_size = client_packet_header_size,
        .cb.buffer_begin = client_buffer_begin,
        .cb.buffer_end = client_buffer_end,
        .cb.buffer_create = client_buffer_create,
@@ -118,12 +118,13 @@ static const struct lib_ring_buffer_config client_config = {
 };
 
 static
-struct channel *ltt_channel_create(struct ltt_session *session, void *buf_addr,
-                                  size_t subbuf_size, size_t num_subbuf,
-                                  unsigned int switch_timer_interval,
-                                  unsigned int read_timer_interval)
+struct channel *_channel_create(const char *name,
+                               struct ltt_session *session, void *buf_addr,
+                               size_t subbuf_size, size_t num_subbuf,
+                               unsigned int switch_timer_interval,
+                               unsigned int read_timer_interval)
 {
-       return channel_create(&client_config, "[lttng]", session, buf_addr,
+       return channel_create(&client_config, name, session, buf_addr,
                              subbuf_size, num_subbuf, switch_timer_interval,
                              read_timer_interval);
 }
@@ -140,8 +141,8 @@ struct lib_ring_buffer *ltt_buffer_read_open(struct channel *chan)
        struct lib_ring_buffer *buf;
        int cpu;
 
-       for_each_channel_cpu(cpu, chan->chan) {
-               buf = channel_get_ring_buffer(&config_config, chan, cpu);
+       for_each_channel_cpu(cpu, chan) {
+               buf = channel_get_ring_buffer(&client_config, chan, cpu);
                if (!lib_ring_buffer_open_read(buf))
                        return buf;
        }
@@ -149,19 +150,48 @@ struct lib_ring_buffer *ltt_buffer_read_open(struct channel *chan)
 }
 
 static
-struct lib_ring_buffer *ltt_buffer_read_close(struct lib_ring_buffer *buf)
+void ltt_buffer_read_close(struct lib_ring_buffer *buf)
 {
        lib_ring_buffer_release_read(buf);
+       
+}
+
+int ltt_event_reserve(struct lib_ring_buffer_ctx *ctx)
+{
+       int ret, cpu;
+
+       cpu = lib_ring_buffer_get_cpu(&client_config);
+       if (cpu < 0)
+               return -EPERM;
+       ctx->cpu = cpu;
+
+       ret = lib_ring_buffer_reserve(&client_config, ctx);
+       if (ret)
+               goto put;
+       return ret;
+
+put:
+       lib_ring_buffer_put_cpu(&client_config);
+       return ret;
 }
 
+void ltt_event_commit(struct lib_ring_buffer_ctx *ctx)
+{
+       lib_ring_buffer_commit(&client_config, ctx);
+       lib_ring_buffer_put_cpu(&client_config);
+}
+
+
 static struct ltt_transport ltt_relay_transport = {
        .name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING,
        .owner = THIS_MODULE,
        .ops = {
-               .create_channel = ltt_channel_create,
-               .destroy_channel = ltt_channel_destroy,
+               .channel_create = _channel_create,
+               .channel_destroy = ltt_channel_destroy,
                .buffer_read_open = ltt_buffer_read_open,
                .buffer_read_close = ltt_buffer_read_close,
+               .event_reserve = ltt_event_reserve,
+               .event_commit = ltt_event_commit,
        },
 };
 
@@ -172,12 +202,16 @@ static int __init ltt_ring_buffer_client_init(void)
        return 0;
 }
 
+module_init(ltt_ring_buffer_client_init);
+
 static void __exit ltt_ring_buffer_client_exit(void)
 {
        printk(KERN_INFO "LTT : ltt ring buffer client exit\n");
        ltt_transport_unregister(&ltt_relay_transport);
 }
 
+module_exit(ltt_ring_buffer_client_exit);
+
 MODULE_LICENSE("GPL and additional rights");
 MODULE_AUTHOR("Mathieu Desnoyers");
 MODULE_DESCRIPTION("LTTng ring buffer " RING_BUFFER_MODE_TEMPLATE_STRING
diff --git a/ltt-serialize.c b/ltt-serialize.c
deleted file mode 100644 (file)
index 1d5a5df..0000000
+++ /dev/null
@@ -1,969 +0,0 @@
-/*
- * LTTng serializing code.
- *
- * Copyright Mathieu Desnoyers, March 2007.
- *
- * Dual LGPL v2.1/GPL v2 license.
- *
- * See this discussion about weirdness about passing va_list and then va_list to
- * functions. (related to array argument passing). va_list seems to be
- * implemented as an array on x86_64, but not on i386... This is why we pass a
- * va_list * to ltt_vtrace.
- */
-
-#include <stdarg.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/module.h>
-
-#include "ltt-tracer.h"
-#include "ltt-relay-lockless.h"
-
-enum ltt_type {
-       LTT_TYPE_SIGNED_INT,
-       LTT_TYPE_UNSIGNED_INT,
-       LTT_TYPE_STRING,
-       LTT_TYPE_NONE,
-};
-
-#define LTT_ATTRIBUTE_NETWORK_BYTE_ORDER (1<<1)
-
-/*
- * Stack used to keep track of string length at size calculation, passed to
- * string copy to handle racy input string updates.
- * Can be used by any context; this is ensured by putting the stack position
- * back to its original position after using it.
- */
-#define TRACER_STACK_LEN       (PAGE_SIZE / sizeof(unsigned long))
-static DEFINE_PER_CPU(unsigned long [TRACER_STACK_LEN],
-                     tracer_stack);
-static DEFINE_PER_CPU(unsigned int, tracer_stack_pos);
-
-/*
- * Inspired from vsnprintf
- *
- * The serialization format string supports the basic printf format strings.
- * In addition, it defines new formats that can be used to serialize more
- * complex/non portable data structures.
- *
- * Typical use:
- *
- * field_name %ctype
- * field_name #tracetype %ctype
- * field_name #tracetype %ctype1 %ctype2 ...
- *
- * A conversion is performed between format string types supported by GCC and
- * the trace type requested. GCC type is used to perform type checking on format
- * strings. Trace type is used to specify the exact binary representation
- * in the trace. A mapping is done between one or more GCC types to one trace
- * type. Sign extension, if required by the conversion, is performed following
- * the trace type.
- *
- * If a gcc format is not declared with a trace format, the gcc format is
- * also used as binary representation in the trace.
- *
- * Strings are supported with %s.
- * A single tracetype (sequence) can take multiple c types as parameter.
- *
- * c types:
- *
- * see printf(3).
- *
- * Note: to write a uint32_t in a trace, the following expression is recommended
- * si it can be portable:
- *
- * ("#4u%lu", (unsigned long)var)
- *
- * trace types:
- *
- * Serialization specific formats :
- *
- * Fixed size integers
- * #1u     writes uint8_t
- * #2u     writes uint16_t
- * #4u     writes uint32_t
- * #8u     writes uint64_t
- * #1d     writes int8_t
- * #2d     writes int16_t
- * #4d     writes int32_t
- * #8d     writes int64_t
- * i.e.:
- * #1u%lu #2u%lu #4d%lu #8d%lu #llu%hu #d%lu
- *
- * * Attributes:
- *
- * n:  (for network byte order)
- * #ntracetype%ctype
- *            is written in the trace in network byte order.
- *
- * i.e.: #bn4u%lu, #n%lu, #b%u
- *
- * TODO (eventually)
- * Variable length sequence
- * #a #tracetype1 #tracetype2 %array_ptr %elem_size %num_elems
- *            In the trace:
- *            #a specifies that this is a sequence
- *            #tracetype1 is the type of elements in the sequence
- *            #tracetype2 is the type of the element count
- *            GCC input:
- *            array_ptr is a pointer to an array that contains members of size
- *            elem_size.
- *            num_elems is the number of elements in the array.
- * i.e.: #a #lu #lu %p %lu %u
- *
- * Callback
- * #k         callback (taken from the probe data)
- *            The following % arguments are exepected by the callback
- *
- * i.e.: #a #lu #lu #k %p
- *
- * Note: No conversion is done from floats to integers, nor from integers to
- * floats between c types and trace types. float conversion from double to float
- * or from float to double is also not supported.
- *
- * REMOVE
- * %*b     expects sizeof(data), data
- *         where sizeof(data) is 1, 2, 4 or 8
- *
- * Fixed length struct, union or array.
- * FIXME: unable to extract those sizes statically.
- * %*r     expects sizeof(*ptr), ptr
- * %*.*r   expects sizeof(*ptr), __alignof__(*ptr), ptr
- * struct and unions removed.
- * Fixed length array:
- * [%p]#a[len #tracetype]
- * i.e.: [%p]#a[12 #lu]
- *
- * Variable length sequence
- * %*.*:*v expects sizeof(*ptr), __alignof__(*ptr), elem_num, ptr
- *         where elem_num is the number of elements in the sequence
- */
-static inline
-const char *parse_trace_type(const char *fmt, char *trace_size,
-                            enum ltt_type *trace_type,
-                            unsigned long *attributes)
-{
-       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
-                               /* 'z' support added 23/7/1999 S.H.    */
-                               /* 'z' changed to 'Z' --davidm 1/25/99 */
-                               /* 't' added for ptrdiff_t */
-
-       /* parse attributes. */
-repeat:
-       switch (*fmt) {
-       case 'n':
-               *attributes |= LTT_ATTRIBUTE_NETWORK_BYTE_ORDER;
-               ++fmt;
-               goto repeat;
-       }
-
-       /* get the conversion qualifier */
-       qualifier = -1;
-       if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
-           *fmt == 'Z' || *fmt == 'z' || *fmt == 't' ||
-           *fmt == 'S' || *fmt == '1' || *fmt == '2' ||
-           *fmt == '4' || *fmt == 8) {
-               qualifier = *fmt;
-               ++fmt;
-               if (qualifier == 'l' && *fmt == 'l') {
-                       qualifier = 'L';
-                       ++fmt;
-               }
-       }
-
-       switch (*fmt) {
-       case 'c':
-               *trace_type = LTT_TYPE_UNSIGNED_INT;
-               *trace_size = sizeof(unsigned char);
-               goto parse_end;
-       case 's':
-               *trace_type = LTT_TYPE_STRING;
-               goto parse_end;
-       case 'p':
-               *trace_type = LTT_TYPE_UNSIGNED_INT;
-               *trace_size = sizeof(void *);
-               goto parse_end;
-       case 'd':
-       case 'i':
-               *trace_type = LTT_TYPE_SIGNED_INT;
-               break;
-       case 'o':
-       case 'u':
-       case 'x':
-       case 'X':
-               *trace_type = LTT_TYPE_UNSIGNED_INT;
-               break;
-       default:
-               if (!*fmt)
-                       --fmt;
-               goto parse_end;
-       }
-       switch (qualifier) {
-       case 'L':
-               *trace_size = sizeof(long long);
-               break;
-       case 'l':
-               *trace_size = sizeof(long);
-               break;
-       case 'Z':
-       case 'z':
-               *trace_size = sizeof(size_t);
-               break;
-       case 't':
-               *trace_size = sizeof(ptrdiff_t);
-               break;
-       case 'h':
-               *trace_size = sizeof(short);
-               break;
-       case '1':
-               *trace_size = sizeof(uint8_t);
-               break;
-       case '2':
-               *trace_size = sizeof(uint16_t);
-               break;
-       case '4':
-               *trace_size = sizeof(uint32_t);
-               break;
-       case '8':
-               *trace_size = sizeof(uint64_t);
-               break;
-       default:
-               *trace_size = sizeof(int);
-       }
-
-parse_end:
-       return fmt;
-}
-
-/*
- * Restrictions:
- * Field width and precision are *not* supported.
- * %n not supported.
- */
-static inline
-const char *parse_c_type(const char *fmt, char *c_size, enum ltt_type *c_type,
-                        char *outfmt)
-{
-       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
-                               /* 'z' support added 23/7/1999 S.H.    */
-                               /* 'z' changed to 'Z' --davidm 1/25/99 */
-                               /* 't' added for ptrdiff_t */
-
-       /* process flags : ignore standard print formats for now. */
-repeat:
-       switch (*fmt) {
-       case '-':
-       case '+':
-       case ' ':
-       case '#':
-       case '0':
-               ++fmt;
-               goto repeat;
-       }
-
-       /* get the conversion qualifier */
-       qualifier = -1;
-       if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
-           *fmt == 'Z' || *fmt == 'z' || *fmt == 't' ||
-           *fmt == 'S') {
-               qualifier = *fmt;
-               ++fmt;
-               if (qualifier == 'l' && *fmt == 'l') {
-                       qualifier = 'L';
-                       ++fmt;
-               }
-       }
-
-       if (outfmt) {
-               if (qualifier != -1)
-                       *outfmt++ = (char)qualifier;
-               *outfmt++ = *fmt;
-               *outfmt = 0;
-       }
-
-       switch (*fmt) {
-       case 'c':
-               *c_type = LTT_TYPE_UNSIGNED_INT;
-               *c_size = sizeof(unsigned char);
-               goto parse_end;
-       case 's':
-               *c_type = LTT_TYPE_STRING;
-               goto parse_end;
-       case 'p':
-               *c_type = LTT_TYPE_UNSIGNED_INT;
-               *c_size = sizeof(void *);
-               goto parse_end;
-       case 'd':
-       case 'i':
-               *c_type = LTT_TYPE_SIGNED_INT;
-               break;
-       case 'o':
-       case 'u':
-       case 'x':
-       case 'X':
-               *c_type = LTT_TYPE_UNSIGNED_INT;
-               break;
-       default:
-               if (!*fmt)
-                       --fmt;
-               goto parse_end;
-       }
-       switch (qualifier) {
-       case 'L':
-               *c_size = sizeof(long long);
-               break;
-       case 'l':
-               *c_size = sizeof(long);
-               break;
-       case 'Z':
-       case 'z':
-               *c_size = sizeof(size_t);
-               break;
-       case 't':
-               *c_size = sizeof(ptrdiff_t);
-               break;
-       case 'h':
-               *c_size = sizeof(short);
-               break;
-       default:
-               *c_size = sizeof(int);
-       }
-
-parse_end:
-       return fmt;
-}
-
-static inline
-size_t serialize_trace_data(struct ltt_chanbuf *buf, size_t buf_offset,
-                           char trace_size, enum ltt_type trace_type,
-                           char c_size, enum ltt_type c_type,
-                           unsigned int *stack_pos_ctx,
-                           int *largest_align,
-                           va_list *args)
-{
-       union {
-               unsigned long v_ulong;
-               uint64_t v_uint64;
-               struct {
-                       const char *s;
-                       size_t len;
-               } v_string;
-       } tmp;
-
-       /*
-        * Be careful about sign extension here.
-        * Sign extension is done with the destination (trace) type.
-        */
-       switch (trace_type) {
-       case LTT_TYPE_SIGNED_INT:
-               switch (c_size) {
-               case 1:
-                       tmp.v_ulong = (long)(int8_t)va_arg(*args, int);
-                       break;
-               case 2:
-                       tmp.v_ulong = (long)(int16_t)va_arg(*args, int);
-                       break;
-               case 4:
-                       tmp.v_ulong = (long)(int32_t)va_arg(*args, int);
-                       break;
-               case 8:
-                       tmp.v_uint64 = va_arg(*args, int64_t);
-                       break;
-               default:
-                       BUG();
-               }
-               break;
-       case LTT_TYPE_UNSIGNED_INT:
-               switch (c_size) {
-               case 1:
-                       tmp.v_ulong = (unsigned long)(uint8_t)va_arg(*args, unsigned int);
-                       break;
-               case 2:
-                       tmp.v_ulong = (unsigned long)(uint16_t)va_arg(*args, unsigned int);
-                       break;
-               case 4:
-                       tmp.v_ulong = (unsigned long)(uint32_t)va_arg(*args, unsigned int);
-                       break;
-               case 8:
-                       tmp.v_uint64 = va_arg(*args, uint64_t);
-                       break;
-               default:
-                       BUG();
-               }
-               break;
-       case LTT_TYPE_STRING:
-               tmp.v_string.s = va_arg(*args, const char *);
-               if ((unsigned long)tmp.v_string.s < PAGE_SIZE)
-                       tmp.v_string.s = "<NULL>";
-               if (!buf) {
-                       /*
-                        * Reserve tracer stack entry.
-                        */
-                       __get_cpu_var(tracer_stack_pos)++;
-                       WARN_ON_ONCE(__get_cpu_var(tracer_stack_pos)
-                                    > TRACER_STACK_LEN);
-                       barrier();
-                       __get_cpu_var(tracer_stack)[*stack_pos_ctx] =
-                                       strlen(tmp.v_string.s) + 1;
-               }
-               tmp.v_string.len = __get_cpu_var(tracer_stack)
-                                       [(*stack_pos_ctx)++];
-               if (buf)
-                       ltt_relay_strncpy(&buf->a, buf->a.chan, buf_offset,
-                                         tmp.v_string.s, tmp.v_string.len);
-               buf_offset += tmp.v_string.len;
-               goto copydone;
-       default:
-               BUG();
-       }
-
-       /*
-        * If trace_size is lower or equal to 4 bytes, there is no sign
-        * extension to do because we are already encoded in a long. Therefore,
-        * we can combine signed and unsigned ops. 4 bytes float also works
-        * with this, because we do a simple copy of 4 bytes into 4 bytes
-        * without manipulation (and we do not support conversion from integers
-        * to floats).
-        * It is also the case if c_size is 8 bytes, which is the largest
-        * possible integer.
-        */
-       if (ltt_get_alignment()) {
-               buf_offset += ltt_align(buf_offset, trace_size);
-               if (largest_align)
-                       *largest_align = max_t(int, *largest_align, trace_size);
-       }
-       if (trace_size <= 4 || c_size == 8) {
-               if (buf) {
-                       switch (trace_size) {
-                       case 1:
-                               if (c_size == 8)
-                                       ltt_relay_write(&buf->a, buf->a.chan,
-                                       buf_offset,
-                                       (uint8_t[]){ (uint8_t)tmp.v_uint64 },
-                                       sizeof(uint8_t));
-                               else
-                                       ltt_relay_write(&buf->a, buf->a.chan,
-                                       buf_offset,
-                                       (uint8_t[]){ (uint8_t)tmp.v_ulong },
-                                       sizeof(uint8_t));
-                               break;
-                       case 2:
-                               if (c_size == 8)
-                                       ltt_relay_write(&buf->a, buf->a.chan,
-                                       buf_offset,
-                                       (uint16_t[]){ (uint16_t)tmp.v_uint64 },
-                                       sizeof(uint16_t));
-                               else
-                                       ltt_relay_write(&buf->a, buf->a.chan,
-                                       buf_offset,
-                                       (uint16_t[]){ (uint16_t)tmp.v_ulong },
-                                       sizeof(uint16_t));
-                               break;
-                       case 4:
-                               if (c_size == 8)
-                                       ltt_relay_write(&buf->a, buf->a.chan,
-                                       buf_offset,
-                                       (uint32_t[]){ (uint32_t)tmp.v_uint64 },
-                                       sizeof(uint32_t));
-                               else
-                                       ltt_relay_write(&buf->a, buf->a.chan,
-                                       buf_offset,
-                                       (uint32_t[]){ (uint32_t)tmp.v_ulong },
-                                       sizeof(uint32_t));
-                               break;
-                       case 8:
-                               /*
-                                * c_size cannot be other than 8 here because
-                                * trace_size > 4.
-                                */
-                               ltt_relay_write(&buf->a, buf->a.chan, buf_offset,
-                               (uint64_t[]){ (uint64_t)tmp.v_uint64 },
-                               sizeof(uint64_t));
-                               break;
-                       default:
-                               BUG();
-                       }
-               }
-               buf_offset += trace_size;
-               goto copydone;
-       } else {
-               /*
-                * Perform sign extension.
-                */
-               if (buf) {
-                       switch (trace_type) {
-                       case LTT_TYPE_SIGNED_INT:
-                               ltt_relay_write(&buf->a, buf->a.chan, buf_offset,
-                                       (int64_t[]){ (int64_t)tmp.v_ulong },
-                                       sizeof(int64_t));
-                               break;
-                       case LTT_TYPE_UNSIGNED_INT:
-                               ltt_relay_write(&buf->a, buf->a.chan, buf_offset,
-                                       (uint64_t[]){ (uint64_t)tmp.v_ulong },
-                                       sizeof(uint64_t));
-                               break;
-                       default:
-                               BUG();
-                       }
-               }
-               buf_offset += trace_size;
-               goto copydone;
-       }
-
-copydone:
-       return buf_offset;
-}
-
-notrace size_t
-ltt_serialize_data(struct ltt_chanbuf *buf, size_t buf_offset,
-                  struct ltt_serialize_closure *closure,
-                  void *serialize_private, unsigned int stack_pos_ctx,
-                  int *largest_align, const char *fmt, va_list *args)
-{
-       char trace_size = 0, c_size = 0;        /*
-                                                * 0 (unset), 1, 2, 4, 8 bytes.
-                                                */
-       enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE;
-       unsigned long attributes = 0;
-
-       for (; *fmt ; ++fmt) {
-               switch (*fmt) {
-               case '#':
-                       /* tracetypes (#) */
-                       ++fmt;                  /* skip first '#' */
-                       if (*fmt == '#')        /* Escaped ## */
-                               break;
-                       attributes = 0;
-                       fmt = parse_trace_type(fmt, &trace_size, &trace_type,
-                                              &attributes);
-                       break;
-               case '%':
-                       /* c types (%) */
-                       ++fmt;                  /* skip first '%' */
-                       if (*fmt == '%')        /* Escaped %% */
-                               break;
-                       fmt = parse_c_type(fmt, &c_size, &c_type, NULL);
-                       /*
-                        * Output c types if no trace types has been
-                        * specified.
-                        */
-                       if (!trace_size)
-                               trace_size = c_size;
-                       if (trace_type == LTT_TYPE_NONE)
-                               trace_type = c_type;
-                       if (c_type == LTT_TYPE_STRING)
-                               trace_type = LTT_TYPE_STRING;
-                       /* perform trace write */
-                       buf_offset = serialize_trace_data(buf, buf_offset,
-                                                         trace_size,
-                                                         trace_type, c_size,
-                                                         c_type,
-                                                         &stack_pos_ctx,
-                                                         largest_align,
-                                                         args);
-                       trace_size = 0;
-                       c_size = 0;
-                       trace_type = LTT_TYPE_NONE;
-                       c_size = LTT_TYPE_NONE;
-                       attributes = 0;
-                       break;
-                       /* default is to skip the text, doing nothing */
-               }
-       }
-       return buf_offset;
-}
-EXPORT_SYMBOL_GPL(ltt_serialize_data);
-
-static inline
-uint64_t unserialize_base_type(struct ltt_chanbuf *buf,
-                              size_t *ppos, char trace_size,
-                              enum ltt_type trace_type)
-{
-       uint64_t tmp;
-
-       *ppos += ltt_align(*ppos, trace_size);
-       ltt_relay_read(&buf->a, *ppos, &tmp, trace_size);
-       *ppos += trace_size;
-
-       switch (trace_type) {
-       case LTT_TYPE_SIGNED_INT:
-               switch (trace_size) {
-               case 1:
-                       return (uint64_t)*(int8_t *)&tmp;
-               case 2:
-                       return (uint64_t)*(int16_t *)&tmp;
-               case 4:
-                       return (uint64_t)*(int32_t *)&tmp;
-               case 8:
-                       return tmp;
-               }
-               break;
-       case LTT_TYPE_UNSIGNED_INT:
-               switch (trace_size) {
-               case 1:
-                       return (uint64_t)*(uint8_t *)&tmp;
-               case 2:
-                       return (uint64_t)*(uint16_t *)&tmp;
-               case 4:
-                       return (uint64_t)*(uint32_t *)&tmp;
-               case 8:
-                       return tmp;
-               }
-               break;
-       default:
-               break;
-       }
-
-       BUG();
-       return 0;
-}
-
-static
-int serialize_printf_data(struct ltt_chanbuf *buf, size_t *ppos,
-                         char trace_size, enum ltt_type trace_type,
-                         char c_size, enum ltt_type c_type, char *output,
-                         ssize_t outlen, const char *outfmt)
-{
-       u64 value;
-       outlen = outlen < 0 ? 0 : outlen;
-
-       if (trace_type == LTT_TYPE_STRING) {
-               size_t len = ltt_relay_read_cstr(&buf->a, *ppos, output,
-                                                outlen);
-               *ppos += len + 1;
-               return len;
-       }
-
-       value = unserialize_base_type(buf, ppos, trace_size, trace_type);
-
-       if (c_size == 8)
-               return snprintf(output, outlen, outfmt, value);
-       else
-               return snprintf(output, outlen, outfmt, (unsigned int)value);
-}
-
-/**
- * ltt_serialize_printf - Format a string and place it in a buffer
- * @buf: The ltt-relay buffer that store binary data
- * @buf_offset: binary data's offset in @buf (should be masked to use as offset)
- * @msg_size: return message's length
- * @output: The buffer to place the result into
- * @outlen: The size of the buffer, including the trailing '\0'
- * @fmt: The format string to use
- *
- * The return value is the number of characters which would
- * be generated for the given input, excluding the trailing
- * '\0', as per ISO C99. If the return is greater than or equal to @outlen,
- * the resulting string is truncated.
- */
-size_t ltt_serialize_printf(struct ltt_chanbuf *buf, unsigned long buf_offset,
-                           size_t *msg_size, char *output, size_t outlen,
-                           const char *fmt)
-{
-       char trace_size = 0, c_size = 0;        /*
-                                                * 0 (unset), 1, 2, 4, 8 bytes.
-                                                */
-       enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE;
-       unsigned long attributes = 0;
-       char outfmt[4] = "%";
-       size_t outpos = 0;
-       size_t len;
-       size_t msgpos = buf_offset;
-
-       for (; *fmt ; ++fmt) {
-               switch (*fmt) {
-               case '#':
-                       /* tracetypes (#) */
-                       ++fmt;                  /* skip first '#' */
-                       if (*fmt == '#') {      /* Escaped ## */
-                               if (outpos < outlen)
-                                       output[outpos] = '#';
-                               outpos++;
-                               break;
-                       }
-                       attributes = 0;
-                       fmt = parse_trace_type(fmt, &trace_size, &trace_type,
-                                              &attributes);
-                       break;
-               case '%':
-                       /* c types (%) */
-                       ++fmt;                  /* skip first '%' */
-                       if (*fmt == '%') {      /* Escaped %% */
-                               if (outpos < outlen)
-                                       output[outpos] = '%';
-                               outpos++;
-                               break;
-                       }
-                       fmt = parse_c_type(fmt, &c_size, &c_type, outfmt + 1);
-                       /*
-                        * Output c types if no trace types has been
-                        * specified.
-                        */
-                       if (!trace_size)
-                               trace_size = c_size;
-                       if (trace_type == LTT_TYPE_NONE)
-                               trace_type = c_type;
-                       if (c_type == LTT_TYPE_STRING)
-                               trace_type = LTT_TYPE_STRING;
-
-                       /* perform trace printf */
-                       len = serialize_printf_data(buf, &msgpos, trace_size,
-                                                   trace_type, c_size, c_type,
-                                                   output + outpos,
-                                                   outlen - outpos, outfmt);
-                       outpos += len;
-                       trace_size = 0;
-                       c_size = 0;
-                       trace_type = LTT_TYPE_NONE;
-                       c_size = LTT_TYPE_NONE;
-                       attributes = 0;
-                       break;
-               default:
-                       if (outpos < outlen)
-                               output[outpos] = *fmt;
-                       outpos++;
-                       break;
-               }
-       }
-       if (msg_size)
-               *msg_size = (size_t)(msgpos - buf_offset);
-       /*
-        * Make sure we end output with terminating \0 when truncated.
-        */
-       if (outpos >= outlen + 1)
-               output[outlen] = '\0';
-       return outpos;
-}
-EXPORT_SYMBOL_GPL(ltt_serialize_printf);
-
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-
-unsigned int ltt_fmt_largest_align(size_t align_drift, const char *fmt)
-{
-       char trace_size = 0, c_size = 0;
-       enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE;
-       unsigned long attributes = 0;
-       int largest_align = 1;
-
-       for (; *fmt ; ++fmt) {
-               switch (*fmt) {
-               case '#':
-                       /* tracetypes (#) */
-                       ++fmt;                  /* skip first '#' */
-                       if (*fmt == '#')        /* Escaped ## */
-                               break;
-                       attributes = 0;
-                       fmt = parse_trace_type(fmt, &trace_size, &trace_type,
-                                              &attributes);
-
-                       largest_align = max_t(int, largest_align, trace_size);
-                       if (largest_align >= ltt_get_alignment())
-                               goto exit;
-                       break;
-               case '%':
-                       /* c types (%) */
-                       ++fmt;                  /* skip first '%' */
-                       if (*fmt == '%')        /* Escaped %% */
-                               break;
-                       fmt = parse_c_type(fmt, &c_size, &c_type, NULL);
-                       /*
-                        * Output c types if no trace types has been
-                        * specified.
-                        */
-                       if (!trace_size)
-                               trace_size = c_size;
-                       if (trace_type == LTT_TYPE_NONE)
-                               trace_type = c_type;
-                       if (c_type == LTT_TYPE_STRING)
-                               trace_type = LTT_TYPE_STRING;
-
-                       largest_align = max_t(int, largest_align, trace_size);
-                       if (largest_align >= ltt_get_alignment())
-                               goto exit;
-
-                       trace_size = 0;
-                       c_size = 0;
-                       trace_type = LTT_TYPE_NONE;
-                       c_size = LTT_TYPE_NONE;
-                       break;
-               }
-       }
-
-exit:
-       largest_align = min_t(int, largest_align, ltt_get_alignment());
-       return (largest_align - align_drift) & (largest_align - 1);
-}
-EXPORT_SYMBOL_GPL(ltt_fmt_largest_align);
-
-#endif
-
-/*
- * Calculate data size
- * Assume that the padding for alignment starts at a sizeof(void *) address.
- */
-static notrace
-size_t ltt_get_data_size(struct ltt_serialize_closure *closure,
-                        void *serialize_private, unsigned int stack_pos_ctx,
-                        int *largest_align, const char *fmt, va_list *args)
-{
-       ltt_serialize_cb cb = closure->callbacks[0];
-       closure->cb_idx = 0;
-       return (size_t)cb(NULL, 0, closure, serialize_private, stack_pos_ctx,
-                         largest_align, fmt, args);
-}
-
-static notrace
-void ltt_write_event_data(struct ltt_chanbuf *buf, size_t buf_offset,
-                         struct ltt_serialize_closure *closure,
-                         void *serialize_private, unsigned int stack_pos_ctx,
-                         int largest_align, const char *fmt, va_list *args)
-{
-       ltt_serialize_cb cb = closure->callbacks[0];
-       closure->cb_idx = 0;
-       buf_offset += ltt_align(buf_offset, largest_align);
-       cb(buf, buf_offset, closure, serialize_private, stack_pos_ctx, NULL,
-          fmt, args);
-}
-
-
-notrace
-void ltt_vtrace(const struct marker *mdata, void *probe_data, void *call_data,
-               const char *fmt, va_list *args)
-{
-       int largest_align, ret;
-       struct ltt_active_marker *pdata;
-       uint16_t eID;
-       size_t data_size, slot_size;
-       unsigned int chan_index;
-       struct ltt_chanbuf *buf;
-       struct ltt_chan *chan;
-       struct ltt_trace *trace, *dest_trace = NULL;
-       uint64_t tsc;
-       long buf_offset;
-       va_list args_copy;
-       struct ltt_serialize_closure closure;
-       struct ltt_probe_private_data *private_data = call_data;
-       void *serialize_private = NULL;
-       int cpu;
-       unsigned int rflags;
-       unsigned int stack_pos_ctx;
-
-       /*
-        * This test is useful for quickly exiting static tracing when no trace
-        * is active. We expect to have an active trace when we get here.
-        */
-       if (unlikely(ltt_traces.num_active_traces == 0))
-               return;
-
-       rcu_read_lock_sched_notrace();
-       cpu = smp_processor_id();
-       __get_cpu_var(ltt_nesting)++;
-       stack_pos_ctx = __get_cpu_var(tracer_stack_pos);
-       /*
-        * asm volatile and "memory" clobber prevent the compiler from moving
-        * instructions out of the ltt nesting count. This is required to ensure
-        * that probe side-effects which can cause recursion (e.g. unforeseen
-        * traps, divisions by 0, ...) are triggered within the incremented
-        * nesting count section.
-        */
-       barrier();
-       pdata = (struct ltt_active_marker *)probe_data;
-       eID = mdata->event_id;
-       chan_index = mdata->channel_id;
-       closure.callbacks = pdata->probe->callbacks;
-
-       if (unlikely(private_data)) {
-               dest_trace = private_data->trace;
-               if (private_data->serializer)
-                       closure.callbacks = &private_data->serializer;
-               serialize_private = private_data->serialize_private;
-       }
-
-       va_copy(args_copy, *args);
-       /*
-        * Assumes event payload to start on largest_align alignment.
-        */
-       largest_align = 1;      /* must be non-zero for ltt_align */
-       data_size = ltt_get_data_size(&closure, serialize_private,
-                                     stack_pos_ctx, &largest_align,
-                                     fmt, &args_copy);
-       largest_align = min_t(int, largest_align, sizeof(void *));
-       va_end(args_copy);
-
-       /* Iterate on each trace */
-       list_for_each_entry_rcu(trace, &ltt_traces.head, list) {
-               /*
-                * Expect the filter to filter out events. If we get here,
-                * we went through tracepoint activation as a first step.
-                */
-               if (unlikely(dest_trace && trace != dest_trace))
-                       continue;
-               if (unlikely(!trace->active))
-                       continue;
-               if (unlikely(!ltt_run_filter(trace, eID)))
-                       continue;
-#ifdef LTT_DEBUG_EVENT_SIZE
-               rflags = LTT_RFLAG_ID_SIZE;
-#else
-               if (unlikely(eID >= LTT_FREE_EVENTS))
-                       rflags = LTT_RFLAG_ID;
-               else
-                       rflags = 0;
-#endif
-               /*
-                * Skip channels added after trace creation.
-                */
-               if (unlikely(chan_index >= trace->nr_channels))
-                       continue;
-               chan = &trace->channels[chan_index];
-               if (!chan->active)
-                       continue;
-
-               /* reserve space : header and data */
-               ret = ltt_reserve_slot(chan, trace, data_size, largest_align,
-                                      cpu, &buf, &slot_size, &buf_offset,
-                                      &tsc, &rflags);
-               if (unlikely(ret < 0))
-                       continue; /* buffer full */
-
-               va_copy(args_copy, *args);
-               /* Out-of-order write : header and data */
-               buf_offset = ltt_write_event_header(&buf->a, &chan->a,
-                                                   buf_offset, eID, data_size,
-                                                   tsc, rflags);
-               ltt_write_event_data(buf, buf_offset, &closure,
-                                    serialize_private, stack_pos_ctx,
-                                    largest_align, fmt, &args_copy);
-               va_end(args_copy);
-               /* Out-of-order commit */
-               ltt_commit_slot(buf, chan, buf_offset, data_size, slot_size);
-       }
-       /*
-        * asm volatile and "memory" clobber prevent the compiler from moving
-        * instructions out of the ltt nesting count. This is required to ensure
-        * that probe side-effects which can cause recursion (e.g. unforeseen
-        * traps, divisions by 0, ...) are triggered within the incremented
-        * nesting count section.
-        */
-       barrier();
-       __get_cpu_var(tracer_stack_pos) = stack_pos_ctx;
-       __get_cpu_var(ltt_nesting)--;
-       rcu_read_unlock_sched_notrace();
-}
-EXPORT_SYMBOL_GPL(ltt_vtrace);
-
-notrace
-void ltt_trace(const struct marker *mdata, void *probe_data, void *call_data,
-              const char *fmt, ...)
-{
-       va_list args;
-
-       va_start(args, fmt);
-       ltt_vtrace(mdata, probe_data, call_data, fmt, &args);
-       va_end(args);
-}
-EXPORT_SYMBOL_GPL(ltt_trace);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers");
-MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Serializer");
index 1ac8c5b32eb36f35238ce60db23f43a7f4d0c9d2..cb82658b19c0ea014f5823ae434d1259cfe668bf 100644 (file)
 #include <linux/percpu.h>
 #include <linux/ltt-core.h>
 
-/* ltt's root dir in debugfs */
-#define LTT_ROOT        "ltt"
+struct ltt_session;
+struct ltt_channel;
+struct ltt_event;
 
-/*
- * All modifications of ltt_traces must be done by ltt-tracer.c, while holding
- * the semaphore. Only reading of this information can be done elsewhere, with
- * the RCU mechanism : the preemption must be disabled while reading the
- * list.
- */
-struct ltt_traces {
-       struct list_head setup_head;    /* Pre-allocated traces list */
-       struct list_head head;          /* Allocated Traces list */
-       unsigned int num_active_traces; /* Number of active traces */
-} ____cacheline_aligned;
-
-extern struct ltt_traces ltt_traces;
-
-/*
- * get dentry of ltt's root dir
- */
-struct dentry *get_ltt_root(void);
-
-void put_ltt_root(void);
-
-/* Keep track of trap nesting inside LTT */
-DECLARE_PER_CPU(unsigned int, ltt_nesting);
-
-typedef int (*ltt_run_filter_functor)(void *trace, uint16_t eID);
+typedef int (*ltt_run_filter_functor)(struct ltt_session *session,
+                                     struct ltt_channel *chan,
+                                     struct ltt_event *event);
 
 extern ltt_run_filter_functor ltt_run_filter;
 
diff --git a/ltt-tracer.c b/ltt-tracer.c
deleted file mode 100644 (file)
index 5cdea93..0000000
+++ /dev/null
@@ -1,1112 +0,0 @@
-/*
- * ltt/ltt-tracer.c
- *
- * Copyright (c) 2005-2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Tracing management internal kernel API. Trace buffer allocation/free, tracing
- * start/stop.
- *
- * Author:
- *     Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Inspired from LTT :
- *  Karim Yaghmour (karim@opersys.com)
- *  Tom Zanussi (zanussi@us.ibm.com)
- *  Bob Wisniewski (bob@watson.ibm.com)
- * And from K42 :
- *  Bob Wisniewski (bob@watson.ibm.com)
- *
- * Changelog:
- *  22/09/06, Move to the marker/probes mechanism.
- *  19/10/05, Complete lockless mechanism.
- *  27/05/05, Modular redesign and rewrite.
- *
- * Dual LGPL v2.1/GPL v2 license.
- */
-
-#include <linux/time.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/rcupdate.h>
-#include <linux/sched.h>
-#include <linux/bitops.h>
-#include <linux/fs.h>
-#include <linux/cpu.h>
-#include <linux/kref.h>
-#include <linux/delay.h>
-#include <linux/vmalloc.h>
-#include <asm/atomic.h>
-
-#include "ltt-tracer.h"
-
-static void synchronize_trace(void)
-{
-       synchronize_sched();
-#ifdef CONFIG_PREEMPT_RT
-       synchronize_rcu();
-#endif
-}
-
-static void async_wakeup(unsigned long data);
-
-static DEFINE_TIMER(ltt_async_wakeup_timer, async_wakeup, 0, 0);
-
-/* Default callbacks for modules */
-notrace
-int ltt_filter_control_default(enum ltt_filter_control_msg msg,
-                              struct ltt_trace *trace)
-{
-       return 0;
-}
-
-int ltt_statedump_default(struct ltt_trace *trace)
-{
-       return 0;
-}
-
-/* Callbacks for registered modules */
-
-int (*ltt_filter_control_functor)
-       (enum ltt_filter_control_msg msg, struct ltt_trace *trace) =
-                                       ltt_filter_control_default;
-struct module *ltt_filter_control_owner;
-
-/* These function pointers are protected by a trace activation check */
-struct module *ltt_run_filter_owner;
-int (*ltt_statedump_functor)(struct ltt_trace *trace) = ltt_statedump_default;
-struct module *ltt_statedump_owner;
-
-struct chan_info_struct {
-       const char *name;
-       unsigned int def_sb_size;
-       unsigned int def_n_sb;
-} chan_infos[] = {
-       [LTT_CHANNEL_METADATA] = {
-               LTT_METADATA_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_FD_STATE] = {
-               LTT_FD_STATE_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_GLOBAL_STATE] = {
-               LTT_GLOBAL_STATE_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_IRQ_STATE] = {
-               LTT_IRQ_STATE_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_MODULE_STATE] = {
-               LTT_MODULE_STATE_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_NETIF_STATE] = {
-               LTT_NETIF_STATE_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_SOFTIRQ_STATE] = {
-               LTT_SOFTIRQ_STATE_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_SWAP_STATE] = {
-               LTT_SWAP_STATE_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_SYSCALL_STATE] = {
-               LTT_SYSCALL_STATE_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_TASK_STATE] = {
-               LTT_TASK_STATE_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_VM_STATE] = {
-               LTT_VM_STATE_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_MED,
-               LTT_DEFAULT_N_SUBBUFS_MED,
-       },
-       [LTT_CHANNEL_FS] = {
-               LTT_FS_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_MED,
-               LTT_DEFAULT_N_SUBBUFS_MED,
-       },
-       [LTT_CHANNEL_INPUT] = {
-               LTT_INPUT_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_IPC] = {
-               LTT_IPC_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_LOW,
-               LTT_DEFAULT_N_SUBBUFS_LOW,
-       },
-       [LTT_CHANNEL_KERNEL] = {
-               LTT_KERNEL_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_HIGH,
-               LTT_DEFAULT_N_SUBBUFS_HIGH,
-       },
-       [LTT_CHANNEL_MM] = {
-               LTT_MM_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_MED,
-               LTT_DEFAULT_N_SUBBUFS_MED,
-       },
-       [LTT_CHANNEL_RCU] = {
-               LTT_RCU_CHANNEL,
-               LTT_DEFAULT_SUBBUF_SIZE_MED,
-               LTT_DEFAULT_N_SUBBUFS_MED,
-       },
-       [LTT_CHANNEL_DEFAULT] = {
-               NULL,
-               LTT_DEFAULT_SUBBUF_SIZE_MED,
-               LTT_DEFAULT_N_SUBBUFS_MED,
-       },
-};
-
-static enum ltt_channels get_channel_type_from_name(const char *name)
-{
-       int i;
-
-       if (!name)
-               return LTT_CHANNEL_DEFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(chan_infos); i++)
-               if (chan_infos[i].name && !strcmp(name, chan_infos[i].name))
-                       return (enum ltt_channels)i;
-
-       return LTT_CHANNEL_DEFAULT;
-}
-
-/**
- * ltt_module_register - LTT module registration
- * @name: module type
- * @function: callback to register
- * @owner: module which owns the callback
- *
- * The module calling this registration function must ensure that no
- * trap-inducing code will be executed by "function". E.g. vmalloc_sync_all()
- * must be called between a vmalloc and the moment the memory is made visible to
- * "function". This registration acts as a vmalloc_sync_all. Therefore, only if
- * the module allocates virtual memory after its registration must it
- * synchronize the TLBs.
- */
-int ltt_module_register(enum ltt_module_function name, void *function,
-                       struct module *owner)
-{
-       int ret = 0;
-
-       /*
-        * Make sure no page fault can be triggered by the module about to be
-        * registered. We deal with this here so we don't have to call
-        * vmalloc_sync_all() in each module's init.
-        */
-       vmalloc_sync_all();
-
-       switch (name) {
-       case LTT_FUNCTION_RUN_FILTER:
-               if (ltt_run_filter_owner != NULL) {
-                       ret = -EEXIST;
-                       goto end;
-               }
-               ltt_filter_register((ltt_run_filter_functor)function);
-               ltt_run_filter_owner = owner;
-               break;
-       case LTT_FUNCTION_FILTER_CONTROL:
-               if (ltt_filter_control_owner != NULL) {
-                       ret = -EEXIST;
-                       goto end;
-               }
-               ltt_filter_control_functor =
-                       (int (*)(enum ltt_filter_control_msg,
-                       struct ltt_trace *))function;
-               ltt_filter_control_owner = owner;
-               break;
-       case LTT_FUNCTION_STATEDUMP:
-               if (ltt_statedump_owner != NULL) {
-                       ret = -EEXIST;
-                       goto end;
-               }
-               ltt_statedump_functor =
-                       (int (*)(struct ltt_trace *))function;
-               ltt_statedump_owner = owner;
-               break;
-       }
-end:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(ltt_module_register);
-
-/**
- * ltt_module_unregister - LTT module unregistration
- * @name: module type
- */
-void ltt_module_unregister(enum ltt_module_function name)
-{
-       switch (name) {
-       case LTT_FUNCTION_RUN_FILTER:
-               ltt_filter_unregister();
-               ltt_run_filter_owner = NULL;
-               /* Wait for preempt sections to finish */
-               synchronize_trace();
-               break;
-       case LTT_FUNCTION_FILTER_CONTROL:
-               ltt_filter_control_functor = ltt_filter_control_default;
-               ltt_filter_control_owner = NULL;
-               break;
-       case LTT_FUNCTION_STATEDUMP:
-               ltt_statedump_functor = ltt_statedump_default;
-               ltt_statedump_owner = NULL;
-               break;
-       }
-
-}
-EXPORT_SYMBOL_GPL(ltt_module_unregister);
-
-static LIST_HEAD(ltt_transport_list);
-
-/**
- * ltt_transport_register - LTT transport registration
- * @transport: transport structure
- *
- * Registers a transport which can be used as output to extract the data out of
- * LTTng. The module calling this registration function must ensure that no
- * trap-inducing code will be executed by the transport functions. E.g.
- * vmalloc_sync_all() must be called between a vmalloc and the moment the memory
- * is made visible to the transport function. This registration acts as a
- * vmalloc_sync_all. Therefore, only if the module allocates virtual memory
- * after its registration must it synchronize the TLBs.
- */
-void ltt_transport_register(struct ltt_transport *transport)
-{
-       /*
-        * Make sure no page fault can be triggered by the module about to be
-        * registered. We deal with this here so we don't have to call
-        * vmalloc_sync_all() in each module's init.
-        */
-       vmalloc_sync_all();
-
-       ltt_lock_traces();
-       list_add_tail(&transport->node, &ltt_transport_list);
-       ltt_unlock_traces();
-}
-EXPORT_SYMBOL_GPL(ltt_transport_register);
-
-/**
- * ltt_transport_unregister - LTT transport unregistration
- * @transport: transport structure
- */
-void ltt_transport_unregister(struct ltt_transport *transport)
-{
-       ltt_lock_traces();
-       list_del(&transport->node);
-       ltt_unlock_traces();
-}
-EXPORT_SYMBOL_GPL(ltt_transport_unregister);
-
-static inline
-int is_channel_overwrite(enum ltt_channels chan, enum trace_mode mode)
-{
-       switch (mode) {
-       case LTT_TRACE_NORMAL:
-               return 0;
-       case LTT_TRACE_FLIGHT:
-               switch (chan) {
-               case LTT_CHANNEL_METADATA:
-                       return 0;
-               default:
-                       return 1;
-               }
-       case LTT_TRACE_HYBRID:
-               switch (chan) {
-               case LTT_CHANNEL_KERNEL:
-               case LTT_CHANNEL_FS:
-               case LTT_CHANNEL_MM:
-               case LTT_CHANNEL_RCU:
-               case LTT_CHANNEL_IPC:
-               case LTT_CHANNEL_INPUT:
-                       return 1;
-               default:
-                       return 0;
-               }
-       default:
-               return 0;
-       }
-}
-
-/**
- * _ltt_trace_find - find a trace by given name.
- * trace_name: trace name
- *
- * Returns a pointer to the trace structure, NULL if not found.
- */
-static struct ltt_trace *_ltt_trace_find(const char *trace_name)
-{
-       struct ltt_trace *trace;
-
-       list_for_each_entry(trace, &ltt_traces.head, list)
-               if (!strncmp(trace->trace_name, trace_name, NAME_MAX))
-                       return trace;
-
-       return NULL;
-}
-
-/* _ltt_trace_find_setup :
- * find a trace in setup list by given name.
- *
- * Returns a pointer to the trace structure, NULL if not found.
- */
-struct ltt_trace *_ltt_trace_find_setup(const char *trace_name)
-{
-       struct ltt_trace *trace;
-
-       list_for_each_entry(trace, &ltt_traces.setup_head, list)
-               if (!strncmp(trace->trace_name, trace_name, NAME_MAX))
-                       return trace;
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(_ltt_trace_find_setup);
-
-/**
- * ltt_release_trace - Release a LTT trace
- * @kref : reference count on the trace
- */
-void ltt_release_trace(struct kref *kref)
-{
-       struct ltt_trace *trace = container_of(kref, struct ltt_trace, kref);
-
-       trace->ops->remove_dirs(trace);
-       module_put(trace->transport->owner);
-       ltt_channels_trace_free(trace);
-       kfree(trace);
-}
-EXPORT_SYMBOL_GPL(ltt_release_trace);
-
-static inline void prepare_chan_size_num(unsigned int *subbuf_size,
-                                        unsigned int *n_subbufs)
-{
-       /* Make sure the subbuffer size is larger than a page */
-       *subbuf_size = max_t(unsigned int, *subbuf_size, PAGE_SIZE);
-
-       /* round to next power of 2 */
-       *subbuf_size = 1 << get_count_order(*subbuf_size);
-       *n_subbufs = 1 << get_count_order(*n_subbufs);
-
-       /* Subbuf size and number must both be power of two */
-       WARN_ON(hweight32(*subbuf_size) != 1);
-       WARN_ON(hweight32(*n_subbufs) != 1);
-}
-
-int _ltt_trace_setup(const char *trace_name)
-{
-       int err = 0;
-       struct ltt_trace *new_trace = NULL;
-       int metadata_index;
-       unsigned int chan;
-       enum ltt_channels chantype;
-
-       if (_ltt_trace_find_setup(trace_name)) {
-               printk(KERN_ERR "LTT : Trace name %s already used.\n",
-                               trace_name);
-               err = -EEXIST;
-               goto traces_error;
-       }
-
-       if (_ltt_trace_find(trace_name)) {
-               printk(KERN_ERR "LTT : Trace name %s already used.\n",
-                               trace_name);
-               err = -EEXIST;
-               goto traces_error;
-       }
-
-       new_trace = kzalloc(sizeof(struct ltt_trace), GFP_KERNEL);
-       if (!new_trace) {
-               printk(KERN_ERR
-                       "LTT : Unable to allocate memory for trace %s\n",
-                       trace_name);
-               err = -ENOMEM;
-               goto traces_error;
-       }
-       strncpy(new_trace->trace_name, trace_name, NAME_MAX);
-       if (ltt_channels_trace_alloc(&new_trace->nr_channels, 0)) {
-               printk(KERN_ERR
-                       "LTT : Unable to allocate memory for chaninfo  %s\n",
-                       trace_name);
-               err = -ENOMEM;
-               goto trace_free;
-       }
-
-       /*
-        * Force metadata channel to no overwrite.
-        */
-       metadata_index = ltt_channels_get_index_from_name("metadata");
-       WARN_ON(metadata_index < 0);
-       new_trace->settings[metadata_index].overwrite = 0;
-
-       /*
-        * Set hardcoded tracer defaults for some channels
-        */
-       for (chan = 0; chan < new_trace->nr_channels; chan++) {
-               chantype = get_channel_type_from_name(
-                       ltt_channels_get_name_from_index(chan));
-               new_trace->settings[chan].sb_size =
-                       chan_infos[chantype].def_sb_size;
-               new_trace->settings[chan].n_sb =
-                       chan_infos[chantype].def_n_sb;
-       }
-
-       list_add(&new_trace->list, &ltt_traces.setup_head);
-       return 0;
-
-trace_free:
-       kfree(new_trace);
-traces_error:
-       return err;
-}
-EXPORT_SYMBOL_GPL(_ltt_trace_setup);
-
-
-int ltt_trace_setup(const char *trace_name)
-{
-       int ret;
-       ltt_lock_traces();
-       ret = _ltt_trace_setup(trace_name);
-       ltt_unlock_traces();
-       return ret;
-}
-EXPORT_SYMBOL_GPL(ltt_trace_setup);
-
-/* must be called from within a traces lock. */
-static void _ltt_trace_free(struct ltt_trace *trace)
-{
-       list_del(&trace->list);
-       kfree(trace);
-}
-
-int ltt_trace_set_type(const char *trace_name, const char *trace_type)
-{
-       int err = 0;
-       struct ltt_trace *trace;
-       struct ltt_transport *tran_iter, *transport = NULL;
-
-       ltt_lock_traces();
-
-       trace = _ltt_trace_find_setup(trace_name);
-       if (!trace) {
-               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
-               err = -ENOENT;
-               goto traces_error;
-       }
-
-       list_for_each_entry(tran_iter, &ltt_transport_list, node) {
-               if (!strcmp(tran_iter->name, trace_type)) {
-                       transport = tran_iter;
-                       break;
-               }
-       }
-       if (!transport) {
-               printk(KERN_ERR "LTT : Transport %s is not present.\n",
-                       trace_type);
-               err = -EINVAL;
-               goto traces_error;
-       }
-
-       trace->transport = transport;
-
-traces_error:
-       ltt_unlock_traces();
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_trace_set_type);
-
-int ltt_trace_set_channel_subbufsize(const char *trace_name,
-                                    const char *channel_name,
-                                    unsigned int size)
-{
-       int err = 0;
-       struct ltt_trace *trace;
-       int index;
-
-       ltt_lock_traces();
-
-       trace = _ltt_trace_find_setup(trace_name);
-       if (!trace) {
-               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
-               err = -ENOENT;
-               goto traces_error;
-       }
-
-       index = ltt_channels_get_index_from_name(channel_name);
-       if (index < 0) {
-               printk(KERN_ERR "LTT : Channel %s not found\n", channel_name);
-               err = -ENOENT;
-               goto traces_error;
-       }
-       trace->settings[index].sb_size = size;
-
-traces_error:
-       ltt_unlock_traces();
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_trace_set_channel_subbufsize);
-
-int ltt_trace_set_channel_subbufcount(const char *trace_name,
-                                     const char *channel_name,
-                                     unsigned int cnt)
-{
-       int err = 0;
-       struct ltt_trace *trace;
-       int index;
-
-       ltt_lock_traces();
-
-       trace = _ltt_trace_find_setup(trace_name);
-       if (!trace) {
-               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
-               err = -ENOENT;
-               goto traces_error;
-       }
-
-       index = ltt_channels_get_index_from_name(channel_name);
-       if (index < 0) {
-               printk(KERN_ERR "LTT : Channel %s not found\n", channel_name);
-               err = -ENOENT;
-               goto traces_error;
-       }
-       trace->settings[index].n_sb = cnt;
-
-traces_error:
-       ltt_unlock_traces();
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_trace_set_channel_subbufcount);
-
-int ltt_trace_set_channel_switch_timer(const char *trace_name,
-                                      const char *channel_name,
-                                      unsigned long interval)
-{
-       int err = 0;
-       struct ltt_trace *trace;
-       int index;
-
-       ltt_lock_traces();
-
-       trace = _ltt_trace_find_setup(trace_name);
-       if (!trace) {
-               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
-               err = -ENOENT;
-               goto traces_error;
-       }
-
-       index = ltt_channels_get_index_from_name(channel_name);
-       if (index < 0) {
-               printk(KERN_ERR "LTT : Channel %s not found\n", channel_name);
-               err = -ENOENT;
-               goto traces_error;
-       }
-       ltt_channels_trace_set_timer(&trace->settings[index], interval);
-
-traces_error:
-       ltt_unlock_traces();
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_trace_set_channel_switch_timer);
-
-int ltt_trace_set_channel_overwrite(const char *trace_name,
-                                   const char *channel_name,
-                                   unsigned int overwrite)
-{
-       int err = 0;
-       struct ltt_trace *trace;
-       int index;
-
-       ltt_lock_traces();
-
-       trace = _ltt_trace_find_setup(trace_name);
-       if (!trace) {
-               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
-               err = -ENOENT;
-               goto traces_error;
-       }
-
-       /*
-        * Always put the metadata channel in non-overwrite mode :
-        * This is a very low traffic channel and it can't afford to have its
-        * data overwritten : this data (marker info) is necessary to be
-        * able to read the trace.
-        */
-       if (overwrite && !strcmp(channel_name, "metadata")) {
-               printk(KERN_ERR "LTT : Trying to set metadata channel to "
-                               "overwrite mode\n");
-               err = -EINVAL;
-               goto traces_error;
-       }
-
-       index = ltt_channels_get_index_from_name(channel_name);
-       if (index < 0) {
-               printk(KERN_ERR "LTT : Channel %s not found\n", channel_name);
-               err = -ENOENT;
-               goto traces_error;
-       }
-
-       trace->settings[index].overwrite = overwrite;
-
-traces_error:
-       ltt_unlock_traces();
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_trace_set_channel_overwrite);
-
-int ltt_trace_alloc(const char *trace_name)
-{
-       int err = 0;
-       struct ltt_trace *trace;
-       int sb_size, n_sb;
-       unsigned long flags;
-       int chan;
-       const char *channel_name;
-
-       ltt_lock_traces();
-
-       trace = _ltt_trace_find_setup(trace_name);
-       if (!trace) {
-               printk(KERN_ERR "LTT : Trace not found %s\n", trace_name);
-               err = -ENOENT;
-               goto traces_error;
-       }
-
-       kref_init(&trace->kref);
-       init_waitqueue_head(&trace->kref_wq);
-       trace->active = 0;
-       get_trace_clock();
-       trace->freq_scale = trace_clock_freq_scale();
-
-       if (!trace->transport) {
-               printk(KERN_ERR "LTT : Transport is not set.\n");
-               err = -EINVAL;
-               goto transport_error;
-       }
-       if (!try_module_get(trace->transport->owner)) {
-               printk(KERN_ERR "LTT : Can't lock transport module.\n");
-               err = -ENODEV;
-               goto transport_error;
-       }
-       trace->ops = &trace->transport->ops;
-
-       err = trace->ops->create_dirs(trace);
-       if (err) {
-               printk(KERN_ERR "LTT : Can't create dir for trace %s.\n",
-                       trace_name);
-               goto dirs_error;
-       }
-
-       local_irq_save(flags);
-       trace->start_freq = trace_clock_frequency();
-       trace->start_tsc = trace_clock_read64();
-       do_gettimeofday(&trace->start_time);
-       local_irq_restore(flags);
-
-       for (chan = 0; chan < trace->nr_channels; chan++) {
-               channel_name = ltt_channels_get_name_from_index(chan);
-               WARN_ON(!channel_name);
-               /*
-                * note: sb_size and n_sb will be overwritten with updated
-                * values by channel creation.
-                */
-               sb_size = trace->settings[chan].sb_size;
-               n_sb = trace->settings[chan].n_sb;
-               prepare_chan_size_num(&sb_size, &n_sb);
-               trace->channels[chan] = ltt_create_channel(channel_name,
-                                             trace, NULL, sb_size, n_sb,
-                                             trace->settings[chan].overwrite,
-                                             trace->settings[chan].switch_timer_interval,
-                                             trace->settings[chan].read_timer_interval);
-               if (err != 0) {
-                       printk(KERN_ERR "LTT : Can't create channel %s.\n",
-                               channel_name);
-                       goto create_channel_error;
-               }
-       }
-
-       list_del(&trace->list);
-       if (list_empty(&ltt_traces.head))
-               set_kernel_trace_flag_all_tasks();
-       list_add_rcu(&trace->list, &ltt_traces.head);
-       synchronize_trace();
-
-       ltt_unlock_traces();
-
-       return 0;
-
-create_channel_error:
-       for (chan--; chan >= 0; chan--)
-               ltt_channel_destroy(trace->channels[chan]);
-       trace->ops->remove_dirs(trace);
-
-dirs_error:
-       module_put(trace->transport->owner);
-transport_error:
-       put_trace_clock();
-traces_error:
-       ltt_unlock_traces();
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_trace_alloc);
-
-/*
- * It is worked as a wrapper for current version of ltt_control.ko.
- * We will make a new ltt_control based on debugfs, and control each channel's
- * buffer.
- */
-static
-int ltt_trace_create(const char *trace_name, const char *trace_type,
-                    enum trace_mode mode,
-                    unsigned int subbuf_size_low, unsigned int n_subbufs_low,
-                    unsigned int subbuf_size_med, unsigned int n_subbufs_med,
-                    unsigned int subbuf_size_high, unsigned int n_subbufs_high)
-{
-       int err = 0;
-
-       err = ltt_trace_setup(trace_name);
-       if (IS_ERR_VALUE(err))
-               return err;
-
-       err = ltt_trace_set_type(trace_name, trace_type);
-       if (IS_ERR_VALUE(err))
-               return err;
-
-       err = ltt_trace_alloc(trace_name);
-       if (IS_ERR_VALUE(err))
-               return err;
-
-       return err;
-}
-
-/* Must be called while sure that trace is in the list. */
-static int _ltt_trace_destroy(struct ltt_trace *trace)
-{
-       int err = -EPERM;
-
-       if (trace == NULL) {
-               err = -ENOENT;
-               goto traces_error;
-       }
-       if (trace->active) {
-               printk(KERN_ERR
-                       "LTT : Can't destroy trace %s : tracer is active\n",
-                       trace->trace_name);
-               err = -EBUSY;
-               goto active_error;
-       }
-       /* Everything went fine */
-       list_del_rcu(&trace->list);
-       synchronize_trace();
-       if (list_empty(&ltt_traces.head)) {
-               clear_kernel_trace_flag_all_tasks();
-       }
-       return 0;
-
-       /* error handling */
-active_error:
-traces_error:
-       return err;
-}
-
-/* Sleepable part of the destroy */
-static void __ltt_trace_destroy(struct ltt_trace *trace)
-{
-       int i;
-
-       for (i = 0; i < trace->nr_channels; i++)
-               ltt_channel_destroy(trace->channels[i]);
-       kref_put(&trace->kref, ltt_release_trace);
-}
-
-int ltt_trace_destroy(const char *trace_name)
-{
-       int err = 0;
-       struct ltt_trace *trace;
-
-       ltt_lock_traces();
-
-       trace = _ltt_trace_find(trace_name);
-       if (trace) {
-               err = _ltt_trace_destroy(trace);
-               if (err)
-                       goto error;
-
-               __ltt_trace_destroy(trace);
-               ltt_unlock_traces();
-               put_trace_clock();
-
-               return 0;
-       }
-
-       trace = _ltt_trace_find_setup(trace_name);
-       if (trace) {
-               _ltt_trace_free(trace);
-               ltt_unlock_traces();
-               return 0;
-       }
-
-       err = -ENOENT;
-
-       /* Error handling */
-error:
-       ltt_unlock_traces();
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_trace_destroy);
-
-/* must be called from within a traces lock. */
-static int _ltt_trace_start(struct ltt_trace *trace)
-{
-       int err = 0;
-
-       if (trace == NULL) {
-               err = -ENOENT;
-               goto traces_error;
-       }
-       if (trace->active)
-               printk(KERN_INFO "LTT : Tracing already active for trace %s\n",
-                               trace->trace_name);
-       if (!try_module_get(ltt_run_filter_owner)) {
-               err = -ENODEV;
-               printk(KERN_ERR "LTT : Can't lock filter module.\n");
-               goto get_ltt_run_filter_error;
-       }
-       trace->active = 1;
-       /* Read by trace points without protection : be careful */
-       ltt_traces.num_active_traces++;
-       return err;
-
-       /* error handling */
-get_ltt_run_filter_error:
-traces_error:
-       return err;
-}
-
-int ltt_trace_start(const char *trace_name)
-{
-       int err = 0;
-       struct ltt_trace *trace;
-
-       ltt_lock_traces();
-
-       trace = _ltt_trace_find(trace_name);
-       err = _ltt_trace_start(trace);
-       if (err)
-               goto no_trace;
-
-       ltt_unlock_traces();
-
-       /*
-        * Call the kernel state dump.
-        * Events will be mixed with real kernel events, it's ok.
-        * Notice that there is no protection on the trace : that's exactly
-        * why we iterate on the list and check for trace equality instead of
-        * directly using this trace handle inside the logging function.
-        */
-
-       ltt_dump_marker_state(trace);
-
-       if (!try_module_get(ltt_statedump_owner)) {
-               err = -ENODEV;
-               printk(KERN_ERR
-                       "LTT : Can't lock state dump module.\n");
-       } else {
-               ltt_statedump_functor(trace);
-               module_put(ltt_statedump_owner);
-       }
-
-       return err;
-
-       /* Error handling */
-no_trace:
-       ltt_unlock_traces();
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_trace_start);
-
-/* must be called from within traces lock */
-static int _ltt_trace_stop(struct ltt_trace *trace)
-{
-       int err = -EPERM;
-
-       if (trace == NULL) {
-               err = -ENOENT;
-               goto traces_error;
-       }
-       if (!trace->active)
-               printk(KERN_INFO "LTT : Tracing not active for trace %s\n",
-                               trace->trace_name);
-       if (trace->active) {
-               trace->active = 0;
-               ltt_traces.num_active_traces--;
-               synchronize_trace(); /* Wait for each tracing to be finished */
-       }
-       module_put(ltt_run_filter_owner);
-       /* Everything went fine */
-       return 0;
-
-       /* Error handling */
-traces_error:
-       return err;
-}
-
-int ltt_trace_stop(const char *trace_name)
-{
-       int err = 0;
-       struct ltt_trace *trace;
-
-       ltt_lock_traces();
-       trace = _ltt_trace_find(trace_name);
-       err = _ltt_trace_stop(trace);
-       ltt_unlock_traces();
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_trace_stop);
-
-/**
- * ltt_control - Trace control in-kernel API
- * @msg: Action to perform
- * @trace_name: Trace on which the action must be done
- * @trace_type: Type of trace (normal, flight, hybrid)
- * @args: Arguments specific to the action
- */
-int ltt_control(enum ltt_control_msg msg, const char *trace_name,
-               const char *trace_type, union ltt_control_args args)
-{
-       int err = -EPERM;
-
-       printk(KERN_ALERT "ltt_control : trace %s\n", trace_name);
-       switch (msg) {
-       case LTT_CONTROL_START:
-               printk(KERN_DEBUG "Start tracing %s\n", trace_name);
-               err = ltt_trace_start(trace_name);
-               break;
-       case LTT_CONTROL_STOP:
-               printk(KERN_DEBUG "Stop tracing %s\n", trace_name);
-               err = ltt_trace_stop(trace_name);
-               break;
-       case LTT_CONTROL_CREATE_TRACE:
-               printk(KERN_DEBUG "Creating trace %s\n", trace_name);
-               err = ltt_trace_create(trace_name, trace_type,
-                       args.new_trace.mode,
-                       args.new_trace.subbuf_size_low,
-                       args.new_trace.n_subbufs_low,
-                       args.new_trace.subbuf_size_med,
-                       args.new_trace.n_subbufs_med,
-                       args.new_trace.subbuf_size_high,
-                       args.new_trace.n_subbufs_high);
-               break;
-       case LTT_CONTROL_DESTROY_TRACE:
-               printk(KERN_DEBUG "Destroying trace %s\n", trace_name);
-               err = ltt_trace_destroy(trace_name);
-               break;
-       }
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_control);
-
-/**
- * ltt_filter_control - Trace filter control in-kernel API
- * @msg: Action to perform on the filter
- * @trace_name: Trace on which the action must be done
- */
-int ltt_filter_control(enum ltt_filter_control_msg msg, const char *trace_name)
-{
-       int err;
-       struct ltt_trace *trace;
-
-       printk(KERN_DEBUG "ltt_filter_control : trace %s\n", trace_name);
-       ltt_lock_traces();
-       trace = _ltt_trace_find(trace_name);
-       if (trace == NULL) {
-               printk(KERN_ALERT
-                       "Trace does not exist. Cannot proxy control request\n");
-               err = -ENOENT;
-               goto trace_error;
-       }
-       if (!try_module_get(ltt_filter_control_owner)) {
-               err = -ENODEV;
-               goto get_module_error;
-       }
-       switch (msg) {
-       case LTT_FILTER_DEFAULT_ACCEPT:
-               printk(KERN_DEBUG
-                       "Proxy filter default accept %s\n", trace_name);
-               err = (*ltt_filter_control_functor)(msg, trace);
-               break;
-       case LTT_FILTER_DEFAULT_REJECT:
-               printk(KERN_DEBUG
-                       "Proxy filter default reject %s\n", trace_name);
-               err = (*ltt_filter_control_functor)(msg, trace);
-               break;
-       default:
-               err = -EPERM;
-       }
-       module_put(ltt_filter_control_owner);
-
-get_module_error:
-trace_error:
-       ltt_unlock_traces();
-       return err;
-}
-EXPORT_SYMBOL_GPL(ltt_filter_control);
-
-int __init ltt_init(void)
-{
-       /* Make sure no page fault can be triggered by this module */
-       vmalloc_sync_all();
-       init_timer_deferrable(&ltt_async_wakeup_timer);
-       return 0;
-}
-
-module_init(ltt_init)
-
-static void __exit ltt_exit(void)
-{
-       struct ltt_trace *trace;
-       struct list_head *pos, *n;
-
-       ltt_lock_traces();
-       /* Stop each trace, currently being read by RCU read-side */
-       list_for_each_entry_rcu(trace, &ltt_traces.head, list)
-               _ltt_trace_stop(trace);
-       /* Wait for quiescent state. Readers have preemption disabled. */
-       synchronize_trace();
-       /* Safe iteration is now permitted. It does not have to be RCU-safe
-        * because no readers are left. */
-       list_for_each_safe(pos, n, &ltt_traces.head) {
-               trace = container_of(pos, struct ltt_trace, list);
-               /* _ltt_trace_destroy does a synchronize_trace() */
-               _ltt_trace_destroy(trace);
-               __ltt_trace_destroy(trace);
-       }
-       /* free traces in pre-alloc status */
-       list_for_each_safe(pos, n, &ltt_traces.setup_head) {
-               trace = container_of(pos, struct ltt_trace, list);
-               _ltt_trace_free(trace);
-       }
-
-       ltt_unlock_traces();
-}
-
-module_exit(ltt_exit)
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers");
-MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Tracer Kernel API");
index 6ed4fa94d623e968feef29323ae18dedf7dc89d0..3b5c3605fce7c7491943ed20afbec50c51be1d0f 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/local.h>
 
 #include "ltt-tracer-core.h"
+#include "ltt-events.h"
 
 /* Number of bytes to log with a read/write event */
 #define LTT_LOG_RW_SIZE                        32L
@@ -193,13 +194,24 @@ struct event_header {
  * because gcc generates poor code on at least powerpc and mips. Don't ever
  * let gcc add padding between the structure elements.
  */
-struct subbuffer_header {
-       uint64_t cycle_count_begin;     /* Cycle count at subbuffer start */
-       uint64_t cycle_count_end;       /* Cycle count at subbuffer end */
-       uint32_t magic_number;          /*
+struct packet_header {
+       uint32_t magic;                 /*
                                         * Trace magic number.
                                         * contains endianness information.
                                         */
+       uint8_t trace_uuid[16];
+       uint32_t stream_id;
+       uint64_t timestamp_begin;       /* Cycle count at subbuffer start */
+       uint64_t timestamp_end; /* Cycle count at subbuffer end */
+       uint32_t content_size;          /* Size of data in subbuffer */
+       uint32_t packet_size;           /* Subbuffer size (include padding) */
+       uint32_t events_lost;           /*
+                                        * Events lost in this subbuffer since
+                                        * the beginning of the trace.
+                                        * (may overflow)
+                                        */
+       /* TODO: move to metadata */
+#if 0
        uint8_t major_version;
        uint8_t minor_version;
        uint8_t arch_size;              /* Architecture pointer size */
@@ -211,18 +223,7 @@ struct subbuffer_header {
                                         * used all along the trace.
                                         */
        uint32_t freq_scale;            /* Frequency scaling (divisor) */
-       uint32_t data_size;             /* Size of data in subbuffer */
-       uint32_t sb_size;               /* Subbuffer size (include padding) */
-       uint32_t events_lost;           /*
-                                        * Events lost in this subbuffer since
-                                        * the beginning of the trace.
-                                        * (may overflow)
-                                        */
-       uint32_t subbuf_corrupt;        /*
-                                        * Corrupted (lost) subbuffers since
-                                        * the begginig of the trace.
-                                        * (may overflow)
-                                        */
+#endif //0
        uint8_t header_end[0];          /* End of header */
 };
 
@@ -301,9 +302,9 @@ unsigned char record_header_size(const struct lib_ring_buffer_config *config,
 #include <linux/ringbuffer/api.h>
 
 extern
-size_t ltt_write_event_header_slow(const struct lib_ring_buffer_config *config,
-                                  struct lib_ring_buffer_ctx *ctx,
-                                  u16 eID, u32 event_size);
+void ltt_write_event_header_slow(const struct lib_ring_buffer_config *config,
+                                struct lib_ring_buffer_ctx *ctx,
+                                u16 eID, u32 event_size);
 
 /*
  * ltt_write_event_header
@@ -397,49 +398,10 @@ size_t ltt_read_event_header(struct ltt_chanbuf_alloc *bufa, long buf_offset,
 }
 #endif //0
 
-/*
- * Control channels :
- * control/metadata
- * control/interrupts
- * control/...
- *
- * cpu channel :
- * cpu
- */
-#define LTT_RELAY_ROOT                 "ltt"
-
-#define LTT_METADATA_CHANNEL           "metadata_state"
-#define LTT_FD_STATE_CHANNEL           "fd_state"
-#define LTT_GLOBAL_STATE_CHANNEL       "global_state"
-#define LTT_IRQ_STATE_CHANNEL          "irq_state"
-#define LTT_MODULE_STATE_CHANNEL       "module_state"
-#define LTT_NETIF_STATE_CHANNEL                "netif_state"
-#define LTT_SOFTIRQ_STATE_CHANNEL      "softirq_state"
-#define LTT_SWAP_STATE_CHANNEL         "swap_state"
-#define LTT_SYSCALL_STATE_CHANNEL      "syscall_state"
-#define LTT_TASK_STATE_CHANNEL         "task_state"
-#define LTT_VM_STATE_CHANNEL           "vm_state"
-#define LTT_FS_CHANNEL                 "fs"
-#define LTT_INPUT_CHANNEL              "input"
-#define LTT_IPC_CHANNEL                        "ipc"
-#define LTT_KERNEL_CHANNEL             "kernel"
-#define LTT_MM_CHANNEL                 "mm"
-#define LTT_RCU_CHANNEL                        "rcu"
-
-#define LTT_FLIGHT_PREFIX              "flight-"
-
-#define LTT_ASCII                      "ascii"
-
 /* Tracer properties */
-#define LTT_DEFAULT_SUBBUF_SIZE_LOW    65536
-#define LTT_DEFAULT_N_SUBBUFS_LOW      2
-#define LTT_DEFAULT_SUBBUF_SIZE_MED    262144
-#define LTT_DEFAULT_N_SUBBUFS_MED      2
-#define LTT_DEFAULT_SUBBUF_SIZE_HIGH   1048576
-#define LTT_DEFAULT_N_SUBBUFS_HIGH     2
-#define LTT_TRACER_MAGIC_NUMBER                0x00D6B7ED
-#define LTT_TRACER_VERSION_MAJOR       2
-#define LTT_TRACER_VERSION_MINOR       6
+#define CTF_MAGIC_NUMBER               0xC1FC1FC1
+#define LTT_TRACER_VERSION_MAJOR       3
+#define LTT_TRACER_VERSION_MINOR       0
 
 /**
  * ltt_write_trace_header - Write trace header
@@ -447,20 +409,21 @@ size_t ltt_read_event_header(struct ltt_chanbuf_alloc *bufa, long buf_offset,
  * @header: Memory address where the information must be written to
  */
 static __inline__
-void ltt_write_trace_header(void *priv,
-                           struct subbuffer_header *header)
+void write_trace_header(const struct lib_ring_buffer_config *config,
+                       struct packet_header *header)
 {
-       struct ltt_session *session = priv;
-
-       header->magic_number = LTT_TRACER_MAGIC_NUMBER;
+       header->magic = CTF_MAGIC_NUMBER;
+#if 0
+       /* TODO: move start time to metadata */
        header->major_version = LTT_TRACER_VERSION_MAJOR;
        header->minor_version = LTT_TRACER_VERSION_MINOR;
        header->arch_size = sizeof(void *);
-       header->alignment = lib_ring_buffer_get_alignment();
-       header->start_time_sec = session->start_time.tv_sec;
-       header->start_time_usec = session->start_time.tv_usec;
-       header->start_freq = session->start_freq;
-       header->freq_scale = session->freq_scale;
+       header->alignment = lib_ring_buffer_get_alignment(config);
+       header->start_time_sec = ltt_chan->session->start_time.tv_sec;
+       header->start_time_usec = ltt_chan->session->start_time.tv_usec;
+       header->start_freq = ltt_chan->session->start_freq;
+       header->freq_scale = ltt_chan->session->freq_scale;
+#endif //0
 }
 
 /*
@@ -485,35 +448,10 @@ extern void ltt_module_unregister(enum ltt_module_function name);
 
 /* Exported control function */
 
-enum ltt_control_msg {
-       LTT_CONTROL_START,
-       LTT_CONTROL_STOP,
-       LTT_CONTROL_CREATE_TRACE,
-       LTT_CONTROL_DESTROY_TRACE
-};
-
-union ltt_control_args {
-       struct {
-               enum trace_mode mode;
-               unsigned int subbuf_size_low;
-               unsigned int n_subbufs_low;
-               unsigned int subbuf_size_med;
-               unsigned int n_subbufs_med;
-               unsigned int subbuf_size_high;
-               unsigned int n_subbufs_high;
-       } new_trace;
-};
-
 void ltt_core_register(int (*function)(u8, void *));
 
 void ltt_core_unregister(void);
 
-extern int ltt_marker_connect(const char *channel, const char *mname,
-                             const char *pname);
-extern int ltt_marker_disconnect(const char *channel, const char *mname,
-                                const char *pname);
-extern void ltt_dump_marker_state(struct ltt_trace *trace);
-
 extern
 void ltt_statedump_register_kprobes_dump(void (*callback)(void *call_data));
 extern
diff --git a/ltt-type-serializer.c b/ltt-type-serializer.c
deleted file mode 100644 (file)
index 7d06490..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * ltt-type-serializer.c
- *
- * LTTng specialized type serializer.
- *
- * Copyright Mathieu Desnoyers, 2008.
- *
- * Dual LGPL v2.1/GPL v2 license.
- */
-#include <linux/module.h>
-
-#include "ltt-type-serializer.h"
-#include "ltt-relay-lockless.h"
-
-notrace
-void _ltt_specialized_trace(const struct marker *mdata, void *probe_data,
-               void *serialize_private, unsigned int data_size,
-               unsigned int largest_align)
-{
-       int ret;
-       uint16_t eID;
-       size_t slot_size;
-       unsigned int chan_index;
-       struct ltt_chanbuf *buf;
-       struct ltt_chan *chan;
-       struct ltt_trace *trace;
-       uint64_t tsc;
-       long buf_offset;
-       int cpu;
-       unsigned int rflags;
-
-       /*
-        * If we get here, it's probably because we have useful work to do.
-        */
-       if (unlikely(ltt_traces.num_active_traces == 0))
-               return;
-
-       rcu_read_lock_sched_notrace();
-       cpu = smp_processor_id();
-       __get_cpu_var(ltt_nesting)++;
-       /*
-        * asm volatile and "memory" clobber prevent the compiler from moving
-        * instructions out of the ltt nesting count. This is required to ensure
-        * that probe side-effects which can cause recursion (e.g. unforeseen
-        * traps, divisions by 0, ...) are triggered within the incremented
-        * nesting count section.
-        */
-       barrier();
-       eID = mdata->event_id;
-       chan_index = mdata->channel_id;
-
-       /*
-        * Iterate on each trace, typically small number of active traces,
-        * list iteration with prefetch is usually slower.
-        */
-       __list_for_each_entry_rcu(trace, &ltt_traces.head, list) {
-               if (unlikely(!trace->active))
-                       continue;
-               if (unlikely(!ltt_run_filter(trace, eID)))
-                       continue;
-#ifdef LTT_DEBUG_EVENT_SIZE
-               rflags = LTT_RFLAG_ID_SIZE;
-#else
-               if (unlikely(eID >= LTT_FREE_EVENTS))
-                       rflags = LTT_RFLAG_ID;
-               else
-                       rflags = 0;
-#endif
-               /*
-                * Skip channels added after trace creation.
-                */
-               if (unlikely(chan_index >= trace->nr_channels))
-                       continue;
-               chan = &trace->channels[chan_index];
-               if (!chan->active)
-                       continue;
-
-               /* reserve space : header and data */
-               ret = ltt_reserve_slot(chan, trace, data_size, largest_align,
-                                      cpu, &buf, &slot_size, &buf_offset, &tsc,
-                                      &rflags);
-               if (unlikely(ret < 0))
-                       continue; /* buffer full */
-
-               /* Out-of-order write : header and data */
-               buf_offset = ltt_write_event_header(&buf->a, &chan->a,
-                                                   buf_offset, eID, data_size,
-                                                   tsc, rflags);
-               if (data_size) {
-                       buf_offset += ltt_align(buf_offset, largest_align);
-                       ltt_relay_write(&buf->a, &chan->a, buf_offset,
-                                       serialize_private, data_size);
-                       buf_offset += data_size;
-               }
-               /* Out-of-order commit */
-               ltt_commit_slot(buf, chan, buf_offset, data_size, slot_size);
-       }
-       /*
-        * asm volatile and "memory" clobber prevent the compiler from moving
-        * instructions out of the ltt nesting count. This is required to ensure
-        * that probe side-effects which can cause recursion (e.g. unforeseen
-        * traps, divisions by 0, ...) are triggered within the incremented
-        * nesting count section.
-        */
-       barrier();
-       __get_cpu_var(ltt_nesting)--;
-       rcu_read_unlock_sched_notrace();
-}
-EXPORT_SYMBOL_GPL(_ltt_specialized_trace);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers");
-MODULE_DESCRIPTION("LTT type serializer");
diff --git a/ltt-type-serializer.h b/ltt-type-serializer.h
deleted file mode 100644 (file)
index 49712c8..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-#ifndef _LTT_TYPE_SERIALIZER_H
-#define _LTT_TYPE_SERIALIZER_H
-
-#include <linux/if.h>  /* For IFNAMSIZ */
-
-#include "ltt-tracer.h"
-
-/*
- * largest_align must be non-zero, equal to the minimum between the largest type
- * and sizeof(void *).
- */
-extern void _ltt_specialized_trace(const struct marker *mdata, void *probe_data,
-               void *serialize_private, unsigned int data_size,
-               unsigned int largest_align);
-
-/*
- * Statically check that 0 < largest_align < sizeof(void *) to make sure it is
- * dumb-proof. It will make sure 0 is changed into 1 and unsigned long long is
- * changed into sizeof(void *) on 32-bit architectures.
- */
-static inline void ltt_specialized_trace(const struct marker *mdata,
-               void *probe_data,
-               void *serialize_private, unsigned int data_size,
-               unsigned int largest_align)
-{
-       largest_align = min_t(unsigned int, largest_align, sizeof(void *));
-       largest_align = max_t(unsigned int, largest_align, 1);
-       _ltt_specialized_trace(mdata, probe_data, serialize_private, data_size,
-               largest_align);
-}
-
-/*
- * Type serializer definitions.
- */
-
-/*
- * Return size of structure without end-of-structure padding.
- */
-#define serialize_sizeof(type) offsetof(typeof(type), end_field)
-
-struct serialize_long_int {
-       unsigned long f1;
-       unsigned int f2;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_int_int_long {
-       unsigned int f1;
-       unsigned int f2;
-       unsigned long f3;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_int_int_short {
-       unsigned int f1;
-       unsigned int f2;
-       unsigned short f3;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_long_long_long {
-       unsigned long f1;
-       unsigned long f2;
-       unsigned long f3;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_long_long_int {
-       unsigned long f1;
-       unsigned long f2;
-       unsigned int f3;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_long_long_short_char {
-       unsigned long f1;
-       unsigned long f2;
-       unsigned short f3;
-       unsigned char f4;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_long_long_short {
-       unsigned long f1;
-       unsigned long f2;
-       unsigned short f3;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_long_short_char {
-       unsigned long f1;
-       unsigned short f2;
-       unsigned char f3;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_long_short {
-       unsigned long f1;
-       unsigned short f2;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_long_char {
-       unsigned long f1;
-       unsigned char f2;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_long_ifname {
-       unsigned long f1;
-       unsigned char f2[IFNAMSIZ];
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_sizet_int {
-       size_t f1;
-       unsigned int f2;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_long_long_sizet_int {
-       unsigned long f1;
-       unsigned long f2;
-       size_t f3;
-       unsigned int f4;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_long_long_sizet_int_int {
-       unsigned long f1;
-       unsigned long f2;
-       size_t f3;
-       unsigned int f4;
-       unsigned int f5;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_l4421224411111 {
-       unsigned long f1;
-       uint32_t f2;
-       uint32_t f3;
-       uint16_t f4;
-       uint8_t f5;
-       uint16_t f6;
-       uint16_t f7;
-       uint32_t f8;
-       uint32_t f9;
-       uint8_t f10;
-       uint8_t f11;
-       uint8_t f12;
-       uint8_t f13;
-       uint8_t f14;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_l214421224411111 {
-       unsigned long f1;
-       uint16_t f2;
-       uint8_t f3;
-       uint32_t f4;
-       uint32_t f5;
-       uint16_t f6;
-       uint8_t f7;
-       uint16_t f8;
-       uint16_t f9;
-       uint32_t f10;
-       uint32_t f11;
-       uint8_t f12;
-       uint8_t f13;
-       uint8_t f14;
-       uint8_t f15;
-       uint8_t f16;
-       uint8_t end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-
-struct serialize_l4412228 {
-       unsigned long f1;
-       uint32_t f2;
-       uint32_t f3;
-       uint8_t f4;
-       uint16_t f5;
-       uint16_t f6;
-       uint16_t f7;
-       uint64_t f8;
-       unsigned char end_field[0];
-} RING_BUFFER_ALIGN_ATTR;
-#endif /* _LTT_TYPE_SERIALIZER_H */
This page took 0.147273 seconds and 4 git commands to generate.