diff options
author | hunt <hunt> | 2008-02-27 19:45:45 +0000 |
---|---|---|
committer | hunt <hunt> | 2008-02-27 19:45:45 +0000 |
commit | 9a5de18784b77de82e5121861fac892c2d4d2630 (patch) | |
tree | 54d0a3fb138a31627788606953bb1cb37897caf8 | |
parent | a2dc47ddef0dbed1b0dc912c876f5f57f97c1ede (diff) | |
download | systemtap-steved-9a5de18784b77de82e5121861fac892c2d4d2630.tar.gz systemtap-steved-9a5de18784b77de82e5121861fac892c2d4d2630.tar.xz systemtap-steved-9a5de18784b77de82e5121861fac892c2d4d2630.zip |
2008-02-27 Martin Hunt <hunt@redhat.com>
* sym.h (_stp_module): Add text_size, lock, and unwind data
pointer.
* sym.c (_stp_find_module_by_addr): New function.
(_stp_kallsyms_lookup): Call _stp_find_module_by_addr().
(_stp_get_unwind_info): New.
* runtime.h: Move debug macros to debug.h. Include it.
* debug.h: New file.
* map.c: Update debug calls.
* map-gen.c: Update debug calls.
* pmap-gen.c: Update debug calls.
* mempool.c: New file.
* symbols.c: Use rwlocks. Use new dbug macros. Handle
unwind info if present.
* transport.c: Include mempool.c. Update dbug and kbug calls
to new macros.
* transport_msgs.h (_stp_command_name): Add
struct containing message names for debugging.
* control.c, procfs.c: Use new dbug macros. Use
new mempool functions.
-rw-r--r-- | runtime/ChangeLog | 16 | ||||
-rw-r--r-- | runtime/debug.h | 66 | ||||
-rw-r--r-- | runtime/map-gen.c | 5 | ||||
-rw-r--r-- | runtime/map.c | 6 | ||||
-rw-r--r-- | runtime/mempool.c | 135 | ||||
-rw-r--r-- | runtime/pmap-gen.c | 5 | ||||
-rw-r--r-- | runtime/runtime.h | 18 | ||||
-rw-r--r-- | runtime/staprun/symbols.c | 21 | ||||
-rw-r--r-- | runtime/sym.c | 203 | ||||
-rw-r--r-- | runtime/sym.h | 85 | ||||
-rw-r--r-- | runtime/transport/ChangeLog | 13 | ||||
-rw-r--r-- | runtime/transport/control.c | 209 | ||||
-rw-r--r-- | runtime/transport/procfs.c | 288 | ||||
-rw-r--r-- | runtime/transport/symbols.c | 185 | ||||
-rw-r--r-- | runtime/transport/transport.c | 33 | ||||
-rw-r--r-- | runtime/transport/transport_msgs.h | 23 |
16 files changed, 760 insertions, 551 deletions
diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 512fa061..497b9d5b 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,19 @@ +2008-02-27 Martin Hunt <hunt@redhat.com> + + * sym.h (_stp_module): Add text_size, lock, and unwind data + pointer. + * sym.c (_stp_find_module_by_addr): New function. + (_stp_kallsyms_lookup): Call _stp_find_module_by_addr(). + (_stp_get_unwind_info): New. + + * runtime.h: Move debug macros to debug.h. Include it. + * debug.h: New file. + * map.c: Update debug calls. + * map-gen.c: Update debug calls. + * pmap-gen.c: Update debug calls. + + * mempool.c: New file. + 2008-02-27 Dave Brolley <brolley@redhat.com> PR5189 diff --git a/runtime/debug.h b/runtime/debug.h new file mode 100644 index 00000000..8f877ede --- /dev/null +++ b/runtime/debug.h @@ -0,0 +1,66 @@ +/* Systemtap Debug Macros + * Copyright (C) 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. + */ + +#ifndef _STP_DEBUG_H_ +#define _STP_DEBUG_H_ + +/* These are always on. + * _dbug() writes to systemtap stderr. + * errk() writes to the system log. + */ +#define _dbug(args...) _stp_dbug(__FUNCTION__, __LINE__, args) + +#define errk(args...) do { \ + printk("Systemtap Error at %s:%d ",__FUNCTION__, __LINE__); \ + printk(args); \ + } while (0) + +#ifdef DEBUG_TRANSPORT +#undef DEBUG_TRANSPORT +#define DEBUG_TRANSPORT 1 +#else +#define DEBUG_TRANSPORT 0 +#endif + +#ifdef DEBUG_UNWIND +#undef DEBUG_UNWIND +#define DEBUG_UNWIND 2 +#else +#define DEBUG_UNWIND 0 +#endif + +#ifdef DEBUG_SYMBOLS +#undef DEBUG_SYMBOLS +#define DEBUG_SYMBOLS 4 +#else +#define DEBUG_SYMBOLS 0 +#endif + +#define DEBUG_TYPE (DEBUG_TRANSPORT|DEBUG_UNWIND|DEBUG_SYMBOLS) + +#if DEBUG_TYPE > 0 + +#define dbug(type, args...) do { \ + if ((type) & DEBUG_TYPE) \ + _stp_dbug(__FUNCTION__, __LINE__, args); \ + } while (0) + +#define kbug(type, args...) do { \ + if ((type) & DEBUG_TYPE) { \ + printk("%s:%d ",__FUNCTION__, __LINE__); \ + printk(args); \ + } \ + } while (0) + +#else +#define dbug(type, args...) ; +#define kbug(type, args...) ; +#endif /* DEBUG_TYPE > 0 */ + +#endif /* _STP_DEBUG_H_ */ diff --git a/runtime/map-gen.c b/runtime/map-gen.c index a17f7e34..ce6e8742 100644 --- a/runtime/map-gen.c +++ b/runtime/map-gen.c @@ -229,7 +229,6 @@ static key_data KEYSYM(map_get_key) (struct map_node *mn, int n, int *type) key_data ptr; struct KEYSYM(map_node) *m = (struct KEYSYM(map_node) *)mn; - dbug ("n = %d type=%lx\n", n, type); if (n > KEY_ARITY || n < 1) { if (type) *type = END; @@ -359,7 +358,6 @@ MAP KEYSYM(_stp_map_new) (unsigned max_entries, int htype, ...) start = va_arg(ap, int); stop = va_arg(ap, int); interval = va_arg(ap, int); - // dbug ("start=%d stop=%d interval=%d\n", start, stop, interval); va_end (ap); } @@ -404,7 +402,6 @@ int KEYSYM(__stp_map_set) (MAP map, ALLKEYSD(key), VSTYPE val, int add) hlist_for_each(e, head) { n = (struct KEYSYM(map_node) *)((long)e - sizeof(struct list_head)); - //dbug ("n=%lx key1=%ld n->key1=%ld\n", (long)n, key1, n->key1); if (KEY1_EQ_P(n->key1, key1) #if KEY_ARITY > 1 && KEY2_EQ_P(n->key2, key2) @@ -423,8 +420,6 @@ int KEYSYM(__stp_map_set) (MAP map, ALLKEYSD(key), VSTYPE val, int add) } } /* key not found */ - dbug("key not found\n"); - n = (struct KEYSYM(map_node)*)_new_map_create (map, head); if (n == NULL) return -1; diff --git a/runtime/map.c b/runtime/map.c index 70990876..513e27df 100644 --- a/runtime/map.c +++ b/runtime/map.c @@ -138,7 +138,6 @@ int64_t _stp_key_get_int64 (struct map_node *mn, int n) if (mn) { res = (*mn->map->get_key)(mn, n, &type).val; - dbug("type=%d\n", type); if (type != INT64) res = 0; } @@ -159,7 +158,6 @@ char *_stp_key_get_str (struct map_node *mn, int n) if (mn) { str = (*mn->map->get_key)(mn, n, &type).strp; - dbug("type=%d\n", type); if (type != STRING) str = "bad type"; } @@ -716,7 +714,6 @@ void _stp_map_printn (MAP map, int n, const char *fmt) struct map_node *ptr; int type, num; key_data kd; - dbug ("print map %lx fmt=%s\n", (long)map, fmt); if (n < 0) return; @@ -763,7 +760,6 @@ static struct map_node *_stp_new_agg(MAP agg, struct hlist_head *ahead, struct m { struct map_node *aptr; /* copy keys and aggregate */ - dbug("creating new entry in %lx\n", (long)agg); aptr = _new_map_create(agg, ahead); if (aptr == NULL) return NULL; @@ -952,12 +948,10 @@ static struct map_node *_new_map_create (MAP map, struct hlist_head *head) return NULL; } m = (struct map_node *)map->head.next; - dbug ("got %lx off head\n", (long)m); hlist_del_init(&m->hnode); } else { m = (struct map_node *)map->pool.next; map->num++; - dbug ("got %lx off pool\n", (long)m); } list_move_tail(&m->lnode, &map->head); diff --git a/runtime/mempool.c b/runtime/mempool.c new file mode 100644 index 00000000..0fbb4326 --- /dev/null +++ b/runtime/mempool.c @@ -0,0 +1,135 @@ +/* -*- linux-c -*- + * Preallocated memory pools + * Copyright (C) 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. + */ + +#ifndef _STP_MEMPOOL_C_ +#define _STP_MEMPOOL_C_ + +/* An opaque struct identifying the memory pool. */ +typedef struct { + struct list_head free_list; + unsigned num; + unsigned size; + spinlock_t lock; +} _stp_mempool_t; + +/* for internal use only */ +struct _stp_mem_buffer { + struct list_head list; + _stp_mempool_t *pool; + void *buf; +}; + +/* Delete a memory pool */ +static void _stp_mempool_destroy(_stp_mempool_t *pool) +{ + struct list_head *p, *tmp; + if (pool) { + list_for_each_safe(p, tmp, &pool->free_list) { + list_del(p); + _stp_kfree(p); + } + _stp_kfree(pool); + } +} + +/* Create a new memory pool */ +static _stp_mempool_t *_stp_mempool_init(size_t size, size_t num) +{ + int i, alloc_size; + struct _stp_mem_buffer *m; + + _stp_mempool_t *pool = (_stp_mempool_t *)_stp_kmalloc(sizeof(_stp_mempool_t)); + if (unlikely(pool == NULL)) { + errk("Memory allocation failed.\n"); + return NULL; + } + + INIT_LIST_HEAD(&pool->free_list); + spin_lock_init(&pool->lock); + + alloc_size = size + sizeof(struct _stp_mem_buffer) - sizeof(void *); + + for (i = 0; i < num; i++) { + m = (struct _stp_mem_buffer *)_stp_kmalloc(alloc_size); + if (unlikely(m == NULL)) + goto err; + m->pool = pool; + list_add((struct list_head *)m, &pool->free_list); + } + pool->num = num; + pool->size = alloc_size; + return pool; + +err: + _stp_mempool_destroy(pool); + return NULL; +} + +/* Resize a memory pool */ +static int _stp_mempool_resize(_stp_mempool_t *pool, size_t num) +{ + int i; + unsigned long flags; + struct _stp_mem_buffer *m; + + if (unlikely(num == 0 || num == pool->num)) + return pool->num; + + if (num > pool->num) { + for (i = 0; i < num - pool->num; i++) { + m = (struct _stp_mem_buffer *)_stp_kmalloc(pool->size); + if (unlikely(m == NULL)) + goto done; + m->pool = pool; + pool->num++; + spin_lock_irqsave(&pool->lock, flags); + list_add((struct list_head *)m, &pool->free_list); + spin_unlock_irqrestore(&pool->lock, flags); + } + } else { + for (i = 0; i < pool->num - num; i++) { + spin_lock_irqsave(&pool->lock, flags); + m = (struct _stp_mem_buffer *)pool->free_list.next; + list_del(&m->list); + spin_unlock_irqrestore(&pool->lock, flags); + _stp_kfree(m); + } + pool->num = num; + } +done: + return num; +} + +/* allocate a buffer from a memory pool */ +static void *_stp_mempool_alloc(_stp_mempool_t *pool) +{ + unsigned long flags; + struct _stp_mem_buffer *ptr = NULL; + spin_lock_irqsave(&pool->lock, flags); + if (likely(!list_empty(&pool->free_list))) { + ptr = (struct _stp_mem_buffer *)pool->free_list.next; + list_del_init(&ptr->list); + spin_unlock_irqrestore(&pool->lock, flags); + return &ptr->buf; + } + spin_unlock_irqrestore(&pool->lock, flags); + return NULL; +} + +/* return a buffer to its memory pool */ +static void _stp_mempool_free(void *buf) +{ + unsigned long flags; + struct _stp_mem_buffer *m = container_of(buf, struct _stp_mem_buffer, buf); + spin_lock_irqsave(&m->pool->lock, flags); + list_add(&m->list, &m->pool->free_list); + spin_unlock_irqrestore(&m->pool->lock, flags); +} +#endif /* _STP_MEMPOOL_C_ */ diff --git a/runtime/pmap-gen.c b/runtime/pmap-gen.c index 0efffdb6..8666549b 100644 --- a/runtime/pmap-gen.c +++ b/runtime/pmap-gen.c @@ -437,7 +437,6 @@ PMAP KEYSYM(_stp_pmap_new) (unsigned max_entries, int htype, ...) start = va_arg(ap, int); stop = va_arg(ap, int); interval = va_arg(ap, int); - // dbug ("start=%d stop=%d interval=%d\n", start, stop, interval); va_end (ap); } @@ -515,8 +514,6 @@ int KEYSYM(__stp_pmap_set) (MAP map, ALLKEYSD(key), VSTYPE val, int add) } /* key not found */ - dbug("key not found\n"); - n = (struct KEYSYM(pmap_node)*)_new_map_create (map, head); if (n == NULL) return -1; @@ -678,7 +675,6 @@ VALTYPE KEYSYM(_stp_pmap_get) (PMAP pmap, ALLKEYSD(key)) #endif ) { if (anode == NULL) { - // dbug("agg=%lx ahead=%lx\n", (long)agg, (long)ahead); anode = _stp_new_agg(agg, ahead, (struct map_node *)n); } else { if (clear_agg) { @@ -738,7 +734,6 @@ int KEYSYM(__stp_pmap_del) (MAP map, ALLKEYSD(key)) } /* key not found */ - dbug("key not found\n"); return 0; } diff --git a/runtime/runtime.h b/runtime/runtime.h index d951833d..318d3038 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -1,5 +1,5 @@ /* main header file - * Copyright (C) 2005-2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. * Copyright (C) 2005, 2006 Intel Corporation. * * This file is part of systemtap, and is free software. You can @@ -46,21 +46,7 @@ static void _stp_dbug (const char *func, int line, const char *fmt, ...); void _stp_error (const char *fmt, ...); -#ifdef DEBUG -/** Prints debug line. - * This function prints a debug message immediately to staprun. - * If the last character is not a newline, then one is added. - * @param args A variable number of args in a format like printf. - * @ingroup io - */ -#define dbug(args...) _stp_dbug(__FUNCTION__, __LINE__, args) -#define kbug(args...) {printk("%s:%d ",__FUNCTION__, __LINE__); printk(args); } -#else -#define dbug(args...) ; -#define kbug(args...) ; -#endif /* DEBUG */ -#define _dbug(args...) _stp_dbug(__FUNCTION__, __LINE__, args) -#define errk(args...) {printk("Systemtap Error at %s:%d ",__FUNCTION__, __LINE__); printk(args); } +#include "debug.h" /* atomic globals */ static atomic_t _stp_transport_failures = ATOMIC_INIT (0); diff --git a/runtime/staprun/symbols.c b/runtime/staprun/symbols.c index e33ee624..c7362d9e 100644 --- a/runtime/staprun/symbols.c +++ b/runtime/staprun/symbols.c @@ -19,9 +19,10 @@ static int send_data(int32_t type, void *data, int len) return write(control_channel, data, len); } + /* Get the sections for a module. Put them in the supplied buffer */ /* in the following order: */ -/* [struct _stp_msg_module][struct _stp_symbol sections ...][string data]*/ +/* [struct _stp_msg_module][struct _stp_symbol sections ...][string data][unwind data] */ /* Return the total length of all the data. */ #define SECDIR "/sys/module/%s/sections" @@ -31,8 +32,9 @@ static int get_sections(char *name, char *data_start, int datalen) char filename[STP_MODULE_NAME_LEN + 256]; char buf[32], strdata_start[32768]; char *strdata=strdata_start, *data=data_start; - int fd, len, res; + int fd, len, res, unwind_data_len=0; struct _stp_msg_module *mod = (struct _stp_msg_module *)data_start; + struct dirent *d; DIR *secdir; void *sec; @@ -63,6 +65,9 @@ static int get_sections(char *name, char *data_start, int datalen) return -1; } + /* FIXME: optionally fill in unwind data here */ + mod->unwind_len = unwind_data_len; + while ((d = readdir(secdir))) { char *secname = d->d_name; @@ -138,6 +143,14 @@ static int get_sections(char *name, char *data_start, int datalen) while (len--) *data++ = *strdata++; +#if 0 + if (unwind_data_len) { + if ((unwind_data_len + data - data_start) > datalen) + goto err0; + memcpy(data, unwind_data, unwind_data_len); + data += unwind_data_len; + } +#endif return data - data_start; err1: @@ -211,7 +224,7 @@ int do_kernel_symbols(void) int ret, num_syms, i = 0, struct_symbol_size; int max_syms= MAX_SYMBOLS, data_basesize = MAX_SYMBOLS*32; - if (kernel_ptr_size == 8) + if (kernel_ptr_size == 8) struct_symbol_size = sizeof(struct _stp_symbol64); else struct_symbol_size = sizeof(struct _stp_symbol32); @@ -285,10 +298,12 @@ int do_kernel_symbols(void) if (num_syms <= 0) goto err; + /* send header */ struct _stp_msg_symbol_hdr smsh; smsh.num_syms = num_syms; smsh.sym_size = (uint32_t)(dataptr - data_base); + smsh.unwind_size = (uint32_t)0; if (send_request(STP_SYMBOLS, &smsh, sizeof(smsh)) <= 0) goto err; diff --git a/runtime/sym.c b/runtime/sym.c index 56c93064..3c2f859a 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * Symbolic Lookup Functions - * Copyright (C) 2005, 2006, 2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. * Copyright (C) 2006 Intel Corporation. * * This file is part of systemtap, and is free software. You can @@ -9,8 +9,8 @@ * later version. */ -#ifndef _SYM_C_ -#define _SYM_C_ +#ifndef _STP_SYM_C_ +#define _STP_SYM_C_ #include "string.c" @@ -20,11 +20,12 @@ * @{ */ -unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset) { +unsigned long _stp_module_relocate(const char *module, const char *section, unsigned long offset) +{ static struct _stp_module *last = NULL; static struct _stp_symbol *last_sec; unsigned long flags; - int i,j; + int i, j; /* if module is -1, we invalidate last. _stp_del_module calls this when modules are deleted. */ if ((long)module == -1) { @@ -32,53 +33,52 @@ unsigned long _stp_module_relocate (const char *module, const char *section, uns return 0; } - dbug("%s, %s, %lx\n", module, section, offset); + dbug(DEBUG_SYMBOLS, "%s, %s, %lx\n", module, section, offset); - STP_LOCK_MODULES; - if (! module - || !strcmp (section, "") /* absolute, unrelocated address */ - || _stp_num_modules == 0) { - STP_UNLOCK_MODULES; - return offset; + STP_RLOCK_MODULES; + if (!module || !strcmp(section, "") /* absolute, unrelocated address */ + ||_stp_num_modules == 0) { + STP_RUNLOCK_MODULES; + return offset; } /* Most likely our relocation is in the same section of the same module as the last. */ if (last) { - if (!strcmp (module, last->name) && !strcmp (section, last_sec->symbol)) { + if (!strcmp(module, last->name) && !strcmp(section, last_sec->symbol)) { offset += last_sec->addr; - STP_UNLOCK_MODULES; - dbug("offset = %lx\n", offset); + STP_RUNLOCK_MODULES; + dbug(DEBUG_SYMBOLS, "offset = %lx\n", offset); return offset; } } /* not cached. need to scan all modules */ - if (! strcmp (module, "kernel")) { - STP_UNLOCK_MODULES; + if (!strcmp(module, "kernel")) { + STP_RUNLOCK_MODULES; /* See also transport/symbols.c (_stp_do_symbols). */ - if (strcmp (section, "_stext")) + if (strcmp(section, "_stext")) return 0; else return offset + _stp_modules[0]->text; } else { /* relocatable module */ - for (i = 1; i < _stp_num_modules; i++) { /* skip over [0]=kernel */ + for (i = 1; i < _stp_num_modules; i++) { /* skip over [0]=kernel */ last = _stp_modules[i]; if (strcmp(module, last->name)) continue; for (j = 0; j < (int)last->num_sections; j++) { last_sec = &last->sections[j]; - if (!strcmp (section, last_sec->symbol)) { + if (!strcmp(section, last_sec->symbol)) { offset += last_sec->addr; - STP_UNLOCK_MODULES; - dbug("offset = %lx\n", offset); + STP_RUNLOCK_MODULES; + dbug(DEBUG_SYMBOLS, "offset = %lx\n", offset); return offset; } } } } - STP_UNLOCK_MODULES; + STP_RUNLOCK_MODULES; last = NULL; return 0; } @@ -97,24 +97,15 @@ static unsigned long _stp_kallsyms_lookup_name(const char *name) return 0; } -static const char * _stp_kallsyms_lookup ( - unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset, - char **modname, - char *namebuf) +static struct _stp_module *_stp_find_module_by_addr(unsigned long addr) { - struct _stp_module *m; - struct _stp_symbol *s; - unsigned long flags; - unsigned end, begin = 0; + unsigned begin = 0; + unsigned end = _stp_num_modules; - if (STP_TRYLOCK_MODULES) + if (unlikely(addr < _stp_modules_by_addr[0]->text)) return NULL; - end = _stp_num_modules; - - if (_stp_num_modules >= 2 && addr > _stp_modules_by_addr[1]->text) { + if (_stp_num_modules > 1 && addr > _stp_modules_by_addr[0]->data) { /* binary search on index [begin,end) */ do { unsigned mid = (begin + end) / 2; @@ -125,18 +116,51 @@ static const char * _stp_kallsyms_lookup ( } while (begin + 1 < end); /* result index in $begin, guaranteed between [0,_stp_num_modules) */ } - m = _stp_modules_by_addr[begin]; - begin = 0; - end = m->num_symbols; + /* check if addr is past the last module */ + if (unlikely(begin == _stp_num_modules - 1 + && (addr > _stp_modules_by_addr[begin]->text + _stp_modules_by_addr[begin]->text_size))) + return NULL; + + return _stp_modules_by_addr[begin]; +} - /* m->data is the lowest address of a data section. It should be */ - /* after the text section. */ - /* If our address is in the data section, then return now. */ - if (m->data > m->text && addr >= m->data) { - STP_UNLOCK_MODULES; +static struct _stp_module *_stp_get_unwind_info(unsigned long addr) +{ + struct _stp_module *m; + struct _stp_symbol *s; + unsigned long flags; + + STP_RLOCK_MODULES; + m = _stp_find_module_by_addr(addr); + if (unlikely(m == NULL)) { + STP_RUNLOCK_MODULES; return NULL; } - + /* Lock the module struct so it doesn't go away while being used. */ + /* Probably could never happen, but lock it to be sure for now. */ + read_lock(&m->lock); + + STP_RUNLOCK_MODULES; + return m; +} + +static const char *_stp_kallsyms_lookup(unsigned long addr, + unsigned long *symbolsize, unsigned long *offset, char **modname, char *namebuf) +{ + struct _stp_module *m; + struct _stp_symbol *s; + unsigned long flags; + unsigned end, begin = 0; + + STP_RLOCK_MODULES; + m = _stp_find_module_by_addr(addr); + if (unlikely(m == NULL)) { + STP_RUNLOCK_MODULES; + return NULL; + } + + end = m->num_symbols; + /* binary search for symbols within the module */ do { unsigned mid = (begin + end) / 2; @@ -148,31 +172,29 @@ static const char * _stp_kallsyms_lookup ( /* result index in $begin */ s = &m->symbols[begin]; - if (addr < s->addr) { - STP_UNLOCK_MODULES; - return NULL; - } else { - if (offset) *offset = addr - s->addr; - if (modname) *modname = m->name; + if (likely(addr >= s->addr)) { + if (offset) + *offset = addr - s->addr; + if (modname) + *modname = m->name; if (symbolsize) { if ((begin + 1) < m->num_symbols) - *symbolsize = m->symbols[begin+1].addr - s->addr; + *symbolsize = m->symbols[begin + 1].addr - s->addr; else *symbolsize = 0; // NB: This is only a heuristic. Sometimes there are large // gaps between text areas of modules. } if (namebuf) { - strlcpy (namebuf, s->symbol, KSYM_NAME_LEN+1); - STP_UNLOCK_MODULES; + strlcpy(namebuf, s->symbol, KSYM_NAME_LEN + 1); + STP_RUNLOCK_MODULES; return namebuf; - } - else { - STP_UNLOCK_MODULES; + } else { + STP_RUNLOCK_MODULES; return s->symbol; } } - STP_UNLOCK_MODULES; + STP_RUNLOCK_MODULES; return NULL; } @@ -182,31 +204,31 @@ static const char * _stp_kallsyms_lookup ( * a probe because it is too time-consuming. Use at module exit time. */ -void _stp_symbol_print (unsigned long address) -{ +void _stp_symbol_print(unsigned long address) +{ char *modname; - const char *name; - unsigned long offset, size; + const char *name; + unsigned long offset, size; - name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); + name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); - _stp_printf ("%p", (int64_t)address); + _stp_printf("%p", (int64_t) address); - if (name) { + if (name) { if (modname && *modname) - _stp_printf (" : %s+%#lx/%#lx [%s]", name, offset, size, modname); + _stp_printf(" : %s+%#lx/%#lx [%s]", name, offset, size, modname); else - _stp_printf (" : %s+%#lx/%#lx", name, offset, size); + _stp_printf(" : %s+%#lx/%#lx", name, offset, size); } } /* Like _stp_symbol_print, except only print if the address is a valid function address */ -void _stp_func_print (unsigned long address, int verbose, int exact) -{ +void _stp_func_print(unsigned long address, int verbose, int exact) +{ char *modname; - const char *name; - unsigned long offset, size; + const char *name; + unsigned long offset, size; char *exstr; if (exact) @@ -214,33 +236,32 @@ void _stp_func_print (unsigned long address, int verbose, int exact) else exstr = " (inexact)"; - name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); + name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); if (name) { if (verbose) { if (modname && *modname) - _stp_printf (" %p : %s+%#lx/%#lx [%s]%s\n", - (int64_t)address, name, offset, size, modname, exstr); + _stp_printf(" %p : %s+%#lx/%#lx [%s]%s\n", + (int64_t) address, name, offset, size, modname, exstr); else - _stp_printf (" %p : %s+%#lx/%#lx%s\n", - (int64_t)address, name, offset, size, exstr); - } else - _stp_printf ("%p ", (int64_t)address); + _stp_printf(" %p : %s+%#lx/%#lx%s\n", (int64_t) address, name, offset, size, exstr); + } else + _stp_printf("%p ", (int64_t) address); } } -void _stp_symbol_snprint (char *str, size_t len, unsigned long address) -{ - char *modname; - const char *name; - unsigned long offset, size; - - name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); - if (name) - strlcpy(str, name, len); - else - _stp_snprintf(str, len, "%p", (int64_t)address); +void _stp_symbol_snprint(char *str, size_t len, unsigned long address) +{ + char *modname; + const char *name; + unsigned long offset, size; + + name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); + if (name) + strlcpy(str, name, len); + else + _stp_snprintf(str, len, "%p", (int64_t) address); } /** @} */ -#endif /* _SYM_C_ */ +#endif /* _STP_SYM_C_ */ diff --git a/runtime/sym.h b/runtime/sym.h index 6a55a22e..b124882a 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2005, 2006 Red Hat Inc. +/* -*- linux-c -*- + * Copyright (C) 2005-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 @@ -13,39 +13,59 @@ #define STP_MODULE_NAME_LEN 64 struct _stp_symbol { - unsigned long addr; - const char *symbol; + unsigned long addr; + const char *symbol; +}; +struct stap_symbol { + unsigned long addr; + const char *symbol; + const char *module; }; -struct _stp_module { - /* the module name, or "" for kernel */ - char name[STP_MODULE_NAME_LEN]; - - /* A pointer to the struct module. Note that we cannot */ - /* trust this because as of 2.6.19, there are not yet */ - /* any notifier hooks that will tell us when a module */ - /* is unloading. */ - unsigned long module; - - /* the start of the module's text and data sections */ - unsigned long text; - unsigned long data; - - /* how many symbols this module has that we are interested in */ - uint32_t num_symbols; - - /* how many sections this module has */ - uint32_t num_sections; - struct _stp_symbol *sections; - - /* how the symbol_data below was allocated */ - int32_t allocated; /* 0 = kmalloc, 1 = vmalloc */ - - /* an array of num_symbols _stp_symbol structs */ - struct _stp_symbol *symbols; /* ordered by address */ +DEFINE_RWLOCK(_stp_module_lock); +#define STP_RLOCK_MODULES read_lock_irqsave(&_stp_module_lock, flags) +#define STP_WLOCK_MODULES write_lock_irqsave(&_stp_module_lock, flags) +#define STP_RUNLOCK_MODULES read_unlock_irqrestore(&_stp_module_lock, flags) +#define STP_WUNLOCK_MODULES write_unlock_irqrestore(&_stp_module_lock, flags) - /* where we stash our copy of the strtab */ - void *symbol_data; /* private */ +struct _stp_module { + /* the module name, or "" for kernel */ + char name[STP_MODULE_NAME_LEN]; + + /* A pointer to the struct module. Note that we cannot */ + /* trust this because as of 2.6.19, there are not yet */ + /* any notifier hooks that will tell us when a module */ + /* is unloading. */ + unsigned long module; + + /* the start of the module's text and data sections */ + unsigned long text; + unsigned long data; + + uint32_t text_size; + + /* how many symbols this module has that we are interested in */ + uint32_t num_symbols; + + /* how many sections this module has */ + uint32_t num_sections; + + /* how the symbol_data below was allocated */ + int32_t allocated; /* 0 = kmalloc, 1 = vmalloc */ + + struct _stp_symbol *sections; + + /* an array of num_symbols _stp_symbol structs */ + struct _stp_symbol *symbols; /* ordered by address */ + + /* where we stash our copy of the strtab */ + void *symbol_data; + + /* the stack unwind data for this module */ + void *unwind_data; + uint32_t unwind_data_len; + rwlock_t lock; /* lock while unwinding is happening */ + }; #ifndef STP_MAX_MODULES @@ -62,4 +82,5 @@ struct _stp_module *_stp_modules_by_addr[STP_MAX_MODULES]; int _stp_num_modules = 0; unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset); +static struct _stp_module *_stp_get_unwind_info (unsigned long addr); #endif /* _STAP_SYMBOLS_H_ */ diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index 764e3579..c3837f86 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,3 +1,16 @@ +2008-02-27 Martin Hunt <hunt@redhat.com> + + * symbols.c: Use rwlocks. Use new dbug macros. Handle + unwind info if present. + + * transport.c: Include mempool.c. Update dbug and kbug calls + to new macros. + * transport_msgs.h (_stp_command_name): Add + struct containing message names for debugging. + + * control.c, procfs.c: Use new dbug macros. Use + new mempool functions. + 2008-01-28 Martin Hunt <hunt@redhat.com> * control.c, procfs.c, symbols.c: Use DEFINE_SPINLOCK diff --git a/runtime/transport/control.c b/runtime/transport/control.c index 0bf99fc8..6a5b272d 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -12,15 +12,13 @@ #define STP_DEFAULT_BUFFERS 50 static int _stp_current_buffers = STP_DEFAULT_BUFFERS; +static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; static struct list_head _stp_sym_ready_q; -static struct list_head _stp_pool_q; -DEFINE_SPINLOCK(_stp_pool_lock); DEFINE_SPINLOCK(_stp_ctl_ready_lock); DEFINE_SPINLOCK(_stp_sym_ready_lock); -static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static ssize_t _stp_sym_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { static int saved_type = 0; int type; @@ -28,7 +26,7 @@ static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, if (count < sizeof(int32_t)) return 0; - /* Allow sending of packet type followed by data in the next packet.*/ + /* Allow sending of packet type followed by data in the next packet. */ if (count == sizeof(int32_t)) { if (get_user(saved_type, (int __user *)buf)) return -EFAULT; @@ -42,11 +40,14 @@ static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, count -= sizeof(int); buf += sizeof(int); } - - kbug ("count:%d type:%d\n", (int)count, type); + +#if DEBUG_TRANSPORT > 0 + if (type < STP_MAX_CMD) + _dbug("Got %s. len=%d\n", _stp_command_name[type], (int)count); +#endif switch (type) { - case STP_SYMBOLS: + case STP_SYMBOLS: count = _stp_do_symbols(buf, count); break; case STP_MODULE: @@ -54,21 +55,20 @@ static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, count = _stp_do_module(buf, count); else { /* count == 1 indicates end of initial modules list */ - _stp_ctl_send(STP_TRANSPORT, NULL, 0); + _stp_ctl_send(STP_TRANSPORT, NULL, 0); } break; case STP_EXIT: _stp_exit_flag = 1; break; default: - errk ("invalid symbol command type %d\n", type); + errk("invalid symbol command type %d\n", type); return -EINVAL; } return count; } -static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int type; static int started = 0; @@ -79,7 +79,10 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, if (get_user(type, (int __user *)buf)) return -EFAULT; - kbug ("count:%d type:%d\n", (int)count, type); +#if DEBUG_TRANSPORT > 0 + if (type < STP_MAX_CMD) + _dbug("Got %s. len=%d\n", _stp_command_name[type], (int)count); +#endif count -= sizeof(int); buf += sizeof(int); @@ -90,9 +93,9 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, struct _stp_msg_start st; if (count < sizeof(st)) return 0; - if (copy_from_user (&st, buf, sizeof(st))) + if (copy_from_user(&st, buf, sizeof(st))) return -EFAULT; - _stp_handle_start (&st); + _stp_handle_start(&st); started = 1; } break; @@ -107,11 +110,11 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, #endif case STP_READY: /* request symbolic information */ - _stp_ask_for_symbols(); + _stp_ask_for_symbols(); break; - + default: - errk ("invalid command type %d\n", type); + errk("invalid command type %d\n", type); return -EINVAL; } @@ -130,55 +133,55 @@ struct _stp_buffer { static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq); static DECLARE_WAIT_QUEUE_HEAD(_stp_sym_wq); -#ifdef DEBUG -static void _stp_ctl_write_dbug (int type, void *data, int len) +#if DEBUG_TRANSPORT > 0 +static void _stp_ctl_write_dbug(int type, void *data, int len) { char buf[64]; switch (type) { case STP_START: - printk("_stp_ctl_write: sending STP_START\n"); + _dbug("sending STP_START\n"); break; case STP_EXIT: - printk("_stp_ctl_write: sending STP_EXIT\n"); + _dbug("sending STP_EXIT\n"); break; case STP_OOB_DATA: - snprintf(buf, sizeof(buf), "%s", (char *)data); - printk("_stp_ctl_write: sending %d bytes of STP_OOB_DATA: %s\n", len, buf); + snprintf(buf, sizeof(buf), "%s", (char *)data); + _dbug("sending %d bytes of STP_OOB_DATA: %s\n", len, buf); break; case STP_SYSTEM: - snprintf(buf, sizeof(buf), "%s", (char *)data); - printk("_stp_ctl_write: sending STP_SYSTEM: %s\n", buf); + snprintf(buf, sizeof(buf), "%s", (char *)data); + _dbug("sending STP_SYSTEM: %s\n", buf); break; case STP_TRANSPORT: - printk("_stp_ctl_write: sending STP_TRANSPORT\n"); + _dbug("sending STP_TRANSPORT\n"); break; default: - printk("_stp_ctl_write: ERROR: unknown message type: %d\n", type); + _dbug("ERROR: unknown message type: %d\n", type); break; } } -static void _stp_sym_write_dbug (int type, void *data, int len) +static void _stp_sym_write_dbug(int type, void *data, int len) { switch (type) { case STP_SYMBOLS: - printk("_stp_sym_write: sending STP_SYMBOLS\n"); + _dbug("sending STP_SYMBOLS\n"); break; case STP_MODULE: - printk("_stp_sym_write: sending STP_MODULE\n"); + _dbug("sending STP_MODULE\n"); break; default: - printk("_stp_sym_write: ERROR: unknown message type: %d\n", type); + _dbug("ERROR: unknown message type: %d\n", type); break; } } #endif -static int _stp_ctl_write (int type, void *data, unsigned len) +static int _stp_ctl_write(int type, void *data, unsigned len) { struct _stp_buffer *bptr; unsigned long flags; - unsigned numtrylock; -#ifdef DEBUG + +#if DEBUG_TRANSPORT > 0 _stp_ctl_write_dbug(type, data, len); #endif @@ -186,47 +189,29 @@ static int _stp_ctl_write (int type, void *data, unsigned len) if (unlikely(len > STP_CTL_BUFFER_SIZE)) return 0; - numtrylock = 0; - while (!spin_trylock_irqsave (&_stp_pool_lock, flags) && (++numtrylock < MAXTRYLOCK)) - ndelay (TRYLOCKDELAY); - if (unlikely (numtrylock >= MAXTRYLOCK)) - return 0; - - if (unlikely(list_empty(&_stp_pool_q))) { - spin_unlock_irqrestore(&_stp_pool_lock, flags); - dbug("_stp_pool_q empty\n"); + /* get a buffer from the free pool */ + bptr = _stp_mempool_alloc(_stp_pool_q); + if (unlikely(bptr == NULL)) return -1; - } - - /* get the next buffer from the pool */ - bptr = (struct _stp_buffer *)_stp_pool_q.next; - list_del_init(&bptr->list); - spin_unlock_irqrestore(&_stp_pool_lock, flags); bptr->type = type; memcpy(bptr->buf, data, len); bptr->len = len; - - /* put it on the pool of ready buffers */ - numtrylock = 0; - while (!spin_trylock_irqsave (&_stp_ctl_ready_lock, flags) && (++numtrylock < MAXTRYLOCK)) - ndelay (TRYLOCKDELAY); - - if (unlikely (numtrylock >= MAXTRYLOCK)) - return 0; + /* put it on the pool of ready buffers */ + spin_lock_irqsave(&_stp_ctl_ready_lock, flags); list_add_tail(&bptr->list, &_stp_ctl_ready_q); spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags); return len; } -static int _stp_sym_write (int type, void *data, unsigned len) +static int _stp_sym_write(int type, void *data, unsigned len) { struct _stp_buffer *bptr; unsigned long flags; -#ifdef DEBUG +#if DEBUG_TRANSPORT > 0 _stp_sym_write_dbug(type, data, len); #endif @@ -234,24 +219,17 @@ static int _stp_sym_write (int type, void *data, unsigned len) if (unlikely(len > STP_CTL_BUFFER_SIZE)) return 0; - spin_lock_irqsave (&_stp_pool_lock, flags); - if (unlikely(list_empty(&_stp_pool_q))) { - spin_unlock_irqrestore(&_stp_pool_lock, flags); - dbug("_stp_pool_q empty\n"); + /* get a buffer from the free pool */ + bptr = _stp_mempool_alloc(_stp_pool_q); + if (unlikely(bptr == NULL)) return -1; - } - - /* get the next buffer from the pool */ - bptr = (struct _stp_buffer *)_stp_pool_q.next; - list_del_init(&bptr->list); - spin_unlock_irqrestore(&_stp_pool_lock, flags); bptr->type = type; memcpy(bptr->buf, data, len); bptr->len = len; - + /* put it on the pool of ready buffers */ - spin_lock_irqsave (&_stp_sym_ready_lock, flags); + spin_lock_irqsave(&_stp_sym_ready_lock, flags); list_add_tail(&bptr->list, &_stp_sym_ready_q); spin_unlock_irqrestore(&_stp_sym_ready_lock, flags); @@ -262,25 +240,24 @@ static int _stp_sym_write (int type, void *data, unsigned len) } /* send commands with timeout and retry */ -static int _stp_ctl_send (int type, void *data, int len) +static int _stp_ctl_send(int type, void *data, int len) { int err, trylimit = 50; - kbug("ctl_send: type=%d len=%d\n", type, len); + kbug(DEBUG_TRANSPORT, "ctl_send: type=%d len=%d\n", type, len); if (unlikely(type == STP_SYMBOLS || type == STP_MODULE)) { while ((err = _stp_sym_write(type, data, len)) < 0 && trylimit--) - msleep (5); + msleep(5); } else { while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--) - msleep (5); + msleep(5); if (err > 0) wake_up_interruptible(&_stp_ctl_wq); } - kbug("returning %d\n", err); + kbug(DEBUG_TRANSPORT, "returning %d\n", err); return err; } -static ssize_t -_stp_sym_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos) +static ssize_t _stp_sym_read_cmd(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct _stp_buffer *bptr; int len; @@ -296,7 +273,7 @@ _stp_sym_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp return -ERESTARTSYS; spin_lock_irqsave(&_stp_sym_ready_lock, flags); } - + /* get the next buffer off the ready list */ bptr = (struct _stp_buffer *)_stp_sym_ready_q.next; list_del_init(&bptr->list); @@ -314,15 +291,12 @@ _stp_sym_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp } /* put it on the pool of free buffers */ - spin_lock_irqsave(&_stp_pool_lock, flags); - list_add_tail(&bptr->list, &_stp_pool_q); - spin_unlock_irqrestore(&_stp_pool_lock, flags); + _stp_mempool_free(bptr); return len; } -static ssize_t -_stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos) +static ssize_t _stp_ctl_read_cmd(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct _stp_buffer *bptr; int len; @@ -338,7 +312,7 @@ _stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp return -ERESTARTSYS; spin_lock_irqsave(&_stp_ctl_ready_lock, flags); } - + /* get the next buffer off the ready list */ bptr = (struct _stp_buffer *)_stp_ctl_ready_q.next; list_del_init(&bptr->list); @@ -356,15 +330,13 @@ _stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp } /* put it on the pool of free buffers */ - spin_lock_irqsave(&_stp_pool_lock, flags); - list_add_tail(&bptr->list, &_stp_pool_q); - spin_unlock_irqrestore(&_stp_pool_lock, flags); + _stp_mempool_free(bptr); return len; } static int _stp_sym_opens = 0; -static int _stp_sym_open_cmd (struct inode *inode, struct file *file) +static int _stp_sym_open_cmd(struct inode *inode, struct file *file) { /* only allow one reader */ if (_stp_sym_opens) @@ -374,14 +346,14 @@ static int _stp_sym_open_cmd (struct inode *inode, struct file *file) return 0; } -static int _stp_sym_close_cmd (struct inode *inode, struct file *file) +static int _stp_sym_close_cmd(struct inode *inode, struct file *file) { if (_stp_sym_opens) _stp_sym_opens--; return 0; } -static int _stp_ctl_open_cmd (struct inode *inode, struct file *file) +static int _stp_ctl_open_cmd(struct inode *inode, struct file *file) { if (_stp_attached) return -1; @@ -390,7 +362,7 @@ static int _stp_ctl_open_cmd (struct inode *inode, struct file *file) return 0; } -static int _stp_ctl_close_cmd (struct inode *inode, struct file *file) +static int _stp_ctl_close_cmd(struct inode *inode, struct file *file) { if (_stp_attached) _stp_detach(); @@ -416,12 +388,12 @@ static struct file_operations _stp_sym_fops_cmd = { static struct dentry *_stp_cmd_file = NULL; static struct dentry *_stp_sym_file = NULL; -static int _stp_register_ctl_channel (void) +static int _stp_register_ctl_channel(void) { int i; struct list_head *p, *tmp; char buf[32]; - + if (_stp_utt == NULL) { errk("_expected _stp_utt to be set.\n"); return -1; @@ -429,21 +401,16 @@ static int _stp_register_ctl_channel (void) INIT_LIST_HEAD(&_stp_ctl_ready_q); INIT_LIST_HEAD(&_stp_sym_ready_q); - INIT_LIST_HEAD(&_stp_pool_q); /* allocate buffers */ - for (i = 0; i < STP_DEFAULT_BUFFERS; i++) { - p = (struct list_head *)_stp_kmalloc(sizeof(struct _stp_buffer)); - // printk("allocated buffer at %lx\n", (long)p); - if (!p) - goto err0; - _stp_allocated_net_memory += sizeof(struct _stp_buffer); - list_add (p, &_stp_pool_q); - } + _stp_pool_q = _stp_mempool_init(sizeof(struct _stp_buffer), STP_DEFAULT_BUFFERS); + if (unlikely(_stp_pool_q == NULL)) + goto err0; + _stp_allocated_net_memory += sizeof(struct _stp_buffer) * STP_DEFAULT_BUFFERS; /* create [debugfs]/systemtap/module_name/.cmd */ _stp_cmd_file = debugfs_create_file(".cmd", 0600, _stp_utt->dir, NULL, &_stp_ctl_fops_cmd); - if (_stp_cmd_file == NULL) + if (_stp_cmd_file == NULL) goto err0; _stp_cmd_file->d_inode->i_uid = _stp_uid; _stp_cmd_file->d_inode->i_gid = _stp_gid; @@ -455,35 +422,29 @@ static int _stp_register_ctl_channel (void) return 0; err0: - if (_stp_cmd_file) debugfs_remove(_stp_cmd_file); - - list_for_each_safe(p, tmp, &_stp_pool_q) { - list_del(p); - _stp_kfree(p); - } - errk ("Error creating systemtap debugfs entries.\n"); + if (_stp_cmd_file) + debugfs_remove(_stp_cmd_file); + _stp_mempool_destroy(_stp_pool_q); + errk("Error creating systemtap debugfs entries.\n"); return -1; } - -static void _stp_unregister_ctl_channel (void) +static void _stp_unregister_ctl_channel(void) { struct list_head *p, *tmp; - if (_stp_sym_file) debugfs_remove(_stp_sym_file); - if (_stp_cmd_file) debugfs_remove(_stp_cmd_file); + if (_stp_sym_file) + debugfs_remove(_stp_sym_file); + if (_stp_cmd_file) + debugfs_remove(_stp_cmd_file); - /* free memory pools */ - list_for_each_safe(p, tmp, &_stp_pool_q) { - list_del(p); - _stp_kfree(p); - } + /* Return memory to pool and free it. */ list_for_each_safe(p, tmp, &_stp_sym_ready_q) { list_del(p); - _stp_kfree(p); + _stp_mempool_free(p); } list_for_each_safe(p, tmp, &_stp_ctl_ready_q) { list_del(p); - _stp_kfree(p); + _stp_mempool_free(p); } + _stp_mempool_destroy(_stp_pool_q); } - diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c index 33f6db33..2afea1c9 100644 --- a/runtime/transport/procfs.c +++ b/runtime/transport/procfs.c @@ -12,18 +12,16 @@ #define STP_DEFAULT_BUFFERS 256 static int _stp_current_buffers = STP_DEFAULT_BUFFERS; +static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; static struct list_head _stp_sym_ready_q; -static struct list_head _stp_pool_q; -DEFINE_SPINLOCK(_stp_pool_lock); DEFINE_SPINLOCK(_stp_ctl_ready_lock); DEFINE_SPINLOCK(_stp_sym_ready_lock); #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) +static ssize_t _stp_proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int num; struct _stp_buf_info out; @@ -46,8 +44,7 @@ _stp_proc_read (struct file *file, char __user *buf, size_t count, loff_t *ppos) } /* handle the per-cpu subbuf info write for relayfs */ -static ssize_t _stp_proc_write (struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static ssize_t _stp_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct _stp_consumed_info info; int cpu = *(int *)(PDE(file->f_dentry->d_inode)->data); @@ -65,8 +62,7 @@ static struct file_operations _stp_proc_fops = { }; #endif /* STP_BULKMODE */ -static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static ssize_t _stp_sym_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { static int saved_type = 0; int type; @@ -74,7 +70,7 @@ static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, if (count < sizeof(int32_t)) return 0; - /* Allow sending of packet type followed by data in the next packet.*/ + /* Allow sending of packet type followed by data in the next packet. */ if (count == sizeof(int32_t)) { if (get_user(saved_type, (int __user *)buf)) return -EFAULT; @@ -88,11 +84,14 @@ static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, count -= sizeof(int); buf += sizeof(int); } - - // kbug ("count:%d type:%d\n", (int)count, type); + +#if DEBUG_TRANSPORT > 0 + if (type < STP_MAX_CMD) + _dbug("Got %s. len=%d\n", _stp_command_name[type], (int)count); +#endif switch (type) { - case STP_SYMBOLS: + case STP_SYMBOLS: count = _stp_do_symbols(buf, count); break; case STP_MODULE: @@ -100,19 +99,19 @@ static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, count = _stp_do_module(buf, count); else { /* count == 1 indicates end of initial modules list */ - _stp_ctl_send(STP_TRANSPORT, NULL, 0); + _stp_ctl_send(STP_TRANSPORT, NULL, 0); } break; default: - errk ("invalid symbol command type %d\n", type); + errk("invalid symbol command type %d\n", type); return -EINVAL; } return count; } -static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, - size_t count, loff_t *ppos) + +static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int type; static int started = 0; @@ -123,7 +122,10 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, if (get_user(type, (int __user *)buf)) return -EFAULT; - // kbug ("count:%d type:%d\n", count, type); +#if DEBUG_TRANSPORT > 0 + if (type < STP_MAX_CMD) + _dbug("Got %s. len=%d\n", _stp_command_name[type], (int)count); +#endif count -= sizeof(int); buf += sizeof(int); @@ -134,9 +136,9 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, struct _stp_msg_start st; if (count < sizeof(st)) return 0; - if (copy_from_user (&st, buf, sizeof(st))) + if (copy_from_user(&st, buf, sizeof(st))) return -EFAULT; - _stp_handle_start (&st); + _stp_handle_start(&st); started = 1; } break; @@ -145,10 +147,10 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, break; case STP_READY: /* request symbolic information */ - _stp_ask_for_symbols(); + _stp_ask_for_symbols(); break; default: - errk ("invalid command type %d\n", type); + errk("invalid command type %d\n", type); return -EINVAL; } @@ -165,76 +167,66 @@ struct _stp_buffer { static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq); static DECLARE_WAIT_QUEUE_HEAD(_stp_sym_wq); -#ifdef DEBUG -static void _stp_ctl_write_dbug (int type, void *data, int len) +#if DEBUG_TRANSPORT > 0 +static void _stp_ctl_write_dbug(int type, void *data, int len) { char buf[64]; switch (type) { - case STP_REALTIME_DATA: - break; case STP_START: - printk("_stp_ctl_write: sending STP_START\n"); + _dbug("sending STP_START\n"); break; case STP_EXIT: - printk("_stp_ctl_write: sending STP_EXIT\n"); + _dbug("sending STP_EXIT\n"); break; case STP_OOB_DATA: - snprintf(buf, sizeof(buf), "%s", (char *)data); - printk("_stp_ctl_write: sending %d bytes of STP_OOB_DATA: %s\n", len, buf); + snprintf(buf, sizeof(buf), "%s", (char *)data); + _dbug("sending %d bytes of STP_OOB_DATA: %s\n", len, buf); break; case STP_SYSTEM: - snprintf(buf, sizeof(buf), "%s", (char *)data); - printk("_stp_ctl_write: sending STP_SYSTEM: %s\n", buf); + snprintf(buf, sizeof(buf), "%s", (char *)data); + _dbug("sending STP_SYSTEM: %s\n", buf); break; case STP_TRANSPORT: - printk("_stp_ctl_write: sending STP_TRANSPORT\n"); + _dbug("sending STP_TRANSPORT\n"); break; default: - printk("_stp_ctl_write: ERROR: unknown message type: %d\n", type); + _dbug("ERROR: unknown message type: %d\n", type); break; } } -static void _stp_sym_write_dbug (int type, void *data, int len) +static void _stp_sym_write_dbug(int type, void *data, int len) { switch (type) { case STP_SYMBOLS: - printk("_stp_sym_write: sending STP_SYMBOLS\n"); + _dbug("sending STP_SYMBOLS\n"); break; case STP_MODULE: - printk("_stp_sym_write: sending STP_MODULE\n"); + _dbug("sending STP_MODULE\n"); break; default: - printk("_stp_sym_write: ERROR: unknown message type: %d\n", type); + _dbug("ERROR: unknown message type: %d\n", type); break; } } #endif -static int _stp_ctl_write (int type, void *data, int len) +static int _stp_ctl_write(int type, void *data, int len) { struct _stp_buffer *bptr; unsigned long flags; - unsigned numtrylock; -#ifdef DEBUG +#if DEBUG_TRANSPORT > 0 _stp_ctl_write_dbug(type, data, len); #endif #define WRITE_AGG #ifdef WRITE_AGG - numtrylock = 0; - while (!spin_trylock_irqsave (&_stp_ctl_ready_lock, flags) && (++numtrylock < MAXTRYLOCK)) - ndelay (TRYLOCKDELAY); - if (unlikely (numtrylock >= MAXTRYLOCK)) - return 0; - + spin_lock_irqsave(&_stp_ctl_ready_lock, flags); if (!list_empty(&_stp_ctl_ready_q)) { bptr = (struct _stp_buffer *)_stp_ctl_ready_q.prev; - if (bptr->len + len <= STP_BUFFER_SIZE - && type == STP_REALTIME_DATA - && bptr->type == STP_REALTIME_DATA) { - memcpy (bptr->buf + bptr->len, data, len); + if (bptr->len + len <= STP_BUFFER_SIZE && type == STP_REALTIME_DATA && bptr->type == STP_REALTIME_DATA) { + memcpy(bptr->buf + bptr->len, data, len); bptr->len += len; spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags); return len; @@ -247,47 +239,29 @@ static int _stp_ctl_write (int type, void *data, int len) if (unlikely(len > STP_BUFFER_SIZE)) return 0; - numtrylock = 0; - while (!spin_trylock_irqsave (&_stp_pool_lock, flags) && (++numtrylock < MAXTRYLOCK)) - ndelay (TRYLOCKDELAY); - if (unlikely (numtrylock >= MAXTRYLOCK)) - return 0; - - if (unlikely(list_empty(&_stp_pool_q))) { - spin_unlock_irqrestore(&_stp_pool_lock, flags); - dbug("_stp_pool_q empty\n"); + /* get a buffer from the free pool */ + bptr = _stp_mempool_alloc(_stp_pool_q); + if (unlikely(bptr == NULL)) return -1; - } - - /* get the next buffer from the pool */ - bptr = (struct _stp_buffer *)_stp_pool_q.next; - list_del_init(&bptr->list); - spin_unlock_irqrestore(&_stp_pool_lock, flags); bptr->type = type; - memcpy (bptr->buf, data, len); + memcpy(bptr->buf, data, len); bptr->len = len; - - /* put it on the pool of ready buffers */ - numtrylock = 0; - while (!spin_trylock_irqsave (&_stp_ctl_ready_lock, flags) && (++numtrylock < MAXTRYLOCK)) - ndelay (TRYLOCKDELAY); - - if (unlikely (numtrylock >= MAXTRYLOCK)) - return 0; + /* put it on the pool of ready buffers */ + spin_lock_irqsave(&_stp_ctl_ready_lock, flags); list_add_tail(&bptr->list, &_stp_ctl_ready_q); spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags); return len; } -static int _stp_sym_write (int type, void *data, unsigned len) +static int _stp_sym_write(int type, void *data, unsigned len) { struct _stp_buffer *bptr; unsigned long flags; -#ifdef DEBUG +#if DEBUG_TRANSPORT > 0 _stp_sym_write_dbug(type, data, len); #endif @@ -295,24 +269,17 @@ static int _stp_sym_write (int type, void *data, unsigned len) if (unlikely(len > STP_BUFFER_SIZE)) return 0; - spin_lock_irqsave (&_stp_pool_lock, flags); - if (unlikely(list_empty(&_stp_pool_q))) { - spin_unlock_irqrestore(&_stp_pool_lock, flags); - dbug("_stp_pool_q empty\n"); + /* get a buffer from the free pool */ + bptr = _stp_mempool_alloc(_stp_pool_q); + if (unlikely(bptr == NULL)) return -1; - } - - /* get the next buffer from the pool */ - bptr = (struct _stp_buffer *)_stp_pool_q.next; - list_del_init(&bptr->list); - spin_unlock_irqrestore(&_stp_pool_lock, flags); bptr->type = type; memcpy(bptr->buf, data, len); bptr->len = len; /* put it on the pool of ready buffers */ - spin_lock_irqsave (&_stp_sym_ready_lock, flags); + spin_lock_irqsave(&_stp_sym_ready_lock, flags); list_add_tail(&bptr->list, &_stp_sym_ready_q); spin_unlock_irqrestore(&_stp_sym_ready_lock, flags); @@ -323,23 +290,24 @@ static int _stp_sym_write (int type, void *data, unsigned len) } /* send commands with timeout and retry */ -static int _stp_ctl_send (int type, void *data, int len) +static int _stp_ctl_send(int type, void *data, int len) { int err, trylimit = 50; + kbug(DEBUG_TRANSPORT, "ctl_send: type=%d len=%d\n", type, len); if (unlikely(type == STP_SYMBOLS || type == STP_MODULE)) { while ((err = _stp_sym_write(type, data, len)) < 0 && trylimit--) - msleep (5); + msleep(5); } else { while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--) - msleep (5); + msleep(5); if (err > 0) wake_up_interruptible(&_stp_ctl_wq); } + kbug(DEBUG_TRANSPORT, "returning %d\n", err); return err; } -static ssize_t -_stp_sym_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos) +static ssize_t _stp_sym_read_cmd(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct _stp_buffer *bptr; int len; @@ -355,7 +323,7 @@ _stp_sym_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp return -ERESTARTSYS; spin_lock_irqsave(&_stp_sym_ready_lock, flags); } - + /* get the next buffer off the ready list */ bptr = (struct _stp_buffer *)_stp_sym_ready_q.next; list_del_init(&bptr->list); @@ -373,15 +341,12 @@ _stp_sym_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp } /* put it on the pool of free buffers */ - spin_lock_irqsave(&_stp_pool_lock, flags); - list_add_tail(&bptr->list, &_stp_pool_q); - spin_unlock_irqrestore(&_stp_pool_lock, flags); + _stp_mempool_free(bptr); return len; } -static ssize_t -_stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos) +static ssize_t _stp_ctl_read_cmd(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct _stp_buffer *bptr; int len; @@ -397,7 +362,7 @@ _stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp return -ERESTARTSYS; spin_lock_irqsave(&_stp_ctl_ready_lock, flags); } - + /* get the next buffer off the ready list */ bptr = (struct _stp_buffer *)_stp_ctl_ready_q.next; list_del_init(&bptr->list); @@ -415,15 +380,13 @@ _stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp } /* put it on the pool of free buffers */ - spin_lock_irqsave(&_stp_pool_lock, flags); - list_add_tail(&bptr->list, &_stp_pool_q); - spin_unlock_irqrestore(&_stp_pool_lock, flags); + _stp_mempool_free(bptr); return len; } static int _stp_sym_opens = 0; -static int _stp_sym_open_cmd (struct inode *inode, struct file *file) +static int _stp_sym_open_cmd(struct inode *inode, struct file *file) { /* only allow one reader */ if (_stp_sym_opens) @@ -433,14 +396,14 @@ static int _stp_sym_open_cmd (struct inode *inode, struct file *file) return 0; } -static int _stp_sym_close_cmd (struct inode *inode, struct file *file) +static int _stp_sym_close_cmd(struct inode *inode, struct file *file) { if (_stp_sym_opens) _stp_sym_opens--; return 0; } -static int _stp_ctl_open_cmd (struct inode *inode, struct file *file) +static int _stp_ctl_open_cmd(struct inode *inode, struct file *file) { if (_stp_attached) return -1; @@ -449,7 +412,7 @@ static int _stp_ctl_open_cmd (struct inode *inode, struct file *file) return 0; } -static int _stp_ctl_close_cmd (struct inode *inode, struct file *file) +static int _stp_ctl_close_cmd(struct inode *inode, struct file *file) { if (_stp_attached) _stp_detach(); @@ -482,46 +445,14 @@ static int my_proc_match(int len, const char *name, struct proc_dir_entry *de) /* set the number of buffers to use to 'num' */ static int _stp_set_buffers(int num) { - int i; - struct list_head *p; - unsigned long flags; - - //printk("stp_set_buffers %d\n", num); - - if (num == 0 || num == _stp_current_buffers) - return _stp_current_buffers; - - if (num > _stp_current_buffers) { - for (i = 0; i < num - _stp_current_buffers; i++) { - p = (struct list_head *)_stp_kmalloc(sizeof(struct _stp_buffer)); - if (!p) { - _stp_current_buffers += i; - goto err; - } - _stp_allocated_net_memory += sizeof(struct _stp_buffer); - spin_lock_irqsave(&_stp_pool_lock, flags); - list_add (p, &_stp_pool_q); - spin_unlock_irqrestore(&_stp_pool_lock, flags); - } - } else { - for (i = 0; i < _stp_current_buffers - num; i++) { - spin_lock_irqsave(&_stp_pool_lock, flags); - p = _stp_pool_q.next; - list_del(p); - spin_unlock_irqrestore(&_stp_pool_lock, flags); - _stp_kfree(p); - } - } - _stp_current_buffers = num; -err: - return _stp_current_buffers; + kbug(DEBUG_TRANSPORT, "stp_set_buffers %d\n", num); + return _stp_mempool_resize(_stp_pool_q, num); } -static int _stp_ctl_read_bufsize (char *page, char **start, off_t off, - int count, int *eof, void *data) +static int _stp_ctl_read_bufsize(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = sprintf(page, "%d,%d\n", _stp_nsubbufs, _stp_subbuf_size); - if (len <= off+count) + if (len <= off + count) *eof = 1; *start = page + off; len -= off; @@ -532,7 +463,7 @@ static int _stp_ctl_read_bufsize (char *page, char **start, off_t off, return len; } -static int _stp_register_ctl_channel (void) +static int _stp_register_ctl_channel(void) { int i; const char *dirname = "systemtap"; @@ -546,17 +477,12 @@ static int _stp_register_ctl_channel (void) INIT_LIST_HEAD(&_stp_ctl_ready_q); INIT_LIST_HEAD(&_stp_sym_ready_q); - INIT_LIST_HEAD(&_stp_pool_q); /* allocate buffers */ - for (i = 0; i < STP_DEFAULT_BUFFERS; i++) { - p = (struct list_head *)_stp_kmalloc(sizeof(struct _stp_buffer)); - // printk("allocated buffer at %lx\n", (long)p); - if (!p) - goto err0; - _stp_allocated_net_memory += sizeof(struct _stp_buffer); - list_add (p, &_stp_pool_q); - } + _stp_pool_q = _stp_mempool_init(sizeof(struct _stp_buffer), STP_DEFAULT_BUFFERS); + if (unlikely(_stp_pool_q == NULL)) + goto err0; + _stp_allocated_net_memory += sizeof(struct _stp_buffer) * STP_DEFAULT_BUFFERS; if (!_stp_mkdir_proc_module()) goto err0; @@ -565,15 +491,15 @@ static int _stp_register_ctl_channel (void) /* now for each cpu "n", create /proc/systemtap/module_name/n */ for_each_cpu(i) { sprintf(buf, "%d", i); - de = create_proc_entry (buf, 0600, _stp_proc_root); - if (de == NULL) + de = create_proc_entry(buf, 0600, _stp_proc_root); + if (de == NULL) goto err1; de->uid = _stp_uid; de->gid = _stp_gid; de->proc_fops = &_stp_proc_fops; de->data = _stp_kmalloc(sizeof(int)); if (de->data == NULL) { - remove_proc_entry (buf, _stp_proc_root); + remove_proc_entry(buf, _stp_proc_root); goto err1; } *(int *)de->data = i; @@ -582,48 +508,44 @@ static int _stp_register_ctl_channel (void) #endif /* STP_BULKMODE */ /* create /proc/systemtap/module_name/.cmd */ - de = create_proc_entry (".cmd", 0600, _stp_proc_root); - if (de == NULL) + de = create_proc_entry(".cmd", 0600, _stp_proc_root); + if (de == NULL) goto err1; de->uid = _stp_uid; de->gid = _stp_gid; de->proc_fops = &_stp_proc_fops_cmd; /* create /proc/systemtap/module_name/.symbols */ - de = create_proc_entry (".symbols", 0600, _stp_proc_root); - if (de == NULL) + de = create_proc_entry(".symbols", 0600, _stp_proc_root); + if (de == NULL) goto err2; de->proc_fops = &_stp_sym_fops_cmd; return 0; err2: - remove_proc_entry (".cmd", _stp_proc_root); + remove_proc_entry(".cmd", _stp_proc_root); err1: #ifdef STP_BULKMODE for (de = _stp_proc_root->subdir; de; de = de->next) - _stp_kfree (de->data); + _stp_kfree(de->data); for_each_cpu(j) { if (j == i) break; sprintf(buf, "%d", j); - remove_proc_entry (buf, _stp_proc_root); - + remove_proc_entry(buf, _stp_proc_root); + } - if (bs) remove_proc_entry ("bufsize", _stp_proc_root); + if (bs) + remove_proc_entry("bufsize", _stp_proc_root); #endif /* STP_BULKMODE */ _stp_rmdir_proc_module(); err0: - list_for_each_safe(p, tmp, &_stp_pool_q) { - list_del(p); - _stp_kfree(p); - } - - errk ("Error creating systemtap /proc entries.\n"); + _stp_mempool_destroy(_stp_pool_q); + errk("Error creating systemtap /proc entries.\n"); return -1; } - -static void _stp_unregister_ctl_channel (void) +static void _stp_unregister_ctl_channel(void) { struct list_head *p, *tmp; char buf[32]; @@ -632,31 +554,27 @@ static void _stp_unregister_ctl_channel (void) struct proc_dir_entry *de; kbug("unregistering procfs\n"); for (de = _stp_proc_root->subdir; de; de = de->next) - _stp_kfree (de->data); + _stp_kfree(de->data); for_each_cpu(i) { sprintf(buf, "%d", i); - remove_proc_entry (buf, _stp_proc_root); + remove_proc_entry(buf, _stp_proc_root); } - remove_proc_entry ("bufsize", _stp_proc_root); + remove_proc_entry("bufsize", _stp_proc_root); #endif /* STP_BULKMODE */ - remove_proc_entry (".symbols", _stp_proc_root); - remove_proc_entry (".cmd", _stp_proc_root); + remove_proc_entry(".symbols", _stp_proc_root); + remove_proc_entry(".cmd", _stp_proc_root); _stp_rmdir_proc_module(); - /* free memory pools */ - list_for_each_safe(p, tmp, &_stp_pool_q) { - list_del(p); - _stp_kfree(p); - } + /* Return memory to pool and free it. */ list_for_each_safe(p, tmp, &_stp_sym_ready_q) { list_del(p); - _stp_kfree(p); + _stp_mempool_free(p); } list_for_each_safe(p, tmp, &_stp_ctl_ready_q) { list_del(p); - _stp_kfree(p); + _stp_mempool_free(p); } + _stp_mempool_destroy(_stp_pool_q); } - diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index e740dde8..8c453a55 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -16,16 +16,6 @@ #define _SYMBOLS_C_ #include "../sym.h" -DEFINE_SPINLOCK(_stp_module_lock); -#define STP_TRYLOCK_MODULES ({ \ - int numtrylock = 0; \ - while (!spin_trylock_irqsave (&_stp_module_lock, flags) && (++numtrylock < MAXTRYLOCK)) \ - ndelay (TRYLOCKDELAY); \ - (numtrylock >= MAXTRYLOCK); \ - }) -#define STP_LOCK_MODULES spin_lock_irqsave(&_stp_module_lock, flags) -#define STP_UNLOCK_MODULES spin_unlock_irqrestore(&_stp_module_lock, flags) - static char *_stp_symbol_data = NULL; static int _stp_symbol_state = 0; static char *_stp_module_data = NULL; @@ -63,7 +53,7 @@ static unsigned _stp_get_sym_sizes(struct module *m, unsigned *dsize) } /* allocate space for a module and symbols */ -static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize) +static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize, unsigned unwindsize) { struct _stp_module *mod = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module)); if (mod == NULL) @@ -85,6 +75,14 @@ static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize) mod->allocated |= 2; } + mod->unwind_data = _stp_kmalloc(unwindsize); + if (mod->unwind_data == NULL) { + mod->unwind_data = _stp_vmalloc(unwindsize); + if (mod->unwind_data == NULL) + goto bad; + mod->allocated |= 4; + } + mod->num_symbols = num; return mod; @@ -97,19 +95,40 @@ bad: _stp_kfree(mod->symbols); mod->symbols = NULL; } + if (mod->symbol_data) { + if (mod->allocated & 2) + _stp_vfree(mod->symbol_data); + else + _stp_kfree(mod->symbol_data); + mod->symbol_data = NULL; + } + _stp_kfree(mod); + if (mod->symbols) { + if (mod->allocated & 1) + _stp_vfree(mod->symbols); + else + _stp_kfree(mod->symbols); + mod->symbols = NULL; + } _stp_kfree(mod); } return NULL; } -static struct _stp_module * _stp_alloc_module_from_module (struct module *m) +static struct _stp_module * _stp_alloc_module_from_module (struct module *m, uint32_t unwind_len) { unsigned datasize, num = _stp_get_sym_sizes(m, &datasize); - return _stp_alloc_module(num, datasize); + return _stp_alloc_module(num, datasize, unwind_len); } static void _stp_free_module(struct _stp_module *mod) { + /* The module write lock is held. Any prior readers of this */ + /* module's data will have read locks and need to finish before */ + /* the memory is freed. */ + write_lock(&mod->lock); + write_unlock(&mod->lock); /* there will be no more readers */ + /* free symbol memory */ if (mod->symbols) { if (mod->allocated & 1) @@ -126,21 +145,30 @@ static void _stp_free_module(struct _stp_module *mod) mod->symbol_data = NULL; } + if (mod->unwind_data) { + if (mod->allocated & 4) + _stp_vfree(mod->unwind_data); + else + _stp_kfree(mod->unwind_data); + mod->unwind_data = NULL; + + } if (mod->sections) { _stp_kfree(mod->sections); mod->sections = NULL; } + /* free module memory */ _stp_kfree(mod); } /* Delete a module and free its memory. */ -/* The lock should already be held before calling this. */ +/* The module lock should already be held before calling this. */ static void _stp_del_module(struct _stp_module *mod) { int i, num; - // kbug("deleting %s\n", mod->name); + // kbug(DEBUG_SYMBOLS, "deleting %s\n", mod->name); /* signal relocation code to clear its cache */ _stp_module_relocate((char *)-1, NULL, 0); @@ -185,7 +213,7 @@ static unsigned long _stp_kallsyms_lookup_name(const char *name); static int _stp_do_symbols(const char __user *buf, int count) { struct _stp_symbol *s; - unsigned datasize, num; + unsigned datasize, num, unwindsize; int i; switch (_stp_symbol_state) { @@ -198,23 +226,26 @@ static int _stp_do_symbols(const char __user *buf, int count) return -EFAULT; if (get_user(datasize, (unsigned __user *)(buf+4))) return -EFAULT; - //kbug("num=%d datasize=%d\n", num, datasize); + if (get_user(unwindsize, (unsigned __user *)(buf+8))) + return -EFAULT; + dbug(DEBUG_UNWIND, "num=%d datasize=%d unwindsize=%d\n", num, datasize, unwindsize); - _stp_modules[0] = _stp_alloc_module(num, datasize); + _stp_modules[0] = _stp_alloc_module(num, datasize, unwindsize); if (_stp_modules[0] == NULL) { errk("cannot allocate memory\n"); return -EFAULT; } + rwlock_init(&_stp_modules[0]->lock); _stp_symbol_state = 1; break; case 1: - //kbug("got stap_symbols, count=%d\n", count); + dbug(DEBUG_SYMBOLS, "got stap_symbols, count=%d\n", count); if (copy_from_user ((char *)_stp_modules[0]->symbols, buf, count)) return -EFAULT; _stp_symbol_state = 2; break; case 2: - //kbug("got symbol data, count=%d buf=%p\n", count, buf); + dbug(DEBUG_SYMBOLS, "got symbol data, count=%d buf=%p\n", count, buf); if (copy_from_user (_stp_modules[0]->symbol_data, buf, count)) return -EFAULT; _stp_num_modules = 1; @@ -227,8 +258,19 @@ static int _stp_do_symbols(const char __user *buf, int count) /* NB: this mapping is used by kernel/_stext pseudo-relocations. */ _stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext"); _stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext"); + _stp_modules[0]->text_size = _stp_modules[0]->data - _stp_modules[0]->text; _stp_modules_by_addr[0] = _stp_modules[0]; - //kbug("done with symbol data\n"); + dbug(DEBUG_SYMBOLS, "Got kernel symbols. text=%p len=%u\n", + (int64_t)_stp_modules[0]->text, _stp_modules[0]->text_size); + break; + case 3: + dbug(DEBUG_UNWIND, "got unwind data, count=%d\n", count); + _stp_symbol_state = 4; + if (copy_from_user (_stp_modules[0]->unwind_data, buf, count)) { + _dbug("cfu failed\n"); + return -EFAULT; + } + _stp_modules[0]->unwind_data_len = count; break; default: errk("unexpected symbol data of size %d.\n", count); @@ -266,10 +308,8 @@ static void u32_swap(void *a, void *b, int size) static void generic_swap(void *a, void *b, int size) { - char t; - do { - t = *(char *)a; + char t = *(char *)a; *(char *)a++ = *(char *)b; *(char *)b++ = t; } while (--size > 0); @@ -328,7 +368,7 @@ void _stp_sort(void *base, size_t num, size_t size, } /* Create a new _stp_module and load the symbols */ -static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod) +static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod, uint32_t unwind_len) { unsigned i, num=0; struct module *m = (struct module *)imod->module; @@ -336,12 +376,12 @@ static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod) char *dataptr; if (m == NULL) { - kbug("imod->module is NULL\n"); + kbug(DEBUG_SYMBOLS, "imod->module is NULL\n"); return NULL; } if (try_module_get(m)) { - mod = _stp_alloc_module_from_module(m); + mod = _stp_alloc_module_from_module(m, unwind_len); if (mod == NULL) { module_put(m); errk("failed to allocate memory for module.\n"); @@ -354,6 +394,8 @@ static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod) mod->data = imod->data; mod->num_sections = imod->num_sections; mod->sections = imod->sections; + mod->text_size = m->core_text_size; + rwlock_init(&mod->lock); /* now copy all the symbols we are interested in */ dataptr = mod->symbol_data; @@ -375,24 +417,32 @@ static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod) return mod; } -/* Do we already have this module? */ -static int _stp_module_exists(struct _stp_module *mod) +/* Remove any old module info from our database */ +static void _stp_module_exists_delete (struct _stp_module *mod) { - int i, res; - unsigned long flags; - // kbug("exists? %s\n", mod->name); - STP_LOCK_MODULES; - for (i = 1; i < _stp_num_modules; i++) { - res = strcmp(_stp_modules[i]->name, mod->name); - if (res > 0) + int i, num; + + /* remove any old modules with the same name */ + for (num = 1; num < _stp_num_modules; num++) { + if (strcmp(_stp_modules[num]->name, mod->name) == 0) { + dbug(DEBUG_SYMBOLS, "found existing module with name %s. Deleting.\n", mod->name); + _stp_del_module(_stp_modules[num]); break; - if (res == 0 && _stp_modules[i]->module == mod->module) { - STP_UNLOCK_MODULES; - return 1; } } - STP_UNLOCK_MODULES; - return 0; + + /* remove modules with overlapping addresses */ + for (num = 1; num < _stp_num_modules; num++) { + if (mod->text + mod->text_size < _stp_modules_by_addr[num]->text) + continue; + if (mod->text < _stp_modules_by_addr[num]->text + + _stp_modules_by_addr[num]->text_size) { + dbug(DEBUG_SYMBOLS, "New module %s overlaps with old module %s. Deleting old.\n", + mod->name, _stp_modules_by_addr[num]->name); + _stp_del_module(_stp_modules_by_addr[num]); + } + } + } static int _stp_ins_module(struct _stp_module *mod) @@ -400,9 +450,11 @@ static int _stp_ins_module(struct _stp_module *mod) int i, num, res, ret = 0; unsigned long flags; - // kbug("insert %s\n", mod->name); + // kbug(DEBUG_SYMBOLS, "insert %s\n", mod->name); - STP_LOCK_MODULES; + STP_WLOCK_MODULES; + + _stp_module_exists_delete(mod); /* check for overflow */ if (_stp_num_modules == STP_MAX_MODULES) { @@ -412,32 +464,25 @@ static int _stp_ins_module(struct _stp_module *mod) } /* insert alphabetically in _stp_modules[] */ - for (num = 1; num < _stp_num_modules; num++) { - res = strcmp(_stp_modules[num]->name, mod->name); - if (res < 0) - continue; - if (res > 0) + for (num = 1; num < _stp_num_modules; num++) + if (strcmp(_stp_modules[num]->name, mod->name) > 0) break; - _stp_del_module(_stp_modules[num]); - break; - } for (i = _stp_num_modules; i > num; i--) _stp_modules[i] = _stp_modules[i-1]; _stp_modules[num] = mod; /* insert by text address in _stp_modules_by_addr[] */ - for (num = 1; num < _stp_num_modules; num++) { - if (_stp_modules_by_addr[num]->text > mod->text) + for (num = 1; num < _stp_num_modules; num++) + if (mod->text < _stp_modules_by_addr[num]->text) break; - } for (i = _stp_num_modules; i > num; i--) _stp_modules_by_addr[i] = _stp_modules_by_addr[i-1]; _stp_modules_by_addr[num] = mod; - + _stp_num_modules++; done: - STP_UNLOCK_MODULES; + STP_WUNLOCK_MODULES; return ret; } @@ -456,13 +501,13 @@ static int _stp_do_module(const char __user *buf, int count) if (copy_from_user ((char *)&tmpmod, buf, sizeof(tmpmod))) return -EFAULT; - section_len = count - sizeof(tmpmod); + section_len = count - sizeof(tmpmod) - tmpmod.unwind_len; if (section_len <= 0) { errk("section_len = %d\n", section_len); return -EFAULT; } - kbug("Got module %s, count=%d section_len=%d\n", - tmpmod.name, count, section_len); + dbug(DEBUG_SYMBOLS, "Got module %s, count=%d section_len=%d unwind_len=%d\n", + tmpmod.name, count, section_len, tmpmod.unwind_len); strcpy(mod.name, tmpmod.name); mod.module = tmpmod.module; @@ -470,9 +515,6 @@ static int _stp_do_module(const char __user *buf, int count) mod.data = tmpmod.data; mod.num_sections = tmpmod.num_sections; - if (_stp_module_exists(&mod)) - return count; - /* copy in section data */ mod.sections = _stp_kmalloc(section_len); if (mod.sections == NULL) { @@ -489,18 +531,27 @@ static int _stp_do_module(const char __user *buf, int count) + (long)((long)mod.sections + mod.num_sections * sizeof(struct _stp_symbol))); } - #ifdef DEBUG_SYMBOLS + #if 0 for (i = 0; i < mod.num_sections; i++) - printk("section %d (stored at %p): %s %lx\n", i, &mod.sections[i], mod.sections[i].symbol, mod.sections[i].addr); + _dbug("section %d (stored at %p): %s %lx\n", i, &mod.sections[i], mod.sections[i].symbol, mod.sections[i].addr); #endif /* load symbols from tmpmod.module to mod */ - m = _stp_load_module_symbols(&mod); + m = _stp_load_module_symbols(&mod, tmpmod.unwind_len); if (m == NULL) { _stp_kfree(mod.sections); return 0; } + dbug(DEBUG_SYMBOLS, "module %s loaded. Text=%p text_size=%u\n", m->name, (int64_t)m->text, m->text_size); + /* finally copy unwind info */ + if (copy_from_user (m->unwind_data, buf+sizeof(tmpmod)+section_len, tmpmod.unwind_len)) { + _stp_free_module(m); + _stp_kfree(mod.sections); + return -EFAULT; + } + m->unwind_data_len = tmpmod.unwind_len; + if (_stp_ins_module(m) < 0) { _stp_free_module(m); return -ENOMEM; @@ -513,20 +564,18 @@ static int _stp_ctl_send (int type, void *data, int len); static int _stp_module_load_notify(struct notifier_block * self, unsigned long val, void * data) { -#ifdef CONFIG_MODULES struct module *mod = (struct module *)data; struct _stp_module rmod; switch (val) { case MODULE_STATE_COMING: - dbug("module %s loaded\n", mod->name); + dbug(DEBUG_SYMBOLS, "module %s load notify\n", mod->name); strlcpy(rmod.name, mod->name, STP_MODULE_NAME_LEN); _stp_ctl_send(STP_MODULE, &rmod, sizeof(struct _stp_module)); break; default: errk("module loaded? val=%ld\n", val); } -#endif return 0; } diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 6b90ee64..8335e44b 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -18,6 +18,7 @@ #include <linux/namei.h> #include "transport.h" #include "time.c" +#include "../mempool.c" #include "symbols.c" #include "../procfs.c" @@ -76,7 +77,7 @@ static void _stp_ask_for_symbols(void) if (sent_symbols == 0) { /* ask for symbols and modules */ - kbug("AFS\n"); + kbug(DEBUG_SYMBOLS|DEBUG_TRANSPORT, "AFS\n"); req.endian = 0x1234; req.ptr_size = sizeof(char *); @@ -94,7 +95,7 @@ static void _stp_ask_for_symbols(void) void _stp_handle_start (struct _stp_msg_start *st) { - kbug ("stp_handle_start\n"); + kbug (DEBUG_TRANSPORT, "stp_handle_start\n"); if (register_module_notifier(&_stp_module_load_nb)) errk("failed to load module notifier\n"); @@ -116,7 +117,7 @@ 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 dont_rmmod) { - kbug("cleanup_and_exit (%d)\n", dont_rmmod); + kbug(DEBUG_TRANSPORT, "cleanup_and_exit (%d)\n", dont_rmmod); if (!_stp_exit_called) { int failures; @@ -127,23 +128,23 @@ static void _stp_cleanup_and_exit (int dont_rmmod) _stp_exit_called = 1; if (_stp_probes_started) { - kbug("calling probe_exit\n"); + kbug(DEBUG_TRANSPORT, "calling probe_exit\n"); /* tell the stap-generated code to unload its probes, etc */ probe_exit(); - kbug("done with probe_exit\n"); + kbug(DEBUG_TRANSPORT, "done with probe_exit\n"); } failures = atomic_read(&_stp_transport_failures); if (failures) _stp_warn ("There were %d transport failures.\n", failures); - kbug("************** calling startstop 0 *************\n"); + kbug(DEBUG_TRANSPORT, "************** calling startstop 0 *************\n"); if (_stp_utt) utt_trace_startstop(_stp_utt, 0, &utt_seq); - kbug("ctl_send STP_EXIT\n"); + kbug(DEBUG_TRANSPORT, "ctl_send STP_EXIT\n"); /* tell staprun to exit (if it is still there) */ _stp_ctl_send(STP_EXIT, &dont_rmmod, sizeof(int)); - kbug("done with ctl_send STP_EXIT\n"); + kbug(DEBUG_TRANSPORT, "done with ctl_send STP_EXIT\n"); } } @@ -152,7 +153,7 @@ static void _stp_cleanup_and_exit (int dont_rmmod) */ static void _stp_detach(void) { - kbug("detach\n"); + kbug(DEBUG_TRANSPORT, "detach\n"); _stp_attached = 0; _stp_pid = 0; @@ -168,7 +169,7 @@ static void _stp_detach(void) */ static void _stp_attach(void) { - kbug("attach\n"); + kbug(DEBUG_TRANSPORT, "attach\n"); _stp_attached = 1; _stp_pid = current->pid; utt_set_overwrite(0); @@ -210,7 +211,7 @@ static void _stp_work_queue (void *data) */ void _stp_transport_close() { - kbug("%d: ************** transport_close *************\n", current->pid); + kbug(DEBUG_TRANSPORT, "%d: ************** transport_close *************\n", current->pid); _stp_cleanup_and_exit(1); destroy_workqueue(_stp_wq); _stp_unregister_ctl_channel(); @@ -219,7 +220,7 @@ void _stp_transport_close() _stp_kill_time(); _stp_print_cleanup(); /* free print buffers */ _stp_mem_debug_done(); - kbug("---- CLOSED ----\n"); + kbug(DEBUG_TRANSPORT, "---- CLOSED ----\n"); } @@ -248,7 +249,7 @@ int _stp_transport_init(void) { int ret; - kbug("transport_init\n"); + kbug(DEBUG_TRANSPORT, "transport_init\n"); _stp_init_pid = current->pid; _stp_uid = current->uid; _stp_gid = current->gid; @@ -263,7 +264,7 @@ int _stp_transport_init(void) unsigned size = _stp_bufsize * 1024 * 1024; _stp_subbuf_size = ((size >> 2) + 1) * 65536; _stp_nsubbufs = size / _stp_subbuf_size; - kbug("Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size); + kbug(DEBUG_TRANSPORT, "Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size); } /* initialize timer code */ @@ -388,12 +389,12 @@ static struct dentry *_stp_get_root_dir(const char *name) { _stp_lock_inode(sb->s_root->d_inode); root = lookup_one_len(name, sb->s_root, strlen(name)); _stp_unlock_inode(sb->s_root->d_inode); - kbug("root=%p\n", root); + kbug(DEBUG_TRANSPORT, "root=%p\n", root); if (!IS_ERR(root)) dput(root); else { root = NULL; - kbug("Could not create or find transport directory.\n"); + kbug(DEBUG_TRANSPORT, "Could not create or find transport directory.\n"); } } _stp_unlock_debugfs(); diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index b2187cd5..55de2d4a 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -36,7 +36,30 @@ enum STP_SUBBUFS_CONSUMED, STP_REALTIME_DATA, #endif + + STP_MAX_CMD +}; + +#ifdef DEBUG_TRANSPORT +static const char *_stp_command_name[] = { + "STP_START", + "STP_EXIT", + "STP_OOB_DATA", + "STP_SYSTEM", + "STP_SYMBOLS", + "STP_MODULE", + "STP_TRANSPORT", + "STP_CONNECT", + "STP_DISCONNECT", + "STP_BULK", + "STP_READY", +#ifdef STP_OLD_TRANSPORT + "STP_BUF_INFO", + "STP_SUBBUFS_CONSUMED", + "STP_REALTIME_DATA", +#endif }; +#endif /* DEBUG_TRANSPORT */ /* control channel messages */ |