From 85a9ca7ff30ef892e5865c5541fd11f6c6de33a3 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Fri, 13 May 2011 04:24:30 -0400 Subject: [PATCH] Keep event description registry instead of just name callback mapping Signed-off-by: Mathieu Desnoyers --- ltt-debugfs-abi.c | 32 +++++------ ltt-events.c | 27 +++------ ltt-events.h | 130 ++++++++++++++++++++++-------------------- ltt-probes.c | 99 +++++++++++++------------------- probes/lttng-events.h | 49 +++++++--------- 5 files changed, 152 insertions(+), 185 deletions(-) diff --git a/ltt-debugfs-abi.c b/ltt-debugfs-abi.c index 99b41966..0f649fc2 100644 --- a/ltt-debugfs-abi.c +++ b/ltt-debugfs-abi.c @@ -124,30 +124,30 @@ void lttng_metadata_create_events(struct file *channel_file) { struct ltt_channel *channel = channel_file->private_data; char *event_name = "lttng-metadata"; + const struct lttng_event_desc *event_desc; struct ltt_event *event; int ret; - void *probe; - probe = ltt_probe_get(event_name); - if (!probe) { + event_desc = ltt_event_get(event_name); + if (!event_desc) { ret = -ENOENT; - goto probe_error; + goto get_error; } /* * We tolerate no failure path after event creation. It will stay * invariant for the rest of the session. */ event = ltt_event_create(channel, event_name, INSTRUM_TRACEPOINTS, - probe, NULL); + event_desc, NULL); if (!event) { - goto event_error; + goto create_error; ret = -EEXIST; } return; -event_error: - ltt_probe_put(probe); -probe_error: +create_error: + ltt_event_put(event_desc); +get_error: WARN_ON(1); return; /* not allowed to return error */ } @@ -338,12 +338,12 @@ int lttng_abi_create_event(struct file *channel_file, struct lttng_event __user *uevent_param) { struct ltt_channel *channel = channel_file->private_data; + const struct lttng_event_desc *event_desc; struct ltt_event *event; char *event_name; struct lttng_event event_param; int event_fd, ret; struct file *event_file; - void *probe; if (copy_from_user(&event_param, uevent_param, sizeof(event_param))) return -EFAULT; @@ -356,10 +356,10 @@ int lttng_abi_create_event(struct file *channel_file, } event_name[PATH_MAX - 1] = '\0'; - probe = ltt_probe_get(event_name); - if (!probe) { + event_desc = ltt_event_get(event_name); + if (!event_desc) { ret = -ENOENT; - goto probe_error; + goto get_error; } event_fd = get_unused_fd(); if (event_fd < 0) { @@ -378,7 +378,7 @@ int lttng_abi_create_event(struct file *channel_file, * invariant for the rest of the session. */ event = ltt_event_create(channel, event_name, event_param.itype, - probe, NULL); + event_desc, NULL); if (!event) { goto event_error; ret = -EEXIST; @@ -395,8 +395,8 @@ event_error: file_error: put_unused_fd(event_fd); fd_error: - ltt_probe_put(probe); -probe_error: + ltt_event_put(event_desc); +get_error: name_error: kfree(event_name); return ret; diff --git a/ltt-events.c b/ltt-events.c index 512e7a24..a5ca1aba 100644 --- a/ltt-events.c +++ b/ltt-events.c @@ -167,7 +167,8 @@ void _ltt_channel_destroy(struct ltt_channel *chan) */ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, enum instrum_type itype, - void *probe, void *filter) + const struct lttng_event_desc *event_desc, + void *filter) { struct ltt_event *event; int ret; @@ -180,17 +181,13 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, * creation). Might require a hash if we have lots of events. */ list_for_each_entry(event, &chan->session->events, list) - if (!strcmp(event->name, name)) + if (!strcmp(event->desc->name, name)) goto exist; event = kmem_cache_zalloc(event_cache, GFP_KERNEL); if (!event) goto cache_error; - event->name = kmalloc(strlen(name) + 1, GFP_KERNEL); - if (!event->name) - goto name_error; - strcpy(event->name, name); event->chan = chan; - event->probe = probe; + event->desc = event_desc; event->filter = filter; event->id = chan->free_event_id++; event->itype = itype; @@ -198,7 +195,8 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, smp_wmb(); switch (itype) { case INSTRUM_TRACEPOINTS: - ret = tracepoint_probe_register(name, probe, event); + ret = tracepoint_probe_register(name, event_desc->probe_callback, + event); if (ret) goto register_error; break; @@ -210,8 +208,6 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, return event; register_error: - kfree(event->name); -name_error: kmem_cache_free(event_cache, event); cache_error: exist: @@ -229,7 +225,8 @@ int _ltt_event_unregister(struct ltt_event *event) switch (event->itype) { case INSTRUM_TRACEPOINTS: - ret = tracepoint_probe_unregister(event->name, event->probe, + ret = tracepoint_probe_unregister(event->desc->name, + event->desc->probe_callback, event); if (ret) return ret; @@ -245,7 +242,7 @@ int _ltt_event_unregister(struct ltt_event *event) */ void _ltt_event_destroy(struct ltt_event *event) { - kfree(event->name); + ltt_event_put(event->desc); list_del(&event->list); kmem_cache_free(event_cache, event); } @@ -297,16 +294,11 @@ static int __init ltt_events_init(void) event_cache = KMEM_CACHE(ltt_event, 0); if (!event_cache) return -ENOMEM; - ret = ltt_probes_init(); - if (ret) - goto error; ret = ltt_debugfs_abi_init(); if (ret) goto error_abi; return 0; error_abi: - ltt_probes_exit(); -error: kmem_cache_destroy(event_cache); return ret; } @@ -318,7 +310,6 @@ static void __exit ltt_events_exit(void) struct ltt_session *session, *tmpsession; ltt_debugfs_abi_exit(); - ltt_probes_exit(); list_for_each_entry_safe(session, tmpsession, &sessions, list) ltt_session_destroy(session); kmem_cache_destroy(event_cache); diff --git a/ltt-events.h b/ltt-events.h index 9e0ad2d7..344b6fd1 100644 --- a/ltt-events.h +++ b/ltt-events.h @@ -16,62 +16,6 @@ struct ltt_channel; struct ltt_session; struct lib_ring_buffer_ctx; -/* - * ltt_event structure is referred to by the tracing fast path. It must be - * kept small. - */ -struct ltt_event { - unsigned int id; - struct ltt_channel *chan; - void *probe; - void *filter; - char *name; - enum instrum_type itype; - struct list_head list; /* Event list */ -}; - -struct ltt_channel_ops { - struct channel *(*channel_create)(const char *name, - struct ltt_session *session, - void *buf_addr, - size_t subbuf_size, size_t num_subbuf, - unsigned int switch_timer_interval, - unsigned int read_timer_interval); - void (*channel_destroy)(struct channel *chan); - struct lib_ring_buffer *(*buffer_read_open)(struct channel *chan); - void (*buffer_read_close)(struct lib_ring_buffer *buf); - int (*event_reserve)(struct lib_ring_buffer_ctx *ctx); - void (*event_commit)(struct lib_ring_buffer_ctx *ctx); - void (*event_write)(struct lib_ring_buffer_ctx *ctx, const void *src, - size_t len); -}; - -struct ltt_channel { - struct channel *chan; /* Channel buffers */ - /* Event ID management */ - struct ltt_session *session; - struct file *file; /* File associated to channel */ - unsigned int free_event_id; /* Next event ID to allocate */ - struct list_head list; /* Channel list */ - wait_queue_head_t notify_wait; /* Channel addition notif. waitqueue */ - struct ltt_channel_ops *ops; -}; - -struct ltt_session { - int active; /* Is trace session active ? */ - struct file *file; /* File associated to session */ - struct list_head chan; /* Channel list head */ - struct list_head events; /* Event list head */ - struct list_head list; /* Session list */ -}; - -struct ltt_transport { - char *name; - struct module *owner; - struct list_head node; - struct ltt_channel_ops ops; -}; - /* Type description */ /* Update the astract_types name table in lttng-types.c along with this enum */ @@ -143,6 +87,67 @@ struct lttng_event_desc { unsigned int nr_fields; }; +struct lttng_probe_desc { + const struct lttng_event_desc *event_desc; + unsigned int nr_events; + struct list_head head; /* chain registered probes */ +}; + +/* + * ltt_event structure is referred to by the tracing fast path. It must be + * kept small. + */ +struct ltt_event { + unsigned int id; + struct ltt_channel *chan; + const struct lttng_event_desc *desc; + void *filter; + enum instrum_type itype; + struct list_head list; /* Event list */ +}; + +struct ltt_channel_ops { + struct channel *(*channel_create)(const char *name, + struct ltt_session *session, + void *buf_addr, + size_t subbuf_size, size_t num_subbuf, + unsigned int switch_timer_interval, + unsigned int read_timer_interval); + void (*channel_destroy)(struct channel *chan); + struct lib_ring_buffer *(*buffer_read_open)(struct channel *chan); + void (*buffer_read_close)(struct lib_ring_buffer *buf); + int (*event_reserve)(struct lib_ring_buffer_ctx *ctx); + void (*event_commit)(struct lib_ring_buffer_ctx *ctx); + void (*event_write)(struct lib_ring_buffer_ctx *ctx, const void *src, + size_t len); +}; + +struct ltt_channel { + struct channel *chan; /* Channel buffers */ + /* Event ID management */ + struct ltt_session *session; + struct file *file; /* File associated to channel */ + unsigned int free_event_id; /* Next event ID to allocate */ + struct list_head list; /* Channel list */ + wait_queue_head_t notify_wait; /* Channel addition notif. waitqueue */ + struct ltt_channel_ops *ops; +}; + +struct ltt_session { + int active; /* Is trace session active ? */ + struct file *file; /* File associated to session */ + struct list_head chan; /* Channel list head */ + struct list_head events; /* Event list head */ + struct list_head list; /* Session list */ +}; + +struct ltt_transport { + char *name; + struct module *owner; + struct list_head node; + struct ltt_channel_ops ops; +}; + struct ltt_session *ltt_session_create(void); int ltt_session_start(struct ltt_session *session); int ltt_session_stop(struct ltt_session *session); @@ -164,7 +169,8 @@ void _ltt_channel_destroy(struct ltt_channel *chan); struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, enum instrum_type itype, - void *probe, void *filter); + const struct lttng_event_desc *event_desc, + void *filter); int _ltt_event_unregister(struct ltt_event *event); void _ltt_event_destroy(struct ltt_event *event); @@ -174,11 +180,9 @@ void ltt_transport_unregister(struct ltt_transport *transport); int ltt_debugfs_abi_init(void); void ltt_debugfs_abi_exit(void); -int ltt_probe_register(const char *name, void *cb); -void ltt_probe_unregister(const char *name); -void *ltt_probe_get(const char *name); -void ltt_probe_put(void *cb); -int ltt_probes_init(void); -void ltt_probes_exit(void); +int ltt_probe_register(struct lttng_probe_desc *desc); +void ltt_probe_unregister(struct lttng_probe_desc *desc); +const struct lttng_event_desc *ltt_event_get(const char *name); +void ltt_event_put(const struct lttng_event_desc *desc); #endif /* _LTT_EVENTS_H */ diff --git a/ltt-probes.c b/ltt-probes.c index f8f1ef22..dbdb50d4 100644 --- a/ltt-probes.c +++ b/ltt-probes.c @@ -9,103 +9,82 @@ #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) +/* + * TODO: registration of probe descriptions in dynamically allocated memory (not + * directly in a module memory) will require some care for refcounting: it's + * currently done by just refcounting the module in event_get/put. + */ +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; + /* + * 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 = kmem_cache_zalloc(probe_cache, GFP_KERNEL); - if (!probe) { - ret = -ENOMEM; - 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) + event = find_event(name); + if (!event) goto end; - cb = probe->cb; - ret = try_module_get(__module_text_address((unsigned long) cb)); + ret = try_module_get(__module_text_address((unsigned long) event)); WARN_ON_ONCE(!ret); end: mutex_unlock(&probe_mutex); - return cb; -} -EXPORT_SYMBOL_GPL(ltt_probe_get); - -void ltt_probe_put(void *cb) -{ - module_put(__module_text_address((unsigned long) cb)); -} -EXPORT_SYMBOL_GPL(ltt_probe_put); - -int __init ltt_probes_init(void) -{ - probe_cache = KMEM_CACHE(ltt_probe, 0); - if (!probe_cache) - return -ENOMEM; - return 0; + return event; } +EXPORT_SYMBOL_GPL(ltt_event_get); -void __exit ltt_probes_exit(void) +void ltt_event_put(const struct lttng_event_desc *event) { - kmem_cache_destroy(probe_cache); + module_put(__module_text_address((unsigned long) event)); } +EXPORT_SYMBOL_GPL(ltt_event_put); diff --git a/probes/lttng-events.h b/probes/lttng-events.h index 3a5a3b9c..a739bbc8 100644 --- a/probes/lttng-events.h +++ b/probes/lttng-events.h @@ -173,6 +173,25 @@ static const struct lttng_event_desc TP_ID(__event_desc___, TRACE_SYSTEM)[] = { #undef TP_ID1 #undef TP_ID + +/* + * Stage 2.1 of the trace events. + * + * Create a toplevel descriptor for the whole probe. + */ + +#define TP_ID1(_token, _system) _token##_system +#define TP_ID(_token, _system) TP_ID1(_token, _system) + +/* non-const because list head will be modified when registered. */ +static struct lttng_probe_desc TP_ID(__probe_desc___, TRACE_SYSTEM) = { + .event_desc = TP_ID(__event_desc___, TRACE_SYSTEM), + .nr_events = ARRAY_SIZE(TP_ID(__event_desc___, TRACE_SYSTEM)), +}; + +#undef TP_ID1 +#undef TP_ID + /* * Stage 3 of the trace events. * @@ -581,46 +600,20 @@ static void __event_probe__##_name(void *__data, _proto) \ static int TP_ID(__lttng_events_init__, TRACE_SYSTEM)(void) { int ret; - int i; wrapper_vmalloc_sync_all(); ret = TP_ID(__lttng_types_init__, TRACE_SYSTEM)(); if (ret) return ret; - for (i = 0; i < ARRAY_SIZE(TP_ID(__event_desc___, TRACE_SYSTEM)); i++) { - const struct lttng_event_desc *event_desc; - - event_desc = &TP_ID(__event_desc___, TRACE_SYSTEM)[i]; - ret = ltt_probe_register(event_desc->name, - event_desc->probe_callback); - if (ret) - goto error; - } - return 0; - -error: - for (i--; i >= 0; i--) { - const struct lttng_event_desc *event_desc; - - event_desc = &TP_ID(__event_desc___, TRACE_SYSTEM)[i]; - ltt_probe_unregister(event_desc->name); - } - return ret; + return ltt_probe_register(&TP_ID(__probe_desc___, TRACE_SYSTEM)); } module_init_eval(__lttng_events_init__, TRACE_SYSTEM); static void TP_ID(__lttng_events_exit__, TRACE_SYSTEM)(void) { - int i; - - for (i = 0; i < ARRAY_SIZE(TP_ID(__event_desc___, TRACE_SYSTEM)); i++) { - const struct lttng_event_desc *event_desc; - - event_desc = &TP_ID(__event_desc___, TRACE_SYSTEM)[i]; - ltt_probe_unregister(event_desc->name); - } TP_ID(__lttng_types_exit__, TRACE_SYSTEM)(); + ltt_probe_unregister(&TP_ID(__probe_desc___, TRACE_SYSTEM)); } module_exit_eval(__lttng_events_exit__, TRACE_SYSTEM); -- 2.34.1