X-Git-Url: http://git.efficios.com/?p=deliverable%2Flttng-modules.git;a=blobdiff_plain;f=lttng-events.c;h=a4570b7b45a7d175ec2cf03680c7376786464eef;hp=a66e6711fc03bc0ec2a20732dc33e956451177c9;hb=refs%2Fheads%2Fns-phase-1;hpb=489de24bfb835022b64c2e71d717eaf333ab3633 diff --git a/lttng-events.c b/lttng-events.c index a66e6711..a4570b7b 100644 --- a/lttng-events.c +++ b/lttng-events.c @@ -1,23 +1,10 @@ -/* +/* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1) + * * lttng-events.c * * Holds LTTng per-session event registry. * * Copyright (C) 2010-2012 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; only - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* @@ -40,18 +27,19 @@ #include #include #include +#include -#include #include /* for wrapper_vmalloc_sync_all() */ #include #include #include +#include #include #include #include #include #include -#include +#include #include #include @@ -87,7 +75,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(); @@ -130,7 +123,7 @@ struct lttng_session *lttng_session_create(void) int i; mutex_lock(&sessions_mutex); - session = kzalloc(sizeof(struct lttng_session), GFP_KERNEL); + session = lttng_kvzalloc(sizeof(struct lttng_session), GFP_KERNEL); if (!session) goto err; INIT_LIST_HEAD(&session->chan); @@ -141,7 +134,7 @@ struct lttng_session *lttng_session_create(void) GFP_KERNEL); if (!metadata_cache) goto err_free_session; - metadata_cache->data = lttng_vzalloc(METADATA_CACHE_DEFAULT_SIZE); + metadata_cache->data = vzalloc(METADATA_CACHE_DEFAULT_SIZE); if (!metadata_cache->data) goto err_free_cache; metadata_cache->cache_alloc = METADATA_CACHE_DEFAULT_SIZE; @@ -161,7 +154,7 @@ struct lttng_session *lttng_session_create(void) err_free_cache: kfree(metadata_cache); err_free_session: - kfree(session); + lttng_kvfree(session); err: mutex_unlock(&sessions_mutex); return NULL; @@ -184,7 +177,7 @@ void lttng_session_destroy(struct lttng_session *session) int ret; mutex_lock(&sessions_mutex); - ACCESS_ONCE(session->active) = 0; + WRITE_ONCE(session->active, 0); list_for_each_entry(chan, &session->chan, list) { ret = lttng_syscalls_unregister(chan); WARN_ON(ret); @@ -210,7 +203,7 @@ void lttng_session_destroy(struct lttng_session *session) kref_put(&session->metadata_cache->refcount, metadata_cache_destroy); list_del(&session->list); mutex_unlock(&sessions_mutex); - kfree(session); + lttng_kvfree(session); } int lttng_session_statedump(struct lttng_session *session) @@ -237,6 +230,9 @@ int lttng_session_enable(struct lttng_session *session) /* Set transient enabler state to "enabled" */ session->tstate = 1; + /* We need to sync enablers with session before activation. */ + lttng_session_sync_enablers(session); + /* * Snapshot the number of events per channel to know the type of header * we need to use. @@ -250,25 +246,22 @@ int lttng_session_enable(struct lttng_session *session) chan->header_type = 2; /* large */ } - /* We need to sync enablers with session before activation. */ - lttng_session_sync_enablers(session); - /* Clear each stream's quiescent state. */ list_for_each_entry(chan, &session->chan, list) { if (chan->channel_type != METADATA_CHANNEL) lib_ring_buffer_clear_quiescent_channel(chan->chan); } - ACCESS_ONCE(session->active) = 1; - ACCESS_ONCE(session->been_active) = 1; + WRITE_ONCE(session->active, 1); + WRITE_ONCE(session->been_active, 1); ret = _lttng_session_metadata_statedump(session); if (ret) { - ACCESS_ONCE(session->active) = 0; + WRITE_ONCE(session->active, 0); goto end; } ret = lttng_statedump_start(session); if (ret) - ACCESS_ONCE(session->active) = 0; + WRITE_ONCE(session->active, 0); end: mutex_unlock(&sessions_mutex); return ret; @@ -284,7 +277,7 @@ int lttng_session_disable(struct lttng_session *session) ret = -EBUSY; goto end; } - ACCESS_ONCE(session->active) = 0; + WRITE_ONCE(session->active, 0); /* Set transient enabler state to "disabled" */ session->tstate = 0; @@ -340,8 +333,6 @@ end: return ret; } - - int lttng_channel_enable(struct lttng_channel *channel) { int ret = 0; @@ -359,7 +350,7 @@ int lttng_channel_enable(struct lttng_channel *channel) channel->tstate = 1; lttng_session_sync_enablers(channel->session); /* Set atomically the state to "enabled" */ - ACCESS_ONCE(channel->enabled) = 1; + WRITE_ONCE(channel->enabled, 1); end: mutex_unlock(&sessions_mutex); return ret; @@ -379,7 +370,7 @@ int lttng_channel_disable(struct lttng_channel *channel) goto end; } /* Set atomically the state to "disabled" */ - ACCESS_ONCE(channel->enabled) = 0; + WRITE_ONCE(channel->enabled, 0); /* Set transient enabler state to "enabled" */ channel->tstate = 0; lttng_session_sync_enablers(channel->session); @@ -408,8 +399,9 @@ int lttng_event_enable(struct lttng_event *event) break; case LTTNG_KERNEL_KPROBE: case LTTNG_KERNEL_FUNCTION: + case LTTNG_KERNEL_UPROBE: case LTTNG_KERNEL_NOOP: - ACCESS_ONCE(event->enabled) = 1; + WRITE_ONCE(event->enabled, 1); break; case LTTNG_KERNEL_KRETPROBE: ret = lttng_kretprobes_event_enable_state(event, 1); @@ -443,8 +435,9 @@ int lttng_event_disable(struct lttng_event *event) break; case LTTNG_KERNEL_KPROBE: case LTTNG_KERNEL_FUNCTION: + case LTTNG_KERNEL_UPROBE: case LTTNG_KERNEL_NOOP: - ACCESS_ONCE(event->enabled) = 0; + WRITE_ONCE(event->enabled, 0); break; case LTTNG_KERNEL_KRETPROBE: ret = lttng_kretprobes_event_enable_state(event, 0); @@ -589,6 +582,7 @@ 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: @@ -752,6 +746,28 @@ 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 + * we may want to apply filters. + */ + event->enabled = 0; + event->registered = 1; + + /* + * Populate lttng_event structure before event + * registration. + */ + smp_wmb(); + + ret = lttng_uprobes_register(event_param->name, + event_param->u.uprobe.fd, + event); + if (ret) + goto register_error; + ret = try_module_get(event->desc->owner); + WARN_ON_ONCE(!ret); + break; default: WARN_ON_ONCE(1); ret = -EINVAL; @@ -814,6 +830,7 @@ 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: @@ -863,6 +880,10 @@ 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; default: WARN_ON_ONCE(1); } @@ -896,6 +917,10 @@ void _lttng_event_destroy(struct lttng_event *event) case LTTNG_KERNEL_NOOP: case LTTNG_KERNEL_SYSCALL: break; + case LTTNG_KERNEL_UPROBE: + module_put(event->desc->owner); + lttng_uprobes_destroy_private(event); + break; default: WARN_ON_ONCE(1); } @@ -1115,8 +1140,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); @@ -1142,11 +1167,11 @@ fd_error: * Enabler management. */ static -int lttng_match_enabler_wildcard(const char *desc_name, - const char *name) +int lttng_match_enabler_star_glob(const char *desc_name, + const char *pattern) { - /* Compare excluding final '*' */ - if (strncmp(desc_name, name, strlen(name) - 1)) + if (!strutils_star_glob_match(pattern, LTTNG_SIZE_MAX, + desc_name, LTTNG_SIZE_MAX)) return 0; return 1; } @@ -1191,8 +1216,8 @@ int lttng_desc_match_enabler(const struct lttng_event_desc *desc, return -EINVAL; } switch (enabler->type) { - case LTTNG_ENABLER_WILDCARD: - return lttng_match_enabler_wildcard(desc_name, enabler_name); + case LTTNG_ENABLER_STAR_GLOB: + return lttng_match_enabler_star_glob(desc_name, enabler_name); case LTTNG_ENABLER_NAME: return lttng_match_enabler_name(desc_name, enabler_name); default: @@ -1445,6 +1470,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) { @@ -1515,7 +1552,7 @@ void lttng_session_sync_enablers(struct lttng_session *session) */ enabled = enabled && session->tstate && event->chan->tstate; - ACCESS_ONCE(event->enabled) = enabled; + WRITE_ONCE(event->enabled, enabled); /* * Sync tracepoint registration with event enabled * state. @@ -1641,7 +1678,7 @@ int lttng_metadata_printf(struct lttng_session *session, va_list ap; struct lttng_metadata_stream *stream; - WARN_ON_ONCE(!ACCESS_ONCE(session->active)); + WARN_ON_ONCE(!READ_ONCE(session->active)); va_start(ap, fmt); str = kvasprintf(GFP_KERNEL, fmt, ap); @@ -1659,7 +1696,7 @@ int lttng_metadata_printf(struct lttng_session *session, tmp_cache_alloc_size = max_t(unsigned int, session->metadata_cache->cache_alloc + len, session->metadata_cache->cache_alloc << 1); - tmp_cache_realloc = lttng_vzalloc(tmp_cache_alloc_size); + tmp_cache_realloc = vzalloc(tmp_cache_alloc_size); if (!tmp_cache_realloc) goto err; if (session->metadata_cache->data) { @@ -2048,6 +2085,7 @@ int _lttng_field_statedump(struct lttng_session *session, ret = _lttng_enum_statedump(session, field, nesting); break; case atype_array: + case atype_array_bitfield: { const struct lttng_basic_type *elem_type; @@ -2086,6 +2124,7 @@ int _lttng_field_statedump(struct lttng_session *session, break; } case atype_sequence: + case atype_sequence_bitfield: { const struct lttng_basic_type *elem_type; const struct lttng_basic_type *length_type; @@ -2228,7 +2267,7 @@ int _lttng_event_metadata_statedump(struct lttng_session *session, { int ret = 0; - if (event->metadata_dumped || !ACCESS_ONCE(session->active)) + if (event->metadata_dumped || !READ_ONCE(session->active)) return 0; if (chan->channel_type == METADATA_CHANNEL) return 0; @@ -2295,7 +2334,7 @@ int _lttng_channel_metadata_statedump(struct lttng_session *session, { int ret = 0; - if (chan->metadata_dumped || !ACCESS_ONCE(session->active)) + if (chan->metadata_dumped || !READ_ONCE(session->active)) return 0; if (chan->channel_type == METADATA_CHANNEL) @@ -2452,7 +2491,7 @@ int _lttng_session_metadata_statedump(struct lttng_session *session) struct lttng_event *event; int ret = 0; - if (!ACCESS_ONCE(session->active)) + if (!READ_ONCE(session->active)) return 0; if (session->metadata_dumped) goto skip_session; @@ -2644,6 +2683,133 @@ void lttng_transport_unregister(struct lttng_transport *transport) } EXPORT_SYMBOL_GPL(lttng_transport_unregister); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) + +enum cpuhp_state lttng_hp_prepare; +enum cpuhp_state lttng_hp_online; + +static int lttng_hotplug_prepare(unsigned int cpu, struct hlist_node *node) +{ + struct lttng_cpuhp_node *lttng_node; + + lttng_node = container_of(node, struct lttng_cpuhp_node, node); + switch (lttng_node->component) { + case LTTNG_RING_BUFFER_FRONTEND: + return 0; + case LTTNG_RING_BUFFER_BACKEND: + return lttng_cpuhp_rb_backend_prepare(cpu, lttng_node); + case LTTNG_RING_BUFFER_ITER: + return 0; + case LTTNG_CONTEXT_PERF_COUNTERS: + return 0; + default: + return -EINVAL; + } +} + +static int lttng_hotplug_dead(unsigned int cpu, struct hlist_node *node) +{ + struct lttng_cpuhp_node *lttng_node; + + lttng_node = container_of(node, struct lttng_cpuhp_node, node); + switch (lttng_node->component) { + case LTTNG_RING_BUFFER_FRONTEND: + return lttng_cpuhp_rb_frontend_dead(cpu, lttng_node); + case LTTNG_RING_BUFFER_BACKEND: + return 0; + case LTTNG_RING_BUFFER_ITER: + return 0; + case LTTNG_CONTEXT_PERF_COUNTERS: + return lttng_cpuhp_perf_counter_dead(cpu, lttng_node); + default: + return -EINVAL; + } +} + +static int lttng_hotplug_online(unsigned int cpu, struct hlist_node *node) +{ + struct lttng_cpuhp_node *lttng_node; + + lttng_node = container_of(node, struct lttng_cpuhp_node, node); + switch (lttng_node->component) { + case LTTNG_RING_BUFFER_FRONTEND: + return lttng_cpuhp_rb_frontend_online(cpu, lttng_node); + case LTTNG_RING_BUFFER_BACKEND: + return 0; + case LTTNG_RING_BUFFER_ITER: + return lttng_cpuhp_rb_iter_online(cpu, lttng_node); + case LTTNG_CONTEXT_PERF_COUNTERS: + return lttng_cpuhp_perf_counter_online(cpu, lttng_node); + default: + return -EINVAL; + } +} + +static int lttng_hotplug_offline(unsigned int cpu, struct hlist_node *node) +{ + struct lttng_cpuhp_node *lttng_node; + + lttng_node = container_of(node, struct lttng_cpuhp_node, node); + switch (lttng_node->component) { + case LTTNG_RING_BUFFER_FRONTEND: + return lttng_cpuhp_rb_frontend_offline(cpu, lttng_node); + case LTTNG_RING_BUFFER_BACKEND: + return 0; + case LTTNG_RING_BUFFER_ITER: + return 0; + case LTTNG_CONTEXT_PERF_COUNTERS: + return 0; + default: + return -EINVAL; + } +} + +static int __init lttng_init_cpu_hotplug(void) +{ + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_BP_PREPARE_DYN, "lttng:prepare", + lttng_hotplug_prepare, + lttng_hotplug_dead); + if (ret < 0) { + return ret; + } + lttng_hp_prepare = ret; + lttng_rb_set_hp_prepare(ret); + + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "lttng:online", + lttng_hotplug_online, + lttng_hotplug_offline); + if (ret < 0) { + cpuhp_remove_multi_state(lttng_hp_prepare); + lttng_hp_prepare = 0; + return ret; + } + lttng_hp_online = ret; + lttng_rb_set_hp_online(ret); + + return 0; +} + +static void __exit lttng_exit_cpu_hotplug(void) +{ + lttng_rb_set_hp_online(0); + cpuhp_remove_multi_state(lttng_hp_online); + lttng_rb_set_hp_prepare(0); + cpuhp_remove_multi_state(lttng_hp_prepare); +} + +#else /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) */ +static int lttng_init_cpu_hotplug(void) +{ + return 0; +} +static void lttng_exit_cpu_hotplug(void) +{ +} +#endif /* #else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) */ + + static int __init lttng_events_init(void) { int ret; @@ -2677,14 +2843,29 @@ static int __init lttng_events_init(void) ret = lttng_logger_init(); if (ret) goto error_logger; - printk(KERN_NOTICE "LTTng: Loaded modules v%s.%s.%s%s (%s)\n", + ret = lttng_init_cpu_hotplug(); + if (ret) + goto error_hotplug; + printk(KERN_NOTICE "LTTng: Loaded modules v%s.%s.%s%s (%s)%s%s\n", __stringify(LTTNG_MODULES_MAJOR_VERSION), __stringify(LTTNG_MODULES_MINOR_VERSION), __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION), LTTNG_MODULES_EXTRAVERSION, - LTTNG_VERSION_NAME); + LTTNG_VERSION_NAME, +#ifdef LTTNG_EXTRA_VERSION_GIT + LTTNG_EXTRA_VERSION_GIT[0] == '\0' ? "" : " - " LTTNG_EXTRA_VERSION_GIT, +#else + "", +#endif +#ifdef LTTNG_EXTRA_VERSION_NAME + LTTNG_EXTRA_VERSION_NAME[0] == '\0' ? "" : " - " LTTNG_EXTRA_VERSION_NAME); +#else + ""); +#endif return 0; +error_hotplug: + lttng_logger_exit(); error_logger: lttng_abi_exit(); error_abi: @@ -2693,12 +2874,22 @@ error_kmem: lttng_tracepoint_exit(); error_tp: lttng_context_exit(); - printk(KERN_NOTICE "LTTng: Failed to load modules v%s.%s.%s%s (%s)\n", + printk(KERN_NOTICE "LTTng: Failed to load modules v%s.%s.%s%s (%s)%s%s\n", __stringify(LTTNG_MODULES_MAJOR_VERSION), __stringify(LTTNG_MODULES_MINOR_VERSION), __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION), LTTNG_MODULES_EXTRAVERSION, - LTTNG_VERSION_NAME); + LTTNG_VERSION_NAME, +#ifdef LTTNG_EXTRA_VERSION_GIT + LTTNG_EXTRA_VERSION_GIT[0] == '\0' ? "" : " - " LTTNG_EXTRA_VERSION_GIT, +#else + "", +#endif +#ifdef LTTNG_EXTRA_VERSION_NAME + LTTNG_EXTRA_VERSION_NAME[0] == '\0' ? "" : " - " LTTNG_EXTRA_VERSION_NAME); +#else + ""); +#endif return ret; } @@ -2708,6 +2899,7 @@ static void __exit lttng_events_exit(void) { struct lttng_session *session, *tmpsession; + lttng_exit_cpu_hotplug(); lttng_logger_exit(); lttng_abi_exit(); list_for_each_entry_safe(session, tmpsession, &sessions, list) @@ -2715,19 +2907,36 @@ static void __exit lttng_events_exit(void) kmem_cache_destroy(event_cache); lttng_tracepoint_exit(); lttng_context_exit(); - printk(KERN_NOTICE "LTTng: Unloaded modules v%s.%s.%s%s (%s)\n", + printk(KERN_NOTICE "LTTng: Unloaded modules v%s.%s.%s%s (%s)%s%s\n", __stringify(LTTNG_MODULES_MAJOR_VERSION), __stringify(LTTNG_MODULES_MINOR_VERSION), __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION), LTTNG_MODULES_EXTRAVERSION, - LTTNG_VERSION_NAME); + LTTNG_VERSION_NAME, +#ifdef LTTNG_EXTRA_VERSION_GIT + LTTNG_EXTRA_VERSION_GIT[0] == '\0' ? "" : " - " LTTNG_EXTRA_VERSION_GIT, +#else + "", +#endif +#ifdef LTTNG_EXTRA_VERSION_NAME + LTTNG_EXTRA_VERSION_NAME[0] == '\0' ? "" : " - " LTTNG_EXTRA_VERSION_NAME); +#else + ""); +#endif } module_exit(lttng_events_exit); +#include "extra_version/patches.i" +#ifdef LTTNG_EXTRA_VERSION_GIT +MODULE_INFO(extra_version_git, LTTNG_EXTRA_VERSION_GIT); +#endif +#ifdef LTTNG_EXTRA_VERSION_NAME +MODULE_INFO(extra_version_name, LTTNG_EXTRA_VERSION_NAME); +#endif MODULE_LICENSE("GPL and additional rights"); MODULE_AUTHOR("Mathieu Desnoyers "); -MODULE_DESCRIPTION("LTTng Events"); +MODULE_DESCRIPTION("LTTng tracer"); MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "." __stringify(LTTNG_MODULES_MINOR_VERSION) "." __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION)