From 23c1c6557af76d506a28bcb3e864d3500e6dc565 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 24 Feb 2009 11:54:16 -0600 Subject: Major hacking to minimal config. 2009-02-24 David Smith * print.h: New file. * print.c: Includes new print.h file. * print_new.c (stp_print_flush): Commented out some code that needs replacing. * sym.c: Includes sym.h. * transport/debugfs.c: Includes transport.h. * transport/relayfs.c: Updated _stp_get_root_dir() call. * transport/transport.c: Ifdef'ed out most setup. * transport/transport.h: Ifdef'ed out all but basics. * transport/utt.c (utt_create_tree): Updated _stp_get_root_dir() call. * transport/utt.h: Commented out 'rchan' in struct utt_trace. (utt_reserve): Ifdef'ed out guts. --- runtime/print.c | 1 + runtime/print.h | 16 +++++ runtime/print_new.c | 5 +- runtime/sym.c | 1 + runtime/transport/debugfs.c | 1 + runtime/transport/relayfs.c | 2 +- runtime/transport/transport.c | 140 ++++++++++++++++++++++++++++++++++-------- runtime/transport/transport.h | 36 ++++++++--- runtime/transport/utt.c | 4 +- runtime/transport/utt.h | 9 ++- 10 files changed, 175 insertions(+), 40 deletions(-) create mode 100644 runtime/print.h (limited to 'runtime') diff --git a/runtime/print.c b/runtime/print.c index 2c84d3c9..fa517cb5 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -14,6 +14,7 @@ #include "string.h" #include "vsprintf.c" +#include "print.h" #include "transport/transport.c" /** @file print.c diff --git a/runtime/print.h b/runtime/print.h new file mode 100644 index 00000000..d5c588a3 --- /dev/null +++ b/runtime/print.h @@ -0,0 +1,16 @@ +/* -*- linux-c -*- + * Copyright (C) 2009 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. + */ + +#ifndef _STP_PRINT_H_ +#define _STP_PRINT_H_ + +static int _stp_print_init(void); +static void _stp_print_cleanup(void); + +#endif /* _STP_PRINT_H_ */ diff --git a/runtime/print_new.c b/runtime/print_new.c index fa7b4727..43e37822 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -28,8 +28,9 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) pb->len = 0; - if (unlikely(!_stp_utt || _stp_utt->trace_state != Utt_trace_running)) - return; +//DRS FIXME: this digs down too deep in internals +// if (unlikely(!_stp_utt || _stp_utt->trace_state != Utt_trace_running)) +// return; #ifdef STP_BULKMODE { diff --git a/runtime/sym.c b/runtime/sym.c index 1d88a862..31700326 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -12,6 +12,7 @@ #ifndef _STP_SYM_C_ #define _STP_SYM_C_ +#include "sym.h" #include "string.c" /** @file sym.c diff --git a/runtime/transport/debugfs.c b/runtime/transport/debugfs.c index 85ee604d..7de57335 100644 --- a/runtime/transport/debugfs.c +++ b/runtime/transport/debugfs.c @@ -10,6 +10,7 @@ */ #include +#include "transport.h" #define STP_DEFAULT_BUFFERS 50 diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index 6eefda8d..42be4283 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -86,7 +86,7 @@ static struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts) if (!utt) return NULL; - utt->utt_tree_root = _stp_get_root_dir(utts->root); + utt->utt_tree_root = _stp_get_root_dir(); if (!utt->utt_tree_root) goto err; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 7fcebd42..2d82270a 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -14,10 +14,21 @@ #ifndef _TRANSPORT_TRANSPORT_C_ #define _TRANSPORT_TRANSPORT_C_ -#include -#include #include "transport.h" -#include "time.c" +struct utt_trace { + int dummy; +}; +static struct utt_trace *_stp_utt = NULL; +static int _stp_ctl_write(int type, void *data, unsigned len) { + return 0; +} + +static int _stp_exit_flag = 0; + +#include +#include +#if 0 +#include #include "../mempool.c" #include "symbols.c" @@ -37,10 +48,15 @@ static int _stp_exit_flag = 0; #endif #include "control.c" +#endif /* if 0 */ +static unsigned _stp_nsubbufs = 8; +static unsigned _stp_subbuf_size = 65536*4; + /* module parameters */ static int _stp_bufsize; module_param(_stp_bufsize, int, 0); MODULE_PARM_DESC(_stp_bufsize, "buffer size"); +#if 0 /* forward declarations */ static void probe_exit(void); @@ -173,6 +189,7 @@ static void _stp_work_queue(void *data) if (likely(_stp_attached)) queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } +#endif /* #if 0 */ /** * _stp_transport_close - close ctl and relayfs channels @@ -180,9 +197,11 @@ static void _stp_work_queue(void *data) * This is called automatically when the module is unloaded. * */ -static void _stp_transport_close() +static void _stp_transport_close(void) { - dbug_trans(1, "%d: ************** transport_close *************\n", current->pid); + dbug_trans(1, "%d: ************** transport_close *************\n", + current->pid); +#if 0 _stp_cleanup_and_exit(0); destroy_workqueue(_stp_wq); _stp_unregister_ctl_channel(); @@ -190,9 +209,13 @@ static void _stp_transport_close() utt_trace_remove(_stp_utt); _stp_print_cleanup(); /* free print buffers */ _stp_mem_debug_done(); +#endif + _stp_transport_fs_close(); + dbug_trans(1, "---- CLOSED ----\n"); } +#if 0 static struct utt_trace *_stp_utt_open(void) { struct utt_trace_setup utts; @@ -209,6 +232,7 @@ static struct utt_trace *_stp_utt_open(void) return utt_trace_setup(&utts); } +#endif /* #if 0 */ /** * _stp_transport_init() is called from the module initialization. @@ -217,7 +241,6 @@ static struct utt_trace *_stp_utt_open(void) static int _stp_transport_init(void) { dbug_trans(1, "transport_init\n"); - _stp_init_pid = current->pid; #ifdef STAPCONF_TASK_UID _stp_uid = current->uid; _stp_gid = current->gid; @@ -226,6 +249,8 @@ static int _stp_transport_init(void) _stp_gid = current_gid(); #endif +// DRS: is RELAY_GUEST/RELAY_HOST documented? does it work? are there +// test cases? #ifdef RELAY_GUEST /* Guest scripts use relay only for reporting warnings and errors */ _stp_subbuf_size = 65536; @@ -243,6 +268,10 @@ static int _stp_transport_init(void) dbug_trans(1, "Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size); } + if (_stp_transport_fs_init(THIS_MODULE->name)) + return -1; + +#if 0 #if !defined (STP_OLD_TRANSPORT) || defined (STP_BULKMODE) /* open utt (relayfs) channel to send data to userspace */ _stp_utt = _stp_utt_open(); @@ -253,11 +282,13 @@ static int _stp_transport_init(void) /* create control channel */ if (_stp_register_ctl_channel() < 0) goto err1; +#endif /* #if 0 */ /* create print buffers */ if (_stp_print_init() < 0) goto err2; +#if 0 /* start transport */ utt_trace_startstop(_stp_utt, 1, &utt_seq); @@ -270,16 +301,19 @@ static int _stp_transport_init(void) /* Signal stapio to send us STP_START back (XXX: ?!?!?!). */ _stp_ctl_send(STP_TRANSPORT, NULL, 0); +#endif /* #if 0 */ return 0; err3: _stp_print_cleanup(); err2: +#if 0 _stp_unregister_ctl_channel(); err1: if (_stp_utt) utt_trace_remove(_stp_utt); +#endif /* #if 0 */ err0: return -1; } @@ -331,51 +365,109 @@ static void _stp_unlock_transport_dir(void) } } -/* _stp_get_root_dir(name) - creates root directory 'name' or */ -/* returns a pointer to it if it already exists. Used in */ -/* utt.c and relayfs.c. Will not be necessary if utt is included */ -/* in the kernel. */ +static struct dentry *__stp_root_dir = NULL; -static struct dentry *_stp_get_root_dir(const char *name) +/* _stp_get_root_dir() - creates root directory or returns + * a pointer to it if it already exists. */ + +static struct dentry *_stp_get_root_dir(void) { struct file_system_type *fs; - struct dentry *root; struct super_block *sb; + const char *name = "systemtap"; + + if (__stp_root_dir != NULL) { + return __stp_root_dir; + } #ifdef STP_OLD_TRANSPORT fs = get_fs_type("relayfs"); + if (!fs) { + errk("Couldn't find relayfs filesystem.\n"); + return NULL; + } #else fs = get_fs_type("debugfs"); -#endif if (!fs) { - errk("Couldn't find debugfs or relayfs filesystem.\n"); + errk("Couldn't find debugfs filesystem.\n"); return NULL; } +#endif if (!_stp_lock_transport_dir()) { errk("Couldn't lock transport directory.\n"); return NULL; } #ifdef STP_OLD_TRANSPORT - root = relayfs_create_dir(name, NULL); + __stp_root_dir = relayfs_create_dir(name, NULL); #else - root = debugfs_create_dir(name, NULL); + __stp_root_dir = debugfs_create_dir(name, NULL); #endif - if (!root) { - /* couldn't create it because it is already there, so find it. */ - sb = list_entry(fs->fs_supers.next, struct super_block, s_instances); + if (!__stp_root_dir) { + /* Couldn't create it because it is already there, so + * find it. */ + sb = list_entry(fs->fs_supers.next, struct super_block, + s_instances); _stp_lock_inode(sb->s_root->d_inode); - root = lookup_one_len(name, sb->s_root, strlen(name)); + __stp_root_dir = lookup_one_len(name, sb->s_root, + strlen(name)); _stp_unlock_inode(sb->s_root->d_inode); - if (!IS_ERR(root)) - dput(root); + if (!IS_ERR(__stp_root_dir)) + dput(__stp_root_dir); else { - root = NULL; + __stp_root_dir = NULL; errk("Could not create or find transport directory.\n"); } } _stp_unlock_transport_dir(); - return root; + return __stp_root_dir; +} + +static void _stp_remove_root_dir(void) +{ + if (__stp_root_dir) { + if (!_stp_lock_transport_dir()) { + errk("Unable to lock transport directory.\n"); + return; + } + if (simple_empty(__stp_root_dir)) + debugfs_remove(__stp_root_dir); + _stp_unlock_transport_dir(); + __stp_root_dir = NULL; + } } +static struct dentry *__stp_module_dir = NULL; + +static int _stp_transport_fs_init(const char *module_name) +{ + struct dentry *root_dir; + + if (module_name == NULL) + return -1; + + root_dir = _stp_get_root_dir(); + if (root_dir == NULL) + return -1; + + __stp_module_dir = debugfs_create_dir(module_name, root_dir); + if (!__stp_module_dir) { + _stp_remove_root_dir(); + return -1; + } + return 0; +} + +static void _stp_transport_fs_close(void) +{ + dbug_trans(1, "stp_transport_fs_close\n"); + if (__stp_module_dir) { + debugfs_remove(__stp_module_dir); + __stp_module_dir = NULL; + } + + _stp_remove_root_dir(); +} + + #endif /* _TRANSPORT_C_ */ diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index 7d249c45..c6d850ef 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -11,6 +11,20 @@ /* amount of data a print can send. */ #define STP_BUFFER_SIZE 8192 +struct utt_trace; + +static int _stp_ctl_write(int type, void *data, unsigned len); + +static int _stp_transport_init(void); +static void _stp_transport_close(void); + +static inline void *utt_reserve(struct utt_trace *utt, size_t length) +{ + return NULL; +} + + +#if 0 /* STP_CTL_BUFFER_SIZE is the maximum size of a message */ /* exchanged on the control channel. */ #ifdef STP_OLD_TRANSPORT @@ -23,27 +37,33 @@ /* how often the work queue wakes up and checks buffers */ #define STP_WORK_TIMER (HZ/100) -static unsigned _stp_nsubbufs = 8; -static unsigned _stp_subbuf_size = 65536*4; +#endif /* #if 0 */ +static unsigned _stp_nsubbufs; +static unsigned _stp_subbuf_size; static int _stp_transport_init(void); static void _stp_transport_close(void); -static void _stp_warn (const char *fmt, ...); -static int _stp_print_init(void); -static void _stp_print_cleanup(void); -static struct dentry *_stp_get_root_dir(const char *name); - static int _stp_lock_transport_dir(void); static void _stp_unlock_transport_dir(void); +static struct dentry *_stp_get_root_dir(void); + +static int _stp_transport_fs_init(const char *module_name); +static void _stp_transport_fs_close(void); + +#if 0 +static void _stp_warn (const char *fmt, ...); + static void _stp_attach(void); static void _stp_detach(void); static void _stp_handle_start(struct _stp_msg_start *st); static int _stp_pid = 0; +#endif static uid_t _stp_uid = 0; static gid_t _stp_gid = 0; -static pid_t _stp_init_pid = 0; +#if 0 static int _stp_attached = 0; +#endif #endif /* _TRANSPORT_TRANSPORT_H_ */ diff --git a/runtime/transport/utt.c b/runtime/transport/utt.c index 915662b2..2dd303a5 100644 --- a/runtime/transport/utt.c +++ b/runtime/transport/utt.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include "utt.h" @@ -157,7 +156,7 @@ static struct dentry *utt_create_tree(struct utt_trace *utt, const char *root, c return NULL; if (!utt->utt_tree_root) { - utt->utt_tree_root = _stp_get_root_dir(root); + utt->utt_tree_root = _stp_get_root_dir(); if (!utt->utt_tree_root) goto err; } @@ -169,7 +168,6 @@ err: return dir; } - static void utt_trace_cleanup(struct utt_trace *utt) { if (utt == NULL) diff --git a/runtime/transport/utt.h b/runtime/transport/utt.h index 40e54919..0a0944c0 100644 --- a/runtime/transport/utt.h +++ b/runtime/transport/utt.h @@ -9,11 +9,11 @@ enum { struct utt_trace { int trace_state; - struct rchan *rchan; +// struct rchan *rchan; struct dentry *dir; /* systemtap/module_name */ struct dentry *dropped_file; atomic_t dropped; - struct dentry *utt_tree_root; /* systemtap */ + struct dentry *utt_tree_root; /* systemtap */ void *private_data; atomic_t wakeup; struct timer_list timer; @@ -41,6 +41,7 @@ struct utt_trace_setup { static struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts); + static int utt_trace_startstop(struct utt_trace *utt, int start, unsigned int *trace_seq); static void utt_trace_cleanup(struct utt_trace *utt); @@ -60,6 +61,7 @@ static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, */ static inline void *utt_reserve(struct utt_trace *utt, size_t length) { +#if 0 void *reserved; struct rchan_buf *buf = utt->rchan->buf[smp_processor_id()]; @@ -72,6 +74,9 @@ static inline void *utt_reserve(struct utt_trace *utt, size_t length) buf->offset += length; return reserved; +#else + return NULL; +#endif } #endif -- cgit From 64c962fed5f50a7f82f8b570e000cdcff757862b Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 25 Feb 2009 09:04:19 -0600 Subject: More cleanup. 2009-02-25 David Smith * debug.h: Removed unused variable '_stp_transport_state'. * print_new.c (stp_print_flush): Ifdef'ed out call to utt_reserve(). * runtime.h: Added _stp_warn() prototype. * transport/control.c: Includes control.h, mempool.c, and symbols.c. Renamed '_stp_attached' to '_stp_ctl_attached'. * transport/control.h: Removed _stp_pool_q declaration. * transport/debugfs.c (_stp_register_ctl_channel_fs): Uses _stp_get_module_dir(). * transport/transport.c: Cleanup. * transport/transport.h: Ditto. --- runtime/debug.h | 1 - runtime/print_new.c | 4 +++ runtime/runtime.h | 1 + runtime/transport/control.c | 8 +++-- runtime/transport/control.h | 1 - runtime/transport/debugfs.c | 7 +++-- runtime/transport/transport.c | 68 ++++++++++++++++++++++++++++++------------- runtime/transport/transport.h | 18 ++++-------- 8 files changed, 68 insertions(+), 40 deletions(-) (limited to 'runtime') diff --git a/runtime/debug.h b/runtime/debug.h index e8b2e701..ce0c3943 100644 --- a/runtime/debug.h +++ b/runtime/debug.h @@ -14,7 +14,6 @@ * _dbug() writes to systemtap stderr. * errk() writes to the system log. */ -static int _stp_transport_state = 0; #define _dbug(args...) _stp_dbug(__FUNCTION__, __LINE__, args) diff --git a/runtime/print_new.c b/runtime/print_new.c index 43e37822..bebaa19c 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -57,7 +57,11 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) void *buf; unsigned long flags; spin_lock_irqsave(&_stp_print_lock, flags); +#if 0 buf = utt_reserve(_stp_utt, len); +#else + buf = NULL; +#endif if (likely(buf)) memcpy(buf, pb->buf, len); else diff --git a/runtime/runtime.h b/runtime/runtime.h index fc5d454f..25456beb 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -45,6 +45,7 @@ static void _stp_dbug (const char *func, int line, const char *fmt, ...); static void _stp_error (const char *fmt, ...); +static void _stp_warn (const char *fmt, ...); #include "debug.h" diff --git a/runtime/transport/control.c b/runtime/transport/control.c index edde244d..7626305a 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -9,6 +9,10 @@ * later version. */ +#include "control.h" +#include "../mempool.c" +#include "symbols.c" + static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; static DEFINE_SPINLOCK(_stp_ctl_ready_lock); @@ -192,7 +196,7 @@ static ssize_t _stp_ctl_read_cmd(struct file *file, char __user *buf, static int _stp_ctl_open_cmd(struct inode *inode, struct file *file) { - if (_stp_attached) + if (_stp_ctl_attached) return -1; _stp_attach(); return 0; @@ -200,7 +204,7 @@ static int _stp_ctl_open_cmd(struct inode *inode, struct file *file) static int _stp_ctl_close_cmd(struct inode *inode, struct file *file) { - if (_stp_attached) + if (_stp_ctl_attached) _stp_detach(); return 0; } diff --git a/runtime/transport/control.h b/runtime/transport/control.h index 5e7204ee..48289276 100644 --- a/runtime/transport/control.h +++ b/runtime/transport/control.h @@ -15,7 +15,6 @@ #include #include -static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; static spinlock_t _stp_ctl_ready_lock; static wait_queue_head_t _stp_ctl_wq; diff --git a/runtime/transport/debugfs.c b/runtime/transport/debugfs.c index 7de57335..7a08982a 100644 --- a/runtime/transport/debugfs.c +++ b/runtime/transport/debugfs.c @@ -23,13 +23,14 @@ static struct dentry *_stp_cmd_file = NULL; static int _stp_register_ctl_channel_fs(void) { - if (_stp_utt == NULL) { - errk("_expected _stp_utt to be set.\n"); + struct dentry *module_dir = _stp_get_module_dir(); + if (module_dir == NULL) { + errk("no module directory found.\n"); return -1; } /* create [debugfs]/systemtap/module_name/.cmd */ - _stp_cmd_file = debugfs_create_file(".cmd", 0600, _stp_utt->dir, + _stp_cmd_file = debugfs_create_file(".cmd", 0600, module_dir, NULL, &_stp_ctl_fops_cmd); if (_stp_cmd_file == NULL) { errk("Error creating systemtap debugfs entries.\n"); diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 2d82270a..12e98a38 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -15,29 +15,36 @@ #define _TRANSPORT_TRANSPORT_C_ #include "transport.h" +#include +#include +#include + struct utt_trace { int dummy; }; -static struct utt_trace *_stp_utt = NULL; -static int _stp_ctl_write(int type, void *data, unsigned len) { - return 0; +//static struct utt_trace *_stp_utt = NULL; + +static void utt_set_overwrite(int overwrite) +{ + return; } static int _stp_exit_flag = 0; -#include -#include +static uid_t _stp_uid = 0; +static gid_t _stp_gid = 0; +static int _stp_pid = 0; + +static int _stp_ctl_attached = 0; + +static pid_t _stp_target = 0; +static int _stp_probes_started = 0; + #if 0 #include -#include "../mempool.c" -#include "symbols.c" static struct utt_trace *_stp_utt = NULL; static unsigned int utt_seq = 1; -static int _stp_probes_started = 0; -static pid_t _stp_target = 0; -static int _stp_exit_called = 0; -static int _stp_exit_flag = 0; #include "control.h" #ifdef STP_OLD_TRANSPORT #include "relayfs.c" @@ -48,6 +55,10 @@ static int _stp_exit_flag = 0; #endif #include "control.c" +#else /* #if 0 */ +#include "control.h" +#include "debugfs.c" +#include "control.c" #endif /* if 0 */ static unsigned _stp_nsubbufs = 8; static unsigned _stp_subbuf_size = 65536*4; @@ -56,12 +67,13 @@ static unsigned _stp_subbuf_size = 65536*4; static int _stp_bufsize; module_param(_stp_bufsize, int, 0); MODULE_PARM_DESC(_stp_bufsize, "buffer size"); -#if 0 /* forward declarations */ static void probe_exit(void); static int probe_start(void); +#if 0 static void _stp_exit(void); +#endif /* #if 0 */ /* check for new workqueue API */ #ifdef DECLARE_DELAYED_WORK @@ -105,6 +117,8 @@ static void _stp_handle_start(struct _stp_msg_start *st) /* when someone does /sbin/rmmod on a loaded systemtap module. */ static void _stp_cleanup_and_exit(int send_exit) { + static int _stp_exit_called = 0; + if (!_stp_exit_called) { int failures; @@ -125,8 +139,10 @@ static void _stp_cleanup_and_exit(int send_exit) _stp_warn("There were %d transport failures.\n", failures); dbug_trans(1, "************** calling startstop 0 *************\n"); +#if 0 if (_stp_utt) utt_trace_startstop(_stp_utt, 0, &utt_seq); +#endif dbug_trans(1, "ctl_send STP_EXIT\n"); if (send_exit) @@ -141,7 +157,7 @@ static void _stp_cleanup_and_exit(int send_exit) static void _stp_detach(void) { dbug_trans(1, "detach\n"); - _stp_attached = 0; + _stp_ctl_attached = 0; _stp_pid = 0; if (!_stp_exit_flag) @@ -157,7 +173,7 @@ static void _stp_detach(void) static void _stp_attach(void) { dbug_trans(1, "attach\n"); - _stp_attached = 1; + _stp_ctl_attached = 1; _stp_pid = current->pid; utt_set_overwrite(0); queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); @@ -186,10 +202,9 @@ static void _stp_work_queue(void *data) /* if exit flag is set AND we have finished with probe_start() */ if (unlikely(_stp_exit_flag && _stp_probes_started)) _stp_cleanup_and_exit(1); - if (likely(_stp_attached)) + if (likely(_stp_ctl_attached)) queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } -#endif /* #if 0 */ /** * _stp_transport_close - close ctl and relayfs channels @@ -203,13 +218,17 @@ static void _stp_transport_close(void) current->pid); #if 0 _stp_cleanup_and_exit(0); +#endif /* #if 0 */ destroy_workqueue(_stp_wq); _stp_unregister_ctl_channel(); +#if 0 if (_stp_utt) utt_trace_remove(_stp_utt); +#endif /* #if 0 */ _stp_print_cleanup(); /* free print buffers */ +#if 0 _stp_mem_debug_done(); -#endif +#endif /* #if 0 */ _stp_transport_fs_close(); dbug_trans(1, "---- CLOSED ----\n"); @@ -278,11 +297,11 @@ static int _stp_transport_init(void) if (!_stp_utt) goto err0; #endif +#endif /* #if 0 */ /* create control channel */ if (_stp_register_ctl_channel() < 0) goto err1; -#endif /* #if 0 */ /* create print buffers */ if (_stp_print_init() < 0) @@ -291,14 +310,14 @@ static int _stp_transport_init(void) #if 0 /* start transport */ utt_trace_startstop(_stp_utt, 1, &utt_seq); +#endif /* #if 0 */ /* create workqueue of kernel threads */ _stp_wq = create_workqueue("systemtap"); if (!_stp_wq) goto err3; - _stp_transport_state = 1; - +#if 0 /* Signal stapio to send us STP_START back (XXX: ?!?!?!). */ _stp_ctl_send(STP_TRANSPORT, NULL, 0); #endif /* #if 0 */ @@ -308,11 +327,13 @@ static int _stp_transport_init(void) err3: _stp_print_cleanup(); err2: -#if 0 _stp_unregister_ctl_channel(); err1: +#if 0 if (_stp_utt) utt_trace_remove(_stp_utt); +#else + _stp_transport_fs_close(); #endif /* #if 0 */ err0: return -1; @@ -439,6 +460,11 @@ static void _stp_remove_root_dir(void) static struct dentry *__stp_module_dir = NULL; +static inline struct dentry *_stp_get_module_dir(void) +{ + return __stp_module_dir; +} + static int _stp_transport_fs_init(const char *module_name) { struct dentry *root_dir; diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index c6d850ef..dec23c72 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -24,7 +24,6 @@ static inline void *utt_reserve(struct utt_trace *utt, size_t length) } -#if 0 /* STP_CTL_BUFFER_SIZE is the maximum size of a message */ /* exchanged on the control channel. */ #ifdef STP_OLD_TRANSPORT @@ -37,7 +36,6 @@ static inline void *utt_reserve(struct utt_trace *utt, size_t length) /* how often the work queue wakes up and checks buffers */ #define STP_WORK_TIMER (HZ/100) -#endif /* #if 0 */ static unsigned _stp_nsubbufs; static unsigned _stp_subbuf_size; @@ -48,22 +46,18 @@ static int _stp_lock_transport_dir(void); static void _stp_unlock_transport_dir(void); static struct dentry *_stp_get_root_dir(void); +static struct dentry *_stp_get_module_dir(void); static int _stp_transport_fs_init(const char *module_name); static void _stp_transport_fs_close(void); -#if 0 -static void _stp_warn (const char *fmt, ...); - static void _stp_attach(void); static void _stp_detach(void); static void _stp_handle_start(struct _stp_msg_start *st); -static int _stp_pid = 0; -#endif -static uid_t _stp_uid = 0; -static gid_t _stp_gid = 0; -#if 0 -static int _stp_attached = 0; -#endif +static uid_t _stp_uid; +static gid_t _stp_gid; + +static int _stp_ctl_attached; + #endif /* _TRANSPORT_TRANSPORT_H_ */ -- cgit From 176b56b261a711822f35e36ec5e2d5e0758770de Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 4 Mar 2009 12:51:29 -0600 Subject: Start of new ring_buffer transport. 2009-03-04 David Smith * runtime.h: Added _stp_exit() prototype. * transport/ring_buffer.c: New file. * transport/transport.c: Removed unneeded utt_trace lines. Includes transport/ring_buffer.c. (_stp_transport_fs_init): Calls _stp_transport_data_fs_init(). (_stp_transport_fs_close): Calls _stp_transport_data_fs_close(). * transport/transport.h: Added prototypes. --- runtime/runtime.h | 2 + runtime/transport/ring_buffer.c | 338 ++++++++++++++++++++++++++++++++++++++++ runtime/transport/transport.c | 29 ++-- runtime/transport/transport.h | 4 + 4 files changed, 363 insertions(+), 10 deletions(-) create mode 100644 runtime/transport/ring_buffer.c (limited to 'runtime') diff --git a/runtime/runtime.h b/runtime/runtime.h index 25456beb..28283db6 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -47,6 +47,8 @@ static void _stp_dbug (const char *func, int line, const char *fmt, ...); static void _stp_error (const char *fmt, ...); static void _stp_warn (const char *fmt, ...); +static void _stp_exit(void); + #include "debug.h" /* atomic globals */ diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c new file mode 100644 index 00000000..53149fcd --- /dev/null +++ b/runtime/transport/ring_buffer.c @@ -0,0 +1,338 @@ +#include +#include + +static struct ring_buffer *__stp_ring_buffer = NULL; +//DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); + +static void __stp_free_ring_buffer(void) +{ + 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; + + dbug_trans(1, "%lu\n", buffer_size); + __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); + if (!__stp_ring_buffer) + goto fail; + +// DRS: do we need this? +#if 0 + for_each_possible_cpu(i) { + struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); + + b->last_task = NULL; + b->last_is_kernel = -1; + b->tracing = 0; + b->buffer_size = buffer_size; + b->sample_received = 0; + b->sample_lost_overflow = 0; + b->backtrace_aborted = 0; + b->sample_invalid_eip = 0; + b->cpu = i; + INIT_DELAYED_WORK(&b->work, wq_sync_buffer); + } +#endif + return 0; + +fail: + __stp_free_ring_buffer(); + return -ENOMEM; +} + + +static atomic_t _stp_trace_attached = ATOMIC_INIT(0); +static struct trace_iterator _stp_trace_iter; + +static int _stp_data_open_trace(struct inode *inode, struct file *file) +{ + /* We only allow for one reader */ + dbug_trans(1, "trace attach\n"); + if (atomic_inc_return(&_stp_trace_attached) != 1) { + atomic_dec(&_stp_trace_attached); + dbug_trans(1, "returning EBUSY\n"); + return -EBUSY; + } + + file->private_data = &_stp_trace_iter; + return 0; +} + +static int _stp_data_release_trace(struct inode *inode, struct file *file) +{ + dbug_trans(1, "trace detach\n"); + atomic_dec(&_stp_trace_attached); + return 0; +} + +struct trace_seq { + unsigned char buffer[PAGE_SIZE]; + unsigned int len; + unsigned int readpos; +}; + +ssize_t +_stp_trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) +{ + int len; + int ret; + + dbug_trans(1, "s: %p\n", s); + if (s == NULL) + return -EFAULT; + + dbug_trans(1, "len: %d, readpos: %d, buffer: %p\n", s->len, + s->readpos, s->buffer); + if (s->len <= s->readpos) + return -EBUSY; + + len = s->len - s->readpos; + if (cnt > len) + cnt = len; + ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt); + if (ret) + return -EFAULT; + + s->readpos += len; + return cnt; +} + +static void +trace_seq_reset(struct trace_seq *s) +{ + s->len = 0; + s->readpos = 0; +} + +/* + * Trace iterator - used by printout routines who present trace + * results to users and which routines might sleep, etc: + */ +struct trace_iterator { +#if 0 + struct trace_array *tr; + struct tracer *trace; + void *private; +#endif + struct ring_buffer_iter *buffer_iter[NR_CPUS]; + + /* The below is zeroed out in pipe_read */ + struct trace_seq seq; +#if 0 + struct trace_entry *ent; + int cpu; + u64 ts; + + unsigned long iter_flags; +#endif + loff_t pos; +#if 0 + long idx; + + cpumask_var_t started; +#endif +}; + +static int trace_empty(struct trace_iterator *iter) +{ + int cpu; + + for_each_possible_cpu(cpu) { + if (iter->buffer_iter[cpu]) { + if (!ring_buffer_iter_empty(iter->buffer_iter[cpu])) + return 0; +#if 0 + } else { + if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) + return 0; +#endif + } + } + + return 1; +} + +/* Must be called with trace_types_lock mutex held. */ +static int tracing_wait_pipe(struct file *filp) +{ + struct trace_iterator *iter = filp->private_data; + + while (trace_empty(iter)) { + + if ((filp->f_flags & O_NONBLOCK)) { + 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)) { + return -EINTR; + } + +#if 0 + if (iter->trace != current_trace) + return 0; + + /* + * We block until we read something and tracing is disabled. + * We still block if tracing is disabled, but we have never + * read anything. This allows a user to cat this file, and + * then enable tracing. But after we have read something, + * we give an EOF when tracing is again disabled. + * + * iter->pos will be 0 if we haven't read anything. + */ + if (!tracer_enabled && iter->pos) + break; +#else + if (iter->pos) + break; +#endif + + continue; + } + + return 1; +} + +/* + * Consumer reader. + */ +static ssize_t +_stp_data_read_trace(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + struct trace_iterator *iter = filp->private_data; + ssize_t sret; + + /* return any leftover data */ + dbug_trans(1, "%lu\n", (unsigned long)cnt); + sret = _stp_trace_seq_to_user(&iter->seq, ubuf, cnt); + if (sret != -EBUSY) + return sret; + + trace_seq_reset(&iter->seq); + +waitagain: + sret = tracing_wait_pipe(filp); + if (sret <= 0) + goto out; + + /* stop when tracing is finished */ + if (trace_empty(iter)) { + sret = 0; + goto out; + } + + if (cnt >= PAGE_SIZE) + cnt = PAGE_SIZE - 1; + + /* reset all but tr, trace, and overruns */ + memset(&iter->seq, 0, + sizeof(struct trace_iterator) - + offsetof(struct trace_iterator, seq)); + iter->pos = -1; + +#if 0 + while (find_next_entry_inc(iter) != NULL) { + enum print_line_t ret; + int len = iter->seq.len; + + ret = print_trace_line(iter); + if (ret == TRACE_TYPE_PARTIAL_LINE) { + /* don't print partial lines */ + iter->seq.len = len; + break; + } + if (ret != TRACE_TYPE_NO_CONSUME) + trace_consume(iter); + + if (iter->seq.len >= cnt) + break; + } +#endif + + /* Now copy what we have to the user */ + sret = _stp_trace_seq_to_user(&iter->seq, ubuf, cnt); + if (iter->seq.readpos >= iter->seq.len) + trace_seq_reset(&iter->seq); + + /* + * If there was nothing to send to user, inspite of consuming trace + * entries, go back to wait for more entries. + */ + if (sret == -EBUSY) + goto waitagain; + +out: + return sret; +} + +static struct file_operations __stp_data_fops = { + .owner = THIS_MODULE, + .open = _stp_data_open_trace, + .release = _stp_data_release_trace, +#if 0 + .poll = tracing_poll_pipe, +#endif + .read = _stp_data_read_trace, +#if 0 + .splice_read = tracing_splice_read_pipe, +#endif +}; + +static struct dentry *__stp_entry; + +static int _stp_transport_data_fs_init(void) +{ + int rc; + + // allocate buffer + dbug_trans(1, "entry...\n"); + rc = __stp_alloc_ring_buffer(); + if (rc != 0) + return rc; + + // create file(s) + __stp_entry = debugfs_create_file("trace", 0600, _stp_get_module_dir(), + NULL, &__stp_data_fops); + if (!__stp_entry) + pr_warning("Could not create debugfs 'trace' entry\n"); + else { + __stp_entry->d_inode->i_uid = _stp_uid; + __stp_entry->d_inode->i_gid = _stp_gid; + } + + dbug_trans(1, "returning 0...\n"); + return 0; +} + +static void _stp_transport_data_fs_close(void) +{ + if (__stp_entry) + debugfs_remove(__stp_entry); + __stp_entry = NULL; + + __stp_free_ring_buffer(); +} + diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 12e98a38..093d8b7b 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -19,11 +19,6 @@ #include #include -struct utt_trace { - int dummy; -}; -//static struct utt_trace *_stp_utt = NULL; - static void utt_set_overwrite(int overwrite) { return; @@ -59,6 +54,7 @@ static unsigned int utt_seq = 1; #include "control.h" #include "debugfs.c" #include "control.c" +#include "ring_buffer.c" #endif /* if 0 */ static unsigned _stp_nsubbufs = 8; static unsigned _stp_subbuf_size = 65536*4; @@ -71,9 +67,6 @@ MODULE_PARM_DESC(_stp_bufsize, "buffer size"); /* forward declarations */ static void probe_exit(void); static int probe_start(void); -#if 0 -static void _stp_exit(void); -#endif /* #if 0 */ /* check for new workqueue API */ #ifdef DECLARE_DELAYED_WORK @@ -287,8 +280,8 @@ static int _stp_transport_init(void) dbug_trans(1, "Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size); } - if (_stp_transport_fs_init(THIS_MODULE->name)) - return -1; + if (_stp_transport_fs_init(THIS_MODULE->name) != 0) + goto err0; #if 0 #if !defined (STP_OLD_TRANSPORT) || defined (STP_BULKMODE) @@ -297,6 +290,7 @@ static int _stp_transport_init(void) if (!_stp_utt) goto err0; #endif +#else /* #if 0 */ #endif /* #if 0 */ /* create control channel */ @@ -322,20 +316,25 @@ static int _stp_transport_init(void) _stp_ctl_send(STP_TRANSPORT, NULL, 0); #endif /* #if 0 */ + dbug_trans(1, "returning 0...\n"); return 0; err3: + dbug_trans(1, "err3\n"); _stp_print_cleanup(); err2: + dbug_trans(1, "err2\n"); _stp_unregister_ctl_channel(); err1: #if 0 if (_stp_utt) utt_trace_remove(_stp_utt); #else + dbug_trans(1, "err1\n"); _stp_transport_fs_close(); #endif /* #if 0 */ err0: + dbug_trans(1, "err0\n"); return -1; } @@ -469,6 +468,7 @@ static int _stp_transport_fs_init(const char *module_name) { struct dentry *root_dir; + dbug_trans(1, "entry\n"); if (module_name == NULL) return -1; @@ -481,12 +481,21 @@ static int _stp_transport_fs_init(const char *module_name) _stp_remove_root_dir(); return -1; } + + if (_stp_transport_data_fs_init() != 0) { + _stp_remove_root_dir(); + return -1; + } + dbug_trans(1, "returning 0\n"); return 0; } static void _stp_transport_fs_close(void) { dbug_trans(1, "stp_transport_fs_close\n"); + + _stp_transport_data_fs_close(); + if (__stp_module_dir) { debugfs_remove(__stp_module_dir); __stp_module_dir = NULL; diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index dec23c72..c79549d4 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -60,4 +60,8 @@ static gid_t _stp_gid; static int _stp_ctl_attached; +static int _stp_bufsize; +static int _stp_transport_data_fs_init(void); +static void _stp_transport_data_fs_close(void); + #endif /* _TRANSPORT_TRANSPORT_H_ */ -- cgit From eb3101a40fe446cffab677a7d117f028bae9afba Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 9 Mar 2009 10:06:20 -0500 Subject: First working version that actually produces output. 2009-03-09 David Smith * print_new.c (stp_print_flush): Calls _stp_data_write_reserve() and _stp_data_write_commit(). * transport/ring_buffer.c (__stp_alloc_ring_buffer): Sets up a default buffer size of STP_BUFFER_SIZE; (trace_seq_reset): New function. (peek_next_entry): New function. (__find_next_entry): New function. (find_next_entry_inc): New function. (_stp_data_read_trace): Uses find_next_entry_inc() to get the next entry, then calls _stp_entry_to_user() to copy it to the user's buffer, then calls ring_buffer_consume() to consume it. (_stp_data_write_reserve): New function. (_stp_data_write_commit): New function. * transport/transport.c (_stp_transport_close): Calls functions that were ifdef'ed out. * transport/transport.h (struct _stp_entry): Added _stp_entry definition and _stp_data_write_reserve()/_stp_data_write_commit() prototypes. --- runtime/print_new.c | 17 +-- runtime/transport/ring_buffer.c | 302 ++++++++++++++++++++++++++++++++-------- runtime/transport/transport.c | 6 - runtime/transport/transport.h | 9 ++ 4 files changed, 262 insertions(+), 72 deletions(-) (limited to 'runtime') diff --git a/runtime/print_new.c b/runtime/print_new.c index bebaa19c..2759ebcf 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -23,6 +23,7 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) uint32_t len = pb->len; /* check to see if there is anything in the buffer */ + dbug_trans(1, "len = %ud\n", len); if (likely (len == 0)) return; @@ -54,16 +55,16 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) } #else { - void *buf; + struct _stp_entry *entry; unsigned long flags; + + dbug_trans(1, "calling _stp_data_write...\n"); spin_lock_irqsave(&_stp_print_lock, flags); -#if 0 - buf = utt_reserve(_stp_utt, len); -#else - buf = NULL; -#endif - if (likely(buf)) - memcpy(buf, pb->buf, len); + entry = _stp_data_write_reserve(len); + if (likely(entry)) { + memcpy(entry->buf, pb->buf, len); + _stp_data_write_commit(entry); + } else atomic_inc (&_stp_transport_failures); spin_unlock_irqrestore(&_stp_print_lock, flags); diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 53149fcd..8b176ae3 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -4,8 +4,58 @@ static struct ring_buffer *__stp_ring_buffer = NULL; //DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); +#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; +#else +static struct ring_buffer_iter *__stp_ring_buffer_iter[NR_CPUS]; +#endif + static void __stp_free_ring_buffer(void) { + int i; + +#if 0 + if (__stp_ring_buffer) { + ring_buffer_record_disable(__stp_ring_buffer); + for_each_possible_cpu(i) { + ring_buffer_record_disable_cpu(__stp_ring_buffer, i); + } + } +#endif + +#if 0 + for_each_possible_cpu(i) { + if (__stp_ring_buffer_iter[i]) + ring_buffer_read_finish(__stp_ring_buffer_iter[i]); + } +#endif + if (__stp_ring_buffer) ring_buffer_free(__stp_ring_buffer); __stp_ring_buffer = NULL; @@ -16,11 +66,22 @@ static int __stp_alloc_ring_buffer(void) int i; unsigned long buffer_size = _stp_bufsize; + if (buffer_size == 0) + buffer_size = STP_BUFFER_SIZE; dbug_trans(1, "%lu\n", buffer_size); __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); if (!__stp_ring_buffer) goto fail; +#if 0 + dbug_trans(1, "enabling recording...\n"); + ring_buffer_record_enable(__stp_ring_buffer); + for_each_possible_cpu(i) { + ring_buffer_record_enable_cpu(__stp_ring_buffer, i); + } +#endif + + // DRS: do we need this? #if 0 for_each_possible_cpu(i) { @@ -37,7 +98,24 @@ static int __stp_alloc_ring_buffer(void) b->cpu = i; INIT_DELAYED_WORK(&b->work, wq_sync_buffer); } + + /* Allocate the first page for all buffers */ + for_each_possible_cpu(i) { + data = global_trace.data[i] = &per_cpu(global_trace_cpu, i); + max_tr.data[i] = &per_cpu(max_data, i); + } #endif + +#if 0 + for_each_possible_cpu(i) { + __stp_ring_buffer_iter[i] = + ring_buffer_read_start(__stp_ring_buffer, i); + + if (!__stp_ring_buffer_iter[i]) + goto fail; + } +#endif + return 0; fail: @@ -47,7 +125,6 @@ fail: static atomic_t _stp_trace_attached = ATOMIC_INIT(0); -static struct trace_iterator _stp_trace_iter; static int _stp_data_open_trace(struct inode *inode, struct file *file) { @@ -59,7 +136,7 @@ static int _stp_data_open_trace(struct inode *inode, struct file *file) return -EBUSY; } - file->private_data = &_stp_trace_iter; +// file->private_data = &_stp_trace_iter; return 0; } @@ -102,6 +179,28 @@ _stp_trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) return cnt; } +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 void trace_seq_reset(struct trace_seq *s) { @@ -109,6 +208,7 @@ trace_seq_reset(struct trace_seq *s) s->readpos = 0; } +#if 0 /* * Trace iterator - used by printout routines who present trace * results to users and which routines might sleep, etc: @@ -137,34 +237,37 @@ struct trace_iterator { cpumask_var_t started; #endif }; +#endif -static int trace_empty(struct trace_iterator *iter) +#if 0 +static int _stp_data_empty(void) { int cpu; for_each_possible_cpu(cpu) { - if (iter->buffer_iter[cpu]) { - if (!ring_buffer_iter_empty(iter->buffer_iter[cpu])) - return 0; #if 0 - } else { - if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) + if (__stp_ring_buffer_iter[cpu]) { + if (!ring_buffer_iter_empty(__stp_ring_buffer_iter[cpu])) return 0; -#endif } +#else + if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) + return 0; +#endif } return 1; } +#endif /* Must be called with trace_types_lock mutex held. */ -static int tracing_wait_pipe(struct file *filp) +static ssize_t tracing_wait_pipe(struct file *filp) { - struct trace_iterator *iter = filp->private_data; - - while (trace_empty(iter)) { +// while (_stp_data_empty()) { + while (ring_buffer_empty(__stp_ring_buffer)) { if ((filp->f_flags & O_NONBLOCK)) { + dbug_trans(1, "returning -EAGAIN\n"); return -EAGAIN; } @@ -186,6 +289,7 @@ static int tracing_wait_pipe(struct file *filp) //iter->tr->waiter = NULL; if (signal_pending(current)) { + dbug_trans(1, "returning -EINTR\n"); return -EINTR; } @@ -204,17 +308,71 @@ static int tracing_wait_pipe(struct file *filp) */ if (!tracer_enabled && iter->pos) break; -#else - if (iter->pos) - break; #endif continue; } + 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 * +__find_next_entry(int *ent_cpu, u64 *ent_ts) +{ + struct _stp_entry *ent, *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; +} + +/* Find the next real entry, and increment the iterator to the next entry */ +static struct _stp_entry *find_next_entry_inc(void) +{ + return __find_next_entry(&_stp_iter.cpu, &_stp_iter.ts); + +// if (iter->ent) +// trace_iterator_increment(iter); + +// return iter->ent ? iter : NULL; +} + + /* * Consumer reader. */ @@ -222,24 +380,18 @@ static ssize_t _stp_data_read_trace(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { - struct trace_iterator *iter = filp->private_data; ssize_t sret; + struct _stp_entry *entry; - /* return any leftover data */ dbug_trans(1, "%lu\n", (unsigned long)cnt); - sret = _stp_trace_seq_to_user(&iter->seq, ubuf, cnt); - if (sret != -EBUSY) - return sret; - - trace_seq_reset(&iter->seq); -waitagain: 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 (trace_empty(iter)) { + if (ring_buffer_empty(__stp_ring_buffer)) { sret = 0; goto out; } @@ -247,43 +399,23 @@ waitagain: if (cnt >= PAGE_SIZE) cnt = PAGE_SIZE - 1; - /* reset all but tr, trace, and overruns */ - memset(&iter->seq, 0, - sizeof(struct trace_iterator) - - offsetof(struct trace_iterator, seq)); - iter->pos = -1; + dbug_trans(1, "sret = %lu\n", (unsigned long)sret); + sret = 0; + while ((entry = find_next_entry_inc()) != NULL) { + ssize_t len; -#if 0 - while (find_next_entry_inc(iter) != NULL) { - enum print_line_t ret; - int len = iter->seq.len; - - ret = print_trace_line(iter); - if (ret == TRACE_TYPE_PARTIAL_LINE) { - /* don't print partial lines */ - iter->seq.len = len; + len = _stp_entry_to_user(entry, ubuf, cnt); + if (len <= 0) break; - } - if (ret != TRACE_TYPE_NO_CONSUME) - trace_consume(iter); - if (iter->seq.len >= cnt) + ring_buffer_consume(__stp_ring_buffer, _stp_iter.cpu, + &_stp_iter.ts); + ubuf += len; + cnt -= len; + sret += len; + if (cnt <= 0) break; } -#endif - - /* Now copy what we have to the user */ - sret = _stp_trace_seq_to_user(&iter->seq, ubuf, cnt); - if (iter->seq.readpos >= iter->seq.len) - trace_seq_reset(&iter->seq); - - /* - * If there was nothing to send to user, inspite of consuming trace - * entries, go back to wait for more entries. - */ - if (sret == -EBUSY) - goto waitagain; - out: return sret; } @@ -301,6 +433,59 @@ static struct file_operations __stp_data_fops = { #endif }; +/* + * 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 struct _stp_entry * +_stp_data_write_reserve(size_t size) +{ + struct ring_buffer_event *event; + struct _stp_entry *entry; + + event = ring_buffer_lock_reserve(__stp_ring_buffer, + (sizeof(struct _stp_entry) + size), + 0); + if (unlikely(! event)) { + dbug_trans(1, "event = NULL (%p)?\n", event); + return NULL; + } + + entry = ring_buffer_event_data(event); + entry->event = event; + entry->len = size; + return entry; +} + +static int _stp_data_write_commit(struct _stp_entry *entry) +{ + if (unlikely(! entry)) { + dbug_trans(1, "entry = NULL, returning -EINVAL\n"); + return -EINVAL; + } + +#if 0 + return ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); +#else + { + int ret; + 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)); + return ret; + } +#endif +} + + static struct dentry *__stp_entry; static int _stp_transport_data_fs_init(void) @@ -314,7 +499,8 @@ static int _stp_transport_data_fs_init(void) return rc; // create file(s) - __stp_entry = debugfs_create_file("trace", 0600, _stp_get_module_dir(), + __stp_entry = debugfs_create_file("trace0", 0600, + _stp_get_module_dir(), NULL, &__stp_data_fops); if (!__stp_entry) pr_warning("Could not create debugfs 'trace' entry\n"); diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 093d8b7b..c4c9da1e 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -209,9 +209,7 @@ static void _stp_transport_close(void) { dbug_trans(1, "%d: ************** transport_close *************\n", current->pid); -#if 0 _stp_cleanup_and_exit(0); -#endif /* #if 0 */ destroy_workqueue(_stp_wq); _stp_unregister_ctl_channel(); #if 0 @@ -219,9 +217,7 @@ static void _stp_transport_close(void) utt_trace_remove(_stp_utt); #endif /* #if 0 */ _stp_print_cleanup(); /* free print buffers */ -#if 0 _stp_mem_debug_done(); -#endif /* #if 0 */ _stp_transport_fs_close(); dbug_trans(1, "---- CLOSED ----\n"); @@ -311,10 +307,8 @@ static int _stp_transport_init(void) if (!_stp_wq) goto err3; -#if 0 /* Signal stapio to send us STP_START back (XXX: ?!?!?!). */ _stp_ctl_send(STP_TRANSPORT, NULL, 0); -#endif /* #if 0 */ dbug_trans(1, "returning 0...\n"); return 0; diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index c79549d4..feaa950c 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -64,4 +64,13 @@ static int _stp_bufsize; static int _stp_transport_data_fs_init(void); static void _stp_transport_data_fs_close(void); +struct _stp_entry { + void *event; + size_t len; + char buf[]; +}; + +static struct _stp_entry *_stp_data_write_reserve(size_t size); +static int _stp_data_write_commit(struct _stp_entry *entry); + #endif /* _TRANSPORT_TRANSPORT_H_ */ -- cgit From ef20115ab2d3d5d1a2e9fca84eff53c7430a24c6 Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 9 Mar 2009 14:25:10 -0500 Subject: Cleanup. --- runtime/transport/ring_buffer.c | 177 ++++------------------------------------ 1 file changed, 15 insertions(+), 162 deletions(-) (limited to 'runtime') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 8b176ae3..af171d04 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -32,30 +32,10 @@ struct _stp_ring_buffer_iterator { #endif }; static struct _stp_ring_buffer_iterator _stp_iter; -#else -static struct ring_buffer_iter *__stp_ring_buffer_iter[NR_CPUS]; #endif static void __stp_free_ring_buffer(void) { - int i; - -#if 0 - if (__stp_ring_buffer) { - ring_buffer_record_disable(__stp_ring_buffer); - for_each_possible_cpu(i) { - ring_buffer_record_disable_cpu(__stp_ring_buffer, i); - } - } -#endif - -#if 0 - for_each_possible_cpu(i) { - if (__stp_ring_buffer_iter[i]) - ring_buffer_read_finish(__stp_ring_buffer_iter[i]); - } -#endif - if (__stp_ring_buffer) ring_buffer_free(__stp_ring_buffer); __stp_ring_buffer = NULL; @@ -73,49 +53,6 @@ static int __stp_alloc_ring_buffer(void) if (!__stp_ring_buffer) goto fail; -#if 0 - dbug_trans(1, "enabling recording...\n"); - ring_buffer_record_enable(__stp_ring_buffer); - for_each_possible_cpu(i) { - ring_buffer_record_enable_cpu(__stp_ring_buffer, i); - } -#endif - - -// DRS: do we need this? -#if 0 - for_each_possible_cpu(i) { - struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); - - b->last_task = NULL; - b->last_is_kernel = -1; - b->tracing = 0; - b->buffer_size = buffer_size; - b->sample_received = 0; - b->sample_lost_overflow = 0; - b->backtrace_aborted = 0; - b->sample_invalid_eip = 0; - b->cpu = i; - INIT_DELAYED_WORK(&b->work, wq_sync_buffer); - } - - /* Allocate the first page for all buffers */ - for_each_possible_cpu(i) { - data = global_trace.data[i] = &per_cpu(global_trace_cpu, i); - max_tr.data[i] = &per_cpu(max_data, i); - } -#endif - -#if 0 - for_each_possible_cpu(i) { - __stp_ring_buffer_iter[i] = - ring_buffer_read_start(__stp_ring_buffer, i); - - if (!__stp_ring_buffer_iter[i]) - goto fail; - } -#endif - return 0; fail: @@ -123,7 +60,6 @@ fail: return -ENOMEM; } - static atomic_t _stp_trace_attached = ATOMIC_INIT(0); static int _stp_data_open_trace(struct inode *inode, struct file *file) @@ -136,7 +72,6 @@ static int _stp_data_open_trace(struct inode *inode, struct file *file) return -EBUSY; } -// file->private_data = &_stp_trace_iter; return 0; } @@ -208,62 +143,8 @@ trace_seq_reset(struct trace_seq *s) s->readpos = 0; } -#if 0 -/* - * Trace iterator - used by printout routines who present trace - * results to users and which routines might sleep, etc: - */ -struct trace_iterator { -#if 0 - struct trace_array *tr; - struct tracer *trace; - void *private; -#endif - struct ring_buffer_iter *buffer_iter[NR_CPUS]; - - /* The below is zeroed out in pipe_read */ - struct trace_seq seq; -#if 0 - struct trace_entry *ent; - int cpu; - u64 ts; - - unsigned long iter_flags; -#endif - loff_t pos; -#if 0 - long idx; - - cpumask_var_t started; -#endif -}; -#endif - -#if 0 -static int _stp_data_empty(void) -{ - int cpu; - - for_each_possible_cpu(cpu) { -#if 0 - if (__stp_ring_buffer_iter[cpu]) { - if (!ring_buffer_iter_empty(__stp_ring_buffer_iter[cpu])) - return 0; - } -#else - if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) - return 0; -#endif - } - - return 1; -} -#endif - -/* Must be called with trace_types_lock mutex held. */ static ssize_t tracing_wait_pipe(struct file *filp) { -// while (_stp_data_empty()) { while (ring_buffer_empty(__stp_ring_buffer)) { if ((filp->f_flags & O_NONBLOCK)) { @@ -292,25 +173,6 @@ static ssize_t tracing_wait_pipe(struct file *filp) dbug_trans(1, "returning -EINTR\n"); return -EINTR; } - -#if 0 - if (iter->trace != current_trace) - return 0; - - /* - * We block until we read something and tracing is disabled. - * We still block if tracing is disabled, but we have never - * read anything. This allows a user to cat this file, and - * then enable tracing. But after we have read something, - * we give an EOF when tracing is again disabled. - * - * iter->pos will be 0 if we haven't read anything. - */ - if (!tracer_enabled && iter->pos) - break; -#endif - - continue; } dbug_trans(1, "returning 1\n"); @@ -362,14 +224,9 @@ __find_next_entry(int *ent_cpu, u64 *ent_ts) } /* Find the next real entry, and increment the iterator to the next entry */ -static struct _stp_entry *find_next_entry_inc(void) +static struct _stp_entry *find_next_entry(void) { return __find_next_entry(&_stp_iter.cpu, &_stp_iter.ts); - -// if (iter->ent) -// trace_iterator_increment(iter); - -// return iter->ent ? iter : NULL; } @@ -401,7 +258,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, dbug_trans(1, "sret = %lu\n", (unsigned long)sret); sret = 0; - while ((entry = find_next_entry_inc()) != NULL) { + while ((entry = find_next_entry) != NULL) { ssize_t len; len = _stp_entry_to_user(entry, ubuf, cnt); @@ -421,9 +278,9 @@ out: } static struct file_operations __stp_data_fops = { - .owner = THIS_MODULE, - .open = _stp_data_open_trace, - .release = _stp_data_release_trace, + .owner = THIS_MODULE, + .open = _stp_data_open_trace, + .release = _stp_data_release_trace, #if 0 .poll = tracing_poll_pipe, #endif @@ -467,22 +324,18 @@ _stp_data_write_reserve(size_t size) static int _stp_data_write_commit(struct _stp_entry *entry) { - if (unlikely(! entry)) { - dbug_trans(1, "entry = NULL, returning -EINVAL\n"); - return -EINVAL; - } + int ret; -#if 0 - return ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); -#else - { - int ret; - 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)); - return ret; + if (unlikely(! entry)) { + dbug_trans(1, "entry = NULL, returning -EINVAL\n"); + return -EINVAL; } -#endif + + 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)); + + return ret; } -- cgit From 49f34ab20c2afd95b6a34a904563d456d6deb1d1 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 11 Mar 2009 12:54:19 -0500 Subject: Handles polling and breaks down large buffers. 2009-03-11 David Smith * print_new.c (stp_print_flush): Breaks up the buffer into smaller pieces (since the ring_buffer likes lots of small events, not one large one). * transport/ring_buffer.c (__stp_alloc_ring_buffer): Reserves space for struct _stp_entry. (_stp_data_poll_trace): New function. (_stp_data_write_commit): Wakes up any tasks waiting on data. --- runtime/print_new.c | 30 +++++++++++++++++++++++++++++- runtime/transport/ring_buffer.c | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 8 deletions(-) (limited to 'runtime') diff --git a/runtime/print_new.c b/runtime/print_new.c index 2759ebcf..4e579c37 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -60,13 +60,41 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) dbug_trans(1, "calling _stp_data_write...\n"); spin_lock_irqsave(&_stp_print_lock, flags); +#if 0 entry = _stp_data_write_reserve(len); if (likely(entry)) { memcpy(entry->buf, pb->buf, len); _stp_data_write_commit(entry); } else - atomic_inc (&_stp_transport_failures); +#endif + { + uint32_t cnt; + char *bufp = pb->buf; + +#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 8) + while (len > 0) { + if (len > MAX_RESERVE_SIZE) { + len -= MAX_RESERVE_SIZE; + cnt = MAX_RESERVE_SIZE; + } + else { + cnt = len; + len = 0; + } + + entry = _stp_data_write_reserve(cnt); + if (likely(entry)) { + memcpy(entry->buf, bufp, cnt); + _stp_data_write_commit(entry); + bufp += cnt; + } + else { + atomic_inc (&_stp_transport_failures); + break; + } + } + } spin_unlock_irqrestore(&_stp_print_lock, flags); } #endif /* STP_BULKMODE */ diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index af171d04..cab8c2fa 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -1,9 +1,15 @@ #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 @@ -46,13 +52,17 @@ static int __stp_alloc_ring_buffer(void) int i; unsigned long buffer_size = _stp_bufsize; - if (buffer_size == 0) - buffer_size = STP_BUFFER_SIZE; + if (buffer_size == 0) { + dbug_trans(1, "using default buffer size...\n"); + buffer_size = STP_BUFFER_SIZE + + (4000 * sizeof(struct _stp_entry)); + } 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: @@ -224,7 +234,7 @@ __find_next_entry(int *ent_cpu, u64 *ent_ts) } /* Find the next real entry, and increment the iterator to the next entry */ -static struct _stp_entry *find_next_entry(void) +static struct _stp_entry *_stp_find_next_entry(void) { return __find_next_entry(&_stp_iter.cpu, &_stp_iter.ts); } @@ -258,7 +268,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, dbug_trans(1, "sret = %lu\n", (unsigned long)sret); sret = 0; - while ((entry = find_next_entry) != NULL) { + while ((entry = _stp_find_next_entry()) != NULL) { ssize_t len; len = _stp_entry_to_user(entry, ubuf, cnt); @@ -277,13 +287,26 @@ 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, -#if 0 - .poll = tracing_poll_pipe, -#endif + .poll = _stp_data_poll_trace, .read = _stp_data_read_trace, #if 0 .splice_read = tracing_splice_read_pipe, @@ -335,6 +358,7 @@ static int _stp_data_write_commit(struct _stp_entry *entry) dbug_trans(1, "after commit, empty returns %d\n", ring_buffer_empty(__stp_ring_buffer)); + wake_up_interruptible(&_stp_poll_wait); return ret; } -- cgit From 12659e2d5eea60a6c1021effa7776bc8e58bb508 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 11 Mar 2009 16:10:14 -0500 Subject: Small update. 2009-03-11 David Smith * print_new.c (stp_print_flush): Updated MAX_RESERVE_SIZE. * transport/ring_buffer.c (__stp_alloc_ring_buffer): Reserves more space. --- runtime/print_new.c | 2 +- runtime/transport/ring_buffer.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'runtime') diff --git a/runtime/print_new.c b/runtime/print_new.c index 4e579c37..4857b301 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -72,7 +72,7 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) uint32_t cnt; char *bufp = pb->buf; -#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 8) +#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) while (len > 0) { if (len > MAX_RESERVE_SIZE) { len -= MAX_RESERVE_SIZE; diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index cab8c2fa..4295a37b 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -54,8 +54,7 @@ static int __stp_alloc_ring_buffer(void) if (buffer_size == 0) { dbug_trans(1, "using default buffer size...\n"); - buffer_size = STP_BUFFER_SIZE - + (4000 * sizeof(struct _stp_entry)); + buffer_size = STP_BUFFER_SIZE * 30; } dbug_trans(1, "%lu\n", buffer_size); __stp_ring_buffer = ring_buffer_alloc(buffer_size, 0); -- cgit From 976f6b6a6fae081d1d72d06457d64af87db789ef Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 12 Mar 2009 12:57:31 -0500 Subject: Updated buffer size. 2009-03-12 David Smith * transport/ring_buffer.c (__stp_alloc_ring_buffer): Updated buffer size. --- runtime/transport/ring_buffer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'runtime') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 4295a37b..51e9efa2 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -54,8 +54,12 @@ static int __stp_alloc_ring_buffer(void) if (buffer_size == 0) { dbug_trans(1, "using default buffer size...\n"); - buffer_size = STP_BUFFER_SIZE * 30; + 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) -- cgit From c24cd76e91647ebdf98445439083c1b0e0a65dd4 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 12 Mar 2009 16:16:16 -0500 Subject: Start of STP_BULKMODE support. 2009-03-12 David Smith * transport/ring_buffer.c (_stp_transport_data_fs_init): Start of STP_BULKMODE support - creates one trace file per cpu. (_stp_transport_data_fs_close): Cleans up one trace file per cpu. --- runtime/transport/ring_buffer.c | 50 +++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 12 deletions(-) (limited to 'runtime') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 51e9efa2..22e62cdf 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -3,6 +3,10 @@ #include #include +#ifdef STP_BULKMODE +#error "bulkmode support unfinished..." +#endif + static struct ring_buffer *__stp_ring_buffer = NULL; //DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); @@ -366,11 +370,12 @@ static int _stp_data_write_commit(struct _stp_entry *entry) } -static struct dentry *__stp_entry; +static struct dentry *__stp_entry[NR_CPUS] = { NULL }; static int _stp_transport_data_fs_init(void) { int rc; + long cpu; // allocate buffer dbug_trans(1, "entry...\n"); @@ -379,14 +384,31 @@ static int _stp_transport_data_fs_init(void) return rc; // create file(s) - __stp_entry = debugfs_create_file("trace0", 0600, - _stp_get_module_dir(), - NULL, &__stp_data_fops); - if (!__stp_entry) - pr_warning("Could not create debugfs 'trace' entry\n"); - else { - __stp_entry->d_inode->i_uid = _stp_uid; - __stp_entry->d_inode->i_gid = _stp_gid; + for_each_possible_cpu(cpu) { + char cpu_file[9]; /* 5(trace) + 3(XXX) + 1(\0) = 9 */ + + if (cpu > 999 || cpu < 0) { + _stp_transport_data_fs_close(); + return -EINVAL; + } + sprintf(cpu_file, "trace%ld", cpu); + __stp_entry[cpu] = debugfs_create_file(cpu_file, 0600, + _stp_get_module_dir(), + (void *)cpu, + &__stp_data_fops); + + if (!__stp_entry[cpu]) { + pr_warning("Could not create debugfs 'trace' entry\n"); + __stp_free_ring_buffer(); + return -ENOENT; + } + __stp_entry[cpu]->d_inode->i_uid = _stp_uid; + __stp_entry[cpu]->d_inode->i_gid = _stp_gid; + +#ifndef STP_BULKMODE + if (cpu != 0) + break; +#endif } dbug_trans(1, "returning 0...\n"); @@ -395,9 +417,13 @@ static int _stp_transport_data_fs_init(void) static void _stp_transport_data_fs_close(void) { - if (__stp_entry) - debugfs_remove(__stp_entry); - __stp_entry = NULL; + int cpu; + + for_each_possible_cpu(cpu) { + if (__stp_entry[cpu]) + debugfs_remove(__stp_entry[cpu]); + __stp_entry[cpu] = NULL; + } __stp_free_ring_buffer(); } -- cgit From 8d1dd679bdbe3f4c40305fdbca0c1b4002913e87 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 13 Mar 2009 13:22:10 -0500 Subject: More bulkmode support. Only allows for one reader of all trace files. 2009-03-13 David Smith * transport/ring_buffer.c (__stp_free_ring_buffer): Frees _stp_trace_reader_cpumask. (__stp_alloc_ring_buffer): Allocates and clears _stp_trace_reader_cpumask. (_stp_data_open_trace): Instead of using an atomic variable, uses a cpumask variable to allow for only one reader of trace files. (_stp_data_release_trace): Clears cpumask when trace files are closed. --- runtime/transport/ring_buffer.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'runtime') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 22e62cdf..a933ff9a 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef STP_BULKMODE #error "bulkmode support unfinished..." @@ -44,8 +45,11 @@ struct _stp_ring_buffer_iterator { 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; @@ -56,6 +60,10 @@ 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; @@ -77,25 +85,39 @@ fail: return -ENOMEM; } -static atomic_t _stp_trace_attached = ATOMIC_INIT(0); - static int _stp_data_open_trace(struct inode *inode, struct file *file) { - /* We only allow for one reader */ + long cpu_file = (long) inode->i_private; + + /* We only allow for one reader per cpu */ dbug_trans(1, "trace attach\n"); - if (atomic_inc_return(&_stp_trace_attached) != 1) { - atomic_dec(&_stp_trace_attached); +#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 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"); - atomic_dec(&_stp_trace_attached); +#ifdef STP_BULKMODE + cpumask_clear_cpu(cpu_file, _stp_trace_reader_cpumask); +#else + cpumask_clear(_stp_trace_reader_cpumask); +#endif + return 0; } -- cgit From 325d52059ed170a698dd4d13e2b418e8e9ab0862 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 13 Mar 2009 14:22:56 -0500 Subject: More bulkmode support. 2009-03-13 David Smith * transport/ring_buffer.c (_stp_data_open_trace): Passes the inode's private data into the file's private data. (_stp_trace_seq_to_user): Deleted unused function. (trace_seq_reset): Ditto. (__stp_find_next_entry): Renamed and added bulkmode support. (_stp_find_next_entry): Updated call. (_stp_data_read_trace): Updated call. --- runtime/transport/ring_buffer.c | 67 ++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 44 deletions(-) (limited to 'runtime') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index a933ff9a..3ea29f95 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -105,6 +105,7 @@ static int _stp_data_open_trace(struct inode *inode, struct file *file) } cpumask_setall(_stp_trace_reader_cpumask); #endif + file->private_data = inode->i_private; return 0; } @@ -121,38 +122,6 @@ static int _stp_data_release_trace(struct inode *inode, struct file *file) return 0; } -struct trace_seq { - unsigned char buffer[PAGE_SIZE]; - unsigned int len; - unsigned int readpos; -}; - -ssize_t -_stp_trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) -{ - int len; - int ret; - - dbug_trans(1, "s: %p\n", s); - if (s == NULL) - return -EFAULT; - - dbug_trans(1, "len: %d, readpos: %d, buffer: %p\n", s->len, - s->readpos, s->buffer); - if (s->len <= s->readpos) - return -EBUSY; - - len = s->len - s->readpos; - if (cnt > len) - cnt = len; - ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt); - if (ret) - return -EFAULT; - - s->readpos += len; - return cnt; -} - size_t _stp_entry_to_user(struct _stp_entry *entry, char __user *ubuf, size_t cnt) { @@ -175,13 +144,6 @@ _stp_entry_to_user(struct _stp_entry *entry, char __user *ubuf, size_t cnt) return cnt; } -static void -trace_seq_reset(struct trace_seq *s) -{ - s->len = 0; - s->readpos = 0; -} - static ssize_t tracing_wait_pipe(struct file *filp) { while (ring_buffer_empty(__stp_ring_buffer)) { @@ -229,9 +191,24 @@ peek_next_entry(int cpu, u64 *ts) } static struct _stp_entry * -__find_next_entry(int *ent_cpu, u64 *ent_ts) +__stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) { - struct _stp_entry *ent, *next = NULL; + 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(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; @@ -260,12 +237,13 @@ __find_next_entry(int *ent_cpu, u64 *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(void) +static struct _stp_entry *_stp_find_next_entry(long cpu_file) { - return __find_next_entry(&_stp_iter.cpu, &_stp_iter.ts); + return __stp_find_next_entry(cpu_file, &_stp_iter.cpu, &_stp_iter.ts); } @@ -278,6 +256,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, { ssize_t sret; struct _stp_entry *entry; + long cpu_file = (long) filp->private_data; dbug_trans(1, "%lu\n", (unsigned long)cnt); @@ -297,7 +276,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, dbug_trans(1, "sret = %lu\n", (unsigned long)sret); sret = 0; - while ((entry = _stp_find_next_entry()) != NULL) { + while ((entry = _stp_find_next_entry(cpu_file)) != NULL) { ssize_t len; len = _stp_entry_to_user(entry, ubuf, cnt); -- cgit From 7d573b8d318836ef75d1f2888a50da230b7d83cc Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 13 Mar 2009 16:48:58 -0500 Subject: Working bulkmode support. 2009-03-13 David Smith * print_new.c (stp_print_flush): Added bulkmode support for new transport. * transport/ring_buffer.c (__stp_find_next_entry): Fixed syntax error in bulkmode code. (_stp_transport_data_fs_init): Changed 'for_each_possible_cpu()' to 'for_each_online_cpu()' so that non-online cpu's won't have a trace file created. --- runtime/print_new.c | 97 ++++++++++++++++++++++++++++++++++++++--- runtime/transport/ring_buffer.c | 8 +--- 2 files changed, 93 insertions(+), 12 deletions(-) (limited to 'runtime') diff --git a/runtime/print_new.c b/runtime/print_new.c index 4857b301..f8749842 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -33,15 +33,95 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) // if (unlikely(!_stp_utt || _stp_utt->trace_state != Utt_trace_running)) // return; +#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) #ifdef STP_BULKMODE { + struct _stp_entry *entry; #ifdef NO_PERCPU_HEADERS - void *buf = utt_reserve(_stp_utt, len); - if (likely(buf)) - memcpy(buf, pb->buf, len); - else - atomic_inc (&_stp_transport_failures); + { + uint32_t cnt; + char *bufp = pb->buf; + + printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", + __FUNCTION__, __LINE__, pb->len, len); + while (len > 0) { + if (len > MAX_RESERVE_SIZE) { + len -= MAX_RESERVE_SIZE; + cnt = MAX_RESERVE_SIZE; + } + else { + cnt = len; + len = 0; + } + + printk(KERN_ERR "%s:%d - reserving %d bytes\n", + __FUNCTION__, __LINE__, cnt); + entry = _stp_data_write_reserve(cnt); + if (likely(entry)) { + memcpy(entry->buf, bufp, cnt); + _stp_data_write_commit(entry); + bufp += cnt; + } + else { + atomic_inc (&_stp_transport_failures); + break; + } + } + } #else + +#undef MAX_RESERVE_SIZE +#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10 - sizeof(struct _stp_trace)) + { + uint32_t cnt; + char *bufp = pb->buf; + struct _stp_trace t = { .sequence = _stp_seq_inc(), + .pdu_len = len}; + + printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", + __FUNCTION__, __LINE__, pb->len, len); + + entry = _stp_data_write_reserve(sizeof(struct _stp_trace)); + if (likely(entry)) { + /* prevent unaligned access by using + * memcpy() */ + memcpy(entry->buf, &t, sizeof(t)); + _stp_data_write_commit(entry); + } + else { + atomic_inc (&_stp_transport_failures); + return; + } + + while (len > 0) { + if (len > MAX_RESERVE_SIZE) { + len -= MAX_RESERVE_SIZE; + cnt = MAX_RESERVE_SIZE; + } + else { + cnt = len; + len = 0; + } + + printk(KERN_ERR "%s:%d - reserving %d bytes\n", + __FUNCTION__, __LINE__, cnt); + entry = _stp_data_write_reserve(cnt); + if (likely(entry)) { + memcpy(entry->buf, bufp, cnt); + _stp_data_write_commit(entry); + bufp += cnt; + } + else { + atomic_inc (&_stp_transport_failures); + break; + } + } + } + + + + +#if 0 void *buf = utt_reserve(_stp_utt, sizeof(struct _stp_trace) + len); if (likely(buf)) { @@ -51,6 +131,7 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) memcpy(buf + sizeof(t), pb->buf, len); } else atomic_inc (&_stp_transport_failures); +#endif #endif } #else @@ -72,7 +153,9 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) uint32_t cnt; char *bufp = pb->buf; -#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) +//#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) + printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", + __FUNCTION__, __LINE__, pb->len, len); while (len > 0) { if (len > MAX_RESERVE_SIZE) { len -= MAX_RESERVE_SIZE; @@ -83,6 +166,8 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) len = 0; } + printk(KERN_ERR "%s:%d - reserving %d bytes\n", + __FUNCTION__, __LINE__, cnt); entry = _stp_data_write_reserve(cnt); if (likely(entry)) { memcpy(entry->buf, bufp, cnt); diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 3ea29f95..1d46c378 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -4,10 +4,6 @@ #include #include -#ifdef STP_BULKMODE -#error "bulkmode support unfinished..." -#endif - static struct ring_buffer *__stp_ring_buffer = NULL; //DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); @@ -200,7 +196,7 @@ __stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) * 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(buffer, (int)cpu_file)) + if (ring_buffer_empty_cpu(__stp_ring_buffer, (int)cpu_file)) return NULL; ent = peek_next_entry(cpu_file, ent_ts); if (ent_cpu) @@ -385,7 +381,7 @@ static int _stp_transport_data_fs_init(void) return rc; // create file(s) - for_each_possible_cpu(cpu) { + for_each_online_cpu(cpu) { char cpu_file[9]; /* 5(trace) + 3(XXX) + 1(\0) = 9 */ if (cpu > 999 || cpu < 0) { -- cgit From 8f47173deb9aa146b388542116d2638ed04fb03a Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 30 Mar 2009 15:12:27 -0500 Subject: 2009-03-30 David Smith * print_new.c: Whitespace/indent changes only. --- runtime/print_new.c | 168 ++++++++++++++++++++++++---------------------------- 1 file changed, 79 insertions(+), 89 deletions(-) (limited to 'runtime') diff --git a/runtime/print_new.c b/runtime/print_new.c index f8749842..01bbe809 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -21,6 +21,7 @@ static DEFINE_SPINLOCK(_stp_print_lock); void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) { uint32_t len = pb->len; + struct _stp_entry *entry; /* check to see if there is anything in the buffer */ dbug_trans(1, "len = %ud\n", len); @@ -35,125 +36,114 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) #define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) #ifdef STP_BULKMODE - { - struct _stp_entry *entry; #ifdef NO_PERCPU_HEADERS - { - uint32_t cnt; - char *bufp = pb->buf; - - printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", - __FUNCTION__, __LINE__, pb->len, len); - while (len > 0) { - if (len > MAX_RESERVE_SIZE) { - len -= MAX_RESERVE_SIZE; - cnt = MAX_RESERVE_SIZE; - } - else { - cnt = len; - len = 0; - } + { + uint32_t cnt; + char *bufp = pb->buf; + + printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", + __FUNCTION__, __LINE__, pb->len, len); + while (len > 0) { + if (len > MAX_RESERVE_SIZE) { + len -= MAX_RESERVE_SIZE; + cnt = MAX_RESERVE_SIZE; + } + else { + cnt = len; + len = 0; + } - printk(KERN_ERR "%s:%d - reserving %d bytes\n", - __FUNCTION__, __LINE__, cnt); - entry = _stp_data_write_reserve(cnt); - if (likely(entry)) { - memcpy(entry->buf, bufp, cnt); - _stp_data_write_commit(entry); - bufp += cnt; - } - else { - atomic_inc (&_stp_transport_failures); - break; - } + printk(KERN_ERR "%s:%d - reserving %d bytes\n", + __FUNCTION__, __LINE__, cnt); + entry = _stp_data_write_reserve(cnt); + if (likely(entry)) { + memcpy(entry->buf, bufp, cnt); + _stp_data_write_commit(entry); + bufp += cnt; + } + else { + atomic_inc (&_stp_transport_failures); + break; } } -#else + } + +#else /* !NO_PERCPU_HEADERS */ #undef MAX_RESERVE_SIZE #define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10 - sizeof(struct _stp_trace)) - { - uint32_t cnt; - char *bufp = pb->buf; - struct _stp_trace t = { .sequence = _stp_seq_inc(), - .pdu_len = len}; + { + uint32_t cnt; + char *bufp = pb->buf; + struct _stp_trace t = { .sequence = _stp_seq_inc(), + .pdu_len = len}; - printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", - __FUNCTION__, __LINE__, pb->len, len); + printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", + __FUNCTION__, __LINE__, pb->len, len); + + entry = _stp_data_write_reserve(sizeof(struct _stp_trace)); + if (likely(entry)) { + /* prevent unaligned access by using memcpy() */ + memcpy(entry->buf, &t, sizeof(t)); + _stp_data_write_commit(entry); + } + else { + atomic_inc (&_stp_transport_failures); + return; + } + + while (len > 0) { + if (len > MAX_RESERVE_SIZE) { + len -= MAX_RESERVE_SIZE; + cnt = MAX_RESERVE_SIZE; + } + else { + cnt = len; + len = 0; + } - entry = _stp_data_write_reserve(sizeof(struct _stp_trace)); + printk(KERN_ERR "%s:%d - reserving %d bytes\n", + __FUNCTION__, __LINE__, cnt); + entry = _stp_data_write_reserve(cnt); if (likely(entry)) { - /* prevent unaligned access by using - * memcpy() */ - memcpy(entry->buf, &t, sizeof(t)); + memcpy(entry->buf, bufp, cnt); _stp_data_write_commit(entry); + bufp += cnt; } else { atomic_inc (&_stp_transport_failures); - return; - } - - while (len > 0) { - if (len > MAX_RESERVE_SIZE) { - len -= MAX_RESERVE_SIZE; - cnt = MAX_RESERVE_SIZE; - } - else { - cnt = len; - len = 0; - } - - printk(KERN_ERR "%s:%d - reserving %d bytes\n", - __FUNCTION__, __LINE__, cnt); - entry = _stp_data_write_reserve(cnt); - if (likely(entry)) { - memcpy(entry->buf, bufp, cnt); - _stp_data_write_commit(entry); - bufp += cnt; - } - else { - atomic_inc (&_stp_transport_failures); - break; - } + break; } } + } #if 0 - void *buf = utt_reserve(_stp_utt, - sizeof(struct _stp_trace) + len); - if (likely(buf)) { - struct _stp_trace t = { .sequence = _stp_seq_inc(), - .pdu_len = len}; - memcpy(buf, &t, sizeof(t)); // prevent unaligned access - memcpy(buf + sizeof(t), pb->buf, len); - } else - atomic_inc (&_stp_transport_failures); -#endif + /* original code */ + void *buf = utt_reserve(_stp_utt, + sizeof(struct _stp_trace) + len); + if (likely(buf)) { + struct _stp_trace t = { .sequence = _stp_seq_inc(), + .pdu_len = len}; + memcpy(buf, &t, sizeof(t)); // prevent unaligned access + memcpy(buf + sizeof(t), pb->buf, len); + } else + atomic_inc (&_stp_transport_failures); #endif - } -#else + +#endif /* !NO_PERCPU_HEADERS */ +#else /* !STP_BULKMODE */ { - struct _stp_entry *entry; unsigned long flags; dbug_trans(1, "calling _stp_data_write...\n"); spin_lock_irqsave(&_stp_print_lock, flags); -#if 0 - entry = _stp_data_write_reserve(len); - if (likely(entry)) { - memcpy(entry->buf, pb->buf, len); - _stp_data_write_commit(entry); - } - else -#endif { uint32_t cnt; char *bufp = pb->buf; -//#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", __FUNCTION__, __LINE__, pb->len, len); while (len > 0) { @@ -182,5 +172,5 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) } spin_unlock_irqrestore(&_stp_print_lock, flags); } -#endif /* STP_BULKMODE */ +#endif /* !STP_BULKMODE */ } -- cgit From 2e07d704dc5d7304d6a9e666553a1a8ac4382730 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 31 Mar 2009 12:02:25 -0500 Subject: 2009-03-31 David Smith * print_new.c (stp_print_flush): Pushed MAX_RESERVE logic down to _stp_data_write_reserve(). Now just keeps calling _stp_data_write_reserve() until it has written the entire print buffer. * transport/ring_buffer.c (_stp_data_write_reserve): Breaks large reserve requests down into smaller ones for better buffer use. Returns the number of bytes reserved. * transport/transport.h: Updated _stp_data_write_reserve() prototype. --- runtime/print_new.c | 132 +++++++++++----------------------------- runtime/transport/ring_buffer.c | 34 ++++++++--- runtime/transport/transport.h | 3 +- 3 files changed, 64 insertions(+), 105 deletions(-) (limited to 'runtime') diff --git a/runtime/print_new.c b/runtime/print_new.c index 01bbe809..86c44ea7 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -18,14 +18,14 @@ static DEFINE_SPINLOCK(_stp_print_lock); -void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) +void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) { - uint32_t len = pb->len; - struct _stp_entry *entry; + size_t len = pb->len; + struct _stp_entry *entry = NULL; /* check to see if there is anything in the buffer */ - dbug_trans(1, "len = %ud\n", len); - if (likely (len == 0)) + dbug_trans(1, "len = %zu\n", len); + if (likely(len == 0)) return; pb->len = 0; @@ -34,35 +34,23 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) // if (unlikely(!_stp_utt || _stp_utt->trace_state != Utt_trace_running)) // return; -#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) #ifdef STP_BULKMODE #ifdef NO_PERCPU_HEADERS { - uint32_t cnt; char *bufp = pb->buf; - printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", - __FUNCTION__, __LINE__, pb->len, len); while (len > 0) { - if (len > MAX_RESERVE_SIZE) { - len -= MAX_RESERVE_SIZE; - cnt = MAX_RESERVE_SIZE; - } - else { - cnt = len; - len = 0; - } + size_t bytes_reserved; - printk(KERN_ERR "%s:%d - reserving %d bytes\n", - __FUNCTION__, __LINE__, cnt); - entry = _stp_data_write_reserve(cnt); - if (likely(entry)) { - memcpy(entry->buf, bufp, cnt); + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(entry->buf, bufp, bytes_reserved); _stp_data_write_commit(entry); - bufp += cnt; + bufp += bytes_reserved; + len -= bytes_reserved; } else { - atomic_inc (&_stp_transport_failures); + atomic_inc(&_stp_transport_failures); break; } } @@ -70,104 +58,58 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) #else /* !NO_PERCPU_HEADERS */ -#undef MAX_RESERVE_SIZE -#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10 - sizeof(struct _stp_trace)) { - uint32_t cnt; char *bufp = pb->buf; struct _stp_trace t = { .sequence = _stp_seq_inc(), .pdu_len = len}; + size_t bytes_reserved; - printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", - __FUNCTION__, __LINE__, pb->len, len); - - entry = _stp_data_write_reserve(sizeof(struct _stp_trace)); - if (likely(entry)) { + bytes_reserved = _stp_data_write_reserve(sizeof(struct _stp_trace), &entry); + if (likely(entry && bytes_reserved > 0)) { /* prevent unaligned access by using memcpy() */ memcpy(entry->buf, &t, sizeof(t)); _stp_data_write_commit(entry); } else { - atomic_inc (&_stp_transport_failures); + atomic_inc(&_stp_transport_failures); return; } while (len > 0) { - if (len > MAX_RESERVE_SIZE) { - len -= MAX_RESERVE_SIZE; - cnt = MAX_RESERVE_SIZE; - } - else { - cnt = len; - len = 0; - } - - printk(KERN_ERR "%s:%d - reserving %d bytes\n", - __FUNCTION__, __LINE__, cnt); - entry = _stp_data_write_reserve(cnt); - if (likely(entry)) { - memcpy(entry->buf, bufp, cnt); + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(entry->buf, bufp, bytes_reserved); _stp_data_write_commit(entry); - bufp += cnt; + bufp += bytes_reserved; + len -= bytes_reserved; } else { - atomic_inc (&_stp_transport_failures); + atomic_inc(&_stp_transport_failures); break; } } } - - - - -#if 0 - /* original code */ - void *buf = utt_reserve(_stp_utt, - sizeof(struct _stp_trace) + len); - if (likely(buf)) { - struct _stp_trace t = { .sequence = _stp_seq_inc(), - .pdu_len = len}; - memcpy(buf, &t, sizeof(t)); // prevent unaligned access - memcpy(buf + sizeof(t), pb->buf, len); - } else - atomic_inc (&_stp_transport_failures); -#endif - -#endif /* !NO_PERCPU_HEADERS */ -#else /* !STP_BULKMODE */ +#endif /* !NO_PERCPU_HEADERS */ +#else /* !STP_BULKMODE */ { unsigned long flags; + char *bufp = pb->buf; dbug_trans(1, "calling _stp_data_write...\n"); spin_lock_irqsave(&_stp_print_lock, flags); - { - uint32_t cnt; - char *bufp = pb->buf; - - printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", - __FUNCTION__, __LINE__, pb->len, len); - while (len > 0) { - if (len > MAX_RESERVE_SIZE) { - len -= MAX_RESERVE_SIZE; - cnt = MAX_RESERVE_SIZE; - } - else { - cnt = len; - len = 0; - } + while (len > 0) { + size_t bytes_reserved; - printk(KERN_ERR "%s:%d - reserving %d bytes\n", - __FUNCTION__, __LINE__, cnt); - entry = _stp_data_write_reserve(cnt); - if (likely(entry)) { - memcpy(entry->buf, bufp, cnt); - _stp_data_write_commit(entry); - bufp += cnt; - } - else { - atomic_inc (&_stp_transport_failures); - break; - } + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(entry->buf, bufp, bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; } } spin_unlock_irqrestore(&_stp_print_lock, flags); diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 1d46c378..abe9c360 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -317,6 +317,15 @@ static struct file_operations __stp_data_fops = { #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. * @@ -329,24 +338,31 @@ static struct file_operations __stp_data_fops = { * sample. * */ -static struct _stp_entry * -_stp_data_write_reserve(size_t size) +static size_t +_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) { struct ring_buffer_event *event; - struct _stp_entry *entry; + + 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), + (sizeof(struct _stp_entry) + size_request), 0); if (unlikely(! event)) { dbug_trans(1, "event = NULL (%p)?\n", event); - return NULL; + entry = NULL; + return 0; } - entry = ring_buffer_event_data(event); - entry->event = event; - entry->len = size; - return entry; + *entry = ring_buffer_event_data(event); + (*entry)->event = event; + (*entry)->len = size_request; + return size_request; } static int _stp_data_write_commit(struct _stp_entry *entry) diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index feaa950c..7d1f5c5d 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -70,7 +70,8 @@ struct _stp_entry { char buf[]; }; -static struct _stp_entry *_stp_data_write_reserve(size_t size); +static size_t _stp_data_write_reserve(size_t size_request, + struct _stp_entry **entry); static int _stp_data_write_commit(struct _stp_entry *entry); #endif /* _TRANSPORT_TRANSPORT_H_ */ -- cgit From 9b23198d73b782bc05dc2b834c7db3afbdefda86 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 2 Apr 2009 10:16:35 -0500 Subject: Renamed STP_OLD_TRANSPORT to STP_TRANSPORT_VERSION. 2009-04-02 David Smith * runtime.h: Defines STP_TRANSPORT_VERSION instead of STP_OLD_TRANSPORT. * staprun/staprun.h (STP_OLD_TRANSPORT): Ditto. * print.c: Changed STP_OLD_TRANSPORT to STP_TRANSPORT_VERSION. * staprun/mainloop.c (stp_main_loop): Ditto. * transport/transport.c: Ditto. * transport/transport.h: Ditto. * transport/transport_msgs.h: Ditto. * transport/utt.h: Ditto. --- runtime/print.c | 2 +- runtime/runtime.h | 7 ++++++- runtime/staprun/mainloop.c | 2 +- runtime/staprun/staprun.h | 5 +++-- runtime/transport/transport.c | 17 +++++++++++------ runtime/transport/transport.h | 2 +- runtime/transport/transport_msgs.h | 4 ++-- runtime/transport/utt.h | 2 +- 8 files changed, 26 insertions(+), 15 deletions(-) (limited to 'runtime') diff --git a/runtime/print.c b/runtime/print.c index fa517cb5..2e205f10 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -90,7 +90,7 @@ static void _stp_print_cleanup (void) /* The relayfs API changed between 2.6.15 and 2.6.16. */ /* Use the appropriate print flush function. */ -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 #include "print_old.c" #else #include "print_new.c" diff --git a/runtime/runtime.h b/runtime/runtime.h index 28283db6..78c27a84 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -34,9 +34,14 @@ #if !defined (CONFIG_DEBUG_FS) && !defined (CONFIG_DEBUG_FS_MODULE) #error "DebugFS is required and was not found in the kernel." #endif +#ifdef CONFIG_RING_BUFFER +#define STP_TRANSPORT_VERSION 3 +#else +#define STP_TRANSPORT_VERSION 2 +#endif #else /* older kernels have no debugfs and older version of relayfs. */ -#define STP_OLD_TRANSPORT +#define STP_TRANSPORT_VERSION 1 #endif #ifndef stp_for_each_cpu diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index 29eb4f1f..0745f611 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -452,7 +452,7 @@ int stp_main_loop(void) nb -= sizeof(uint32_t); switch (type) { -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 case STP_REALTIME_DATA: { ssize_t bw = write(out_fd[0], data, nb); diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index 84cf63fc..f49cc7db 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -90,8 +90,9 @@ extern char *__name__; /* Grabbed from linux/module.h kernel include. */ #define MODULE_NAME_LEN (64 - sizeof(unsigned long)) -/* we define this so we are compatible with old transport, but we don't have to use it. */ -#define STP_OLD_TRANSPORT +/* We define this so we are compatible with old transport, but we + * don't have to use it. */ +#define STP_TRANSPORT_VERSION 1 #include "../transport/transport_msgs.h" #define RELAYFS_MAGIC 0xF0B4A981 diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index c4c9da1e..c0c97467 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -41,12 +41,17 @@ static int _stp_probes_started = 0; static struct utt_trace *_stp_utt = NULL; static unsigned int utt_seq = 1; #include "control.h" -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 #include "relayfs.c" #include "procfs.c" -#else +#elif STP_TRANSPORT_VERSION == 2 #include "utt.c" #include "debugfs.c" +#elif STP_TRANSPORT_VERSION == 3 +#include "debugfs.c" +#include "ring_buffer.c" +#else +#error "Unknown STP_TRANSPORT_VERSION" #endif #include "control.c" @@ -355,7 +360,7 @@ static struct dentry *_stp_lockfile = NULL; static int _stp_lock_transport_dir(void) { int numtries = 0; -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 while ((_stp_lockfile = relayfs_create_dir("systemtap_lock", NULL)) == NULL) { #else while ((_stp_lockfile = debugfs_create_dir("systemtap_lock", NULL)) == NULL) { @@ -370,7 +375,7 @@ static int _stp_lock_transport_dir(void) static void _stp_unlock_transport_dir(void) { if (_stp_lockfile) { -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 relayfs_remove_dir(_stp_lockfile); #else debugfs_remove(_stp_lockfile); @@ -394,7 +399,7 @@ static struct dentry *_stp_get_root_dir(void) return __stp_root_dir; } -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 fs = get_fs_type("relayfs"); if (!fs) { errk("Couldn't find relayfs filesystem.\n"); @@ -412,7 +417,7 @@ static struct dentry *_stp_get_root_dir(void) errk("Couldn't lock transport directory.\n"); return NULL; } -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 __stp_root_dir = relayfs_create_dir(name, NULL); #else __stp_root_dir = debugfs_create_dir(name, NULL); diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index 7d1f5c5d..1d245cc6 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -26,7 +26,7 @@ static inline void *utt_reserve(struct utt_trace *utt, size_t length) /* STP_CTL_BUFFER_SIZE is the maximum size of a message */ /* exchanged on the control channel. */ -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 /* Old transport sends print output on control channel */ #define STP_CTL_BUFFER_SIZE STP_BUFFER_SIZE #else diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index 596f4925..0d6853f7 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -30,7 +30,7 @@ enum STP_BULK, STP_READY, STP_RELOCATION, - /** deprecated STP_OLD_TRANSPORT **/ + /** deprecated STP_TRANSPORT_VERSION == 1 **/ STP_BUF_INFO, STP_SUBBUFS_CONSUMED, STP_REALTIME_DATA, @@ -81,7 +81,7 @@ struct _stp_msg_start int32_t res; // for reply: result of probe_start() }; -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 /**** for compatibility with old relayfs ****/ struct _stp_buf_info { diff --git a/runtime/transport/utt.h b/runtime/transport/utt.h index 0a0944c0..2a479d70 100644 --- a/runtime/transport/utt.h +++ b/runtime/transport/utt.h @@ -47,7 +47,7 @@ static int utt_trace_startstop(struct utt_trace *utt, int start, static void utt_trace_cleanup(struct utt_trace *utt); static int utt_trace_remove(struct utt_trace *utt); -#ifndef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 2 static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, size_t length); /** -- cgit 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/control.c | 1 + runtime/transport/relay_v2.c | 550 ++++++++++++++++++++++++++++++++++++++++ runtime/transport/ring_buffer.c | 51 +--- runtime/transport/transport.c | 22 +- 4 files changed, 573 insertions(+), 51 deletions(-) create mode 100644 runtime/transport/relay_v2.c (limited to 'runtime') diff --git a/runtime/transport/control.c b/runtime/transport/control.c index 7626305a..4e07a0a7 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -12,6 +12,7 @@ #include "control.h" #include "../mempool.c" #include "symbols.c" +#include static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; 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); +} + diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index abe9c360..99ce2031 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -5,41 +5,20 @@ #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 +struct _stp_ring_buffer_data { 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 struct _stp_ring_buffer_data _stp_rb_data; static cpumask_var_t _stp_trace_reader_cpumask; @@ -159,13 +138,10 @@ static ssize_t tracing_wait_pipe(struct file *filp) * 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; @@ -186,8 +162,9 @@ peek_next_entry(int cpu, u64 *ts) return event ? ring_buffer_event_data(event) : NULL; } +/* Find the next real entry */ static struct _stp_entry * -__stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) +_stp_find_next_entry(long cpu_file) { struct _stp_entry *ent; @@ -199,8 +176,7 @@ __stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) 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; + _stp_rb_data.cpu = cpu_file; return ent; #else @@ -226,22 +202,13 @@ __stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) } } - if (ent_cpu) - *ent_cpu = next_cpu; - - if (ent_ts) - *ent_ts = next_ts; + _stp_rb_data.cpu = next_cpu; + _stp_rb_data.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. @@ -279,8 +246,8 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, if (len <= 0) break; - ring_buffer_consume(__stp_ring_buffer, _stp_iter.cpu, - &_stp_iter.ts); + ring_buffer_consume(__stp_ring_buffer, _stp_rb_data.cpu, + &_stp_rb_data.ts); ubuf += len; cnt -= len; sret += len; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index c0c97467..5a499e8d 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -18,11 +18,14 @@ #include #include #include +#include +#if 0 static void utt_set_overwrite(int overwrite) { return; } +#endif static int _stp_exit_flag = 0; @@ -35,21 +38,19 @@ static int _stp_ctl_attached = 0; static pid_t _stp_target = 0; static int _stp_probes_started = 0; -#if 0 -#include - -static struct utt_trace *_stp_utt = NULL; -static unsigned int utt_seq = 1; +#if 1 +//static struct utt_trace *_stp_utt = NULL; +//static unsigned int utt_seq = 1; #include "control.h" #if STP_TRANSPORT_VERSION == 1 #include "relayfs.c" #include "procfs.c" #elif STP_TRANSPORT_VERSION == 2 -#include "utt.c" +#include "relay_v2.c" #include "debugfs.c" #elif STP_TRANSPORT_VERSION == 3 -#include "debugfs.c" #include "ring_buffer.c" +#include "debugfs.c" #else #error "Unknown STP_TRANSPORT_VERSION" #endif @@ -59,7 +60,6 @@ static unsigned int utt_seq = 1; #include "control.h" #include "debugfs.c" #include "control.c" -#include "ring_buffer.c" #endif /* if 0 */ static unsigned _stp_nsubbufs = 8; static unsigned _stp_subbuf_size = 65536*4; @@ -158,8 +158,10 @@ static void _stp_detach(void) _stp_ctl_attached = 0; _stp_pid = 0; +#if 0 if (!_stp_exit_flag) utt_set_overwrite(1); +#endif cancel_delayed_work(&_stp_work); wake_up_interruptible(&_stp_ctl_wq); @@ -173,7 +175,9 @@ static void _stp_attach(void) dbug_trans(1, "attach\n"); _stp_ctl_attached = 1; _stp_pid = current->pid; +#if 0 utt_set_overwrite(0); +#endif queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } @@ -458,7 +462,7 @@ static void _stp_remove_root_dir(void) static struct dentry *__stp_module_dir = NULL; -static inline struct dentry *_stp_get_module_dir(void) +static struct dentry *_stp_get_module_dir(void) { return __stp_module_dir; } -- cgit From 09334fd8db6c57743a7da34dd55be551fef6e39f Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 6 May 2009 14:32:08 -0500 Subject: Added comments. * runtime/transport/transport.h: Added comments. --- runtime/transport/transport.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'runtime') diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index 1d245cc6..8ab65dec 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -61,7 +61,25 @@ static gid_t _stp_gid; static int _stp_ctl_attached; static int _stp_bufsize; + +/* + * All transports must provide the following functions. + */ + +/* + * _stp_transport_data_fs_init + * + * This function allocates any buffers needed, creates files, + * etc. needed for this transport. + */ static int _stp_transport_data_fs_init(void); + +/* + * _stp_transport_data_fs_close + * + * This function cleans up items created by + * _stp_transport_data_fs_init(). + */ static void _stp_transport_data_fs_close(void); struct _stp_entry { @@ -70,8 +88,27 @@ struct _stp_entry { char buf[]; }; +/* + * _stp_data_write_reserve - reserve bytes + * size_request: number of bytes to reserve + * entry: allocated buffer is returned here + * + * This function attempts to reserve size_request number of bytes, + * returning the number of bytes actually reserved. The allocated + * buffer is returned in entry. Note that the number of bytes + * allocated may be less than the number of bytes requested. + */ static size_t _stp_data_write_reserve(size_t size_request, struct _stp_entry **entry); + +/* + * _stp_data_write_commit - + * entry: _stp_entry returned by + * _stp-data_write_reserve() + * + * This function notifies the transport that the bytes in entry are + * ready to be written. + */ static int _stp_data_write_commit(struct _stp_entry *entry); #endif /* _TRANSPORT_TRANSPORT_H_ */ -- cgit From 6edf848ad0053423dd3b06851ab8d62a260a56e8 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 7 May 2009 15:02:05 -0500 Subject: Hid details of internal ring_buffer.c structure. * runtime/print_new.c (stp_print_flush): Calls _stp_data_entry_data() to get data pointer. * runtime/transport/transport.h: Removed _stp_entry definition. Added _stp_data_entry_data() declaration. * runtime/transport/ring_buffer.c: Uses new _stp_data_entry structure. (_stp_data_entry_data): Added. --- runtime/print_new.c | 13 +++--- runtime/transport/ring_buffer.c | 95 +++++++++++++++++++++++++---------------- runtime/transport/transport.h | 23 +++++----- 3 files changed, 79 insertions(+), 52 deletions(-) (limited to 'runtime') diff --git a/runtime/print_new.c b/runtime/print_new.c index 86c44ea7..b6187978 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -21,7 +21,7 @@ static DEFINE_SPINLOCK(_stp_print_lock); void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) { size_t len = pb->len; - struct _stp_entry *entry = NULL; + void *entry = NULL; /* check to see if there is anything in the buffer */ dbug_trans(1, "len = %zu\n", len); @@ -44,7 +44,8 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) bytes_reserved = _stp_data_write_reserve(len, &entry); if (likely(entry && bytes_reserved > 0)) { - memcpy(entry->buf, bufp, bytes_reserved); + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); _stp_data_write_commit(entry); bufp += bytes_reserved; len -= bytes_reserved; @@ -67,7 +68,7 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) bytes_reserved = _stp_data_write_reserve(sizeof(struct _stp_trace), &entry); if (likely(entry && bytes_reserved > 0)) { /* prevent unaligned access by using memcpy() */ - memcpy(entry->buf, &t, sizeof(t)); + memcpy(_stp_data_entry_data(entry), &t, sizeof(t)); _stp_data_write_commit(entry); } else { @@ -78,7 +79,8 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) while (len > 0) { bytes_reserved = _stp_data_write_reserve(len, &entry); if (likely(entry && bytes_reserved > 0)) { - memcpy(entry->buf, bufp, bytes_reserved); + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); _stp_data_write_commit(entry); bufp += bytes_reserved; len -= bytes_reserved; @@ -102,7 +104,8 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) bytes_reserved = _stp_data_write_reserve(len, &entry); if (likely(entry && bytes_reserved > 0)) { - memcpy(entry->buf, bufp, bytes_reserved); + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); _stp_data_write_commit(entry); bufp += bytes_reserved; len -= bytes_reserved; diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 99ce2031..0385e7d3 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -4,6 +4,11 @@ #include #include +struct _stp_data_entry { + size_t len; + unsigned char buf[]; +}; + static struct ring_buffer *__stp_ring_buffer = NULL; /* _stp_poll_wait is a waitqueue for tasks blocked on @@ -98,12 +103,18 @@ static int _stp_data_release_trace(struct inode *inode, struct file *file) } size_t -_stp_entry_to_user(struct _stp_entry *entry, char __user *ubuf, size_t cnt) +_stp_event_to_user(struct ring_buffer_event *event, char __user *ubuf, + size_t cnt) { int ret; + struct _stp_data_entry *entry; - dbug_trans(1, "entry(%p), ubuf(%p), cnt(%lu)\n", entry, ubuf, cnt); - if (entry == NULL || ubuf == NULL) + dbug_trans(1, "event(%p), ubuf(%p), cnt(%lu)\n", event, ubuf, cnt); + if (event == NULL || ubuf == NULL) + return -EFAULT; + + entry = (struct _stp_data_entry *)ring_buffer_event_data(event); + if (entry == NULL) return -EFAULT; /* We don't do partial entries - just fail. */ @@ -152,21 +163,17 @@ static ssize_t tracing_wait_pipe(struct file *filp) return 1; } -static struct _stp_entry * -peek_next_entry(int cpu, u64 *ts) +static struct ring_buffer_event * +peek_next_event(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; + return ring_buffer_peek(__stp_ring_buffer, cpu, ts); } -/* Find the next real entry */ -static struct _stp_entry * -_stp_find_next_entry(long cpu_file) +/* Find the next real event */ +static struct ring_buffer_event * +_stp_find_next_event(long cpu_file) { - struct _stp_entry *ent; + struct ring_buffer_event *event; #ifdef STP_BULKMODE /* @@ -175,12 +182,12 @@ _stp_find_next_entry(long cpu_file) */ if (ring_buffer_empty_cpu(__stp_ring_buffer, (int)cpu_file)) return NULL; - ent = peek_next_entry(cpu_file, ent_ts); + event = peek_next_event(cpu_file, &_stp_rb_data.ts); _stp_rb_data.cpu = cpu_file; - return ent; + return event; #else - struct _stp_entry *next = NULL; + struct ring_buffer_event *next = NULL; u64 next_ts = 0, ts; int next_cpu = -1; int cpu; @@ -190,13 +197,13 @@ _stp_find_next_entry(long cpu_file) if (ring_buffer_empty_cpu(__stp_ring_buffer, cpu)) continue; - ent = peek_next_entry(cpu, &ts); + event = peek_next_event(cpu, &ts); /* - * Pick the entry with the smallest timestamp: + * Pick the event with the smallest timestamp: */ - if (ent && (!next || ts < next_ts)) { - next = ent; + if (event && (!next || ts < next_ts)) { + next = event; next_cpu = cpu; next_ts = ts; } @@ -218,7 +225,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { ssize_t sret; - struct _stp_entry *entry; + struct ring_buffer_event *event; long cpu_file = (long) filp->private_data; dbug_trans(1, "%lu\n", (unsigned long)cnt); @@ -239,10 +246,10 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, dbug_trans(1, "sret = %lu\n", (unsigned long)sret); sret = 0; - while ((entry = _stp_find_next_entry(cpu_file)) != NULL) { + while ((event = _stp_find_next_event(cpu_file)) != NULL) { ssize_t len; - len = _stp_entry_to_user(entry, ubuf, cnt); + len = _stp_event_to_user(event, ubuf, cnt); if (len <= 0) break; @@ -284,13 +291,14 @@ static struct file_operations __stp_data_fops = { #endif }; -/* Here's how __STP_MAX_RESERVE_SIZE is figured. The value of +/* + * 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) \ + * the case of a small reservation). + */ +#define __STP_MAX_RESERVE_SIZE ((/*BUF_PAGE_SIZE*/ 4080 / 4) \ + - sizeof(struct _stp_data_entry) \ - sizeof(struct ring_buffer_event)) /* @@ -306,9 +314,10 @@ static struct file_operations __stp_data_fops = { * */ static size_t -_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) +_stp_data_write_reserve(size_t size_request, void **entry) { struct ring_buffer_event *event; + struct _stp_data_entry *sde; if (entry == NULL) return -EINVAL; @@ -318,7 +327,7 @@ _stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) } event = ring_buffer_lock_reserve(__stp_ring_buffer, - (sizeof(struct _stp_entry) + size_request), + sizeof(struct _stp_data_entry) + size_request, 0); if (unlikely(! event)) { dbug_trans(1, "event = NULL (%p)?\n", event); @@ -326,22 +335,36 @@ _stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) return 0; } - *entry = ring_buffer_event_data(event); - (*entry)->event = event; - (*entry)->len = size_request; + sde = (struct _stp_data_entry *)ring_buffer_event_data(event); + sde->len = size_request; + + *entry = event; return size_request; } -static int _stp_data_write_commit(struct _stp_entry *entry) +static unsigned char *_stp_data_entry_data(void *entry) +{ + struct ring_buffer_event *event = entry; + struct _stp_data_entry *sde; + + if (event == NULL) + return NULL; + + sde = (struct _stp_data_entry *)ring_buffer_event_data(event); + return sde->buf; +} + +static int _stp_data_write_commit(void *entry) { int ret; + struct ring_buffer_event *event = (struct ring_buffer_event *)entry; if (unlikely(! entry)) { dbug_trans(1, "entry = NULL, returning -EINVAL\n"); return -EINVAL; } - ret = ring_buffer_unlock_commit(__stp_ring_buffer, entry->event, 0); + ret = ring_buffer_unlock_commit(__stp_ring_buffer, event, 0); dbug_trans(1, "after commit, empty returns %d\n", ring_buffer_empty(__stp_ring_buffer)); diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index 8ab65dec..c560be5d 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -82,12 +82,6 @@ static int _stp_transport_data_fs_init(void); */ static void _stp_transport_data_fs_close(void); -struct _stp_entry { - void *event; - size_t len; - char buf[]; -}; - /* * _stp_data_write_reserve - reserve bytes * size_request: number of bytes to reserve @@ -98,17 +92,24 @@ struct _stp_entry { * buffer is returned in entry. Note that the number of bytes * allocated may be less than the number of bytes requested. */ -static size_t _stp_data_write_reserve(size_t size_request, - struct _stp_entry **entry); +static size_t _stp_data_write_reserve(size_t size_request, void **entry); + + +/* + * _stp_data_entry_data - return data pointer from entry + * entry: entry + * + * This function returns the data pointer from entry. + */ +static unsigned char *_stp_data_entry_data(void *entry); /* * _stp_data_write_commit - - * entry: _stp_entry returned by - * _stp-data_write_reserve() + * entry: pointer returned by _stp-data_write_reserve() * * This function notifies the transport that the bytes in entry are * ready to be written. */ -static int _stp_data_write_commit(struct _stp_entry *entry); +static int _stp_data_write_commit(void *entry); #endif /* _TRANSPORT_TRANSPORT_H_ */ -- 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') 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') 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') 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 dd9a3bcbef65bde65491d959e9458bc641924811 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 12 May 2009 13:38:48 -0500 Subject: Start at supporting the original transport (STP_TRANSPORT_VERSION=1). * runtime/print.c: Only use print_new.c. * runtime/print_new.c (stp_print_flush): Add STP_TRANSPORT_VERSION 1 support. * runtime/transport/transport.c: Removed inclusion of procfs.c. * runtime/transport/procfs.c (_stp_proc_read): Adapt to new interface. (_stp_proc_write): Ditto. * runtime/transport/relayfs.c: Ditto. --- runtime/print.c | 6 -- runtime/print_new.c | 9 ++ runtime/transport/procfs.c | 11 ++- runtime/transport/relayfs.c | 187 +++++++++++++++++++----------------------- runtime/transport/transport.c | 1 - 5 files changed, 100 insertions(+), 114 deletions(-) (limited to 'runtime') diff --git a/runtime/print.c b/runtime/print.c index 2e205f10..c1fff306 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -87,14 +87,8 @@ static void _stp_print_cleanup (void) #endif #if !defined(RELAY_GUEST) -/* The relayfs API changed between 2.6.15 and 2.6.16. */ -/* Use the appropriate print flush function. */ -#if STP_TRANSPORT_VERSION == 1 -#include "print_old.c" -#else #include "print_new.c" -#endif #if defined(RELAY_HOST) EXPORT_SYMBOL_GPL(EXPORT_FN(stp_print_flush)); #endif diff --git a/runtime/print_new.c b/runtime/print_new.c index b6187978..2d5a6e10 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -92,7 +92,15 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) } } #endif /* !NO_PERCPU_HEADERS */ + #else /* !STP_BULKMODE */ + +#if STP_TRANSPORT_VERSION == 1 + + if (unlikely(_stp_ctl_write(STP_REALTIME_DATA, pb->buf, len) <= 0)) + atomic_inc (&_stp_transport_failures); + +#else /* STP_TRANSPORT_VERSION != 1 */ { unsigned long flags; char *bufp = pb->buf; @@ -117,5 +125,6 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) } spin_unlock_irqrestore(&_stp_print_lock, flags); } +#endif /* STP_TRANSPORT_VERSION != 1 */ #endif /* !STP_BULKMODE */ } diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c index 6afbdea1..9e05cc14 100644 --- a/runtime/transport/procfs.c +++ b/runtime/transport/procfs.c @@ -14,7 +14,6 @@ #define STP_DEFAULT_BUFFERS 256 #ifdef STP_BULKMODE -extern int _stp_relay_flushing; /* handle the per-cpu subbuf info read for relayfs */ static ssize_t _stp_proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -23,13 +22,13 @@ static ssize_t _stp_proc_read(struct file *file, char __user *buf, size_t count, int cpu = *(int *)(PDE(file->f_dentry->d_inode)->data); - if (!_stp_utt->rchan) + if (!_stp_relay_data.rchan) return -EINVAL; out.cpu = cpu; - 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; + out.produced = atomic_read(&_stp_relay_data.rchan->buf[cpu]->subbufs_produced); + out.consumed = atomic_read(&_stp_relay_data.rchan->buf[cpu]->subbufs_consumed); + out.flushing = _stp_relay_data.flushing; num = sizeof(out); if (copy_to_user(buf, &out, num)) @@ -46,7 +45,7 @@ static ssize_t _stp_proc_write(struct file *file, const char __user *buf, size_t if (copy_from_user(&info, buf, count)) return -EFAULT; - relay_subbufs_consumed(_stp_utt->rchan, cpu, info.consumed); + relay_subbufs_consumed(_stp_relay_data.rchan, cpu, info.consumed); return count; } diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index 42be4283..dac6db1d 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -22,17 +22,33 @@ #include #include #include -#include "utt.h" -static int _stp_relay_flushing = 0; +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; + int flushing; +}; +struct _stp_relay_data_type _stp_relay_data; + +/* We need to include procfs.c here so that it can see the + * _stp_relay_data_type definition. */ +#include "procfs.c" /** - * _stp_subbuf_start - subbuf_start() relayfs callback implementation + * __stp_relay_subbuf_start_callback - subbuf_start() relayfs + * callback implementation */ -static int _stp_subbuf_start(struct rchan_buf *buf, - void *subbuf, - unsigned prev_subbuf_idx, - void *prev_subbuf) +static int +__stp_relay_subbuf_start_callback(struct rchan_buf *buf, + void *subbuf, + unsigned prev_subbuf_idx, + void *prev_subbuf) { unsigned padding = buf->padding[prev_subbuf_idx]; if (prev_subbuf) @@ -42,11 +58,12 @@ static int _stp_subbuf_start(struct rchan_buf *buf, } /** - * _stp_buf_full - buf_full() relayfs callback implementation + * __stp_relay_buf_full_callback - buf_full() relayfs callback + * implementation */ -static void _stp_buf_full(struct rchan_buf *buf, - unsigned subbuf_idx, - void *subbuf) +static void __stp_relay_buf_full_callback(struct rchan_buf *buf, + unsigned subbuf_idx, + void *subbuf) { unsigned padding = buf->padding[subbuf_idx]; *((unsigned *)subbuf) = padding; @@ -54,126 +71,94 @@ static void _stp_buf_full(struct rchan_buf *buf, static struct rchan_callbacks stp_rchan_callbacks = { - .subbuf_start = _stp_subbuf_start, - .buf_full = _stp_buf_full, + .subbuf_start = __stp_relay_subbuf_start_callback, + .buf_full = __stp_relay_buf_full_callback, }; - -static void _stp_remove_relay_dir(struct dentry *dir) -{ - if (dir) - relayfs_remove_dir(dir); -} - -static void _stp_remove_relay_root(struct dentry *root) +static void _stp_transport_data_fs_close(void) { - if (root) { - if (!_stp_lock_transport_dir()) { - errk("Unable to lock transport directory.\n"); - return; - } - _stp_remove_relay_dir(root); - _stp_unlock_transport_dir(); + if (_stp_relay_data.rchan) { + _stp_relay_data.flushing = 1; + relay_flush(_stp_relay_data.rchan); + relay_close(_stp_relay_data.rchan); } + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; } -static struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts) +static int _stp_transport_data_fs_init(void) { - struct utt_trace *utt; + int rc = 0; int i; - utt = _stp_kzalloc(sizeof(*utt)); - if (!utt) - return NULL; - - utt->utt_tree_root = _stp_get_root_dir(); - if (!utt->utt_tree_root) - goto err; - - utt->dir = relayfs_create_dir(utts->name, utt->utt_tree_root); - if (!utt->dir) - goto err; - - dbug_trans(1, "relay_open %d %d\n", utts->buf_size, utts->buf_nr); + dbug_trans(1, "relay_open %d %d\n", _stp_subbuf_size, _stp_nsubbufs); + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + _stp_relay_data.flushing = 0; - utt->rchan = relay_open("trace", utt->dir, utts->buf_size, - utts->buf_nr, 0, &stp_rchan_callbacks); - if (!utt->rchan) + /* Create "trace" file. */ + _stp_relay_data.rchan = relay_open("trace", _stp_get_module_dir(), + _stp_subbuf_size, _stp_nsubbufs, + 0, &stp_rchan_callbacks); + if (!_stp_relay_data.rchan) { + rc = -ENOENT; goto err; + } /* now set ownership */ for_each_online_cpu(i) { - utt->rchan->buf[i]->dentry->d_inode->i_uid = _stp_uid; - utt->rchan->buf[i]->dentry->d_inode->i_gid = _stp_gid; + _stp_relay_data.rchan->buf[i]->dentry->d_inode->i_uid + = _stp_uid; + _stp_relay_data.rchan->buf[i]->dentry->d_inode->i_gid + = _stp_gid; } - utt->rchan->private_data = utt; - utt->trace_state = Utt_trace_setup; - utts->err = 0; - return utt; + /* We're off and running. */ + smp_mb(); + _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + return rc; err: errk("couldn't create relay channel.\n"); - if (utt->dir) - _stp_remove_relay_dir(utt->dir); - if (utt->utt_tree_root) - _stp_remove_relay_root(utt->utt_tree_root); - _stp_kfree(utt); - return NULL; + _stp_transport_data_fs_close(); + return rc; } -static void utt_set_overwrite(int overwrite) +static void stp_relay_set_overwrite(int overwrite) { - if (_stp_utt) - _stp_utt->rchan->overwrite = overwrite; + _stp_relay_data.rchan->overwrite = overwrite; } -static int utt_trace_startstop(struct utt_trace *utt, int start, - unsigned int *trace_seq) +/** + * _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 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. + * + * (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) { - int ret; + if (entry == NULL) + return -EINVAL; - if (!utt) + *entry = relay_reserve(_stp_relay_data.rchan, size_request); + if (*entry == NULL) return 0; - - /* - * 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; - } - } - - return ret; + return size_request; } +static unsigned char *_stp_data_entry_data(void *entry) +{ + /* Nothing to do here. */ + return entry; +} -static int utt_trace_remove(struct utt_trace *utt) +static int _stp_data_write_commit(void *entry) { - dbug_trans(1, "removing relayfs files. %d\n", utt->trace_state); - if (utt && (utt->trace_state == Utt_trace_setup || utt->trace_state == Utt_trace_stopped)) { - if (utt->rchan) - relay_close(utt->rchan); - if (utt->dir) - _stp_remove_relay_dir(utt->dir); - if (utt->utt_tree_root) - _stp_remove_relay_root(utt->utt_tree_root); - _stp_kfree(utt); - } + /* Nothing to do here. */ return 0; } diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 5a499e8d..3d0453bf 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -44,7 +44,6 @@ static int _stp_probes_started = 0; #include "control.h" #if STP_TRANSPORT_VERSION == 1 #include "relayfs.c" -#include "procfs.c" #elif STP_TRANSPORT_VERSION == 2 #include "relay_v2.c" #include "debugfs.c" -- 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/debugfs.c | 7 + runtime/transport/relay_v2.c | 11 +- runtime/transport/ring_buffer.c | 7 + runtime/transport/transport.c | 18 ++ runtime/transport/utt.c | 404 ---------------------------------------- runtime/transport/utt.h | 83 --------- runtime/vsprintf.c | 2 + 7 files changed, 44 insertions(+), 488 deletions(-) delete mode 100644 runtime/transport/utt.c delete mode 100644 runtime/transport/utt.h (limited to 'runtime') diff --git a/runtime/transport/debugfs.c b/runtime/transport/debugfs.c index 7a08982a..6bbef53b 100644 --- a/runtime/transport/debugfs.c +++ b/runtime/transport/debugfs.c @@ -36,6 +36,13 @@ static int _stp_register_ctl_channel_fs(void) errk("Error creating systemtap debugfs entries.\n"); return -1; } + else if (IS_ERR(_stp_cmd_file)) { + _stp_cmd_file = NULL; + errk("Error creating systemtap debugfs entries: %ld\n", + -PTR_ERR(_stp_cmd_file)); + return -1; + } + _stp_cmd_file->d_inode->i_uid = _stp_uid; _stp_cmd_file->d_inode->i_gid = _stp_gid; 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; diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 0385e7d3..217d0735 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -405,6 +405,13 @@ static int _stp_transport_data_fs_init(void) __stp_free_ring_buffer(); return -ENOENT; } + else if (IS_ERR(__stp_entry[cpu])) { + rc = PTR_ERR(__stp_entry[cpu]); + pr_warning("Could not create debugfs 'trace' entry\n"); + __stp_free_ring_buffer(); + return rc; + } + __stp_entry[cpu]->d_inode->i_uid = _stp_uid; __stp_entry[cpu]->d_inode->i_gid = _stp_gid; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 792ea815..ab0806f2 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -453,6 +453,12 @@ static struct dentry *_stp_get_root_dir(void) errk("Could not create or find transport directory.\n"); } } + else if (IS_ERR(__stp_root_dir)) { + __stp_root_dir = NULL; + errk("Could not create root directory \"%s\", error %ld\n", name, + -PTR_ERR(__stp_root_dir)); + } + _stp_unlock_transport_dir(); return __stp_root_dir; } @@ -490,8 +496,20 @@ static int _stp_transport_fs_init(const char *module_name) if (root_dir == NULL) return -1; +#if STP_TRANSPORT_VERSION == 1 + __stp_module_dir = relayfs_create_dir(module_name, root_dir); +#else __stp_module_dir = debugfs_create_dir(module_name, root_dir); +#endif if (!__stp_module_dir) { + errk("Could not create module directory \"%s\"\n", + module_name); + _stp_remove_root_dir(); + return -1; + } + else if (IS_ERR(__stp_module_dir)) { + errk("Could not create module directory \"%s\", error %ld\n", + module_name, -PTR_ERR(__stp_module_dir)); _stp_remove_root_dir(); return -1; } diff --git a/runtime/transport/utt.c b/runtime/transport/utt.c deleted file mode 100644 index 2dd303a5..00000000 --- a/runtime/transport/utt.c +++ /dev/null @@ -1,404 +0,0 @@ -/* -*- 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 int utt_overwrite_flag = 0; - -/* - * utt_switch_subbuf - switch to a new sub-buffer - * - * Most of this function is deadcopy of relay_switch_subbuf. - */ -static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, - size_t length) -{ - char *old, *new; - size_t old_subbuf, new_subbuf; - - if (unlikely(buf == NULL)) - return 0; - - 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(&utt->wakeup, 1); - } - - 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; - } - buf->data = new; - buf->padding[new_subbuf] = 0; - - if (unlikely(length + buf->offset > buf->chan->subbuf_size)) - goto toobig; - - return length; - -toobig: - buf->chan->last_toobig = length; - return 0; -} - -static void __utt_wakeup_readers(struct rchan_buf *buf) -{ - if (buf && waitqueue_active(&buf->read_wait) && - buf->subbufs_produced != buf->subbufs_consumed) - wake_up_interruptible(&buf->read_wait); -} - -static void __utt_wakeup_timer(unsigned long val) -{ - struct utt_trace *utt = (struct utt_trace *)val; - int i; - - if (atomic_read(&utt->wakeup)) { - atomic_set(&utt->wakeup, 0); - if (utt->is_global) - __utt_wakeup_readers(utt->rchan->buf[0]); - else - for_each_possible_cpu(i) - __utt_wakeup_readers(utt->rchan->buf[i]); - } - - mod_timer(&utt->timer, jiffies + UTT_TIMER_INTERVAL); -} - -static void __utt_timer_init(struct utt_trace * utt) -{ - atomic_set(&utt->wakeup, 0); - init_timer(&utt->timer); - utt->timer.expires = jiffies + UTT_TIMER_INTERVAL; - utt->timer.function = __utt_wakeup_timer; - utt->timer.data = (unsigned long)utt; - add_timer(&utt->timer); -} - -static void utt_set_overwrite(int overwrite) -{ - utt_overwrite_flag = overwrite; -} - -static void utt_remove_root(struct utt_trace *utt) -{ - if (utt->utt_tree_root) { - if (!_stp_lock_transport_dir()) { - errk("Unable to lock transport directory.\n"); - return; - } - if (simple_empty(utt->utt_tree_root)) - debugfs_remove(utt->utt_tree_root); - _stp_unlock_transport_dir(); - utt->utt_tree_root = NULL; - } -} - -static void utt_remove_tree(struct utt_trace *utt) -{ - if (utt == NULL || utt->dir == NULL) - return; - debugfs_remove(utt->dir); - utt_remove_root(utt); -} - -static struct dentry *utt_create_tree(struct utt_trace *utt, const char *root, const char *name) -{ - struct dentry *dir = NULL; - - if (root == NULL || name == NULL) - return NULL; - - if (!utt->utt_tree_root) { - utt->utt_tree_root = _stp_get_root_dir(); - if (!utt->utt_tree_root) - goto err; - } - - dir = debugfs_create_dir(name, utt->utt_tree_root); - if (!dir) - utt_remove_root(utt); -err: - return dir; -} - -static void utt_trace_cleanup(struct utt_trace *utt) -{ - if (utt == NULL) - return; - if (utt->rchan) - relay_close(utt->rchan); - if (utt->dropped_file) - debugfs_remove(utt->dropped_file); - utt_remove_tree(utt); - _stp_kfree(utt); -} - -static 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) -{ -#ifdef STAPCONF_INODE_PRIVATE - filp->private_data = inode->i_private; -#else - filp->private_data = inode->u.generic_ip; -#endif - 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 (utt_overwrite_flag || !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) -{ - 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; - } - return file; -} - -static struct dentry *utt_create_global_buf_file_callback(const char *filename, - struct dentry *parent, - int mode, - struct rchan_buf *buf, - int *is_global) -{ - struct dentry *file; - *is_global = 1; - 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 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 - */ -static struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts) -{ - struct utt_trace *utt = NULL; - struct dentry *dir = NULL; - int ret = -EINVAL; - u64 npages; - struct sysinfo si; - - if (!utts->buf_size || !utts->buf_nr) - goto err; - - ret = -ENOMEM; - utt = _stp_kzalloc(sizeof(*utt)); - if (!utt) - goto err; - - ret = -ENOENT; - dir = utt_create_tree(utt, utts->root, utts->name); - if (!dir) - goto err; - utt->dir = dir; - 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; - - npages = utts->buf_size * utts->buf_nr; - if (!utts->is_global) - npages *= num_possible_cpus(); - 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) - 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->is_global = utts->is_global; - - 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->rchan) - relay_close(utt->rchan); - _stp_kfree(utt); - } - if (dir) - utt_remove_tree(utt); - utts->err = ret; - return NULL; -} - -static 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)++; - __utt_timer_init(utt); - smp_mb(); - utt->trace_state = Utt_trace_running; - ret = 0; - } - } else { - if (utt->trace_state == Utt_trace_running) { - utt->trace_state = Utt_trace_stopped; - del_timer_sync(&utt->timer); - relay_flush(utt->rchan); - ret = 0; - } - } - - return ret; -} diff --git a/runtime/transport/utt.h b/runtime/transport/utt.h deleted file mode 100644 index 2a479d70..00000000 --- a/runtime/transport/utt.h +++ /dev/null @@ -1,83 +0,0 @@ -#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; - struct dentry *dir; /* systemtap/module_name */ - struct dentry *dropped_file; - atomic_t dropped; - struct dentry *utt_tree_root; /* systemtap */ - void *private_data; - atomic_t wakeup; - struct timer_list timer; - int is_global; -}; - -#define UTT_TRACE_ROOT_NAME_SIZE 64 /* Largest string for a root dir identifier */ -#define UTT_TRACE_NAME_SIZE 64 /* Largest string for a trace identifier */ - -#ifndef UTT_TIMER_INTERVAL -#define UTT_TIMER_INTERVAL ((HZ + 99) / 100) /* Wakeup timer interval in jiffies (default 10 ms)*/ -#endif - -/* - * 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 */ -}; - - -static struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts); - -static int utt_trace_startstop(struct utt_trace *utt, int start, - unsigned int *trace_seq); -static void utt_trace_cleanup(struct utt_trace *utt); -static int utt_trace_remove(struct utt_trace *utt); - -#if STP_TRANSPORT_VERSION == 2 -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 inline void *utt_reserve(struct utt_trace *utt, size_t length) -{ -#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 NULL; -#endif -} -#endif - -#endif diff --git a/runtime/vsprintf.c b/runtime/vsprintf.c index 23810e75..674946b9 100644 --- a/runtime/vsprintf.c +++ b/runtime/vsprintf.c @@ -12,6 +12,8 @@ #ifndef _VSPRINTF_C_ #define _VSPRINTF_C_ +#include "transport/transport.h" + //forward declaration for _stp_vsnprintf static void * _stp_reserve_bytes (int); -- cgit From a655ff03c59722c229a40909d0de9e3dfe63483e Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 26 May 2009 14:08:57 -0500 Subject: Cleanup and better original transport support. * runtime/print.h: Moved _stp_reserve_bytes() prototype here. * runtime/vsprintf.c (_stp_vsnprintf): Includes print.h to get _stp_reserve_bytes() prototype. * runtime/transport/transport.c (_stp_remove_root_dir): Better cleanup for STP_TRANSPORT_VERSION == 1. (_stp_transport_fs_close): Ditto. --- runtime/print.h | 1 + runtime/transport/transport.c | 11 ++++++++++- runtime/vsprintf.c | 4 +--- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'runtime') diff --git a/runtime/print.h b/runtime/print.h index d5c588a3..c2731a2f 100644 --- a/runtime/print.h +++ b/runtime/print.h @@ -12,5 +12,6 @@ static int _stp_print_init(void); static void _stp_print_cleanup(void); +static void *_stp_reserve_bytes(int numbytes); #endif /* _STP_PRINT_H_ */ diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index ab0806f2..8425536a 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -470,8 +470,13 @@ static void _stp_remove_root_dir(void) errk("Unable to lock transport directory.\n"); return; } - if (simple_empty(__stp_root_dir)) + if (simple_empty(__stp_root_dir)) { +#if STP_TRANSPORT_VERSION == 1 + relayfs_remove_dir(__stp_root_dir); +#else debugfs_remove(__stp_root_dir); +#endif + } _stp_unlock_transport_dir(); __stp_root_dir = NULL; } @@ -529,7 +534,11 @@ static void _stp_transport_fs_close(void) _stp_transport_data_fs_close(); if (__stp_module_dir) { +#if STP_TRANSPORT_VERSION == 1 + relayfs_remove_dir(__stp_module_dir); +#else debugfs_remove(__stp_module_dir); +#endif __stp_module_dir = NULL; } diff --git a/runtime/vsprintf.c b/runtime/vsprintf.c index 674946b9..5875d509 100644 --- a/runtime/vsprintf.c +++ b/runtime/vsprintf.c @@ -12,11 +12,9 @@ #ifndef _VSPRINTF_C_ #define _VSPRINTF_C_ +#include "print.h" #include "transport/transport.h" -//forward declaration for _stp_vsnprintf -static void * _stp_reserve_bytes (int); - static int skip_atoi(const char **s) { int i=0; -- 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/control.c | 18 ++++++++++++++++++ runtime/transport/relay_v2.c | 29 +++++++++++++++++++++-------- runtime/transport/relayfs.c | 26 ++++++++++++++++++++------ runtime/transport/ring_buffer.c | 10 ++++++++++ runtime/transport/transport.c | 13 ++++--------- runtime/transport/transport.h | 14 ++++++++++++++ 6 files changed, 87 insertions(+), 23 deletions(-) (limited to 'runtime') diff --git a/runtime/transport/control.c b/runtime/transport/control.c index a1624152..11338eb2 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -100,6 +100,24 @@ static void _stp_ctl_write_dbug(int type, void *data, int len) case STP_TRANSPORT: _dbug("sending STP_TRANSPORT\n"); break; + case STP_CONNECT: + _dbug("sending STP_CONNECT\n"); + break; + case STP_DISCONNECT: + _dbug("sending STP_DISCONNECT\n"); + break; + case STP_BULK: + _dbug("sending STP_BULK\n"); + break; + case STP_READY: + case STP_RELOCATION: + case STP_BUF_INFO: + case STP_SUBBUFS_CONSUMED: + _dbug("sending old message\n"); + break; + case STP_REALTIME_DATA: + _dbug("sending %d bytes of STP_REALTIME_DATA\n", len); + break; case STP_REQUEST_EXIT: _dbug("sending STP_REQUEST_EXIT\n"); break; 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: diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index dac6db1d..191b932f 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -75,14 +75,29 @@ static struct rchan_callbacks stp_rchan_callbacks = .buf_full = __stp_relay_buf_full_callback, }; +static void _stp_transport_data_fs_start(void) +{ + if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED) + _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) { + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + _stp_relay_data.flushing = 1; + 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.rchan) { - _stp_relay_data.flushing = 1; - 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) @@ -111,9 +126,8 @@ static int _stp_transport_data_fs_init(void) = _stp_gid; } - /* We're off and running. */ - smp_mb(); - _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + /* We're initialized. */ + _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; return rc; err: diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 217d0735..bed441e5 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -425,6 +425,16 @@ static int _stp_transport_data_fs_init(void) return 0; } +static void _stp_transport_data_fs_start(void) +{ + /* Do nothing. */ +} + +static void _stp_transport_data_fs_stop(void) +{ + /* Do nothing. */ +} + static void _stp_transport_data_fs_close(void) { int cpu; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 8425536a..84959f71 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -135,11 +135,8 @@ static void _stp_cleanup_and_exit(int send_exit) if (failures) _stp_warn("There were %d transport failures.\n", failures); - dbug_trans(1, "************** calling startstop 0 *************\n"); -#if 0 - if (_stp_utt) - utt_trace_startstop(_stp_utt, 0, &utt_seq); -#endif + dbug_trans(1, "*** calling _stp_transport_data_fs_stop ***\n"); + _stp_transport_data_fs_stop(); dbug_trans(1, "ctl_send STP_EXIT\n"); if (send_exit) @@ -236,9 +233,9 @@ static void _stp_transport_close(void) if (_stp_utt) utt_trace_remove(_stp_utt); #endif /* #if 0 */ + _stp_transport_fs_close(); _stp_print_cleanup(); /* free print buffers */ _stp_mem_debug_done(); - _stp_transport_fs_close(); dbug_trans(1, "---- CLOSED ----\n"); } @@ -317,10 +314,8 @@ static int _stp_transport_init(void) if (_stp_print_init() < 0) goto err2; -#if 0 /* start transport */ - utt_trace_startstop(_stp_utt, 1, &utt_seq); -#endif /* #if 0 */ + _stp_transport_data_fs_start(); /* create workqueue of kernel threads */ _stp_wq = create_workqueue("systemtap"); diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index c560be5d..df2d496d 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -74,6 +74,20 @@ static int _stp_bufsize; */ static int _stp_transport_data_fs_init(void); +/* + * _stp_transport_data_fs_start + * + * This function actually starts the transport. + */ +static void _stp_transport_data_fs_start(void); + +/* + * _stp_transport_data_fs_start + * + * This function stops the transport without doing any cleanup. + */ +static void _stp_transport_data_fs_stop(void); + /* * _stp_transport_data_fs_close * -- cgit From af274e5bd4593fa79c0489e0b6105f4bd23310c8 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 3 Jun 2009 15:20:46 -0500 Subject: Make sure all DEBUG_TRANS output uses printk. * runtime/transport/control.c (_stp_ctl_write_cmd): Calls dbug_trans2 instead of _dbug (so that printk is used instead of the transport itself). (_stp_ctl_write_dbug): Ditto. * runtime/debug.h (dbug_trans2): New macro. --- runtime/debug.h | 6 ++++++ runtime/transport/control.c | 28 +++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) (limited to 'runtime') diff --git a/runtime/debug.h b/runtime/debug.h index ce0c3943..5c9cca74 100644 --- a/runtime/debug.h +++ b/runtime/debug.h @@ -38,8 +38,14 @@ printk(args); \ } \ } while (0) + +#define dbug_trans2(args...) do { \ + printk("%s:%d ",__FUNCTION__, __LINE__); \ + printk(args); \ + } while (0) #else #define dbug_trans(level, args...) ; +#define dbug_trans2(args...) ; #endif #ifdef DEBUG_UNWIND /* stack unwinder */ diff --git a/runtime/transport/control.c b/runtime/transport/control.c index 11338eb2..35130f0f 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -37,7 +37,8 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz #ifdef DEBUG_TRANS if (type < STP_MAX_CMD) - _dbug("Got %s. len=%d\n", _stp_command_name[type], (int)count); + dbug_trans2("Got %s. len=%d\n", _stp_command_name[type], + (int)count); #endif switch (type) { @@ -84,45 +85,46 @@ static void _stp_ctl_write_dbug(int type, void *data, int len) char buf[64]; switch (type) { case STP_START: - _dbug("sending STP_START\n"); + dbug_trans2("sending STP_START\n"); break; case STP_EXIT: - _dbug("sending STP_EXIT\n"); + dbug_trans2("sending STP_EXIT\n"); break; case STP_OOB_DATA: snprintf(buf, sizeof(buf), "%s", (char *)data); - _dbug("sending %d bytes of STP_OOB_DATA: %s\n", len, buf); + dbug_trans2("sending %d bytes of STP_OOB_DATA: %s\n", len, + buf); break; case STP_SYSTEM: snprintf(buf, sizeof(buf), "%s", (char *)data); - _dbug("sending STP_SYSTEM: %s\n", buf); + dbug_trans2("sending STP_SYSTEM: %s\n", buf); break; case STP_TRANSPORT: - _dbug("sending STP_TRANSPORT\n"); + dbug_trans2("sending STP_TRANSPORT\n"); break; case STP_CONNECT: - _dbug("sending STP_CONNECT\n"); + dbug_trans2("sending STP_CONNECT\n"); break; case STP_DISCONNECT: - _dbug("sending STP_DISCONNECT\n"); + dbug_trans2("sending STP_DISCONNECT\n"); break; case STP_BULK: - _dbug("sending STP_BULK\n"); + dbug_trans2("sending STP_BULK\n"); break; case STP_READY: case STP_RELOCATION: case STP_BUF_INFO: case STP_SUBBUFS_CONSUMED: - _dbug("sending old message\n"); + dbug_trans2("sending old message\n"); break; case STP_REALTIME_DATA: - _dbug("sending %d bytes of STP_REALTIME_DATA\n", len); + dbug_trans2("sending %d bytes of STP_REALTIME_DATA\n", len); break; case STP_REQUEST_EXIT: - _dbug("sending STP_REQUEST_EXIT\n"); + dbug_trans2("sending STP_REQUEST_EXIT\n"); break; default: - _dbug("ERROR: unknown message type: %d\n", type); + dbug_trans2("ERROR: unknown message type: %d\n", type); break; } } -- cgit From 0bd709c3a8ff717f3ad78fdc079ce0468bec3ffa Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 28 May 2009 10:58:17 -0500 Subject: Avoid 1 case of holding a semaphore while mmap callbacks are being made. * runtime/task_finder.c (__stp_call_mmap_callbacks_with_addr): Renamed from __stp_call_mmap_callbacks_with_vma(). Also added some code from __stp_utrace_task_finder_target_syscall_exit() that locks the 'mmap_sem' semaphore. This avoids holding the semaphore while the mmap callbacks are made. (__stp_utrace_task_finder_target_syscall_exit): Just calls __stp_call_mmap_callbacks_with_addr() in the mmap case. --- runtime/task_finder.c | 132 ++++++++++++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 57 deletions(-) (limited to 'runtime') diff --git a/runtime/task_finder.c b/runtime/task_finder.c index f5e059ca..b35192a2 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -580,43 +580,90 @@ __stp_call_mmap_callbacks(struct stap_task_finder_target *tgt, } } + +static struct vm_area_struct * +__stp_find_file_based_vma(struct mm_struct *mm, unsigned long addr) +{ + struct vm_area_struct *vma = find_vma(mm, addr); + + // I'm not positive why the checking for vm_start > addr is + // necessary, but it seems to be (sometimes find_vma() returns + // a vma that addr doesn't belong to). + if (vma && (vma->vm_file == NULL || vma->vm_start > addr)) + vma = NULL; + return vma; +} + + static void -__stp_call_mmap_callbacks_with_vma(struct stap_task_finder_target *tgt, - struct task_struct *tsk, - struct vm_area_struct *vma) +__stp_call_mmap_callbacks_with_addr(struct stap_task_finder_target *tgt, + struct task_struct *tsk, + unsigned long addr) { - char *mmpath_buf; - char *mmpath; - int rc; + struct mm_struct *mm; + struct vm_area_struct *vma; + char *mmpath_buf = NULL; + char *mmpath = NULL; + long err; + unsigned long length; + unsigned long offset; + unsigned long vm_flags; - // Allocate space for a path - mmpath_buf = _stp_kmalloc(PATH_MAX); - if (mmpath_buf == NULL) { - _stp_error("Unable to allocate space for path"); + mm = get_task_mm(tsk); + if (! mm) return; - } - // Grab the path associated with this vma. + down_read(&mm->mmap_sem); + vma = __stp_find_file_based_vma(mm, addr); + if (vma) { + // Cache information we need from the vma + addr = vma->vm_start; + length = vma->vm_end - vma->vm_start; + offset = (vma->vm_pgoff << PAGE_SHIFT); + vm_flags = vma->vm_flags; + + // Allocate space for a path + mmpath_buf = _stp_kmalloc(PATH_MAX); + if (mmpath_buf == NULL) { + _stp_error("Unable to allocate space for path"); + } + else { + // Grab the path associated with this vma. #ifdef STAPCONF_DPATH_PATH - mmpath = d_path(&(vma->vm_file->f_path), mmpath_buf, PATH_MAX); + mmpath = d_path(&(vma->vm_file->f_path), mmpath_buf, + PATH_MAX); #else - mmpath = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt, - mmpath_buf, PATH_MAX); + mmpath = d_path(vma->vm_file->f_dentry, + vma->vm_file->f_vfsmnt, mmpath_buf, + PATH_MAX); #endif - if (mmpath == NULL || IS_ERR(mmpath)) { - rc = -PTR_ERR(mmpath); - _stp_error("Unable to get path (error %d) for pid %d", - rc, (int)tsk->pid); - } - else { - __stp_call_mmap_callbacks(tgt, tsk, mmpath, vma->vm_start, - vma->vm_end - vma->vm_start, - (vma->vm_pgoff << PAGE_SHIFT), - vma->vm_flags); + if (mmpath == NULL || IS_ERR(mmpath)) { + long err = ((mmpath == NULL) ? 0 + : -PTR_ERR(mmpath)); + _stp_error("Unable to get path (error %ld) for pid %d", + err, (int)tsk->pid); + mmpath = NULL; + } + } } - _stp_kfree(mmpath_buf); + + // At this point, we're done with the vma (assuming we found + // one). We can't hold the 'mmap_sem' semaphore while making + // callbacks. + up_read(&mm->mmap_sem); + + if (mmpath) + __stp_call_mmap_callbacks(tgt, tsk, mmpath, addr, + length, offset, vm_flags); + + // Cleanup. + if (mmpath_buf) + _stp_kfree(mmpath_buf); + mmput(mm); + return; } + static inline void __stp_call_munmap_callbacks(struct stap_task_finder_target *tgt, struct task_struct *tsk, unsigned long addr, @@ -1055,19 +1102,6 @@ utftq_out: } -static struct vm_area_struct * -__stp_find_file_based_vma(struct mm_struct *mm, unsigned long addr) -{ - struct vm_area_struct *vma = find_vma(mm, addr); - - // I'm not positive why the checking for vm_start > addr is - // necessary, but it seems to be (sometimes find_vma() returns - // a vma that addr doesn't belong to). - if (vma && (vma->vm_file == NULL || vma->vm_start > addr)) - vma = NULL; - return vma; -} - #ifdef UTRACE_ORIG_VERSION static u32 __stp_utrace_task_finder_target_syscall_entry(struct utrace_attached_engine *engine, @@ -1194,24 +1228,8 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, } else if (entry->syscall_no == MMAP_SYSCALL_NO(tsk) || entry->syscall_no == MMAP2_SYSCALL_NO(tsk)) { - struct mm_struct *mm; - - mm = get_task_mm(tsk); - if (mm) { - struct vm_area_struct *vma; - - down_read(&mm->mmap_sem); - vma = __stp_find_file_based_vma(mm, rv); - - // Call the callbacks - if (vma) { - __stp_call_mmap_callbacks_with_vma(tgt, tsk, - vma); - } - - up_read(&mm->mmap_sem); - mmput(mm); - } + // Call the callbacks + __stp_call_mmap_callbacks_with_addr(tgt, tsk, rv); } else { // mprotect // Call the callbacks -- cgit From b56f0c8b802fbdf93f40b4a233095ea970cfed2b Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 1 Jun 2009 12:20:08 -0500 Subject: Avoid holding semaphore while making mmap callbacks. * runtime/task_finder.c (__stp_call_mmap_callbacks_for_task): Grabs the 'mmap_sem' sempaphore. Caches vma information, releases the semaphore, then makes mmap callbacks. (__stp_utrace_task_finder_target_quiesce): Calls __stp_call_mmap_callbacks_for_task() to make mmap callbacks on initial attach to a task. --- runtime/task_finder.c | 182 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 130 insertions(+), 52 deletions(-) (limited to 'runtime') diff --git a/runtime/task_finder.c b/runtime/task_finder.c index b35192a2..dab56170 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -983,6 +983,135 @@ __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, return UTRACE_DETACH; } +static void +__stp_call_mmap_callbacks_for_task(struct stap_task_finder_target *tgt, + struct task_struct *tsk) +{ + struct mm_struct *mm; + char *mmpath_buf; + char *mmpath; + struct vm_area_struct *vma; + int file_based_vmas = 0; + struct vma_cache_t { +#ifdef STAPCONF_DPATH_PATH + struct path *f_path; +#else + struct dentry *f_dentry; + struct vfsmount *f_vfsmnt; +#endif + unsigned long addr; + unsigned long length; + unsigned long offset; + unsigned long vm_flags; + }; + struct vma_cache_t *vma_cache = NULL; + struct vma_cache_t *vma_cache_p; + + /* Call the mmap_callback for every vma associated with + * a file. */ + mm = get_task_mm(tsk); + if (! mm) + return; + + // Allocate space for a path + mmpath_buf = _stp_kmalloc(PATH_MAX); + if (mmpath_buf == NULL) { + mmput(mm); + _stp_error("Unable to allocate space for path"); + return; + } + + down_read(&mm->mmap_sem); + + // First find the number of file-based vmas. + vma = mm->mmap; + while (vma) { + if (vma->vm_file) + file_based_vmas++; + vma = vma->vm_next; + } + + // Now allocate an array to cache vma information in. + if (file_based_vmas > 0) + vma_cache = _stp_kmalloc(sizeof(struct vma_cache_t) + * file_based_vmas); + if (vma_cache != NULL) { + // Loop through the vmas again, and cache needed information. + vma = mm->mmap; + vma_cache_p = vma_cache; + while (vma) { + if (vma->vm_file) { +#ifdef STAPCONF_DPATH_PATH + // Notice we're increasing the reference + // count for 'f_path'. This way it won't + // get deleted from out under us. + vma_cache_p->f_path = &(vma->vm_file->f_path); + path_get(vma_cache_p->f_path); +#else + // Notice we're increasing the reference + // count for 'f_dentry' and 'f_vfsmnt'. + // This way they won't get deleted from + // out under us. + vma_cache_p->f_dentry = vma->vm_file->f_dentry; + dget(vma_cache_p->f_path); + vma_cache_p->f_vfsmnt = vma->vm_file->f_vfsmnt; + mntget(vma_cache_p->f_vfsmnt); +#endif + vma_cache_p->addr = vma->vm_start; + vma_cache_p->length = vma->vm_end - vma->vm_start; + vma_cache_p->offset = (vma->vm_pgoff << PAGE_SHIFT); + vma_cache_p->vm_flags = vma->vm_flags; + vma_cache_p++; + } + vma = vma->vm_next; + } + } + + // At this point, we're done with the vmas (assuming we found + // any). We can't hold the 'mmap_sem' semaphore while making + // callbacks. + up_read(&mm->mmap_sem); + + if (vma_cache) { + int i; + + // Loop over our cached information and make callbacks + // based on it. + vma_cache_p = vma_cache; + for (i = 0; i < file_based_vmas; i++) { +#ifdef STAPCONF_DPATH_PATH + mmpath = d_path(vma_cache_p->f_path, mmpath_buf, + PATH_MAX); + path_put(vma_cache_p->f_path); +#else + mmpath = d_path(vma_cache_p->f_dentry, + vma_cache_p->f_vfsmnt, mmpath_buf, + PATH_MAX); + dput(vma_cache_p->f_dentry); + mntput(vma_cache_p->f_vfsmnt); +#endif + if (mmpath == NULL || IS_ERR(mmpath)) { + long err = ((mmpath == NULL) ? 0 + : -PTR_ERR(mmpath)); + _stp_error("Unable to get path (error %ld) for pid %d", + err, (int)tsk->pid); + } + else { + __stp_call_mmap_callbacks(tgt, tsk, mmpath, + vma_cache_p->addr, + vma_cache_p->length, + vma_cache_p->offset, + vma_cache_p->vm_flags); + } + vma_cache_p++; + } + _stp_kfree(vma_cache); + } + + mmput(mm); /* We're done with mm */ + _stp_kfree(mmpath_buf); +} + #ifdef UTRACE_ORIG_VERSION static u32 __stp_utrace_task_finder_target_quiesce(struct utrace_attached_engine *engine, @@ -1043,60 +1172,9 @@ __stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action, don't bother inform map callback clients about its memory map, since they will simply duplicate each other. */ if (tgt->mmap_events == 1 && tsk->tgid == tsk->pid) { - struct mm_struct *mm; - char *mmpath_buf; - char *mmpath; - struct vm_area_struct *vma; - int rc; - - /* Call the mmap_callback for every vma associated with - * a file. */ - mm = get_task_mm(tsk); - if (! mm) - goto utftq_out; - - // Allocate space for a path - mmpath_buf = _stp_kmalloc(PATH_MAX); - if (mmpath_buf == NULL) { - mmput(mm); - _stp_error("Unable to allocate space for path"); - goto utftq_out; - } - - down_read(&mm->mmap_sem); - vma = mm->mmap; - while (vma) { - if (vma->vm_file) { -#ifdef STAPCONF_DPATH_PATH - mmpath = d_path(&(vma->vm_file->f_path), - mmpath_buf, PATH_MAX); -#else - mmpath = d_path(vma->vm_file->f_dentry, - vma->vm_file->f_vfsmnt, - mmpath_buf, PATH_MAX); -#endif - if (mmpath) { - __stp_call_mmap_callbacks(tgt, tsk, - mmpath, - vma->vm_start, - vma->vm_end - vma->vm_start, - (vma->vm_pgoff - << PAGE_SHIFT), - vma->vm_flags); - } - else { - _stp_dbug(__FUNCTION__, __LINE__, - "no mmpath?\n"); - } - } - vma = vma->vm_next; - } - up_read(&mm->mmap_sem); - mmput(mm); /* We're done with mm */ - _stp_kfree(mmpath_buf); + __stp_call_mmap_callbacks_for_task(tgt, tsk); } -utftq_out: __stp_tf_handler_end(); return UTRACE_RESUME; } -- cgit From 43229357282fd51eb1a3c7742932068873c27270 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 2 Jun 2009 11:21:24 -0500 Subject: Fixed cut-and-paste error. * runtime/task_finder.c (__stp_call_mmap_callbacks_for_task): Fixed cut-and-paste error. --- runtime/task_finder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime') diff --git a/runtime/task_finder.c b/runtime/task_finder.c index dab56170..672b21f1 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -1053,7 +1053,7 @@ __stp_call_mmap_callbacks_for_task(struct stap_task_finder_target *tgt, // This way they won't get deleted from // out under us. vma_cache_p->f_dentry = vma->vm_file->f_dentry; - dget(vma_cache_p->f_path); + dget(vma_cache_p->f_dentry); vma_cache_p->f_vfsmnt = vma->vm_file->f_vfsmnt; mntget(vma_cache_p->f_vfsmnt); #endif -- 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') 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 +- runtime/transport/relayfs.c | 2 +- runtime/transport/ring_buffer.c | 4 ++++ runtime/transport/transport.c | 15 ++------------- runtime/transport/transport.h | 17 +++++++++-------- 5 files changed, 17 insertions(+), 23 deletions(-) (limited to 'runtime') 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; } diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index 191b932f..c557efbc 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -136,7 +136,7 @@ err: return rc; } -static void stp_relay_set_overwrite(int overwrite) +static void _stp_transport_data_fs_overwrite(int overwrite) { _stp_relay_data.rchan->overwrite = overwrite; } diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index bed441e5..45ad8e2b 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -448,3 +448,7 @@ static void _stp_transport_data_fs_close(void) __stp_free_ring_buffer(); } +static void _stp_transport_data_fs_overwrite(int overwrite) +{ + /* FIXME: Just a place holder for now. */ +} diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 84959f71..a1d90dcf 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -20,13 +20,6 @@ #include #include -#if 0 -static void utt_set_overwrite(int overwrite) -{ - return; -} -#endif - static int _stp_exit_flag = 0; static uid_t _stp_uid = 0; @@ -166,10 +159,8 @@ static void _stp_detach(void) _stp_ctl_attached = 0; _stp_pid = 0; -#if 0 if (!_stp_exit_flag) - utt_set_overwrite(1); -#endif + _stp_transport_data_fs_overwrite(1); cancel_delayed_work(&_stp_work); wake_up_interruptible(&_stp_ctl_wq); @@ -183,9 +174,7 @@ static void _stp_attach(void) dbug_trans(1, "attach\n"); _stp_ctl_attached = 1; _stp_pid = current->pid; -#if 0 - utt_set_overwrite(0); -#endif + _stp_transport_data_fs_overwrite(0); queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index df2d496d..b3d15ef3 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -11,19 +11,11 @@ /* amount of data a print can send. */ #define STP_BUFFER_SIZE 8192 -struct utt_trace; - static int _stp_ctl_write(int type, void *data, unsigned len); static int _stp_transport_init(void); static void _stp_transport_close(void); -static inline void *utt_reserve(struct utt_trace *utt, size_t length) -{ - return NULL; -} - - /* STP_CTL_BUFFER_SIZE is the maximum size of a message */ /* exchanged on the control channel. */ #if STP_TRANSPORT_VERSION == 1 @@ -96,6 +88,15 @@ static void _stp_transport_data_fs_stop(void); */ static void _stp_transport_data_fs_close(void); +/* + * _stp_transport_data_fs_overwrite - set data overwrite mode + * overwrite: boolean + * + * When in overwrite mode and the transport buffers are full, older + * data gets overwritten. + */ +static void _stp_transport_data_fs_overwrite(int overwrite); + /* * _stp_data_write_reserve - reserve bytes * size_request: number of bytes to reserve -- cgit From 7c0bbff77507c69b706af667ac33770fb6180cbb Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 18 Jun 2009 15:56:45 -0500 Subject: Removed unused code (and all references to 'utt'). --- runtime/transport/transport.c | 52 ------------------------------------------- 1 file changed, 52 deletions(-) (limited to 'runtime') diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index a1d90dcf..7f844f5d 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -31,9 +31,6 @@ static int _stp_ctl_attached = 0; static pid_t _stp_target = 0; static int _stp_probes_started = 0; -#if 1 -//static struct utt_trace *_stp_utt = NULL; -//static unsigned int utt_seq = 1; #include "control.h" #if STP_TRANSPORT_VERSION == 1 #include "relayfs.c" @@ -48,11 +45,6 @@ static int _stp_probes_started = 0; #endif #include "control.c" -#else /* #if 0 */ -#include "control.h" -#include "debugfs.c" -#include "control.c" -#endif /* if 0 */ static unsigned _stp_nsubbufs = 8; static unsigned _stp_subbuf_size = 65536*4; @@ -218,10 +210,6 @@ static void _stp_transport_close(void) _stp_cleanup_and_exit(0); destroy_workqueue(_stp_wq); _stp_unregister_ctl_channel(); -#if 0 - if (_stp_utt) - utt_trace_remove(_stp_utt); -#endif /* #if 0 */ _stp_transport_fs_close(); _stp_print_cleanup(); /* free print buffers */ _stp_mem_debug_done(); @@ -229,25 +217,6 @@ static void _stp_transport_close(void) dbug_trans(1, "---- CLOSED ----\n"); } -#if 0 -static struct utt_trace *_stp_utt_open(void) -{ - struct utt_trace_setup utts; - strlcpy(utts.root, "systemtap", sizeof(utts.root)); - strlcpy(utts.name, THIS_MODULE->name, sizeof(utts.name)); - utts.buf_size = _stp_subbuf_size; - utts.buf_nr = _stp_nsubbufs; - -#ifdef STP_BULKMODE - utts.is_global = 0; -#else - utts.is_global = 1; -#endif - - return utt_trace_setup(&utts); -} -#endif /* #if 0 */ - /** * _stp_transport_init() is called from the module initialization. * It does the bare minimum to exchange commands with staprun @@ -263,8 +232,6 @@ static int _stp_transport_init(void) _stp_gid = current_gid(); #endif -// DRS: is RELAY_GUEST/RELAY_HOST documented? does it work? are there -// test cases? #ifdef RELAY_GUEST /* Guest scripts use relay only for reporting warnings and errors */ _stp_subbuf_size = 65536; @@ -285,16 +252,6 @@ static int _stp_transport_init(void) if (_stp_transport_fs_init(THIS_MODULE->name) != 0) goto err0; -#if 0 -#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 -#else /* #if 0 */ -#endif /* #if 0 */ - /* create control channel */ if (_stp_register_ctl_channel() < 0) goto err1; @@ -318,21 +275,12 @@ static int _stp_transport_init(void) return 0; err3: - dbug_trans(1, "err3\n"); _stp_print_cleanup(); err2: - dbug_trans(1, "err2\n"); _stp_unregister_ctl_channel(); err1: -#if 0 - if (_stp_utt) - utt_trace_remove(_stp_utt); -#else - dbug_trans(1, "err1\n"); _stp_transport_fs_close(); -#endif /* #if 0 */ err0: - dbug_trans(1, "err0\n"); return -1; } -- cgit From f530a9fec01f287d42072632d5607d5fa275479d Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 18 Jun 2009 16:11:17 -0500 Subject: Moved global data into a single structure. --- runtime/transport/ring_buffer.c | 84 ++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 39 deletions(-) (limited to 'runtime') diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 45ad8e2b..418465c2 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -9,12 +9,6 @@ struct _stp_data_entry { unsigned char buf[]; }; -static struct ring_buffer *__stp_ring_buffer = NULL; - -/* _stp_poll_wait is a waitqueue for tasks blocked on - * _stp_data_poll_trace() */ -static DECLARE_WAIT_QUEUE_HEAD(_stp_poll_wait); - /* * Trace iterator - used by printout routines who present trace * results to users and which routines might sleep, etc: @@ -23,16 +17,24 @@ struct _stp_ring_buffer_data { int cpu; u64 ts; }; -static struct _stp_ring_buffer_data _stp_rb_data; -static cpumask_var_t _stp_trace_reader_cpumask; +struct _stp_relay_data_type { + struct ring_buffer *rb; + struct _stp_ring_buffer_data rb_data; + cpumask_var_t trace_reader_cpumask; +}; +static struct _stp_relay_data_type _stp_relay_data; + +/* _stp_poll_wait is a waitqueue for tasks blocked on + * _stp_data_poll_trace() */ +static DECLARE_WAIT_QUEUE_HEAD(_stp_poll_wait); 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; + free_cpumask_var(_stp_relay_data.trace_reader_cpumask); + if (_stp_relay_data.rb) + ring_buffer_free(_stp_relay_data.rb); + _stp_relay_data.rb = NULL; } static int __stp_alloc_ring_buffer(void) @@ -40,9 +42,10 @@ 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)) + if (!alloc_cpumask_var(&_stp_relay_data.trace_reader_cpumask, + GFP_KERNEL)) goto fail; - cpumask_clear(_stp_trace_reader_cpumask); + cpumask_clear(_stp_relay_data.trace_reader_cpumask); if (buffer_size == 0) { dbug_trans(1, "using default buffer size...\n"); @@ -53,11 +56,11 @@ static int __stp_alloc_ring_buffer(void) * 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) + _stp_relay_data.rb = ring_buffer_alloc(buffer_size, 0); + if (!_stp_relay_data.rb) goto fail; - dbug_trans(1, "size = %lu\n", ring_buffer_size(__stp_ring_buffer)); + dbug_trans(1, "size = %lu\n", ring_buffer_size(_stp_relay_data.rb)); return 0; fail: @@ -72,18 +75,18 @@ static int _stp_data_open_trace(struct inode *inode, struct file *file) /* 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); + if (!cpumask_test_cpu(cpu_file, _stp_relay_data.trace_reader_cpumask)) + cpumask_set_cpu(cpu_file, _stp_relay_data.trace_reader_cpumask); else { dbug_trans(1, "returning EBUSY\n"); return -EBUSY; } #else - if (!cpumask_empty(_stp_trace_reader_cpumask)) { + if (!cpumask_empty(_stp_relay_data.trace_reader_cpumask)) { dbug_trans(1, "returning EBUSY\n"); return -EBUSY; } - cpumask_setall(_stp_trace_reader_cpumask); + cpumask_setall(_stp_relay_data.trace_reader_cpumask); #endif file->private_data = inode->i_private; return 0; @@ -94,9 +97,9 @@ 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); + cpumask_clear_cpu(cpu_file, _stp_relay_data.trace_reader_cpumask); #else - cpumask_clear(_stp_trace_reader_cpumask); + cpumask_clear(_stp_relay_data.trace_reader_cpumask); #endif return 0; @@ -132,7 +135,7 @@ _stp_event_to_user(struct ring_buffer_event *event, char __user *ubuf, static ssize_t tracing_wait_pipe(struct file *filp) { - while (ring_buffer_empty(__stp_ring_buffer)) { + while (ring_buffer_empty(_stp_relay_data.rb)) { if ((filp->f_flags & O_NONBLOCK)) { dbug_trans(1, "returning -EAGAIN\n"); @@ -166,7 +169,7 @@ static ssize_t tracing_wait_pipe(struct file *filp) static struct ring_buffer_event * peek_next_event(int cpu, u64 *ts) { - return ring_buffer_peek(__stp_ring_buffer, cpu, ts); + return ring_buffer_peek(_stp_relay_data.rb, cpu, ts); } /* Find the next real event */ @@ -180,10 +183,10 @@ _stp_find_next_event(long cpu_file) * 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)) + if (ring_buffer_empty_cpu(_stp_relay_data.rb, (int)cpu_file)) return NULL; - event = peek_next_event(cpu_file, &_stp_rb_data.ts); - _stp_rb_data.cpu = cpu_file; + event = peek_next_event(cpu_file, &_stp_relay_data.rb_data.ts); + _stp_relay_data.rb_data.cpu = cpu_file; return event; #else @@ -194,7 +197,7 @@ _stp_find_next_event(long cpu_file) for_each_possible_cpu(cpu) { - if (ring_buffer_empty_cpu(__stp_ring_buffer, cpu)) + if (ring_buffer_empty_cpu(_stp_relay_data.rb, cpu)) continue; event = peek_next_event(cpu, &ts); @@ -209,8 +212,8 @@ _stp_find_next_event(long cpu_file) } } - _stp_rb_data.cpu = next_cpu; - _stp_rb_data.ts = next_ts; + _stp_relay_data.rb_data.cpu = next_cpu; + _stp_relay_data.rb_data.ts = next_ts; return next; #endif @@ -236,7 +239,7 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, goto out; /* stop when tracing is finished */ - if (ring_buffer_empty(__stp_ring_buffer)) { + if (ring_buffer_empty(_stp_relay_data.rb)) { sret = 0; goto out; } @@ -253,8 +256,9 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, if (len <= 0) break; - ring_buffer_consume(__stp_ring_buffer, _stp_rb_data.cpu, - &_stp_rb_data.ts); + ring_buffer_consume(_stp_relay_data.rb, + _stp_relay_data.rb_data.cpu, + &_stp_relay_data.rb_data.ts); ubuf += len; cnt -= len; sret += len; @@ -270,10 +274,10 @@ 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)) + if (! ring_buffer_empty(_stp_relay_data.rb)) return POLLIN | POLLRDNORM; poll_wait(filp, &_stp_poll_wait, poll_table); - if (! ring_buffer_empty(__stp_ring_buffer)) + if (! ring_buffer_empty(_stp_relay_data.rb)) return POLLIN | POLLRDNORM; dbug_trans(1, "exit\n"); @@ -326,7 +330,7 @@ _stp_data_write_reserve(size_t size_request, void **entry) size_request = __STP_MAX_RESERVE_SIZE; } - event = ring_buffer_lock_reserve(__stp_ring_buffer, + event = ring_buffer_lock_reserve(_stp_relay_data.rb, sizeof(struct _stp_data_entry) + size_request, 0); if (unlikely(! event)) { @@ -364,9 +368,9 @@ static int _stp_data_write_commit(void *entry) return -EINVAL; } - ret = ring_buffer_unlock_commit(__stp_ring_buffer, event, 0); + ret = ring_buffer_unlock_commit(_stp_relay_data.rb, event, 0); dbug_trans(1, "after commit, empty returns %d\n", - ring_buffer_empty(__stp_ring_buffer)); + ring_buffer_empty(_stp_relay_data.rb)); wake_up_interruptible(&_stp_poll_wait); return ret; @@ -380,6 +384,8 @@ static int _stp_transport_data_fs_init(void) int rc; long cpu; + _stp_relay_data.rb = NULL; + // allocate buffer dbug_trans(1, "entry...\n"); rc = __stp_alloc_ring_buffer(); -- 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/print_new.c | 5 ++--- runtime/transport/relay_v2.c | 11 +++++------ runtime/transport/relayfs.c | 11 +++++------ runtime/transport/ring_buffer.c | 16 ++++++++++++++-- runtime/transport/transport.h | 14 ++++++++++++++ 5 files changed, 40 insertions(+), 17 deletions(-) (limited to 'runtime') diff --git a/runtime/print_new.c b/runtime/print_new.c index 2d5a6e10..52017426 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -30,9 +30,8 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) pb->len = 0; -//DRS FIXME: this digs down too deep in internals -// if (unlikely(!_stp_utt || _stp_utt->trace_state != Utt_trace_running)) -// return; + if (unlikely(_stp_transport_get_state() != STP_TRANSPORT_RUNNING)) + return; #ifdef STP_BULKMODE #ifdef NO_PERCPU_HEADERS 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; diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index c557efbc..338b2771 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -23,12 +23,6 @@ #include #include -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; @@ -136,6 +130,11 @@ err: return rc; } +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.rchan->overwrite = overwrite; diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 418465c2..0b73d4b4 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -19,6 +19,7 @@ struct _stp_ring_buffer_data { }; struct _stp_relay_data_type { + enum _stp_transport_state transport_state; struct ring_buffer *rb; struct _stp_ring_buffer_data rb_data; cpumask_var_t trace_reader_cpumask; @@ -384,6 +385,7 @@ static int _stp_transport_data_fs_init(void) int rc; long cpu; + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; _stp_relay_data.rb = NULL; // allocate buffer @@ -428,17 +430,22 @@ static int _stp_transport_data_fs_init(void) } dbug_trans(1, "returning 0...\n"); + _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; return 0; } static void _stp_transport_data_fs_start(void) { - /* Do nothing. */ + if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED) { + _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + } } static void _stp_transport_data_fs_stop(void) { - /* Do nothing. */ + if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) { + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + } } static void _stp_transport_data_fs_close(void) @@ -454,6 +461,11 @@ static void _stp_transport_data_fs_close(void) __stp_free_ring_buffer(); } +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) { /* FIXME: Just a place holder for now. */ diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index b3d15ef3..871e37b3 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -54,10 +54,24 @@ static int _stp_ctl_attached; static int _stp_bufsize; + +enum _stp_transport_state { + STP_TRANSPORT_STOPPED, + STP_TRANSPORT_INITIALIZED, + STP_TRANSPORT_RUNNING, +}; + /* * All transports must provide the following functions. */ +/* + * _stp_transport_get_state + * + * This function returns the current transport state. + */ +static enum _stp_transport_state _stp_transport_get_state(void); + /* * _stp_transport_data_fs_init * -- cgit From ac4f1eca71edee2feb2cbdad1a044549f30da023 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 18 Jun 2009 16:49:59 -0500 Subject: Cleanup. * runtime/print_old.c: Removed unneeded file. * runtime/print_flush.c: Renamed from print_new.c * runtime/print.c: Includes print_flush.c (instead of print_new.c). --- runtime/print.c | 2 +- runtime/print_flush.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++ runtime/print_new.c | 129 -------------------------------------------------- runtime/print_old.c | 55 --------------------- 4 files changed, 130 insertions(+), 185 deletions(-) create mode 100644 runtime/print_flush.c delete mode 100644 runtime/print_new.c delete mode 100644 runtime/print_old.c (limited to 'runtime') diff --git a/runtime/print.c b/runtime/print.c index d51c8108..69e04073 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -89,7 +89,7 @@ static void _stp_print_cleanup (void) #if !defined(RELAY_GUEST) -#include "print_new.c" +#include "print_flush.c" #if defined(RELAY_HOST) EXPORT_SYMBOL_GPL(EXPORT_FN(stp_print_flush)); #endif diff --git a/runtime/print_flush.c b/runtime/print_flush.c new file mode 100644 index 00000000..52017426 --- /dev/null +++ b/runtime/print_flush.c @@ -0,0 +1,129 @@ +/* -*- linux-c -*- + * Print Flush Function + * Copyright (C) 2007-2008 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. + */ + +/** Send the print buffer to the transport now. + * Output accumulates in the print buffer until it + * is filled, or this is called. This MUST be called before returning + * from a probe or accumulated output in the print buffer will be lost. + * + * @note Preemption must be disabled to use this. + */ + +static DEFINE_SPINLOCK(_stp_print_lock); + +void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) +{ + size_t len = pb->len; + void *entry = NULL; + + /* check to see if there is anything in the buffer */ + dbug_trans(1, "len = %zu\n", len); + if (likely(len == 0)) + return; + + pb->len = 0; + + if (unlikely(_stp_transport_get_state() != STP_TRANSPORT_RUNNING)) + return; + +#ifdef STP_BULKMODE +#ifdef NO_PERCPU_HEADERS + { + char *bufp = pb->buf; + + while (len > 0) { + size_t bytes_reserved; + + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; + } + } + } + +#else /* !NO_PERCPU_HEADERS */ + + { + char *bufp = pb->buf; + struct _stp_trace t = { .sequence = _stp_seq_inc(), + .pdu_len = len}; + size_t bytes_reserved; + + bytes_reserved = _stp_data_write_reserve(sizeof(struct _stp_trace), &entry); + if (likely(entry && bytes_reserved > 0)) { + /* prevent unaligned access by using memcpy() */ + memcpy(_stp_data_entry_data(entry), &t, sizeof(t)); + _stp_data_write_commit(entry); + } + else { + atomic_inc(&_stp_transport_failures); + return; + } + + while (len > 0) { + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; + } + } + } +#endif /* !NO_PERCPU_HEADERS */ + +#else /* !STP_BULKMODE */ + +#if STP_TRANSPORT_VERSION == 1 + + if (unlikely(_stp_ctl_write(STP_REALTIME_DATA, pb->buf, len) <= 0)) + atomic_inc (&_stp_transport_failures); + +#else /* STP_TRANSPORT_VERSION != 1 */ + { + unsigned long flags; + char *bufp = pb->buf; + + dbug_trans(1, "calling _stp_data_write...\n"); + spin_lock_irqsave(&_stp_print_lock, flags); + while (len > 0) { + size_t bytes_reserved; + + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; + } + } + spin_unlock_irqrestore(&_stp_print_lock, flags); + } +#endif /* STP_TRANSPORT_VERSION != 1 */ +#endif /* !STP_BULKMODE */ +} diff --git a/runtime/print_new.c b/runtime/print_new.c deleted file mode 100644 index 52017426..00000000 --- a/runtime/print_new.c +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- linux-c -*- - * Print Flush Function - * Copyright (C) 2007-2008 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. - */ - -/** Send the print buffer to the transport now. - * Output accumulates in the print buffer until it - * is filled, or this is called. This MUST be called before returning - * from a probe or accumulated output in the print buffer will be lost. - * - * @note Preemption must be disabled to use this. - */ - -static DEFINE_SPINLOCK(_stp_print_lock); - -void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) -{ - size_t len = pb->len; - void *entry = NULL; - - /* check to see if there is anything in the buffer */ - dbug_trans(1, "len = %zu\n", len); - if (likely(len == 0)) - return; - - pb->len = 0; - - if (unlikely(_stp_transport_get_state() != STP_TRANSPORT_RUNNING)) - return; - -#ifdef STP_BULKMODE -#ifdef NO_PERCPU_HEADERS - { - char *bufp = pb->buf; - - while (len > 0) { - size_t bytes_reserved; - - bytes_reserved = _stp_data_write_reserve(len, &entry); - if (likely(entry && bytes_reserved > 0)) { - memcpy(_stp_data_entry_data(entry), bufp, - bytes_reserved); - _stp_data_write_commit(entry); - bufp += bytes_reserved; - len -= bytes_reserved; - } - else { - atomic_inc(&_stp_transport_failures); - break; - } - } - } - -#else /* !NO_PERCPU_HEADERS */ - - { - char *bufp = pb->buf; - struct _stp_trace t = { .sequence = _stp_seq_inc(), - .pdu_len = len}; - size_t bytes_reserved; - - bytes_reserved = _stp_data_write_reserve(sizeof(struct _stp_trace), &entry); - if (likely(entry && bytes_reserved > 0)) { - /* prevent unaligned access by using memcpy() */ - memcpy(_stp_data_entry_data(entry), &t, sizeof(t)); - _stp_data_write_commit(entry); - } - else { - atomic_inc(&_stp_transport_failures); - return; - } - - while (len > 0) { - bytes_reserved = _stp_data_write_reserve(len, &entry); - if (likely(entry && bytes_reserved > 0)) { - memcpy(_stp_data_entry_data(entry), bufp, - bytes_reserved); - _stp_data_write_commit(entry); - bufp += bytes_reserved; - len -= bytes_reserved; - } - else { - atomic_inc(&_stp_transport_failures); - break; - } - } - } -#endif /* !NO_PERCPU_HEADERS */ - -#else /* !STP_BULKMODE */ - -#if STP_TRANSPORT_VERSION == 1 - - if (unlikely(_stp_ctl_write(STP_REALTIME_DATA, pb->buf, len) <= 0)) - atomic_inc (&_stp_transport_failures); - -#else /* STP_TRANSPORT_VERSION != 1 */ - { - unsigned long flags; - char *bufp = pb->buf; - - dbug_trans(1, "calling _stp_data_write...\n"); - spin_lock_irqsave(&_stp_print_lock, flags); - while (len > 0) { - size_t bytes_reserved; - - bytes_reserved = _stp_data_write_reserve(len, &entry); - if (likely(entry && bytes_reserved > 0)) { - memcpy(_stp_data_entry_data(entry), bufp, - bytes_reserved); - _stp_data_write_commit(entry); - bufp += bytes_reserved; - len -= bytes_reserved; - } - else { - atomic_inc(&_stp_transport_failures); - break; - } - } - spin_unlock_irqrestore(&_stp_print_lock, flags); - } -#endif /* STP_TRANSPORT_VERSION != 1 */ -#endif /* !STP_BULKMODE */ -} diff --git a/runtime/print_old.c b/runtime/print_old.c deleted file mode 100644 index 5c117e5f..00000000 --- a/runtime/print_old.c +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- linux-c -*- - * Print Flush Function - * 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. - */ - -/** Send the print buffer to the transport now. - * Output accumulates in the print buffer until it - * is filled, or this is called. This MUST be called before returning - * from a probe or accumulated output in the print buffer will be lost. - * - * @note Preemption must be disabled to use this. - */ - -void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) -{ - uint32_t len = pb->len; - - /* check to see if there is anything in the buffer */ - if (likely (len == 0)) - return; - - pb->len = 0; - -#ifdef STP_BULKMODE - { -#ifdef NO_PERCPU_HEADERS - void *buf = relay_reserve(_stp_utt->rchan, len); - if (likely(buf)) - memcpy(buf, pb->buf, len); - else - atomic_inc (&_stp_transport_failures); -#else - void *buf = relay_reserve(_stp_utt->rchan, - sizeof(struct _stp_trace) + len); - if (likely(buf)) { - struct _stp_trace t = { .sequence = _stp_seq_inc(), - .pdu_len = len}; - memcpy(buf, &t, sizeof(t)); // prevent unaligned access - memcpy(buf + sizeof(t), pb->buf, len); - } else - atomic_inc (&_stp_transport_failures); -#endif - } -#else - { - if (unlikely(_stp_ctl_write(STP_REALTIME_DATA, pb->buf, len) <= 0)) - atomic_inc (&_stp_transport_failures); - } -#endif /* STP_BULKMODE */ -} -- cgit From 3aae22ce894f935ac1371f501a09cecfbde18727 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 19 Jun 2009 11:13:15 -0500 Subject: Disabled transport version 3 (for now). --- runtime/transport/transport.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'runtime') diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 7f844f5d..1d029e53 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -31,6 +31,12 @@ static int _stp_ctl_attached = 0; static pid_t _stp_target = 0; static int _stp_probes_started = 0; +// For now, disable transport version 3 +#if STP_TRANSPORT_VERSION == 3 +#undef STP_TRANSPORT_VERSION +#define STP_TRANSPORT_VERSION 2 +#endif + #include "control.h" #if STP_TRANSPORT_VERSION == 1 #include "relayfs.c" -- cgit From d3584129c20e4246ed5fe53b0f14105d8b7fa212 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 19 Jun 2009 18:19:51 -0400 Subject: Fix on-file flight recorder mode bugs on old kernel. * runtime/staprun/common.c (make_outfile_name): Moved from relay.c, fix not to open /dev/null.XXX output files, and add 'bulk' argument for bulkmode. * runtime/staprun/relay.c (make_outfile_name): Moved to common.c. * runtime/staprun/relay_old.c (open_oldoutfile): Fix to use fopen() and store FILE * to percpu_tmpfile[cpu]. --- runtime/staprun/common.c | 27 +++++++++++++++++++++++++++ runtime/staprun/relay.c | 30 +++--------------------------- runtime/staprun/relay_old.c | 17 ++++++++++------- runtime/staprun/staprun.h | 3 ++- 4 files changed, 42 insertions(+), 35 deletions(-) (limited to 'runtime') diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c index c67ce340..5c4a8431 100644 --- a/runtime/staprun/common.c +++ b/runtime/staprun/common.c @@ -66,6 +66,33 @@ int stap_strfloctime(char *buf, size_t max, const char *fmt, time_t t) return (int)ret; } +int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t, int bulk) +{ + int len; + if (PATH_MAX < max) + max = PATH_MAX; + len = stap_strfloctime(buf, max, outfile_name, t); + if (len < 0) { + err("Invalid FILE name format\n"); + return -1; + } + /* special case: for testing we sometimes want to write to /dev/null */ + if (strcmp(outfile_name, "/dev/null") == 0) { + strcpy(buf, "/dev/null"); + } else { + if (bulk) { + if (snprintf_chk(&buf[len], max - len, "_cpu%d.%d", + cpu, fnum)) + return -1; + } else { + /* stream mode */ + if (snprintf_chk(&buf[len], max - len, ".%d", fnum)) + return -1; + } + } + return 0; +} + void parse_args(int argc, char **argv) { int c; diff --git a/runtime/staprun/relay.c b/runtime/staprun/relay.c index b9796241..f4aa139f 100644 --- a/runtime/staprun/relay.c +++ b/runtime/staprun/relay.c @@ -73,31 +73,6 @@ time_t read_backlog(int cpu, int fnum) return time_backlog[cpu][fnum & BACKLOG_MASK]; } -int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t) -{ - int len; - len = stap_strfloctime(buf, max, outfile_name, t); - if (len < 0) { - err("Invalid FILE name format\n"); - return -1; - } - if (bulkmode) { - /* special case: for testing we sometimes want to write to /dev/null */ - if (strcmp(outfile_name, "/dev/null") == 0) { - strcpy(buf, "/dev/null"); - } else { - if (snprintf_chk(&buf[len], PATH_MAX - len, - "_cpu%d.%d", cpu, fnum)) - return -1; - } - } else { - /* stream mode */ - if (snprintf_chk(&buf[len], PATH_MAX - len, ".%d", fnum)) - return -1; - } - return 0; -} - static int open_outfile(int fnum, int cpu, int remove_file) { char buf[PATH_MAX]; @@ -112,14 +87,15 @@ static int open_outfile(int fnum, int cpu, int remove_file) if (remove_file) { /* remove oldest file */ if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max, - cpu, read_backlog(cpu, fnum - fnum_max)) < 0) + cpu, read_backlog(cpu, fnum - fnum_max), + bulkmode) < 0) return -1; remove(buf); /* don't care */ } write_backlog(cpu, fnum, t); } - if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t) < 0) + if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t, bulkmode) < 0) return -1; out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); if (out_fd[cpu] < 0) { diff --git a/runtime/staprun/relay_old.c b/runtime/staprun/relay_old.c index 33d2daf3..71d8acee 100644 --- a/runtime/staprun/relay_old.c +++ b/runtime/staprun/relay_old.c @@ -87,30 +87,33 @@ static int open_oldoutfile(int fnum, int cpu, int remove_file) if (fnum_max) { if (remove_file) { /* remove oldest file */ - if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max, - cpu, read_backlog(cpu, fnum - fnum_max)) < 0) + if (make_outfile_name(buf, PATH_MAX, + fnum - fnum_max, cpu, + read_backlog(cpu, fnum - fnum_max), + bulkmode) < 0) return -1; remove(buf); /* don't care */ } write_backlog(cpu, fnum, t); } - if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t) < 0) + if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t, bulkmode) < 0) return -1; } else if (bulkmode) { if (sprintf_chk(buf, "stpd_cpu%d.%d", cpu, fnum)) return -1; } else { /* stream mode */ - out_fd[cpu] = STDOUT_FILENO; + percpu_tmpfile[cpu] = stdout; return 0; } - out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); - if (out_fd[cpu] < 0) { + if((percpu_tmpfile[cpu] = fopen(buf, "w+")) == NULL) { perr("Couldn't open output file %s", buf); return -1; } - if (set_clexec(out_fd[cpu]) < 0) + if (set_clexec(fileno(percpu_tmpfile[cpu])) < 0) { + perr("Couldn't clear exec bit of open output file %s", buf); return -1; + } return 0; } /** diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index bd6402e4..3c9dab3f 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -120,7 +120,8 @@ int init_oldrelayfs(void); void close_oldrelayfs(int); int write_realtime_data(void *data, ssize_t nb); void setup_signals(void); -int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t); +int make_outfile_name(char *buf, int max, int fnum, int cpu, + time_t t, int bulk); int init_backlog(int cpu); void write_backlog(int cpu, int fnum, time_t t); time_t read_backlog(int cpu, int fnum); -- cgit