#include <linux/jhash.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
-#include <linux/uuid.h>
#include <linux/dmi.h>
-#include <wrapper/vmalloc.h> /* for wrapper_vmalloc_sync_all() */
+#include <wrapper/uuid.h>
+#include <wrapper/vmalloc.h> /* for wrapper_vmalloc_sync_mappings() */
#include <wrapper/random.h>
#include <wrapper/tracepoint.h>
#include <wrapper/list.h>
#include <lttng-abi-old.h>
#include <lttng-endian.h>
#include <lttng-string-utils.h>
+#include <wrapper/compiler_attributes.h>
#include <wrapper/ringbuffer/backend.h>
#include <wrapper/ringbuffer/frontend.h>
#include <wrapper/time.h>
+#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,16,0))
+#include <linux/stdarg.h>
+#else
+#include <stdarg.h>
+#endif
+
#define METADATA_CACHE_DEFAULT_SIZE 4096
static LIST_HEAD(sessions);
void synchronize_trace(void)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,1,0))
+#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,1,0) || \
+ LTTNG_RHEL_KERNEL_RANGE(4,18,0,193,0,0, 4,19,0,0,0,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)
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);
WARN_ON(ret);
}
synchronize_trace(); /* Wait for in-flight events to complete */
+ list_for_each_entry(chan, &session->chan, list) {
+ ret = lttng_syscalls_destroy(chan);
+ WARN_ON(ret);
+ }
list_for_each_entry_safe(enabler, tmpenabler,
&session->enablers_head, node)
lttng_enabler_destroy(enabler);
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);
lttng_id_tracker_destroy(&session->pid_tracker, false);
lttng_id_tracker_destroy(&session->vpid_tracker, false);
lttng_id_tracker_destroy(&session->uid_tracker, false);
ret = -EINVAL;
break;
case LTTNG_KERNEL_KPROBE:
- case LTTNG_KERNEL_FUNCTION:
case LTTNG_KERNEL_UPROBE:
case LTTNG_KERNEL_NOOP:
WRITE_ONCE(event->enabled, 1);
case LTTNG_KERNEL_KRETPROBE:
ret = lttng_kretprobes_event_enable_state(event, 1);
break;
+ case LTTNG_KERNEL_FUNCTION:
+ lttng_fallthrough;
default:
WARN_ON_ONCE(1);
ret = -EINVAL;
ret = -EINVAL;
break;
case LTTNG_KERNEL_KPROBE:
- case LTTNG_KERNEL_FUNCTION:
case LTTNG_KERNEL_UPROBE:
case LTTNG_KERNEL_NOOP:
WRITE_ONCE(event->enabled, 0);
case LTTNG_KERNEL_KRETPROBE:
ret = lttng_kretprobes_event_enable_state(event, 0);
break;
+ case LTTNG_KERNEL_FUNCTION:
+ lttng_fallthrough;
default:
WARN_ON_ONCE(1);
ret = -EINVAL;
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:
+ lttng_fallthrough;
default:
WARN_ON_ONCE(1);
ret = -EINVAL;
event_return->enabled = 0;
event_return->registered = 1;
event_return->instrumentation = itype;
+ INIT_LIST_HEAD(&event_return->bytecode_runtime_head);
+ INIT_LIST_HEAD(&event_return->enablers_ref_head);
/*
* Populate lttng_event structure before kretprobe registration.
*/
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:
/*
event->enabled = 0;
event->registered = 0;
event->desc = event_desc;
+ switch (event_param->u.syscall.entryexit) {
+ case LTTNG_KERNEL_SYSCALL_ENTRYEXIT:
+ ret = -EINVAL;
+ goto register_error;
+ case LTTNG_KERNEL_SYSCALL_ENTRY:
+ event->u.syscall.entryexit = LTTNG_SYSCALL_ENTRY;
+ break;
+ case LTTNG_KERNEL_SYSCALL_EXIT:
+ event->u.syscall.entryexit = LTTNG_SYSCALL_EXIT;
+ break;
+ }
+ switch (event_param->u.syscall.abi) {
+ case LTTNG_KERNEL_SYSCALL_ABI_ALL:
+ ret = -EINVAL;
+ goto register_error;
+ case LTTNG_KERNEL_SYSCALL_ABI_NATIVE:
+ event->u.syscall.abi = LTTNG_SYSCALL_ABI_NATIVE;
+ break;
+ case LTTNG_KERNEL_SYSCALL_ABI_COMPAT:
+ event->u.syscall.abi = LTTNG_SYSCALL_ABI_COMPAT;
+ break;
+ }
if (!event->desc) {
ret = -EINVAL;
goto register_error;
ret = try_module_get(event->desc->owner);
WARN_ON_ONCE(!ret);
break;
+ case LTTNG_KERNEL_FUNCTION:
+ lttng_fallthrough;
default:
WARN_ON_ONCE(1);
ret = -EINVAL;
event);
break;
case LTTNG_KERNEL_SYSCALL:
- ret = lttng_syscall_filter_enable(event->chan,
- desc->name);
+ ret = lttng_syscall_filter_enable(event->chan, event);
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:
+ lttng_fallthrough;
default:
WARN_ON_ONCE(1);
}
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);
+ ret = lttng_syscall_filter_disable(event->chan, event);
break;
case LTTNG_KERNEL_NOOP:
ret = 0;
lttng_uprobes_unregister(event);
ret = 0;
break;
+ case LTTNG_KERNEL_FUNCTION:
+ lttng_fallthrough;
default:
WARN_ON_ONCE(1);
}
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_put(event->desc);
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;
module_put(event->desc->owner);
lttng_uprobes_destroy_private(event);
break;
+ case LTTNG_KERNEL_FUNCTION:
+ lttng_fallthrough;
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);
}
struct lttng_enabler *enabler)
{
const char *desc_name, *enabler_name;
+ bool compat = false, entry = false;
enabler_name = enabler->event_param.name;
switch (enabler->event_param.instrumentation) {
case LTTNG_KERNEL_TRACEPOINT:
desc_name = desc->name;
+ switch (enabler->type) {
+ 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:
+ return -EINVAL;
+ }
break;
case LTTNG_KERNEL_SYSCALL:
desc_name = desc->name;
- if (!strncmp(desc_name, "compat_", strlen("compat_")))
+ if (!strncmp(desc_name, "compat_", strlen("compat_"))) {
desc_name += strlen("compat_");
+ compat = true;
+ }
if (!strncmp(desc_name, "syscall_exit_",
strlen("syscall_exit_"))) {
desc_name += strlen("syscall_exit_");
} else if (!strncmp(desc_name, "syscall_entry_",
strlen("syscall_entry_"))) {
desc_name += strlen("syscall_entry_");
+ entry = true;
} else {
WARN_ON_ONCE(1);
return -EINVAL;
}
+ switch (enabler->event_param.u.syscall.entryexit) {
+ case LTTNG_KERNEL_SYSCALL_ENTRYEXIT:
+ break;
+ case LTTNG_KERNEL_SYSCALL_ENTRY:
+ if (!entry)
+ return 0;
+ break;
+ case LTTNG_KERNEL_SYSCALL_EXIT:
+ if (entry)
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (enabler->event_param.u.syscall.abi) {
+ case LTTNG_KERNEL_SYSCALL_ABI_ALL:
+ break;
+ case LTTNG_KERNEL_SYSCALL_ABI_NATIVE:
+ if (compat)
+ return 0;
+ break;
+ case LTTNG_KERNEL_SYSCALL_ABI_COMPAT:
+ if (!compat)
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (enabler->event_param.u.syscall.match) {
+ case LTTNG_SYSCALL_MATCH_NAME:
+ switch (enabler->type) {
+ 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:
+ return -EINVAL;
+ }
+ break;
+ case LTTNG_SYSCALL_MATCH_NR:
+ return -EINVAL; /* Not implemented. */
+ default:
+ return -EINVAL;
+ }
break;
default:
WARN_ON_ONCE(1);
return -EINVAL;
}
- switch (enabler->type) {
- 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:
- return -EINVAL;
- }
}
static
static
int lttng_enabler_ref_events(struct lttng_enabler *enabler)
{
- struct lttng_session *session = enabler->chan->session;
+ struct lttng_channel *chan = enabler->chan;
+ struct lttng_session *session = chan->session;
struct lttng_event *event;
+ if (enabler->event_param.instrumentation == LTTNG_KERNEL_SYSCALL &&
+ enabler->event_param.u.syscall.entryexit == LTTNG_KERNEL_SYSCALL_ENTRYEXIT &&
+ enabler->event_param.u.syscall.abi == LTTNG_KERNEL_SYSCALL_ABI_ALL &&
+ enabler->event_param.u.syscall.match == LTTNG_SYSCALL_MATCH_NAME &&
+ !strcmp(enabler->event_param.name, "*")) {
+ if (enabler->enabled)
+ WRITE_ONCE(chan->syscall_all, 1);
+ else
+ WRITE_ONCE(chan->syscall_all, 0);
+ }
+
/* First ensure that probe events are created for this enabler. */
lttng_create_event_if_missing(enabler);
* 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;
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,
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, ...)
char *str;
size_t len;
va_list ap;
- struct lttng_metadata_stream *stream;
- WARN_ON_ONCE(!READ_ONCE(session->active));
+ WARN_ON_ONCE(!LTTNG_READ_ONCE(session->active));
va_start(ap, fmt);
str = kvasprintf(GFP_KERNEL, fmt, ap);
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;
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;
}
/*
* 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,
{
int ret = 0;
- if (event->metadata_dumped || !READ_ONCE(session->active))
+ if (event->metadata_dumped || !LTTNG_READ_ONCE(session->active))
return 0;
if (chan->channel_type == METADATA_CHANNEL)
return 0;
+ lttng_metadata_begin(session);
+
ret = lttng_metadata_printf(session,
"event {\n"
" name = \"%s\";\n"
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,
{
int ret = 0;
- if (chan->metadata_dumped || !READ_ONCE(session->active))
+ if (chan->metadata_dumped || !LTTNG_READ_ONCE(session->active))
return 0;
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"
chan->metadata_dumped = 1;
end:
+ lttng_metadata_end(session);
return ret;
}
static
int print_escaped_ctf_string(struct lttng_session *session, const char *string)
{
- int ret;
+ int ret = 0;
size_t i;
char cur;
if (ret)
goto error;
/* We still print the current char */
- /* Fallthrough */
+ lttng_fallthrough;
default:
ret = lttng_metadata_printf(session, "%c", cur);
break;
struct lttng_event *event;
int ret = 0;
- if (!READ_ONCE(session->active))
+ if (!LTTNG_READ_ONCE(session->active))
return 0;
+
+ lttng_metadata_begin(session);
+
if (session->metadata_dumped)
goto skip_session;
}
session->metadata_dumped = 1;
end:
+ lttng_metadata_end(session);
return ret;
}
* 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)
/*
* 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);
}
EXPORT_SYMBOL_GPL(lttng_transport_unregister);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0))
+#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(4,10,0))
enum cpuhp_state lttng_hp_prepare;
enum cpuhp_state lttng_hp_online;
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;
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)
#else
"");
#endif
+#ifdef CONFIG_LTTNG_EXPERIMENTAL_BITWISE_ENUM
+ printk(KERN_NOTICE "LTTng: Experimental bitwise enum enabled.\n");
+#endif /* CONFIG_LTTNG_EXPERIMENTAL_BITWISE_ENUM */
return 0;
error_hotplug: