Remove deprecated code
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Mon, 17 Jan 2011 06:55:08 +0000 (01:55 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Mon, 17 Jan 2011 06:55:08 +0000 (01:55 -0500)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
discard/ltt-filter.c [new file with mode: 0644]
discard/ltt-kprobes.c [new file with mode: 0644]
discard/ltt-statedump.c [new file with mode: 0644]
discard/ltt-trace-control.c [new file with mode: 0644]
discard/ltt-userspace-event.c [new file with mode: 0644]
ltt-filter.c [deleted file]
ltt-kprobes.c [deleted file]
ltt-statedump.c [deleted file]
ltt-trace-control.c [deleted file]
ltt-tracer.h
ltt-userspace-event.c [deleted file]

diff --git a/discard/ltt-filter.c b/discard/ltt-filter.c
new file mode 100644 (file)
index 0000000..ec113af
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 Mathieu Desnoyers
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+
+#include "ltt-tracer.h"
+
+#define LTT_FILTER_DIR "filter"
+
+/*
+ * Protects the ltt_filter_dir allocation.
+ */
+static DEFINE_MUTEX(ltt_filter_mutex);
+
+static struct dentry *ltt_filter_dir;
+
+struct dentry *get_filter_root(void)
+{
+       struct dentry *ltt_root_dentry;
+
+       mutex_lock(&ltt_filter_mutex);
+       if (!ltt_filter_dir) {
+               ltt_root_dentry = get_ltt_root();
+               if (!ltt_root_dentry)
+                       goto err_no_root;
+
+               ltt_filter_dir = debugfs_create_dir(LTT_FILTER_DIR,
+                                                   ltt_root_dentry);
+               if (!ltt_filter_dir)
+                       printk(KERN_ERR
+                              "ltt_filter_init: failed to create dir %s\n",
+                              LTT_FILTER_DIR);
+       }
+err_no_root:
+       mutex_unlock(&ltt_filter_mutex);
+       return ltt_filter_dir;
+}
+EXPORT_SYMBOL_GPL(get_filter_root);
+
+static void __exit ltt_filter_exit(void)
+{
+       debugfs_remove(ltt_filter_dir);
+}
+
+module_exit(ltt_filter_exit);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>");
+MODULE_DESCRIPTION("Linux Trace Toolkit Filter");
diff --git a/discard/ltt-kprobes.c b/discard/ltt-kprobes.c
new file mode 100644 (file)
index 0000000..7539381
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * (C) Copyright       2009 -
+ *             Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * LTTng kprobes integration module.
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#include <linux/module.h>
+#include <linux/kprobes.h>
+#include <linux/marker.h>
+#include <linux/mutex.h>
+#include <linux/jhash.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/kallsyms.h>
+
+#include "ltt-type-serializer.h"
+#include "ltt-tracer.h"
+
+#define LTT_KPROBES_DIR        "kprobes"
+#define LTT_KPROBES_ENABLE     "enable"
+#define LTT_KPROBES_DISABLE    "disable"
+#define LTT_KPROBES_LIST       "list"
+
+/* Active LTTng kprobes hash table */
+static DEFINE_MUTEX(ltt_kprobes_mutex);
+
+#define LTT_KPROBE_HASH_BITS   6
+#define LTT_KPROBE_TABLE_SIZE  (1 << LTT_KPROBE_HASH_BITS)
+static struct hlist_head ltt_kprobe_table[LTT_KPROBE_TABLE_SIZE];
+
+struct kprobe_entry {
+       struct hlist_node hlist;
+       struct kprobe kp;
+       char key[0];
+};
+
+static struct dentry *ltt_kprobes_dir,
+                    *ltt_kprobes_enable_dentry,
+                    *ltt_kprobes_disable_dentry,
+                    *ltt_kprobes_list_dentry;
+
+static int module_exit;
+
+
+static void trace_kprobe_table_entry(void *call_data, struct kprobe_entry *e)
+{
+       unsigned long addr;
+       char *namebuf = (char *)__get_free_page(GFP_KERNEL);
+
+       if (e->kp.addr) {
+               sprint_symbol(namebuf, (unsigned long)e->kp.addr);
+               addr = (unsigned long)e->kp.addr;
+       } else {
+               strncpy(namebuf, e->kp.symbol_name, PAGE_SIZE - 1);
+               /* TODO : add offset */
+               addr = kallsyms_lookup_name(namebuf);
+       }
+       if (addr)
+               __trace_mark(0, kprobe_state, kprobe_table, call_data,
+                            "ip 0x%lX symbol %s", addr, namebuf);
+       free_page((unsigned long)namebuf);
+}
+
+DEFINE_MARKER(kernel, kprobe, "ip %lX");
+
+static int ltt_kprobe_handler_pre(struct kprobe *p, struct pt_regs *regs)
+{
+       struct marker *marker;
+       unsigned long data;
+
+       data = (unsigned long)p->addr;
+       marker = &GET_MARKER(kernel, kprobe);
+       ltt_specialized_trace(marker, marker->single.probe_private,
+                             &data, sizeof(data), sizeof(data));
+       return 0;
+}
+
+static int ltt_register_kprobe(const char *key)
+{
+       struct hlist_head *head;
+       struct hlist_node *node;
+       struct kprobe_entry *e = NULL;
+       char *symbol_name = NULL;
+       unsigned long addr;
+       unsigned int offset = 0;
+       u32 hash;
+       size_t key_len = strlen(key) + 1;
+       int ret;
+
+       if (key_len == 1)
+               return -ENOENT; /* only \0 */
+
+       if (sscanf(key, "%li", &addr) != 1)
+               addr = 0;
+
+       if (!addr) {
+               const char *symbol_end = NULL;
+               unsigned int symbol_len;        /* includes final \0 */
+
+               symbol_end = strchr(key, ' ');
+               if (symbol_end)
+                       symbol_len = symbol_end - key + 1;
+               else
+                       symbol_len = key_len;
+               symbol_name = kmalloc(symbol_len, GFP_KERNEL);
+               if (!symbol_name) {
+                       ret = -ENOMEM;
+                       goto error;
+               }
+               memcpy(symbol_name, key, symbol_len - 1);
+               symbol_name[symbol_len-1] = '\0';
+               if (symbol_end) {
+                       symbol_end++;   /* start of offset */
+                       if (sscanf(symbol_end, "%i", &offset) != 1)
+                               offset = 0;
+               }
+       }
+
+       hash = jhash(key, key_len-1, 0);
+       head = &ltt_kprobe_table[hash & ((1 << LTT_KPROBE_HASH_BITS)-1)];
+       hlist_for_each_entry(e, node, head, hlist) {
+               if (!strcmp(key, e->key)) {
+                       printk(KERN_NOTICE "Kprobe %s busy\n", key);
+                       ret = -EBUSY;
+                       goto error;
+               }
+       }
+       /*
+        * Using kzalloc here to allocate a variable length element. Could
+        * cause some memory fragmentation if overused.
+        */
+       e = kzalloc(sizeof(struct kprobe_entry) + key_len, GFP_KERNEL);
+       if (!e) {
+               ret = -ENOMEM;
+               goto error;
+       }
+       memcpy(e->key, key, key_len);
+       hlist_add_head(&e->hlist, head);
+       e->kp.pre_handler = ltt_kprobe_handler_pre;
+       e->kp.symbol_name = symbol_name;
+       e->kp.offset = offset;
+       e->kp.addr = (void *)addr;
+       ret = register_kprobe(&e->kp);
+       if (ret < 0)
+               goto error_list_del;
+       trace_kprobe_table_entry(NULL, e);
+       return 0;
+
+error_list_del:
+       hlist_del(&e->hlist);
+error:
+       kfree(symbol_name);
+       kfree(e);
+       return ret;
+}
+
+static int ltt_unregister_kprobe(const char *key)
+{
+       struct hlist_head *head;
+       struct hlist_node *node;
+       struct kprobe_entry *e;
+       int found = 0;
+       size_t key_len = strlen(key) + 1;
+       u32 hash;
+
+       hash = jhash(key, key_len-1, 0);
+       head = &ltt_kprobe_table[hash & ((1 << LTT_KPROBE_HASH_BITS)-1)];
+       hlist_for_each_entry(e, node, head, hlist) {
+               if (!strcmp(key, e->key)) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found)
+               return -ENOENT;
+       hlist_del(&e->hlist);
+       unregister_kprobe(&e->kp);
+       kfree(e->kp.symbol_name);
+       kfree(e);
+       return 0;
+}
+
+static void ltt_unregister_all_kprobes(void)
+{
+       struct kprobe_entry *e;
+       struct hlist_head *head;
+       struct hlist_node *node, *tmp;
+       unsigned int i;
+
+       for (i = 0; i < LTT_KPROBE_TABLE_SIZE; i++) {
+               head = &ltt_kprobe_table[i];
+               hlist_for_each_entry_safe(e, node, tmp, head, hlist) {
+                       hlist_del(&e->hlist);
+                       unregister_kprobe(&e->kp);
+                       kfree(e->kp.symbol_name);
+                       kfree(e);
+               }
+       }
+}
+
+/*
+ * Allows to specify either
+ * - symbol
+ * - symbol offset
+ * - address
+ */
+static ssize_t enable_op_write(struct file *file,
+       const char __user *user_buf, size_t count, loff_t *ppos)
+{
+       int err, buf_size;
+       char *end;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+
+       mutex_lock(&ltt_kprobes_mutex);
+       if (module_exit) {
+               err = -EPERM;
+               goto error;
+       }
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto error;
+       buf[buf_size] = '\0';
+       end = strchr(buf, '\n');
+       if (end)
+               *end = '\0';
+       err = ltt_register_kprobe(buf);
+       if (err)
+               goto error;
+
+       mutex_unlock(&ltt_kprobes_mutex);
+       free_page((unsigned long)buf);
+       return count;
+error:
+       mutex_unlock(&ltt_kprobes_mutex);
+       free_page((unsigned long)buf);
+       return err;
+}
+
+static const struct file_operations ltt_kprobes_enable = {
+       .write = enable_op_write,
+};
+
+static ssize_t disable_op_write(struct file *file,
+       const char __user *user_buf, size_t count, loff_t *ppos)
+{
+       int err, buf_size;
+       char *end;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+
+       mutex_lock(&ltt_kprobes_mutex);
+       if (module_exit)
+               goto end;
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto error;
+       buf[buf_size] = '\0';
+       end = strchr(buf, '\n');
+       if (end)
+               *end = '\0';
+       err = ltt_unregister_kprobe(buf);
+       if (err)
+               goto error;
+end:
+       mutex_unlock(&ltt_kprobes_mutex);
+       free_page((unsigned long)buf);
+       return count;
+error:
+       mutex_unlock(&ltt_kprobes_mutex);
+       free_page((unsigned long)buf);
+       return err;
+}
+
+static const struct file_operations ltt_kprobes_disable = {
+       .write = disable_op_write,
+};
+
+/*
+ * This seqfile read is not perfectly safe, as a kprobe could be removed from
+ * the hash table between two reads. This will result in an incomplete output.
+ */
+static struct kprobe_entry *ltt_find_next_kprobe(struct kprobe_entry *prev)
+{
+       struct kprobe_entry *e;
+       struct hlist_head *head;
+       struct hlist_node *node;
+       unsigned int i;
+       int found = 0;
+
+       if (prev == (void *)-1UL)
+               return NULL;
+
+       if (!prev)
+               found = 1;
+
+       for (i = 0; i < LTT_KPROBE_TABLE_SIZE; i++) {
+               head = &ltt_kprobe_table[i];
+               hlist_for_each_entry(e, node, head, hlist) {
+                       if (found)
+                               return e;
+                       if (e == prev)
+                               found = 1;
+               }
+       }
+       return NULL;
+}
+
+static void *lk_next(struct seq_file *m, void *p, loff_t *pos)
+{
+       m->private = ltt_find_next_kprobe(m->private);
+       if (!m->private) {
+               m->private = (void *)-1UL;
+               return NULL;
+       }
+       return m->private;
+}
+
+static void *lk_start(struct seq_file *m, loff_t *pos)
+{
+       mutex_lock(&ltt_kprobes_mutex);
+       if (!*pos)
+               m->private = NULL;
+       m->private = ltt_find_next_kprobe(m->private);
+       if (!m->private) {
+               m->private = (void *)-1UL;
+               return NULL;
+       }
+       return m->private;
+}
+
+static void lk_stop(struct seq_file *m, void *p)
+{
+       mutex_unlock(&ltt_kprobes_mutex);
+}
+
+static int lk_show(struct seq_file *m, void *p)
+{
+       struct kprobe_entry *e = m->private;
+       seq_printf(m, "%s\n", e->key);
+       return 0;
+}
+
+static const struct seq_operations ltt_kprobes_list_op = {
+       .start = lk_start,
+       .next = lk_next,
+       .stop = lk_stop,
+       .show = lk_show,
+};
+
+static int ltt_kprobes_list_open(struct inode *inode, struct file *file)
+{
+       int ret;
+
+       ret = seq_open(file, &ltt_kprobes_list_op);
+       if (ret == 0)
+               ((struct seq_file *)file->private_data)->private = NULL;
+       return ret;
+}
+
+static int ltt_kprobes_list_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq = file->private_data;
+
+       seq->private = NULL;
+       return seq_release(inode, file);
+}
+
+static const struct file_operations ltt_kprobes_list = {
+       .open = ltt_kprobes_list_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = ltt_kprobes_list_release,
+};
+
+/*
+ * kprobes table dump. Callback invoked by ltt-statedump. ltt-statedump must
+ * take a reference to this module before calling this callback.
+ */
+void ltt_dump_kprobes_table(void *call_data)
+{
+       struct kprobe_entry *e;
+       struct hlist_head *head;
+       struct hlist_node *node;
+       unsigned int i;
+
+       for (i = 0; i < LTT_KPROBE_TABLE_SIZE; i++) {
+               head = &ltt_kprobe_table[i];
+               hlist_for_each_entry(e, node, head, hlist)
+                       trace_kprobe_table_entry(call_data, e);
+       }
+}
+EXPORT_SYMBOL_GPL(ltt_dump_kprobes_table);
+
+static int __init ltt_kprobes_init(void)
+{
+       struct dentry *ltt_root_dentry;
+       int ret = 0;
+
+       printk(KERN_INFO "LTT : ltt-kprobes init\n");
+       mutex_lock(&ltt_kprobes_mutex);
+
+       ltt_root_dentry = get_ltt_root();
+       if (!ltt_root_dentry) {
+               ret = -ENOENT;
+               goto err_no_root;
+       }
+
+       ltt_kprobes_dir = debugfs_create_dir(LTT_KPROBES_DIR, ltt_root_dentry);
+       if (!ltt_kprobes_dir) {
+               printk(KERN_ERR
+                      "ltt_kprobes_init: failed to create dir %s\n",
+                       LTT_KPROBES_DIR);
+               ret = -ENOMEM;
+               goto err_no_dir;
+       }
+
+       ltt_kprobes_enable_dentry = debugfs_create_file(LTT_KPROBES_ENABLE,
+                                                       S_IWUSR,
+                                                       ltt_kprobes_dir, NULL,
+                                                       &ltt_kprobes_enable);
+       if (IS_ERR(ltt_kprobes_enable_dentry) || !ltt_kprobes_enable_dentry) {
+               printk(KERN_ERR
+                      "ltt_kprobes_init: failed to create file %s\n",
+                       LTT_KPROBES_ENABLE);
+               ret = -ENOMEM;
+               goto err_no_enable;
+       }
+
+       ltt_kprobes_disable_dentry = debugfs_create_file(LTT_KPROBES_DISABLE,
+                                                        S_IWUSR,
+                                                        ltt_kprobes_dir, NULL,
+                                                        &ltt_kprobes_disable);
+       if (IS_ERR(ltt_kprobes_disable_dentry) || !ltt_kprobes_disable_dentry) {
+               printk(KERN_ERR
+                      "ltt_kprobes_init: failed to create file %s\n",
+                       LTT_KPROBES_DISABLE);
+               ret = -ENOMEM;
+               goto err_no_disable;
+       }
+
+       ltt_kprobes_list_dentry = debugfs_create_file(LTT_KPROBES_LIST,
+                                                     S_IWUSR, ltt_kprobes_dir,
+                                                     NULL, &ltt_kprobes_list);
+       if (IS_ERR(ltt_kprobes_list_dentry) || !ltt_kprobes_list_dentry) {
+               printk(KERN_ERR
+                      "ltt_kprobes_init: failed to create file %s\n",
+                       LTT_KPROBES_LIST);
+               ret = -ENOMEM;
+               goto err_no_list;
+       }
+       ltt_statedump_register_kprobes_dump(ltt_dump_kprobes_table);
+
+       mutex_unlock(&ltt_kprobes_mutex);
+       return ret;
+
+err_no_list:
+       debugfs_remove(ltt_kprobes_disable_dentry);
+err_no_disable:
+       debugfs_remove(ltt_kprobes_enable_dentry);
+err_no_enable:
+       debugfs_remove(ltt_kprobes_dir);
+err_no_dir:
+err_no_root:
+       mutex_unlock(&ltt_kprobes_mutex);
+       return ret;
+}
+module_init(ltt_kprobes_init);
+
+static void __exit ltt_kprobes_exit(void)
+{
+       printk(KERN_INFO "LTT : ltt-kprobes exit\n");
+       mutex_lock(&ltt_kprobes_mutex);
+       module_exit = 1;
+       ltt_statedump_unregister_kprobes_dump(ltt_dump_kprobes_table);
+       debugfs_remove(ltt_kprobes_list_dentry);
+       debugfs_remove(ltt_kprobes_disable_dentry);
+       debugfs_remove(ltt_kprobes_enable_dentry);
+       debugfs_remove(ltt_kprobes_dir);
+       ltt_unregister_all_kprobes();
+       mutex_unlock(&ltt_kprobes_mutex);
+}
+module_exit(ltt_kprobes_exit);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Kprobes Support");
diff --git a/discard/ltt-statedump.c b/discard/ltt-statedump.c
new file mode 100644 (file)
index 0000000..06ade69
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * Linux Trace Toolkit Kernel State Dump
+ *
+ * Copyright 2005 -
+ * Jean-Hugues Deschenes <jean-hugues.deschenes@polymtl.ca>
+ *
+ * Changes:
+ *     Eric Clement:                   Add listing of network IP interface
+ *     2006, 2007 Mathieu Desnoyers    Fix kernel threads
+ *                                     Various updates
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/inet.h>
+#include <linux/ip.h>
+#include <linux/kthread.h>
+#include <linux/proc_fs.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
+#include <linux/irqnr.h>
+#include <linux/cpu.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/marker.h>
+#include <linux/fdtable.h>
+#include <linux/swap.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+
+#include "ltt-tracer.h"
+
+#ifdef CONFIG_GENERIC_HARDIRQS
+#include <linux/irq.h>
+#endif
+
+#define NB_PROC_CHUNK 20
+
+/*
+ * Protected by the trace lock.
+ */
+static struct delayed_work cpu_work[NR_CPUS];
+static DECLARE_WAIT_QUEUE_HEAD(statedump_wq);
+static atomic_t kernel_threads_to_run;
+
+static void empty_cb(void *call_data)
+{
+}
+
+static DEFINE_MUTEX(statedump_cb_mutex);
+static void (*ltt_dump_kprobes_table_cb)(void *call_data) = empty_cb;
+
+enum lttng_thread_type {
+       LTTNG_USER_THREAD = 0,
+       LTTNG_KERNEL_THREAD = 1,
+};
+
+enum lttng_execution_mode {
+       LTTNG_USER_MODE = 0,
+       LTTNG_SYSCALL = 1,
+       LTTNG_TRAP = 2,
+       LTTNG_IRQ = 3,
+       LTTNG_SOFTIRQ = 4,
+       LTTNG_MODE_UNKNOWN = 5,
+};
+
+enum lttng_execution_submode {
+       LTTNG_NONE = 0,
+       LTTNG_UNKNOWN = 1,
+};
+
+enum lttng_process_status {
+       LTTNG_UNNAMED = 0,
+       LTTNG_WAIT_FORK = 1,
+       LTTNG_WAIT_CPU = 2,
+       LTTNG_EXIT = 3,
+       LTTNG_ZOMBIE = 4,
+       LTTNG_WAIT = 5,
+       LTTNG_RUN = 6,
+       LTTNG_DEAD = 7,
+};
+
+#ifdef CONFIG_INET
+static void ltt_enumerate_device(struct ltt_probe_private_data *call_data,
+                                struct net_device *dev)
+{
+       struct in_device *in_dev;
+       struct in_ifaddr *ifa;
+
+       if (dev->flags & IFF_UP) {
+               in_dev = in_dev_get(dev);
+               if (in_dev) {
+                       for (ifa = in_dev->ifa_list; ifa != NULL;
+                            ifa = ifa->ifa_next)
+                               __trace_mark(0, netif_state,
+                                            network_ipv4_interface,
+                                            call_data,
+                                            "name %s address #n4u%lu up %d",
+                                            dev->name,
+                                            (unsigned long)ifa->ifa_address,
+                                            0);
+                       in_dev_put(in_dev);
+               }
+       } else
+               __trace_mark(0, netif_state, network_ip_interface,
+                            call_data, "name %s address #n4u%lu up %d",
+                            dev->name, 0UL, 0);
+}
+
+static inline int
+ltt_enumerate_network_ip_interface(struct ltt_probe_private_data *call_data)
+{
+       struct net_device *dev;
+
+       read_lock(&dev_base_lock);
+       for_each_netdev(&init_net, dev)
+               ltt_enumerate_device(call_data, dev);
+       read_unlock(&dev_base_lock);
+
+       return 0;
+}
+#else /* CONFIG_INET */
+static inline int
+ltt_enumerate_network_ip_interface(struct ltt_probe_private_data *call_data)
+{
+       return 0;
+}
+#endif /* CONFIG_INET */
+
+
+static inline void
+ltt_enumerate_task_fd(struct ltt_probe_private_data *call_data,
+                     struct task_struct *t, char *tmp)
+{
+       struct fdtable *fdt;
+       struct file *filp;
+       unsigned int i;
+       const unsigned char *path;
+
+       if (!t->files)
+               return;
+
+       spin_lock(&t->files->file_lock);
+       fdt = files_fdtable(t->files);
+       for (i = 0; i < fdt->max_fds; i++) {
+               filp = fcheck_files(t->files, i);
+               if (!filp)
+                       continue;
+               path = d_path(&filp->f_path, tmp, PAGE_SIZE);
+               /* Make sure we give at least some info */
+               __trace_mark(0, fd_state, file_descriptor, call_data,
+                            "filename %s pid %d fd %u",
+                            (IS_ERR(path))?(filp->f_dentry->d_name.name):(path),
+                            t->pid, i);
+       }
+       spin_unlock(&t->files->file_lock);
+}
+
+static inline int
+ltt_enumerate_file_descriptors(struct ltt_probe_private_data *call_data)
+{
+       struct task_struct *t = &init_task;
+       char *tmp = (char *)__get_free_page(GFP_KERNEL);
+
+       /* Enumerate active file descriptors */
+       do {
+               read_lock(&tasklist_lock);
+               if (t != &init_task)
+                       atomic_dec(&t->usage);
+               t = next_task(t);
+               atomic_inc(&t->usage);
+               read_unlock(&tasklist_lock);
+               task_lock(t);
+               ltt_enumerate_task_fd(call_data, t, tmp);
+               task_unlock(t);
+       } while (t != &init_task);
+       free_page((unsigned long)tmp);
+       return 0;
+}
+
+static inline void
+ltt_enumerate_task_vm_maps(struct ltt_probe_private_data *call_data,
+               struct task_struct *t)
+{
+       struct mm_struct *mm;
+       struct vm_area_struct *map;
+       unsigned long ino;
+
+       /* get_task_mm does a task_lock... */
+       mm = get_task_mm(t);
+       if (!mm)
+               return;
+
+       map = mm->mmap;
+       if (map) {
+               down_read(&mm->mmap_sem);
+               while (map) {
+                       if (map->vm_file)
+                               ino = map->vm_file->f_dentry->d_inode->i_ino;
+                       else
+                               ino = 0;
+                       __trace_mark(0, vm_state, vm_map, call_data,
+                                    "pid %d start %lu end %lu flags %lu "
+                                    "pgoff %lu inode %lu",
+                                    t->pid, map->vm_start, map->vm_end,
+                                    map->vm_flags, map->vm_pgoff << PAGE_SHIFT,
+                                    ino);
+                       map = map->vm_next;
+               }
+               up_read(&mm->mmap_sem);
+       }
+       mmput(mm);
+}
+
+static inline int
+ltt_enumerate_vm_maps(struct ltt_probe_private_data *call_data)
+{
+       struct task_struct *t = &init_task;
+
+       do {
+               read_lock(&tasklist_lock);
+               if (t != &init_task)
+                       atomic_dec(&t->usage);
+               t = next_task(t);
+               atomic_inc(&t->usage);
+               read_unlock(&tasklist_lock);
+               ltt_enumerate_task_vm_maps(call_data, t);
+       } while (t != &init_task);
+       return 0;
+}
+
+#ifdef CONFIG_GENERIC_HARDIRQS
+static inline void list_interrupts(struct ltt_probe_private_data *call_data)
+{
+       unsigned int irq;
+       unsigned long flags = 0;
+       struct irq_desc *desc;
+
+       /* needs irq_desc */
+       for_each_irq_desc(irq, desc) {
+               struct irqaction *action;
+               const char *irq_chip_name =
+                       desc->chip->name ? : "unnamed_irq_chip";
+
+               local_irq_save(flags);
+               raw_spin_lock(&desc->lock);
+               for (action = desc->action; action; action = action->next)
+                       __trace_mark(0, irq_state, interrupt, call_data,
+                                    "name %s action %s irq_id %u",
+                                    irq_chip_name, action->name, irq);
+               raw_spin_unlock(&desc->lock);
+               local_irq_restore(flags);
+       }
+}
+#else
+static inline void list_interrupts(struct ltt_probe_private_data *call_data)
+{
+}
+#endif
+
+static inline int
+ltt_enumerate_process_states(struct ltt_probe_private_data *call_data)
+{
+       struct task_struct *t = &init_task;
+       struct task_struct *p = t;
+       enum lttng_process_status status;
+       enum lttng_thread_type type;
+       enum lttng_execution_mode mode;
+       enum lttng_execution_submode submode;
+
+       do {
+               mode = LTTNG_MODE_UNKNOWN;
+               submode = LTTNG_UNKNOWN;
+
+               read_lock(&tasklist_lock);
+               if (t != &init_task) {
+                       atomic_dec(&t->usage);
+                       t = next_thread(t);
+               }
+               if (t == p) {
+                       p = next_task(t);
+                       t = p;
+               }
+               atomic_inc(&t->usage);
+               read_unlock(&tasklist_lock);
+
+               task_lock(t);
+
+               if (t->exit_state == EXIT_ZOMBIE)
+                       status = LTTNG_ZOMBIE;
+               else if (t->exit_state == EXIT_DEAD)
+                       status = LTTNG_DEAD;
+               else if (t->state == TASK_RUNNING) {
+                       /* Is this a forked child that has not run yet? */
+                       if (list_empty(&t->rt.run_list))
+                               status = LTTNG_WAIT_FORK;
+                       else
+                               /*
+                                * All tasks are considered as wait_cpu;
+                                * the viewer will sort out if the task was
+                                * really running at this time.
+                                */
+                               status = LTTNG_WAIT_CPU;
+               } else if (t->state &
+                       (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)) {
+                       /* Task is waiting for something to complete */
+                       status = LTTNG_WAIT;
+               } else
+                       status = LTTNG_UNNAMED;
+               submode = LTTNG_NONE;
+
+               /*
+                * Verification of t->mm is to filter out kernel threads;
+                * Viewer will further filter out if a user-space thread was
+                * in syscall mode or not.
+                */
+               if (t->mm)
+                       type = LTTNG_USER_THREAD;
+               else
+                       type = LTTNG_KERNEL_THREAD;
+
+               __trace_mark(0, task_state, process_state, call_data,
+                            "pid %d parent_pid %d name %s type %d mode %d "
+                            "submode %d status %d tgid %d",
+                            t->pid, t->parent->pid, t->comm,
+                            type, mode, submode, status, t->tgid);
+               task_unlock(t);
+       } while (t != &init_task);
+
+       return 0;
+}
+
+void ltt_statedump_register_kprobes_dump(void (*callback)(void *call_data))
+{
+       mutex_lock(&statedump_cb_mutex);
+       ltt_dump_kprobes_table_cb = callback;
+       mutex_unlock(&statedump_cb_mutex);
+}
+EXPORT_SYMBOL_GPL(ltt_statedump_register_kprobes_dump);
+
+void ltt_statedump_unregister_kprobes_dump(void (*callback)(void *call_data))
+{
+       mutex_lock(&statedump_cb_mutex);
+       ltt_dump_kprobes_table_cb = empty_cb;
+       mutex_unlock(&statedump_cb_mutex);
+}
+EXPORT_SYMBOL_GPL(ltt_statedump_unregister_kprobes_dump);
+
+void ltt_statedump_work_func(struct work_struct *work)
+{
+       if (atomic_dec_and_test(&kernel_threads_to_run))
+               /* If we are the last thread, wake up do_ltt_statedump */
+               wake_up(&statedump_wq);
+}
+
+static int do_ltt_statedump(struct ltt_probe_private_data *call_data)
+{
+       int cpu;
+       struct module *cb_owner;
+
+       printk(KERN_DEBUG "LTT state dump thread start\n");
+       ltt_enumerate_process_states(call_data);
+       ltt_enumerate_file_descriptors(call_data);
+       list_modules(call_data);
+       ltt_enumerate_vm_maps(call_data);
+       list_interrupts(call_data);
+       ltt_enumerate_network_ip_interface(call_data);
+       ltt_dump_swap_files(call_data);
+       ltt_dump_sys_call_table(call_data);
+       ltt_dump_softirq_vec(call_data);
+       ltt_dump_idt_table(call_data);
+
+       mutex_lock(&statedump_cb_mutex);
+
+       cb_owner = __module_address((unsigned long)ltt_dump_kprobes_table_cb);
+       __module_get(cb_owner);
+       ltt_dump_kprobes_table_cb(call_data);
+       module_put(cb_owner);
+
+       mutex_unlock(&statedump_cb_mutex);
+
+       /*
+        * Fire off a work queue on each CPU. Their sole purpose in life
+        * is to guarantee that each CPU has been in a state where is was in
+        * syscall mode (i.e. not in a trap, an IRQ or a soft IRQ).
+        */
+       get_online_cpus();
+       atomic_set(&kernel_threads_to_run, num_online_cpus());
+       for_each_online_cpu(cpu) {
+               INIT_DELAYED_WORK(&cpu_work[cpu], ltt_statedump_work_func);
+               schedule_delayed_work_on(cpu, &cpu_work[cpu], 0);
+       }
+       /* Wait for all threads to run */
+       __wait_event(statedump_wq, (atomic_read(&kernel_threads_to_run) != 0));
+       put_online_cpus();
+       /* Our work is done */
+       printk(KERN_DEBUG "LTT state dump end\n");
+       __trace_mark(0, global_state, statedump_end,
+                    call_data, MARK_NOARGS);
+       return 0;
+}
+
+/*
+ * Called with trace lock held.
+ */
+int ltt_statedump_start(struct ltt_trace *trace)
+{
+       struct ltt_probe_private_data call_data;
+       printk(KERN_DEBUG "LTT state dump begin\n");
+
+       call_data.trace = trace;
+       call_data.serializer = NULL;
+       return do_ltt_statedump(&call_data);
+}
+
+static int __init statedump_init(void)
+{
+       int ret;
+       printk(KERN_DEBUG "LTT : State dump init\n");
+       ret = ltt_module_register(LTT_FUNCTION_STATEDUMP,
+                       ltt_statedump_start, THIS_MODULE);
+       return ret;
+}
+
+static void __exit statedump_exit(void)
+{
+       printk(KERN_DEBUG "LTT : State dump exit\n");
+       ltt_module_unregister(LTT_FUNCTION_STATEDUMP);
+}
+
+module_init(statedump_init)
+module_exit(statedump_exit)
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Jean-Hugues Deschenes");
+MODULE_DESCRIPTION("Linux Trace Toolkit Statedump");
diff --git a/discard/ltt-trace-control.c b/discard/ltt-trace-control.c
new file mode 100644 (file)
index 0000000..0a02549
--- /dev/null
@@ -0,0 +1,1426 @@
+/*
+ * LTT trace control module over debugfs.
+ *
+ * Copyright 2008 - Zhaolei <zhaolei@cn.fujitsu.com>
+ *
+ * Copyright 2009 - Gui Jianfeng <guijianfeng@cn.fujitsu.com>
+ *                  Make mark-control work in debugfs
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+/*
+ * Todo:
+ *   Impl read operations for control file to read attributes
+ *   Create a README file in ltt control dir, for display help info
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/notifier.h>
+#include <linux/jiffies.h>
+#include <linux/marker.h>
+
+#include "ltt-tracer.h"
+
+#define LTT_CONTROL_DIR "control"
+#define MARKERS_CONTROL_DIR "markers"
+#define LTT_SETUP_TRACE_FILE "setup_trace"
+#define LTT_DESTROY_TRACE_FILE "destroy_trace"
+
+#define LTT_WRITE_MAXLEN       (128)
+
+struct dentry *ltt_control_dir, *ltt_setup_trace_file, *ltt_destroy_trace_file,
+       *markers_control_dir;
+
+/*
+ * the traces_lock nests inside control_lock.
+ * control_lock protects the consistency of directories presented in ltt
+ * directory.
+ */
+static DEFINE_MUTEX(control_lock);
+
+/*
+ * big note about locking for marker control files :
+ * If a marker control file is added/removed manually racing with module
+ * load/unload, there may be warning messages appearing, but those two
+ * operations should be able to execute concurrently without any lock
+ * synchronizing their operation one wrt another.
+ * Locking the marker mutex, module mutex and also keeping a mutex here
+ * from mkdir/rmdir _and_ from the notifier called from module load/unload makes
+ * life miserable and just asks for deadlocks.
+ */
+
+/*
+ * lookup a file/dir in parent dir.
+ * only designed to work well for debugfs.
+ * (although it maybe ok for other fs)
+ *
+ * return:
+ *     file/dir's dentry on success
+ *     NULL on failure
+ */
+static struct dentry *dir_lookup(struct dentry *parent, const char *name)
+{
+       struct qstr q;
+       struct dentry *d;
+
+       q.name = name;
+       q.len = strlen(name);
+       q.hash = full_name_hash(q.name, q.len);
+
+       d = d_lookup(parent, &q);
+       if (d)
+               dput(d);
+
+       return d;
+}
+
+
+static ssize_t alloc_write(struct file *file, const char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       int err = 0;
+       int buf_size;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+       char *cmd = (char *)__get_free_page(GFP_KERNEL);
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto err_copy_from_user;
+       buf[buf_size] = 0;
+
+       if (sscanf(buf, "%s", cmd) != 1) {
+               err = -EPERM;
+               goto err_get_cmd;
+       }
+
+       if ((cmd[0] != 'Y' && cmd[0] != 'y' && cmd[0] != '1') || cmd[1]) {
+               err = -EPERM;
+               goto err_bad_cmd;
+       }
+
+       err = ltt_trace_alloc(file->f_dentry->d_parent->d_name.name);
+       if (IS_ERR_VALUE(err)) {
+               printk(KERN_ERR "alloc_write: ltt_trace_alloc failed: %d\n",
+                       err);
+               goto err_alloc_trace;
+       }
+
+       free_page((unsigned long)buf);
+       free_page((unsigned long)cmd);
+       return count;
+
+err_alloc_trace:
+err_bad_cmd:
+err_get_cmd:
+err_copy_from_user:
+       free_page((unsigned long)buf);
+       free_page((unsigned long)cmd);
+       return err;
+}
+
+static const struct file_operations ltt_alloc_operations = {
+       .write = alloc_write,
+};
+
+
+static ssize_t enabled_write(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       int err = 0;
+       int buf_size;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+       char *cmd = (char *)__get_free_page(GFP_KERNEL);
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto err_copy_from_user;
+       buf[buf_size] = 0;
+
+       if (sscanf(buf, "%s", cmd) != 1) {
+               err = -EPERM;
+               goto err_get_cmd;
+       }
+
+       if (cmd[1]) {
+               err = -EPERM;
+               goto err_bad_cmd;
+       }
+
+       switch (cmd[0]) {
+       case 'Y':
+       case 'y':
+       case '1':
+               err = ltt_trace_start(file->f_dentry->d_parent->d_name.name);
+               if (IS_ERR_VALUE(err)) {
+                       printk(KERN_ERR
+                              "enabled_write: ltt_trace_start failed: %d\n",
+                              err);
+                       err = -EPERM;
+                       goto err_start_trace;
+               }
+               break;
+       case 'N':
+       case 'n':
+       case '0':
+               err = ltt_trace_stop(file->f_dentry->d_parent->d_name.name);
+               if (IS_ERR_VALUE(err)) {
+                       printk(KERN_ERR
+                              "enabled_write: ltt_trace_stop failed: %d\n",
+                              err);
+                       err = -EPERM;
+                       goto err_stop_trace;
+               }
+               break;
+       default:
+               err = -EPERM;
+               goto err_bad_cmd;
+       }
+
+       free_page((unsigned long)buf);
+       free_page((unsigned long)cmd);
+       return count;
+
+err_stop_trace:
+err_start_trace:
+err_bad_cmd:
+err_get_cmd:
+err_copy_from_user:
+       free_page((unsigned long)buf);
+       free_page((unsigned long)cmd);
+       return err;
+}
+
+static const struct file_operations ltt_enabled_operations = {
+       .write = enabled_write,
+};
+
+
+static ssize_t trans_write(struct file *file, const char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+       char *trans_name = (char *)__get_free_page(GFP_KERNEL);
+       int err = 0;
+       int buf_size;
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto err_copy_from_user;
+       buf[buf_size] = 0;
+
+       if (sscanf(buf, "%s", trans_name) != 1) {
+               err = -EPERM;
+               goto err_get_transname;
+       }
+
+       err = ltt_trace_set_type(file->f_dentry->d_parent->d_name.name,
+                                trans_name);
+       if (IS_ERR_VALUE(err)) {
+               printk(KERN_ERR "trans_write: ltt_trace_set_type failed: %d\n",
+                      err);
+               goto err_set_trans;
+       }
+
+       free_page((unsigned long)buf);
+       free_page((unsigned long)trans_name);
+       return count;
+
+err_set_trans:
+err_get_transname:
+err_copy_from_user:
+       free_page((unsigned long)buf);
+       free_page((unsigned long)trans_name);
+       return err;
+}
+
+static const struct file_operations ltt_trans_operations = {
+       .write = trans_write,
+};
+
+
+static ssize_t channel_subbuf_num_write(struct file *file,
+               const char __user *user_buf, size_t count, loff_t *ppos)
+{
+       int err = 0;
+       int buf_size;
+       unsigned int num;
+       const char *channel_name;
+       const char *trace_name;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto err_copy_from_user;
+       buf[buf_size] = 0;
+
+       if (sscanf(buf, "%u", &num) != 1) {
+               err = -EPERM;
+               goto err_get_number;
+       }
+
+       channel_name = file->f_dentry->d_parent->d_name.name;
+       trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
+
+       err = ltt_trace_set_channel_subbufcount(trace_name, channel_name, num);
+       if (IS_ERR_VALUE(err)) {
+               printk(KERN_ERR "channel_subbuf_num_write: "
+                      "ltt_trace_set_channel_subbufcount failed: %d\n", err);
+               goto err_set_subbufcount;
+       }
+
+       free_page((unsigned long)buf);
+       return count;
+
+err_set_subbufcount:
+err_get_number:
+err_copy_from_user:
+       free_page((unsigned long)buf);
+       return err;
+}
+
+static const struct file_operations ltt_channel_subbuf_num_operations = {
+       .write = channel_subbuf_num_write,
+};
+
+
+static
+ssize_t channel_subbuf_size_write(struct file *file,
+                                 const char __user *user_buf,
+                                 size_t count, loff_t *ppos)
+{
+       int err = 0;
+       int buf_size;
+       unsigned int num;
+       const char *channel_name;
+       const char *trace_name;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto err_copy_from_user;
+       buf[buf_size] = 0;
+
+       if (sscanf(buf, "%u", &num) != 1) {
+               err = -EPERM;
+               goto err_get_number;
+       }
+
+       channel_name = file->f_dentry->d_parent->d_name.name;
+       trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
+
+       err = ltt_trace_set_channel_subbufsize(trace_name, channel_name, num);
+       if (IS_ERR_VALUE(err)) {
+               printk(KERN_ERR "channel_subbuf_size_write: "
+                      "ltt_trace_set_channel_subbufsize failed: %d\n", err);
+               goto err_set_subbufsize;
+       }
+
+       free_page((unsigned long)buf);
+       return count;
+
+err_set_subbufsize:
+err_get_number:
+err_copy_from_user:
+       free_page((unsigned long)buf);
+       return err;
+}
+
+static const struct file_operations ltt_channel_subbuf_size_operations = {
+       .write = channel_subbuf_size_write,
+};
+
+static
+ssize_t channel_switch_timer_write(struct file *file,
+                                  const char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       int err = 0;
+       int buf_size;
+       unsigned long num;
+       const char *channel_name;
+       const char *trace_name;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto err_copy_from_user;
+       buf[buf_size] = 0;
+
+       if (sscanf(buf, "%lu", &num) != 1) {
+               err = -EPERM;
+               goto err_get_number;
+       }
+
+       channel_name = file->f_dentry->d_parent->d_name.name;
+       trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
+
+       /* Convert from ms to us */
+       num *= 1000;
+
+       err = ltt_trace_set_channel_switch_timer(trace_name, channel_name, num);
+       if (IS_ERR_VALUE(err)) {
+               printk(KERN_ERR "channel_switch_timer_write: "
+                      "ltt_trace_set_channel_switch_timer failed: %d\n", err);
+               goto err_set_switch_timer;
+       }
+
+       free_page((unsigned long)buf);
+       return count;
+
+err_set_switch_timer:
+err_get_number:
+err_copy_from_user:
+       free_page((unsigned long)buf);
+       return err;
+}
+
+static struct file_operations ltt_channel_switch_timer_operations = {
+       .write = channel_switch_timer_write,
+};
+
+static
+ssize_t channel_overwrite_write(struct file *file,
+                               const char __user *user_buf, size_t count,
+                               loff_t *ppos)
+{
+       int err = 0;
+       int buf_size;
+       const char *channel_name;
+       const char *trace_name;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+       char *cmd = (char *)__get_free_page(GFP_KERNEL);
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto err_copy_from_user;
+       buf[buf_size] = 0;
+
+       if (sscanf(buf, "%s", cmd) != 1) {
+               err = -EPERM;
+               goto err_get_cmd;
+       }
+
+       if (cmd[1]) {
+               err = -EPERM;
+               goto err_bad_cmd;
+       }
+
+       channel_name = file->f_dentry->d_parent->d_name.name;
+       trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
+
+       switch (cmd[0]) {
+       case 'Y':
+       case 'y':
+       case '1':
+               err = ltt_trace_set_channel_overwrite(trace_name, channel_name,
+                                                     1);
+               if (IS_ERR_VALUE(err)) {
+                       printk(KERN_ERR "channel_overwrite_write: "
+                              "ltt_trace_set_channel_overwrite failed: %d\n",
+                              err);
+                       goto err_set_subbufsize;
+               }
+               break;
+       case 'N':
+       case 'n':
+       case '0':
+               err = ltt_trace_set_channel_overwrite(trace_name, channel_name,
+                                                     0);
+               if (IS_ERR_VALUE(err)) {
+                       printk(KERN_ERR "channel_overwrite_write: "
+                              "ltt_trace_set_channel_overwrite failed: %d\n",
+                              err);
+                       goto err_set_subbufsize;
+               }
+               break;
+       default:
+               err = -EPERM;
+               goto err_bad_cmd;
+       }
+
+       free_page((unsigned long)buf);
+       free_page((unsigned long)cmd);
+       return count;
+
+err_set_subbufsize:
+err_bad_cmd:
+err_get_cmd:
+err_copy_from_user:
+       free_page((unsigned long)buf);
+       free_page((unsigned long)cmd);
+       return err;
+}
+
+static const struct file_operations ltt_channel_overwrite_operations = {
+       .write = channel_overwrite_write,
+};
+
+
+static
+ssize_t channel_enable_write(struct file *file,
+                            const char __user *user_buf, size_t count,
+                            loff_t *ppos)
+{
+       int err = 0;
+       int buf_size;
+       const char *channel_name;
+       const char *trace_name;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+       char *cmd = (char *)__get_free_page(GFP_KERNEL);
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto err_copy_from_user;
+       buf[buf_size] = 0;
+
+       if (sscanf(buf, "%s", cmd) != 1) {
+               err = -EPERM;
+               goto err_get_cmd;
+       }
+
+       if (cmd[1]) {
+               err = -EPERM;
+               goto err_bad_cmd;
+       }
+
+       channel_name = file->f_dentry->d_parent->d_name.name;
+       trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
+
+       switch (cmd[0]) {
+       case 'Y':
+       case 'y':
+       case '1':
+               err = ltt_trace_set_channel_enable(trace_name, channel_name,
+                                                  1);
+               if (IS_ERR_VALUE(err)) {
+                       printk(KERN_ERR "channel_enable_write: "
+                              "ltt_trace_set_channel_enable failed: %d\n",
+                              err);
+                       goto err_set_subbufsize;
+               }
+               break;
+       case 'N':
+       case 'n':
+       case '0':
+               err = ltt_trace_set_channel_enable(trace_name, channel_name,
+                                                  0);
+               if (IS_ERR_VALUE(err)) {
+                       printk(KERN_ERR "channel_enable_write: "
+                              "ltt_trace_set_channel_enable failed: %d\n",
+                              err);
+                       goto err_set_subbufsize;
+               }
+               break;
+       default:
+               err = -EPERM;
+               goto err_bad_cmd;
+       }
+
+       free_page((unsigned long)buf);
+       free_page((unsigned long)cmd);
+       return count;
+
+err_set_subbufsize:
+err_bad_cmd:
+err_get_cmd:
+err_copy_from_user:
+       free_page((unsigned long)buf);
+       free_page((unsigned long)cmd);
+       return err;
+}
+
+static const struct file_operations ltt_channel_enable_operations = {
+       .write = channel_enable_write,
+};
+
+
+static int _create_trace_control_dir(const char *trace_name,
+                                    struct ltt_trace *trace)
+{
+       int err;
+       struct dentry *trace_root, *channel_root;
+       struct dentry *tmp_den;
+       int i;
+
+       /* debugfs/control/trace_name */
+       trace_root = debugfs_create_dir(trace_name, ltt_control_dir);
+       if (IS_ERR(trace_root) || !trace_root) {
+               printk(KERN_ERR "_create_trace_control_dir: "
+                      "create control root dir of %s failed\n", trace_name);
+               err = -ENOMEM;
+               goto err_create_trace_root;
+       }
+
+       /* debugfs/control/trace_name/alloc */
+       tmp_den = debugfs_create_file("alloc", S_IWUSR, trace_root, NULL,
+                                     &ltt_alloc_operations);
+       if (IS_ERR(tmp_den) || !tmp_den) {
+               printk(KERN_ERR "_create_trace_control_dir: "
+                      "create file of alloc failed\n");
+               err = -ENOMEM;
+               goto err_create_subdir;
+       }
+
+       /* debugfs/control/trace_name/trans */
+       tmp_den = debugfs_create_file("trans", S_IWUSR, trace_root, NULL,
+                                     &ltt_trans_operations);
+       if (IS_ERR(tmp_den) || !tmp_den) {
+               printk(KERN_ERR "_create_trace_control_dir: "
+                      "create file of trans failed\n");
+               err = -ENOMEM;
+               goto err_create_subdir;
+       }
+
+       /* debugfs/control/trace_name/enabled */
+       tmp_den = debugfs_create_file("enabled", S_IWUSR, trace_root, NULL,
+                                     &ltt_enabled_operations);
+       if (IS_ERR(tmp_den) || !tmp_den) {
+               printk(KERN_ERR "_create_trace_control_dir: "
+                      "create file of enabled failed\n");
+               err = -ENOMEM;
+               goto err_create_subdir;
+       }
+
+       /* debugfs/control/trace_name/channel/ */
+       channel_root = debugfs_create_dir("channel", trace_root);
+       if (IS_ERR(channel_root) || !channel_root) {
+               printk(KERN_ERR "_create_trace_control_dir: "
+                      "create dir of channel failed\n");
+               err = -ENOMEM;
+               goto err_create_subdir;
+       }
+
+       /*
+        * Create dir and files in debugfs/ltt/control/trace_name/channel/
+        * Following things(without <>) will be created:
+        * `-- <control>
+        *     `-- <trace_name>
+        *         `-- <channel>
+        *             |-- <channel_name>
+        *             |   |-- enable
+        *             |   |-- overwrite
+        *             |   |-- subbuf_num
+        *             |   |-- subbuf_size
+        *             |   `-- switch_timer
+        *             `-- ...
+        */
+
+       for (i = 0; i < trace->nr_channels; i++) {
+               struct dentry *channel_den;
+               struct ltt_chan *chan;
+
+               chan = &trace->channels[i];
+               if (!chan->active)
+                       continue;
+               channel_den = debugfs_create_dir(chan->a.filename,
+                                                channel_root);
+               if (IS_ERR(channel_den) || !channel_den) {
+                       printk(KERN_ERR "_create_trace_control_dir: "
+                              "create channel dir of %s failed\n",
+                              chan->a.filename);
+                       err = -ENOMEM;
+                       goto err_create_subdir;
+               }
+
+               tmp_den = debugfs_create_file("subbuf_num", S_IWUSR,
+                                             channel_den, NULL,
+                                             &ltt_channel_subbuf_num_operations);
+               if (IS_ERR(tmp_den) || !tmp_den) {
+                       printk(KERN_ERR "_create_trace_control_dir: "
+                              "create subbuf_num in %s failed\n",
+                              chan->a.filename);
+                       err = -ENOMEM;
+                       goto err_create_subdir;
+               }
+
+               tmp_den = debugfs_create_file("subbuf_size", S_IWUSR,
+                                             channel_den, NULL,
+                                             &ltt_channel_subbuf_size_operations);
+               if (IS_ERR(tmp_den) || !tmp_den) {
+                       printk(KERN_ERR "_create_trace_control_dir: "
+                              "create subbuf_size in %s failed\n",
+                              chan->a.filename);
+                       err = -ENOMEM;
+                       goto err_create_subdir;
+               }
+
+               tmp_den = debugfs_create_file("enable", S_IWUSR, channel_den,
+                                             NULL,
+                                             &ltt_channel_enable_operations);
+               if (IS_ERR(tmp_den) || !tmp_den) {
+                       printk(KERN_ERR "_create_trace_control_dir: "
+                              "create enable in %s failed\n",
+                              chan->a.filename);
+                       err = -ENOMEM;
+                       goto err_create_subdir;
+               }
+
+               tmp_den = debugfs_create_file("overwrite", S_IWUSR, channel_den,
+                                             NULL,
+                                             &ltt_channel_overwrite_operations);
+               if (IS_ERR(tmp_den) || !tmp_den) {
+                       printk(KERN_ERR "_create_trace_control_dir: "
+                              "create overwrite in %s failed\n",
+                              chan->a.filename);
+                       err = -ENOMEM;
+                       goto err_create_subdir;
+               }
+
+               tmp_den = debugfs_create_file("switch_timer", S_IWUSR,
+                                             channel_den, NULL,
+                                             &ltt_channel_switch_timer_operations);
+               if (IS_ERR(tmp_den) || !tmp_den) {
+                       printk(KERN_ERR "_create_trace_control_dir: "
+                              "create switch_timer in %s failed\n",
+                              chan->a.filename);
+                       err = -ENOMEM;
+                       goto err_create_subdir;
+               }
+       }
+
+       return 0;
+
+err_create_subdir:
+       debugfs_remove_recursive(trace_root);
+err_create_trace_root:
+       return err;
+}
+
+static
+ssize_t setup_trace_write(struct file *file, const char __user *user_buf,
+                         size_t count, loff_t *ppos)
+{
+       int err = 0;
+       int buf_size;
+       struct ltt_trace *trace;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+       char *trace_name = (char *)__get_free_page(GFP_KERNEL);
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto err_copy_from_user;
+       buf[buf_size] = 0;
+
+       if (sscanf(buf, "%s", trace_name) != 1) {
+               err = -EPERM;
+               goto err_get_tracename;
+       }
+
+       mutex_lock(&control_lock);
+       ltt_lock_traces();
+
+       err = _ltt_trace_setup(trace_name);
+       if (IS_ERR_VALUE(err)) {
+               printk(KERN_ERR
+                      "setup_trace_write: ltt_trace_setup failed: %d\n", err);
+               goto err_setup_trace;
+       }
+       trace = _ltt_trace_find_setup(trace_name);
+       BUG_ON(!trace);
+       err = _create_trace_control_dir(trace_name, trace);
+       if (IS_ERR_VALUE(err)) {
+               printk(KERN_ERR "setup_trace_write: "
+                      "_create_trace_control_dir failed: %d\n", err);
+               goto err_create_trace_control_dir;
+       }
+
+       ltt_unlock_traces();
+       mutex_unlock(&control_lock);
+
+       free_page((unsigned long)buf);
+       free_page((unsigned long)trace_name);
+       return count;
+
+err_create_trace_control_dir:
+       ltt_trace_destroy(trace_name);
+err_setup_trace:
+       ltt_unlock_traces();
+       mutex_unlock(&control_lock);
+err_get_tracename:
+err_copy_from_user:
+       free_page((unsigned long)buf);
+       free_page((unsigned long)trace_name);
+       return err;
+}
+
+static const struct file_operations ltt_setup_trace_operations = {
+       .write = setup_trace_write,
+};
+
+static
+ssize_t destroy_trace_write(struct file *file, const char __user *user_buf,
+                           size_t count, loff_t *ppos)
+{
+       struct dentry *trace_den;
+       int buf_size;
+       int err = 0;
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+       char *trace_name = (char *)__get_free_page(GFP_KERNEL);
+
+       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+       err = copy_from_user(buf, user_buf, buf_size);
+       if (err)
+               goto err_copy_from_user;
+       buf[buf_size] = 0;
+
+       if (sscanf(buf, "%s", trace_name) != 1) {
+               err = -EPERM;
+               goto err_get_tracename;
+       }
+
+       mutex_lock(&control_lock);
+
+       err = ltt_trace_destroy(trace_name);
+       if (IS_ERR_VALUE(err)) {
+               printk(KERN_ERR
+                      "destroy_trace_write: ltt_trace_destroy failed: %d\n",
+                      err);
+               err = -EPERM;
+               goto err_destroy_trace;
+       }
+
+       trace_den = dir_lookup(ltt_control_dir, trace_name);
+       if (!trace_den) {
+               printk(KERN_ERR
+                      "destroy_trace_write: lookup for %s's dentry failed\n",
+                      trace_name);
+               err = -ENOENT;
+               goto err_get_dentry;
+       }
+
+       debugfs_remove_recursive(trace_den);
+
+       mutex_unlock(&control_lock);
+
+       free_page((unsigned long)buf);
+       free_page((unsigned long)trace_name);
+       return count;
+
+err_get_dentry:
+err_destroy_trace:
+       mutex_unlock(&control_lock);
+err_get_tracename:
+err_copy_from_user:
+       free_page((unsigned long)buf);
+       free_page((unsigned long)trace_name);
+       return err;
+}
+
+static const struct file_operations ltt_destroy_trace_operations = {
+       .write = destroy_trace_write,
+};
+
+static void init_marker_dir(struct dentry *dentry,
+                           const struct inode_operations *opt)
+{
+       dentry->d_inode->i_op = opt;
+}
+
+static
+ssize_t marker_enable_read(struct file *filp, char __user *ubuf,
+                          size_t cnt, loff_t *ppos)
+{
+       char *buf;
+       const char *channel, *marker;
+       int len, enabled, present;
+
+       marker = filp->f_dentry->d_parent->d_name.name;
+       channel = filp->f_dentry->d_parent->d_parent->d_name.name;
+
+       len = 0;
+       buf = (char *)__get_free_page(GFP_KERNEL);
+
+       /*
+        * Note: we cannot take the marker lock to make these two checks
+        * atomic, because the marker mutex nests inside the module mutex, taken
+        * inside the marker present check.
+        */
+       enabled = is_marker_enabled(channel, marker);
+       present = is_marker_present(channel, marker);
+
+       if (enabled && present)
+               len = snprintf(buf, PAGE_SIZE, "%d\n", 1);
+       else if (enabled && !present)
+               len = snprintf(buf, PAGE_SIZE, "%d\n", 2);
+       else
+               len = snprintf(buf, PAGE_SIZE, "%d\n", 0);
+
+
+       if (len >= PAGE_SIZE) {
+               len = PAGE_SIZE;
+               buf[PAGE_SIZE] = '\0';
+       }
+       len = simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
+       free_page((unsigned long)buf);
+
+       return len;
+}
+
+static
+ssize_t marker_enable_write(struct file *filp, const char __user *ubuf,
+                           size_t cnt, loff_t *ppos)
+{
+       char *buf = (char *)__get_free_page(GFP_KERNEL);
+       int buf_size;
+       ssize_t ret = 0;
+       const char *channel, *marker;
+
+       marker = filp->f_dentry->d_parent->d_name.name;
+       channel = filp->f_dentry->d_parent->d_parent->d_name.name;
+
+       buf_size = min_t(size_t, cnt, PAGE_SIZE - 1);
+       ret = copy_from_user(buf, ubuf, buf_size);
+       if (ret)
+               goto end;
+
+       buf[buf_size] = 0;
+
+       switch (buf[0]) {
+       case 'Y':
+       case 'y':
+       case '1':
+               ret = ltt_marker_connect(channel, marker, "default");
+               if (ret)
+                       goto end;
+               break;
+       case 'N':
+       case 'n':
+       case '0':
+               ret = ltt_marker_disconnect(channel, marker, "default");
+               if (ret)
+                       goto end;
+               break;
+       default:
+               ret = -EPERM;
+               goto end;
+       }
+       ret = cnt;
+end:
+       free_page((unsigned long)buf);
+       return ret;
+}
+
+static const struct file_operations enable_fops = {
+       .read = marker_enable_read,
+       .write = marker_enable_write,
+};
+
+/*
+ * In practice, the output size should never be larger than 4096 kB. If it
+ * ever happens, the output will simply be truncated.
+ */
+static
+ssize_t marker_info_read(struct file *filp, char __user *ubuf,
+                        size_t cnt, loff_t *ppos)
+{
+       char *buf;
+       const char *channel, *marker;
+       int len;
+       struct marker_iter iter;
+
+       marker = filp->f_dentry->d_parent->d_name.name;
+       channel = filp->f_dentry->d_parent->d_parent->d_name.name;
+
+       len = 0;
+       buf = (char *)__get_free_page(GFP_KERNEL);
+
+       if (is_marker_enabled(channel, marker) &&
+           !is_marker_present(channel, marker)) {
+               len += snprintf(buf + len, PAGE_SIZE - len,
+                               "Marker Pre-enabled\n");
+               goto out;
+       }
+
+       marker_iter_reset(&iter);
+       marker_iter_start(&iter);
+       for (; iter.marker != NULL; marker_iter_next(&iter)) {
+               if (!strcmp(iter.marker->channel, channel) &&
+                   !strcmp(iter.marker->name, marker))
+                       len += snprintf(buf + len, PAGE_SIZE - len,
+                                      "Location: %s\n"
+                                      "format: \"%s\"\nstate: %d\n"
+                                      "event_id: %hu\n"
+                                      "call: 0x%p\n"
+                                      "probe %s : 0x%p\n\n",
+#ifdef CONFIG_MODULES
+                                      iter.module ? iter.module->name :
+#endif
+                                      "Core Kernel",
+                                      iter.marker->format,
+                                      _imv_read(iter.marker->state),
+                                      iter.marker->event_id,
+                                      iter.marker->call,
+                                      iter.marker->ptype ?
+                                      "multi" : "single", iter.marker->ptype ?
+                                      (void *)iter.marker->multi :
+                                      (void *)iter.marker->single.func);
+                       if (len >= PAGE_SIZE)
+                               break;
+       }
+       marker_iter_stop(&iter);
+
+out:
+       if (len >= PAGE_SIZE) {
+               len = PAGE_SIZE;
+               buf[PAGE_SIZE] = '\0';
+       }
+
+       len = simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
+       free_page((unsigned long)buf);
+
+       return len;
+}
+
+static const struct file_operations info_fops = {
+       .read = marker_info_read,
+};
+
+static int marker_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+       struct dentry *marker_d, *enable_d, *info_d, *channel_d;
+       int ret;
+
+       ret = 0;
+       channel_d = (struct dentry *)dir->i_private;
+       mutex_unlock(&dir->i_mutex);
+
+       marker_d = debugfs_create_dir(dentry->d_name.name,
+                                     channel_d);
+       if (IS_ERR(marker_d)) {
+               ret = PTR_ERR(marker_d);
+               goto out;
+       }
+
+       enable_d = debugfs_create_file("enable", 0644, marker_d,
+                                      NULL, &enable_fops);
+       if (IS_ERR(enable_d) || !enable_d) {
+               printk(KERN_ERR
+                      "%s: create file of %s failed\n",
+                      __func__, "enable");
+               ret = -ENOMEM;
+               goto remove_marker_dir;
+       }
+
+       info_d = debugfs_create_file("info", 0644, marker_d,
+                                    NULL, &info_fops);
+       if (IS_ERR(info_d) || !info_d) {
+               printk(KERN_ERR
+                      "%s: create file of %s failed\n",
+                      __func__, "info");
+               ret = -ENOMEM;
+               goto remove_enable_dir;
+       }
+
+       goto out;
+
+remove_enable_dir:
+       debugfs_remove(enable_d);
+remove_marker_dir:
+       debugfs_remove(marker_d);
+out:
+       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+       return ret;
+}
+
+static int marker_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       struct dentry *marker_d, *channel_d;
+       const char *channel, *name;
+       int ret, enabled, present;
+
+       ret = 0;
+
+       channel_d = (struct dentry *)dir->i_private;
+       channel = channel_d->d_name.name;
+
+       marker_d = dir_lookup(channel_d, dentry->d_name.name);
+
+       if (!marker_d) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       name = marker_d->d_name.name;
+
+       enabled = is_marker_enabled(channel, name);
+       present = is_marker_present(channel, name);
+
+       if (present || (!present && enabled)) {
+               ret = -EPERM;
+               goto out;
+       }
+
+       mutex_unlock(&dir->i_mutex);
+       mutex_unlock(&dentry->d_inode->i_mutex);
+       debugfs_remove_recursive(marker_d);
+       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+       mutex_lock(&dentry->d_inode->i_mutex);
+out:
+       return ret;
+}
+
+const struct inode_operations channel_dir_opt = {
+       .lookup = simple_lookup,
+       .mkdir = marker_mkdir,
+       .rmdir = marker_rmdir,
+};
+
+static int channel_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+       struct dentry *channel_d;
+       int ret;
+
+       ret = 0;
+       mutex_unlock(&dir->i_mutex);
+
+       channel_d = debugfs_create_dir(dentry->d_name.name,
+                                      markers_control_dir);
+       if (IS_ERR(channel_d)) {
+               ret = PTR_ERR(channel_d);
+               goto out;
+       }
+
+       channel_d->d_inode->i_private = (void *)channel_d;
+       init_marker_dir(channel_d, &channel_dir_opt);
+out:
+       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+       return ret;
+}
+
+static int channel_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       struct dentry *channel_d;
+       int ret;
+
+       ret = 0;
+
+       channel_d = dir_lookup(markers_control_dir, dentry->d_name.name);
+       if (!channel_d) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       if (list_empty(&channel_d->d_subdirs)) {
+               mutex_unlock(&dir->i_mutex);
+               mutex_unlock(&dentry->d_inode->i_mutex);
+               debugfs_remove(channel_d);
+               mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+               mutex_lock(&dentry->d_inode->i_mutex);
+       } else
+               ret = -EPERM;
+
+out:
+       return ret;
+}
+
+const struct inode_operations root_dir_opt = {
+       .lookup = simple_lookup,
+       .mkdir = channel_mkdir,
+       .rmdir = channel_rmdir
+};
+
+static int build_marker_file(struct marker *marker)
+{
+       struct dentry *channel_d, *marker_d, *enable_d, *info_d;
+       int err;
+
+       channel_d = dir_lookup(markers_control_dir, marker->channel);
+       if (!channel_d) {
+               channel_d = debugfs_create_dir(marker->channel,
+                                              markers_control_dir);
+               if (IS_ERR(channel_d) || !channel_d) {
+                       printk(KERN_ERR
+                              "%s: build channel dir of %s failed\n",
+                              __func__, marker->channel);
+                       err = -ENOMEM;
+                       goto err_build_fail;
+               }
+               channel_d->d_inode->i_private = (void *)channel_d;
+               init_marker_dir(channel_d, &channel_dir_opt);
+       }
+
+       marker_d  = dir_lookup(channel_d, marker->name);
+       if (!marker_d) {
+               marker_d = debugfs_create_dir(marker->name, channel_d);
+               if (IS_ERR(marker_d) || !marker_d) {
+                       printk(KERN_ERR
+                              "%s: marker dir of %s failed\n",
+                              __func__, marker->name);
+                       err = -ENOMEM;
+                       goto err_build_fail;
+               }
+       }
+
+       enable_d = dir_lookup(marker_d, "enable");
+       if (!enable_d) {
+               enable_d = debugfs_create_file("enable", 0644, marker_d,
+                                               NULL, &enable_fops);
+               if (IS_ERR(enable_d) || !enable_d) {
+                       printk(KERN_ERR
+                              "%s: create file of %s failed\n",
+                              __func__, "enable");
+                       err = -ENOMEM;
+                       goto err_build_fail;
+               }
+       }
+
+       info_d = dir_lookup(marker_d, "info");
+       if (!info_d) {
+               info_d = debugfs_create_file("info", 0444, marker_d,
+                                               NULL, &info_fops);
+               if (IS_ERR(info_d) || !info_d) {
+                       printk(KERN_ERR
+                              "%s: create file of %s failed\n",
+                              __func__, "enable");
+                       err = -ENOMEM;
+                       goto err_build_fail;
+               }
+       }
+
+       return 0;
+
+err_build_fail:
+       return err;
+}
+
+static int build_marker_control_files(void)
+{
+       struct marker_iter iter;
+       int err;
+
+       err = 0;
+       if (!markers_control_dir)
+               return -EEXIST;
+
+       marker_iter_reset(&iter);
+       marker_iter_start(&iter);
+       for (; iter.marker != NULL; marker_iter_next(&iter)) {
+               err = build_marker_file(iter.marker);
+               if (err)
+                       goto out;
+       }
+       marker_iter_stop(&iter);
+
+out:
+       return err;
+}
+
+#ifdef CONFIG_MODULES
+static int remove_marker_control_dir(struct module *mod, struct marker *marker)
+{
+       struct dentry *channel_d, *marker_d;
+       const char *channel, *name;
+       int count;
+       struct marker_iter iter;
+
+       count = 0;
+
+       channel_d = dir_lookup(markers_control_dir, marker->channel);
+       if (!channel_d)
+               return -ENOENT;
+       channel = channel_d->d_name.name;
+
+       marker_d = dir_lookup(channel_d, marker->name);
+       if (!marker_d)
+               return -ENOENT;
+       name = marker_d->d_name.name;
+
+       marker_iter_reset(&iter);
+       marker_iter_start(&iter);
+       for (; iter.marker != NULL; marker_iter_next(&iter)) {
+               if (!strcmp(iter.marker->channel, channel) &&
+                   !strcmp(iter.marker->name, name) && mod != iter.module)
+                       count++;
+       }
+
+       if (count > 0)
+               goto end;
+
+       debugfs_remove_recursive(marker_d);
+       if (list_empty(&channel_d->d_subdirs))
+               debugfs_remove(channel_d);
+
+end:
+       marker_iter_stop(&iter);
+       return 0;
+}
+
+static void cleanup_control_dir(struct module *mod, struct marker *begin,
+                               struct marker *end)
+{
+       struct marker *iter;
+
+       if (!markers_control_dir)
+               return;
+
+       for (iter = begin; iter < end; iter++)
+               remove_marker_control_dir(mod, iter);
+
+       return;
+}
+
+static void build_control_dir(struct module *mod, struct marker *begin,
+                             struct marker *end)
+{
+       struct marker *iter;
+       int err;
+
+       err = 0;
+       if (!markers_control_dir)
+               return;
+
+       for (iter = begin; iter < end; iter++) {
+               err = build_marker_file(iter);
+               if (err)
+                       goto err_build_fail;
+       }
+
+       return;
+err_build_fail:
+       cleanup_control_dir(mod, begin, end);
+}
+
+static int module_notify(struct notifier_block *self,
+                 unsigned long val, void *data)
+{
+       struct module *mod = data;
+
+       switch (val) {
+       case MODULE_STATE_COMING:
+               build_control_dir(mod, mod->markers,
+                                 mod->markers + mod->num_markers);
+               break;
+       case MODULE_STATE_GOING:
+               cleanup_control_dir(mod, mod->markers,
+                                   mod->markers + mod->num_markers);
+               break;
+       }
+       return NOTIFY_DONE;
+}
+#else
+static inline int module_notify(struct notifier_block *self,
+               unsigned long val, void *data)
+{
+       return 0;
+}
+#endif
+
+static struct notifier_block module_nb = {
+       .notifier_call = module_notify,
+};
+
+static int __init ltt_trace_control_init(void)
+{
+       int err = 0;
+       struct dentry *ltt_root_dentry;
+
+       ltt_root_dentry = get_ltt_root();
+       if (!ltt_root_dentry) {
+               err = -ENOENT;
+               goto err_no_root;
+       }
+
+       ltt_control_dir = debugfs_create_dir(LTT_CONTROL_DIR, ltt_root_dentry);
+       if (IS_ERR(ltt_control_dir) || !ltt_control_dir) {
+               printk(KERN_ERR
+                      "ltt_channel_control_init: create dir of %s failed\n",
+                      LTT_CONTROL_DIR);
+               err = -ENOMEM;
+               goto err_create_control_dir;
+       }
+
+       ltt_setup_trace_file = debugfs_create_file(LTT_SETUP_TRACE_FILE,
+                                                  S_IWUSR, ltt_root_dentry,
+                                                  NULL,
+                                                  &ltt_setup_trace_operations);
+       if (IS_ERR(ltt_setup_trace_file) || !ltt_setup_trace_file) {
+               printk(KERN_ERR
+                      "ltt_channel_control_init: create file of %s failed\n",
+                      LTT_SETUP_TRACE_FILE);
+               err = -ENOMEM;
+               goto err_create_setup_trace_file;
+       }
+
+       ltt_destroy_trace_file = debugfs_create_file(LTT_DESTROY_TRACE_FILE,
+                                                    S_IWUSR, ltt_root_dentry,
+                                                    NULL,
+                                                    &ltt_destroy_trace_operations);
+       if (IS_ERR(ltt_destroy_trace_file) || !ltt_destroy_trace_file) {
+               printk(KERN_ERR
+                      "ltt_channel_control_init: create file of %s failed\n",
+                      LTT_DESTROY_TRACE_FILE);
+               err = -ENOMEM;
+               goto err_create_destroy_trace_file;
+       }
+
+       markers_control_dir = debugfs_create_dir(MARKERS_CONTROL_DIR,
+                                                ltt_root_dentry);
+       if (IS_ERR(markers_control_dir) || !markers_control_dir) {
+               printk(KERN_ERR
+                      "ltt_channel_control_init: create dir of %s failed\n",
+                      MARKERS_CONTROL_DIR);
+               err = -ENOMEM;
+               goto err_create_marker_control_dir;
+       }
+
+       init_marker_dir(markers_control_dir, &root_dir_opt);
+
+       if (build_marker_control_files())
+               goto err_build_fail;
+
+       if (!register_module_notifier(&module_nb))
+               return 0;
+
+err_build_fail:
+       debugfs_remove_recursive(markers_control_dir);
+       markers_control_dir = NULL;
+err_create_marker_control_dir:
+       debugfs_remove(ltt_destroy_trace_file);
+err_create_destroy_trace_file:
+       debugfs_remove(ltt_setup_trace_file);
+err_create_setup_trace_file:
+       debugfs_remove(ltt_control_dir);
+err_create_control_dir:
+err_no_root:
+       return err;
+}
+
+static void __exit ltt_trace_control_exit(void)
+{
+       struct dentry *trace_dir;
+
+       /* destory all traces */
+       list_for_each_entry(trace_dir, &ltt_control_dir->d_subdirs,
+                           d_u.d_child) {
+               ltt_trace_stop(trace_dir->d_name.name);
+               ltt_trace_destroy(trace_dir->d_name.name);
+       }
+
+       /* clean dirs in debugfs */
+       debugfs_remove(ltt_setup_trace_file);
+       debugfs_remove(ltt_destroy_trace_file);
+       debugfs_remove_recursive(ltt_control_dir);
+       debugfs_remove_recursive(markers_control_dir);
+       unregister_module_notifier(&module_nb);
+       put_ltt_root();
+}
+
+module_init(ltt_trace_control_init);
+module_exit(ltt_trace_control_exit);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Zhao Lei <zhaolei@cn.fujitsu.com>");
+MODULE_DESCRIPTION("Linux Trace Toolkit Trace Controller");
diff --git a/discard/ltt-userspace-event.c b/discard/ltt-userspace-event.c
new file mode 100644 (file)
index 0000000..c716d72
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 Mathieu Desnoyers
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#include <linux/module.h>
+#include <linux/marker.h>
+#include <linux/uaccess.h>
+#include <linux/gfp.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+
+#include "ltt-type-serializer.h"
+
+#define LTT_WRITE_EVENT_FILE   "write_event"
+
+DEFINE_MARKER(userspace, event, "string %s");
+static struct dentry *ltt_event_file;
+
+/**
+ * write_event - write a userspace string into the trace system
+ * @file: file pointer
+ * @user_buf: user string
+ * @count: length to copy, including the final NULL
+ * @ppos: unused
+ *
+ * Copy a string into a trace event, in channel "userspace", event "event".
+ * Copies until either \n or \0 is reached.
+ * On success, returns the number of bytes copied from the source, including the
+ * \n or \0 character (if there was one in the count range). It cannot return
+ * more than count.
+ * Inspired from tracing_mark_write implementation from Steven Rostedt and
+ * Ingo Molnar.
+ */
+static
+ssize_t write_event(struct file *file, const char __user *user_buf,
+                   size_t count, loff_t *ppos)
+{
+       struct marker *marker;
+       char *buf, *end;
+       long copycount;
+       ssize_t ret;
+
+       buf = kmalloc(count + 1, GFP_KERNEL);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto string_out;
+       }
+       copycount = strncpy_from_user(buf, user_buf, count);
+       if (copycount < 0) {
+               ret = -EFAULT;
+               goto string_err;
+       }
+       /* Cut from the first nil or newline. */
+       buf[copycount] = '\0';
+       end = strchr(buf, '\n');
+       if (end) {
+               *end = '\0';
+               copycount = end - buf;
+       }
+       /* Add final \0 to copycount */
+       copycount++;
+       marker = &GET_MARKER(userspace, event);
+       ltt_specialized_trace(marker, marker->single.probe_private, buf,
+                             copycount, sizeof(char));
+       /* If there is no \0 nor \n in count, do not return a larger value */
+       ret = min_t(size_t, copycount, count);
+string_err:
+       kfree(buf);
+string_out:
+       return ret;
+}
+
+static const struct file_operations ltt_userspace_operations = {
+       .write = write_event,
+};
+
+static int __init ltt_userspace_init(void)
+{
+       struct dentry *ltt_root_dentry;
+       int err = 0;
+
+       ltt_root_dentry = get_ltt_root();
+       if (!ltt_root_dentry) {
+               err = -ENOENT;
+               goto err_no_root;
+       }
+
+       ltt_event_file = debugfs_create_file(LTT_WRITE_EVENT_FILE,
+                                            S_IWUGO,
+                                            ltt_root_dentry,
+                                            NULL,
+                                            &ltt_userspace_operations);
+       if (IS_ERR(ltt_event_file) || !ltt_event_file) {
+               printk(KERN_ERR
+                       "ltt_userspace_init: failed to create file %s\n",
+                       LTT_WRITE_EVENT_FILE);
+               err = -EPERM;
+               goto err_no_file;
+       }
+
+       return err;
+err_no_file:
+       put_ltt_root();
+err_no_root:
+       return err;
+}
+
+static void __exit ltt_userspace_exit(void)
+{
+       debugfs_remove(ltt_event_file);
+       put_ltt_root();
+}
+
+module_init(ltt_userspace_init);
+module_exit(ltt_userspace_exit);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>");
+MODULE_DESCRIPTION("Linux Trace Toolkit Userspace Event");
diff --git a/ltt-filter.c b/ltt-filter.c
deleted file mode 100644 (file)
index ec113af..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2008 Mathieu Desnoyers
- *
- * Dual LGPL v2.1/GPL v2 license.
- */
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/fs.h>
-#include <linux/mutex.h>
-
-#include "ltt-tracer.h"
-
-#define LTT_FILTER_DIR "filter"
-
-/*
- * Protects the ltt_filter_dir allocation.
- */
-static DEFINE_MUTEX(ltt_filter_mutex);
-
-static struct dentry *ltt_filter_dir;
-
-struct dentry *get_filter_root(void)
-{
-       struct dentry *ltt_root_dentry;
-
-       mutex_lock(&ltt_filter_mutex);
-       if (!ltt_filter_dir) {
-               ltt_root_dentry = get_ltt_root();
-               if (!ltt_root_dentry)
-                       goto err_no_root;
-
-               ltt_filter_dir = debugfs_create_dir(LTT_FILTER_DIR,
-                                                   ltt_root_dentry);
-               if (!ltt_filter_dir)
-                       printk(KERN_ERR
-                              "ltt_filter_init: failed to create dir %s\n",
-                              LTT_FILTER_DIR);
-       }
-err_no_root:
-       mutex_unlock(&ltt_filter_mutex);
-       return ltt_filter_dir;
-}
-EXPORT_SYMBOL_GPL(get_filter_root);
-
-static void __exit ltt_filter_exit(void)
-{
-       debugfs_remove(ltt_filter_dir);
-}
-
-module_exit(ltt_filter_exit);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>");
-MODULE_DESCRIPTION("Linux Trace Toolkit Filter");
diff --git a/ltt-kprobes.c b/ltt-kprobes.c
deleted file mode 100644 (file)
index 7539381..0000000
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * (C) Copyright       2009 -
- *             Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
- *
- * LTTng kprobes integration module.
- *
- * Dual LGPL v2.1/GPL v2 license.
- */
-
-#include <linux/module.h>
-#include <linux/kprobes.h>
-#include <linux/marker.h>
-#include <linux/mutex.h>
-#include <linux/jhash.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/debugfs.h>
-#include <linux/kallsyms.h>
-
-#include "ltt-type-serializer.h"
-#include "ltt-tracer.h"
-
-#define LTT_KPROBES_DIR        "kprobes"
-#define LTT_KPROBES_ENABLE     "enable"
-#define LTT_KPROBES_DISABLE    "disable"
-#define LTT_KPROBES_LIST       "list"
-
-/* Active LTTng kprobes hash table */
-static DEFINE_MUTEX(ltt_kprobes_mutex);
-
-#define LTT_KPROBE_HASH_BITS   6
-#define LTT_KPROBE_TABLE_SIZE  (1 << LTT_KPROBE_HASH_BITS)
-static struct hlist_head ltt_kprobe_table[LTT_KPROBE_TABLE_SIZE];
-
-struct kprobe_entry {
-       struct hlist_node hlist;
-       struct kprobe kp;
-       char key[0];
-};
-
-static struct dentry *ltt_kprobes_dir,
-                    *ltt_kprobes_enable_dentry,
-                    *ltt_kprobes_disable_dentry,
-                    *ltt_kprobes_list_dentry;
-
-static int module_exit;
-
-
-static void trace_kprobe_table_entry(void *call_data, struct kprobe_entry *e)
-{
-       unsigned long addr;
-       char *namebuf = (char *)__get_free_page(GFP_KERNEL);
-
-       if (e->kp.addr) {
-               sprint_symbol(namebuf, (unsigned long)e->kp.addr);
-               addr = (unsigned long)e->kp.addr;
-       } else {
-               strncpy(namebuf, e->kp.symbol_name, PAGE_SIZE - 1);
-               /* TODO : add offset */
-               addr = kallsyms_lookup_name(namebuf);
-       }
-       if (addr)
-               __trace_mark(0, kprobe_state, kprobe_table, call_data,
-                            "ip 0x%lX symbol %s", addr, namebuf);
-       free_page((unsigned long)namebuf);
-}
-
-DEFINE_MARKER(kernel, kprobe, "ip %lX");
-
-static int ltt_kprobe_handler_pre(struct kprobe *p, struct pt_regs *regs)
-{
-       struct marker *marker;
-       unsigned long data;
-
-       data = (unsigned long)p->addr;
-       marker = &GET_MARKER(kernel, kprobe);
-       ltt_specialized_trace(marker, marker->single.probe_private,
-                             &data, sizeof(data), sizeof(data));
-       return 0;
-}
-
-static int ltt_register_kprobe(const char *key)
-{
-       struct hlist_head *head;
-       struct hlist_node *node;
-       struct kprobe_entry *e = NULL;
-       char *symbol_name = NULL;
-       unsigned long addr;
-       unsigned int offset = 0;
-       u32 hash;
-       size_t key_len = strlen(key) + 1;
-       int ret;
-
-       if (key_len == 1)
-               return -ENOENT; /* only \0 */
-
-       if (sscanf(key, "%li", &addr) != 1)
-               addr = 0;
-
-       if (!addr) {
-               const char *symbol_end = NULL;
-               unsigned int symbol_len;        /* includes final \0 */
-
-               symbol_end = strchr(key, ' ');
-               if (symbol_end)
-                       symbol_len = symbol_end - key + 1;
-               else
-                       symbol_len = key_len;
-               symbol_name = kmalloc(symbol_len, GFP_KERNEL);
-               if (!symbol_name) {
-                       ret = -ENOMEM;
-                       goto error;
-               }
-               memcpy(symbol_name, key, symbol_len - 1);
-               symbol_name[symbol_len-1] = '\0';
-               if (symbol_end) {
-                       symbol_end++;   /* start of offset */
-                       if (sscanf(symbol_end, "%i", &offset) != 1)
-                               offset = 0;
-               }
-       }
-
-       hash = jhash(key, key_len-1, 0);
-       head = &ltt_kprobe_table[hash & ((1 << LTT_KPROBE_HASH_BITS)-1)];
-       hlist_for_each_entry(e, node, head, hlist) {
-               if (!strcmp(key, e->key)) {
-                       printk(KERN_NOTICE "Kprobe %s busy\n", key);
-                       ret = -EBUSY;
-                       goto error;
-               }
-       }
-       /*
-        * Using kzalloc here to allocate a variable length element. Could
-        * cause some memory fragmentation if overused.
-        */
-       e = kzalloc(sizeof(struct kprobe_entry) + key_len, GFP_KERNEL);
-       if (!e) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       memcpy(e->key, key, key_len);
-       hlist_add_head(&e->hlist, head);
-       e->kp.pre_handler = ltt_kprobe_handler_pre;
-       e->kp.symbol_name = symbol_name;
-       e->kp.offset = offset;
-       e->kp.addr = (void *)addr;
-       ret = register_kprobe(&e->kp);
-       if (ret < 0)
-               goto error_list_del;
-       trace_kprobe_table_entry(NULL, e);
-       return 0;
-
-error_list_del:
-       hlist_del(&e->hlist);
-error:
-       kfree(symbol_name);
-       kfree(e);
-       return ret;
-}
-
-static int ltt_unregister_kprobe(const char *key)
-{
-       struct hlist_head *head;
-       struct hlist_node *node;
-       struct kprobe_entry *e;
-       int found = 0;
-       size_t key_len = strlen(key) + 1;
-       u32 hash;
-
-       hash = jhash(key, key_len-1, 0);
-       head = &ltt_kprobe_table[hash & ((1 << LTT_KPROBE_HASH_BITS)-1)];
-       hlist_for_each_entry(e, node, head, hlist) {
-               if (!strcmp(key, e->key)) {
-                       found = 1;
-                       break;
-               }
-       }
-       if (!found)
-               return -ENOENT;
-       hlist_del(&e->hlist);
-       unregister_kprobe(&e->kp);
-       kfree(e->kp.symbol_name);
-       kfree(e);
-       return 0;
-}
-
-static void ltt_unregister_all_kprobes(void)
-{
-       struct kprobe_entry *e;
-       struct hlist_head *head;
-       struct hlist_node *node, *tmp;
-       unsigned int i;
-
-       for (i = 0; i < LTT_KPROBE_TABLE_SIZE; i++) {
-               head = &ltt_kprobe_table[i];
-               hlist_for_each_entry_safe(e, node, tmp, head, hlist) {
-                       hlist_del(&e->hlist);
-                       unregister_kprobe(&e->kp);
-                       kfree(e->kp.symbol_name);
-                       kfree(e);
-               }
-       }
-}
-
-/*
- * Allows to specify either
- * - symbol
- * - symbol offset
- * - address
- */
-static ssize_t enable_op_write(struct file *file,
-       const char __user *user_buf, size_t count, loff_t *ppos)
-{
-       int err, buf_size;
-       char *end;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-
-       mutex_lock(&ltt_kprobes_mutex);
-       if (module_exit) {
-               err = -EPERM;
-               goto error;
-       }
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto error;
-       buf[buf_size] = '\0';
-       end = strchr(buf, '\n');
-       if (end)
-               *end = '\0';
-       err = ltt_register_kprobe(buf);
-       if (err)
-               goto error;
-
-       mutex_unlock(&ltt_kprobes_mutex);
-       free_page((unsigned long)buf);
-       return count;
-error:
-       mutex_unlock(&ltt_kprobes_mutex);
-       free_page((unsigned long)buf);
-       return err;
-}
-
-static const struct file_operations ltt_kprobes_enable = {
-       .write = enable_op_write,
-};
-
-static ssize_t disable_op_write(struct file *file,
-       const char __user *user_buf, size_t count, loff_t *ppos)
-{
-       int err, buf_size;
-       char *end;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-
-       mutex_lock(&ltt_kprobes_mutex);
-       if (module_exit)
-               goto end;
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto error;
-       buf[buf_size] = '\0';
-       end = strchr(buf, '\n');
-       if (end)
-               *end = '\0';
-       err = ltt_unregister_kprobe(buf);
-       if (err)
-               goto error;
-end:
-       mutex_unlock(&ltt_kprobes_mutex);
-       free_page((unsigned long)buf);
-       return count;
-error:
-       mutex_unlock(&ltt_kprobes_mutex);
-       free_page((unsigned long)buf);
-       return err;
-}
-
-static const struct file_operations ltt_kprobes_disable = {
-       .write = disable_op_write,
-};
-
-/*
- * This seqfile read is not perfectly safe, as a kprobe could be removed from
- * the hash table between two reads. This will result in an incomplete output.
- */
-static struct kprobe_entry *ltt_find_next_kprobe(struct kprobe_entry *prev)
-{
-       struct kprobe_entry *e;
-       struct hlist_head *head;
-       struct hlist_node *node;
-       unsigned int i;
-       int found = 0;
-
-       if (prev == (void *)-1UL)
-               return NULL;
-
-       if (!prev)
-               found = 1;
-
-       for (i = 0; i < LTT_KPROBE_TABLE_SIZE; i++) {
-               head = &ltt_kprobe_table[i];
-               hlist_for_each_entry(e, node, head, hlist) {
-                       if (found)
-                               return e;
-                       if (e == prev)
-                               found = 1;
-               }
-       }
-       return NULL;
-}
-
-static void *lk_next(struct seq_file *m, void *p, loff_t *pos)
-{
-       m->private = ltt_find_next_kprobe(m->private);
-       if (!m->private) {
-               m->private = (void *)-1UL;
-               return NULL;
-       }
-       return m->private;
-}
-
-static void *lk_start(struct seq_file *m, loff_t *pos)
-{
-       mutex_lock(&ltt_kprobes_mutex);
-       if (!*pos)
-               m->private = NULL;
-       m->private = ltt_find_next_kprobe(m->private);
-       if (!m->private) {
-               m->private = (void *)-1UL;
-               return NULL;
-       }
-       return m->private;
-}
-
-static void lk_stop(struct seq_file *m, void *p)
-{
-       mutex_unlock(&ltt_kprobes_mutex);
-}
-
-static int lk_show(struct seq_file *m, void *p)
-{
-       struct kprobe_entry *e = m->private;
-       seq_printf(m, "%s\n", e->key);
-       return 0;
-}
-
-static const struct seq_operations ltt_kprobes_list_op = {
-       .start = lk_start,
-       .next = lk_next,
-       .stop = lk_stop,
-       .show = lk_show,
-};
-
-static int ltt_kprobes_list_open(struct inode *inode, struct file *file)
-{
-       int ret;
-
-       ret = seq_open(file, &ltt_kprobes_list_op);
-       if (ret == 0)
-               ((struct seq_file *)file->private_data)->private = NULL;
-       return ret;
-}
-
-static int ltt_kprobes_list_release(struct inode *inode, struct file *file)
-{
-       struct seq_file *seq = file->private_data;
-
-       seq->private = NULL;
-       return seq_release(inode, file);
-}
-
-static const struct file_operations ltt_kprobes_list = {
-       .open = ltt_kprobes_list_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = ltt_kprobes_list_release,
-};
-
-/*
- * kprobes table dump. Callback invoked by ltt-statedump. ltt-statedump must
- * take a reference to this module before calling this callback.
- */
-void ltt_dump_kprobes_table(void *call_data)
-{
-       struct kprobe_entry *e;
-       struct hlist_head *head;
-       struct hlist_node *node;
-       unsigned int i;
-
-       for (i = 0; i < LTT_KPROBE_TABLE_SIZE; i++) {
-               head = &ltt_kprobe_table[i];
-               hlist_for_each_entry(e, node, head, hlist)
-                       trace_kprobe_table_entry(call_data, e);
-       }
-}
-EXPORT_SYMBOL_GPL(ltt_dump_kprobes_table);
-
-static int __init ltt_kprobes_init(void)
-{
-       struct dentry *ltt_root_dentry;
-       int ret = 0;
-
-       printk(KERN_INFO "LTT : ltt-kprobes init\n");
-       mutex_lock(&ltt_kprobes_mutex);
-
-       ltt_root_dentry = get_ltt_root();
-       if (!ltt_root_dentry) {
-               ret = -ENOENT;
-               goto err_no_root;
-       }
-
-       ltt_kprobes_dir = debugfs_create_dir(LTT_KPROBES_DIR, ltt_root_dentry);
-       if (!ltt_kprobes_dir) {
-               printk(KERN_ERR
-                      "ltt_kprobes_init: failed to create dir %s\n",
-                       LTT_KPROBES_DIR);
-               ret = -ENOMEM;
-               goto err_no_dir;
-       }
-
-       ltt_kprobes_enable_dentry = debugfs_create_file(LTT_KPROBES_ENABLE,
-                                                       S_IWUSR,
-                                                       ltt_kprobes_dir, NULL,
-                                                       &ltt_kprobes_enable);
-       if (IS_ERR(ltt_kprobes_enable_dentry) || !ltt_kprobes_enable_dentry) {
-               printk(KERN_ERR
-                      "ltt_kprobes_init: failed to create file %s\n",
-                       LTT_KPROBES_ENABLE);
-               ret = -ENOMEM;
-               goto err_no_enable;
-       }
-
-       ltt_kprobes_disable_dentry = debugfs_create_file(LTT_KPROBES_DISABLE,
-                                                        S_IWUSR,
-                                                        ltt_kprobes_dir, NULL,
-                                                        &ltt_kprobes_disable);
-       if (IS_ERR(ltt_kprobes_disable_dentry) || !ltt_kprobes_disable_dentry) {
-               printk(KERN_ERR
-                      "ltt_kprobes_init: failed to create file %s\n",
-                       LTT_KPROBES_DISABLE);
-               ret = -ENOMEM;
-               goto err_no_disable;
-       }
-
-       ltt_kprobes_list_dentry = debugfs_create_file(LTT_KPROBES_LIST,
-                                                     S_IWUSR, ltt_kprobes_dir,
-                                                     NULL, &ltt_kprobes_list);
-       if (IS_ERR(ltt_kprobes_list_dentry) || !ltt_kprobes_list_dentry) {
-               printk(KERN_ERR
-                      "ltt_kprobes_init: failed to create file %s\n",
-                       LTT_KPROBES_LIST);
-               ret = -ENOMEM;
-               goto err_no_list;
-       }
-       ltt_statedump_register_kprobes_dump(ltt_dump_kprobes_table);
-
-       mutex_unlock(&ltt_kprobes_mutex);
-       return ret;
-
-err_no_list:
-       debugfs_remove(ltt_kprobes_disable_dentry);
-err_no_disable:
-       debugfs_remove(ltt_kprobes_enable_dentry);
-err_no_enable:
-       debugfs_remove(ltt_kprobes_dir);
-err_no_dir:
-err_no_root:
-       mutex_unlock(&ltt_kprobes_mutex);
-       return ret;
-}
-module_init(ltt_kprobes_init);
-
-static void __exit ltt_kprobes_exit(void)
-{
-       printk(KERN_INFO "LTT : ltt-kprobes exit\n");
-       mutex_lock(&ltt_kprobes_mutex);
-       module_exit = 1;
-       ltt_statedump_unregister_kprobes_dump(ltt_dump_kprobes_table);
-       debugfs_remove(ltt_kprobes_list_dentry);
-       debugfs_remove(ltt_kprobes_disable_dentry);
-       debugfs_remove(ltt_kprobes_enable_dentry);
-       debugfs_remove(ltt_kprobes_dir);
-       ltt_unregister_all_kprobes();
-       mutex_unlock(&ltt_kprobes_mutex);
-}
-module_exit(ltt_kprobes_exit);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers");
-MODULE_DESCRIPTION("Linux Trace Toolkit Kprobes Support");
diff --git a/ltt-statedump.c b/ltt-statedump.c
deleted file mode 100644 (file)
index 06ade69..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * Linux Trace Toolkit Kernel State Dump
- *
- * Copyright 2005 -
- * Jean-Hugues Deschenes <jean-hugues.deschenes@polymtl.ca>
- *
- * Changes:
- *     Eric Clement:                   Add listing of network IP interface
- *     2006, 2007 Mathieu Desnoyers    Fix kernel threads
- *                                     Various updates
- *
- * Dual LGPL v2.1/GPL v2 license.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netlink.h>
-#include <linux/inet.h>
-#include <linux/ip.h>
-#include <linux/kthread.h>
-#include <linux/proc_fs.h>
-#include <linux/file.h>
-#include <linux/interrupt.h>
-#include <linux/irqnr.h>
-#include <linux/cpu.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/marker.h>
-#include <linux/fdtable.h>
-#include <linux/swap.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-#include "ltt-tracer.h"
-
-#ifdef CONFIG_GENERIC_HARDIRQS
-#include <linux/irq.h>
-#endif
-
-#define NB_PROC_CHUNK 20
-
-/*
- * Protected by the trace lock.
- */
-static struct delayed_work cpu_work[NR_CPUS];
-static DECLARE_WAIT_QUEUE_HEAD(statedump_wq);
-static atomic_t kernel_threads_to_run;
-
-static void empty_cb(void *call_data)
-{
-}
-
-static DEFINE_MUTEX(statedump_cb_mutex);
-static void (*ltt_dump_kprobes_table_cb)(void *call_data) = empty_cb;
-
-enum lttng_thread_type {
-       LTTNG_USER_THREAD = 0,
-       LTTNG_KERNEL_THREAD = 1,
-};
-
-enum lttng_execution_mode {
-       LTTNG_USER_MODE = 0,
-       LTTNG_SYSCALL = 1,
-       LTTNG_TRAP = 2,
-       LTTNG_IRQ = 3,
-       LTTNG_SOFTIRQ = 4,
-       LTTNG_MODE_UNKNOWN = 5,
-};
-
-enum lttng_execution_submode {
-       LTTNG_NONE = 0,
-       LTTNG_UNKNOWN = 1,
-};
-
-enum lttng_process_status {
-       LTTNG_UNNAMED = 0,
-       LTTNG_WAIT_FORK = 1,
-       LTTNG_WAIT_CPU = 2,
-       LTTNG_EXIT = 3,
-       LTTNG_ZOMBIE = 4,
-       LTTNG_WAIT = 5,
-       LTTNG_RUN = 6,
-       LTTNG_DEAD = 7,
-};
-
-#ifdef CONFIG_INET
-static void ltt_enumerate_device(struct ltt_probe_private_data *call_data,
-                                struct net_device *dev)
-{
-       struct in_device *in_dev;
-       struct in_ifaddr *ifa;
-
-       if (dev->flags & IFF_UP) {
-               in_dev = in_dev_get(dev);
-               if (in_dev) {
-                       for (ifa = in_dev->ifa_list; ifa != NULL;
-                            ifa = ifa->ifa_next)
-                               __trace_mark(0, netif_state,
-                                            network_ipv4_interface,
-                                            call_data,
-                                            "name %s address #n4u%lu up %d",
-                                            dev->name,
-                                            (unsigned long)ifa->ifa_address,
-                                            0);
-                       in_dev_put(in_dev);
-               }
-       } else
-               __trace_mark(0, netif_state, network_ip_interface,
-                            call_data, "name %s address #n4u%lu up %d",
-                            dev->name, 0UL, 0);
-}
-
-static inline int
-ltt_enumerate_network_ip_interface(struct ltt_probe_private_data *call_data)
-{
-       struct net_device *dev;
-
-       read_lock(&dev_base_lock);
-       for_each_netdev(&init_net, dev)
-               ltt_enumerate_device(call_data, dev);
-       read_unlock(&dev_base_lock);
-
-       return 0;
-}
-#else /* CONFIG_INET */
-static inline int
-ltt_enumerate_network_ip_interface(struct ltt_probe_private_data *call_data)
-{
-       return 0;
-}
-#endif /* CONFIG_INET */
-
-
-static inline void
-ltt_enumerate_task_fd(struct ltt_probe_private_data *call_data,
-                     struct task_struct *t, char *tmp)
-{
-       struct fdtable *fdt;
-       struct file *filp;
-       unsigned int i;
-       const unsigned char *path;
-
-       if (!t->files)
-               return;
-
-       spin_lock(&t->files->file_lock);
-       fdt = files_fdtable(t->files);
-       for (i = 0; i < fdt->max_fds; i++) {
-               filp = fcheck_files(t->files, i);
-               if (!filp)
-                       continue;
-               path = d_path(&filp->f_path, tmp, PAGE_SIZE);
-               /* Make sure we give at least some info */
-               __trace_mark(0, fd_state, file_descriptor, call_data,
-                            "filename %s pid %d fd %u",
-                            (IS_ERR(path))?(filp->f_dentry->d_name.name):(path),
-                            t->pid, i);
-       }
-       spin_unlock(&t->files->file_lock);
-}
-
-static inline int
-ltt_enumerate_file_descriptors(struct ltt_probe_private_data *call_data)
-{
-       struct task_struct *t = &init_task;
-       char *tmp = (char *)__get_free_page(GFP_KERNEL);
-
-       /* Enumerate active file descriptors */
-       do {
-               read_lock(&tasklist_lock);
-               if (t != &init_task)
-                       atomic_dec(&t->usage);
-               t = next_task(t);
-               atomic_inc(&t->usage);
-               read_unlock(&tasklist_lock);
-               task_lock(t);
-               ltt_enumerate_task_fd(call_data, t, tmp);
-               task_unlock(t);
-       } while (t != &init_task);
-       free_page((unsigned long)tmp);
-       return 0;
-}
-
-static inline void
-ltt_enumerate_task_vm_maps(struct ltt_probe_private_data *call_data,
-               struct task_struct *t)
-{
-       struct mm_struct *mm;
-       struct vm_area_struct *map;
-       unsigned long ino;
-
-       /* get_task_mm does a task_lock... */
-       mm = get_task_mm(t);
-       if (!mm)
-               return;
-
-       map = mm->mmap;
-       if (map) {
-               down_read(&mm->mmap_sem);
-               while (map) {
-                       if (map->vm_file)
-                               ino = map->vm_file->f_dentry->d_inode->i_ino;
-                       else
-                               ino = 0;
-                       __trace_mark(0, vm_state, vm_map, call_data,
-                                    "pid %d start %lu end %lu flags %lu "
-                                    "pgoff %lu inode %lu",
-                                    t->pid, map->vm_start, map->vm_end,
-                                    map->vm_flags, map->vm_pgoff << PAGE_SHIFT,
-                                    ino);
-                       map = map->vm_next;
-               }
-               up_read(&mm->mmap_sem);
-       }
-       mmput(mm);
-}
-
-static inline int
-ltt_enumerate_vm_maps(struct ltt_probe_private_data *call_data)
-{
-       struct task_struct *t = &init_task;
-
-       do {
-               read_lock(&tasklist_lock);
-               if (t != &init_task)
-                       atomic_dec(&t->usage);
-               t = next_task(t);
-               atomic_inc(&t->usage);
-               read_unlock(&tasklist_lock);
-               ltt_enumerate_task_vm_maps(call_data, t);
-       } while (t != &init_task);
-       return 0;
-}
-
-#ifdef CONFIG_GENERIC_HARDIRQS
-static inline void list_interrupts(struct ltt_probe_private_data *call_data)
-{
-       unsigned int irq;
-       unsigned long flags = 0;
-       struct irq_desc *desc;
-
-       /* needs irq_desc */
-       for_each_irq_desc(irq, desc) {
-               struct irqaction *action;
-               const char *irq_chip_name =
-                       desc->chip->name ? : "unnamed_irq_chip";
-
-               local_irq_save(flags);
-               raw_spin_lock(&desc->lock);
-               for (action = desc->action; action; action = action->next)
-                       __trace_mark(0, irq_state, interrupt, call_data,
-                                    "name %s action %s irq_id %u",
-                                    irq_chip_name, action->name, irq);
-               raw_spin_unlock(&desc->lock);
-               local_irq_restore(flags);
-       }
-}
-#else
-static inline void list_interrupts(struct ltt_probe_private_data *call_data)
-{
-}
-#endif
-
-static inline int
-ltt_enumerate_process_states(struct ltt_probe_private_data *call_data)
-{
-       struct task_struct *t = &init_task;
-       struct task_struct *p = t;
-       enum lttng_process_status status;
-       enum lttng_thread_type type;
-       enum lttng_execution_mode mode;
-       enum lttng_execution_submode submode;
-
-       do {
-               mode = LTTNG_MODE_UNKNOWN;
-               submode = LTTNG_UNKNOWN;
-
-               read_lock(&tasklist_lock);
-               if (t != &init_task) {
-                       atomic_dec(&t->usage);
-                       t = next_thread(t);
-               }
-               if (t == p) {
-                       p = next_task(t);
-                       t = p;
-               }
-               atomic_inc(&t->usage);
-               read_unlock(&tasklist_lock);
-
-               task_lock(t);
-
-               if (t->exit_state == EXIT_ZOMBIE)
-                       status = LTTNG_ZOMBIE;
-               else if (t->exit_state == EXIT_DEAD)
-                       status = LTTNG_DEAD;
-               else if (t->state == TASK_RUNNING) {
-                       /* Is this a forked child that has not run yet? */
-                       if (list_empty(&t->rt.run_list))
-                               status = LTTNG_WAIT_FORK;
-                       else
-                               /*
-                                * All tasks are considered as wait_cpu;
-                                * the viewer will sort out if the task was
-                                * really running at this time.
-                                */
-                               status = LTTNG_WAIT_CPU;
-               } else if (t->state &
-                       (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)) {
-                       /* Task is waiting for something to complete */
-                       status = LTTNG_WAIT;
-               } else
-                       status = LTTNG_UNNAMED;
-               submode = LTTNG_NONE;
-
-               /*
-                * Verification of t->mm is to filter out kernel threads;
-                * Viewer will further filter out if a user-space thread was
-                * in syscall mode or not.
-                */
-               if (t->mm)
-                       type = LTTNG_USER_THREAD;
-               else
-                       type = LTTNG_KERNEL_THREAD;
-
-               __trace_mark(0, task_state, process_state, call_data,
-                            "pid %d parent_pid %d name %s type %d mode %d "
-                            "submode %d status %d tgid %d",
-                            t->pid, t->parent->pid, t->comm,
-                            type, mode, submode, status, t->tgid);
-               task_unlock(t);
-       } while (t != &init_task);
-
-       return 0;
-}
-
-void ltt_statedump_register_kprobes_dump(void (*callback)(void *call_data))
-{
-       mutex_lock(&statedump_cb_mutex);
-       ltt_dump_kprobes_table_cb = callback;
-       mutex_unlock(&statedump_cb_mutex);
-}
-EXPORT_SYMBOL_GPL(ltt_statedump_register_kprobes_dump);
-
-void ltt_statedump_unregister_kprobes_dump(void (*callback)(void *call_data))
-{
-       mutex_lock(&statedump_cb_mutex);
-       ltt_dump_kprobes_table_cb = empty_cb;
-       mutex_unlock(&statedump_cb_mutex);
-}
-EXPORT_SYMBOL_GPL(ltt_statedump_unregister_kprobes_dump);
-
-void ltt_statedump_work_func(struct work_struct *work)
-{
-       if (atomic_dec_and_test(&kernel_threads_to_run))
-               /* If we are the last thread, wake up do_ltt_statedump */
-               wake_up(&statedump_wq);
-}
-
-static int do_ltt_statedump(struct ltt_probe_private_data *call_data)
-{
-       int cpu;
-       struct module *cb_owner;
-
-       printk(KERN_DEBUG "LTT state dump thread start\n");
-       ltt_enumerate_process_states(call_data);
-       ltt_enumerate_file_descriptors(call_data);
-       list_modules(call_data);
-       ltt_enumerate_vm_maps(call_data);
-       list_interrupts(call_data);
-       ltt_enumerate_network_ip_interface(call_data);
-       ltt_dump_swap_files(call_data);
-       ltt_dump_sys_call_table(call_data);
-       ltt_dump_softirq_vec(call_data);
-       ltt_dump_idt_table(call_data);
-
-       mutex_lock(&statedump_cb_mutex);
-
-       cb_owner = __module_address((unsigned long)ltt_dump_kprobes_table_cb);
-       __module_get(cb_owner);
-       ltt_dump_kprobes_table_cb(call_data);
-       module_put(cb_owner);
-
-       mutex_unlock(&statedump_cb_mutex);
-
-       /*
-        * Fire off a work queue on each CPU. Their sole purpose in life
-        * is to guarantee that each CPU has been in a state where is was in
-        * syscall mode (i.e. not in a trap, an IRQ or a soft IRQ).
-        */
-       get_online_cpus();
-       atomic_set(&kernel_threads_to_run, num_online_cpus());
-       for_each_online_cpu(cpu) {
-               INIT_DELAYED_WORK(&cpu_work[cpu], ltt_statedump_work_func);
-               schedule_delayed_work_on(cpu, &cpu_work[cpu], 0);
-       }
-       /* Wait for all threads to run */
-       __wait_event(statedump_wq, (atomic_read(&kernel_threads_to_run) != 0));
-       put_online_cpus();
-       /* Our work is done */
-       printk(KERN_DEBUG "LTT state dump end\n");
-       __trace_mark(0, global_state, statedump_end,
-                    call_data, MARK_NOARGS);
-       return 0;
-}
-
-/*
- * Called with trace lock held.
- */
-int ltt_statedump_start(struct ltt_trace *trace)
-{
-       struct ltt_probe_private_data call_data;
-       printk(KERN_DEBUG "LTT state dump begin\n");
-
-       call_data.trace = trace;
-       call_data.serializer = NULL;
-       return do_ltt_statedump(&call_data);
-}
-
-static int __init statedump_init(void)
-{
-       int ret;
-       printk(KERN_DEBUG "LTT : State dump init\n");
-       ret = ltt_module_register(LTT_FUNCTION_STATEDUMP,
-                       ltt_statedump_start, THIS_MODULE);
-       return ret;
-}
-
-static void __exit statedump_exit(void)
-{
-       printk(KERN_DEBUG "LTT : State dump exit\n");
-       ltt_module_unregister(LTT_FUNCTION_STATEDUMP);
-}
-
-module_init(statedump_init)
-module_exit(statedump_exit)
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Jean-Hugues Deschenes");
-MODULE_DESCRIPTION("Linux Trace Toolkit Statedump");
diff --git a/ltt-trace-control.c b/ltt-trace-control.c
deleted file mode 100644 (file)
index 0a02549..0000000
+++ /dev/null
@@ -1,1426 +0,0 @@
-/*
- * LTT trace control module over debugfs.
- *
- * Copyright 2008 - Zhaolei <zhaolei@cn.fujitsu.com>
- *
- * Copyright 2009 - Gui Jianfeng <guijianfeng@cn.fujitsu.com>
- *                  Make mark-control work in debugfs
- *
- * Dual LGPL v2.1/GPL v2 license.
- */
-
-/*
- * Todo:
- *   Impl read operations for control file to read attributes
- *   Create a README file in ltt control dir, for display help info
- */
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/uaccess.h>
-#include <linux/debugfs.h>
-#include <linux/notifier.h>
-#include <linux/jiffies.h>
-#include <linux/marker.h>
-
-#include "ltt-tracer.h"
-
-#define LTT_CONTROL_DIR "control"
-#define MARKERS_CONTROL_DIR "markers"
-#define LTT_SETUP_TRACE_FILE "setup_trace"
-#define LTT_DESTROY_TRACE_FILE "destroy_trace"
-
-#define LTT_WRITE_MAXLEN       (128)
-
-struct dentry *ltt_control_dir, *ltt_setup_trace_file, *ltt_destroy_trace_file,
-       *markers_control_dir;
-
-/*
- * the traces_lock nests inside control_lock.
- * control_lock protects the consistency of directories presented in ltt
- * directory.
- */
-static DEFINE_MUTEX(control_lock);
-
-/*
- * big note about locking for marker control files :
- * If a marker control file is added/removed manually racing with module
- * load/unload, there may be warning messages appearing, but those two
- * operations should be able to execute concurrently without any lock
- * synchronizing their operation one wrt another.
- * Locking the marker mutex, module mutex and also keeping a mutex here
- * from mkdir/rmdir _and_ from the notifier called from module load/unload makes
- * life miserable and just asks for deadlocks.
- */
-
-/*
- * lookup a file/dir in parent dir.
- * only designed to work well for debugfs.
- * (although it maybe ok for other fs)
- *
- * return:
- *     file/dir's dentry on success
- *     NULL on failure
- */
-static struct dentry *dir_lookup(struct dentry *parent, const char *name)
-{
-       struct qstr q;
-       struct dentry *d;
-
-       q.name = name;
-       q.len = strlen(name);
-       q.hash = full_name_hash(q.name, q.len);
-
-       d = d_lookup(parent, &q);
-       if (d)
-               dput(d);
-
-       return d;
-}
-
-
-static ssize_t alloc_write(struct file *file, const char __user *user_buf,
-                          size_t count, loff_t *ppos)
-{
-       int err = 0;
-       int buf_size;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-       char *cmd = (char *)__get_free_page(GFP_KERNEL);
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto err_copy_from_user;
-       buf[buf_size] = 0;
-
-       if (sscanf(buf, "%s", cmd) != 1) {
-               err = -EPERM;
-               goto err_get_cmd;
-       }
-
-       if ((cmd[0] != 'Y' && cmd[0] != 'y' && cmd[0] != '1') || cmd[1]) {
-               err = -EPERM;
-               goto err_bad_cmd;
-       }
-
-       err = ltt_trace_alloc(file->f_dentry->d_parent->d_name.name);
-       if (IS_ERR_VALUE(err)) {
-               printk(KERN_ERR "alloc_write: ltt_trace_alloc failed: %d\n",
-                       err);
-               goto err_alloc_trace;
-       }
-
-       free_page((unsigned long)buf);
-       free_page((unsigned long)cmd);
-       return count;
-
-err_alloc_trace:
-err_bad_cmd:
-err_get_cmd:
-err_copy_from_user:
-       free_page((unsigned long)buf);
-       free_page((unsigned long)cmd);
-       return err;
-}
-
-static const struct file_operations ltt_alloc_operations = {
-       .write = alloc_write,
-};
-
-
-static ssize_t enabled_write(struct file *file, const char __user *user_buf,
-                            size_t count, loff_t *ppos)
-{
-       int err = 0;
-       int buf_size;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-       char *cmd = (char *)__get_free_page(GFP_KERNEL);
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto err_copy_from_user;
-       buf[buf_size] = 0;
-
-       if (sscanf(buf, "%s", cmd) != 1) {
-               err = -EPERM;
-               goto err_get_cmd;
-       }
-
-       if (cmd[1]) {
-               err = -EPERM;
-               goto err_bad_cmd;
-       }
-
-       switch (cmd[0]) {
-       case 'Y':
-       case 'y':
-       case '1':
-               err = ltt_trace_start(file->f_dentry->d_parent->d_name.name);
-               if (IS_ERR_VALUE(err)) {
-                       printk(KERN_ERR
-                              "enabled_write: ltt_trace_start failed: %d\n",
-                              err);
-                       err = -EPERM;
-                       goto err_start_trace;
-               }
-               break;
-       case 'N':
-       case 'n':
-       case '0':
-               err = ltt_trace_stop(file->f_dentry->d_parent->d_name.name);
-               if (IS_ERR_VALUE(err)) {
-                       printk(KERN_ERR
-                              "enabled_write: ltt_trace_stop failed: %d\n",
-                              err);
-                       err = -EPERM;
-                       goto err_stop_trace;
-               }
-               break;
-       default:
-               err = -EPERM;
-               goto err_bad_cmd;
-       }
-
-       free_page((unsigned long)buf);
-       free_page((unsigned long)cmd);
-       return count;
-
-err_stop_trace:
-err_start_trace:
-err_bad_cmd:
-err_get_cmd:
-err_copy_from_user:
-       free_page((unsigned long)buf);
-       free_page((unsigned long)cmd);
-       return err;
-}
-
-static const struct file_operations ltt_enabled_operations = {
-       .write = enabled_write,
-};
-
-
-static ssize_t trans_write(struct file *file, const char __user *user_buf,
-                          size_t count, loff_t *ppos)
-{
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-       char *trans_name = (char *)__get_free_page(GFP_KERNEL);
-       int err = 0;
-       int buf_size;
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto err_copy_from_user;
-       buf[buf_size] = 0;
-
-       if (sscanf(buf, "%s", trans_name) != 1) {
-               err = -EPERM;
-               goto err_get_transname;
-       }
-
-       err = ltt_trace_set_type(file->f_dentry->d_parent->d_name.name,
-                                trans_name);
-       if (IS_ERR_VALUE(err)) {
-               printk(KERN_ERR "trans_write: ltt_trace_set_type failed: %d\n",
-                      err);
-               goto err_set_trans;
-       }
-
-       free_page((unsigned long)buf);
-       free_page((unsigned long)trans_name);
-       return count;
-
-err_set_trans:
-err_get_transname:
-err_copy_from_user:
-       free_page((unsigned long)buf);
-       free_page((unsigned long)trans_name);
-       return err;
-}
-
-static const struct file_operations ltt_trans_operations = {
-       .write = trans_write,
-};
-
-
-static ssize_t channel_subbuf_num_write(struct file *file,
-               const char __user *user_buf, size_t count, loff_t *ppos)
-{
-       int err = 0;
-       int buf_size;
-       unsigned int num;
-       const char *channel_name;
-       const char *trace_name;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto err_copy_from_user;
-       buf[buf_size] = 0;
-
-       if (sscanf(buf, "%u", &num) != 1) {
-               err = -EPERM;
-               goto err_get_number;
-       }
-
-       channel_name = file->f_dentry->d_parent->d_name.name;
-       trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
-
-       err = ltt_trace_set_channel_subbufcount(trace_name, channel_name, num);
-       if (IS_ERR_VALUE(err)) {
-               printk(KERN_ERR "channel_subbuf_num_write: "
-                      "ltt_trace_set_channel_subbufcount failed: %d\n", err);
-               goto err_set_subbufcount;
-       }
-
-       free_page((unsigned long)buf);
-       return count;
-
-err_set_subbufcount:
-err_get_number:
-err_copy_from_user:
-       free_page((unsigned long)buf);
-       return err;
-}
-
-static const struct file_operations ltt_channel_subbuf_num_operations = {
-       .write = channel_subbuf_num_write,
-};
-
-
-static
-ssize_t channel_subbuf_size_write(struct file *file,
-                                 const char __user *user_buf,
-                                 size_t count, loff_t *ppos)
-{
-       int err = 0;
-       int buf_size;
-       unsigned int num;
-       const char *channel_name;
-       const char *trace_name;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto err_copy_from_user;
-       buf[buf_size] = 0;
-
-       if (sscanf(buf, "%u", &num) != 1) {
-               err = -EPERM;
-               goto err_get_number;
-       }
-
-       channel_name = file->f_dentry->d_parent->d_name.name;
-       trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
-
-       err = ltt_trace_set_channel_subbufsize(trace_name, channel_name, num);
-       if (IS_ERR_VALUE(err)) {
-               printk(KERN_ERR "channel_subbuf_size_write: "
-                      "ltt_trace_set_channel_subbufsize failed: %d\n", err);
-               goto err_set_subbufsize;
-       }
-
-       free_page((unsigned long)buf);
-       return count;
-
-err_set_subbufsize:
-err_get_number:
-err_copy_from_user:
-       free_page((unsigned long)buf);
-       return err;
-}
-
-static const struct file_operations ltt_channel_subbuf_size_operations = {
-       .write = channel_subbuf_size_write,
-};
-
-static
-ssize_t channel_switch_timer_write(struct file *file,
-                                  const char __user *user_buf,
-                                  size_t count, loff_t *ppos)
-{
-       int err = 0;
-       int buf_size;
-       unsigned long num;
-       const char *channel_name;
-       const char *trace_name;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto err_copy_from_user;
-       buf[buf_size] = 0;
-
-       if (sscanf(buf, "%lu", &num) != 1) {
-               err = -EPERM;
-               goto err_get_number;
-       }
-
-       channel_name = file->f_dentry->d_parent->d_name.name;
-       trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
-
-       /* Convert from ms to us */
-       num *= 1000;
-
-       err = ltt_trace_set_channel_switch_timer(trace_name, channel_name, num);
-       if (IS_ERR_VALUE(err)) {
-               printk(KERN_ERR "channel_switch_timer_write: "
-                      "ltt_trace_set_channel_switch_timer failed: %d\n", err);
-               goto err_set_switch_timer;
-       }
-
-       free_page((unsigned long)buf);
-       return count;
-
-err_set_switch_timer:
-err_get_number:
-err_copy_from_user:
-       free_page((unsigned long)buf);
-       return err;
-}
-
-static struct file_operations ltt_channel_switch_timer_operations = {
-       .write = channel_switch_timer_write,
-};
-
-static
-ssize_t channel_overwrite_write(struct file *file,
-                               const char __user *user_buf, size_t count,
-                               loff_t *ppos)
-{
-       int err = 0;
-       int buf_size;
-       const char *channel_name;
-       const char *trace_name;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-       char *cmd = (char *)__get_free_page(GFP_KERNEL);
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto err_copy_from_user;
-       buf[buf_size] = 0;
-
-       if (sscanf(buf, "%s", cmd) != 1) {
-               err = -EPERM;
-               goto err_get_cmd;
-       }
-
-       if (cmd[1]) {
-               err = -EPERM;
-               goto err_bad_cmd;
-       }
-
-       channel_name = file->f_dentry->d_parent->d_name.name;
-       trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
-
-       switch (cmd[0]) {
-       case 'Y':
-       case 'y':
-       case '1':
-               err = ltt_trace_set_channel_overwrite(trace_name, channel_name,
-                                                     1);
-               if (IS_ERR_VALUE(err)) {
-                       printk(KERN_ERR "channel_overwrite_write: "
-                              "ltt_trace_set_channel_overwrite failed: %d\n",
-                              err);
-                       goto err_set_subbufsize;
-               }
-               break;
-       case 'N':
-       case 'n':
-       case '0':
-               err = ltt_trace_set_channel_overwrite(trace_name, channel_name,
-                                                     0);
-               if (IS_ERR_VALUE(err)) {
-                       printk(KERN_ERR "channel_overwrite_write: "
-                              "ltt_trace_set_channel_overwrite failed: %d\n",
-                              err);
-                       goto err_set_subbufsize;
-               }
-               break;
-       default:
-               err = -EPERM;
-               goto err_bad_cmd;
-       }
-
-       free_page((unsigned long)buf);
-       free_page((unsigned long)cmd);
-       return count;
-
-err_set_subbufsize:
-err_bad_cmd:
-err_get_cmd:
-err_copy_from_user:
-       free_page((unsigned long)buf);
-       free_page((unsigned long)cmd);
-       return err;
-}
-
-static const struct file_operations ltt_channel_overwrite_operations = {
-       .write = channel_overwrite_write,
-};
-
-
-static
-ssize_t channel_enable_write(struct file *file,
-                            const char __user *user_buf, size_t count,
-                            loff_t *ppos)
-{
-       int err = 0;
-       int buf_size;
-       const char *channel_name;
-       const char *trace_name;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-       char *cmd = (char *)__get_free_page(GFP_KERNEL);
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto err_copy_from_user;
-       buf[buf_size] = 0;
-
-       if (sscanf(buf, "%s", cmd) != 1) {
-               err = -EPERM;
-               goto err_get_cmd;
-       }
-
-       if (cmd[1]) {
-               err = -EPERM;
-               goto err_bad_cmd;
-       }
-
-       channel_name = file->f_dentry->d_parent->d_name.name;
-       trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
-
-       switch (cmd[0]) {
-       case 'Y':
-       case 'y':
-       case '1':
-               err = ltt_trace_set_channel_enable(trace_name, channel_name,
-                                                  1);
-               if (IS_ERR_VALUE(err)) {
-                       printk(KERN_ERR "channel_enable_write: "
-                              "ltt_trace_set_channel_enable failed: %d\n",
-                              err);
-                       goto err_set_subbufsize;
-               }
-               break;
-       case 'N':
-       case 'n':
-       case '0':
-               err = ltt_trace_set_channel_enable(trace_name, channel_name,
-                                                  0);
-               if (IS_ERR_VALUE(err)) {
-                       printk(KERN_ERR "channel_enable_write: "
-                              "ltt_trace_set_channel_enable failed: %d\n",
-                              err);
-                       goto err_set_subbufsize;
-               }
-               break;
-       default:
-               err = -EPERM;
-               goto err_bad_cmd;
-       }
-
-       free_page((unsigned long)buf);
-       free_page((unsigned long)cmd);
-       return count;
-
-err_set_subbufsize:
-err_bad_cmd:
-err_get_cmd:
-err_copy_from_user:
-       free_page((unsigned long)buf);
-       free_page((unsigned long)cmd);
-       return err;
-}
-
-static const struct file_operations ltt_channel_enable_operations = {
-       .write = channel_enable_write,
-};
-
-
-static int _create_trace_control_dir(const char *trace_name,
-                                    struct ltt_trace *trace)
-{
-       int err;
-       struct dentry *trace_root, *channel_root;
-       struct dentry *tmp_den;
-       int i;
-
-       /* debugfs/control/trace_name */
-       trace_root = debugfs_create_dir(trace_name, ltt_control_dir);
-       if (IS_ERR(trace_root) || !trace_root) {
-               printk(KERN_ERR "_create_trace_control_dir: "
-                      "create control root dir of %s failed\n", trace_name);
-               err = -ENOMEM;
-               goto err_create_trace_root;
-       }
-
-       /* debugfs/control/trace_name/alloc */
-       tmp_den = debugfs_create_file("alloc", S_IWUSR, trace_root, NULL,
-                                     &ltt_alloc_operations);
-       if (IS_ERR(tmp_den) || !tmp_den) {
-               printk(KERN_ERR "_create_trace_control_dir: "
-                      "create file of alloc failed\n");
-               err = -ENOMEM;
-               goto err_create_subdir;
-       }
-
-       /* debugfs/control/trace_name/trans */
-       tmp_den = debugfs_create_file("trans", S_IWUSR, trace_root, NULL,
-                                     &ltt_trans_operations);
-       if (IS_ERR(tmp_den) || !tmp_den) {
-               printk(KERN_ERR "_create_trace_control_dir: "
-                      "create file of trans failed\n");
-               err = -ENOMEM;
-               goto err_create_subdir;
-       }
-
-       /* debugfs/control/trace_name/enabled */
-       tmp_den = debugfs_create_file("enabled", S_IWUSR, trace_root, NULL,
-                                     &ltt_enabled_operations);
-       if (IS_ERR(tmp_den) || !tmp_den) {
-               printk(KERN_ERR "_create_trace_control_dir: "
-                      "create file of enabled failed\n");
-               err = -ENOMEM;
-               goto err_create_subdir;
-       }
-
-       /* debugfs/control/trace_name/channel/ */
-       channel_root = debugfs_create_dir("channel", trace_root);
-       if (IS_ERR(channel_root) || !channel_root) {
-               printk(KERN_ERR "_create_trace_control_dir: "
-                      "create dir of channel failed\n");
-               err = -ENOMEM;
-               goto err_create_subdir;
-       }
-
-       /*
-        * Create dir and files in debugfs/ltt/control/trace_name/channel/
-        * Following things(without <>) will be created:
-        * `-- <control>
-        *     `-- <trace_name>
-        *         `-- <channel>
-        *             |-- <channel_name>
-        *             |   |-- enable
-        *             |   |-- overwrite
-        *             |   |-- subbuf_num
-        *             |   |-- subbuf_size
-        *             |   `-- switch_timer
-        *             `-- ...
-        */
-
-       for (i = 0; i < trace->nr_channels; i++) {
-               struct dentry *channel_den;
-               struct ltt_chan *chan;
-
-               chan = &trace->channels[i];
-               if (!chan->active)
-                       continue;
-               channel_den = debugfs_create_dir(chan->a.filename,
-                                                channel_root);
-               if (IS_ERR(channel_den) || !channel_den) {
-                       printk(KERN_ERR "_create_trace_control_dir: "
-                              "create channel dir of %s failed\n",
-                              chan->a.filename);
-                       err = -ENOMEM;
-                       goto err_create_subdir;
-               }
-
-               tmp_den = debugfs_create_file("subbuf_num", S_IWUSR,
-                                             channel_den, NULL,
-                                             &ltt_channel_subbuf_num_operations);
-               if (IS_ERR(tmp_den) || !tmp_den) {
-                       printk(KERN_ERR "_create_trace_control_dir: "
-                              "create subbuf_num in %s failed\n",
-                              chan->a.filename);
-                       err = -ENOMEM;
-                       goto err_create_subdir;
-               }
-
-               tmp_den = debugfs_create_file("subbuf_size", S_IWUSR,
-                                             channel_den, NULL,
-                                             &ltt_channel_subbuf_size_operations);
-               if (IS_ERR(tmp_den) || !tmp_den) {
-                       printk(KERN_ERR "_create_trace_control_dir: "
-                              "create subbuf_size in %s failed\n",
-                              chan->a.filename);
-                       err = -ENOMEM;
-                       goto err_create_subdir;
-               }
-
-               tmp_den = debugfs_create_file("enable", S_IWUSR, channel_den,
-                                             NULL,
-                                             &ltt_channel_enable_operations);
-               if (IS_ERR(tmp_den) || !tmp_den) {
-                       printk(KERN_ERR "_create_trace_control_dir: "
-                              "create enable in %s failed\n",
-                              chan->a.filename);
-                       err = -ENOMEM;
-                       goto err_create_subdir;
-               }
-
-               tmp_den = debugfs_create_file("overwrite", S_IWUSR, channel_den,
-                                             NULL,
-                                             &ltt_channel_overwrite_operations);
-               if (IS_ERR(tmp_den) || !tmp_den) {
-                       printk(KERN_ERR "_create_trace_control_dir: "
-                              "create overwrite in %s failed\n",
-                              chan->a.filename);
-                       err = -ENOMEM;
-                       goto err_create_subdir;
-               }
-
-               tmp_den = debugfs_create_file("switch_timer", S_IWUSR,
-                                             channel_den, NULL,
-                                             &ltt_channel_switch_timer_operations);
-               if (IS_ERR(tmp_den) || !tmp_den) {
-                       printk(KERN_ERR "_create_trace_control_dir: "
-                              "create switch_timer in %s failed\n",
-                              chan->a.filename);
-                       err = -ENOMEM;
-                       goto err_create_subdir;
-               }
-       }
-
-       return 0;
-
-err_create_subdir:
-       debugfs_remove_recursive(trace_root);
-err_create_trace_root:
-       return err;
-}
-
-static
-ssize_t setup_trace_write(struct file *file, const char __user *user_buf,
-                         size_t count, loff_t *ppos)
-{
-       int err = 0;
-       int buf_size;
-       struct ltt_trace *trace;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-       char *trace_name = (char *)__get_free_page(GFP_KERNEL);
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto err_copy_from_user;
-       buf[buf_size] = 0;
-
-       if (sscanf(buf, "%s", trace_name) != 1) {
-               err = -EPERM;
-               goto err_get_tracename;
-       }
-
-       mutex_lock(&control_lock);
-       ltt_lock_traces();
-
-       err = _ltt_trace_setup(trace_name);
-       if (IS_ERR_VALUE(err)) {
-               printk(KERN_ERR
-                      "setup_trace_write: ltt_trace_setup failed: %d\n", err);
-               goto err_setup_trace;
-       }
-       trace = _ltt_trace_find_setup(trace_name);
-       BUG_ON(!trace);
-       err = _create_trace_control_dir(trace_name, trace);
-       if (IS_ERR_VALUE(err)) {
-               printk(KERN_ERR "setup_trace_write: "
-                      "_create_trace_control_dir failed: %d\n", err);
-               goto err_create_trace_control_dir;
-       }
-
-       ltt_unlock_traces();
-       mutex_unlock(&control_lock);
-
-       free_page((unsigned long)buf);
-       free_page((unsigned long)trace_name);
-       return count;
-
-err_create_trace_control_dir:
-       ltt_trace_destroy(trace_name);
-err_setup_trace:
-       ltt_unlock_traces();
-       mutex_unlock(&control_lock);
-err_get_tracename:
-err_copy_from_user:
-       free_page((unsigned long)buf);
-       free_page((unsigned long)trace_name);
-       return err;
-}
-
-static const struct file_operations ltt_setup_trace_operations = {
-       .write = setup_trace_write,
-};
-
-static
-ssize_t destroy_trace_write(struct file *file, const char __user *user_buf,
-                           size_t count, loff_t *ppos)
-{
-       struct dentry *trace_den;
-       int buf_size;
-       int err = 0;
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-       char *trace_name = (char *)__get_free_page(GFP_KERNEL);
-
-       buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-       err = copy_from_user(buf, user_buf, buf_size);
-       if (err)
-               goto err_copy_from_user;
-       buf[buf_size] = 0;
-
-       if (sscanf(buf, "%s", trace_name) != 1) {
-               err = -EPERM;
-               goto err_get_tracename;
-       }
-
-       mutex_lock(&control_lock);
-
-       err = ltt_trace_destroy(trace_name);
-       if (IS_ERR_VALUE(err)) {
-               printk(KERN_ERR
-                      "destroy_trace_write: ltt_trace_destroy failed: %d\n",
-                      err);
-               err = -EPERM;
-               goto err_destroy_trace;
-       }
-
-       trace_den = dir_lookup(ltt_control_dir, trace_name);
-       if (!trace_den) {
-               printk(KERN_ERR
-                      "destroy_trace_write: lookup for %s's dentry failed\n",
-                      trace_name);
-               err = -ENOENT;
-               goto err_get_dentry;
-       }
-
-       debugfs_remove_recursive(trace_den);
-
-       mutex_unlock(&control_lock);
-
-       free_page((unsigned long)buf);
-       free_page((unsigned long)trace_name);
-       return count;
-
-err_get_dentry:
-err_destroy_trace:
-       mutex_unlock(&control_lock);
-err_get_tracename:
-err_copy_from_user:
-       free_page((unsigned long)buf);
-       free_page((unsigned long)trace_name);
-       return err;
-}
-
-static const struct file_operations ltt_destroy_trace_operations = {
-       .write = destroy_trace_write,
-};
-
-static void init_marker_dir(struct dentry *dentry,
-                           const struct inode_operations *opt)
-{
-       dentry->d_inode->i_op = opt;
-}
-
-static
-ssize_t marker_enable_read(struct file *filp, char __user *ubuf,
-                          size_t cnt, loff_t *ppos)
-{
-       char *buf;
-       const char *channel, *marker;
-       int len, enabled, present;
-
-       marker = filp->f_dentry->d_parent->d_name.name;
-       channel = filp->f_dentry->d_parent->d_parent->d_name.name;
-
-       len = 0;
-       buf = (char *)__get_free_page(GFP_KERNEL);
-
-       /*
-        * Note: we cannot take the marker lock to make these two checks
-        * atomic, because the marker mutex nests inside the module mutex, taken
-        * inside the marker present check.
-        */
-       enabled = is_marker_enabled(channel, marker);
-       present = is_marker_present(channel, marker);
-
-       if (enabled && present)
-               len = snprintf(buf, PAGE_SIZE, "%d\n", 1);
-       else if (enabled && !present)
-               len = snprintf(buf, PAGE_SIZE, "%d\n", 2);
-       else
-               len = snprintf(buf, PAGE_SIZE, "%d\n", 0);
-
-
-       if (len >= PAGE_SIZE) {
-               len = PAGE_SIZE;
-               buf[PAGE_SIZE] = '\0';
-       }
-       len = simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
-       free_page((unsigned long)buf);
-
-       return len;
-}
-
-static
-ssize_t marker_enable_write(struct file *filp, const char __user *ubuf,
-                           size_t cnt, loff_t *ppos)
-{
-       char *buf = (char *)__get_free_page(GFP_KERNEL);
-       int buf_size;
-       ssize_t ret = 0;
-       const char *channel, *marker;
-
-       marker = filp->f_dentry->d_parent->d_name.name;
-       channel = filp->f_dentry->d_parent->d_parent->d_name.name;
-
-       buf_size = min_t(size_t, cnt, PAGE_SIZE - 1);
-       ret = copy_from_user(buf, ubuf, buf_size);
-       if (ret)
-               goto end;
-
-       buf[buf_size] = 0;
-
-       switch (buf[0]) {
-       case 'Y':
-       case 'y':
-       case '1':
-               ret = ltt_marker_connect(channel, marker, "default");
-               if (ret)
-                       goto end;
-               break;
-       case 'N':
-       case 'n':
-       case '0':
-               ret = ltt_marker_disconnect(channel, marker, "default");
-               if (ret)
-                       goto end;
-               break;
-       default:
-               ret = -EPERM;
-               goto end;
-       }
-       ret = cnt;
-end:
-       free_page((unsigned long)buf);
-       return ret;
-}
-
-static const struct file_operations enable_fops = {
-       .read = marker_enable_read,
-       .write = marker_enable_write,
-};
-
-/*
- * In practice, the output size should never be larger than 4096 kB. If it
- * ever happens, the output will simply be truncated.
- */
-static
-ssize_t marker_info_read(struct file *filp, char __user *ubuf,
-                        size_t cnt, loff_t *ppos)
-{
-       char *buf;
-       const char *channel, *marker;
-       int len;
-       struct marker_iter iter;
-
-       marker = filp->f_dentry->d_parent->d_name.name;
-       channel = filp->f_dentry->d_parent->d_parent->d_name.name;
-
-       len = 0;
-       buf = (char *)__get_free_page(GFP_KERNEL);
-
-       if (is_marker_enabled(channel, marker) &&
-           !is_marker_present(channel, marker)) {
-               len += snprintf(buf + len, PAGE_SIZE - len,
-                               "Marker Pre-enabled\n");
-               goto out;
-       }
-
-       marker_iter_reset(&iter);
-       marker_iter_start(&iter);
-       for (; iter.marker != NULL; marker_iter_next(&iter)) {
-               if (!strcmp(iter.marker->channel, channel) &&
-                   !strcmp(iter.marker->name, marker))
-                       len += snprintf(buf + len, PAGE_SIZE - len,
-                                      "Location: %s\n"
-                                      "format: \"%s\"\nstate: %d\n"
-                                      "event_id: %hu\n"
-                                      "call: 0x%p\n"
-                                      "probe %s : 0x%p\n\n",
-#ifdef CONFIG_MODULES
-                                      iter.module ? iter.module->name :
-#endif
-                                      "Core Kernel",
-                                      iter.marker->format,
-                                      _imv_read(iter.marker->state),
-                                      iter.marker->event_id,
-                                      iter.marker->call,
-                                      iter.marker->ptype ?
-                                      "multi" : "single", iter.marker->ptype ?
-                                      (void *)iter.marker->multi :
-                                      (void *)iter.marker->single.func);
-                       if (len >= PAGE_SIZE)
-                               break;
-       }
-       marker_iter_stop(&iter);
-
-out:
-       if (len >= PAGE_SIZE) {
-               len = PAGE_SIZE;
-               buf[PAGE_SIZE] = '\0';
-       }
-
-       len = simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
-       free_page((unsigned long)buf);
-
-       return len;
-}
-
-static const struct file_operations info_fops = {
-       .read = marker_info_read,
-};
-
-static int marker_mkdir(struct inode *dir, struct dentry *dentry, int mode)
-{
-       struct dentry *marker_d, *enable_d, *info_d, *channel_d;
-       int ret;
-
-       ret = 0;
-       channel_d = (struct dentry *)dir->i_private;
-       mutex_unlock(&dir->i_mutex);
-
-       marker_d = debugfs_create_dir(dentry->d_name.name,
-                                     channel_d);
-       if (IS_ERR(marker_d)) {
-               ret = PTR_ERR(marker_d);
-               goto out;
-       }
-
-       enable_d = debugfs_create_file("enable", 0644, marker_d,
-                                      NULL, &enable_fops);
-       if (IS_ERR(enable_d) || !enable_d) {
-               printk(KERN_ERR
-                      "%s: create file of %s failed\n",
-                      __func__, "enable");
-               ret = -ENOMEM;
-               goto remove_marker_dir;
-       }
-
-       info_d = debugfs_create_file("info", 0644, marker_d,
-                                    NULL, &info_fops);
-       if (IS_ERR(info_d) || !info_d) {
-               printk(KERN_ERR
-                      "%s: create file of %s failed\n",
-                      __func__, "info");
-               ret = -ENOMEM;
-               goto remove_enable_dir;
-       }
-
-       goto out;
-
-remove_enable_dir:
-       debugfs_remove(enable_d);
-remove_marker_dir:
-       debugfs_remove(marker_d);
-out:
-       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
-       return ret;
-}
-
-static int marker_rmdir(struct inode *dir, struct dentry *dentry)
-{
-       struct dentry *marker_d, *channel_d;
-       const char *channel, *name;
-       int ret, enabled, present;
-
-       ret = 0;
-
-       channel_d = (struct dentry *)dir->i_private;
-       channel = channel_d->d_name.name;
-
-       marker_d = dir_lookup(channel_d, dentry->d_name.name);
-
-       if (!marker_d) {
-               ret = -ENOENT;
-               goto out;
-       }
-
-       name = marker_d->d_name.name;
-
-       enabled = is_marker_enabled(channel, name);
-       present = is_marker_present(channel, name);
-
-       if (present || (!present && enabled)) {
-               ret = -EPERM;
-               goto out;
-       }
-
-       mutex_unlock(&dir->i_mutex);
-       mutex_unlock(&dentry->d_inode->i_mutex);
-       debugfs_remove_recursive(marker_d);
-       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
-       mutex_lock(&dentry->d_inode->i_mutex);
-out:
-       return ret;
-}
-
-const struct inode_operations channel_dir_opt = {
-       .lookup = simple_lookup,
-       .mkdir = marker_mkdir,
-       .rmdir = marker_rmdir,
-};
-
-static int channel_mkdir(struct inode *dir, struct dentry *dentry, int mode)
-{
-       struct dentry *channel_d;
-       int ret;
-
-       ret = 0;
-       mutex_unlock(&dir->i_mutex);
-
-       channel_d = debugfs_create_dir(dentry->d_name.name,
-                                      markers_control_dir);
-       if (IS_ERR(channel_d)) {
-               ret = PTR_ERR(channel_d);
-               goto out;
-       }
-
-       channel_d->d_inode->i_private = (void *)channel_d;
-       init_marker_dir(channel_d, &channel_dir_opt);
-out:
-       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
-       return ret;
-}
-
-static int channel_rmdir(struct inode *dir, struct dentry *dentry)
-{
-       struct dentry *channel_d;
-       int ret;
-
-       ret = 0;
-
-       channel_d = dir_lookup(markers_control_dir, dentry->d_name.name);
-       if (!channel_d) {
-               ret = -ENOENT;
-               goto out;
-       }
-
-       if (list_empty(&channel_d->d_subdirs)) {
-               mutex_unlock(&dir->i_mutex);
-               mutex_unlock(&dentry->d_inode->i_mutex);
-               debugfs_remove(channel_d);
-               mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
-               mutex_lock(&dentry->d_inode->i_mutex);
-       } else
-               ret = -EPERM;
-
-out:
-       return ret;
-}
-
-const struct inode_operations root_dir_opt = {
-       .lookup = simple_lookup,
-       .mkdir = channel_mkdir,
-       .rmdir = channel_rmdir
-};
-
-static int build_marker_file(struct marker *marker)
-{
-       struct dentry *channel_d, *marker_d, *enable_d, *info_d;
-       int err;
-
-       channel_d = dir_lookup(markers_control_dir, marker->channel);
-       if (!channel_d) {
-               channel_d = debugfs_create_dir(marker->channel,
-                                              markers_control_dir);
-               if (IS_ERR(channel_d) || !channel_d) {
-                       printk(KERN_ERR
-                              "%s: build channel dir of %s failed\n",
-                              __func__, marker->channel);
-                       err = -ENOMEM;
-                       goto err_build_fail;
-               }
-               channel_d->d_inode->i_private = (void *)channel_d;
-               init_marker_dir(channel_d, &channel_dir_opt);
-       }
-
-       marker_d  = dir_lookup(channel_d, marker->name);
-       if (!marker_d) {
-               marker_d = debugfs_create_dir(marker->name, channel_d);
-               if (IS_ERR(marker_d) || !marker_d) {
-                       printk(KERN_ERR
-                              "%s: marker dir of %s failed\n",
-                              __func__, marker->name);
-                       err = -ENOMEM;
-                       goto err_build_fail;
-               }
-       }
-
-       enable_d = dir_lookup(marker_d, "enable");
-       if (!enable_d) {
-               enable_d = debugfs_create_file("enable", 0644, marker_d,
-                                               NULL, &enable_fops);
-               if (IS_ERR(enable_d) || !enable_d) {
-                       printk(KERN_ERR
-                              "%s: create file of %s failed\n",
-                              __func__, "enable");
-                       err = -ENOMEM;
-                       goto err_build_fail;
-               }
-       }
-
-       info_d = dir_lookup(marker_d, "info");
-       if (!info_d) {
-               info_d = debugfs_create_file("info", 0444, marker_d,
-                                               NULL, &info_fops);
-               if (IS_ERR(info_d) || !info_d) {
-                       printk(KERN_ERR
-                              "%s: create file of %s failed\n",
-                              __func__, "enable");
-                       err = -ENOMEM;
-                       goto err_build_fail;
-               }
-       }
-
-       return 0;
-
-err_build_fail:
-       return err;
-}
-
-static int build_marker_control_files(void)
-{
-       struct marker_iter iter;
-       int err;
-
-       err = 0;
-       if (!markers_control_dir)
-               return -EEXIST;
-
-       marker_iter_reset(&iter);
-       marker_iter_start(&iter);
-       for (; iter.marker != NULL; marker_iter_next(&iter)) {
-               err = build_marker_file(iter.marker);
-               if (err)
-                       goto out;
-       }
-       marker_iter_stop(&iter);
-
-out:
-       return err;
-}
-
-#ifdef CONFIG_MODULES
-static int remove_marker_control_dir(struct module *mod, struct marker *marker)
-{
-       struct dentry *channel_d, *marker_d;
-       const char *channel, *name;
-       int count;
-       struct marker_iter iter;
-
-       count = 0;
-
-       channel_d = dir_lookup(markers_control_dir, marker->channel);
-       if (!channel_d)
-               return -ENOENT;
-       channel = channel_d->d_name.name;
-
-       marker_d = dir_lookup(channel_d, marker->name);
-       if (!marker_d)
-               return -ENOENT;
-       name = marker_d->d_name.name;
-
-       marker_iter_reset(&iter);
-       marker_iter_start(&iter);
-       for (; iter.marker != NULL; marker_iter_next(&iter)) {
-               if (!strcmp(iter.marker->channel, channel) &&
-                   !strcmp(iter.marker->name, name) && mod != iter.module)
-                       count++;
-       }
-
-       if (count > 0)
-               goto end;
-
-       debugfs_remove_recursive(marker_d);
-       if (list_empty(&channel_d->d_subdirs))
-               debugfs_remove(channel_d);
-
-end:
-       marker_iter_stop(&iter);
-       return 0;
-}
-
-static void cleanup_control_dir(struct module *mod, struct marker *begin,
-                               struct marker *end)
-{
-       struct marker *iter;
-
-       if (!markers_control_dir)
-               return;
-
-       for (iter = begin; iter < end; iter++)
-               remove_marker_control_dir(mod, iter);
-
-       return;
-}
-
-static void build_control_dir(struct module *mod, struct marker *begin,
-                             struct marker *end)
-{
-       struct marker *iter;
-       int err;
-
-       err = 0;
-       if (!markers_control_dir)
-               return;
-
-       for (iter = begin; iter < end; iter++) {
-               err = build_marker_file(iter);
-               if (err)
-                       goto err_build_fail;
-       }
-
-       return;
-err_build_fail:
-       cleanup_control_dir(mod, begin, end);
-}
-
-static int module_notify(struct notifier_block *self,
-                 unsigned long val, void *data)
-{
-       struct module *mod = data;
-
-       switch (val) {
-       case MODULE_STATE_COMING:
-               build_control_dir(mod, mod->markers,
-                                 mod->markers + mod->num_markers);
-               break;
-       case MODULE_STATE_GOING:
-               cleanup_control_dir(mod, mod->markers,
-                                   mod->markers + mod->num_markers);
-               break;
-       }
-       return NOTIFY_DONE;
-}
-#else
-static inline int module_notify(struct notifier_block *self,
-               unsigned long val, void *data)
-{
-       return 0;
-}
-#endif
-
-static struct notifier_block module_nb = {
-       .notifier_call = module_notify,
-};
-
-static int __init ltt_trace_control_init(void)
-{
-       int err = 0;
-       struct dentry *ltt_root_dentry;
-
-       ltt_root_dentry = get_ltt_root();
-       if (!ltt_root_dentry) {
-               err = -ENOENT;
-               goto err_no_root;
-       }
-
-       ltt_control_dir = debugfs_create_dir(LTT_CONTROL_DIR, ltt_root_dentry);
-       if (IS_ERR(ltt_control_dir) || !ltt_control_dir) {
-               printk(KERN_ERR
-                      "ltt_channel_control_init: create dir of %s failed\n",
-                      LTT_CONTROL_DIR);
-               err = -ENOMEM;
-               goto err_create_control_dir;
-       }
-
-       ltt_setup_trace_file = debugfs_create_file(LTT_SETUP_TRACE_FILE,
-                                                  S_IWUSR, ltt_root_dentry,
-                                                  NULL,
-                                                  &ltt_setup_trace_operations);
-       if (IS_ERR(ltt_setup_trace_file) || !ltt_setup_trace_file) {
-               printk(KERN_ERR
-                      "ltt_channel_control_init: create file of %s failed\n",
-                      LTT_SETUP_TRACE_FILE);
-               err = -ENOMEM;
-               goto err_create_setup_trace_file;
-       }
-
-       ltt_destroy_trace_file = debugfs_create_file(LTT_DESTROY_TRACE_FILE,
-                                                    S_IWUSR, ltt_root_dentry,
-                                                    NULL,
-                                                    &ltt_destroy_trace_operations);
-       if (IS_ERR(ltt_destroy_trace_file) || !ltt_destroy_trace_file) {
-               printk(KERN_ERR
-                      "ltt_channel_control_init: create file of %s failed\n",
-                      LTT_DESTROY_TRACE_FILE);
-               err = -ENOMEM;
-               goto err_create_destroy_trace_file;
-       }
-
-       markers_control_dir = debugfs_create_dir(MARKERS_CONTROL_DIR,
-                                                ltt_root_dentry);
-       if (IS_ERR(markers_control_dir) || !markers_control_dir) {
-               printk(KERN_ERR
-                      "ltt_channel_control_init: create dir of %s failed\n",
-                      MARKERS_CONTROL_DIR);
-               err = -ENOMEM;
-               goto err_create_marker_control_dir;
-       }
-
-       init_marker_dir(markers_control_dir, &root_dir_opt);
-
-       if (build_marker_control_files())
-               goto err_build_fail;
-
-       if (!register_module_notifier(&module_nb))
-               return 0;
-
-err_build_fail:
-       debugfs_remove_recursive(markers_control_dir);
-       markers_control_dir = NULL;
-err_create_marker_control_dir:
-       debugfs_remove(ltt_destroy_trace_file);
-err_create_destroy_trace_file:
-       debugfs_remove(ltt_setup_trace_file);
-err_create_setup_trace_file:
-       debugfs_remove(ltt_control_dir);
-err_create_control_dir:
-err_no_root:
-       return err;
-}
-
-static void __exit ltt_trace_control_exit(void)
-{
-       struct dentry *trace_dir;
-
-       /* destory all traces */
-       list_for_each_entry(trace_dir, &ltt_control_dir->d_subdirs,
-                           d_u.d_child) {
-               ltt_trace_stop(trace_dir->d_name.name);
-               ltt_trace_destroy(trace_dir->d_name.name);
-       }
-
-       /* clean dirs in debugfs */
-       debugfs_remove(ltt_setup_trace_file);
-       debugfs_remove(ltt_destroy_trace_file);
-       debugfs_remove_recursive(ltt_control_dir);
-       debugfs_remove_recursive(markers_control_dir);
-       unregister_module_notifier(&module_nb);
-       put_ltt_root();
-}
-
-module_init(ltt_trace_control_init);
-module_exit(ltt_trace_control_exit);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Zhao Lei <zhaolei@cn.fujitsu.com>");
-MODULE_DESCRIPTION("Linux Trace Toolkit Trace Controller");
index 84b3731f08cde346b61c2a3ace65988112571823..2f947b7eb4be31a233a7a5dde773a67226ad1da5 100644 (file)
@@ -72,71 +72,6 @@ enum ltt_channels {
        LTT_CHANNEL_DEFAULT,
 };
 
-#if 0
-size_t ltt_serialize_printf(struct lib_ring_buffer *buf, unsigned long buf_offset,
-                           size_t *msg_size, char *output, size_t outlen,
-                           const char *fmt);
-
-/*
- * Unique ID assigned to each registered probe.
- */
-enum marker_id {
-       MARKER_ID_SET_MARKER_ID = 0,    /* Static IDs available (range 0-7) */
-       MARKER_ID_SET_MARKER_FORMAT,
-       MARKER_ID_COMPACT,              /* Compact IDs (range: 8-127)       */
-       MARKER_ID_DYNAMIC,              /* Dynamic IDs (range: 128-65535)   */
-};
-
-/* static ids 0-1 reserved for internal use. */
-#define MARKER_CORE_IDS                2
-static __inline__ enum marker_id marker_id_type(uint16_t id)
-{
-       if (id < MARKER_CORE_IDS)
-               return (enum marker_id)id;
-       else
-               return MARKER_ID_DYNAMIC;
-}
-
-struct user_dbg_data {
-       unsigned long avail_size;
-       unsigned long write;
-       unsigned long read;
-};
-
-enum trace_mode { LTT_TRACE_NORMAL, LTT_TRACE_FLIGHT, LTT_TRACE_HYBRID };
-
-#define CHANNEL_FLAG_ENABLE    (1U<<0)
-#define CHANNEL_FLAG_OVERWRITE (1U<<1)
-#endif //0
-
-#if 0
-/* Per-trace information - each trace/flight recorder represented by one */
-struct ltt_trace {
-       /* First 32 bytes cache-hot cacheline */
-       struct list_head list;
-       struct ltt_chan **channels;
-       unsigned int nr_channels;
-       int active;
-       /* Second 32 bytes cache-hot cacheline */
-       struct ltt_trace_ops *ops;
-       u32 freq_scale;
-       u64 start_freq;
-       u64 start_tsc;
-       unsigned long long start_monotonic;
-       struct timeval          start_time;
-       struct ltt_channel_setting *settings;
-       struct {
-               struct dentry                   *trace_root;
-               struct dentry                   *ascii_root;
-       } dentry;
-       struct kref kref; /* Each channel has a kref of the trace struct */
-       struct ltt_transport *transport;
-       struct kref ltt_transport_kref;
-       wait_queue_head_t kref_wq; /* Place for ltt_trace_destroy to sleep */
-       char trace_name[NAME_MAX];
-} ____cacheline_aligned;
-#endif //0
-
 /*
  * Hardcoded event headers
  *
@@ -326,70 +261,6 @@ slow_path:
        ltt_write_event_header_slow(config, ctx, eID, event_size);
 }
 
-#if 0
-/*
- * ltt_read_event_header
- * buf_offset must aligned on 32 bits
- */
-static __inline__
-size_t ltt_read_event_header(struct ltt_chanbuf_alloc *bufa, long buf_offset,
-                            u64 *tsc, u32 *event_size, u16 *eID,
-                            unsigned int *rflags)
-{
-       struct ltt_event_header header;
-       u16 small_size;
-
-       ltt_relay_read(bufa, buf_offset, &header, sizeof(header));
-       buf_offset += sizeof(header);
-
-       *event_size = INT_MAX;
-       *eID = header.id_time >> LTT_TSC_BITS;
-       *tsc = header.id_time & LTT_TSC_MASK;
-
-       switch (*eID) {
-       case 29:
-               *rflags = LTT_RFLAG_ID_SIZE_TSC;
-               ltt_relay_read(bufa, buf_offset, eID, sizeof(u16));
-               buf_offset += sizeof(u16);
-               ltt_relay_read(bufa, buf_offset, &small_size, sizeof(u16));
-               buf_offset += sizeof(u16);
-               if (small_size == LTT_MAX_SMALL_SIZE) {
-                       ltt_relay_read(bufa, buf_offset, event_size,
-                                       sizeof(u32));
-                       buf_offset += sizeof(u32);
-               } else
-                       *event_size = small_size;
-               buf_offset += ltt_align(buf_offset, sizeof(u64));
-               ltt_relay_read(bufa, buf_offset, tsc, sizeof(u64));
-               buf_offset += sizeof(u64);
-               break;
-       case 30:
-               *rflags = LTT_RFLAG_ID_SIZE;
-               ltt_relay_read(bufa, buf_offset, eID, sizeof(u16));
-               buf_offset += sizeof(u16);
-               ltt_relay_read(bufa, buf_offset, &small_size, sizeof(u16));
-               buf_offset += sizeof(u16);
-               if (small_size == LTT_MAX_SMALL_SIZE) {
-                       ltt_relay_read(bufa, buf_offset, event_size,
-                                       sizeof(u32));
-                       buf_offset += sizeof(u32);
-               } else
-                       *event_size = small_size;
-               break;
-       case 31:
-               *rflags = LTT_RFLAG_ID;
-               ltt_relay_read(bufa, buf_offset, eID, sizeof(u16));
-               buf_offset += sizeof(u16);
-               break;
-       default:
-               *rflags = 0;
-               break;
-       }
-
-       return buf_offset;
-}
-#endif //0
-
 /* Tracer properties */
 #define CTF_MAGIC_NUMBER               0xC1FC1FC1
 #define LTT_TRACER_VERSION_MAJOR       3
diff --git a/ltt-userspace-event.c b/ltt-userspace-event.c
deleted file mode 100644 (file)
index c716d72..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2008 Mathieu Desnoyers
- *
- * Dual LGPL v2.1/GPL v2 license.
- */
-
-#include <linux/module.h>
-#include <linux/marker.h>
-#include <linux/uaccess.h>
-#include <linux/gfp.h>
-#include <linux/fs.h>
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-
-#include "ltt-type-serializer.h"
-
-#define LTT_WRITE_EVENT_FILE   "write_event"
-
-DEFINE_MARKER(userspace, event, "string %s");
-static struct dentry *ltt_event_file;
-
-/**
- * write_event - write a userspace string into the trace system
- * @file: file pointer
- * @user_buf: user string
- * @count: length to copy, including the final NULL
- * @ppos: unused
- *
- * Copy a string into a trace event, in channel "userspace", event "event".
- * Copies until either \n or \0 is reached.
- * On success, returns the number of bytes copied from the source, including the
- * \n or \0 character (if there was one in the count range). It cannot return
- * more than count.
- * Inspired from tracing_mark_write implementation from Steven Rostedt and
- * Ingo Molnar.
- */
-static
-ssize_t write_event(struct file *file, const char __user *user_buf,
-                   size_t count, loff_t *ppos)
-{
-       struct marker *marker;
-       char *buf, *end;
-       long copycount;
-       ssize_t ret;
-
-       buf = kmalloc(count + 1, GFP_KERNEL);
-       if (!buf) {
-               ret = -ENOMEM;
-               goto string_out;
-       }
-       copycount = strncpy_from_user(buf, user_buf, count);
-       if (copycount < 0) {
-               ret = -EFAULT;
-               goto string_err;
-       }
-       /* Cut from the first nil or newline. */
-       buf[copycount] = '\0';
-       end = strchr(buf, '\n');
-       if (end) {
-               *end = '\0';
-               copycount = end - buf;
-       }
-       /* Add final \0 to copycount */
-       copycount++;
-       marker = &GET_MARKER(userspace, event);
-       ltt_specialized_trace(marker, marker->single.probe_private, buf,
-                             copycount, sizeof(char));
-       /* If there is no \0 nor \n in count, do not return a larger value */
-       ret = min_t(size_t, copycount, count);
-string_err:
-       kfree(buf);
-string_out:
-       return ret;
-}
-
-static const struct file_operations ltt_userspace_operations = {
-       .write = write_event,
-};
-
-static int __init ltt_userspace_init(void)
-{
-       struct dentry *ltt_root_dentry;
-       int err = 0;
-
-       ltt_root_dentry = get_ltt_root();
-       if (!ltt_root_dentry) {
-               err = -ENOENT;
-               goto err_no_root;
-       }
-
-       ltt_event_file = debugfs_create_file(LTT_WRITE_EVENT_FILE,
-                                            S_IWUGO,
-                                            ltt_root_dentry,
-                                            NULL,
-                                            &ltt_userspace_operations);
-       if (IS_ERR(ltt_event_file) || !ltt_event_file) {
-               printk(KERN_ERR
-                       "ltt_userspace_init: failed to create file %s\n",
-                       LTT_WRITE_EVENT_FILE);
-               err = -EPERM;
-               goto err_no_file;
-       }
-
-       return err;
-err_no_file:
-       put_ltt_root();
-err_no_root:
-       return err;
-}
-
-static void __exit ltt_userspace_exit(void)
-{
-       debugfs_remove(ltt_event_file);
-       put_ltt_root();
-}
-
-module_init(ltt_userspace_init);
-module_exit(ltt_userspace_exit);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>");
-MODULE_DESCRIPTION("Linux Trace Toolkit Userspace Event");
This page took 0.109558 seconds and 4 git commands to generate.