]> sourceware.org Git - systemtap.git/commitdiff
2007-03-14 Martin Hunt <hunt@redhat.com>
authorhunt <hunt>
Wed, 14 Mar 2007 16:12:40 +0000 (16:12 +0000)
committerhunt <hunt>
Wed, 14 Mar 2007 16:12:40 +0000 (16:12 +0000)
* transport_msgs.h: ifdef old messages as such.
Add support for new transport.
* relayfs.c: Simplify and add new interface to look
like utt.
* utt.[ch]: New files. Similar to the proposed utt interface.
These setup and teardown relayfs on debugfs.
* control.c: New file. Implements a simple control channel.
A small subset of procfs.c.
* procfs.c: This is now only used for old kernels lacking newer
relayfs. Change STP_RELAYFS to STP_BULKMODE. Use new
messages from transport_msgs.h. Don't support
RELAYFS_CHANNEL_VERSION >= 4. CHanges all control channel functions
to new names. Use pids instead of module names in /proc names.

runtime/transport/ChangeLog
runtime/transport/control.c [new file with mode: 0644]
runtime/transport/procfs.c
runtime/transport/relayfs.c
runtime/transport/symbols.c
runtime/transport/transport.c
runtime/transport/transport.h
runtime/transport/transport_msgs.h
runtime/transport/utt.c [new file with mode: 0644]
runtime/transport/utt.h [new file with mode: 0644]

index 54bde5d2c7fc06fbbb73534deffb44a3c14cd589..f9dca7f2fcd21e3abb90547b65535ff1dc7a6cc9 100644 (file)
@@ -1,3 +1,19 @@
+2007-03-14  Martin Hunt  <hunt@redhat.com>
+
+       * transport_msgs.h: ifdef old messages as such.
+       Add support for new transport.
+       * relayfs.c: Simplify and add new interface to look
+       like utt.
+       * utt.[ch]: New files. Similar to the proposed utt interface.
+       These setup and teardown relayfs on debugfs.
+       * control.c: New file. Implements a simple control channel.
+       A small subset of procfs.c.
+       * procfs.c: This is now only used for old kernels lacking newer 
+       relayfs. Change STP_RELAYFS to STP_BULKMODE. Use new
+       messages from transport_msgs.h. Don't support 
+       RELAYFS_CHANNEL_VERSION >= 4. CHanges all control channel functions
+       to new names. Use pids instead of module names in /proc names.
+
 2007-03-12  Frank Ch. Eigler  <fche@elastic.org>
 
        * procfs.c (_stp_register_procfs): Use /proc/MODULE rather than
diff --git a/runtime/transport/control.c b/runtime/transport/control.c
new file mode 100644 (file)
index 0000000..3ad3e30
--- /dev/null
@@ -0,0 +1,275 @@
+/* -*- linux-c -*-
+ *
+ * debugfs control channel
+ * Copyright (C) 2007 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software.  You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#define STP_DEFAULT_BUFFERS 20
+static int _stp_current_buffers = STP_DEFAULT_BUFFERS;
+
+static struct list_head _stp_ready_q;
+static struct list_head _stp_pool_q;
+spinlock_t _stp_pool_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t _stp_ready_lock = SPIN_LOCK_UNLOCKED;
+
+static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       int type;
+
+       if (count < sizeof(int))
+               return 0;
+
+       if (get_user(type, (int __user *)buf))
+               return -EFAULT;
+
+       //kbug ("count:%d type:%d\n", count, type);
+
+       if (type == STP_SYMBOLS) {
+               count -= sizeof(long);
+               buf += sizeof(long);
+       } else {
+               count -= sizeof(int);
+               buf += sizeof(int);
+       }
+
+       switch (type) {
+       case STP_START:
+       {
+               struct _stp_msg_start st;
+               if (count < sizeof(st))
+                       return 0;
+               if (copy_from_user (&st, buf, sizeof(st)))
+                       return -EFAULT;
+               _stp_handle_start (&st);
+               break;
+       }
+
+       case STP_SYMBOLS:
+               count = _stp_do_symbols(buf, count);
+               break;
+       case STP_MODULE:
+               count = _stp_do_module(buf, count);
+               break;
+       case STP_EXIT:
+               _stp_exit_flag = 1;
+               break;
+       default:
+               errk ("invalid command type %d\n", type);
+               return -EINVAL;
+       }
+
+       return count;
+}
+
+struct _stp_buffer {
+       struct list_head list;
+       int len;
+       int type;
+       char buf[STP_BUFFER_SIZE];
+};
+
+static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq);
+
+#ifdef DEBUG
+static void _stp_ctl_write_dbug (int type, void *data, int len)
+{
+       char buf[64];
+       switch (type) {
+       case STP_START:
+               printk("_stp_ctl_write: sending STP_START\n");
+               break;
+       case STP_EXIT:
+               printk("_stp_ctl_write: sending STP_EXIT\n");
+               break;
+       case STP_OOB_DATA:
+               snprintf(buf, sizeof(buf), "%s", (char *)data); 
+               printk("_stp_ctl_write: sending %d bytes of STP_OOB_DATA: %s\n", len, buf);
+               break;
+       case STP_SYSTEM:
+               snprintf(buf, sizeof(buf), "%s", (char *)data); 
+               printk("_stp_ctl_write: sending STP_SYSTEM: %s\n", buf);
+               break;
+       case STP_SYMBOLS:
+               printk("_stp_ctl_write: sending STP_SYMBOLS\n");
+               break;
+       case STP_MODULE:
+               printk("_stp_ctl_write: sending STP_MODULE\n");
+               break;
+       case STP_TRANSPORT:
+               printk("_stp_ctl_write: sending STP_TRANSPORT\n");
+               break;
+       default:
+               printk("_stp_ctl_write: ERROR: unknown message type: %d\n", type);
+               break;
+       }
+}
+#endif
+
+static int _stp_ctl_write (int type, void *data, int len)
+{
+       struct _stp_buffer *bptr;
+       unsigned long flags;
+       unsigned numtrylock;
+
+#ifdef DEBUG
+       _stp_ctl_write_dbug(type, data, len);
+#endif
+       numtrylock = 0;
+       while (!spin_trylock_irqsave (&_stp_pool_lock, flags) && (++numtrylock < MAXTRYLOCK)) 
+               ndelay (TRYLOCKDELAY);
+       if (unlikely (numtrylock >= MAXTRYLOCK)) 
+               return 0;
+
+       if (list_empty(&_stp_pool_q)) {
+               spin_unlock_irqrestore(&_stp_pool_lock, flags); 
+               return -1;
+       }
+
+       /* get the next buffer from the pool */
+       bptr = (struct _stp_buffer *)_stp_pool_q.next;
+       list_del_init(&bptr->list);
+       spin_unlock_irqrestore(&_stp_pool_lock, flags);
+
+       bptr->type = type;
+       memcpy (bptr->buf, data, len);
+       bptr->len = len;
+       
+       /* put it on the pool of ready buffers */
+       numtrylock = 0;
+       while (!spin_trylock_irqsave (&_stp_ready_lock, flags) && (++numtrylock < MAXTRYLOCK)) 
+               ndelay (TRYLOCKDELAY);
+       if (unlikely (numtrylock >= MAXTRYLOCK))
+               return 0;
+       list_add_tail(&bptr->list, &_stp_ready_q);
+       spin_unlock_irqrestore(&_stp_ready_lock, flags);
+
+       return len;
+}
+
+/* send commands with timeout and retry */
+static int _stp_ctl_send (int type, void *data, int len)
+{
+       int err, trylimit = 50;
+       kbug("ctl_send: type=%d len=%d\n", type, len);
+       while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--)
+               msleep (5);
+       kbug("returning %d\n", err);
+       return err;
+}
+
+static ssize_t
+_stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+       struct _stp_buffer *bptr;
+       int len;
+       unsigned long flags;
+
+       /* FIXME FIXME FIXME. assuming count is large enough to hold buffer!! */
+
+       /* wait for nonempty ready queue */
+       spin_lock_irqsave(&_stp_ready_lock, flags);
+       while (list_empty(&_stp_ready_q)) {
+               spin_unlock_irqrestore(&_stp_ready_lock, flags);
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               if (wait_event_interruptible(_stp_ctl_wq, !list_empty(&_stp_ready_q)))
+                       return -ERESTARTSYS;
+               spin_lock_irqsave(&_stp_ready_lock, flags);
+       }
+  
+       /* get the next buffer off the ready list */
+       bptr = (struct _stp_buffer *)_stp_ready_q.next;
+       list_del_init(&bptr->list);
+       spin_unlock_irqrestore(&_stp_ready_lock, flags);
+
+       /* write it out */
+       len = bptr->len + 4;
+       if (copy_to_user(buf, &bptr->type, len)) {
+               /* now what?  We took it off the queue then failed to send it */
+               /* we can't put it back on the queue because it will likely be out-of-order */
+               /* fortunately this should never happen */
+               /* FIXME need to mark this as a transport failure */
+               return -EFAULT;
+       }
+
+       /* put it on the pool of free buffers */
+       spin_lock_irqsave(&_stp_pool_lock, flags);
+       list_add_tail(&bptr->list, &_stp_pool_q);
+       spin_unlock_irqrestore(&_stp_pool_lock, flags);
+
+       return len;
+}
+
+
+static struct file_operations _stp_ctl_fops_cmd = {
+       .owner = THIS_MODULE,
+       .read = _stp_ctl_read_cmd,
+       .write = _stp_ctl_write_cmd,
+};
+
+static struct dentry *_stp_cmd_file = NULL;
+
+static int _stp_register_ctl_channel (void)
+{
+       int i;
+       struct list_head *p, *tmp;
+       char buf[32];
+
+       if (_stp_utt == NULL) {
+               errk("_expected _stp_utt to be set.\n");
+               return -1;
+       }
+
+       INIT_LIST_HEAD(&_stp_ready_q);
+       INIT_LIST_HEAD(&_stp_pool_q);
+
+       /* allocate buffers */
+       for (i = 0; i < STP_DEFAULT_BUFFERS; i++) {
+               p = (struct list_head *)kmalloc(sizeof(struct _stp_buffer),STP_ALLOC_FLAGS);
+               // printk("allocated buffer at %lx\n", (long)p);
+               if (!p)
+                       goto err0;
+               _stp_allocated_net_memory += sizeof(struct _stp_buffer);
+               list_add (p, &_stp_pool_q);
+       }
+       
+
+       /* create [debugfs]/systemtap_[pid]/cmd  */
+       _stp_cmd_file = debugfs_create_file("cmd", 0444, _stp_utt->utt_tree_root, NULL, &_stp_ctl_fops_cmd);
+       if (_stp_cmd_file == NULL) 
+               goto err0;
+
+       return 0;
+
+err0:
+       list_for_each_safe(p, tmp, &_stp_pool_q) {
+               list_del(p);
+               kfree(p);
+       }
+       errk ("Error creating systemtap debugfs entries.\n");
+       return -1;
+}
+
+
+static void _stp_unregister_ctl_channel (void)
+{
+       struct list_head *p, *tmp;
+       if (_stp_cmd_file) debugfs_remove(_stp_cmd_file);
+
+       /* free memory pools */
+       list_for_each_safe(p, tmp, &_stp_pool_q) {
+               list_del(p);
+               kfree(p);
+       }
+       list_for_each_safe(p, tmp, &_stp_ready_q) {
+               list_del(p);
+               kfree(p);
+       }
+}
+
index 64538ae6a369303a28e91a6b361bea55a915c636..bb97c4119394cb7d7ded25760d78a13183d37feb 100644 (file)
@@ -17,7 +17,7 @@ static struct list_head _stp_pool_q;
 spinlock_t _stp_pool_lock = SPIN_LOCK_UNLOCKED;
 spinlock_t _stp_ready_lock = SPIN_LOCK_UNLOCKED;
 
-#ifdef STP_RELAYFS
+#ifdef STP_BULKMODE
 extern int _stp_relay_flushing;
 /* handle the per-cpu subbuf info read for relayfs */
 static ssize_t
@@ -28,17 +28,12 @@ _stp_proc_read (struct file *file, char __user *buf, size_t count, loff_t *ppos)
 
        int cpu = *(int *)(PDE(file->f_dentry->d_inode)->data);
 
-       if (!_stp_chan)
+       if (!_stp_utt->rchan)
                return -EINVAL;
 
        out.cpu = cpu;
-#if (RELAYFS_CHANNEL_VERSION >= 4) || defined (CONFIG_RELAY)
-       out.produced = _stp_chan->buf[cpu]->subbufs_produced;
-       out.consumed = _stp_chan->buf[cpu]->subbufs_consumed;
-#else
-       out.produced = atomic_read(&_stp_chan->buf[cpu]->subbufs_produced);
-       out.consumed = atomic_read(&_stp_chan->buf[cpu]->subbufs_consumed);
-#endif  /* RELAYFS_CHANNEL_VERSION >= 4 || CONFIG_RELAY */
+       out.produced = atomic_read(&_stp_utt->rchan->buf[cpu]->subbufs_produced);
+       out.consumed = atomic_read(&_stp_utt->rchan->buf[cpu]->subbufs_consumed);
        out.flushing = _stp_relay_flushing;
 
        num = sizeof(out);
@@ -57,7 +52,7 @@ static ssize_t _stp_proc_write (struct file *file, const char __user *buf,
        if (copy_from_user(&info, buf, count))
                return -EFAULT;
 
-       relay_subbufs_consumed(_stp_chan, cpu, info.consumed);
+       relay_subbufs_consumed(_stp_utt->rchan, cpu, info.consumed);
        return count;
 }
 
@@ -66,9 +61,9 @@ static struct file_operations _stp_proc_fops = {
        .read = _stp_proc_read,
        .write = _stp_proc_write,
 };
-#endif
+#endif /* STP_BULKMODE */
 
-static ssize_t _stp_proc_write_cmd (struct file *file, const char __user *buf,
+static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
                                    size_t count, loff_t *ppos)
 {
        int type;
@@ -92,10 +87,10 @@ static ssize_t _stp_proc_write_cmd (struct file *file, const char __user *buf,
        switch (type) {
        case STP_START:
        {
-               struct _stp_transport_start st;
-               if (count < sizeof(struct _stp_transport_start))
+               struct _stp_msg_start st;
+               if (count < sizeof(st))
                        return 0;
-               if (copy_from_user (&st, buf, sizeof(struct _stp_transport_start)))
+               if (copy_from_user (&st, buf, sizeof(st)))
                        return -EFAULT;
                _stp_handle_start (&st);
                break;
@@ -110,20 +105,8 @@ static ssize_t _stp_proc_write_cmd (struct file *file, const char __user *buf,
        case STP_EXIT:
                _stp_exit_flag = 1;
                break;
-       case STP_TRANSPORT_INFO:
-       {
-               struct _stp_transport_info ti;
-               kbug("STP_TRANSPORT_INFO %d %d\n", (int)count, (int)sizeof(struct _stp_transport_info));
-               if (count < sizeof(struct _stp_transport_info))
-                       return 0;
-               if (copy_from_user (&ti, buf, sizeof(struct _stp_transport_info)))
-                       return -EFAULT;
-               if (_stp_transport_open (&ti) < 0)
-                       return -1;
-               break;
-       }
        default:
-               printk ("invalid command type %d\n", type);
+               errk ("invalid command type %d\n", type);
                return -EINVAL;
        }
 
@@ -137,9 +120,9 @@ struct _stp_buffer {
        char buf[STP_BUFFER_SIZE];
 };
 
-static DECLARE_WAIT_QUEUE_HEAD(_stp_proc_wq);
+static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq);
 
-static int _stp_write (int type, void *data, int len)
+static int _stp_ctl_write (int type, void *data, int len)
 {
        struct _stp_buffer *bptr;
        unsigned long flags;
@@ -200,8 +183,19 @@ static int _stp_write (int type, void *data, int len)
        return len;
 }
 
+/* send commands with timeout and retry */
+static int _stp_ctl_send (int type, void *data, int len)
+{
+       int err, trylimit = 50;
+       kbug("ctl_send: type=%d len=%d\n", type, len);
+       while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--)
+               msleep (5);
+       kbug("returning %d\n", err);
+       return err;
+}
+
 static ssize_t
-_stp_proc_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
+_stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
 {
        struct _stp_buffer *bptr;
        int len;
@@ -215,7 +209,7 @@ _stp_proc_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *p
                spin_unlock_irqrestore(&_stp_ready_lock, flags);
                if (file->f_flags & O_NONBLOCK)
                        return -EAGAIN;
-               if (wait_event_interruptible(_stp_proc_wq, !list_empty(&_stp_ready_q)))
+               if (wait_event_interruptible(_stp_ctl_wq, !list_empty(&_stp_ready_q)))
                        return -ERESTARTSYS;
                spin_lock_irqsave(&_stp_ready_lock, flags);
        }
@@ -246,12 +240,11 @@ _stp_proc_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *p
 
 static struct file_operations _stp_proc_fops_cmd = {
        .owner = THIS_MODULE,
-       .read = _stp_proc_read_cmd,
-       .write = _stp_proc_write_cmd,
-//     .poll = _stp_proc_poll_cmd
+       .read = _stp_ctl_read_cmd,
+       .write = _stp_ctl_write_cmd,
 };
 
-static struct proc_dir_entry *_stp_proc_root, *_stp_proc_mod;
+static struct proc_dir_entry *_stp_proc_root, *_stp_proc_pid;
 
 /* copy since proc_match is not MODULE_EXPORT'd */
 static int my_proc_match(int len, const char *name, struct proc_dir_entry *de)
@@ -299,13 +292,14 @@ err:
        return _stp_current_buffers;
 }
 
-static int _stp_register_procfs (void)
+static int _stp_register_ctl_channel (void)
 {
        int i;
-#ifdef STP_RELAYFS     
+       char buf[32];
+#ifdef STP_BULKMODE
        int j;
-       char buf[8];
 #endif
+
        struct proc_dir_entry *de;
        struct list_head *p, *tmp;
 
@@ -322,84 +316,80 @@ static int _stp_register_procfs (void)
                list_add (p, &_stp_pool_q);
        }
 
-        /* Formerly, we allocated /proc/systemtap, but unfortunately
-           that's racy with multiple concurrent probes.  So now we set
-           _stp_proc_root to proc_root.  This way, /proc/stap_XXXX
-           rather than /proc/systemtap/stap_XXXX will be the directory
-           under which cmd/ etc. will show up.  */
-        _stp_proc_root = NULL;
-
-       /* now create /proc/systemtap/module_name */
-       _stp_proc_mod = proc_mkdir (THIS_MODULE->name, _stp_proc_root);
-       if (_stp_proc_mod == NULL)
+       /* now create /proc/systemtap_[pid] */
+       sprintf(buf, "systemtap_%d", _stp_pid);
+       _stp_proc_pid = proc_mkdir (buf, NULL);
+       if (!_stp_proc_pid)
                goto err0;
-
-#ifdef STP_RELAYFS     
-       /* now for each cpu "n", create /proc/systemtap/module_name/n  */
+#ifdef STP_BULKMODE
+       /* now for each cpu "n", create /proc/systemtap_[pid]/n  */
        for_each_cpu(i) {
                sprintf(buf, "%d", i);
-               de = create_proc_entry (buf, S_IFREG|S_IRUSR, _stp_proc_mod);
+               de = create_proc_entry (buf, S_IFREG|S_IRUSR, _stp_proc_pid);
                if (de == NULL) 
                        goto err1;
                de->proc_fops = &_stp_proc_fops;
                de->data = _stp_kmalloc(sizeof(int));
                if (de->data == NULL) {
-                       remove_proc_entry (buf, _stp_proc_mod);
+                       remove_proc_entry (buf, _stp_proc_pid);
                        goto err1;
                }
                *(int *)de->data = i;
        }
-#endif
+#endif /* STP_BULKMODE */
 
-       /* finally create /proc/systemtap/module_name/cmd  */
-       de = create_proc_entry ("cmd", S_IFREG|S_IRUSR, _stp_proc_mod);
+       /* finally create /proc/systemtap_[pid]/cmd  */
+       de = create_proc_entry ("cmd", S_IFREG|S_IRUSR, _stp_proc_pid);
        if (de == NULL) 
                goto err1;
        de->proc_fops = &_stp_proc_fops_cmd;
        return 0;
 
 err1:
-#ifdef STP_RELAYFS
-       for (de = _stp_proc_mod->subdir; de; de = de->next)
+#ifdef STP_BULKMODE
+       for (de = _stp_proc_pid->subdir; de; de = de->next)
                kfree (de->data);
        for_each_cpu(j) {
                if (j == i)
                        break;
                sprintf(buf, "%d", i);
-               remove_proc_entry (buf, _stp_proc_mod);
+               remove_proc_entry (buf, _stp_proc_pid);
                
        }
-#endif
-        remove_proc_entry (THIS_MODULE->name, _stp_proc_root);
+#endif /* STP_BULKMODE */
+       sprintf(buf, "systemtap_%d", _stp_pid);
+       remove_proc_entry (buf, NULL);
 err0:
        list_for_each_safe(p, tmp, &_stp_pool_q) {
                list_del(p);
                kfree(p);
        }
 
-       printk (KERN_ERR "Error creating systemtap /proc entries.\n");
+       errk ("Error creating systemtap /proc entries.\n");
        return -1;
 }
 
 
-static void _stp_unregister_procfs (void)
+static void _stp_unregister_ctl_channel (void)
 {
        struct list_head *p, *tmp;
-#ifdef STP_RELAYFS
+       char buf[32];
+#ifdef STP_BULKMODE
        int i;
-       char buf[8];
        struct proc_dir_entry *de;
-
-       for (de = _stp_proc_mod->subdir; de; de = de->next)
+       kbug("unregistering procfs\n");
+       for (de = _stp_proc_pid->subdir; de; de = de->next)
                kfree (de->data);
 
        for_each_cpu(i) {
                sprintf(buf, "%d", i);
-               remove_proc_entry (buf, _stp_proc_mod);
+               remove_proc_entry (buf, _stp_proc_pid);
        }
-#endif
-       remove_proc_entry ("cmd", _stp_proc_mod);
-       remove_proc_entry (THIS_MODULE->name, _stp_proc_root);
+#endif /* STP_BULKMODE */
+
+       remove_proc_entry ("cmd", _stp_proc_pid);
+       sprintf(buf, "systemtap_%d", _stp_pid);
+       remove_proc_entry (buf, NULL);
 
        /* free memory pools */
        list_for_each_safe(p, tmp, &_stp_pool_q) {
index 1b616b7efc6aa0083e8e90f496891c02dadf96e1..ccbdc63e5d8b6870238d0a371fe95d6a08b48546 100644 (file)
@@ -1,47 +1,37 @@
-#ifndef _TRANSPORT_RELAYFS_C_ /* -*- linux-c -*- */
-#define _TRANSPORT_RELAYFS_C_
-
-/*
- * relayfs.c - stp relayfs-related transport functions
+/* -*- linux-c -*- 
+ * relayfs.c - relayfstransport functions
  *
- * Copyright (C) IBM Corporation, 2005
- * Copyright (C) Redhat Inc, 2005
+ * Copyright (C) IBM Corporation, 2005, 2006
+ * Copyright (C) Red Hat Inc, 2005, 2006, 2007
  *
- * This file is released under the GPL.
+ * This file is part of systemtap, and is free software.  You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
  */
 
-/** @file relayfs.c
- * @brief Systemtap relayfs-related transport functions
- */
+/* This file is only for older kernels that have no debugfs. */
 
-/** @addtogroup transport Transport Functions
- * @{
- */
-
-#include "relayfs.h"
+/* relayfs is required! */
+#if !defined (CONFIG_RELAYFS_FS) && !defined (CONFIG_RELAYFS_FS_MODULE)
+#error "RelayFS does not appear to be in this kernel!"
+#endif
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/relayfs_fs.h>
+#include <linux/namei.h>
+#include "utt.h"
 
-#if (RELAYFS_CHANNEL_VERSION >= 4) || defined (CONFIG_RELAY)
+static int _stp_relay_flushing = 0;
 
-/**
- *     _stp_subbuf_start - subbuf_start() relayfs callback implementation
- */
-static int _stp_subbuf_start(struct rchan_buf *buf,
-                            void *subbuf,
-                            void *prev_subbuf,
-                            size_t prev_padding)
+static void _stp_remove_relay_dir(struct dentry *dir)
 {
-       if (relay_buf_full(buf))
-               return 0;
-
-       if (prev_subbuf)
-               *((unsigned *)prev_subbuf) = prev_padding;
-
-       subbuf_start_reserve(buf, sizeof(unsigned int));
-
-       return 1;
+       if (dir)
+               relayfs_remove_dir(dir);
 }
 
-#else
 
 /**
  *     _stp_subbuf_start - subbuf_start() relayfs callback implementation
@@ -69,196 +59,90 @@ static void _stp_buf_full(struct rchan_buf *buf,
        *((unsigned *)subbuf) = padding;
 }
 
-#endif /* RELAYFS_CHANNEL_VERSION >= 4 || CONFIG_RELAY */
-
-#if defined (CONFIG_RELAY)
-static struct dentry *_stp_create_buf_file(const char *filename,
-                                          struct dentry *parent,
-                                          int mode,
-                                          struct rchan_buf *buf,
-                                          int *is_global)
-{
-       return debugfs_create_file(filename, mode, parent, buf,
-                                   &relay_file_operations);
-}
-
-static int _stp_remove_buf_file(struct dentry *dentry)
-{
-        debugfs_remove(dentry);
-
-        return 0;
-}
-#endif /* CONFIG_RELAY */
-
-/* relayfs callback functions */
-#if defined (CONFIG_RELAY)
 static struct rchan_callbacks stp_rchan_callbacks =
 {
        .subbuf_start = _stp_subbuf_start,
-       .create_buf_file = _stp_create_buf_file,
-       .remove_buf_file = _stp_remove_buf_file,
-};
-#else
-static struct rchan_callbacks stp_rchan_callbacks =
-{
-       .subbuf_start = _stp_subbuf_start,
-#if (RELAYFS_CHANNEL_VERSION < 4)
        .buf_full = _stp_buf_full,
-#endif  /* RELAYFS_CHANNEL_VERSION < 4 */
 };
-#endif  /* CONFIG_RELAY */
-
-static struct dentry *_stp_create_relay_dir(const char *dirname, struct dentry *parent)
-{
-       struct dentry *dir;
-       
-#if defined (CONFIG_RELAY)
-       dir = debugfs_create_dir(dirname, parent);
-       if (IS_ERR(dir)) {
-               printk("STP: Couldn't create directory %s - debugfs not configured in.\n", dirname);
-               dir = NULL;
-       }
-#else
-       dir = relayfs_create_dir(dirname, parent);
-#endif
-
-       return dir;
-}
 
-static void _stp_remove_relay_dir(struct dentry *dir)
-{
-       if (dir == NULL)
-               return;
-       
-#if defined (CONFIG_RELAY)
-               debugfs_remove(dir);
-#else
-               relayfs_remove_dir(dir);
-#endif
-}
 
-static inline void _stp_lock_inode(struct inode *inode)
+static void _stp_remove_relay_root(struct dentry *root)
 {
-#ifdef DEFINE_MUTEX
-       mutex_lock(&inode->i_mutex);
-#else
-       down(&inode->i_sem);
-#endif
+       if (root)
+               _stp_remove_relay_dir(root);
 }
 
-static inline void _stp_unlock_inode(struct inode *inode)
+struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts)
 {
-#ifdef DEFINE_MUTEX
-       mutex_unlock(&inode->i_mutex);
-#else
-       up(&inode->i_sem);
-#endif
-}
+       struct utt_trace *utt;
 
-static struct dentry *_stp_get_relay_root(void)
-{
-       struct file_system_type *fs;
-       struct super_block *sb;
-       struct dentry *root;
-       char *dirname = "systemtap";
+       utt = _stp_kzalloc(sizeof(*utt));
+       if (!utt)
+               return NULL;
 
-       root = _stp_create_relay_dir(dirname, NULL);
-       if (root)
-               return root;
-       
-#if defined (CONFIG_RELAY)
-       fs = get_fs_type("debugfs");
-#else
-       fs = get_fs_type("relayfs");
-#endif
-       if (!fs)
+       utt->utt_tree_root = relayfs_create_dir(utts->root, NULL);
+       if (!utt->utt_tree_root) {
+               errk("couldn't get relay root dir.\n");
                return NULL;
+       }
 
-       sb = list_entry(fs->fs_supers.next, struct super_block, s_instances);
-       _stp_lock_inode(sb->s_root->d_inode);
-       root = lookup_one_len(dirname, sb->s_root, strlen(dirname));
-       _stp_unlock_inode(sb->s_root->d_inode);
-       if (!IS_ERR(root))
-               dput(root);
        
-       return root;
-}
-
-static void _stp_put_relay_root(struct dentry *root)
-{
-       if (root)
-               _stp_remove_relay_dir(root);
-}
-
-static struct dentry *_relay_root;
+       kbug("relay_open %d %d\n",  utts->buf_size, utts->buf_nr);
+       utt->rchan = relay_open("trace", utt->utt_tree_root, utts->buf_size, utts->buf_nr, 0, &stp_rchan_callbacks);
+       if (!utt->rchan) {
+               errk("couldn't create relay channel.\n");
+               _stp_remove_relay_root(utt->utt_tree_root);
+               return NULL;
+       }
 
-/**
- *     _stp_relayfs_close - destroys relayfs channel
- *     @chan: the relayfs channel
- *     @dir: the directory containing the relayfs files
- */
-void _stp_relayfs_close(struct rchan *chan, struct dentry *dir)
-{
-       if (!chan)
-               return;
-       relay_close(chan);
-       _stp_remove_relay_dir(dir);
-       _stp_put_relay_root(_relay_root);
+       utt->rchan->private_data = utt;
+       utt->trace_state = Utt_trace_setup;
+       utts->err = 0;
+       return utt;
 }
 
-/**
- *     _stp_relayfs_open - create relayfs channel
- *     @n_subbufs: number of relayfs sub-buffers
- *     @subbuf_size: size of relayfs sub-buffers
- *     @pid: daemon pid
- *     @outdir: receives directory dentry
- *
- *     Returns relay channel, NULL on failure
- *
- *     Creates relayfs files as /systemtap/pid/cpuX in relayfs root
- */
-struct rchan *_stp_relayfs_open(unsigned n_subbufs,
-                               unsigned subbuf_size,
-                               int pid,
-                               struct dentry **outdir)
+int utt_trace_startstop(struct utt_trace *utt, int start,
+                       unsigned int *trace_seq)
 {
-       char dirname[16];
-       struct rchan *chan;
-       struct dentry* root, *dir;
-
-       sprintf(dirname, "%d", pid);
-       
-       root = _stp_get_relay_root();
-       if (!root) {
-               printk("STP: couldn't get relay root dir.\n");
-               return NULL;
-       }
+       int ret;
 
-       dir = _stp_create_relay_dir(dirname, root);
-       if (!dir) {
-               printk("STP: couldn't create relay dir %s.\n", dirname);
-               _stp_put_relay_root(root);
-               return NULL;
-       }
-       
-#if (RELAYFS_CHANNEL_VERSION >= 4)
-       chan = relay_open("cpu", dir, subbuf_size,
-                         n_subbufs, &stp_rchan_callbacks);
-#else
-       chan = relay_open("cpu", dir, subbuf_size,
-                         n_subbufs, 0, &stp_rchan_callbacks);
-#endif /* RELAYFS_CHANNEL_VERSION >= 4 */
+       if (!utt)
+               return 0;
 
-       if (!chan) {
-               printk("STP: couldn't create relay channel.\n");
-               _stp_remove_relay_dir(dir);
-               _stp_put_relay_root(root);
+       /*
+        * For starting a trace, we can transition from a setup or stopped
+        * trace. For stopping a trace, the state must be running
+        */
+       ret = -EINVAL;
+       if (start) {
+               if (utt->trace_state == Utt_trace_setup ||
+                   utt->trace_state == Utt_trace_stopped) {
+                       if (trace_seq)
+                               (*trace_seq)++;
+                       smp_mb();
+                       utt->trace_state = Utt_trace_running;
+                       ret = 0;
+               }
+       } else {
+               if (utt->trace_state == Utt_trace_running) {
+                       utt->trace_state = Utt_trace_stopped;
+                       _stp_relay_flushing = 1;
+                       relay_flush(utt->rchan);
+                       ret = 0;
+               }
        }
 
-       _relay_root = root;
-       *outdir = dir;
-       return chan;
+       return ret;
 }
 
-#endif /* _TRANSPORT_RELAYFS_C_ */
 
+int utt_trace_remove(struct utt_trace *utt)
+{
+       kbug("removing relayfs files. %d\n", utt->trace_state);
+       if (utt && (utt->trace_state == Utt_trace_setup || utt->trace_state == Utt_trace_stopped)) {
+               relay_close(utt->rchan);
+               _stp_remove_relay_root(utt->utt_tree_root);
+               kfree(utt);
+       }
+       return 0;
+}
index c21c0ede57ffd37b884579b606dc2cda6efee235..abe60226c1a8cf72248179c09b1ffd499a25535f 100644 (file)
@@ -170,7 +170,7 @@ static int _stp_do_symbols(const char __user *buf, int count)
        switch (_stp_symbol_state) {
        case 0:
                if (count != 8) {
-                       printk("unexpected systemtap error: _stp_do_symbols: count=%d\n", count);
+                       errk(" _stp_do_symbols: count=%d\n", count);
                        return -EFAULT;
                }               
                if (get_user(num, (unsigned __user *)buf))
@@ -181,7 +181,7 @@ static int _stp_do_symbols(const char __user *buf, int count)
 
                _stp_modules[0] = _stp_alloc_module(num, datasize);
                if (_stp_modules[0] == NULL) {
-                       printk("unexpected systemtap error: cannot allocate memory\n");
+                       errk("cannot allocate memory\n");
                        return -EFAULT;
                }
                _stp_symbol_state = 1;
@@ -207,7 +207,7 @@ static int _stp_do_symbols(const char __user *buf, int count)
                _stp_modules_by_addr[0] = _stp_modules[0];
                break;
        default:
-               printk("systemtap error: unexpected symbol data of size %d.\n", count);
+               errk("unexpected symbol data of size %d.\n", count);
        }
        return count;
 }
@@ -251,7 +251,7 @@ static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod)
                mod = _stp_alloc_module_from_module(m);
                if (mod == NULL) {
                        module_put(m);
-                       printk("Systemtap failed to allocate memory for module.\n");
+                       errk("failed to allocate memory for module.\n");
                        return NULL;
                }
 
@@ -347,7 +347,7 @@ static int _stp_do_module(const char __user *buf, int count)
        int i;
 
        if (count < sizeof(tmpmod)) {
-               printk("_stp_do_modules: expected %d and got %d\n", (int)sizeof(tmpmod), count);
+               errk("expected %d and got %d\n", (int)sizeof(tmpmod), count);
                return -EFAULT;
        }
        if (copy_from_user ((char *)&tmpmod, buf, sizeof(tmpmod)))
@@ -361,7 +361,7 @@ static int _stp_do_module(const char __user *buf, int count)
        /* copy in section data */
        tmpmod.sections = _stp_kmalloc(count - sizeof(tmpmod));
        if (tmpmod.sections == NULL) {
-               printk("_stp_do_module: unable to allocate memory.\n");
+               errk("unable to allocate memory.\n");
                return -EFAULT;
        }
        if (copy_from_user ((char *)tmpmod.sections, buf+sizeof(tmpmod), count-sizeof(tmpmod))) {
@@ -391,7 +391,7 @@ static int _stp_do_module(const char __user *buf, int count)
        return count;
 }
 
-static int _stp_transport_send (int type, void *data, int len);
+static int _stp_ctl_send (int type, void *data, int len);
 
 static int _stp_module_load_notify(struct notifier_block * self, unsigned long val, void * data)
 {
@@ -403,10 +403,10 @@ static int _stp_module_load_notify(struct notifier_block * self, unsigned long v
        case MODULE_STATE_COMING:
                dbug("module %s loaded\n", mod->name);
                strlcpy(rmod.name, mod->name, STP_MODULE_NAME_LEN);
-               _stp_transport_send(STP_MODULE, &rmod, sizeof(struct _stp_module));
+               _stp_ctl_send(STP_MODULE, &rmod, sizeof(struct _stp_module));
                break;
        default:
-               printk("module loaded? val=%ld\n", val);
+               errk("module loaded? val=%ld\n", val);
        }
 #endif
        return 0;
index de0e8c2dafc7b64a093b74082994a47bd20e9759..59402f6f11ffee8e7878201c1598d54b3efde4d2 100644 (file)
 #include "time.c"
 #include "symbols.c"
 
-#ifdef STP_RELAYFS
+#ifdef STP_OLD_TRANSPORT
 #include "relayfs.c"
-static struct rchan *_stp_chan;
-static struct dentry *_stp_dir;
-int _stp_relay_flushing = 0;
+#else
+#include "utt.c"
 #endif
 
-static atomic_t _stp_start_finished = ATOMIC_INIT (0);
-static int _stp_dpid;
-static int _stp_pid;
+static struct utt_trace *_stp_utt = NULL;
+static unsigned int utt_seq = 1;
+
+static int _stp_start_finished = 0;
+static int _stp_probes_started = 0;
 
+/* module parameters */
+static int _stp_pid, _stp_bufsize;
 module_param(_stp_pid, int, 0);
-MODULE_PARM_DESC(_stp_pid, "daemon pid");
+MODULE_PARM_DESC(_stp_pid, "pid");
+module_param(_stp_bufsize, int, 0);
+MODULE_PARM_DESC(_stp_bufsize, "buffer size");
 
-int _stp_target = 0;
-int _stp_exit_called = 0;
+pid_t _stp_target = 0;
+static int _stp_exit_called = 0;
 int _stp_exit_flag = 0;
 
 /* forward declarations */
 void probe_exit(void);
 int probe_start(void);
 void _stp_exit(void);
-void _stp_handle_start (struct _stp_transport_start *st);
+void _stp_handle_start (struct _stp_msg_start *st);
+
 
-/* check for new workquqeq API */
+/* check for new workqueue API */
 #ifdef DECLARE_DELAYED_WORK 
 static void _stp_work_queue (struct work_struct *data);
 static DECLARE_DELAYED_WORK(_stp_work, _stp_work_queue);
@@ -53,105 +59,59 @@ static DECLARE_WORK(_stp_work, _stp_work_queue, NULL);
 #endif
 
 static struct workqueue_struct *_stp_wq;
-int _stp_transport_open(struct _stp_transport_info *info);
 
+#ifdef STP_OLD_TRANSPORT
 #include "procfs.c"
+#else
+#include "control.c"
+#endif
 
-/* send commands with timeout and retry */
-static int _stp_transport_send (int type, void *data, int len)
+void _stp_ask_for_symbols(void)
 {
-       int err, trylimit = 50;
-       while ((err = _stp_write(type, data, len)) < 0 && trylimit--)
-               msleep (5);
-       return err;
-}
+       struct _stp_msg_symbol req;
+       struct _stp_module mod;
+       struct _stp_msg_trans tran;
 
-#ifndef STP_RELAYFS
-static int _stp_transport_write (void *data, int len)  
-{
-       /* when _stp_exit_called is set, we are in probe_exit() and we can sleep */
-       if (_stp_exit_called)
-               return _stp_transport_send (STP_REALTIME_DATA, data, len);
-       return _stp_write(STP_REALTIME_DATA, data, len);
-}
-#endif /*STP_RELAYFS */
+       /* ask for symbols, modules, and send transport info */
+       kbug("AFS\n");
 
-/*
- *     _stp_handle_buf_info - handle STP_BUF_INFO
- */
-#ifdef STP_RELAYFS
-static void _stp_handle_buf_info(int *cpuptr)
-{
-       struct _stp_buf_info out;
+       req.endian = 0x1234;
+       req.ptr_size = sizeof(char *);
+       _stp_ctl_send(STP_SYMBOLS, &req, sizeof(req));
+       
+       strcpy(mod.name, "");
+       _stp_ctl_send(STP_MODULE, &mod, sizeof(mod));
 
-       out.cpu = *cpuptr;
-#if (RELAYFS_CHANNEL_VERSION >= 4) || defined (CONFIG_RELAY)
-       out.produced = _stp_chan->buf[*cpuptr]->subbufs_produced;
-       out.consumed = _stp_chan->buf[*cpuptr]->subbufs_consumed;
+#ifdef STP_BULKMODE
+       tran.bulk_mode = 1;
 #else
-       out.produced = atomic_read(&_stp_chan->buf[*cpuptr]->subbufs_produced);
-       out.consumed = atomic_read(&_stp_chan->buf[*cpuptr]->subbufs_consumed);
-#endif /* RELAYFS_CHANNEL_VERSION >=_4 || CONFIG_RELAY */
-
-       _stp_transport_send(STP_BUF_INFO, &out, sizeof(out));
-}
+       tran.bulk_mode = 0;
 #endif
+       tran.subbuf_size =_stp_subbuf_size;
+       tran.n_subbufs = _stp_nsubbufs;
+       _stp_ctl_send(STP_TRANSPORT, &tran, sizeof(tran));
+}
 
 /*
  *     _stp_handle_start - handle STP_START
  */
 
-void _stp_handle_start (struct _stp_transport_start *st)
+void _stp_handle_start (struct _stp_msg_start *st)
 {
-#ifdef CONFIG_MODULES
-       static int got_modules=0;
-#endif
-
-       kbug ("stp_handle_start pid=%d\n", st->pid);
-
-       /* we've got a start request, but first, grab kernel symbols if we need them */
-       if (_stp_num_modules == 0) {
-               struct _stp_symbol_req req;
-               req.endian = 0x1234;
-               req.ptr_size = sizeof(char *);
-               _stp_transport_send(STP_SYMBOLS, &req, sizeof(req));
-               return;
-       }
-
-#ifdef CONFIG_MODULES
-       /* grab current module addresses if we haven't already */
-       if (got_modules == 0) {
-               struct _stp_module mod;
-               strcpy(mod.name, "");
-               got_modules = 1;
-               _stp_transport_send(STP_MODULE, &mod, sizeof(struct _stp_module));
-               return;
-       }
+       kbug ("stp_handle_start\n");
 
        if (register_module_notifier(&_stp_module_load_nb))
-               printk("Systemtap error: failed to load module notifier\n");
-#endif
+               errk("failed to load module notifier\n");
 
-       /* note: st->pid is actually the return code for the reply packet */
-       st->pid = probe_start();
-       atomic_set(&_stp_start_finished,1);
+       _stp_target = st->target;
+       st->res = probe_start();
+       _stp_start_finished = 1;
+       if (st->res >= 0)
+               _stp_probes_started = 1;
 
-       /* if probe_start() failed, suppress calling probe_exit() */
-       if (st->pid < 0)
-               _stp_exit_called = 1;
-
-       _stp_transport_send(STP_START, st, sizeof(*st));
+       _stp_ctl_send(STP_START, st, sizeof(*st));
 }
 
-#ifdef STP_RELAYFS
-/**
- *     _stp_handle_subbufs_consumed - handle STP_SUBBUFS_CONSUMED
- */
-static void _stp_handle_subbufs_consumed(int pid, struct _stp_consumed_info *info)
-{
-       relay_subbufs_consumed(_stp_chan, info->cpu, info->consumed);
-}
-#endif
 
 /* common cleanup code. */
 /* This is called from the kernel thread when an exit was requested */
@@ -165,31 +125,29 @@ static void _stp_cleanup_and_exit (int dont_rmmod)
        if (!_stp_exit_called) {
                int failures;
 
-#ifdef CONFIG_MODULES
                unregister_module_notifier(&_stp_module_load_nb);
-#endif
+
                /* we only want to do this stuff once */
                _stp_exit_called = 1;
 
-               kbug("calling probe_exit\n");
-               /* tell the stap-generated code to unload its probes, etc */
-               probe_exit();
-               kbug("done with probe_exit\n");
+               if (_stp_probes_started) {
+                       kbug("calling probe_exit\n");
+                       /* tell the stap-generated code to unload its probes, etc */
+                       probe_exit();
+                       kbug("done with probe_exit\n");
+               }
 
                failures = atomic_read(&_stp_transport_failures);
                if (failures)
                        _stp_warn ("There were %d transport failures.\n", failures);
 
-#ifdef STP_RELAYFS
-               if (_stp_transport_mode == STP_TRANSPORT_RELAYFS) {
-                       _stp_relay_flushing = 1;
-                       relay_flush(_stp_chan);
-               }
-#endif
-               kbug("transport_send STP_EXIT\n");
+               kbug("************** calling startstop 0 *************\n");
+               if (_stp_utt) utt_trace_startstop(_stp_utt, 0, &utt_seq);
+
+               kbug("ctl_send STP_EXIT\n");
                /* tell staprun to exit (if it is still there) */
-               _stp_transport_send(STP_EXIT, &dont_rmmod, sizeof(int));
-               kbug("done with transport_send STP_EXIT\n");
+               _stp_ctl_send(STP_EXIT, &dont_rmmod, sizeof(int));
+               kbug("done with ctl_send STP_EXIT\n");
        }
 }
 
@@ -212,20 +170,20 @@ static void _stp_work_queue (void *data)
        spin_unlock_irqrestore(&_stp_ready_lock, flags);
 
        if (do_io)
-               wake_up_interruptible(&_stp_proc_wq);
+               wake_up_interruptible(&_stp_ctl_wq);
 
        /* if exit flag is set AND we have finished with probe_start() */
-       if (unlikely(_stp_exit_flag && atomic_read(&_stp_start_finished))) {
+       if (unlikely(_stp_exit_flag && _stp_start_finished)) {
                _stp_cleanup_and_exit(0);
                cancel_delayed_work(&_stp_work);
                flush_workqueue(_stp_wq);
-               wake_up_interruptible(&_stp_proc_wq);
+               wake_up_interruptible(&_stp_ctl_wq);
        } else
                queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER);
 }
 
 /**
- *     _stp_transport_close - close proc and relayfs channels
+ *     _stp_transport_close - close ctl and relayfs channels
  *
  *     This is called automatically when the module is unloaded.
  *     
@@ -236,15 +194,10 @@ void _stp_transport_close()
        _stp_cleanup_and_exit(1);
        cancel_delayed_work(&_stp_work);
        destroy_workqueue(_stp_wq);
-       wake_up_interruptible(&_stp_proc_wq);
-#ifdef STP_RELAYFS
-       if (_stp_transport_mode == STP_TRANSPORT_RELAYFS) 
-               _stp_relayfs_close(_stp_chan, _stp_dir);
-#endif
-#ifdef CONFIG_MODULES
+       wake_up_interruptible(&_stp_ctl_wq);
        unregister_module_notifier(&_stp_module_load_nb);
-#endif
-       _stp_unregister_procfs();
+       _stp_unregister_ctl_channel();
+       if (_stp_utt) utt_trace_remove(_stp_utt);
        _stp_free_modules();
        _stp_kill_time();
        _stp_print_cleanup();   /* free print buffers */
@@ -252,61 +205,21 @@ void _stp_transport_close()
        kbug("---- CLOSED ----\n");
 }
 
-/**
- *     _stp_transport_open - open proc and relayfs channels
- *      with proper parameters
- *     Returns negative on failure, >0 otherwise.
- *
- *     This function registers the probe with the control channel,
- *     and if the probe output will not be 'streaming', creates a
- *     relayfs channel for it.  This must be called before any I/O is
- *     done. 
- * 
- *      This function is called in response to an STP_TRANSPORT
- *      message from staprun cmd.  It replies with a similar message
- *      containing the final parameters used.
- */
 
-int _stp_transport_open(struct _stp_transport_info *info)
+static struct utt_trace *_stp_utt_open(void)
 {
-       kbug ("stp_transport_open: %d Mb buffer. target=%d\n", info->buf_size, info->target);
-
-       info->transport_mode = _stp_transport_mode;
-       info->merge = 0;
+       struct utt_trace_setup utts;    
+       sprintf(utts.root, "systemtap_%d", _stp_pid);
+       utts.buf_size = _stp_subbuf_size;
+       utts.buf_nr = _stp_nsubbufs;
 
-       kbug("transport_mode=%d\n", info->transport_mode);
-       _stp_target = info->target;
-
-#ifdef STP_RELAYFS
-       if (_stp_transport_mode == STP_TRANSPORT_RELAYFS) {
-               if (info->buf_size) {
-                       unsigned size = info->buf_size * 1024 * 1024;
-                       subbuf_size = ((size >> 2) + 1) * 65536;
-                       n_subbufs = size / subbuf_size;
-               }
-               info->n_subbufs = n_subbufs;
-               info->subbuf_size = subbuf_size;
-
-#ifdef STP_RELAYFS_MERGE
-               info->merge = 1;
-#endif
-
-               _stp_chan = _stp_relayfs_open(n_subbufs, subbuf_size, _stp_pid, &_stp_dir);
-               _stp_allocated_net_memory += n_subbufs * subbuf_size;
-
-               if (!_stp_chan)
-                       return -ENOMEM;
-               kbug ("stp_transport_open: %u Mb buffers, subbuf_size=%u, n_subbufs=%u\n",
-                     info->buf_size, subbuf_size, n_subbufs);
-       } else 
+#ifdef STP_BULKMODE
+       utts.is_global = 0;
+#else
+       utts.is_global = 1;
 #endif
-       {
-               if (info->buf_size) 
-                       _stp_set_buffers(info->buf_size * 1024 * 1024 / STP_BUFFER_SIZE);
-       }
 
-       /* send reply */
-       return _stp_transport_send (STP_TRANSPORT_INFO, info, sizeof(*info));
+       return utt_trace_setup(&utts);
 }
 
 /**
@@ -319,63 +232,53 @@ int _stp_transport_init(void)
 
        kbug("transport_init from %ld %ld\n", (long)_stp_pid, (long)current->pid);
 
-       /* create print buffers */
-       ret = _stp_print_init();
-       if (ret < 0)
-               goto out;
+       if (_stp_bufsize) {
+               unsigned size = _stp_bufsize * 1024 * 1024;
+               _stp_subbuf_size = ((size >> 2) + 1) * 65536;
+               _stp_nsubbufs = size / _stp_subbuf_size;
+               kbug("Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size);
+       }
 
        /* initialize timer code */
-       ret =_stp_init_time();
-       if (ret)
-               goto print_cleanup;
+       if (_stp_init_time())
+               return -1;
+
+#if !defined (STP_OLD_TRANSPORT) || defined (STP_BULKMODE)
+       /* open utt (relayfs) channel to send data to userspace */
+       _stp_utt = _stp_utt_open();
+       if (!_stp_utt)
+               goto err0;
+#endif
+       /* create debugfs/procfs control channel */
+       if (_stp_register_ctl_channel() < 0)
+               goto err1;
+
+       /* create print buffers */
+       if (_stp_print_init() < 0)
+               goto err2;
 
-       /* set up procfs communications */
-       ret = _stp_register_procfs();
-       if (ret < 0)
-               goto kill_time;
+       utt_trace_startstop(_stp_utt, 1, &utt_seq);
 
        /* create workqueue of kernel threads */
        _stp_wq = create_workqueue("systemtap");
        if (!_stp_wq)
-          goto proc_cleanup;
+               goto err3;
+
        queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER);
-out:
-       return ret;
 
-proc_cleanup:
-       ret = -1;
-       _stp_unregister_procfs();
-kill_time:
+       /* request symbolic information */
+       _stp_ask_for_symbols();
+       return 0;
+
+err3:
+       _stp_print_cleanup();
+err2:
+       _stp_unregister_ctl_channel();
+err1:
+       if (_stp_utt) utt_trace_remove(_stp_utt);       
+err0:
        _stp_kill_time();
-print_cleanup:
-       _stp_print_cleanup();   /* free print buffers */
-       goto out;
+       return -1;
 }
 
-
-/* like relay_write except returns an error code */
-
-#ifdef STP_RELAYFS
-static int _stp_relay_write (const void *data, unsigned length)
-{
-       unsigned long flags;
-       struct rchan_buf *buf;
-
-       if (unlikely(length == 0))
-               return 0;
-
-       local_irq_save(flags);
-       buf = _stp_chan->buf[smp_processor_id()];
-       if (unlikely(buf->offset + length > _stp_chan->subbuf_size))
-               length = relay_switch_subbuf(buf, length);
-       memcpy(buf->data + buf->offset, data, length);
-       buf->offset += length;
-       local_irq_restore(flags);
-       
-       if (unlikely(length == 0))
-               return -1;
-       
-       return length;
-}
-#endif
 #endif /* _TRANSPORT_C_ */
index da5737347e984c8d4572efe6ebcaafd733ea2cfe..2d77414cb8d643b69cc9e8205f57647e668e1ca0 100644 (file)
@@ -5,7 +5,6 @@
  * @brief Header file for stp transport
  */
 
-#include "relayfs.h"
 #include "transport_msgs.h"
 
 void _stp_warn (const char *fmt, ...);
@@ -15,15 +14,8 @@ void _stp_warn (const char *fmt, ...);
 /* how often the work queue wakes up and checks buffers */
 #define STP_WORK_TIMER (HZ/100)
 
-#ifdef STP_RELAYFS
-static unsigned n_subbufs = 16;
-static unsigned subbuf_size = 65536;
-#define _stp_transport_write(data, len)  _stp_relay_write(data, len)
-static int _stp_transport_mode = STP_TRANSPORT_RELAYFS;
-#else
-static int _stp_transport_mode = STP_TRANSPORT_PROC;
-#endif
-
+static unsigned _stp_nsubbufs = 4;
+static unsigned _stp_subbuf_size = 65536*2;
 extern void _stp_transport_close(void);
 extern int _stp_print_init(void);
 extern void _stp_print_cleanup(void);
index f43627f1063c0681acd7e110166de53dcfd74882..be1a291482e5990a5ff27552afbab3f969d11534 100644 (file)
@@ -1,67 +1,84 @@
-/* SystemTap transport values */
-enum
-{
-       STP_TRANSPORT_PROC = 1,
-       STP_TRANSPORT_RELAYFS
+/* -*- linux-c -*- 
+ * transport_msgs.h - messages exchanged between module and userspace
+ *
+ * Copyright (C) Red Hat Inc, 2006-2007
+ *
+ * This file is part of systemtap, and is free software.  You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+struct _stp_trace {
+       uint32_t sequence;      /* event number */
+       uint32_t pdu_len;       /* length of data after this trace */
 };
 
 /* stp control channel command values */
 enum
 {
-       STP_BUF_INFO = 1,
-       STP_SUBBUFS_CONSUMED,
-        STP_REALTIME_DATA,
-        STP_TRANSPORT_INFO,
        STP_START,
         STP_EXIT,
        STP_OOB_DATA,
        STP_SYSTEM,
        STP_SYMBOLS,
        STP_MODULE,
+       STP_TRANSPORT,
+       STP_CONNECT,
+       STP_DISCONNECT,
+#ifdef STP_OLD_TRANSPORT
+       /** deprecated **/
+       STP_BUF_INFO,
+       STP_SUBBUFS_CONSUMED,
+       STP_REALTIME_DATA,
+#endif
 };
 
-/* control channel command structs */
-struct _stp_buf_info
+/* control channel messages */
+
+/* command to execute: sent to staprun */
+struct _stp_msg_cmd
 {
-       int32_t cpu;
-       uint32_t produced;
-       uint32_t consumed;
-       int32_t flushing;
+       char cmd[128];
 };
 
-struct _stp_consumed_info
+/* request for symbol data. sent to staprun */
+struct _stp_msg_symbol
 {
-       int32_t cpu;
-       uint32_t consumed;
+       int32_t endian;
+       int32_t ptr_size;
 };
 
-struct _stp_transport_info
+/* Request to start probes. */
+/* Sent from staprun. Then returned from module. */
+struct _stp_msg_start
 {
-       uint32_t buf_size;
-       uint32_t subbuf_size;
-       uint32_t n_subbufs;
-       int32_t transport_mode;
-       int32_t merge;          // merge relayfs output?
-       int32_t target;         // target pid
-#if 0
-       char cmd[256];          // cmd to process data
-#endif
+       pid_t target;
+        int32_t res;    // for reply: result of probe_start()
 };
 
-struct _stp_transport_start
+/* transport information. sent to staprun */
+struct _stp_msg_trans
 {
-       int32_t pid;    // pid for streaming data
+        int32_t bulk_mode;
+
+       /* old relayfs uses these */
+       uint32_t subbuf_size;
+        uint32_t n_subbufs;
 };
 
-struct _stp_cmd_info
+#ifdef STP_OLD_TRANSPORT
+/**** for compatibility with old relayfs ****/
+struct _stp_buf_info
 {
-       char cmd[128];
+        int32_t cpu;
+        uint32_t produced;
+        uint32_t consumed;
+        int32_t flushing;
 };
-
-struct _stp_symbol_req
+struct _stp_consumed_info
 {
-       int32_t endian;
-       int32_t ptr_size;
+        int32_t cpu;
+        uint32_t consumed;
 };
-
-       
+#endif
diff --git a/runtime/transport/utt.c b/runtime/transport/utt.c
new file mode 100644 (file)
index 0000000..b23260d
--- /dev/null
@@ -0,0 +1,253 @@
+/* -*- linux-c -*- 
+ *
+ * This is a modified version of the proposed utt interface. If that
+ * interface makes it into the kernel, this file can go away.
+ *
+ * Copyright (C) 2006 Jens Axboe <axboe@suse.de>
+ *
+ * Moved to utt.c by Tom Zanussi, 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/relay.h>
+#include "utt.h"
+
+static void utt_remove_root(struct utt_trace *utt)
+{
+       if (utt->utt_tree_root && simple_empty(utt->utt_tree_root)) {
+               debugfs_remove(utt->utt_tree_root);
+               utt->utt_tree_root = NULL;
+       }
+}
+
+static void utt_remove_tree(struct utt_trace *utt)
+{
+       utt_remove_root(utt);
+}
+
+static struct dentry *utt_create_tree(struct utt_trace *utt, const char *root)
+{
+       if (root == NULL)
+               return NULL;
+       
+       if (!utt->utt_tree_root)
+               utt->utt_tree_root = debugfs_create_dir(root, NULL);
+       return utt->utt_tree_root;
+}
+
+
+void utt_trace_cleanup(struct utt_trace *utt)
+{
+       relay_close(utt->rchan);
+       debugfs_remove(utt->dropped_file);
+       utt_remove_tree(utt);
+       free_percpu(utt->sequence);
+       kfree(utt);
+}
+
+int utt_trace_remove(struct utt_trace *utt)
+{
+       if (utt->trace_state == Utt_trace_setup ||
+           utt->trace_state == Utt_trace_stopped)
+               utt_trace_cleanup(utt);
+
+       return 0;
+}
+
+static int utt_dropped_open(struct inode *inode, struct file *filp)
+{
+       filp->private_data = inode->i_private;
+
+       return 0;
+}
+
+static ssize_t utt_dropped_read(struct file *filp, char __user *buffer,
+                               size_t count, loff_t *ppos)
+{
+       struct utt_trace *utt = filp->private_data;
+       char buf[16];
+
+       snprintf(buf, sizeof(buf), "%u\n", atomic_read(&utt->dropped));
+
+       return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+static struct file_operations utt_dropped_fops = {
+       .owner =        THIS_MODULE,
+       .open =         utt_dropped_open,
+       .read =         utt_dropped_read,
+};
+
+/*
+ * Keep track of how many times we encountered a full subbuffer, to aid
+ * the user space app in telling how many lost events there were.
+ */
+static int utt_subbuf_start_callback(struct rchan_buf *buf, void *subbuf,
+                                    void *prev_subbuf, size_t prev_padding)
+{
+       struct utt_trace *utt;
+
+       if (!relay_buf_full(buf))
+               return 1;
+
+       utt = buf->chan->private_data;
+       atomic_inc(&utt->dropped);
+       return 0;
+}
+
+static int utt_remove_buf_file_callback(struct dentry *dentry)
+{
+       debugfs_remove(dentry);
+       return 0;
+}
+
+static struct dentry *utt_create_buf_file_callback(const char *filename,
+                                                  struct dentry *parent,
+                                                  int mode,
+                                                  struct rchan_buf *buf,
+                                                  int *is_global)
+{
+       return debugfs_create_file(filename, mode, parent, buf,
+                                  &relay_file_operations);
+}
+
+static struct dentry *utt_create_global_buf_file_callback(const char *filename,
+                                                         struct dentry *parent,
+                                                         int mode,
+                                                         struct rchan_buf *buf,
+                                                         int *is_global)
+{
+       *is_global = 1;
+       return debugfs_create_file(filename, mode, parent, buf,
+                                  &relay_file_operations);
+}
+
+static struct rchan_callbacks utt_relay_callbacks = {
+       .subbuf_start           = utt_subbuf_start_callback,
+       .create_buf_file        = utt_create_buf_file_callback,
+       .remove_buf_file        = utt_remove_buf_file_callback,
+};
+
+static struct rchan_callbacks utt_relay_callbacks_global = {
+       .subbuf_start           = utt_subbuf_start_callback,
+       .create_buf_file        = utt_create_global_buf_file_callback,
+       .remove_buf_file        = utt_remove_buf_file_callback,
+};
+
+/*
+ * Setup everything required to start tracing
+ */
+struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts)
+{
+       struct utt_trace *utt = NULL;
+       struct dentry *dir = NULL;
+       int ret = -EINVAL;
+
+       if (!utts->buf_size || !utts->buf_nr)
+               goto err;
+
+       ret = -ENOMEM;
+       utt = kzalloc(sizeof(*utt), GFP_KERNEL);
+       if (!utt)
+               goto err;
+
+       utt->sequence = alloc_percpu(unsigned long);
+       if (!utt->sequence)
+               goto err;
+
+       ret = -ENOENT;
+       dir = utt_create_tree(utt, utts->root);
+       if (!dir)
+               goto err;
+
+       atomic_set(&utt->dropped, 0);
+
+       ret = -EIO;
+       utt->dropped_file = debugfs_create_file("dropped", 0444, dir, utt, &utt_dropped_fops);
+       if (!utt->dropped_file)
+               goto err;
+
+#if (RELAYFS_CHANNEL_VERSION >= 7)
+       if (utts->is_global)
+               utt->rchan = relay_open("trace", dir, utts->buf_size, utts->buf_nr, 
+                                       &utt_relay_callbacks_global, NULL);
+       else
+               utt->rchan = relay_open("trace", dir, utts->buf_size, utts->buf_nr, 
+                                       &utt_relay_callbacks, NULL);
+#else
+       if (utts->is_global)
+               utt->rchan = relay_open("trace", dir, utts->buf_size, utts->buf_nr, &utt_relay_callbacks_global);
+       else
+               utt->rchan = relay_open("trace", dir, utts->buf_size, utts->buf_nr, &utt_relay_callbacks);
+#endif
+
+       if (!utt->rchan)
+               goto err;
+       utt->rchan->private_data = utt;
+
+       utt->trace_state = Utt_trace_setup;
+
+       utts->err = 0;
+       return utt;
+err:
+       if (utt) {
+               if (utt->dropped_file)
+                       debugfs_remove(utt->dropped_file);
+               if (utt->sequence)
+                       free_percpu(utt->sequence);
+               if (utt->rchan)
+                       relay_close(utt->rchan);
+               kfree(utt);
+       }
+       if (dir)
+               utt_remove_tree(utt);
+       utts->err = ret;
+       return NULL;
+}
+
+int utt_trace_startstop(struct utt_trace *utt, int start,
+                       unsigned int *trace_seq)
+{
+       int ret;
+
+       /*
+        * For starting a trace, we can transition from a setup or stopped
+        * trace. For stopping a trace, the state must be running
+        */
+       ret = -EINVAL;
+       if (start) {
+               if (utt->trace_state == Utt_trace_setup ||
+                   utt->trace_state == Utt_trace_stopped) {
+                       if (trace_seq)
+                               (*trace_seq)++;
+                       smp_mb();
+                       utt->trace_state = Utt_trace_running;
+                       ret = 0;
+               }
+       } else {
+               if (utt->trace_state == Utt_trace_running) {
+                       utt->trace_state = Utt_trace_stopped;
+                       relay_flush(utt->rchan);
+                       ret = 0;
+               }
+       }
+
+       return ret;
+}
diff --git a/runtime/transport/utt.h b/runtime/transport/utt.h
new file mode 100644 (file)
index 0000000..f6eba64
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef UTT_H
+#define UTT_H
+
+enum {
+       Utt_trace_setup = 1,
+       Utt_trace_running,
+       Utt_trace_stopped,
+};
+
+struct utt_trace {
+       int trace_state;
+       struct rchan *rchan;
+       unsigned long *sequence;
+       struct dentry *dropped_file;
+       atomic_t dropped;
+       struct dentry *utt_tree_root;
+       void *private_data;
+};
+
+#define UTT_TRACE_ROOT_NAME_SIZE       32      /* Largest string for a root dir identifier */
+#define UTT_TRACE_NAME_SIZE            32      /* Largest string for a trace identifier */
+
+/*
+ * User setup structure
+ */
+struct utt_trace_setup {
+       char root[UTT_TRACE_ROOT_NAME_SIZE];    /* input */
+       char name[UTT_TRACE_NAME_SIZE];         /* input */
+       u32 buf_size;                           /* input */
+       u32 buf_nr;                             /* input */
+       int is_global;                          /* input */
+       int err;                                /* output */
+};
+
+
+extern struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts);
+extern int utt_trace_startstop(struct utt_trace *utt, int start,
+                              unsigned int *trace_seq);
+extern void utt_trace_cleanup(struct utt_trace *utt);
+extern int utt_trace_remove(struct utt_trace *utt);
+
+#endif
This page took 0.079269 seconds and 5 git commands to generate.