X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=ltt-events.c;h=28f7bdb44ec687e720920acc8c07e38b37dae4b6;hb=71c1d8431c8b94c34332cf2fbdbd7c9dc5f1489a;hp=6171c1c5791dbdaca021f344a1fa5a7472672067;hpb=8070f5c01e8e64ce52912dd4f27021c5d9e3dce2;p=deliverable%2Flttng-modules.git diff --git a/ltt-events.c b/ltt-events.c index 6171c1c5..28f7bdb4 100644 --- a/ltt-events.c +++ b/ltt-events.c @@ -4,6 +4,8 @@ * Copyright 2010 (c) - Mathieu Desnoyers * * Holds LTTng per-session event registry. + * + * Dual LGPL v2.1/GPL v2 license. */ #include @@ -12,7 +14,7 @@ #include #include #include -#include +#include "wrapper/uuid.h" #include "wrapper/vmalloc.h" /* for wrapper_vmalloc_sync_all() */ #include "ltt-events.h" #include "ltt-tracer.h" @@ -32,8 +34,6 @@ int _ltt_event_metadata_statedump(struct ltt_session *session, static int _ltt_session_metadata_statedump(struct ltt_session *session); - -static void synchronize_trace(void) { synchronize_sched(); @@ -80,7 +80,7 @@ void ltt_session_destroy(struct ltt_session *session) kfree(session); } -int ltt_session_start(struct ltt_session *session) +int ltt_session_enable(struct ltt_session *session) { int ret = 0; struct ltt_channel *chan; @@ -106,18 +106,15 @@ int ltt_session_start(struct ltt_session *session) ACCESS_ONCE(session->active) = 1; ACCESS_ONCE(session->been_active) = 1; - synchronize_trace(); /* Wait for in-flight events to complete */ ret = _ltt_session_metadata_statedump(session); - if (ret) { + if (ret) ACCESS_ONCE(session->active) = 0; - synchronize_trace(); /* Wait for in-flight events to complete */ - } end: mutex_unlock(&sessions_mutex); return ret; } -int ltt_session_stop(struct ltt_session *session) +int ltt_session_disable(struct ltt_session *session) { int ret = 0; @@ -127,12 +124,59 @@ int ltt_session_stop(struct ltt_session *session) goto end; } ACCESS_ONCE(session->active) = 0; - synchronize_trace(); /* Wait for in-flight events to complete */ end: mutex_unlock(&sessions_mutex); return ret; } +int ltt_channel_enable(struct ltt_channel *channel) +{ + int old; + + if (channel == channel->session->metadata) + return -EPERM; + old = xchg(&channel->enabled, 1); + if (old) + return -EEXIST; + return 0; +} + +int ltt_channel_disable(struct ltt_channel *channel) +{ + int old; + + if (channel == channel->session->metadata) + return -EPERM; + old = xchg(&channel->enabled, 0); + if (!old) + return -EEXIST; + return 0; +} + +int ltt_event_enable(struct ltt_event *event) +{ + int old; + + if (event->chan == event->chan->session->metadata) + return -EPERM; + old = xchg(&event->enabled, 1); + if (old) + return -EEXIST; + return 0; +} + +int ltt_event_disable(struct ltt_event *event) +{ + int old; + + if (event->chan == event->chan->session->metadata) + return -EPERM; + old = xchg(&event->enabled, 0); + if (!old) + return -EEXIST; + return 0; +} + static struct ltt_transport *ltt_transport_find(const char *name) { struct ltt_transport *transport; @@ -152,7 +196,7 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, unsigned int read_timer_interval) { struct ltt_channel *chan; - struct ltt_transport *transport; + struct ltt_transport *transport = NULL; mutex_lock(&sessions_mutex); if (session->been_active) @@ -163,11 +207,14 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, transport_name); goto notransport; } + if (!try_module_get(transport->owner)) { + printk(KERN_WARNING "LTT : Can't lock transport module.\n"); + goto notransport; + } chan = kzalloc(sizeof(struct ltt_channel), GFP_KERNEL); if (!chan) goto nomem; chan->session = session; - init_waitqueue_head(&chan->notify_wait); chan->id = session->free_chan_id++; /* * Note: the channel creation op already writes into the packet @@ -179,7 +226,9 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, read_timer_interval); if (!chan->chan) goto create_error; + chan->enabled = 1; chan->ops = &transport->ops; + chan->transport = transport; list_add(&chan->list, &session->chan); mutex_unlock(&sessions_mutex); return chan; @@ -187,6 +236,8 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, create_error: kfree(chan); nomem: + if (transport) + module_put(transport->owner); notransport: active: mutex_unlock(&sessions_mutex); @@ -200,6 +251,7 @@ static void _ltt_channel_destroy(struct ltt_channel *chan) { chan->ops->channel_destroy(chan->chan); + module_put(chan->transport->owner); list_del(&chan->list); lttng_destroy_context(chan->ctx); kfree(chan); @@ -231,6 +283,7 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, event->chan = chan; event->filter = filter; event->id = chan->free_event_id++; + event->enabled = 1; event->instrumentation = event_param->instrumentation; /* Populate ltt_event structure before tracepoint registration. */ smp_wmb(); @@ -256,6 +309,49 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, ret = try_module_get(event->desc->owner); WARN_ON_ONCE(!ret); break; + case LTTNG_KERNEL_KRETPROBE: + { + struct ltt_event *event_return; + + /* kretprobe defines 2 events */ + event_return = + kmem_cache_zalloc(event_cache, GFP_KERNEL); + if (!event_return) + goto register_error; + event_return->chan = chan; + event_return->filter = filter; + event_return->id = chan->free_event_id++; + event_return->enabled = 1; + event_return->instrumentation = event_param->instrumentation; + /* + * Populate ltt_event structure before kretprobe registration. + */ + smp_wmb(); + ret = lttng_kretprobes_register(event_param->name, + event_param->u.kretprobe.symbol_name, + event_param->u.kretprobe.offset, + event_param->u.kretprobe.addr, + event, event_return); + if (ret) { + kmem_cache_free(event_cache, event_return); + goto register_error; + } + /* Take 2 refs on the module: one per event. */ + ret = try_module_get(event->desc->owner); + WARN_ON_ONCE(!ret); + ret = try_module_get(event->desc->owner); + WARN_ON_ONCE(!ret); + ret = _ltt_event_metadata_statedump(chan->session, chan, + event_return); + if (ret) { + kmem_cache_free(event_cache, event_return); + module_put(event->desc->owner); + module_put(event->desc->owner); + goto statedump_error; + } + list_add(&event_return->list, &chan->session->events); + break; + } case LTTNG_KERNEL_FUNCTION: ret = lttng_ftrace_register(event_param->name, event_param->u.ftrace.symbol_name, @@ -308,6 +404,10 @@ int _ltt_event_unregister(struct ltt_event *event) lttng_kprobes_unregister(event); ret = 0; break; + case LTTNG_KERNEL_KRETPROBE: + lttng_kretprobes_unregister(event); + ret = 0; + break; case LTTNG_KERNEL_FUNCTION: lttng_ftrace_unregister(event); ret = 0; @@ -332,6 +432,10 @@ void _ltt_event_destroy(struct ltt_event *event) module_put(event->desc->owner); lttng_kprobes_destroy_private(event); break; + case LTTNG_KERNEL_KRETPROBE: + module_put(event->desc->owner); + lttng_kretprobes_destroy_private(event); + break; case LTTNG_KERNEL_FUNCTION: module_put(event->desc->owner); lttng_ftrace_destroy_private(event); @@ -383,7 +487,7 @@ int lttng_metadata_printf(struct ltt_session *session, * we need to bail out after timeout or being * interrupted. */ - waitret = wait_event_interruptible_timeout(*chan->ops->get_reader_wait_queue(chan), + waitret = wait_event_interruptible_timeout(*chan->ops->get_writer_buf_wait_queue(chan->chan, -1), ({ ret = chan->ops->event_reserve(&ctx, 0); ret != -ENOBUFS || !ret; @@ -397,7 +501,7 @@ int lttng_metadata_printf(struct ltt_session *session, ret = waitret; goto end; } - chan->ops->event_write(&ctx, &str[pos], len); + chan->ops->event_write(&ctx, &str[pos], reserve_len); chan->ops->event_commit(&ctx); } end: @@ -470,31 +574,34 @@ int _ltt_field_statedump(struct ltt_session *session, length_type = &field->type.u.sequence.length_type; ret = lttng_metadata_printf(session, " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n", - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[ __%s_length ];\n", length_type->u.basic.integer.size, - length_type->u.basic.integer.alignment, + (unsigned int) length_type->u.basic.integer.alignment, length_type->u.basic.integer.signedness, (length_type->u.basic.integer.encoding == lttng_encode_none) ? "none" - : (length_type->u.basic.integer.encoding == lttng_encode_UTF8) + : ((length_type->u.basic.integer.encoding == lttng_encode_UTF8) ? "UTF8" - : "ASCII", + : "ASCII"), length_type->u.basic.integer.base, #ifdef __BIG_ENDIAN length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", #else - length_type->u.basic.integer.reverse_byte_order -? " byte_order = be;" : "", + length_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", #endif - field->name, + field->name); + if (ret) + return ret; + + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[ __%s_length ];\n", elem_type->u.basic.integer.size, - elem_type->u.basic.integer.alignment, + (unsigned int) elem_type->u.basic.integer.alignment, elem_type->u.basic.integer.signedness, (elem_type->u.basic.integer.encoding == lttng_encode_none) ? "none" - : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8) + : ((elem_type->u.basic.integer.encoding == lttng_encode_UTF8) ? "UTF8" - : "ASCII", + : "ASCII"), elem_type->u.basic.integer.base, #ifdef __BIG_ENDIAN elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", @@ -502,8 +609,7 @@ int _ltt_field_statedump(struct ltt_session *session, elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", #endif field->name, - field->name - ); + field->name); break; } @@ -575,20 +681,30 @@ int _ltt_event_metadata_statedump(struct ltt_session *session, "event {\n" " name = %s;\n" " id = %u;\n" - " stream_id = %u;\n" - " context := struct {\n", + " stream_id = %u;\n", event->desc->name, event->id, event->chan->id); if (ret) goto end; + if (event->ctx) { + ret = lttng_metadata_printf(session, + " context := struct {\n"); + if (ret) + goto end; + } ret = _ltt_context_metadata_statedump(session, event->ctx); if (ret) goto end; + if (event->ctx) { + ret = lttng_metadata_printf(session, + " };\n"); + if (ret) + goto end; + } ret = lttng_metadata_printf(session, - " };\n" " fields := struct {\n" ); if (ret) @@ -630,22 +746,31 @@ int _ltt_channel_metadata_statedump(struct ltt_session *session, "stream {\n" " id = %u;\n" " event.header := %s;\n" - " packet.context := struct packet_context;\n" - " event.context := {\n", + " packet.context := struct packet_context;\n", chan->id, chan->header_type == 1 ? "struct event_header_compact" : "struct event_header_large"); if (ret) goto end; + if (chan->ctx) { + ret = lttng_metadata_printf(session, + " event.context := struct {\n"); + if (ret) + goto end; + } ret = _ltt_context_metadata_statedump(session, chan->ctx); if (ret) goto end; + if (chan->ctx) { + ret = lttng_metadata_printf(session, + " };\n"); + if (ret) + goto end; + } ret = lttng_metadata_printf(session, - " };\n" - "};\n\n" - ); + "};\n\n"); chan->metadata_dumped = 1; end: