X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Flttng-events.c;h=57ff55b71e45e80c32b8c54547b584a8d47a4899;hb=d96a4a7a78319be3386b57d9068817e9ffac2a24;hp=d1a0706e0b9793b525e5c66212ac23b9e85d0614;hpb=60206944ca1ab9c7b2c8519324e07e1a76a8f936;p=lttng-modules.git diff --git a/src/lttng-events.c b/src/lttng-events.c index d1a0706e..57ff55b7 100644 --- a/src/lttng-events.c +++ b/src/lttng-events.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,7 @@ static LIST_HEAD(sessions); static LIST_HEAD(event_notifier_groups); static LIST_HEAD(lttng_transport_list); +static LIST_HEAD(lttng_counter_transport_list); /* * Protect the sessions and metadata caches. */ @@ -89,21 +91,21 @@ int _lttng_field_statedump(struct lttng_session *session, void synchronize_trace(void) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,1,0)) +#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,1,0)) synchronize_rcu(); #else synchronize_sched(); #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) +#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(3,4,0)) #ifdef CONFIG_PREEMPT_RT_FULL synchronize_rcu(); #endif -#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) */ +#else /* (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(3,4,0)) */ #ifdef CONFIG_PREEMPT_RT synchronize_rcu(); #endif -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) */ +#endif /* (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(3,4,0)) */ } void lttng_lock_sessions(void) @@ -197,6 +199,61 @@ err: return NULL; } +static +struct lttng_counter_transport *lttng_counter_transport_find(const char *name) +{ + struct lttng_counter_transport *transport; + + list_for_each_entry(transport, <tng_counter_transport_list, node) { + if (!strcmp(transport->name, name)) + return transport; + } + return NULL; +} + +struct lttng_counter *lttng_kernel_counter_create( + const char *counter_transport_name, + size_t number_dimensions, const size_t *dimensions_sizes) +{ + struct lttng_counter *counter = NULL; + struct lttng_counter_transport *counter_transport = NULL; + + counter_transport = lttng_counter_transport_find(counter_transport_name); + if (!counter_transport) { + printk(KERN_WARNING "LTTng: counter transport %s not found.\n", + counter_transport_name); + goto notransport; + } + if (!try_module_get(counter_transport->owner)) { + printk(KERN_WARNING "LTTng: Can't lock counter transport module.\n"); + goto notransport; + } + + counter = lttng_kvzalloc(sizeof(struct lttng_counter), GFP_KERNEL); + if (!counter) + goto nomem; + + /* Create event notifier error counter. */ + counter->ops = &counter_transport->ops; + counter->transport = counter_transport; + + counter->counter = counter->ops->counter_create( + number_dimensions, dimensions_sizes, 0); + if (!counter->counter) { + goto create_error; + } + + return counter; + +create_error: + lttng_kvfree(counter); +nomem: + if (counter_transport) + module_put(counter_transport->owner); +notransport: + return NULL; +} + struct lttng_event_notifier_group *lttng_event_notifier_group_create(void) { struct lttng_transport *transport = NULL; @@ -281,7 +338,7 @@ void lttng_session_destroy(struct lttng_session *session) mutex_lock(&sessions_mutex); WRITE_ONCE(session->active, 0); list_for_each_entry(chan, &session->chan, list) { - ret = lttng_syscalls_unregister_event(chan); + ret = lttng_syscalls_unregister_channel(chan); WARN_ON(ret); } list_for_each_entry(event, &session->events, list) { @@ -330,7 +387,7 @@ void lttng_event_notifier_group_destroy( mutex_lock(&sessions_mutex); - ret = lttng_syscalls_unregister_event_notifier(event_notifier_group); + ret = lttng_syscalls_unregister_event_notifier_group(event_notifier_group); WARN_ON(ret); list_for_each_entry_safe(event_notifier, tmpevent_notifier, @@ -354,6 +411,15 @@ void lttng_event_notifier_group_destroy( &event_notifier_group->event_notifiers_head, list) _lttng_event_notifier_destroy(event_notifier); + if (event_notifier_group->error_counter) { + struct lttng_counter *error_counter = event_notifier_group->error_counter; + + error_counter->ops->counter_destroy(error_counter->counter); + module_put(error_counter->transport->owner); + lttng_kvfree(error_counter); + event_notifier_group->error_counter = NULL; + } + event_notifier_group->ops->channel_destroy(event_notifier_group->chan); module_put(event_notifier_group->transport->owner); list_del(&event_notifier_group->node); @@ -549,19 +615,22 @@ int lttng_event_enable(struct lttng_event *event) goto end; } switch (event->instrumentation) { - case LTTNG_KERNEL_TRACEPOINT: + case LTTNG_KERNEL_TRACEPOINT: /* Fall-through */ case LTTNG_KERNEL_SYSCALL: ret = -EINVAL; break; - case LTTNG_KERNEL_KPROBE: + + case LTTNG_KERNEL_KPROBE: /* Fall-through */ 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. */ + + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -585,19 +654,23 @@ int lttng_event_disable(struct lttng_event *event) goto end; } switch (event->instrumentation) { - case LTTNG_KERNEL_TRACEPOINT: + case LTTNG_KERNEL_TRACEPOINT: /* Fall-through */ case LTTNG_KERNEL_SYSCALL: ret = -EINVAL; break; - case LTTNG_KERNEL_KPROBE: + + case LTTNG_KERNEL_KPROBE: /* Fall-through */ 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. */ + + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -617,17 +690,19 @@ int lttng_event_notifier_enable(struct lttng_event_notifier *event_notifier) goto end; } switch (event_notifier->instrumentation) { - case LTTNG_KERNEL_TRACEPOINT: + case LTTNG_KERNEL_TRACEPOINT: /* Fall-through */ case LTTNG_KERNEL_SYSCALL: ret = -EINVAL; break; - case LTTNG_KERNEL_KPROBE: + + case LTTNG_KERNEL_KPROBE: /* Fall-through */ case LTTNG_KERNEL_UPROBE: WRITE_ONCE(event_notifier->enabled, 1); break; - case LTTNG_KERNEL_FUNCTION: - case LTTNG_KERNEL_NOOP: - case LTTNG_KERNEL_KRETPROBE: + + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_KRETPROBE: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -647,17 +722,19 @@ int lttng_event_notifier_disable(struct lttng_event_notifier *event_notifier) goto end; } switch (event_notifier->instrumentation) { - case LTTNG_KERNEL_TRACEPOINT: + case LTTNG_KERNEL_TRACEPOINT: /* Fall-through */ case LTTNG_KERNEL_SYSCALL: ret = -EINVAL; break; - case LTTNG_KERNEL_KPROBE: + + case LTTNG_KERNEL_KPROBE: /* Fall-through */ case LTTNG_KERNEL_UPROBE: WRITE_ONCE(event_notifier->enabled, 0); break; - case LTTNG_KERNEL_FUNCTION: - case LTTNG_KERNEL_NOOP: - case LTTNG_KERNEL_KRETPROBE: + + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_KRETPROBE: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -759,6 +836,7 @@ void _lttng_metadata_channel_hangup(struct lttng_metadata_stream *stream) wake_up_interruptible(&stream->read_wait); } + /* * Supports event creation while tracing session is active. * Needs to be called with sessions mutex held. @@ -784,14 +862,16 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, case LTTNG_KERNEL_TRACEPOINT: event_name = event_desc->name; break; - case LTTNG_KERNEL_KPROBE: - case LTTNG_KERNEL_UPROBE: - case LTTNG_KERNEL_KRETPROBE: - case LTTNG_KERNEL_NOOP: + + case LTTNG_KERNEL_KPROBE: /* Fall-through */ + case LTTNG_KERNEL_UPROBE: /* Fall-through */ + case LTTNG_KERNEL_KRETPROBE: /* Fall-through */ case LTTNG_KERNEL_SYSCALL: event_name = event_param->name; break; - case LTTNG_KERNEL_FUNCTION: /* Fall-through. */ + + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -836,6 +916,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, /* Populate lttng_event structure before event registration. */ smp_wmb(); break; + case LTTNG_KERNEL_KPROBE: /* * Needs to be explicitly enabled after creation, since @@ -860,6 +941,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, ret = try_module_get(event->desc->owner); WARN_ON_ONCE(!ret); break; + case LTTNG_KERNEL_KRETPROBE: { struct lttng_event *event_return; @@ -883,6 +965,8 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, event_return->enabled = 0; event_return->registered = 1; event_return->instrumentation = itype; + INIT_LIST_HEAD(&event_return->filter_bytecode_runtime_head); + INIT_LIST_HEAD(&event_return->enablers_ref_head); /* * Populate lttng_event structure before kretprobe registration. */ @@ -914,7 +998,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, list_add(&event_return->list, &chan->session->events); break; } - case LTTNG_KERNEL_NOOP: + case LTTNG_KERNEL_SYSCALL: /* * Needs to be explicitly enabled after creation, since @@ -950,6 +1034,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, goto register_error; } break; + case LTTNG_KERNEL_UPROBE: /* * Needs to be explicitly enabled after creation, since @@ -972,7 +1057,9 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan, ret = try_module_get(event->desc->owner); WARN_ON_ONCE(!ret); break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -1000,11 +1087,13 @@ full: struct lttng_event_notifier *_lttng_event_notifier_create( const struct lttng_event_desc *event_desc, - uint64_t token, struct lttng_event_notifier_group *event_notifier_group, + uint64_t token, uint64_t error_counter_index, + struct lttng_event_notifier_group *event_notifier_group, struct lttng_kernel_event_notifier *event_notifier_param, void *filter, enum lttng_kernel_instrumentation itype) { struct lttng_event_notifier *event_notifier; + struct lttng_counter *error_counter; const char *event_name; struct hlist_head *head; int ret; @@ -1013,14 +1102,16 @@ struct lttng_event_notifier *_lttng_event_notifier_create( case LTTNG_KERNEL_TRACEPOINT: event_name = event_desc->name; break; - case LTTNG_KERNEL_KPROBE: - case LTTNG_KERNEL_UPROBE: + + case LTTNG_KERNEL_KPROBE: /* Fall-through */ + case LTTNG_KERNEL_UPROBE: /* Fall-through */ case LTTNG_KERNEL_SYSCALL: event_name = event_notifier_param->event.name; break; - case LTTNG_KERNEL_KRETPROBE: - case LTTNG_KERNEL_FUNCTION: - case LTTNG_KERNEL_NOOP: + + case LTTNG_KERNEL_KRETPROBE: /* Fall-through */ + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -1048,11 +1139,14 @@ struct lttng_event_notifier *_lttng_event_notifier_create( event_notifier->group = event_notifier_group; event_notifier->user_token = token; + event_notifier->error_counter_index = error_counter_index; + event_notifier->num_captures = 0; event_notifier->filter = filter; event_notifier->instrumentation = itype; event_notifier->evtype = LTTNG_TYPE_EVENT; event_notifier->send_notification = lttng_event_notifier_notification_send; INIT_LIST_HEAD(&event_notifier->filter_bytecode_runtime_head); + INIT_LIST_HEAD(&event_notifier->capture_bytecode_runtime_head); INIT_LIST_HEAD(&event_notifier->enablers_ref_head); switch (itype) { @@ -1068,6 +1162,7 @@ struct lttng_event_notifier *_lttng_event_notifier_create( /* Populate lttng_event_notifier structure before event registration. */ smp_wmb(); break; + case LTTNG_KERNEL_KPROBE: /* * Needs to be explicitly enabled after creation, since @@ -1092,7 +1187,7 @@ struct lttng_event_notifier *_lttng_event_notifier_create( ret = try_module_get(event_notifier->desc->owner); WARN_ON_ONCE(!ret); break; - case LTTNG_KERNEL_NOOP: + case LTTNG_KERNEL_SYSCALL: /* * Needs to be explicitly enabled after creation, since @@ -1129,6 +1224,7 @@ struct lttng_event_notifier *_lttng_event_notifier_create( goto register_error; } break; + case LTTNG_KERNEL_UPROBE: /* * Needs to be explicitly enabled after creation, since @@ -1152,8 +1248,10 @@ struct lttng_event_notifier *_lttng_event_notifier_create( ret = try_module_get(event_notifier->desc->owner); WARN_ON_ONCE(!ret); break; - case LTTNG_KERNEL_KRETPROBE: - case LTTNG_KERNEL_FUNCTION: + + case LTTNG_KERNEL_KRETPROBE: /* Fall-through */ + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -1162,6 +1260,36 @@ struct lttng_event_notifier *_lttng_event_notifier_create( list_add(&event_notifier->list, &event_notifier_group->event_notifiers_head); hlist_add_head(&event_notifier->hlist, head); + + /* + * Clear the error counter bucket. The sessiond keeps track of which + * bucket is currently in use. We trust it. The session lock + * synchronizes against concurrent creation of the error + * counter. + */ + error_counter = event_notifier_group->error_counter; + if (error_counter) { + size_t dimension_index[1]; + + /* + * Check that the index is within the boundary of the counter. + */ + if (event_notifier->error_counter_index >= event_notifier_group->error_counter_len) { + printk(KERN_INFO "LTTng: event_notifier: Error counter index out-of-bound: counter-len=%zu, index=%llu\n", + event_notifier_group->error_counter_len, event_notifier->error_counter_index); + ret = -EINVAL; + goto register_error; + } + + dimension_index[0] = event_notifier->error_counter_index; + ret = error_counter->ops->counter_clear(error_counter->counter, dimension_index); + if (ret) { + printk(KERN_INFO "LTTng: event_notifier: Unable to clear error counter bucket %llu\n", + event_notifier->error_counter_index); + goto register_error; + } + } + return event_notifier; register_error: @@ -1172,6 +1300,28 @@ type_error: return ERR_PTR(ret); } +int lttng_kernel_counter_read(struct lttng_counter *counter, + const size_t *dim_indexes, int32_t cpu, + int64_t *val, bool *overflow, bool *underflow) +{ + return counter->ops->counter_read(counter->counter, dim_indexes, + cpu, val, overflow, underflow); +} + +int lttng_kernel_counter_aggregate(struct lttng_counter *counter, + const size_t *dim_indexes, int64_t *val, + bool *overflow, bool *underflow) +{ + return counter->ops->counter_aggregate(counter->counter, dim_indexes, + val, overflow, underflow); +} + +int lttng_kernel_counter_clear(struct lttng_counter *counter, + const size_t *dim_indexes) +{ + return counter->ops->counter_clear(counter->counter, dim_indexes); +} + struct lttng_event *lttng_event_create(struct lttng_channel *chan, struct lttng_kernel_event *event_param, void *filter, @@ -1189,7 +1339,8 @@ struct lttng_event *lttng_event_create(struct lttng_channel *chan, struct lttng_event_notifier *lttng_event_notifier_create( const struct lttng_event_desc *event_desc, - uint64_t id, struct lttng_event_notifier_group *event_notifier_group, + uint64_t id, uint64_t error_counter_index, + struct lttng_event_notifier_group *event_notifier_group, struct lttng_kernel_event_notifier *event_notifier_param, void *filter, enum lttng_kernel_instrumentation itype) { @@ -1197,7 +1348,8 @@ struct lttng_event_notifier *lttng_event_notifier_create( mutex_lock(&sessions_mutex); event_notifier = _lttng_event_notifier_create(event_desc, id, - event_notifier_group, event_notifier_param, filter, itype); + error_counter_index, event_notifier_group, + event_notifier_param, filter, itype); mutex_unlock(&sessions_mutex); return event_notifier; } @@ -1219,16 +1371,19 @@ void register_event(struct lttng_event *event) desc->probe_callback, event); break; + case LTTNG_KERNEL_SYSCALL: ret = lttng_syscall_filter_enable_event(event->chan, event); break; - case LTTNG_KERNEL_KPROBE: - case LTTNG_KERNEL_UPROBE: + + case LTTNG_KERNEL_KPROBE: /* Fall-through */ + case LTTNG_KERNEL_UPROBE: /* Fall-through */ case LTTNG_KERNEL_KRETPROBE: - case LTTNG_KERNEL_NOOP: ret = 0; break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); } @@ -1254,24 +1409,30 @@ int _lttng_event_unregister(struct lttng_event *event) event->desc->probe_callback, event); break; + case LTTNG_KERNEL_KPROBE: lttng_kprobes_unregister_event(event); ret = 0; break; + case LTTNG_KERNEL_KRETPROBE: lttng_kretprobes_unregister(event); ret = 0; break; + case LTTNG_KERNEL_SYSCALL: ret = lttng_syscall_filter_disable_event(event->chan, event); break; + case LTTNG_KERNEL_NOOP: ret = 0; break; + case LTTNG_KERNEL_UPROBE: lttng_uprobes_unregister_event(event); ret = 0; break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ default: WARN_ON_ONCE(1); @@ -1298,16 +1459,19 @@ void register_event_notifier(struct lttng_event_notifier *event_notifier) desc->event_notifier_callback, event_notifier); break; + case LTTNG_KERNEL_SYSCALL: ret = lttng_syscall_filter_enable_event_notifier(event_notifier); break; - case LTTNG_KERNEL_KPROBE: + + case LTTNG_KERNEL_KPROBE: /* Fall-through */ case LTTNG_KERNEL_UPROBE: ret = 0; break; - case LTTNG_KERNEL_KRETPROBE: - case LTTNG_KERNEL_FUNCTION: - case LTTNG_KERNEL_NOOP: + + case LTTNG_KERNEL_KRETPROBE: /* Fall-through */ + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); } @@ -1332,20 +1496,24 @@ int _lttng_event_notifier_unregister( event_notifier->desc->event_notifier_callback, event_notifier); break; + case LTTNG_KERNEL_KPROBE: lttng_kprobes_unregister_event_notifier(event_notifier); ret = 0; break; + case LTTNG_KERNEL_UPROBE: lttng_uprobes_unregister_event_notifier(event_notifier); ret = 0; break; + case LTTNG_KERNEL_SYSCALL: ret = lttng_syscall_filter_disable_event_notifier(event_notifier); break; - case LTTNG_KERNEL_KRETPROBE: - case LTTNG_KERNEL_FUNCTION: - case LTTNG_KERNEL_NOOP: + + case LTTNG_KERNEL_KRETPROBE: /* Fall-through */ + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); } @@ -1360,31 +1528,43 @@ int _lttng_event_notifier_unregister( static void _lttng_event_destroy(struct lttng_event *event) { + struct lttng_enabler_ref *enabler_ref, *tmp_enabler_ref; + switch (event->instrumentation) { case LTTNG_KERNEL_TRACEPOINT: lttng_event_desc_put(event->desc); break; + case LTTNG_KERNEL_KPROBE: module_put(event->desc->owner); lttng_kprobes_destroy_event_private(event); break; + case LTTNG_KERNEL_KRETPROBE: module_put(event->desc->owner); lttng_kretprobes_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_event_private(event); break; + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); } list_del(&event->list); lttng_destroy_context(event->ctx); + lttng_free_event_filter_runtime(event); + /* Free event enabler refs */ + list_for_each_entry_safe(enabler_ref, tmp_enabler_ref, + &event->enablers_ref_head, node) + kfree(enabler_ref); kmem_cache_free(event_cache, event); } @@ -1394,27 +1574,38 @@ void _lttng_event_destroy(struct lttng_event *event) static void _lttng_event_notifier_destroy(struct lttng_event_notifier *event_notifier) { + struct lttng_enabler_ref *enabler_ref, *tmp_enabler_ref; + switch (event_notifier->instrumentation) { case LTTNG_KERNEL_TRACEPOINT: lttng_event_desc_put(event_notifier->desc); break; + case LTTNG_KERNEL_KPROBE: module_put(event_notifier->desc->owner); lttng_kprobes_destroy_event_notifier_private(event_notifier); break; - case LTTNG_KERNEL_NOOP: + case LTTNG_KERNEL_SYSCALL: break; + case LTTNG_KERNEL_UPROBE: module_put(event_notifier->desc->owner); lttng_uprobes_destroy_event_notifier_private(event_notifier); break; - case LTTNG_KERNEL_KRETPROBE: - case LTTNG_KERNEL_FUNCTION: + + case LTTNG_KERNEL_KRETPROBE: /* Fall-through */ + case LTTNG_KERNEL_FUNCTION: /* Fall-through */ + case LTTNG_KERNEL_NOOP: /* Fall-through */ default: WARN_ON_ONCE(1); } list_del(&event_notifier->list); + lttng_free_event_notifier_filter_runtime(event_notifier); + /* Free event enabler refs */ + list_for_each_entry_safe(enabler_ref, tmp_enabler_ref, + &event_notifier->enablers_ref_head, node) + kfree(enabler_ref); kmem_cache_free(event_notifier_cache, event_notifier); } @@ -1712,6 +1903,7 @@ int lttng_desc_match_enabler(const struct lttng_event_desc *desc, return -EINVAL; } break; + case LTTNG_KERNEL_SYSCALL: desc_name = desc->name; if (!strncmp(desc_name, "compat_", strlen("compat_"))) { @@ -1774,6 +1966,7 @@ int lttng_desc_match_enabler(const struct lttng_event_desc *desc, return -EINVAL; } break; + default: WARN_ON_ONCE(1); return -EINVAL; @@ -1927,6 +2120,7 @@ void lttng_create_tracepoint_event_notifier_if_missing(struct lttng_event_notifi */ event_notifier = _lttng_event_notifier_create(desc, event_notifier_enabler->base.user_token, + event_notifier_enabler->error_counter_index, event_notifier_group, NULL, NULL, LTTNG_KERNEL_TRACEPOINT); if (IS_ERR(event_notifier)) { @@ -1942,7 +2136,7 @@ void lttng_create_syscall_event_if_missing(struct lttng_event_enabler *event_ena { int ret; - ret = lttng_syscalls_register_event(event_enabler->chan, NULL); + ret = lttng_syscalls_register_event(event_enabler, NULL); WARN_ON_ONCE(ret); } @@ -1969,9 +2163,11 @@ void lttng_create_event_if_missing(struct lttng_event_enabler *event_enabler) case LTTNG_KERNEL_TRACEPOINT: lttng_create_tracepoint_event_if_missing(event_enabler); break; + case LTTNG_KERNEL_SYSCALL: lttng_create_syscall_event_if_missing(event_enabler); break; + default: WARN_ON_ONCE(1); break; @@ -1992,14 +2188,17 @@ int lttng_event_enabler_ref_events(struct lttng_event_enabler *event_enabler) struct lttng_event *event; if (base_enabler->event_param.instrumentation == LTTNG_KERNEL_SYSCALL && - base_enabler->event_param.u.syscall.entryexit == LTTNG_KERNEL_SYSCALL_ENTRYEXIT && base_enabler->event_param.u.syscall.abi == LTTNG_KERNEL_SYSCALL_ABI_ALL && base_enabler->event_param.u.syscall.match == LTTNG_KERNEL_SYSCALL_MATCH_NAME && !strcmp(base_enabler->event_param.name, "*")) { - if (base_enabler->enabled) - WRITE_ONCE(chan->syscall_all, 1); - else - WRITE_ONCE(chan->syscall_all, 0); + int enabled = base_enabler->enabled; + enum lttng_kernel_syscall_entryexit entryexit = base_enabler->event_param.u.syscall.entryexit; + + if (entryexit == LTTNG_KERNEL_SYSCALL_ENTRY || entryexit == LTTNG_KERNEL_SYSCALL_ENTRYEXIT) + WRITE_ONCE(chan->syscall_all_entry, enabled); + + if (entryexit == LTTNG_KERNEL_SYSCALL_EXIT || entryexit == LTTNG_KERNEL_SYSCALL_ENTRYEXIT) + WRITE_ONCE(chan->syscall_all_exit, enabled); } /* First ensure that probe events are created for this enabler. */ @@ -2051,9 +2250,11 @@ void lttng_create_event_notifier_if_missing(struct lttng_event_notifier_enabler case LTTNG_KERNEL_TRACEPOINT: lttng_create_tracepoint_event_notifier_if_missing(event_notifier_enabler); break; + case LTTNG_KERNEL_SYSCALL: lttng_create_syscall_event_notifier_if_missing(event_notifier_enabler); break; + default: WARN_ON_ONCE(1); break; @@ -2120,6 +2321,13 @@ int lttng_event_notifier_enabler_ref_event_notifiers( lttng_enabler_link_bytecode(event_notifier->desc, lttng_static_ctx, &event_notifier->filter_bytecode_runtime_head, <tng_event_notifier_enabler_as_enabler(event_notifier_enabler)->filter_bytecode_head); + + /* Link capture bytecodes if not linked yet. */ + lttng_enabler_link_bytecode(event_notifier->desc, + lttng_static_ctx, &event_notifier->capture_bytecode_runtime_head, + &event_notifier_enabler->capture_bytecode_head); + + event_notifier->num_captures = event_notifier_enabler->num_captures; } return 0; } @@ -2225,7 +2433,7 @@ int lttng_enabler_attach_filter_bytecode(struct lttng_enabler *enabler, ret = get_user(bytecode_len, &bytecode->len); if (ret) return ret; - bytecode_node = kzalloc(sizeof(*bytecode_node) + bytecode_len, + bytecode_node = lttng_kvzalloc(sizeof(*bytecode_node) + bytecode_len, GFP_KERNEL); if (!bytecode_node) return -ENOMEM; @@ -2243,7 +2451,7 @@ int lttng_enabler_attach_filter_bytecode(struct lttng_enabler *enabler, return 0; error_free: - kfree(bytecode_node); + lttng_kvfree(bytecode_node); return ret; } @@ -2289,7 +2497,7 @@ void lttng_enabler_destroy(struct lttng_enabler *enabler) /* Destroy filter bytecode */ list_for_each_entry_safe(filter_node, tmp_filter_node, &enabler->filter_bytecode_head, node) { - kfree(filter_node); + lttng_kvfree(filter_node); } } @@ -2318,6 +2526,10 @@ struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create( event_notifier_enabler->base.format_type = format_type; INIT_LIST_HEAD(&event_notifier_enabler->base.filter_bytecode_head); + INIT_LIST_HEAD(&event_notifier_enabler->capture_bytecode_head); + + event_notifier_enabler->error_counter_index = event_notifier_param->error_counter_index; + event_notifier_enabler->num_captures = 0; memcpy(&event_notifier_enabler->base.event_param, &event_notifier_param->event, sizeof(event_notifier_enabler->base.event_param)); @@ -2375,6 +2587,48 @@ error: return ret; } +int lttng_event_notifier_enabler_attach_capture_bytecode( + struct lttng_event_notifier_enabler *event_notifier_enabler, + struct lttng_kernel_capture_bytecode __user *bytecode) +{ + struct lttng_bytecode_node *bytecode_node; + struct lttng_enabler *enabler = + lttng_event_notifier_enabler_as_enabler(event_notifier_enabler); + uint32_t bytecode_len; + int ret; + + ret = get_user(bytecode_len, &bytecode->len); + if (ret) + return ret; + + bytecode_node = lttng_kvzalloc(sizeof(*bytecode_node) + bytecode_len, + GFP_KERNEL); + if (!bytecode_node) + return -ENOMEM; + + ret = copy_from_user(&bytecode_node->bc, bytecode, + sizeof(*bytecode) + bytecode_len); + if (ret) + goto error_free; + + bytecode_node->type = LTTNG_BYTECODE_NODE_TYPE_CAPTURE; + bytecode_node->enabler = enabler; + + /* Enforce length based on allocated size */ + bytecode_node->bc.len = bytecode_len; + list_add_tail(&bytecode_node->node, &event_notifier_enabler->capture_bytecode_head); + + event_notifier_enabler->num_captures++; + + lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group); + goto end; + +error_free: + lttng_kvfree(bytecode_node); +end: + return ret; +} + int lttng_event_notifier_add_callsite(struct lttng_event_notifier *event_notifier, struct lttng_kernel_event_callsite __user *callsite) { @@ -2433,7 +2687,7 @@ void lttng_session_sync_event_enablers(struct lttng_session *session) int enabled = 0, has_enablers_without_bytecode = 0; switch (event->instrumentation) { - case LTTNG_KERNEL_TRACEPOINT: + case LTTNG_KERNEL_TRACEPOINT: /* Fall-through */ case LTTNG_KERNEL_SYSCALL: /* Enable events */ list_for_each_entry(enabler_ref, @@ -2444,6 +2698,7 @@ void lttng_session_sync_event_enablers(struct lttng_session *session) } } break; + default: /* Not handled with lazy sync. */ continue; @@ -2520,7 +2775,7 @@ void lttng_event_notifier_group_sync_enablers(struct lttng_event_notifier_group int enabled = 0, has_enablers_without_bytecode = 0; switch (event_notifier->instrumentation) { - case LTTNG_KERNEL_TRACEPOINT: + case LTTNG_KERNEL_TRACEPOINT: /* Fall-through */ case LTTNG_KERNEL_SYSCALL: /* Enable event_notifiers */ list_for_each_entry(enabler_ref, @@ -2531,6 +2786,7 @@ void lttng_event_notifier_group_sync_enablers(struct lttng_event_notifier_group } } break; + default: /* Not handled with sync. */ continue; @@ -2565,6 +2821,13 @@ void lttng_event_notifier_group_sync_enablers(struct lttng_event_notifier_group list_for_each_entry(runtime, &event_notifier->filter_bytecode_runtime_head, node) lttng_bytecode_filter_sync_state(runtime); + + /* Enable captures */ + list_for_each_entry(runtime, + &event_notifier->capture_bytecode_runtime_head, node) + lttng_bytecode_capture_sync_state(runtime); + + WRITE_ONCE(event_notifier->eval_capture, !!event_notifier->num_captures); } } @@ -2751,7 +3014,7 @@ int _lttng_integer_type_statedump(struct lttng_session *session, { int ret; - WARN_ON_ONCE(type->atype != atype_integer); + WARN_ON_ONCE(type->type != lttng_kernel_type_integer); ret = print_tabs(session, nesting); if (ret) return ret; @@ -2760,9 +3023,9 @@ int _lttng_integer_type_statedump(struct lttng_session *session, type->u.integer.size, type->u.integer.alignment, type->u.integer.signedness, - (type->u.integer.encoding == lttng_encode_none) + (type->u.integer.encoding == lttng_kernel_string_encoding_none) ? "none" - : (type->u.integer.encoding == lttng_encode_UTF8) + : (type->u.integer.encoding == lttng_kernel_string_encoding_UTF8) ? "UTF8" : "ASCII", type->u.integer.base, @@ -2787,7 +3050,7 @@ int _lttng_struct_type_statedump(struct lttng_session *session, uint32_t i, nr_fields; unsigned int alignment; - WARN_ON_ONCE(type->atype != atype_struct_nestable); + WARN_ON_ONCE(type->type != lttng_kernel_type_struct_nestable); ret = print_tabs(session, nesting); if (ret) @@ -2848,7 +3111,7 @@ int _lttng_variant_type_statedump(struct lttng_session *session, int ret; uint32_t i, nr_choices; - WARN_ON_ONCE(type->atype != atype_variant_nestable); + WARN_ON_ONCE(type->type != lttng_kernel_type_variant_nestable); /* * CTF 1.8 does not allow expressing nonzero variant alignment in a nestable way. */ @@ -2907,7 +3170,7 @@ int _lttng_array_field_statedump(struct lttng_session *session, int ret; const struct lttng_type *elem_type; - WARN_ON_ONCE(field->type.atype != atype_array_nestable); + WARN_ON_ONCE(field->type.type != lttng_kernel_type_array_nestable); if (field->type.u.array_nestable.alignment) { ret = print_tabs(session, nesting); @@ -2925,10 +3188,10 @@ int _lttng_array_field_statedump(struct lttng_session *session, * currently supported. */ elem_type = field->type.u.array_nestable.elem_type; - switch (elem_type->atype) { - case atype_integer: - case atype_struct_nestable: - case atype_variant_nestable: + switch (elem_type->type) { + case lttng_kernel_type_integer: + case lttng_kernel_type_struct_nestable: + case lttng_kernel_type_variant_nestable: ret = _lttng_type_statedump(session, elem_type, nesting); if (ret) return ret; @@ -2956,7 +3219,7 @@ int _lttng_sequence_field_statedump(struct lttng_session *session, const char *length_name; const struct lttng_type *elem_type; - WARN_ON_ONCE(field->type.atype != atype_sequence_nestable); + WARN_ON_ONCE(field->type.type != lttng_kernel_type_sequence_nestable); length_name = field->type.u.sequence_nestable.length_name; @@ -2977,10 +3240,10 @@ int _lttng_sequence_field_statedump(struct lttng_session *session, * currently supported. */ elem_type = field->type.u.sequence_nestable.elem_type; - switch (elem_type->atype) { - case atype_integer: - case atype_struct_nestable: - case atype_variant_nestable: + switch (elem_type->type) { + case lttng_kernel_type_integer: + case lttng_kernel_type_struct_nestable: + case lttng_kernel_type_variant_nestable: ret = _lttng_type_statedump(session, elem_type, nesting); if (ret) return ret; @@ -3004,13 +3267,13 @@ int _lttng_enum_type_statedump(struct lttng_session *session, const struct lttng_type *type, size_t nesting) { - const struct lttng_enum_desc *enum_desc; + const struct lttng_kernel_enum_desc *enum_desc; const struct lttng_type *container_type; int ret; unsigned int i, nr_entries; container_type = type->u.enum_nestable.container_type; - if (container_type->atype != atype_integer) { + if (container_type->type != lttng_kernel_type_integer) { ret = -EINVAL; goto end; } @@ -3031,7 +3294,7 @@ int _lttng_enum_type_statedump(struct lttng_session *session, goto end; /* Dump all entries */ for (i = 0; i < nr_entries; i++) { - const struct lttng_enum_entry *entry = &enum_desc->entries[i]; + const struct lttng_kernel_enum_entry *entry = &enum_desc->entries[i]; int j, len; ret = print_tabs(session, nesting + 1); @@ -3148,14 +3411,14 @@ int _lttng_string_type_statedump(struct lttng_session *session, { int ret; - WARN_ON_ONCE(type->atype != atype_string); + WARN_ON_ONCE(type->type != lttng_kernel_type_string); /* Default encoding is UTF8 */ ret = print_tabs(session, nesting); if (ret) return ret; ret = lttng_metadata_printf(session, "string%s", - type->u.string.encoding == lttng_encode_ASCII ? + type->u.string.encoding == lttng_kernel_string_encoding_ASCII ? " { encoding = ASCII; }" : ""); return ret; } @@ -3167,7 +3430,7 @@ int _lttng_string_field_statedump(struct lttng_session *session, { int ret; - WARN_ON_ONCE(field->type.atype != atype_string); + WARN_ON_ONCE(field->type.type != lttng_kernel_type_string); ret = _lttng_string_type_statedump(session, &field->type, nesting); if (ret) return ret; @@ -3184,26 +3447,26 @@ int _lttng_type_statedump(struct lttng_session *session, { int ret = 0; - switch (type->atype) { - case atype_integer: + switch (type->type) { + case lttng_kernel_type_integer: ret = _lttng_integer_type_statedump(session, type, nesting); break; - case atype_enum_nestable: + case lttng_kernel_type_enum_nestable: ret = _lttng_enum_type_statedump(session, type, nesting); break; - case atype_string: + case lttng_kernel_type_string: ret = _lttng_string_type_statedump(session, type, nesting); break; - case atype_struct_nestable: + case lttng_kernel_type_struct_nestable: ret = _lttng_struct_type_statedump(session, type, nesting); break; - case atype_variant_nestable: + case lttng_kernel_type_variant_nestable: ret = _lttng_variant_type_statedump(session, type, nesting); break; /* Nested arrays and sequences are not supported yet. */ - case atype_array_nestable: - case atype_sequence_nestable: + case lttng_kernel_type_array_nestable: + case lttng_kernel_type_sequence_nestable: default: WARN_ON_ONCE(1); return -EINVAL; @@ -3221,26 +3484,26 @@ int _lttng_field_statedump(struct lttng_session *session, { int ret = 0; - switch (field->type.atype) { - case atype_integer: + switch (field->type.type) { + case lttng_kernel_type_integer: ret = _lttng_integer_field_statedump(session, field, nesting); break; - case atype_enum_nestable: + case lttng_kernel_type_enum_nestable: ret = _lttng_enum_field_statedump(session, field, nesting); break; - case atype_string: + case lttng_kernel_type_string: ret = _lttng_string_field_statedump(session, field, nesting); break; - case atype_struct_nestable: + case lttng_kernel_type_struct_nestable: ret = _lttng_struct_field_statedump(session, field, nesting); break; - case atype_array_nestable: + case lttng_kernel_type_array_nestable: ret = _lttng_array_field_statedump(session, field, nesting); break; - case atype_sequence_nestable: + case lttng_kernel_type_sequence_nestable: ret = _lttng_sequence_field_statedump(session, field, nesting); break; - case atype_variant_nestable: + case lttng_kernel_type_variant_nestable: ret = _lttng_variant_field_statedump(session, field, nesting); break; @@ -3819,7 +4082,30 @@ void lttng_transport_unregister(struct lttng_transport *transport) } EXPORT_SYMBOL_GPL(lttng_transport_unregister); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) +void lttng_counter_transport_register(struct lttng_counter_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_mappings() in each module's init. + */ + wrapper_vmalloc_sync_mappings(); + + mutex_lock(&sessions_mutex); + list_add_tail(&transport->node, <tng_counter_transport_list); + mutex_unlock(&sessions_mutex); +} +EXPORT_SYMBOL_GPL(lttng_counter_transport_register); + +void lttng_counter_transport_unregister(struct lttng_counter_transport *transport) +{ + mutex_lock(&sessions_mutex); + list_del(&transport->node); + mutex_unlock(&sessions_mutex); +} +EXPORT_SYMBOL_GPL(lttng_counter_transport_unregister); + +#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(4,10,0)) enum cpuhp_state lttng_hp_prepare; enum cpuhp_state lttng_hp_online; @@ -3935,7 +4221,7 @@ static void __exit lttng_exit_cpu_hotplug(void) cpuhp_remove_multi_state(lttng_hp_prepare); } -#else /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) */ +#else /* #if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(4,10,0)) */ static int lttng_init_cpu_hotplug(void) { return 0; @@ -3943,7 +4229,7 @@ static int lttng_init_cpu_hotplug(void) static void lttng_exit_cpu_hotplug(void) { } -#endif /* #else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) */ +#endif /* #else #if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(4,10,0)) */ static int __init lttng_events_init(void)