From 52aeb26b8d83c26e00adaf70bbf5a3a828689fb2 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 12 Mar 2009 17:12:38 -0700 Subject: PR9947: move runtime cleanup out of the work queue The kernel lockdep checking found a possible deadlock if a forced rmmod tried to destroy _stp_work_queue at the same time that the work queue was unregistering tracepoints. An unlikely scenario, but still possible. Now the work queue will just issue a STP_REQUEST_EXIT down to usermode, and usermode will echo back an STP_EXIT that triggers the actual probe cleanup. This way the unregistrations are happening in exactly the same context as the registrations were. --- runtime/staprun/mainloop.c | 8 ++++++++ runtime/transport/control.c | 7 ++++++- runtime/transport/transport.c | 20 ++++++++++++++++---- runtime/transport/transport_msgs.h | 8 +++++--- 4 files changed, 35 insertions(+), 8 deletions(-) (limited to 'runtime') diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index 29eb4f1f..db6ef6b7 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -477,6 +477,14 @@ int stp_main_loop(void) cleanup_and_exit(0); break; } + case STP_REQUEST_EXIT: + { + /* module asks us to start exiting, so send STP_EXIT */ + dbug(2, "got STP_REQUEST_EXIT\n"); + int32_t rc, btype = STP_EXIT; + rc = write(control_channel, &btype, sizeof(btype)); + break; + } case STP_START: { struct _stp_msg_start *t = (struct _stp_msg_start *)data; diff --git a/runtime/transport/control.c b/runtime/transport/control.c index edde244d..680d7306 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -13,6 +13,8 @@ static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; static DEFINE_SPINLOCK(_stp_ctl_ready_lock); +static void _stp_cleanup_and_exit(int send_exit); + static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { u32 type; @@ -46,7 +48,7 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz } break; case STP_EXIT: - _stp_exit_flag = 1; + _stp_cleanup_and_exit(1); break; case STP_BULK: #ifdef STP_BULKMODE @@ -93,6 +95,9 @@ static void _stp_ctl_write_dbug(int type, void *data, int len) case STP_TRANSPORT: _dbug("sending STP_TRANSPORT\n"); break; + case STP_REQUEST_EXIT: + _dbug("sending STP_REQUEST_EXIT\n"); + break; default: _dbug("ERROR: unknown message type: %d\n", type); break; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 7fcebd42..762c0a92 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -25,7 +25,6 @@ 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 @@ -89,13 +88,14 @@ 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) { - if (!_stp_exit_called) { + static int called = 0; + if (!called) { int failures; dbug_trans(1, "cleanup_and_exit (%d)\n", send_exit); _stp_exit_flag = 1; /* we only want to do this stuff once */ - _stp_exit_called = 1; + called = 1; if (_stp_probes_started) { dbug_trans(1, "calling probe_exit\n"); @@ -119,6 +119,18 @@ static void _stp_cleanup_and_exit(int send_exit) } } +static void _stp_request_exit(void) +{ + static int called = 0; + if (!called) { + /* we only want to do this once */ + called = 1; + dbug_trans(1, "ctl_send STP_REQUEST_EXIT\n"); + _stp_ctl_send(STP_REQUEST_EXIT, NULL, 0); + dbug_trans(1, "done with ctl_send STP_REQUEST_EXIT\n"); + } +} + /* * Called when stapio closes the control channel. */ @@ -169,7 +181,7 @@ 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); + _stp_request_exit(); if (likely(_stp_attached)) queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index 596f4925..0d9a5983 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -21,19 +21,20 @@ struct _stp_trace { enum { STP_START, - STP_EXIT, + STP_EXIT, STP_OOB_DATA, STP_SYSTEM, STP_TRANSPORT, STP_CONNECT, - STP_DISCONNECT, + STP_DISCONNECT, STP_BULK, STP_READY, - STP_RELOCATION, + STP_RELOCATION, /** deprecated STP_OLD_TRANSPORT **/ STP_BUF_INFO, STP_SUBBUFS_CONSUMED, STP_REALTIME_DATA, + STP_REQUEST_EXIT, STP_MAX_CMD }; @@ -52,6 +53,7 @@ static const char *_stp_command_name[] = { "STP_BUF_INFO", "STP_SUBBUFS_CONSUMED", "STP_REALTIME_DATA", + "STP_REQUEST_EXIT", }; #endif /* DEBUG_TRANS */ -- cgit From 436b47f678c2fc5397ed66a1eddf6b419cc6585b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 13 Mar 2009 16:22:04 -0700 Subject: Move lookup_bad_addr call in STAPCONF_PROBE_KERNEL With most of the implementations, kread/kwrite call deref/store_deref, and so it makes sense to have lookup_bad_addr in the latter as an underlying address check. However, in the STAPCONF_PROBE_KERNEL case that uses probe_kernel_read and probe_kernel_write, the roles are reversed, so lookup_bad_addr needs to be in kread/kwrite. Also note that __deref_bad and __store_deref_bad should only be used in cases that can be determined at compile time. These turn into invalid symbols which prevent the module from loading. (They might be better replaced with compile-time assertions.) --- runtime/loc2c-runtime.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'runtime') diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 0af19edc..92c017d3 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -187,22 +187,22 @@ #define kread(ptr) ({ \ typeof(*(ptr)) _v; \ - if (probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \ - DEREF_FAULT(ptr); \ + if (lookup_bad_addr((unsigned long)(ptr)) || \ + probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \ + DEREF_FAULT(ptr); \ _v; \ }) #define kwrite(ptr, value) ({ \ typeof(*(ptr)) _v; \ _v = (typeof(*(ptr)))(value); \ - if (probe_kernel_write((void *)(ptr), (void *)&_v, sizeof(*(ptr)))) \ - STORE_DEREF_FAULT(ptr); \ + if (lookup_bad_addr((unsigned long)addr) || \ + probe_kernel_write((void *)(ptr), (void *)&_v, sizeof(*(ptr)))) \ + STORE_DEREF_FAULT(ptr); \ }) #define deref(size, addr) ({ \ intptr_t _i; \ - if (lookup_bad_addr((unsigned long)addr)) \ - __deref_bad(); \ switch (size) { \ case 1: _i = kread((u8 *)(addr)); break; \ case 2: _i = kread((u16 *)(addr)); break; \ @@ -215,8 +215,6 @@ }) #define store_deref(size, addr, value) ({ \ - if (lookup_bad_addr((unsigned long)addr)) \ - __store_deref_bad(); \ switch (size) { \ case 1: kwrite((u8 *)(addr), (value)); break; \ case 2: kwrite((u16 *)(addr), (value)); break; \ -- cgit From bb64f40b58a64a9ae065dba5058463ac604c3896 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Sun, 15 Mar 2009 15:29:01 +0100 Subject: Move vma module tracking from pr6866 branch to master. * tapsets.cxx (utrace_derived_probe_group::emit_module_decls): Always emit vm callback probe for __stp_tf_vm_cb. * runtime/task_finder.c (__stp_tf_vm_cb): Always expose, move _stp_dbug statements under ifdef DEBUG_TASK_FINDER_VMA. Find and record corresponding module when vm_path not NULL. * runtime/task_finder_vma.c (struct __stp_tf_vma_entry): Add _stp_module. (stap_add_vma_map_info): Add _stp_module argument and assign. (__stp_tf_get_vma_entry_addr): New static function to get the __stp_tf_vma_entry given an address. --- runtime/task_finder.c | 22 ++++++++++++++++------ runtime/task_finder_vma.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 7 deletions(-) (limited to 'runtime') diff --git a/runtime/task_finder.c b/runtime/task_finder.c index 9db713c3..ae381a41 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -55,7 +55,6 @@ typedef int (*stap_task_finder_vm_callback)(struct stap_task_finder_target *tgt, unsigned long vm_end, unsigned long vm_pgoff); -#ifdef DEBUG_TASK_FINDER_VMA static int __stp_tf_vm_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int map_p, char *vm_path, @@ -63,21 +62,32 @@ static int __stp_tf_vm_cb(struct stap_task_finder_target *tgt, unsigned long vm_end, unsigned long vm_pgoff) { + int i; +#ifdef DEBUG_TASK_FINDER_VMA _stp_dbug(__FUNCTION__, __LINE__, "vm_cb: tsk %d:%d path %s, start 0x%08lx, end 0x%08lx, offset 0x%lx\n", tsk->pid, map_p, vm_path, vm_start, vm_end, vm_pgoff); +#endif if (map_p) { - // FIXME: What should we do with vm_path? We can't save - // the vm_path pointer itself, but we don't have any - // storage space allocated to save it in... - stap_add_vma_map_info(tsk, vm_start, vm_end, vm_pgoff); + struct _stp_module *module = NULL; + if (vm_path != NULL) + for (i = 0; i < _stp_num_modules; i++) + if (strcmp(vm_path, _stp_modules[i]->name) == 0) + { +#ifdef DEBUG_TASK_FINDER_VMA + _stp_dbug(__FUNCTION__, __LINE__, + "vm_cb: matched path %s to module\n", vm_path); +#endif + module = _stp_modules[i]; + break; + } + stap_add_vma_map_info(tsk, vm_start, vm_end, vm_pgoff, module); } else { stap_remove_vma_map_info(tsk, vm_start, vm_end, vm_pgoff); } return 0; } -#endif struct stap_task_finder_target { /* private: */ diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c index 4dce4be8..87a32fe5 100644 --- a/runtime/task_finder_vma.c +++ b/runtime/task_finder_vma.c @@ -25,6 +25,9 @@ struct __stp_tf_vma_entry { unsigned long vm_end; unsigned long vm_pgoff; // Is that enough? Should we store a dcookie for vm_file? + + // Module that this vma entry is mapped from, if any. + struct _stp_module *module; }; static struct __stp_tf_vma_entry @@ -211,7 +214,8 @@ __stp_tf_get_vma_map_entry_internal(struct task_struct *tsk, // Add the vma info to the vma map hash table. static int stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start, - unsigned long vm_end, unsigned long vm_pgoff) + unsigned long vm_end, unsigned long vm_pgoff, + struct _stp_module *module) { struct hlist_head *head; struct hlist_node *node; @@ -242,6 +246,7 @@ stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start, entry->vm_start = vm_start; entry->vm_end = vm_end; entry->vm_pgoff = vm_pgoff; + entry->module = module; head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)]; hlist_add_head(&entry->hlist, head); @@ -305,3 +310,26 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr, mutex_unlock(&__stp_tf_vma_mutex); return rc; } + +// Get vma_entry of the address (vm_start/vm_end) if the vma is +// present in the vma hash table containing. +// Returns NULL if not present. +static struct __stp_tf_vma_entry * +__stp_tf_get_vma_entry_addr(struct task_struct *tsk, unsigned long addr) +{ + struct hlist_head *head; + struct hlist_node *node; + struct __stp_tf_vma_entry *entry; + + mutex_lock(&__stp_tf_vma_mutex); + head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)]; + hlist_for_each_entry(entry, node, head, hlist) { + if (tsk->pid == entry->pid + && addr >= entry->vm_start && addr < entry->vm_end) { + mutex_unlock(&__stp_tf_vma_mutex); + return entry; + } + } + mutex_unlock(&__stp_tf_vma_mutex); + return NULL; +} -- cgit From 924a2ea21d0276229a752e58e5c5c1a9346648be Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 16 Mar 2009 18:36:44 -0700 Subject: PR9951: Prevent GCC warnings in deref() In some configurations, GCC was warning about a possible use of _v in the deref macros. I could not reproduce the error, but the only case where _v is not written is if lookup_bad_addr rejects the address, in which case we will hit DEREF_FAULT and _v won't be used. Now we're priming _v=0 anyway, so GCC has no right to complain... --- runtime/loc2c-runtime.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'runtime') diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 92c017d3..16ddb950 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -186,7 +186,7 @@ */ #define kread(ptr) ({ \ - typeof(*(ptr)) _v; \ + typeof(*(ptr)) _v = 0; \ if (lookup_bad_addr((unsigned long)(ptr)) || \ probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \ DEREF_FAULT(ptr); \ @@ -202,14 +202,13 @@ }) #define deref(size, addr) ({ \ - intptr_t _i; \ + intptr_t _i = 0; \ switch (size) { \ case 1: _i = kread((u8 *)(addr)); break; \ case 2: _i = kread((u16 *)(addr)); break; \ case 4: _i = kread((u32 *)(addr)); break; \ case 8: _i = kread((u64 *)(addr)); break; \ default: __deref_bad(); \ - /* uninitialized _i should also be caught by -Werror */ \ } \ _i; \ }) @@ -235,7 +234,7 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ u8 _b; u16 _w; u32 _l; \ - intptr_t _v; \ + intptr_t _v = 0; \ if (lookup_bad_addr((unsigned long)addr)) \ _bad = 1; \ else \ @@ -275,7 +274,7 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ u8 _b; u16 _w; u32 _l; u64 _q; \ - intptr_t _v; \ + intptr_t _v = 0; \ if (lookup_bad_addr((unsigned long)addr)) \ _bad = 1; \ else \ @@ -392,7 +391,7 @@ extern void __store_deref_bad(void); #define deref(size, addr) \ ({ \ int _bad = 0; \ - intptr_t _v; \ + intptr_t _v = 0; \ if (lookup_bad_addr((unsigned long)addr)) \ _bad = 1; \ else \ -- cgit From 30cb532a560ed152b86506b80490e99195970271 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Tue, 17 Mar 2009 13:50:33 +0100 Subject: Get the canonical path of the main file for comparison at runtime. When given directly by the user through -d or in case of the kernel name and path might differ. path should be used for matching. * runtime/sym.h (_stp_module): Add path field. * runtime/task_finder.c (__stp_tf_vm_cb): Use module path to compare vm_path. * translate.cxx (dump_unwindsyms): Output canonical path. --- runtime/sym.h | 1 + runtime/task_finder.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime') diff --git a/runtime/sym.h b/runtime/sym.h index e642cab4..586b10ca 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -25,6 +25,7 @@ struct _stp_section { struct _stp_module { const char* name; + const char* path; /* canonical path used for runtime matching. */ struct _stp_section *sections; unsigned num_sections; diff --git a/runtime/task_finder.c b/runtime/task_finder.c index ae381a41..38f9145d 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -72,7 +72,7 @@ static int __stp_tf_vm_cb(struct stap_task_finder_target *tgt, struct _stp_module *module = NULL; if (vm_path != NULL) for (i = 0; i < _stp_num_modules; i++) - if (strcmp(vm_path, _stp_modules[i]->name) == 0) + if (strcmp(vm_path, _stp_modules[i]->path) == 0) { #ifdef DEBUG_TASK_FINDER_VMA _stp_dbug(__FUNCTION__, __LINE__, -- cgit From bc1a99dfcf9cd081ddf37f362dc1af2158c016b8 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Wed, 18 Mar 2009 11:42:53 +0100 Subject: Don't mutex_unlock in __stp_tf_get_vma_map_entry_internal. All callers of __stp_tf_get_vma_map_entry_internal lock and unlock the mutex correctly themselves in all cases. This unlock would trigger a double unlock. * runtime/task_finder_vma.c (__stp_tf_get_vma_map_entry_internal): Don't mutex_unlock(&__stp_tf_vma_mutex). --- runtime/task_finder_vma.c | 1 - 1 file changed, 1 deletion(-) (limited to 'runtime') diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c index 87a32fe5..83b206e5 100644 --- a/runtime/task_finder_vma.c +++ b/runtime/task_finder_vma.c @@ -203,7 +203,6 @@ __stp_tf_get_vma_map_entry_internal(struct task_struct *tsk, hlist_for_each_entry(entry, node, head, hlist) { if (tsk->pid == entry->pid && vm_start == entry->addr) { - mutex_unlock(&__stp_tf_vma_mutex); return entry; } } -- cgit From c32faac1fd0249ddd6265cf80c07a24e06d9aa0f Mon Sep 17 00:00:00 2001 From: Maynard Johnson Date: Wed, 18 Mar 2009 12:59:33 -0500 Subject: Fix for spinlock bad magic error with itrace probe point --- runtime/itrace.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'runtime') diff --git a/runtime/itrace.c b/runtime/itrace.c index ed32b0bc..da874f63 100644 --- a/runtime/itrace.c +++ b/runtime/itrace.c @@ -275,6 +275,7 @@ static int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe struct itrace_info *ui; struct task_struct *tsk; + spin_lock_init(&itrace_lock); rcu_read_lock(); tsk = find_task_by_vpid(tid); if (!tsk) { @@ -293,11 +294,6 @@ static int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe put_task_struct(tsk); rcu_read_unlock(); - spin_lock_init(&itrace_lock); - - /* set initial state */ - spin_lock(&itrace_lock); - spin_unlock(&itrace_lock); printk(KERN_INFO "usr_itrace_init: completed for tid = %d\n", tid); return 0; @@ -314,7 +310,6 @@ void static remove_usr_itrace_info(struct itrace_info *ui) if (debug) printk(KERN_INFO "remove_usr_itrace_info: tid=%d\n", ui->tid); - spin_lock(&itrace_lock); if (ui->tsk && ui->engine) { status = utrace_control(ui->tsk, ui->engine, UTRACE_DETACH); if (status < 0 && status != -ESRCH && status != -EALREADY) @@ -322,6 +317,7 @@ void static remove_usr_itrace_info(struct itrace_info *ui) "utrace_control(UTRACE_DETACH) returns %d\n", status); } + spin_lock(&itrace_lock); list_del(&ui->link); spin_unlock(&itrace_lock); kfree(ui); -- cgit From 601915ab6aebff06bfc830be3b0f69976a486d9d Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 19 Mar 2009 11:27:19 -0400 Subject: add runtime/autoconf magic for itrace on pre-find_task_by_vpid kernels --- runtime/autoconf-find-task-pid.c | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 runtime/autoconf-find-task-pid.c (limited to 'runtime') diff --git a/runtime/autoconf-find-task-pid.c b/runtime/autoconf-find-task-pid.c new file mode 100644 index 00000000..549d5ac3 --- /dev/null +++ b/runtime/autoconf-find-task-pid.c @@ -0,0 +1,6 @@ +#include + +void foo (pid_t k) { + struct task_struct *tsk = find_task_by_pid (k); + (void) tsk; +} -- cgit From da049631393c37bad502ffac08a3805778c8d60d Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 19 Mar 2009 11:28:04 -0400 Subject: start of rhel5 compatibility for itrace --- runtime/itrace.c | 42 +++++++++++++++++++++++++++++++++++++++++- runtime/utrace_compatibility.h | 9 ++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) (limited to 'runtime') diff --git a/runtime/itrace.c b/runtime/itrace.c index da874f63..3d9ded2f 100644 --- a/runtime/itrace.c +++ b/runtime/itrace.c @@ -1,6 +1,7 @@ /* * user space instruction tracing * Copyright (C) 2005, 2006, 2007, 2008, 2009 IBM Corp. + * 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 @@ -19,6 +20,7 @@ #include #include #include "uprobes/uprobes.h" +#include "utrace_compatibility.h" #ifndef put_task_struct #define put_task_struct(t) \ @@ -55,7 +57,7 @@ struct itrace_info { struct list_head link; }; -static u32 debug = 1; +static u32 debug = 0 /* 1 */; static LIST_HEAD(usr_itrace_info); static spinlock_t itrace_lock; @@ -118,10 +120,15 @@ static int __access_process_vm(struct task_struct *tsk, unsigned long addr, void return buf - old_buf; } +#ifdef UTRACE_ORIG_VERSION +static u32 usr_itrace_report_quiesce(struct utrace_attached_engine *engine, + struct task_struct *tsk) +#else static u32 usr_itrace_report_quiesce(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, unsigned long event) +#endif { int status; struct itrace_info *ui; @@ -129,10 +136,23 @@ static u32 usr_itrace_report_quiesce(enum utrace_resume_action action, ui = rcu_dereference(engine->data); WARN_ON(!ui); +#ifdef UTRACE_ORIG_VERSION + return (ui->step_flag); // XXX XXX XXX +#else return (event == 0 ? ui->step_flag : UTRACE_RESUME); +#endif } +#ifdef UTRACE_ORIG_VERSION +static u32 usr_itrace_report_signal( + struct utrace_attached_engine *engine, + struct task_struct *tsk, + struct pt_regs *regs, + u32 action, siginfo_t *info, + const struct k_sigaction *orig_ka, + struct k_sigaction *return_ka) +#else static u32 usr_itrace_report_signal(u32 action, struct utrace_attached_engine *engine, struct task_struct *tsk, @@ -140,6 +160,7 @@ static u32 usr_itrace_report_signal(u32 action, siginfo_t *info, const struct k_sigaction *orig_ka, struct k_sigaction *return_ka) +#endif { struct itrace_info *ui; u32 return_flags; @@ -174,16 +195,31 @@ static u32 usr_itrace_report_signal(u32 action, return return_flags; } + + +#ifdef UTRACE_ORIG_VERSION +static u32 usr_itrace_report_clone( + struct utrace_attached_engine *engine, + struct task_struct *parent, + unsigned long clone_flags, + struct task_struct *child) +#else static u32 usr_itrace_report_clone(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *parent, unsigned long clone_flags, struct task_struct *child) +#endif { return UTRACE_RESUME; } +#ifdef UTRACE_ORIG_VERSION +static u32 usr_itrace_report_death(struct utrace_attached_engine *e, + struct task_struct *tsk) +#else static u32 usr_itrace_report_death(struct utrace_attached_engine *e, struct task_struct *tsk, bool group_dead, int signal) +#endif { struct itrace_info *ui = rcu_dereference(e->data); WARN_ON(!ui); @@ -277,7 +313,11 @@ static int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe spin_lock_init(&itrace_lock); rcu_read_lock(); +#ifdef STAPCONF_FIND_TASK_PID + tsk = find_task_by_pid(tid); +#else tsk = find_task_by_vpid(tid); +#endif if (!tsk) { printk(KERN_ERR "usr_itrace_init: Cannot find process %d\n", tid); rcu_read_unlock(); diff --git a/runtime/utrace_compatibility.h b/runtime/utrace_compatibility.h index 00b841d2..4a70da42 100644 --- a/runtime/utrace_compatibility.h +++ b/runtime/utrace_compatibility.h @@ -1,6 +1,6 @@ /* * utrace compatibility defines and inlines - * Copyright (C) 2008 Red Hat Inc. + * Copyright (C) 2008-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 @@ -28,6 +28,8 @@ enum utrace_resume_action { UTRACE_STOP = UTRACE_ACTION_QUIESCE, UTRACE_RESUME = UTRACE_ACTION_RESUME, UTRACE_DETACH = UTRACE_ACTION_DETACH, + UTRACE_SINGLESTEP = UTRACE_ACTION_SINGLESTEP, + UTRACE_BLOCKSTEP = UTRACE_ACTION_BLOCKSTEP, }; static inline struct utrace_attached_engine * @@ -48,6 +50,11 @@ utrace_control(struct task_struct *target, case UTRACE_STOP: return utrace_set_flags(target, engine, (engine->flags | UTRACE_ACTION_QUIESCE)); + case UTRACE_SINGLESTEP: + case UTRACE_BLOCKSTEP: + return utrace_set_flags(target, engine, + engine->flags | action); + default: return -EINVAL; } -- cgit From d2bb12d37037345a77e90aa83512075d78ae968f Mon Sep 17 00:00:00 2001 From: Wenji Huang Date: Wed, 18 Mar 2009 11:17:25 -0400 Subject: PR9940: avoid duplicated calling of uprobes in shared libraries Add map_p argument to __stp_call_vm_callbacks_with_vma to well tune the vma callback. Signed-off-by: Wenji Huang --- runtime/task_finder.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'runtime') diff --git a/runtime/task_finder.c b/runtime/task_finder.c index 38f9145d..2b408763 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -1026,6 +1026,7 @@ __stp_utrace_task_finder_target_syscall_entry(enum utrace_resume_action action, static void __stp_call_vm_callbacks_with_vma(struct stap_task_finder_target *tgt, struct task_struct *tsk, + int map_p, struct vm_area_struct *vma) { char *mmpath_buf; @@ -1052,7 +1053,7 @@ __stp_call_vm_callbacks_with_vma(struct stap_task_finder_target *tgt, rc, (int)tsk->pid); } else { - __stp_call_vm_callbacks(tgt, tsk, 1, mmpath, + __stp_call_vm_callbacks(tgt, tsk, map_p, mmpath, vma->vm_start, vma->vm_end, (vma->vm_pgoff << PAGE_SHIFT)); } @@ -1145,7 +1146,7 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, down_read(&mm->mmap_sem); vma = __stp_find_file_based_vma(mm, rv); if (vma != NULL) { - __stp_call_vm_callbacks_with_vma(tgt, tsk, vma); + __stp_call_vm_callbacks_with_vma(tgt, tsk, 0, vma); } up_read(&mm->mmap_sem); mmput(mm); @@ -1218,6 +1219,7 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, && vma->vm_end <= entry->vm_end) { __stp_call_vm_callbacks_with_vma(tgt, tsk, + 1, vma); if (vma->vm_end >= entry->vm_end) break; -- cgit From f0b8d2671fa56e0e1dcb4cc09fd6f7edf70f8fa3 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 20 Mar 2009 11:54:15 -0400 Subject: PR6930: staprun: supports error message to syslog Add an interface (eprintf) to output error messages to syslogd, because staprun has no stderr after detaching from console. --- runtime/staprun/common.c | 21 +++++++++++++++++++++ runtime/staprun/mainloop.c | 2 +- runtime/staprun/staprun.h | 18 +++++++++++------- 3 files changed, 33 insertions(+), 8 deletions(-) (limited to 'runtime') diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c index fd16b4b8..b8860248 100644 --- a/runtime/staprun/common.c +++ b/runtime/staprun/common.c @@ -344,3 +344,24 @@ int send_request(int type, void *data, int len) if (rc < 0) return rc; return (rc != len+4); } + +#include + +static int use_syslog = 0; + +void eprintf(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + if (use_syslog) + vsyslog(LOG_ERR, fmt, va); + else + vfprintf(stderr, fmt, va); + va_end(va); +} + +void switch_syslog(const char *name) +{ + openlog(name, LOG_PID, LOG_DAEMON); + use_syslog = 1; +} diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index db6ef6b7..e91e6302 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -468,7 +468,7 @@ int stp_main_loop(void) } #endif case STP_OOB_DATA: - fputs((char *)data, stderr); + eprintf("%s", (char *)data); break; case STP_EXIT: { diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index 84cf63fc..4c43e3ee 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -33,31 +33,35 @@ #include #include #include +#include /* Include config.h to pick up dependency for --prefix usage. */ #include "config.h" -#define dbug(level, args...) {if (verbose>=level) {fprintf(stderr,"%s:%s:%d ",__name__,__FUNCTION__, __LINE__); fprintf(stderr,args);}} +extern void eprintf(const char *fmt, ...); +extern void switch_syslog(const char *name); + +#define dbug(level, args...) do {if (verbose>=level) {eprintf("%s:%s:%d ",__name__,__FUNCTION__, __LINE__); eprintf(args);}} while (0) extern char *__name__; /* print to stderr */ -#define err(args...) fprintf(stderr,args) +#define err(args...) eprintf(args) /* better perror() */ #define perr(args...) do { \ int _errno = errno; \ - fputs("ERROR: ", stderr); \ - fprintf(stderr, args); \ - fprintf(stderr, ": %s\n", strerror(_errno)); \ + eprintf("ERROR: "); \ + eprintf(args); \ + eprintf(": %s\n", strerror(_errno)); \ } while (0) /* Error messages. Use these for serious errors, not informational messages to stderr. */ -#define _err(args...) do {fprintf(stderr,"%s:%s:%d: ERROR: ",__name__, __FUNCTION__, __LINE__); fprintf(stderr,args);} while(0) +#define _err(args...) do {eprintf("%s:%s:%d: ERROR: ",__name__, __FUNCTION__, __LINE__); eprintf(args);} while(0) #define _perr(args...) do { \ int _errno = errno; \ _err(args); \ - fprintf(stderr, ": %s\n", strerror(_errno)); \ + eprintf(": %s\n", strerror(_errno)); \ } while (0) #define overflow_error() _err("Internal buffer overflow. Please file a bug report.\n") -- cgit From 54892f28a2747079fae4aa35b80598cbb993a4c3 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 20 Mar 2009 11:59:06 -0400 Subject: PR6930: stapio: run in background as a daemon Add '-D'(daemon mode) option to staprun/stapio for daemon mode. In this mode, stapio shows just its pid and detachs from console. Since it has no stdio, this mode requires -o option. stapio will exit when it receives SIGTERM or detects some error. --- runtime/staprun/common.c | 52 ++++++++++++++++++++++++++++++++++++++++++---- runtime/staprun/mainloop.c | 35 +++++++++++++++++++++++++++++++ runtime/staprun/staprun.h | 1 + 3 files changed, 84 insertions(+), 4 deletions(-) (limited to 'runtime') diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c index b8860248..a1b70d3b 100644 --- a/runtime/staprun/common.c +++ b/runtime/staprun/common.c @@ -27,6 +27,7 @@ int attach_mod; int delete_mod; int load_only; int need_uprobes; +int daemon_mode; /* module variables */ char *modname = NULL; @@ -35,6 +36,21 @@ char *modoptions[MAXMODOPTIONS]; int control_channel = -1; /* NB: fd==0 possible */ +static char path_buf[PATH_MAX]; +static char *get_abspath(char *path) +{ + int len; + if (path[0] == '/') + return path; + + len = strlen(getcwd(path_buf, PATH_MAX)); + if (len + 2 + strlen(path) >= PATH_MAX) + return NULL; + path_buf[len] = '/'; + strcpy(&path_buf[len + 1], path); + return path_buf; +} + void parse_args(int argc, char **argv) { int c; @@ -49,8 +65,9 @@ void parse_args(int argc, char **argv) delete_mod = 0; load_only = 0; need_uprobes = 0; + daemon_mode = 0; - while ((c = getopt(argc, argv, "ALuvb:t:dc:o:x:")) != EOF) { + while ((c = getopt(argc, argv, "ALuvb:t:dc:o:x:D")) != EOF) { switch (c) { case 'u': need_uprobes = 1; @@ -85,11 +102,20 @@ void parse_args(int argc, char **argv) case 'L': load_only = 1; break; + case 'D': + daemon_mode = 1; + break; default: usage(argv[0]); } } - + if (outfile_name) { + outfile_name = get_abspath(outfile_name); + if (outfile_name == NULL) { + err("File name is too long.\n"); + usage(argv[0]); + } + } if (attach_mod && load_only) { err("You can't specify the '-A' and '-L' options together.\n"); usage(argv[0]); @@ -118,12 +144,29 @@ void parse_args(int argc, char **argv) err("You can't specify the '-c' and '-x' options together.\n"); usage(argv[0]); } + + if (daemon_mode && load_only) { + err("You can't specify the '-D' and '-L' options together.\n"); + usage(argv[0]); + } + if (daemon_mode && delete_mod) { + err("You can't specify the '-D' and '-d' options together.\n"); + usage(argv[0]); + } + if (daemon_mode && target_cmd) { + err("You can't specify the '-D' and '-c' options together.\n"); + usage(argv[0]); + } + if (daemon_mode && outfile_name == NULL) { + err("You have to specify output FILE with '-D' option.\n"); + usage(argv[0]); + } } void usage(char *prog) { - err("\n%s [-v] [-c cmd ] [-x pid] [-u user]\n" - "\t[-A|-L] [-b bufsize] [-o FILE] MODULE [module-options]\n", prog); + err("\n%s [-v] [-c cmd ] [-x pid] [-u user] [-A|-L|-d]\n" + "\t[-b bufsize] [-o FILE [-D]] MODULE [module-options]\n", prog); err("-v Increase verbosity.\n"); err("-c cmd Command \'cmd\' will be run and staprun will\n"); err(" exit when it does. The '_stp_target' variable\n"); @@ -140,6 +183,7 @@ void usage(char *prog) err("-d Delete a module. Only detached or unused modules\n"); err(" the user has permission to access will be deleted. Use \"*\"\n"); err(" (quoted) to delete all unused modules.\n"); + err("-D Run in background. This requires '-o' option.\n"); err("MODULE can be either a module name or a module path. If a\n"); err("module name is used, it is looked for in the following\n"); err("directory: /lib/modules/`uname -r`/systemtap\n"); diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index e91e6302..b0d88073 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -318,6 +318,41 @@ int init_stapio(void) if (target_cmd) start_cmd(); + /* Run in background */ + if (daemon_mode) { + pid_t pid; + int ret; + dbug(2, "daemonizing stapio\n"); + + /* daemonize */ + ret = daemon(0, 1); /* don't close stdout at this time. */ + if (ret) { + err("Failed to daemonize stapio\n"); + return -1; + } + + /* change error messages to syslog. */ + switch_syslog("stapio"); + + /* show new pid */ + pid = getpid(); + fprintf(stdout, "%d\n", pid); + fflush(stdout); + + /* redirect all outputs to /dev/null */ + ret = open("/dev/null", O_RDWR); + if (ret < 0) { + err("Failed to open /dev/null\n"); + return -1; + } + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + dup2(ret, STDOUT_FILENO); + dup2(ret, STDERR_FILENO); + close(ret); + } + return 0; } diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index 4c43e3ee..b380cebd 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -157,6 +157,7 @@ extern int attach_mod; extern int delete_mod; extern int load_only; extern int need_uprobes; +extern int daemon_mode; /* getopt variables */ extern char *optarg; -- cgit From acd56c22068963ad48f39890f5307600ff7d5278 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 20 Mar 2009 12:11:30 -0400 Subject: PR6930: stapio: support file switching Add file-switching option(-S size[,N]) to stapio. This option has two arguments, 'size' and 'N', and requires -o option. - When the size of output file exceeds specified 'size'MB, staprun switches output file to the next file. For this purpose, all output file has a serial number as a suffix only when user specifies this option. - Using this option in bulk mode, the output file name will be 'FILE_cpuX.SERIAL'. - When the number of files exceeds specified N, staprun removes the oldest file. This argument can be omitted. --- runtime/staprun/common.c | 30 ++++++++++++++- runtime/staprun/mainloop.c | 15 ++------ runtime/staprun/relay.c | 69 +++++++++++++++++++++++++++++++++- runtime/staprun/relay_old.c | 92 ++++++++++++++++++++++++++++++++++++++++++++- runtime/staprun/staprun.h | 6 ++- 5 files changed, 195 insertions(+), 17 deletions(-) (limited to 'runtime') diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c index a1b70d3b..194488ef 100644 --- a/runtime/staprun/common.c +++ b/runtime/staprun/common.c @@ -28,6 +28,8 @@ int delete_mod; int load_only; int need_uprobes; int daemon_mode; +off_t fsize_max; +int fnum_max; /* module variables */ char *modname = NULL; @@ -54,6 +56,7 @@ static char *get_abspath(char *path) void parse_args(int argc, char **argv) { int c; + char *s; /* Initialize option variables. */ verbose = 0; @@ -66,8 +69,10 @@ void parse_args(int argc, char **argv) load_only = 0; need_uprobes = 0; daemon_mode = 0; + fsize_max = 0; + fnum_max = 0; - while ((c = getopt(argc, argv, "ALuvb:t:dc:o:x:D")) != EOF) { + while ((c = getopt(argc, argv, "ALuvb:t:dc:o:x:S:D")) != EOF) { switch (c) { case 'u': need_uprobes = 1; @@ -105,6 +110,16 @@ void parse_args(int argc, char **argv) case 'D': daemon_mode = 1; break; + case 'S': + fsize_max = strtoul(optarg, &s, 10); + fsize_max <<= 20; + if (s[0] == ',') + fnum_max = (int)strtoul(&s[1], &s, 10); + if (s[0] != '\0') { + err("Invalid file size option '%s'.\n", optarg); + usage(argv[0]); + } + break; default: usage(argv[0]); } @@ -161,12 +176,16 @@ void parse_args(int argc, char **argv) err("You have to specify output FILE with '-D' option.\n"); usage(argv[0]); } + if (outfile_name == NULL && fsize_max != 0) { + err("You have to specify output FILE with '-S' option.\n"); + usage(argv[0]); + } } void usage(char *prog) { err("\n%s [-v] [-c cmd ] [-x pid] [-u user] [-A|-L|-d]\n" - "\t[-b bufsize] [-o FILE [-D]] MODULE [module-options]\n", prog); + "\t[-b bufsize] [-o FILE [-D] [-S size[,N]]] MODULE [module-options]\n", prog); err("-v Increase verbosity.\n"); err("-c cmd Command \'cmd\' will be run and staprun will\n"); err(" exit when it does. The '_stp_target' variable\n"); @@ -184,6 +203,13 @@ void usage(char *prog) err(" the user has permission to access will be deleted. Use \"*\"\n"); err(" (quoted) to delete all unused modules.\n"); err("-D Run in background. This requires '-o' option.\n"); + err("-S size[,N] Switches output file to next file when the size\n"); + err(" of file reaches the specified size. The value\n"); + err(" should be an integer greater than 1 which is\n"); + err(" assumed to be the maximum file size in MB.\n"); + err(" When the number of output files reaches N, it\n"); + err(" switches to the first output file. You can omit\n"); + err(" the second argument.\n"); err("MODULE can be either a module name or a module path. If a\n"); err("module name is used, it is looked for in the following\n"); err("directory: /lib/modules/`uname -r`/systemtap\n"); diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index b0d88073..c80bbba4 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -489,18 +489,11 @@ int stp_main_loop(void) switch (type) { #ifdef STP_OLD_TRANSPORT case STP_REALTIME_DATA: - { - ssize_t bw = write(out_fd[0], data, nb); - if (bw >= 0 && bw != nb) { - nb = nb - bw; - bw = write(out_fd[0], data, nb); - } - if (bw != nb) { - _perr("write error (nb=%ld)", (long)nb); - cleanup_and_exit(0); - } - break; + if (write_realtime_data(data, nb)) { + _perr("write error (nb=%ld)", (long)nb); + cleanup_and_exit(0); } + break; #endif case STP_OOB_DATA: eprintf("%s", (char *)data); diff --git a/runtime/staprun/relay.c b/runtime/staprun/relay.c index 19621933..891913b0 100644 --- a/runtime/staprun/relay.c +++ b/runtime/staprun/relay.c @@ -44,6 +44,52 @@ static int ppoll(struct pollfd *fds, nfds_t nfds, } #endif +int make_outfile_name(char *buf, int max, int fnum, int cpu) +{ + 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, max, "%s_cpu%d.%d", + outfile_name, cpu, fnum)) + return -1; + } + } else { + /* stream mode */ + if (snprintf_chk(buf, max, "%s.%d", outfile_name, fnum)) + return -1; + } + return 0; +} + +static int open_outfile(int fnum, int cpu, int remove_file) +{ + char buf[PATH_MAX]; + if (!outfile_name) { + _err("-S is set without -o. Please file a bug report.\n"); + return -1; + } + + if (remove_file) { + /* remove oldest file */ + if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max, cpu) < 0) + return -1; + remove(buf); /* don't care */ + } + + if (make_outfile_name(buf, PATH_MAX, fnum, cpu) < 0) + return -1; + out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); + if (out_fd[cpu] < 0) { + perr("Couldn't open output file %s", buf); + return -1; + } + if (set_clexec(out_fd[cpu]) < 0) + return -1; + return 0; +} + /** * reader_thread - per-cpu channel buffer reader */ @@ -57,6 +103,9 @@ static void *reader_thread(void *data) struct timespec tim = {.tv_sec=0, .tv_nsec=200000000}, *timeout = &tim; sigset_t sigs; struct sigaction sa; + off_t wsize = 0; + int fnum = 0; + int remove_file = 0; sigemptyset(&sigs); sigaddset(&sigs,SIGUSR2); @@ -99,6 +148,19 @@ static void *reader_thread(void *data) } } while ((rc = read(relay_fd[cpu], buf, sizeof(buf))) > 0) { + wsize += rc; + /* Switching file */ + if (fsize_max && wsize > fsize_max) { + close(out_fd[cpu]); + fnum++; + if (fnum_max && fnum == fnum_max) + remove_file = 1; + if (open_outfile(fnum, cpu, remove_file) < 0) { + perr("Couldn't open file for cpu %d, exiting.", cpu); + return(NULL); + } + wsize = 0; + } if (write(out_fd[cpu], buf, rc) != rc) { perr("Couldn't write to output %d for cpu %d, exiting.", out_fd[cpu], cpu); return(NULL); @@ -163,7 +225,12 @@ int init_relayfs(void) return -1; } - if (bulkmode) { + if (fsize_max) { + /* switch file mode */ + for (i = 0; i < ncpus; i++) + if (open_outfile(0, i, 0) < 0) + return -1; + } else if (bulkmode) { for (i = 0; i < ncpus; i++) { if (outfile_name) { /* special case: for testing we sometimes want to write to /dev/null */ diff --git a/runtime/staprun/relay_old.c b/runtime/staprun/relay_old.c index bd746f19..25ba93bf 100644 --- a/runtime/staprun/relay_old.c +++ b/runtime/staprun/relay_old.c @@ -23,6 +23,14 @@ static int bulkmode = 0; unsigned subbuf_size = 0; unsigned n_subbufs = 0; +struct switchfile_ctrl_block { + off_t wsize; + int fnum; + int rmfile; +}; + +static struct switchfile_ctrl_block global_scb = {0, 0, 0}; + /* per-cpu buffer info */ static struct buf_status { @@ -70,6 +78,36 @@ void close_oldrelayfs(int detach) close_relayfs_files(i); } +static int open_oldoutfile(int fnum, int cpu, int remove_file) +{ + char buf[PATH_MAX]; + if (outfile_name) { + if (remove_file) { + /* remove oldest file */ + if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max, + cpu) < 0) + return -1; + remove(buf); /* don't care */ + } + if (make_outfile_name(buf, PATH_MAX, fnum, cpu) < 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; + return 0; + } + + out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); + if (out_fd[cpu] < 0) { + perr("Couldn't open output file %s", buf); + return -1; + } + if (set_clexec(out_fd[cpu]) < 0) + return -1; + return 0; +} /** * open_relayfs_files - open and mmap buffer and open output file. * Returns -1 on unexpected failure, 0 if file not found, 1 on success. @@ -104,6 +142,11 @@ static int open_relayfs_files(int cpu, const char *relay_filebase, const char *p return -1; } + if (fsize_max) { + if (open_oldoutfile(0, cpu, 0) < 0) + goto err2; + goto opened; + } if (outfile_name) { /* special case: for testing we sometimes want to * write to /dev/null */ @@ -126,6 +169,7 @@ static int open_relayfs_files(int cpu, const char *relay_filebase, const char *p perr("Couldn't open output file %s", tmp); goto err2; } +opened: total_bufsize = subbuf_size * n_subbufs; relay_buffer[cpu] = mmap(NULL, total_bufsize, PROT_READ, @@ -155,7 +199,8 @@ err1: /** * process_subbufs - write ready subbufs to disk */ -static int process_subbufs(struct _stp_buf_info *info) +static int process_subbufs(struct _stp_buf_info *info, + struct switchfile_ctrl_block *scb) { unsigned subbufs_ready, start_subbuf, end_subbuf, subbuf_idx, i; int len, cpu = info->cpu; @@ -173,6 +218,18 @@ static int process_subbufs(struct _stp_buf_info *info) padding = *((unsigned *)subbuf_ptr); subbuf_ptr += sizeof(padding); len = (subbuf_size - sizeof(padding)) - padding; + scb->wsize += len; + if (fsize_max && scb->wsize > fsize_max) { + fclose(percpu_tmpfile[cpu]); + scb->fnum ++; + if (fnum_max && scb->fnum == fnum_max) + scb->rmfile = 1; + if (open_oldoutfile(scb->fnum, cpu, scb->rmfile) < 0) { + perr("Couldn't open file for cpu %d, exiting.", cpu); + exit(1); + } + scb->wsize = 0; + } if (len) { if (fwrite_unlocked (subbuf_ptr, len, 1, percpu_tmpfile[cpu]) != 1) { _perr("Couldn't write to output file for cpu %d, exiting:", cpu); @@ -196,6 +253,7 @@ static void *reader_thread(void *data) struct _stp_consumed_info consumed_info; unsigned subbufs_consumed; cpu_set_t cpu_mask; + struct switchfile_ctrl_block scb = {0, 0, 0}; CPU_ZERO(&cpu_mask); CPU_SET(cpu, &cpu_mask); @@ -217,7 +275,7 @@ static void *reader_thread(void *data) } rc = read(proc_fd[cpu], &status[cpu].info, sizeof(struct _stp_buf_info)); - subbufs_consumed = process_subbufs(&status[cpu].info); + subbufs_consumed = process_subbufs(&status[cpu].info, &scb); if (subbufs_consumed) { if (subbufs_consumed > status[cpu].max_backlog) status[cpu].max_backlog = subbufs_consumed; @@ -232,6 +290,33 @@ static void *reader_thread(void *data) } while (1); } +/** + * write_realtime_data - write realtime data packet to disk + */ +int write_realtime_data(void *data, ssize_t nb) +{ + ssize_t bw; + global_scb.wsize += nb; + if (fsize_max && global_scb.wsize > fsize_max) { + close(out_fd[0]); + global_scb.fnum++; + if (fnum_max && global_scb.fnum == fnum_max) + global_scb.rmfile = 1; + if (open_oldoutfile(global_scb.fnum, 0, + global_scb.rmfile) < 0) { + perr("Couldn't open file, exiting."); + return -1; + } + global_scb.wsize = 0; + } + bw = write(out_fd[0], data, nb); + if (bw >= 0 && bw != nb) { + nb = nb - bw; + bw = write(out_fd[0], data, nb); + } + return bw != nb; +} + /** * init_relayfs - create files and threads for relayfs processing * @@ -249,6 +334,9 @@ int init_oldrelayfs(void) bulkmode = 1; if (!bulkmode) { + if (fsize_max) + return open_oldoutfile(0, 0, 0); + if (outfile_name) { out_fd[0] = open (outfile_name, O_CREAT|O_TRUNC|O_WRONLY, 0666); if (out_fd[0] < 0 || set_clexec(out_fd[0]) < 0) { diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index b380cebd..6d0f9179 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -9,7 +9,7 @@ * * Copyright (C) 2005-2008 Red Hat Inc. */ - +#define _FILE_OFFSET_BITS 64 #include #include #include @@ -117,7 +117,9 @@ int init_relayfs(void); void close_relayfs(void); 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); /* staprun_funcs.c */ void setup_staprun_signals(void); const char *moderror(int err); @@ -158,6 +160,8 @@ extern int delete_mod; extern int load_only; extern int need_uprobes; extern int daemon_mode; +extern off_t fsize_max; +extern int fnum_max; /* getopt variables */ extern char *optarg; -- cgit From 04ae1b090781725631ba3477ff77721b012cdaba Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 20 Mar 2009 13:38:29 -0400 Subject: PR9821: staprun supports subset of strftime. Add strftime subset format support for output file name to systemtap. This format will be evaluated when opening a new output file. --- runtime/staprun/common.c | 119 +++++++++++++++++++++++++++++++++++++++++++- runtime/staprun/relay.c | 89 +++++++++++++++++++++++++++------ runtime/staprun/relay_old.c | 50 +++++++++++++------ runtime/staprun/staprun.h | 6 ++- 4 files changed, 232 insertions(+), 32 deletions(-) (limited to 'runtime') diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c index 194488ef..8200ec9d 100644 --- a/runtime/staprun/common.c +++ b/runtime/staprun/common.c @@ -53,6 +53,113 @@ static char *get_abspath(char *path) return path_buf; } +int stap_strfloctime(char *buf, size_t max, const char *fmt, time_t t) +{ + char *c = buf; + const char *c2 = fmt, *end = buf + max; + int ret, num; + struct tm tm; + if (buf == NULL || fmt == NULL || max <= 1) + return -EINVAL; + localtime_r(&t, &tm); + + while (*c2 != '\0'){ + if (c + 1 >= end) + return -EINVAL; + if (*c2 != '%') { + *c++ = *c2++; + continue; + } + c2++; + switch (*c2++) { + case '%': + *c++ = '%'; + break; + case 'Y': + num = tm.tm_year + 1900; + goto numbering; + case 'y': + num = tm.tm_year % 100; + goto numbering02; + case 'C': + num = ((tm.tm_year + 1900 - 1) / 100) + 1; + goto numbering; + case 'm': + num = tm.tm_mon + 1; + goto numbering02; + case 'd': + num = tm.tm_mday; + goto numbering02; + case 'e': + num = tm.tm_mday; + goto numbering; + case 'F': + ret = snprintf(c, end - c, "%d-%02d-%02d", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + if (ret < 0) return ret; + c += ret; + break; + case 'H': + num = tm.tm_hour; + goto numbering02; + case 'I': + num = tm.tm_hour % 12; + if (num == 0) num = 12; + goto numbering02; + case 'j': + ret = snprintf(c, end - c, "%03d", tm.tm_yday); + if (ret < 0) return ret; + c += ret; + break; + case 'k': + num = tm.tm_hour; + goto numbering; + case 'l': + num = tm.tm_hour % 12; + if (num == 0) num = 12; + goto numbering; + case 'M': + num = tm.tm_min; + goto numbering02; + case 'S': + num = tm.tm_sec; + goto numbering02; + case 'R': + ret = snprintf(c, end - c, "%02d:%02d", + tm.tm_hour, tm.tm_min); + if (ret < 0) return ret; + c += ret; + break; + case 'T': + ret = snprintf(c, end - c, "%02d:%02d:%02d", + tm.tm_hour, tm.tm_min, tm.tm_sec); + if (ret < 0) return ret; + c += ret; + break; + case 'u': + num = tm.tm_wday == 0 ? 7 : tm.tm_wday; + goto numbering; + case 'w': + num = tm.tm_wday; + goto numbering; + default: + return -EINVAL; + } + continue; +numbering: + ret = snprintf(c, end - c, "%d", num); + if (ret < 0) return ret; + c += ret; + continue; +numbering02: + ret = snprintf(c, end - c, "%02d", num); + if (ret < 0) return ret; + c += ret; + } + *c = '\0'; + return c - buf; +} + void parse_args(int argc, char **argv) { int c; @@ -125,11 +232,19 @@ void parse_args(int argc, char **argv) } } if (outfile_name) { + char tmp[PATH_MAX]; + int ret; outfile_name = get_abspath(outfile_name); if (outfile_name == NULL) { err("File name is too long.\n"); usage(argv[0]); } + ret = stap_strfloctime(tmp, PATH_MAX - 18, /* = _cpuNNN.SSSSSSSSSS */ + outfile_name, time(NULL)); + if (ret < 0) { + err("Filename format is invalid or too long.\n"); + usage(argv[0]); + } } if (attach_mod && load_only) { err("You can't specify the '-A' and '-L' options together.\n"); @@ -191,7 +306,9 @@ void usage(char *prog) err(" exit when it does. The '_stp_target' variable\n"); err(" will contain the pid for the command.\n"); err("-x pid Sets the '_stp_target' variable to pid.\n"); - err("-o FILE Send output to FILE.\n"); + err("-o FILE Send output to FILE. This supports a subset of\n"); + err(" strftime(3) (%%%%,%%C,%%Y,%%y,%%m,%%d,%%e,%%F,%%H,%%I\n"); + err(" %%j,%%k,%%l,%%M,%%S,%%R,%%T,%%u,%%w) for FILE.\n"); err("-b buffer size The systemtap module specifies a buffer size.\n"); err(" Setting one here will override that value. The\n"); err(" value should be an integer between 1 and 4095 \n"); diff --git a/runtime/staprun/relay.c b/runtime/staprun/relay.c index 891913b0..50f295b5 100644 --- a/runtime/staprun/relay.c +++ b/runtime/staprun/relay.c @@ -17,6 +17,9 @@ static pthread_t reader[NR_CPUS]; static int relay_fd[NR_CPUS]; static int bulkmode = 0; static volatile int stop_threads = 0; +static time_t *time_backlog[NR_CPUS]; +static int backlog_order=0; +#define BACKLOG_MASK ((1 << backlog_order) - 1) /* * ppoll exists in glibc >= 2.4 @@ -44,20 +47,52 @@ static int ppoll(struct pollfd *fds, nfds_t nfds, } #endif -int make_outfile_name(char *buf, int max, int fnum, int cpu) +int init_backlog(int cpu) { + int order = 0; + if (!fnum_max) + return 0; + while (fnum_max >> order) order++; + if (fnum_max == 1<<(order-1)) order--; + time_backlog[cpu] = (time_t *)calloc(1< Date: Sun, 22 Mar 2009 11:20:23 -0400 Subject: PR9974: adapt to utrace_connected_engine -> utrace_engine Adjusted all headers that #include to follow with: /* PR9974: Adapt to struct renaming. */ --- runtime/itrace.c | 6 ++++++ runtime/task_finder.c | 6 ++++++ runtime/uprobes2/uprobes.c | 6 ++++++ runtime/uprobes2/uprobes.h | 5 +++++ runtime/utrace_compatibility.h | 5 +++++ 5 files changed, 28 insertions(+) (limited to 'runtime') diff --git a/runtime/itrace.c b/runtime/itrace.c index 3d9ded2f..618cbff0 100644 --- a/runtime/itrace.c +++ b/runtime/itrace.c @@ -18,6 +18,12 @@ #include #include #include + +/* PR9974: Adapt to struct renaming. */ +#ifdef UTRACE_API_VERSION +#define utrace_attached_engine utrace_engine +#endif + #include #include "uprobes/uprobes.h" #include "utrace_compatibility.h" diff --git a/runtime/task_finder.c b/runtime/task_finder.c index 2b408763..3f4908cb 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -6,6 +6,12 @@ #endif #include + +/* PR9974: Adapt to struct renaming. */ +#ifdef UTRACE_API_VERSION +#define utrace_attached_engine utrace_engine +#endif + #include #include #include diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c index af187fc9..a0e9f2fe 100644 --- a/runtime/uprobes2/uprobes.c +++ b/runtime/uprobes2/uprobes.c @@ -29,6 +29,12 @@ #include #include #define UPROBES_IMPLEMENTATION 1 + +/* PR9974: Adapt to struct renaming. */ +#ifdef UTRACE_API_VERSION +#define utrace_attached_engine utrace_engine +#endif + #include "uprobes.h" #include #include diff --git a/runtime/uprobes2/uprobes.h b/runtime/uprobes2/uprobes.h index 11d01f5c..112e29e2 100644 --- a/runtime/uprobes2/uprobes.h +++ b/runtime/uprobes2/uprobes.h @@ -23,6 +23,11 @@ #include #include +/* Adapt to struct renaming. */ +#ifdef UTRACE_API_VERSION +#define utrace_attached_engine utrace_engine +#endif + struct pt_regs; enum uprobe_type { diff --git a/runtime/utrace_compatibility.h b/runtime/utrace_compatibility.h index 4a70da42..5521a5c2 100644 --- a/runtime/utrace_compatibility.h +++ b/runtime/utrace_compatibility.h @@ -13,6 +13,11 @@ #include +/* PR9974: Adapt to struct renaming. */ +#ifdef UTRACE_API_VERSION +#define utrace_attached_engine utrace_engine +#endif + #ifdef UTRACE_ACTION_RESUME /* -- cgit