X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=ltt-probes.c;h=81dcbd715df08300b6bcfd9973418f853544e8d0;hb=6fb8de4b6c1e8dcc69ff6f67310c5cf29718101a;hp=f8f1ef225b417473fb0c6a69fc969fe4cbac40bd;hpb=dda6a249b86e7f06e82fb18a26e981522d9e852d;p=lttng-modules.git diff --git a/ltt-probes.c b/ltt-probes.c index f8f1ef22..81dcbd71 100644 --- a/ltt-probes.c +++ b/ltt-probes.c @@ -4,108 +4,161 @@ * Copyright 2010 (c) - Mathieu Desnoyers * * Holds LTTng probes registry. + * + * Dual LGPL v2.1/GPL v2 license. */ #include #include #include -#include +#include -struct ltt_probe { - const char *name; - void *cb; - struct list_head list; -}; +#include "ltt-events.h" static LIST_HEAD(probe_list); static DEFINE_MUTEX(probe_mutex); -static struct kmem_cache *probe_cache; -static struct ltt_probe *find_probe(const char *name) +static +const struct lttng_event_desc *find_event(const char *name) { - struct ltt_probe *probe; + struct lttng_probe_desc *probe_desc; + int i; - list_for_each_entry(probe, &probe_list, list) { - if (!strcmp(probe->name, name)) - return probe; + list_for_each_entry(probe_desc, &probe_list, head) { + for (i = 0; i < probe_desc->nr_events; i++) { + if (!strcmp(probe_desc->event_desc[i]->name, name)) + return probe_desc->event_desc[i]; + } } return NULL; } -int ltt_probe_register(const char *name, void *cb) +int ltt_probe_register(struct lttng_probe_desc *desc) { - struct ltt_probe *probe; int ret = 0; - - if (!cb) - return -EPERM; + int i; mutex_lock(&probe_mutex); - if (find_probe(name)) { - ret = -EEXIST; - goto end; - } - probe = kmem_cache_zalloc(probe_cache, GFP_KERNEL); - if (!probe) { - ret = -ENOMEM; - goto end; + /* + * TODO: This is O(N^2). Turn into a hash table when probe registration + * overhead becomes an issue. + */ + for (i = 0; i < desc->nr_events; i++) { + if (find_event(desc->event_desc[i]->name)) { + ret = -EEXIST; + goto end; + } } - probe->name = name; - probe->cb = cb; - list_add(&probe->list, &probe_list); + list_add(&desc->head, &probe_list); end: mutex_unlock(&probe_mutex); return ret; } EXPORT_SYMBOL_GPL(ltt_probe_register); -void ltt_probe_unregister(const char *name) +void ltt_probe_unregister(struct lttng_probe_desc *desc) { - struct ltt_probe *probe; - mutex_lock(&probe_mutex); - probe = find_probe(name); - WARN_ON_ONCE(!probe); - list_del(&probe->list); + list_del(&desc->head); mutex_unlock(&probe_mutex); - kmem_cache_free(probe_cache, probe); } EXPORT_SYMBOL_GPL(ltt_probe_unregister); -void *ltt_probe_get(const char *name) +const struct lttng_event_desc *ltt_event_get(const char *name) { - struct ltt_probe *probe; - void *cb = NULL; + const struct lttng_event_desc *event; int ret; mutex_lock(&probe_mutex); - probe = find_probe(name); - if (!probe) - goto end; - cb = probe->cb; - ret = try_module_get(__module_text_address((unsigned long) cb)); - WARN_ON_ONCE(!ret); -end: + event = find_event(name); mutex_unlock(&probe_mutex); - return cb; + if (!event) + return NULL; + ret = try_module_get(event->owner); + WARN_ON_ONCE(!ret); + return event; +} +EXPORT_SYMBOL_GPL(ltt_event_get); + +void ltt_event_put(const struct lttng_event_desc *event) +{ + module_put(event->owner); +} +EXPORT_SYMBOL_GPL(ltt_event_put); + +static +void *tp_list_start(struct seq_file *m, loff_t *pos) +{ + struct lttng_probe_desc *probe_desc; + int iter = 0, i; + + mutex_lock(&probe_mutex); + list_for_each_entry(probe_desc, &probe_list, head) { + for (i = 0; i < probe_desc->nr_events; i++) { + if (iter++ >= *pos) + return (void *) probe_desc->event_desc[i]; + } + } + /* End of list */ + return NULL; } -EXPORT_SYMBOL_GPL(ltt_probe_get); -void ltt_probe_put(void *cb) +static +void *tp_list_next(struct seq_file *m, void *p, loff_t *ppos) { - module_put(__module_text_address((unsigned long) cb)); + struct lttng_probe_desc *probe_desc; + int iter = 0, i; + + (*ppos)++; + list_for_each_entry(probe_desc, &probe_list, head) { + for (i = 0; i < probe_desc->nr_events; i++) { + if (iter++ >= *ppos) + return (void *) probe_desc->event_desc[i]; + } + } + /* End of list */ + return NULL; } -EXPORT_SYMBOL_GPL(ltt_probe_put); -int __init ltt_probes_init(void) +static +void tp_list_stop(struct seq_file *m, void *p) { - probe_cache = KMEM_CACHE(ltt_probe, 0); - if (!probe_cache) - return -ENOMEM; + mutex_unlock(&probe_mutex); +} + +static +int tp_list_show(struct seq_file *m, void *p) +{ + const struct lttng_event_desc *probe_desc = p; + + /* + * Don't export lttng internal events (metadata). + */ + if (!strncmp(probe_desc->name, "lttng_", sizeof("lttng_") - 1)) + return 0; + seq_printf(m, "event { name = %s; };\n", + probe_desc->name); return 0; } -void __exit ltt_probes_exit(void) +static +const struct seq_operations lttng_tracepoint_list_seq_ops = { + .start = tp_list_start, + .next = tp_list_next, + .stop = tp_list_stop, + .show = tp_list_show, +}; + +static +int lttng_tracepoint_list_open(struct inode *inode, struct file *file) { - kmem_cache_destroy(probe_cache); + return seq_open(file, <tng_tracepoint_list_seq_ops); } + +const struct file_operations lttng_tracepoint_list_fops = { + .owner = THIS_MODULE, + .open = lttng_tracepoint_list_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +};