X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=lttng-events.c;h=481abeb320dff552f966c0b85701ca7305c819e6;hb=bf5a011d7256c26f8731be6b9983462f02b7c0cb;hp=a3030533d1e62d1c01f4cc8b0db9fed4cffa7425;hpb=a344f64bd188272ee3d0a6055aaa6a3eabd0669d;p=lttng-modules.git diff --git a/lttng-events.c b/lttng-events.c index a3030533..481abeb3 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); @@ -394,7 +401,6 @@ 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); @@ -402,6 +408,7 @@ int lttng_event_enable(struct lttng_event *event) 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; @@ -430,7 +437,6 @@ 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); @@ -438,6 +444,7 @@ int lttng_event_disable(struct lttng_event *event) 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; @@ -580,11 +587,11 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, 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; @@ -707,27 +714,6 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, list_add(&event_return->list, &chan->session->events); break; } - case LTTNG_KERNEL_FUNCTION: - /* - * 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, - event); - 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: /* @@ -749,6 +735,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, */ event->enabled = 0; event->registered = 1; + /* * Populate lttng_event structure before event * registration. @@ -756,14 +743,14 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, smp_wmb(); ret = lttng_uprobes_register(event_param->name, - event_param->u.uprobe.path, - event_param->u.uprobe.offset, + event_param->u.uprobe.fd, event); if (ret) goto register_error; ret = try_module_get(event->desc->owner); WARN_ON_ONCE(!ret); break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -828,10 +815,10 @@ void register_event(struct lttng_event *event) 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); } @@ -865,10 +852,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); @@ -880,6 +863,7 @@ int _lttng_event_unregister(struct lttng_event *event) lttng_uprobes_unregister(event); ret = 0; break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ default: WARN_ON_ONCE(1); } @@ -906,10 +890,6 @@ 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; @@ -917,6 +897,7 @@ void _lttng_event_destroy(struct lttng_event *event) module_put(event->desc->owner); lttng_uprobes_destroy_private(event); break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ default: WARN_ON_ONCE(1); } @@ -1136,8 +1117,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); @@ -1466,6 +1447,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) { @@ -1595,7 +1588,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; @@ -1634,6 +1627,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, @@ -1641,18 +1635,43 @@ 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->metadata_cache->producing != 0) + 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) +{ + mutex_lock(&session->metadata_cache->lock); + session->metadata_cache->producing++; + mutex_unlock(&session->metadata_cache->lock); +} + +static +void lttng_metadata_end(struct lttng_session *session) +{ + mutex_lock(&session->metadata_cache->lock); + WARN_ON_ONCE(!session->metadata_cache->producing); + session->metadata_cache->producing--; + 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, ...) @@ -1672,6 +1691,7 @@ int lttng_metadata_printf(struct lttng_session *session, len = strlen(str); mutex_lock(&session->metadata_cache->lock); + session->metadata_cache->producing++; if (session->metadata_cache->metadata_written + len > session->metadata_cache->cache_alloc) { char *tmp_cache_realloc; @@ -1697,6 +1717,7 @@ int lttng_metadata_printf(struct lttng_session *session, session->metadata_cache->metadata_written, str, len); session->metadata_cache->metadata_written += len; + session->metadata_cache->producing--; mutex_unlock(&session->metadata_cache->lock); kfree(str); @@ -1706,6 +1727,7 @@ int lttng_metadata_printf(struct lttng_session *session, return 0; err: + session->metadata_cache->producing--; mutex_unlock(&session->metadata_cache->lock); kfree(str); return -ENOMEM; @@ -2243,6 +2265,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, @@ -2256,6 +2280,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" @@ -2305,12 +2331,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, @@ -2324,6 +2353,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" @@ -2357,6 +2388,7 @@ int _lttng_channel_metadata_statedump(struct lttng_session *session, chan->metadata_dumped = 1; end: + lttng_metadata_end(session); return ret; } @@ -2431,6 +2463,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) @@ -2438,13 +2473,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); @@ -2462,6 +2505,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. @@ -2477,6 +2575,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; @@ -2537,7 +2638,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, @@ -2549,6 +2650,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", @@ -2625,6 +2739,7 @@ skip_session: } session->metadata_dumped = 1; end: + lttng_metadata_end(session); return ret; } @@ -2635,9 +2750,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) @@ -2645,9 +2760,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);