X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=lttng-events.c;h=bb72156a8d4ce97c07290c70bf1e077fbcf7d907;hb=4baabfe378c1ed249d43d70275854788474fb714;hp=48e1760174569e449a330c766a7c3fca3ecba206;hpb=9f36eaed6f91d5897924b551b44d1edd8cee00e2;p=lttng-modules.git diff --git a/lttng-events.c b/lttng-events.c index 48e17601..bb72156a 100644 --- a/lttng-events.c +++ b/lttng-events.c @@ -27,9 +27,10 @@ #include #include #include +#include #include -#include /* for wrapper_vmalloc_sync_all() */ +#include /* for wrapper_vmalloc_sync_mappings() */ #include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include #define METADATA_CACHE_DEFAULT_SIZE 4096 @@ -76,7 +78,12 @@ int _lttng_field_statedump(struct lttng_session *session, void synchronize_trace(void) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,1,0)) + synchronize_rcu(); +#else synchronize_sched(); +#endif + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) #ifdef CONFIG_PREEMPT_RT_FULL synchronize_rcu(); @@ -124,7 +131,7 @@ struct lttng_session *lttng_session_create(void) goto err; INIT_LIST_HEAD(&session->chan); INIT_LIST_HEAD(&session->events); - uuid_le_gen(&session->uuid); + lttng_guid_gen(&session->uuid); metadata_cache = kzalloc(sizeof(struct lttng_metadata_cache), GFP_KERNEL); @@ -192,8 +199,10 @@ void lttng_session_destroy(struct lttng_session *session) BUG_ON(chan->channel_type == METADATA_CHANNEL); _lttng_channel_destroy(chan); } + mutex_lock(&session->metadata_cache->lock); list_for_each_entry(metadata_stream, &session->metadata_cache->metadata_stream, list) _lttng_metadata_channel_hangup(metadata_stream); + mutex_unlock(&session->metadata_cache->lock); if (session->pid_tracker) lttng_pid_tracker_destroy(session->pid_tracker); kref_put(&session->metadata_cache->refcount, metadata_cache_destroy); @@ -394,13 +403,14 @@ int lttng_event_enable(struct lttng_event *event) ret = -EINVAL; break; case LTTNG_KERNEL_KPROBE: - case LTTNG_KERNEL_FUNCTION: + case LTTNG_KERNEL_UPROBE: case LTTNG_KERNEL_NOOP: WRITE_ONCE(event->enabled, 1); break; case LTTNG_KERNEL_KRETPROBE: ret = lttng_kretprobes_event_enable_state(event, 1); break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through. */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -429,13 +439,14 @@ int lttng_event_disable(struct lttng_event *event) ret = -EINVAL; break; case LTTNG_KERNEL_KPROBE: - case LTTNG_KERNEL_FUNCTION: + case LTTNG_KERNEL_UPROBE: case LTTNG_KERNEL_NOOP: WRITE_ONCE(event->enabled, 0); break; case LTTNG_KERNEL_KRETPROBE: ret = lttng_kretprobes_event_enable_state(event, 0); break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through. */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -576,12 +587,13 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, event_name = event_desc->name; break; case LTTNG_KERNEL_KPROBE: + case LTTNG_KERNEL_UPROBE: case LTTNG_KERNEL_KRETPROBE: - case LTTNG_KERNEL_FUNCTION: case LTTNG_KERNEL_NOOP: case LTTNG_KERNEL_SYSCALL: event_name = event_param->name; break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through. */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -704,41 +716,43 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, list_add(&event_return->list, &chan->session->events); break; } - case LTTNG_KERNEL_FUNCTION: + case LTTNG_KERNEL_NOOP: + case LTTNG_KERNEL_SYSCALL: + /* + * Needs to be explicitly enabled after creation, since + * we may want to apply filters. + */ + event->enabled = 0; + event->registered = 0; + event->desc = event_desc; + if (!event->desc) { + ret = -EINVAL; + goto register_error; + } + break; + case LTTNG_KERNEL_UPROBE: /* * Needs to be explicitly enabled after creation, since * we may want to apply filters. */ event->enabled = 0; event->registered = 1; + /* * Populate lttng_event structure before event * registration. */ smp_wmb(); - ret = lttng_ftrace_register(event_name, - event_param->u.ftrace.symbol_name, + + ret = lttng_uprobes_register(event_param->name, + event_param->u.uprobe.fd, event); - if (ret) { + if (ret) goto register_error; - } ret = try_module_get(event->desc->owner); WARN_ON_ONCE(!ret); break; - case LTTNG_KERNEL_NOOP: - case LTTNG_KERNEL_SYSCALL: - /* - * Needs to be explicitly enabled after creation, since - * we may want to apply filters. - */ - event->enabled = 0; - event->registered = 0; - event->desc = event_desc; - if (!event->desc) { - ret = -EINVAL; - goto register_error; - } - break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -801,11 +815,12 @@ void register_event(struct lttng_event *event) desc->name); break; case LTTNG_KERNEL_KPROBE: + case LTTNG_KERNEL_UPROBE: case LTTNG_KERNEL_KRETPROBE: - case LTTNG_KERNEL_FUNCTION: case LTTNG_KERNEL_NOOP: ret = 0; break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ default: WARN_ON_ONCE(1); } @@ -839,10 +854,6 @@ int _lttng_event_unregister(struct lttng_event *event) lttng_kretprobes_unregister(event); ret = 0; break; - case LTTNG_KERNEL_FUNCTION: - lttng_ftrace_unregister(event); - ret = 0; - break; case LTTNG_KERNEL_SYSCALL: ret = lttng_syscall_filter_disable(event->chan, desc->name); @@ -850,6 +861,11 @@ int _lttng_event_unregister(struct lttng_event *event) case LTTNG_KERNEL_NOOP: ret = 0; break; + case LTTNG_KERNEL_UPROBE: + lttng_uprobes_unregister(event); + ret = 0; + break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ default: WARN_ON_ONCE(1); } @@ -876,13 +892,14 @@ void _lttng_event_destroy(struct lttng_event *event) 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); - break; case LTTNG_KERNEL_NOOP: case LTTNG_KERNEL_SYSCALL: break; + case LTTNG_KERNEL_UPROBE: + module_put(event->desc->owner); + lttng_uprobes_destroy_private(event); + break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ default: WARN_ON_ONCE(1); } @@ -1102,8 +1119,8 @@ int lttng_session_list_tracker_pids(struct lttng_session *session) ret = PTR_ERR(tracker_pids_list_file); goto file_error; } - if (atomic_long_add_unless(&session->file->f_count, - 1, INT_MAX) == INT_MAX) { + if (!atomic_long_add_unless(&session->file->f_count, 1, LONG_MAX)) { + ret = -EOVERFLOW; goto refcount_error; } ret = lttng_tracker_pids_list_fops.open(NULL, tracker_pids_list_file); @@ -1432,6 +1449,18 @@ error_free: return ret; } +int lttng_event_add_callsite(struct lttng_event *event, + struct lttng_kernel_event_callsite __user *callsite) +{ + + switch (event->instrumentation) { + case LTTNG_KERNEL_UPROBE: + return lttng_uprobes_add_callsite(event, callsite); + default: + return -EINVAL; + } +} + int lttng_enabler_attach_context(struct lttng_enabler *enabler, struct lttng_kernel_context *context_param) { @@ -1561,7 +1590,7 @@ void lttng_session_lazy_sync_enablers(struct lttng_session *session) * was written and a negative value on error. */ int lttng_metadata_output_channel(struct lttng_metadata_stream *stream, - struct channel *chan) + struct channel *chan, bool *coherent) { struct lib_ring_buffer_ctx ctx; int ret = 0; @@ -1600,6 +1629,7 @@ int lttng_metadata_output_channel(struct lttng_metadata_stream *stream, ret = stream->transport->ops.event_reserve(&ctx, 0); if (ret != 0) { printk(KERN_WARNING "LTTng: Metadata event reservation failed\n"); + stream->coherent = false; goto end; } stream->transport->ops.event_write(&ctx, @@ -1607,18 +1637,46 @@ int lttng_metadata_output_channel(struct lttng_metadata_stream *stream, reserve_len); stream->transport->ops.event_commit(&ctx); stream->metadata_in += reserve_len; + if (reserve_len < len) + stream->coherent = false; + else + stream->coherent = true; ret = reserve_len; end: + if (coherent) + *coherent = stream->coherent; mutex_unlock(&stream->metadata_cache->lock); return ret; } +static +void lttng_metadata_begin(struct lttng_session *session) +{ + if (atomic_inc_return(&session->metadata_cache->producing) == 1) + mutex_lock(&session->metadata_cache->lock); +} + +static +void lttng_metadata_end(struct lttng_session *session) +{ + WARN_ON_ONCE(!atomic_read(&session->metadata_cache->producing)); + if (atomic_dec_return(&session->metadata_cache->producing) == 0) { + struct lttng_metadata_stream *stream; + + list_for_each_entry(stream, &session->metadata_cache->metadata_stream, list) + wake_up_interruptible(&stream->read_wait); + mutex_unlock(&session->metadata_cache->lock); + } +} + /* * Write the metadata to the metadata cache. * Must be called with sessions_mutex held. * The metadata cache lock protects us from concurrent read access from * thread outputting metadata content to ring buffer. + * The content of the printf is printed as a single atomic metadata + * transaction. */ int lttng_metadata_printf(struct lttng_session *session, const char *fmt, ...) @@ -1626,7 +1684,6 @@ int lttng_metadata_printf(struct lttng_session *session, char *str; size_t len; va_list ap; - struct lttng_metadata_stream *stream; WARN_ON_ONCE(!READ_ONCE(session->active)); @@ -1637,7 +1694,7 @@ int lttng_metadata_printf(struct lttng_session *session, return -ENOMEM; len = strlen(str); - mutex_lock(&session->metadata_cache->lock); + WARN_ON_ONCE(!atomic_read(&session->metadata_cache->producing)); if (session->metadata_cache->metadata_written + len > session->metadata_cache->cache_alloc) { char *tmp_cache_realloc; @@ -1663,16 +1720,11 @@ int lttng_metadata_printf(struct lttng_session *session, session->metadata_cache->metadata_written, str, len); session->metadata_cache->metadata_written += len; - mutex_unlock(&session->metadata_cache->lock); kfree(str); - list_for_each_entry(stream, &session->metadata_cache->metadata_stream, list) - wake_up_interruptible(&stream->read_wait); - return 0; err: - mutex_unlock(&session->metadata_cache->lock); kfree(str); return -ENOMEM; } @@ -2209,6 +2261,8 @@ int _lttng_fields_metadata_statedump(struct lttng_session *session, /* * Must be called with sessions_mutex held. + * The entire event metadata is printed as a single atomic metadata + * transaction. */ static int _lttng_event_metadata_statedump(struct lttng_session *session, @@ -2222,6 +2276,8 @@ int _lttng_event_metadata_statedump(struct lttng_session *session, if (chan->channel_type == METADATA_CHANNEL) return 0; + lttng_metadata_begin(session); + ret = lttng_metadata_printf(session, "event {\n" " name = \"%s\";\n" @@ -2271,12 +2327,15 @@ int _lttng_event_metadata_statedump(struct lttng_session *session, event->metadata_dumped = 1; end: + lttng_metadata_end(session); return ret; } /* * Must be called with sessions_mutex held. + * The entire channel metadata is printed as a single atomic metadata + * transaction. */ static int _lttng_channel_metadata_statedump(struct lttng_session *session, @@ -2290,6 +2349,8 @@ int _lttng_channel_metadata_statedump(struct lttng_session *session, if (chan->channel_type == METADATA_CHANNEL) return 0; + lttng_metadata_begin(session); + WARN_ON_ONCE(!chan->header_type); ret = lttng_metadata_printf(session, "stream {\n" @@ -2323,6 +2384,7 @@ int _lttng_channel_metadata_statedump(struct lttng_session *session, chan->metadata_dumped = 1; end: + lttng_metadata_end(session); return ret; } @@ -2397,6 +2459,9 @@ int _lttng_event_header_declare(struct lttng_session *session) * in future versions. * This function may return a negative offset. It may happen if the * system sets the REALTIME clock to 0 after boot. + * + * Use 64bit timespec on kernels that have it, this makes 32bit arch + * y2038 compliant. */ static int64_t measure_clock_offset(void) @@ -2404,13 +2469,21 @@ int64_t measure_clock_offset(void) uint64_t monotonic_avg, monotonic[2], realtime; uint64_t tcf = trace_clock_freq(); int64_t offset; - struct timespec rts = { 0, 0 }; unsigned long flags; +#ifdef LTTNG_KERNEL_HAS_TIMESPEC64 + struct timespec64 rts = { 0, 0 }; +#else + struct timespec rts = { 0, 0 }; +#endif /* Disable interrupts to increase correlation precision. */ local_irq_save(flags); monotonic[0] = trace_clock_read64(); +#ifdef LTTNG_KERNEL_HAS_TIMESPEC64 + ktime_get_real_ts64(&rts); +#else getnstimeofday(&rts); +#endif monotonic[1] = trace_clock_read64(); local_irq_restore(flags); @@ -2428,6 +2501,61 @@ int64_t measure_clock_offset(void) return offset; } +static +int print_escaped_ctf_string(struct lttng_session *session, const char *string) +{ + int ret; + size_t i; + char cur; + + i = 0; + cur = string[i]; + while (cur != '\0') { + switch (cur) { + case '\n': + ret = lttng_metadata_printf(session, "%s", "\\n"); + break; + case '\\': + case '"': + ret = lttng_metadata_printf(session, "%c", '\\'); + if (ret) + goto error; + /* We still print the current char */ + /* Fallthrough */ + default: + ret = lttng_metadata_printf(session, "%c", cur); + break; + } + + if (ret) + goto error; + + cur = string[++i]; + } +error: + return ret; +} + +static +int print_metadata_escaped_field(struct lttng_session *session, const char *field, + const char *field_value) +{ + int ret; + + ret = lttng_metadata_printf(session, " %s = \"", field); + if (ret) + goto error; + + ret = print_escaped_ctf_string(session, field_value); + if (ret) + goto error; + + ret = lttng_metadata_printf(session, "\";\n"); + +error: + return ret; +} + /* * Output metadata into this session's metadata buffers. * Must be called with sessions_mutex held. @@ -2443,6 +2571,9 @@ int _lttng_session_metadata_statedump(struct lttng_session *session) if (!READ_ONCE(session->active)) return 0; + + lttng_metadata_begin(session); + if (session->metadata_dumped) goto skip_session; @@ -2503,7 +2634,7 @@ int _lttng_session_metadata_statedump(struct lttng_session *session) " tracer_major = %d;\n" " tracer_minor = %d;\n" " tracer_patchlevel = %d;\n" - "};\n\n", + " trace_buffering_scheme = \"global\";\n", current->nsproxy->uts_ns->name.nodename, utsname()->sysname, utsname()->release, @@ -2515,6 +2646,19 @@ int _lttng_session_metadata_statedump(struct lttng_session *session) if (ret) goto end; + ret = print_metadata_escaped_field(session, "trace_name", session->name); + if (ret) + goto end; + ret = print_metadata_escaped_field(session, "trace_creation_datetime", + session->creation_time); + if (ret) + goto end; + + /* Close env */ + ret = lttng_metadata_printf(session, "};\n\n"); + if (ret) + goto end; + ret = lttng_metadata_printf(session, "clock {\n" " name = \"%s\";\n", @@ -2591,6 +2735,7 @@ skip_session: } session->metadata_dumped = 1; end: + lttng_metadata_end(session); return ret; } @@ -2601,9 +2746,9 @@ end: * Registers a transport which can be used as output to extract the data out of * LTTng. The module calling this registration function must ensure that no * trap-inducing code will be executed by the transport functions. E.g. - * vmalloc_sync_all() must be called between a vmalloc and the moment the memory + * vmalloc_sync_mappings() must be called between a vmalloc and the moment the memory * is made visible to the transport function. This registration acts as a - * vmalloc_sync_all. Therefore, only if the module allocates virtual memory + * vmalloc_sync_mappings. Therefore, only if the module allocates virtual memory * after its registration must it synchronize the TLBs. */ void lttng_transport_register(struct lttng_transport *transport) @@ -2611,9 +2756,9 @@ void lttng_transport_register(struct lttng_transport *transport) /* * Make sure no page fault can be triggered by the module about to be * registered. We deal with this here so we don't have to call - * vmalloc_sync_all() in each module's init. + * vmalloc_sync_mappings() in each module's init. */ - wrapper_vmalloc_sync_all(); + wrapper_vmalloc_sync_mappings(); mutex_lock(&sessions_mutex); list_add_tail(&transport->node, <tng_transport_list);