From fbbb89fffb3533a3b4fb63c15eaeaae6956391eb Mon Sep 17 00:00:00 2001 From: hunt Date: Wed, 14 Mar 2007 16:12:40 +0000 Subject: [PATCH] 2007-03-14 Martin Hunt * 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 | 16 ++ runtime/transport/control.c | 275 ++++++++++++++++++++++++ runtime/transport/procfs.c | 134 ++++++------ runtime/transport/relayfs.c | 284 ++++++++----------------- runtime/transport/symbols.c | 18 +- runtime/transport/transport.c | 331 ++++++++++------------------- runtime/transport/transport.h | 12 +- runtime/transport/transport_msgs.h | 93 ++++---- runtime/transport/utt.c | 253 ++++++++++++++++++++++ runtime/transport/utt.h | 42 ++++ 10 files changed, 915 insertions(+), 543 deletions(-) create mode 100644 runtime/transport/control.c create mode 100644 runtime/transport/utt.c create mode 100644 runtime/transport/utt.h diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index 54bde5d2c..f9dca7f2f 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,3 +1,19 @@ +2007-03-14 Martin Hunt + + * 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 * 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 index 000000000..3ad3e3097 --- /dev/null +++ b/runtime/transport/control.c @@ -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); + } +} + diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c index 64538ae6a..bb97c4119 100644 --- a/runtime/transport/procfs.c +++ b/runtime/transport/procfs.c @@ -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) { diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index 1b616b7ef..ccbdc63e5 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -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 +#include +#include +#include +#include +#include +#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; +} diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index c21c0ede5..abe60226c 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -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; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index de0e8c2da..59402f6f1 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -19,31 +19,37 @@ #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_ */ diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index da5737347..2d77414cb 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -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); diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index f43627f10..be1a29148 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -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 index 000000000..b23260d7d --- /dev/null +++ b/runtime/transport/utt.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include +#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 index 000000000..f6eba64b8 --- /dev/null +++ b/runtime/transport/utt.h @@ -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 -- 2.43.5