From 4a8c28f93fa29e47c604e80e383c826070d6c383 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 6 May 2009 12:25:02 -0500 Subject: Start of support for older transport and cleanup. * runtime/transport/control.c: Added inclusion of linux/delay.h to get declaration of msleep(). * runtime/transport/relay_v2.c: New skeleton file for transport version 2. * runtime/transport/ring_buffer.c: Cleanup. * runtime/transport/transport.c: Ditto. --- runtime/transport/relay_v2.c | 550 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 550 insertions(+) create mode 100644 runtime/transport/relay_v2.c (limited to 'runtime/transport/relay_v2.c') diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c new file mode 100644 index 00000000..771a3a3c --- /dev/null +++ b/runtime/transport/relay_v2.c @@ -0,0 +1,550 @@ +#include +#include +#include +#include +#if 0 +#include +#include +#include +#include + +static struct ring_buffer *__stp_ring_buffer = NULL; +//DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); + +/* _stp_poll_wait is a waitqueue for tasks blocked on + * _stp_data_poll_trace() */ +static DECLARE_WAIT_QUEUE_HEAD(_stp_poll_wait); + +#if 1 +/* + * Trace iterator - used by printout routines who present trace + * results to users and which routines might sleep, etc: + */ +struct _stp_ring_buffer_iterator { +#if 0 + struct trace_array *tr; + struct tracer *trace; + void *private; + struct ring_buffer_iter *buffer_iter[NR_CPUS]; + + /* The below is zeroed out in pipe_read */ + struct trace_seq seq; + struct trace_entry *ent; +#endif + int cpu; + u64 ts; + +#if 0 + unsigned long iter_flags; + loff_t pos; + long idx; + + cpumask_var_t started; +#endif +}; +static struct _stp_ring_buffer_iterator _stp_iter; +#endif + +static cpumask_var_t _stp_trace_reader_cpumask; + +static void __stp_free_ring_buffer(void) +{ + free_cpumask_var(_stp_trace_reader_cpumask); + if (__stp_ring_buffer) + ring_buffer_free(__stp_ring_buffer); + __stp_ring_buffer = NULL; +} + +static int __stp_alloc_ring_buffer(void) +{ + int i; + unsigned long buffer_size = _stp_bufsize; + + if (!alloc_cpumask_var(&_stp_trace_reader_cpumask, GFP_KERNEL)) + goto fail; + cpumask_clear(_stp_trace_reader_cpumask); + + if (buffer_size == 0) { + dbug_trans(1, "using default buffer size...\n"); + buffer_size = _stp_nsubbufs * _stp_subbuf_size; + } + /* The number passed to ring_buffer_alloc() is per cpu. Our + * 'buffer_size' is a total number of bytes to allocate. So, + * we need to divide buffer_size by the number of cpus. */ + buffer_size /= num_online_cpus(); + dbug_trans(1, "%lu\n", buffer_size); + __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); + if (!__stp_ring_buffer) + goto fail; + + dbug_trans(1, "size = %lu\n", ring_buffer_size(__stp_ring_buffer)); + return 0; + +fail: + __stp_free_ring_buffer(); + return -ENOMEM; +} + +static int _stp_data_open_trace(struct inode *inode, struct file *file) +{ + long cpu_file = (long) inode->i_private; + + /* We only allow for one reader per cpu */ + dbug_trans(1, "trace attach\n"); +#ifdef STP_BULKMODE + if (!cpumask_test_cpu(cpu_file, _stp_trace_reader_cpumask)) + cpumask_set_cpu(cpu_file, _stp_trace_reader_cpumask); + else { + dbug_trans(1, "returning EBUSY\n"); + return -EBUSY; + } +#else + if (!cpumask_empty(_stp_trace_reader_cpumask)) { + dbug_trans(1, "returning EBUSY\n"); + return -EBUSY; + } + cpumask_setall(_stp_trace_reader_cpumask); +#endif + file->private_data = inode->i_private; + return 0; +} + +static int _stp_data_release_trace(struct inode *inode, struct file *file) +{ + long cpu_file = (long) inode->i_private; + dbug_trans(1, "trace detach\n"); +#ifdef STP_BULKMODE + cpumask_clear_cpu(cpu_file, _stp_trace_reader_cpumask); +#else + cpumask_clear(_stp_trace_reader_cpumask); +#endif + + return 0; +} + +size_t +_stp_entry_to_user(struct _stp_entry *entry, char __user *ubuf, size_t cnt) +{ + int ret; + + dbug_trans(1, "entry(%p), ubuf(%p), cnt(%lu)\n", entry, ubuf, cnt); + if (entry == NULL || ubuf == NULL) + return -EFAULT; + + /* We don't do partial entries - just fail. */ + if (entry->len > cnt) + return -EBUSY; + + if (cnt > entry->len) + cnt = entry->len; + ret = copy_to_user(ubuf, entry->buf, cnt); + if (ret) + return -EFAULT; + + return cnt; +} + +static ssize_t tracing_wait_pipe(struct file *filp) +{ + while (ring_buffer_empty(__stp_ring_buffer)) { + + if ((filp->f_flags & O_NONBLOCK)) { + dbug_trans(1, "returning -EAGAIN\n"); + return -EAGAIN; + } + + /* + * This is a make-shift waitqueue. The reason we don't use + * an actual wait queue is because: + * 1) we only ever have one waiter + * 2) the tracing, traces all functions, we don't want + * the overhead of calling wake_up and friends + * (and tracing them too) + * Anyway, this is really very primitive wakeup. + */ + set_current_state(TASK_INTERRUPTIBLE); + //iter->tr->waiter = current; + + /* sleep for 100 msecs, and try again. */ + schedule_timeout(HZ/10); + + //iter->tr->waiter = NULL; + + if (signal_pending(current)) { + dbug_trans(1, "returning -EINTR\n"); + return -EINTR; + } + } + + dbug_trans(1, "returning 1\n"); + return 1; +} + +static struct _stp_entry * +peek_next_entry(int cpu, u64 *ts) +{ + struct ring_buffer_event *event; + + event = ring_buffer_peek(__stp_ring_buffer, cpu, ts); + + return event ? ring_buffer_event_data(event) : NULL; +} + +static struct _stp_entry * +__stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) +{ + struct _stp_entry *ent; + +#ifdef STP_BULKMODE + /* + * If we are in a per_cpu trace file, don't bother by iterating over + * all cpus and peek directly. + */ + if (ring_buffer_empty_cpu(__stp_ring_buffer, (int)cpu_file)) + return NULL; + ent = peek_next_entry(cpu_file, ent_ts); + if (ent_cpu) + *ent_cpu = cpu_file; + + return ent; +#else + struct _stp_entry *next = NULL; + u64 next_ts = 0, ts; + int next_cpu = -1; + int cpu; + + for_each_possible_cpu(cpu) { + + if (ring_buffer_empty_cpu(__stp_ring_buffer, cpu)) + continue; + + ent = peek_next_entry(cpu, &ts); + + /* + * Pick the entry with the smallest timestamp: + */ + if (ent && (!next || ts < next_ts)) { + next = ent; + next_cpu = cpu; + next_ts = ts; + } + } + + if (ent_cpu) + *ent_cpu = next_cpu; + + if (ent_ts) + *ent_ts = next_ts; + + return next; +#endif +} + +/* Find the next real entry, and increment the iterator to the next entry */ +static struct _stp_entry *_stp_find_next_entry(long cpu_file) +{ + return __stp_find_next_entry(cpu_file, &_stp_iter.cpu, &_stp_iter.ts); +} + + +/* + * Consumer reader. + */ +static ssize_t +_stp_data_read_trace(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + ssize_t sret; + struct _stp_entry *entry; + long cpu_file = (long) filp->private_data; + + dbug_trans(1, "%lu\n", (unsigned long)cnt); + + sret = tracing_wait_pipe(filp); + dbug_trans(1, "tracing_wait_pipe returned %ld\n", sret); + if (sret <= 0) + goto out; + + /* stop when tracing is finished */ + if (ring_buffer_empty(__stp_ring_buffer)) { + sret = 0; + goto out; + } + + if (cnt >= PAGE_SIZE) + cnt = PAGE_SIZE - 1; + + dbug_trans(1, "sret = %lu\n", (unsigned long)sret); + sret = 0; + while ((entry = _stp_find_next_entry(cpu_file)) != NULL) { + ssize_t len; + + len = _stp_entry_to_user(entry, ubuf, cnt); + if (len <= 0) + break; + + ring_buffer_consume(__stp_ring_buffer, _stp_iter.cpu, + &_stp_iter.ts); + ubuf += len; + cnt -= len; + sret += len; + if (cnt <= 0) + break; + } +out: + return sret; +} + + +static unsigned int +_stp_data_poll_trace(struct file *filp, poll_table *poll_table) +{ + dbug_trans(1, "entry\n"); + if (! ring_buffer_empty(__stp_ring_buffer)) + return POLLIN | POLLRDNORM; + poll_wait(filp, &_stp_poll_wait, poll_table); + if (! ring_buffer_empty(__stp_ring_buffer)) + return POLLIN | POLLRDNORM; + + dbug_trans(1, "exit\n"); + return 0; +} + +static struct file_operations __stp_data_fops = { + .owner = THIS_MODULE, + .open = _stp_data_open_trace, + .release = _stp_data_release_trace, + .poll = _stp_data_poll_trace, + .read = _stp_data_read_trace, +#if 0 + .splice_read = tracing_splice_read_pipe, +#endif +}; + +/* Here's how __STP_MAX_RESERVE_SIZE is figured. The value of + * BUF_PAGE_SIZE was gotten from the kernel's ring_buffer code. It + * is divided by 4, so we waste a maximum of 1/4 of the buffer (in + * the case of a small reservation). We then subtract the sizes of + * structures needed for every reservation. */ +#define __STP_MAX_RESERVE_SIZE ((/*BUF_PAGE_SIZE*/ 4080 / 4) \ + - sizeof(struct _stp_entry) \ + - sizeof(struct ring_buffer_event)) + +/* + * This function prepares the cpu buffer to write a sample. + * + * Struct op_entry is used during operations on the ring buffer while + * struct op_sample contains the data that is stored in the ring + * buffer. Struct entry can be uninitialized. The function reserves a + * data array that is specified by size. Use + * op_cpu_buffer_write_commit() after preparing the sample. In case of + * errors a null pointer is returned, otherwise the pointer to the + * sample. + * + */ +static size_t +_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) +{ + struct ring_buffer_event *event; + + if (entry == NULL) + return -EINVAL; + + if (size_request > __STP_MAX_RESERVE_SIZE) { + size_request = __STP_MAX_RESERVE_SIZE; + } + + event = ring_buffer_lock_reserve(__stp_ring_buffer, + (sizeof(struct _stp_entry) + size_request), + 0); + if (unlikely(! event)) { + dbug_trans(1, "event = NULL (%p)?\n", event); + entry = NULL; + return 0; + } + + *entry = ring_buffer_event_data(event); + (*entry)->event = event; + (*entry)->len = size_request; + return size_request; +} +#endif + +static int _stp_data_write_commit(struct _stp_entry *entry) +{ +#if 0 + int ret; + + if (unlikely(! entry)) { + dbug_trans(1, "entry = NULL, returning -EINVAL\n"); + return -EINVAL; + } + + ret = ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); + dbug_trans(1, "after commit, empty returns %d\n", + ring_buffer_empty(__stp_ring_buffer)); + + wake_up_interruptible(&_stp_poll_wait); + return ret; +#else + return 0; +#endif +} + + +#if 0 +static struct dentry *__stp_entry[NR_CPUS] = { NULL }; +#endif + + + +struct _stp_relay_data { + struct rchan *rchan; + int overwrite_flag; +}; +static struct _stp_relay_data _stp_relay; + + + +static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, + size_t length); +/** + * utt_reserve - reserve slot in channel buffer + * @utt: utt channel + * @length: number of bytes to reserve + * + * Returns pointer to reserved slot, NULL if full. + * + * This function is utt_switch_subbuf version of relay_reserve. + */ +static size_t +_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) +{ +#if 0 + void *reserved; + struct rchan_buf *buf = utt->rchan->buf[smp_processor_id()]; + + if (unlikely(buf->offset + length > buf->chan->subbuf_size)) { + length = utt_switch_subbuf(utt, buf, length); + if (!length) + return NULL; + } + reserved = (char*)buf->data + buf->offset; + buf->offset += length; + + return reserved; +#else + return 0; +#endif +} + + + + +static int +_stp_relay_subbuf_start_callback(struct rchan_buf *buf, void *subbuf, + void *prev_subbuf, size_t prev_padding) +{ + if (_stp_relay.overwrite_flag || !relay_buf_full(buf)) + return 1; + + return 0; +} + +static struct dentry * +_stp_relay_create_buf_file_callback(const char *filename, + struct dentry *parent, + int mode, + struct rchan_buf *buf, + int *is_global) +{ + struct dentry *file; + + if (is_global) { +#ifdef STP_BULKMODE + *is_global = 0; +#else + *is_global = 1; +#endif + } + + file = debugfs_create_file(filename, mode, parent, buf, + &relay_file_operations); + if (file) { + file->d_inode->i_uid = _stp_uid; + file->d_inode->i_gid = _stp_gid; + } + return file; +} + +static int +_stp_relay_remove_buf_file_callback(struct dentry *dentry) +{ + debugfs_remove(dentry); + return 0; +} + +static struct rchan_callbacks _stp_relay_callbacks = { + .subbuf_start = _stp_relay_subbuf_start_callback, + .create_buf_file = _stp_relay_create_buf_file_callback, + .remove_buf_file = _stp_relay_remove_buf_file_callback, +}; + +static int _stp_transport_data_fs_init(void) +{ + int rc; + u64 npages; + struct sysinfo si; + + _stp_relay.overwrite_flag = 0; + + npages = _stp_subbuf_size * _stp_nsubbufs; +#ifdef STP_BULKMODE + npages *= num_possible_cpus(); +#endif + npages >>= PAGE_SHIFT; + si_meminfo(&si); +#define MB(i) (unsigned long)((i) >> (20 - PAGE_SHIFT)) + if (npages > (si.freeram + si.bufferram)) { + errk("Not enough free+buffered memory(%luMB) for log buffer(%luMB)\n", + MB(si.freeram + si.bufferram), + MB(npages)); + rc = -ENOMEM; + goto err; + } + else if (npages > si.freeram) { + /* exceeds freeram, but below freeram+bufferram */ + printk(KERN_WARNING + "log buffer size exceeds free memory(%luMB)\n", + MB(si.freeram)); + } + +#if (RELAYFS_CHANNEL_VERSION >= 7) + _stp_relay.rchan = relay_open("trace", _stp_get_module_dir(), + _stp_subbuf_size, _stp_nsubbufs, + &_stp_relay_callbacks, NULL); +#else /* (RELAYFS_CHANNEL_VERSION < 7) */ + _stp_relay.rchan = relay_open("trace", _stp_get_module_dir(), + _stp_subbuf_size, _stp_nsubbufs, + &_stp_relay_callbacks); +#endif /* (RELAYFS_CHANNEL_VERSION < 7) */ + + if (!_stp_relay.rchan) { + rc = -ENOENT; + goto err; + } + dbug_trans(1, "returning 0...\n"); + return 0; + +err: + if (_stp_relay.rchan) + relay_close(_stp_relay.rchan); + return rc; +} + +static void _stp_transport_data_fs_close(void) +{ + if (_stp_relay.rchan) + relay_close(_stp_relay.rchan); +} + -- cgit From b47be87f5bcab55ed08cbfb07f0a39447f3f81ed Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 8 May 2009 15:00:06 -0500 Subject: Working transport version 2 (RHEL5 and recent fedora kernels). * runtime/transport/relay_v2.c: Morphed utt.c into relay_v2.c. Actually works. --- runtime/transport/relay_v2.c | 790 ++++++++++++++++++++----------------------- 1 file changed, 376 insertions(+), 414 deletions(-) (limited to 'runtime/transport/relay_v2.c') diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index 771a3a3c..ea4d9241 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -1,503 +1,427 @@ -#include +/* -*- 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 -#if 0 -#include -#include -#include -#include - -static struct ring_buffer *__stp_ring_buffer = NULL; -//DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); - -/* _stp_poll_wait is a waitqueue for tasks blocked on - * _stp_data_poll_trace() */ -static DECLARE_WAIT_QUEUE_HEAD(_stp_poll_wait); +#include +#include +#include -#if 1 -/* - * Trace iterator - used by printout routines who present trace - * results to users and which routines might sleep, etc: - */ -struct _stp_ring_buffer_iterator { -#if 0 - struct trace_array *tr; - struct tracer *trace; - void *private; - struct ring_buffer_iter *buffer_iter[NR_CPUS]; - - /* The below is zeroed out in pipe_read */ - struct trace_seq seq; - struct trace_entry *ent; +#ifndef STP_RELAY_TIMER_INTERVAL +/* Wakeup timer interval in jiffies (default 10 ms) */ +#define STP_RELAY_TIMER_INTERVAL ((HZ + 99) / 100) #endif - int cpu; - u64 ts; - -#if 0 - unsigned long iter_flags; - loff_t pos; - long idx; - cpumask_var_t started; -#endif +enum _stp_transport_state { + STP_TRANSPORT_STOPPED, + STP_TRANSPORT_INITIALIZED, + STP_TRANSPORT_RUNNING, }; -static struct _stp_ring_buffer_iterator _stp_iter; -#endif -static cpumask_var_t _stp_trace_reader_cpumask; +struct _stp_relay_data_type { + enum _stp_transport_state transport_state; + struct rchan *rchan; + struct dentry *dir; /* systemtap/module_name */ + struct dentry *dropped_file; + atomic_t dropped; + struct dentry *utt_tree_root; /* systemtap */ + atomic_t wakeup; + struct timer_list timer; + int overwrite_flag; +}; +struct _stp_relay_data_type _stp_relay_data; -static void __stp_free_ring_buffer(void) +/* + * __stp_relay_switch_subbuf - switch to a new sub-buffer + * + * Most of this function is deadcopy of relay_switch_subbuf. + */ +static size_t __stp_relay_switch_subbuf(struct rchan_buf *buf, size_t length) { - free_cpumask_var(_stp_trace_reader_cpumask); - if (__stp_ring_buffer) - ring_buffer_free(__stp_ring_buffer); - __stp_ring_buffer = NULL; -} + char *old, *new; + size_t old_subbuf, new_subbuf; -static int __stp_alloc_ring_buffer(void) -{ - int i; - unsigned long buffer_size = _stp_bufsize; + if (unlikely(buf == NULL)) + return 0; - if (!alloc_cpumask_var(&_stp_trace_reader_cpumask, GFP_KERNEL)) - goto fail; - cpumask_clear(_stp_trace_reader_cpumask); + if (unlikely(length > buf->chan->subbuf_size)) + goto toobig; + + if (buf->offset != buf->chan->subbuf_size + 1) { + buf->prev_padding = buf->chan->subbuf_size - buf->offset; + old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; + buf->padding[old_subbuf] = buf->prev_padding; + buf->subbufs_produced++; + buf->dentry->d_inode->i_size += buf->chan->subbuf_size - + buf->padding[old_subbuf]; + smp_mb(); + if (waitqueue_active(&buf->read_wait)) + /* + * Calling wake_up_interruptible() and __mod_timer() + * from here will deadlock if we happen to be logging + * from the scheduler and timer (trying to re-grab + * rq->lock/timer->base->lock), so just set a flag. + */ + atomic_set(&_stp_relay_data.wakeup, 1); + } - if (buffer_size == 0) { - dbug_trans(1, "using default buffer size...\n"); - buffer_size = _stp_nsubbufs * _stp_subbuf_size; + old = buf->data; + new_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; + new = (char*)buf->start + new_subbuf * buf->chan->subbuf_size; + buf->offset = 0; + if (!buf->chan->cb->subbuf_start(buf, new, old, buf->prev_padding)) { + buf->offset = buf->chan->subbuf_size + 1; + return 0; } - /* The number passed to ring_buffer_alloc() is per cpu. Our - * 'buffer_size' is a total number of bytes to allocate. So, - * we need to divide buffer_size by the number of cpus. */ - buffer_size /= num_online_cpus(); - dbug_trans(1, "%lu\n", buffer_size); - __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); - if (!__stp_ring_buffer) - goto fail; - - dbug_trans(1, "size = %lu\n", ring_buffer_size(__stp_ring_buffer)); - return 0; + buf->data = new; + buf->padding[new_subbuf] = 0; + + if (unlikely(length + buf->offset > buf->chan->subbuf_size)) + goto toobig; + + return length; -fail: - __stp_free_ring_buffer(); - return -ENOMEM; +toobig: + buf->chan->last_toobig = length; + return 0; } -static int _stp_data_open_trace(struct inode *inode, struct file *file) +static void __stp_relay_wakeup_readers(struct rchan_buf *buf) { - long cpu_file = (long) inode->i_private; + if (buf && waitqueue_active(&buf->read_wait) && + buf->subbufs_produced != buf->subbufs_consumed) + wake_up_interruptible(&buf->read_wait); +} - /* We only allow for one reader per cpu */ - dbug_trans(1, "trace attach\n"); +static void __stp_relay_wakeup_timer(unsigned long val) +{ #ifdef STP_BULKMODE - if (!cpumask_test_cpu(cpu_file, _stp_trace_reader_cpumask)) - cpumask_set_cpu(cpu_file, _stp_trace_reader_cpumask); - else { - dbug_trans(1, "returning EBUSY\n"); - return -EBUSY; - } -#else - if (!cpumask_empty(_stp_trace_reader_cpumask)) { - dbug_trans(1, "returning EBUSY\n"); - return -EBUSY; - } - cpumask_setall(_stp_trace_reader_cpumask); + int i; #endif - file->private_data = inode->i_private; - return 0; -} -static int _stp_data_release_trace(struct inode *inode, struct file *file) -{ - long cpu_file = (long) inode->i_private; - dbug_trans(1, "trace detach\n"); + if (atomic_read(&_stp_relay_data.wakeup)) { + atomic_set(&_stp_relay_data.wakeup, 0); #ifdef STP_BULKMODE - cpumask_clear_cpu(cpu_file, _stp_trace_reader_cpumask); + for_each_possible_cpu(i) + __stp_relay_wakeup_readers(_stp_relay_data.rchan->buf[i]); #else - cpumask_clear(_stp_trace_reader_cpumask); + __stp_relay_wakeup_readers(_stp_relay_data.rchan->buf[0]); #endif + } - return 0; + mod_timer(&_stp_relay_data.timer, jiffies + STP_RELAY_TIMER_INTERVAL); } -size_t -_stp_entry_to_user(struct _stp_entry *entry, char __user *ubuf, size_t cnt) +static void __stp_relay_timer_init(void) { - int ret; - - dbug_trans(1, "entry(%p), ubuf(%p), cnt(%lu)\n", entry, ubuf, cnt); - if (entry == NULL || ubuf == NULL) - return -EFAULT; - - /* We don't do partial entries - just fail. */ - if (entry->len > cnt) - return -EBUSY; - - if (cnt > entry->len) - cnt = entry->len; - ret = copy_to_user(ubuf, entry->buf, cnt); - if (ret) - return -EFAULT; - - return cnt; + atomic_set(&_stp_relay_data.wakeup, 0); + init_timer(&_stp_relay_data.timer); + _stp_relay_data.timer.expires = jiffies + STP_RELAY_TIMER_INTERVAL; + _stp_relay_data.timer.function = __stp_relay_wakeup_timer; + _stp_relay_data.timer.data = 0; + add_timer(&_stp_relay_data.timer); + smp_mb(); } -static ssize_t tracing_wait_pipe(struct file *filp) +static void stp_relay_set_overwrite(int overwrite) { - while (ring_buffer_empty(__stp_ring_buffer)) { - - if ((filp->f_flags & O_NONBLOCK)) { - dbug_trans(1, "returning -EAGAIN\n"); - return -EAGAIN; - } + _stp_relay_data.overwrite_flag = overwrite; +} - /* - * This is a make-shift waitqueue. The reason we don't use - * an actual wait queue is because: - * 1) we only ever have one waiter - * 2) the tracing, traces all functions, we don't want - * the overhead of calling wake_up and friends - * (and tracing them too) - * Anyway, this is really very primitive wakeup. - */ - set_current_state(TASK_INTERRUPTIBLE); - //iter->tr->waiter = current; - - /* sleep for 100 msecs, and try again. */ - schedule_timeout(HZ/10); - - //iter->tr->waiter = NULL; - - if (signal_pending(current)) { - dbug_trans(1, "returning -EINTR\n"); - return -EINTR; +static void __stp_relay_remove_root(void) +{ + if (_stp_relay_data.utt_tree_root) { + if (!_stp_lock_transport_dir()) { + errk("Unable to lock transport directory.\n"); + return; } + if (simple_empty(_stp_relay_data.utt_tree_root)) + debugfs_remove(_stp_relay_data.utt_tree_root); + _stp_unlock_transport_dir(); + _stp_relay_data.utt_tree_root = NULL; } - - dbug_trans(1, "returning 1\n"); - return 1; } -static struct _stp_entry * -peek_next_entry(int cpu, u64 *ts) +static void __stp_relay_remove_tree(void) { - struct ring_buffer_event *event; - - event = ring_buffer_peek(__stp_ring_buffer, cpu, ts); - - return event ? ring_buffer_event_data(event) : NULL; + if (_stp_relay_data.dir == NULL) + return; + debugfs_remove(_stp_relay_data.dir); + __stp_relay_remove_root(); } -static struct _stp_entry * -__stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) +static struct dentry *__stp_relay_create_tree(const char *root, + const char *name) { - struct _stp_entry *ent; + struct dentry *dir = NULL; -#ifdef STP_BULKMODE - /* - * If we are in a per_cpu trace file, don't bother by iterating over - * all cpus and peek directly. - */ - if (ring_buffer_empty_cpu(__stp_ring_buffer, (int)cpu_file)) - return NULL; - ent = peek_next_entry(cpu_file, ent_ts); - if (ent_cpu) - *ent_cpu = cpu_file; - - return ent; -#else - struct _stp_entry *next = NULL; - u64 next_ts = 0, ts; - int next_cpu = -1; - int cpu; - - for_each_possible_cpu(cpu) { - - if (ring_buffer_empty_cpu(__stp_ring_buffer, cpu)) - continue; + if (root == NULL || name == NULL) + return NULL; - ent = peek_next_entry(cpu, &ts); + if (!_stp_relay_data.utt_tree_root) { + _stp_relay_data.utt_tree_root = _stp_get_root_dir(); + if (!_stp_relay_data.utt_tree_root) + goto err; + } - /* - * Pick the entry with the smallest timestamp: - */ - if (ent && (!next || ts < next_ts)) { - next = ent; - next_cpu = cpu; - next_ts = ts; - } - } - - if (ent_cpu) - *ent_cpu = next_cpu; - - if (ent_ts) - *ent_ts = next_ts; - - return next; -#endif + dir = debugfs_create_dir(name, _stp_relay_data.utt_tree_root); + if (!dir) + __stp_relay_remove_root(); +err: + return dir; } -/* Find the next real entry, and increment the iterator to the next entry */ -static struct _stp_entry *_stp_find_next_entry(long cpu_file) +static void __stp_relay_cleanup(void) { - return __stp_find_next_entry(cpu_file, &_stp_iter.cpu, &_stp_iter.ts); + if (_stp_relay_data.rchan) + relay_close(_stp_relay_data.rchan); + if (_stp_relay_data.dropped_file) + debugfs_remove(_stp_relay_data.dropped_file); + __stp_relay_remove_tree(); } - -/* - * Consumer reader. - */ -static ssize_t -_stp_data_read_trace(struct file *filp, char __user *ubuf, - size_t cnt, loff_t *ppos) +static int _stp_relay_remove(void) { - ssize_t sret; - struct _stp_entry *entry; - long cpu_file = (long) filp->private_data; - - dbug_trans(1, "%lu\n", (unsigned long)cnt); - - sret = tracing_wait_pipe(filp); - dbug_trans(1, "tracing_wait_pipe returned %ld\n", sret); - if (sret <= 0) - goto out; - - /* stop when tracing is finished */ - if (ring_buffer_empty(__stp_ring_buffer)) { - sret = 0; - goto out; - } + if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED || + _stp_relay_data.transport_state == STP_TRANSPORT_STOPPED) + __stp_relay_cleanup(); - if (cnt >= PAGE_SIZE) - cnt = PAGE_SIZE - 1; - - dbug_trans(1, "sret = %lu\n", (unsigned long)sret); - sret = 0; - while ((entry = _stp_find_next_entry(cpu_file)) != NULL) { - ssize_t len; - - len = _stp_entry_to_user(entry, ubuf, cnt); - if (len <= 0) - break; - - ring_buffer_consume(__stp_ring_buffer, _stp_iter.cpu, - &_stp_iter.ts); - ubuf += len; - cnt -= len; - sret += len; - if (cnt <= 0) - break; - } -out: - return sret; + return 0; } - -static unsigned int -_stp_data_poll_trace(struct file *filp, poll_table *poll_table) +static int __stp_relay_dropped_open(struct inode *inode, struct file *filp) { - dbug_trans(1, "entry\n"); - if (! ring_buffer_empty(__stp_ring_buffer)) - return POLLIN | POLLRDNORM; - poll_wait(filp, &_stp_poll_wait, poll_table); - if (! ring_buffer_empty(__stp_ring_buffer)) - return POLLIN | POLLRDNORM; - - dbug_trans(1, "exit\n"); return 0; } -static struct file_operations __stp_data_fops = { - .owner = THIS_MODULE, - .open = _stp_data_open_trace, - .release = _stp_data_release_trace, - .poll = _stp_data_poll_trace, - .read = _stp_data_read_trace, -#if 0 - .splice_read = tracing_splice_read_pipe, -#endif -}; +static ssize_t __stp_relay_dropped_read(struct file *filp, char __user *buffer, + size_t count, loff_t *ppos) +{ + char buf[16]; -/* Here's how __STP_MAX_RESERVE_SIZE is figured. The value of - * BUF_PAGE_SIZE was gotten from the kernel's ring_buffer code. It - * is divided by 4, so we waste a maximum of 1/4 of the buffer (in - * the case of a small reservation). We then subtract the sizes of - * structures needed for every reservation. */ -#define __STP_MAX_RESERVE_SIZE ((/*BUF_PAGE_SIZE*/ 4080 / 4) \ - - sizeof(struct _stp_entry) \ - - sizeof(struct ring_buffer_event)) + snprintf(buf, sizeof(buf), "%u\n", + atomic_read(&_stp_relay_data.dropped)); + + return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); +} + +static struct file_operations __stp_relay_dropped_fops = { + .owner = THIS_MODULE, + .open = __stp_relay_dropped_open, + .read = __stp_relay_dropped_read, +}; /* - * This function prepares the cpu buffer to write a sample. - * - * Struct op_entry is used during operations on the ring buffer while - * struct op_sample contains the data that is stored in the ring - * buffer. Struct entry can be uninitialized. The function reserves a - * data array that is specified by size. Use - * op_cpu_buffer_write_commit() after preparing the sample. In case of - * errors a null pointer is returned, otherwise the pointer to the - * sample. - * + * 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 size_t -_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) +static int __stp_relay_subbuf_start_callback(struct rchan_buf *buf, + void *subbuf, void *prev_subbuf, + size_t prev_padding) { - struct ring_buffer_event *event; - - if (entry == NULL) - return -EINVAL; - - if (size_request > __STP_MAX_RESERVE_SIZE) { - size_request = __STP_MAX_RESERVE_SIZE; - } - - event = ring_buffer_lock_reserve(__stp_ring_buffer, - (sizeof(struct _stp_entry) + size_request), - 0); - if (unlikely(! event)) { - dbug_trans(1, "event = NULL (%p)?\n", event); - entry = NULL; - return 0; - } + if (_stp_relay_data.overwrite_flag || !relay_buf_full(buf)) + return 1; - *entry = ring_buffer_event_data(event); - (*entry)->event = event; - (*entry)->len = size_request; - return size_request; + atomic_inc(&_stp_relay_data.dropped); + return 0; } -#endif -static int _stp_data_write_commit(struct _stp_entry *entry) +static int __stp_relay_remove_buf_file_callback(struct dentry *dentry) { -#if 0 - int ret; + debugfs_remove(dentry); + return 0; +} - if (unlikely(! entry)) { - dbug_trans(1, "entry = NULL, returning -EINVAL\n"); - return -EINVAL; +static struct dentry * +__stp_relay_create_buf_file_callback(const char *filename, + struct dentry *parent, + int mode, + struct rchan_buf *buf, + int *is_global) +{ + struct dentry *file = debugfs_create_file(filename, mode, parent, buf, + &relay_file_operations); + if (file) { + file->d_inode->i_uid = _stp_uid; + file->d_inode->i_gid = _stp_gid; } - - ret = ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); - dbug_trans(1, "after commit, empty returns %d\n", - ring_buffer_empty(__stp_ring_buffer)); - - wake_up_interruptible(&_stp_poll_wait); - return ret; -#else - return 0; -#endif + return file; } +static struct rchan_callbacks __stp_relay_callbacks = { + .subbuf_start = __stp_relay_subbuf_start_callback, + .create_buf_file = __stp_relay_create_buf_file_callback, + .remove_buf_file = __stp_relay_remove_buf_file_callback, +}; #if 0 -static struct dentry *__stp_entry[NR_CPUS] = { NULL }; -#endif - - - -struct _stp_relay_data { - struct rchan *rchan; - int overwrite_flag; -}; -static struct _stp_relay_data _stp_relay; +/* + * Setup everything required to start tracing + */ +static struct _stp_relay_data_type *utt_trace_setup(struct utt_trace_setup *utts) +{ + struct dentry *dir = NULL; + int ret = -EINVAL; + u64 npages; + struct sysinfo si; + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + _stp_relay_data.overwrite_flag = 0; + if (!utts->buf_size || !utts->buf_nr) + goto err; -static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, - size_t length); -/** - * utt_reserve - reserve slot in channel buffer - * @utt: utt channel - * @length: number of bytes to reserve - * - * Returns pointer to reserved slot, NULL if full. - * - * This function is utt_switch_subbuf version of relay_reserve. - */ -static size_t -_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) -{ -#if 0 - void *reserved; - struct rchan_buf *buf = utt->rchan->buf[smp_processor_id()]; + ret = -ENOENT; + dir = __stp_relay_create_tree(utts->root, utts->name); + if (!dir) + goto err; + _stp_relay_data.dir = dir; + atomic_set(&_stp_relay_data.dropped, 0); + + ret = -EIO; + _stp_relay_data.dropped_file = debugfs_create_file("dropped", 0444, + dir, NULL, + &__stp_relay_dropped_fops); + if (!_stp_relay_data.dropped_file) + goto err; - if (unlikely(buf->offset + length > buf->chan->subbuf_size)) { - length = utt_switch_subbuf(utt, buf, length); - if (!length) - return NULL; + npages = utts->buf_size * utts->buf_nr; +#ifndef STP_BULKMODE + npages *= num_possible_cpus(); +#endif + npages >>= PAGE_SHIFT; + si_meminfo(&si); +#define MB(i) (unsigned long)((i) >> (20 - PAGE_SHIFT)) + if (npages > (si.freeram + si.bufferram)) { + errk("Not enough free+buffered memory(%luMB) for log buffer(%luMB)\n", + MB(si.freeram + si.bufferram), + MB(npages)); + ret = -ENOMEM; + goto err; + } else if (npages > si.freeram) { + /* exceeds freeram, but below freeram+bufferram */ + printk(KERN_WARNING + "log buffer size exceeds free memory(%luMB)\n", + MB(si.freeram)); } - reserved = (char*)buf->data + buf->offset; - buf->offset += length; - return reserved; +#if (RELAYFS_CHANNEL_VERSION >= 7) + _stp_relay_data.rchan = relay_open("trace", dir, utts->buf_size, + utts->buf_nr, + &__stp_relay_callbacks, NULL); #else - return 0; + _stp_relay_data.rchan = relay_open("trace", dir, utts->buf_size, + utts->buf_nr, + &__stp_relay_callbacks); #endif -} - - + if (!_stp_relay_data.rchan) + goto err; -static int -_stp_relay_subbuf_start_callback(struct rchan_buf *buf, void *subbuf, - void *prev_subbuf, size_t prev_padding) -{ - if (_stp_relay.overwrite_flag || !relay_buf_full(buf)) - return 1; + _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; - return 0; + utts->err = 0; + return utt; +err: + if (_stp_relay_data.dropped_file) + debugfs_remove(_stp_relay_data.dropped_file); + if (_stp_relay_data.rchan) + relay_close(_stp_relay_data.rchan); + if (dir) + __stp_relay_remove_tree(); + utts->err = ret; + return NULL; } -static struct dentry * -_stp_relay_create_buf_file_callback(const char *filename, - struct dentry *parent, - int mode, - struct rchan_buf *buf, - int *is_global) +static int utt_trace_startstop(struct _stp_relay_data_type *utt, int start) { - struct dentry *file; + int ret; - if (is_global) { -#ifdef STP_BULKMODE - *is_global = 0; -#else - *is_global = 1; -#endif + /* + * 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 (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED || + _stp_relay_data.transport_state == STP_TRANSPORT_STOPPED) { + __stp_relay_timer_init(); + smp_mb(); + _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + ret = 0; + } + } else { + if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) { + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + del_timer_sync(&_stp_relay_data.timer); + relay_flush(_stp_relay_data.rchan); + ret = 0; + } } - file = debugfs_create_file(filename, mode, parent, buf, - &relay_file_operations); - if (file) { - file->d_inode->i_uid = _stp_uid; - file->d_inode->i_gid = _stp_gid; - } - return file; + return ret; } +#endif -static int -_stp_relay_remove_buf_file_callback(struct dentry *dentry) +static void _stp_transport_data_fs_close(void) { - debugfs_remove(dentry); - return 0; + if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) + del_timer_sync(&_stp_relay_data.timer); + + if (_stp_relay_data.dropped_file) + debugfs_remove(_stp_relay_data.dropped_file); + if (_stp_relay_data.rchan) { + relay_flush(_stp_relay_data.rchan); + relay_close(_stp_relay_data.rchan); + } + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; } -static struct rchan_callbacks _stp_relay_callbacks = { - .subbuf_start = _stp_relay_subbuf_start_callback, - .create_buf_file = _stp_relay_create_buf_file_callback, - .remove_buf_file = _stp_relay_remove_buf_file_callback, -}; - static int _stp_transport_data_fs_init(void) { int rc; u64 npages; struct sysinfo si; - _stp_relay.overwrite_flag = 0; + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + _stp_relay_data.overwrite_flag = 0; + atomic_set(&_stp_relay_data.dropped, 0); + _stp_relay_data.dropped_file = NULL; + _stp_relay_data.rchan = NULL; + + /* Create "dropped" file. */ + _stp_relay_data.dropped_file + = debugfs_create_file("dropped", 0444, _stp_get_module_dir(), + NULL, &__stp_relay_dropped_fops); + if (!_stp_relay_data.dropped_file) { + rc = -EIO; + goto err; + } + /* Create "trace" file. */ npages = _stp_subbuf_size * _stp_nsubbufs; #ifdef STP_BULKMODE npages *= num_possible_cpus(); @@ -518,33 +442,71 @@ static int _stp_transport_data_fs_init(void) "log buffer size exceeds free memory(%luMB)\n", MB(si.freeram)); } - #if (RELAYFS_CHANNEL_VERSION >= 7) - _stp_relay.rchan = relay_open("trace", _stp_get_module_dir(), - _stp_subbuf_size, _stp_nsubbufs, - &_stp_relay_callbacks, NULL); + _stp_relay_data.rchan = relay_open("trace", _stp_get_module_dir(), + _stp_subbuf_size, _stp_nsubbufs, + &__stp_relay_callbacks, NULL); #else /* (RELAYFS_CHANNEL_VERSION < 7) */ - _stp_relay.rchan = relay_open("trace", _stp_get_module_dir(), - _stp_subbuf_size, _stp_nsubbufs, - &_stp_relay_callbacks); + _stp_relay_data.rchan = relay_open("trace", _stp_get_module_dir(), + _stp_subbuf_size, _stp_nsubbufs, + &__stp_relay_callbacks); #endif /* (RELAYFS_CHANNEL_VERSION < 7) */ - - if (!_stp_relay.rchan) { + if (!_stp_relay_data.rchan) { rc = -ENOENT; goto err; } dbug_trans(1, "returning 0...\n"); + _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; + + /* We're initialized. Now start the timer. */ + __stp_relay_timer_init(); + _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + return 0; err: - if (_stp_relay.rchan) - relay_close(_stp_relay.rchan); + _stp_transport_data_fs_close(); return rc; } -static void _stp_transport_data_fs_close(void) + +/** + * utt_reserve - reserve slot in channel buffer + * @utt: utt channel + * @length: number of bytes to reserve + * + * Returns pointer to reserved slot, NULL if full. + * + * This function is utt_switch_subbuf version of relay_reserve. + */ +static size_t +_stp_data_write_reserve(size_t size_request, void **entry) +{ + struct rchan_buf *buf; + + if (entry == NULL) + return -EINVAL; + + buf = _stp_relay_data.rchan->buf[smp_processor_id()]; + if (unlikely(buf->offset + size_request > buf->chan->subbuf_size)) { + size_request = __stp_relay_switch_subbuf(buf, size_request); + if (!size_request) + return 0; + } + *entry = (char*)buf->data + buf->offset; + buf->offset += size_request; + + return size_request; +} + +static unsigned char *_stp_data_entry_data(void *entry) { - if (_stp_relay.rchan) - relay_close(_stp_relay.rchan); + /* Nothing to do here. */ + return entry; } +static int _stp_data_write_commit(void *entry) +{ + /* Nothing to do here. */ + return 0; +} -- cgit From 42b8c995e8bac5a36be60870fca7f9ff1af2c2ab Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 8 May 2009 15:21:27 -0500 Subject: Cleaned up runtime/transport/relay_v2.c. * runtime/transport/relay_v2.c: Cleanup. --- runtime/transport/relay_v2.c | 196 ++++--------------------------------------- 1 file changed, 15 insertions(+), 181 deletions(-) (limited to 'runtime/transport/relay_v2.c') diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index ea4d9241..9bcb6ee3 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -1,11 +1,14 @@ /* -*- 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. + * This transport version uses relayfs on top of a debugfs file. This + * code started as a proposed relayfs interface called 'utt'. It has + * been modified and simplified for systemtap. * - * Copyright (C) 2006 Jens Axboe + * Changes Copyright (C) 2009 Red Hat Inc. * - * Moved to utt.c by Tom Zanussi, 2006 + * Original utt code by: + * 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 @@ -44,10 +47,8 @@ enum _stp_transport_state { struct _stp_relay_data_type { enum _stp_transport_state transport_state; struct rchan *rchan; - struct dentry *dir; /* systemtap/module_name */ struct dentry *dropped_file; atomic_t dropped; - struct dentry *utt_tree_root; /* systemtap */ atomic_t wakeup; struct timer_list timer; int overwrite_flag; @@ -151,67 +152,6 @@ static void stp_relay_set_overwrite(int overwrite) _stp_relay_data.overwrite_flag = overwrite; } -static void __stp_relay_remove_root(void) -{ - if (_stp_relay_data.utt_tree_root) { - if (!_stp_lock_transport_dir()) { - errk("Unable to lock transport directory.\n"); - return; - } - if (simple_empty(_stp_relay_data.utt_tree_root)) - debugfs_remove(_stp_relay_data.utt_tree_root); - _stp_unlock_transport_dir(); - _stp_relay_data.utt_tree_root = NULL; - } -} - -static void __stp_relay_remove_tree(void) -{ - if (_stp_relay_data.dir == NULL) - return; - debugfs_remove(_stp_relay_data.dir); - __stp_relay_remove_root(); -} - -static struct dentry *__stp_relay_create_tree(const char *root, - const char *name) -{ - struct dentry *dir = NULL; - - if (root == NULL || name == NULL) - return NULL; - - if (!_stp_relay_data.utt_tree_root) { - _stp_relay_data.utt_tree_root = _stp_get_root_dir(); - if (!_stp_relay_data.utt_tree_root) - goto err; - } - - dir = debugfs_create_dir(name, _stp_relay_data.utt_tree_root); - if (!dir) - __stp_relay_remove_root(); -err: - return dir; -} - -static void __stp_relay_cleanup(void) -{ - if (_stp_relay_data.rchan) - relay_close(_stp_relay_data.rchan); - if (_stp_relay_data.dropped_file) - debugfs_remove(_stp_relay_data.dropped_file); - __stp_relay_remove_tree(); -} - -static int _stp_relay_remove(void) -{ - if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED || - _stp_relay_data.transport_state == STP_TRANSPORT_STOPPED) - __stp_relay_cleanup(); - - return 0; -} - static int __stp_relay_dropped_open(struct inode *inode, struct file *filp) { return 0; @@ -277,115 +217,6 @@ static struct rchan_callbacks __stp_relay_callbacks = { .remove_buf_file = __stp_relay_remove_buf_file_callback, }; -#if 0 -/* - * Setup everything required to start tracing - */ -static struct _stp_relay_data_type *utt_trace_setup(struct utt_trace_setup *utts) -{ - struct dentry *dir = NULL; - int ret = -EINVAL; - u64 npages; - struct sysinfo si; - - _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; - _stp_relay_data.overwrite_flag = 0; - - if (!utts->buf_size || !utts->buf_nr) - goto err; - - ret = -ENOENT; - dir = __stp_relay_create_tree(utts->root, utts->name); - if (!dir) - goto err; - _stp_relay_data.dir = dir; - atomic_set(&_stp_relay_data.dropped, 0); - - ret = -EIO; - _stp_relay_data.dropped_file = debugfs_create_file("dropped", 0444, - dir, NULL, - &__stp_relay_dropped_fops); - if (!_stp_relay_data.dropped_file) - goto err; - - npages = utts->buf_size * utts->buf_nr; -#ifndef STP_BULKMODE - npages *= num_possible_cpus(); -#endif - npages >>= PAGE_SHIFT; - si_meminfo(&si); -#define MB(i) (unsigned long)((i) >> (20 - PAGE_SHIFT)) - if (npages > (si.freeram + si.bufferram)) { - errk("Not enough free+buffered memory(%luMB) for log buffer(%luMB)\n", - MB(si.freeram + si.bufferram), - MB(npages)); - ret = -ENOMEM; - goto err; - } else if (npages > si.freeram) { - /* exceeds freeram, but below freeram+bufferram */ - printk(KERN_WARNING - "log buffer size exceeds free memory(%luMB)\n", - MB(si.freeram)); - } - -#if (RELAYFS_CHANNEL_VERSION >= 7) - _stp_relay_data.rchan = relay_open("trace", dir, utts->buf_size, - utts->buf_nr, - &__stp_relay_callbacks, NULL); -#else - _stp_relay_data.rchan = relay_open("trace", dir, utts->buf_size, - utts->buf_nr, - &__stp_relay_callbacks); -#endif - - if (!_stp_relay_data.rchan) - goto err; - - _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; - - utts->err = 0; - return utt; -err: - if (_stp_relay_data.dropped_file) - debugfs_remove(_stp_relay_data.dropped_file); - if (_stp_relay_data.rchan) - relay_close(_stp_relay_data.rchan); - if (dir) - __stp_relay_remove_tree(); - utts->err = ret; - return NULL; -} - -static int utt_trace_startstop(struct _stp_relay_data_type *utt, int start) -{ - 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 (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED || - _stp_relay_data.transport_state == STP_TRANSPORT_STOPPED) { - __stp_relay_timer_init(); - smp_mb(); - _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; - ret = 0; - } - } else { - if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) { - _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; - del_timer_sync(&_stp_relay_data.timer); - relay_flush(_stp_relay_data.rchan); - ret = 0; - } - } - - return ret; -} -#endif - static void _stp_transport_data_fs_close(void) { if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) @@ -471,13 +302,16 @@ err: /** - * utt_reserve - reserve slot in channel buffer - * @utt: utt channel - * @length: number of bytes to reserve + * _stp_data_write_reserve - try to reserve size_request bytes + * @size_request: number of bytes to attempt to reserve + * @entry: entry is returned here * - * Returns pointer to reserved slot, NULL if full. + * Returns number of bytes reserved, 0 if full. On return, entry + * will point to allocated opaque pointer. Use + * _stp_data_entry_data() to get pointer to copy data into. * - * This function is utt_switch_subbuf version of relay_reserve. + * (For this code's purposes, entry is filled in with the actual + * data pointer, but the caller doesn't know that.) */ static size_t _stp_data_write_reserve(size_t size_request, void **entry) -- cgit From 945563a795f312551157b69542ed1bc3323203c7 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 8 May 2009 15:28:56 -0500 Subject: Sets uid/gid on "dropped" file. * runtime/transport/relay_v2.c (_stp_transport_data_fs_init): Sets uid/gid on "dropped" file. --- runtime/transport/relay_v2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/transport/relay_v2.c') diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index 9bcb6ee3..c0a772ed 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -251,6 +251,8 @@ static int _stp_transport_data_fs_init(void) rc = -EIO; goto err; } + _stp_relay_data.dropped_file->d_inode->i_uid = _stp_uid; + _stp_relay_data.dropped_file->d_inode->i_gid = _stp_gid; /* Create "trace" file. */ npages = _stp_subbuf_size * _stp_nsubbufs; -- cgit From e57421f400d17786c1fdbead5fbca27a1fbe4ec5 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 22 May 2009 10:50:30 -0500 Subject: Added error checking and other updates. * runtime/vsprintf.c: Added transport.h inclusion for STP_BUFFER_SIZE definition. * runtime/transport/debugfs.c (_stp_register_ctl_channel_fs): Added error checking. * runtime/transport/transport.c (_stp_get_root_dir): Ditto. (_stp_transport_fs_init): Added original transport support and error checking. * runtime/transport/relay_v2.c (__stp_relay_create_buf_file_callback): Added error checking. (_stp_transport_data_fs_init): Ditto. * runtime/transport/ring_buffer.c (_stp_transport_data_fs_init): Ditto. * runtime/transport/utt.c: Removed unused file. * runtime/transport/utt.h: Ditto. --- runtime/transport/relay_v2.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'runtime/transport/relay_v2.c') diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index c0a772ed..0c8d0955 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -204,7 +204,10 @@ __stp_relay_create_buf_file_callback(const char *filename, { struct dentry *file = debugfs_create_file(filename, mode, parent, buf, &relay_file_operations); - if (file) { + if (IS_ERR(file)) { + file = NULL; + } + else if (file) { file->d_inode->i_uid = _stp_uid; file->d_inode->i_gid = _stp_gid; } @@ -251,6 +254,12 @@ static int _stp_transport_data_fs_init(void) rc = -EIO; goto err; } + else if (IS_ERR(_stp_relay_data.dropped_file)) { + rc = PTR_ERR(_stp_relay_data.dropped_file); + _stp_relay_data.dropped_file = NULL; + goto err; + } + _stp_relay_data.dropped_file->d_inode->i_uid = _stp_uid; _stp_relay_data.dropped_file->d_inode->i_gid = _stp_gid; -- cgit From 01adca5bca8d61e3fdf09017496deec8859fe12d Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 3 Jun 2009 13:04:54 -0500 Subject: Fixed STP_TRANSPORT_VERSION 1 behavior. * runtime/transport/control.c (_stp_ctl_write_dbug): Added support for more messages. * runtime/transport/relay_v2.c (_stp_transport_data_fs_start): New function. (_stp_transport_data_fs_stop): Ditto. (_stp_transport_data_fs_close): Moved some functionality into _stp_transport_data_fs_stop() and calls _stp_transport_data_fs_stop() also. (_stp_transport_data_fs_init): Moved some functionality into _stp_transport_data_fs_start() and calls _stp_transport_data_fs_start() also. * runtime/transport/relayfs.c (_stp_transport_data_fs_start): New function. (_stp_transport_data_fs_stop): Ditto. (_stp_transport_data_fs_close): Moved some functionality into _stp_transport_data_fs_stop() and calls _stp_transport_data_fs_stop() also. (_stp_transport_data_fs_init): Moved some functionality into _stp_transport_data_fs_start() and calls _stp_transport_data_fs_start() also. * runtime/transport/ring_buffer.c (_stp_transport_data_fs_start): New empty function. (_stp_transport_data_fs_stop): Ditto. * runtime/transport/transport.h: Added _stp_transport_data_fs_start() and _stp_transport_data_fs_stop() prototypes. * runtime/transport/transport.c (_stp_cleanup_and_exit): Calls _stp_transport_data_fs_stop(). (_stp_transport_close): Calls _stp_transport_fs_close() earlier. (_stp_transport_init): Calls _stp_transport_data_fs_start(). --- runtime/transport/relay_v2.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'runtime/transport/relay_v2.c') diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index 0c8d0955..16b5afa1 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -220,18 +220,35 @@ static struct rchan_callbacks __stp_relay_callbacks = { .remove_buf_file = __stp_relay_remove_buf_file_callback, }; -static void _stp_transport_data_fs_close(void) +static void _stp_transport_data_fs_start(void) +{ + if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED) { + /* We're initialized. Now start the timer. */ + __stp_relay_timer_init(); + _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + } +} + +static void _stp_transport_data_fs_stop(void) { - if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) + if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) { del_timer_sync(&_stp_relay_data.timer); + dbug_trans(0, "flushing...\n"); + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + if (_stp_relay_data.rchan) + relay_flush(_stp_relay_data.rchan); + } +} +static void _stp_transport_data_fs_close(void) +{ + _stp_transport_data_fs_stop(); if (_stp_relay_data.dropped_file) debugfs_remove(_stp_relay_data.dropped_file); if (_stp_relay_data.rchan) { - relay_flush(_stp_relay_data.rchan); relay_close(_stp_relay_data.rchan); + _stp_relay_data.rchan = NULL; } - _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; } static int _stp_transport_data_fs_init(void) @@ -300,10 +317,6 @@ static int _stp_transport_data_fs_init(void) dbug_trans(1, "returning 0...\n"); _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; - /* We're initialized. Now start the timer. */ - __stp_relay_timer_init(); - _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; - return 0; err: -- cgit From d05b7a1c363c30c7fcd9d163f457c1ed80d28f19 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 12 Jun 2009 13:20:57 -0500 Subject: Fixed non-bulkmode output on smp systems using transport version 2. * runtime/transport/relay_v2.c (__stp_relay_create_buf_file_callback): Set the 'is_global' return parameter so that smp systems work correctly. --- runtime/transport/relay_v2.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'runtime/transport/relay_v2.c') diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index 16b5afa1..246c4965 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -204,6 +204,21 @@ __stp_relay_create_buf_file_callback(const char *filename, { struct dentry *file = debugfs_create_file(filename, mode, parent, buf, &relay_file_operations); + /* + * Here's what 'is_global' does (from linux/relay.h): + * + * Setting the is_global outparam to a non-zero value will + * cause relay_open() to create a single global buffer rather + * than the default set of per-cpu buffers. + */ + if (is_global) { +#ifdef STP_BULKMODE + *is_global = 0; +#else + *is_global = 1; +#endif + } + if (IS_ERR(file)) { file = NULL; } -- cgit From 24a5e9a6a87b2f7c8b7264ceb94c65a3a9550d47 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 18 Jun 2009 13:09:31 -0500 Subject: Enabled overwrite processing on original transports. * runtime/transport/relay_v2.c (_stp_transport_data_fs_overwrite): Renamed from stp_relay_set_overwrite(). * runtime/transport/relayfs.c (stp_relay_set_overwrite): Ditto. * runtime/transport/ring_buffer.c (_stp_transport_data_fs_overwrite): New place holder function. * runtime/transport/transport.c (_stp_detach): Calls _stp_transport_data_fs_overwrite(). (_stp_attach): Calls _stp_transport_data_fs_overwrite(). * runtime/transport/transport.h: Added prototype for _stp_transport_data_fs_overwrite(). --- runtime/transport/relay_v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/transport/relay_v2.c') diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index 246c4965..aa6f7b99 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -147,7 +147,7 @@ static void __stp_relay_timer_init(void) smp_mb(); } -static void stp_relay_set_overwrite(int overwrite) +static void _stp_transport_data_fs_overwrite(int overwrite) { _stp_relay_data.overwrite_flag = overwrite; } -- cgit From 7b1be319b40ec791c4fdbe77065204a4c3ed439b Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 18 Jun 2009 16:42:35 -0500 Subject: Transports now export their state. * runtime/transport/transport.h: Added prototype for _stp_transport_get_state(). * runtime/transport/relay_v2.c (_stp_transport_get_state): New function. * runtime/transport/relayfs.c (_stp_transport_get_state): Ditto. * runtime/transport/ring_buffer.c (_stp_transport_data_fs_init): Sets state. (_stp_transport_data_fs_start): Ditto. (_stp_transport_data_fs_stop): Ditto. (_stp_transport_get_state): Returns state. * runtime/print_new.c (stp_print_flush): Checks transport state before trying to flush. --- runtime/transport/relay_v2.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'runtime/transport/relay_v2.c') diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index aa6f7b99..65e9c59b 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -38,12 +38,6 @@ #define STP_RELAY_TIMER_INTERVAL ((HZ + 99) / 100) #endif -enum _stp_transport_state { - STP_TRANSPORT_STOPPED, - STP_TRANSPORT_INITIALIZED, - STP_TRANSPORT_RUNNING, -}; - struct _stp_relay_data_type { enum _stp_transport_state transport_state; struct rchan *rchan; @@ -147,6 +141,11 @@ static void __stp_relay_timer_init(void) smp_mb(); } +static enum _stp_transport_state _stp_transport_get_state(void) +{ + return _stp_relay_data.transport_state; +} + static void _stp_transport_data_fs_overwrite(int overwrite) { _stp_relay_data.overwrite_flag = overwrite; -- cgit