X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=liblttng-ust%2Ftracepoint.c;h=f74a43b0ea67076a71c1f03b7b11976a4e3c5849;hb=ade7037b9b18fc90eb1ab919286aaf6ea3dc96a7;hp=1e252ce39d859fc10cc1766757db9ace908da7fe;hpb=8c12a40c4649401a53d868d1cf24619a05d3f81b;p=lttng-ust.git diff --git a/liblttng-ust/tracepoint.c b/liblttng-ust/tracepoint.c index 1e252ce3..f74a43b0 100644 --- a/liblttng-ust/tracepoint.c +++ b/liblttng-ust/tracepoint.c @@ -31,6 +31,7 @@ #include #include +#include /* for LTTNG_UST_SYM_NAME_LEN */ #include #include @@ -45,7 +46,10 @@ static const int tracepoint_debug; static int initialized; static void (*new_tracepoint_cb)(struct tracepoint *); -/* libraries that contain tracepoints (struct tracepoint_lib) */ +/* + * libraries that contain tracepoints (struct tracepoint_lib). + * Protected by UST lock. + */ static CDS_LIST_HEAD(libs); /* @@ -58,7 +62,7 @@ static CDS_LIST_HEAD(libs); /* * Tracepoint hash table, containing the active tracepoints. - * Protected by tracepoints_mutex. + * Protected by ust lock. */ #define TRACEPOINT_HASH_BITS 6 #define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS) @@ -71,7 +75,7 @@ static int need_update; * Note about RCU : * It is used to to delay the free of multiple probes array until a quiescent * state is reached. - * Tracepoint entries modifications are protected by the tracepoints_mutex. + * Tracepoint entries modifications are protected by the ust lock. */ struct tracepoint_entry { struct cds_hlist_node hlist; @@ -83,18 +87,20 @@ struct tracepoint_entry { struct tp_probes { union { struct cds_list_head list; + /* Field below only used for call_rcu scheme */ + /* struct rcu_head head; */ } u; struct tracepoint_probe probes[0]; }; -static inline void *allocate_probes(int count) +static void *allocate_probes(int count) { struct tp_probes *p = zmalloc(count * sizeof(struct tracepoint_probe) + sizeof(struct tp_probes)); return p == NULL ? NULL : p->probes; } -static inline void release_probes(void *old) +static void release_probes(void *old) { if (old) { struct tp_probes *tp_probes = caa_container_of(old, @@ -196,7 +202,7 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe, /* * Get tracepoint if the tracepoint is present in the tracepoint hash table. - * Must be called with tracepoints_mutex held. + * Must be called with ust lock held. * Returns NULL if not present. */ static struct tracepoint_entry *get_tracepoint(const char *name) @@ -204,11 +210,17 @@ static struct tracepoint_entry *get_tracepoint(const char *name) struct cds_hlist_head *head; struct cds_hlist_node *node; struct tracepoint_entry *e; - uint32_t hash = jhash(name, strlen(name), 0); + size_t name_len = strlen(name); + uint32_t hash; + if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) { + WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1); + name_len = LTTNG_UST_SYM_NAME_LEN - 1; + } + hash = jhash(name, name_len, 0); head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; cds_hlist_for_each_entry(e, node, head, hlist) { - if (!strcmp(name, e->name)) + if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) return e; } return NULL; @@ -216,19 +228,24 @@ static struct tracepoint_entry *get_tracepoint(const char *name) /* * Add the tracepoint to the tracepoint hash table. Must be called with - * tracepoints_mutex held. + * ust lock held. */ static struct tracepoint_entry *add_tracepoint(const char *name) { struct cds_hlist_head *head; struct cds_hlist_node *node; struct tracepoint_entry *e; - size_t name_len = strlen(name) + 1; - uint32_t hash = jhash(name, name_len-1, 0); + size_t name_len = strlen(name); + uint32_t hash; + if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) { + WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1); + name_len = LTTNG_UST_SYM_NAME_LEN - 1; + } + hash = jhash(name, name_len, 0); head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; cds_hlist_for_each_entry(e, node, head, hlist) { - if (!strcmp(name, e->name)) { + if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) { DBG("tracepoint %s busy", name); return ERR_PTR(-EEXIST); /* Already there */ } @@ -237,10 +254,11 @@ static struct tracepoint_entry *add_tracepoint(const char *name) * Using zmalloc here to allocate a variable length element. Could * cause some memory fragmentation if overused. */ - e = zmalloc(sizeof(struct tracepoint_entry) + name_len); + e = zmalloc(sizeof(struct tracepoint_entry) + name_len + 1); if (!e) return ERR_PTR(-ENOMEM); - memcpy(&e->name[0], name, name_len); + memcpy(&e->name[0], name, name_len + 1); + e->name[name_len] = '\0'; e->probes = NULL; e->refcount = 0; cds_hlist_add_head(&e->hlist, head); @@ -251,7 +269,7 @@ static struct tracepoint_entry *add_tracepoint(const char *name) * Remove the tracepoint from the tracepoint hash table. Must be called with * ust_lock held. */ -static inline void remove_tracepoint(struct tracepoint_entry *e) +static void remove_tracepoint(struct tracepoint_entry *e) { cds_hlist_del(&e->hlist); free(e); @@ -263,7 +281,7 @@ static inline void remove_tracepoint(struct tracepoint_entry *e) static void set_tracepoint(struct tracepoint_entry **entry, struct tracepoint *elem, int active) { - WARN_ON(strcmp((*entry)->name, elem->name) != 0); + WARN_ON(strncmp((*entry)->name, elem->name, LTTNG_UST_SYM_NAME_LEN - 1) != 0); /* * rcu_assign_pointer has a cmm_smp_wmb() which makes sure that the new @@ -491,105 +509,6 @@ void tracepoint_probe_update_all(void) } } -/* - * Returns 0 if current not found. - * Returns 1 if current found. - * - * Called with UST lock held - */ -int lib_get_iter_tracepoints(struct tracepoint_iter *iter) -{ - struct tracepoint_lib *iter_lib; - int found = 0; - - cds_list_for_each_entry(iter_lib, &libs, list) { - if (iter_lib < iter->lib) - continue; - else if (iter_lib > iter->lib) - iter->tracepoint = NULL; - found = tracepoint_get_iter_range(&iter->tracepoint, - iter_lib->tracepoints_start, - iter_lib->tracepoints_start + iter_lib->tracepoints_count); - if (found) { - iter->lib = iter_lib; - break; - } - } - return found; -} - -/** - * tracepoint_get_iter_range - Get a next tracepoint iterator given a range. - * @tracepoint: current tracepoints (in), next tracepoint (out) - * @begin: beginning of the range - * @end: end of the range - * - * Returns whether a next tracepoint has been found (1) or not (0). - * Will return the first tracepoint in the range if the input tracepoint is - * NULL. - * Called with UST lock held. - */ -int tracepoint_get_iter_range(struct tracepoint * const **tracepoint, - struct tracepoint * const *begin, struct tracepoint * const *end) -{ - if (!*tracepoint && begin != end) - *tracepoint = begin; - while (*tracepoint >= begin && *tracepoint < end) { - if (!**tracepoint) - (*tracepoint)++; /* skip dummy */ - else - return 1; - } - return 0; -} - -/* - * Called with UST lock held. - */ -static void tracepoint_get_iter(struct tracepoint_iter *iter) -{ - int found = 0; - - /* tracepoints in libs. */ - found = lib_get_iter_tracepoints(iter); - if (!found) - tracepoint_iter_reset(iter); -} - -/* - * Called with UST lock held. - */ -void tracepoint_iter_start(struct tracepoint_iter *iter) -{ - tracepoint_get_iter(iter); -} - -/* - * Called with UST lock held. - */ -void tracepoint_iter_next(struct tracepoint_iter *iter) -{ - iter->tracepoint++; - /* - * iter->tracepoint may be invalid because we blindly incremented it. - * Make sure it is valid by marshalling on the tracepoints, getting the - * tracepoints from following library if necessary. - */ - tracepoint_get_iter(iter); -} - -/* - * Called with UST lock held. - */ -void tracepoint_iter_stop(struct tracepoint_iter *iter) -{ -} - -void tracepoint_iter_reset(struct tracepoint_iter *iter) -{ - iter->tracepoint = NULL; -} - void tracepoint_set_new_tracepoint_cb(void (*cb)(struct tracepoint *)) { new_tracepoint_cb = cb; @@ -607,6 +526,20 @@ static void new_tracepoints(struct tracepoint * const *start, struct tracepoint } } +static +void lib_disable_tracepoints(struct tracepoint * const *begin, + struct tracepoint * const *end) +{ + struct tracepoint * const *iter; + + for (iter = begin; iter < end; iter++) { + if (!*iter) + continue; /* skip dummy */ + disable_tracepoint(*iter); + } + +} + int tracepoint_register_lib(struct tracepoint * const *tracepoints_start, int tracepoints_count) { @@ -649,18 +582,34 @@ lib_added: int tracepoint_unregister_lib(struct tracepoint * const *tracepoints_start) { struct tracepoint_lib *lib; + int tracepoints_count; ust_lock(); cds_list_for_each_entry(lib, &libs, list) { if (lib->tracepoints_start == tracepoints_start) { struct tracepoint_lib *lib2free = lib; + cds_list_del(&lib->list); + tracepoints_count = lib->tracepoints_count; free(lib2free); - break; + goto found; } } + goto end; +found: + /* + * Force tracepoint disarm for all tracepoints of this lib. + * This takes care of destructor of library that would leave a + * LD_PRELOAD wrapper override function enabled for tracing, but + * the session teardown would not be able to reach the + * tracepoint anymore to disable it. + */ + lib_disable_tracepoints(tracepoints_start, + tracepoints_start + tracepoints_count); + DBG("just unregistered a tracepoints section from %p", + tracepoints_start); +end: ust_unlock(); - return 0; } @@ -675,3 +624,25 @@ void exit_tracepoint(void) { initialized = 0; } + +/* + * Create the wrapper symbols. + */ +#undef tp_rcu_read_lock_bp +#undef tp_rcu_read_unlock_bp +#undef tp_rcu_dereference_bp + +void tp_rcu_read_lock_bp(void) +{ + rcu_read_lock_bp(); +} + +void tp_rcu_read_unlock_bp(void) +{ + rcu_read_unlock_bp(); +} + +void *tp_rcu_dereference_sym_bp(void *p) +{ + return rcu_dereference_bp(p); +}