-/*
+/* 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 <mathieu.desnoyers@efficios.com>
- *
- * 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
*/
/*
#include <linux/jhash.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
+#include <linux/dmi.h>
#include <wrapper/uuid.h>
-#include <wrapper/vmalloc.h> /* for wrapper_vmalloc_sync_all() */
+#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/vzalloc.h>
#include <wrapper/ringbuffer/backend.h>
#include <wrapper/ringbuffer/frontend.h>
+#include <wrapper/time.h>
#define METADATA_CACHE_DEFAULT_SIZE 4096
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();
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);
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;
for (i = 0; i < LTTNG_EVENT_HT_SIZE; i++)
INIT_HLIST_HEAD(&session->events_ht.table[i]);
list_add(&session->list, &sessions);
+ session->pid_tracker.session = session;
+ session->pid_tracker.tracker_type = TRACKER_PID;
+ session->vpid_tracker.session = session;
+ session->vpid_tracker.tracker_type = TRACKER_VPID;
+ session->uid_tracker.session = session;
+ session->uid_tracker.tracker_type = TRACKER_UID;
+ session->vuid_tracker.session = session;
+ session->vuid_tracker.tracker_type = TRACKER_VUID;
+ session->gid_tracker.session = session;
+ session->gid_tracker.tracker_type = TRACKER_GID;
+ session->vgid_tracker.session = session;
+ session->vgid_tracker.tracker_type = TRACKER_VGID;
mutex_unlock(&sessions_mutex);
return session;
}
list_for_each_entry(metadata_stream, &session->metadata_cache->metadata_stream, list)
_lttng_metadata_channel_hangup(metadata_stream);
- if (session->pid_tracker)
- lttng_pid_tracker_destroy(session->pid_tracker);
+ lttng_id_tracker_destroy(&session->pid_tracker, false);
+ lttng_id_tracker_destroy(&session->vpid_tracker, false);
+ lttng_id_tracker_destroy(&session->uid_tracker, false);
+ lttng_id_tracker_destroy(&session->vuid_tracker, false);
+ lttng_id_tracker_destroy(&session->gid_tracker, false);
+ lttng_id_tracker_destroy(&session->vgid_tracker, false);
kref_put(&session->metadata_cache->refcount, metadata_cache_destroy);
list_del(&session->list);
mutex_unlock(&sessions_mutex);
/* 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.
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)
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;
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;
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;
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;
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);
}
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);
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);
}
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);
}
kmem_cache_free(event_cache, event);
}
-int lttng_session_track_pid(struct lttng_session *session, int pid)
+struct lttng_id_tracker *get_tracker(struct lttng_session *session,
+ enum tracker_type tracker_type)
+{
+ switch (tracker_type) {
+ case TRACKER_PID:
+ return &session->pid_tracker;
+ case TRACKER_VPID:
+ return &session->vpid_tracker;
+ case TRACKER_UID:
+ return &session->uid_tracker;
+ case TRACKER_VUID:
+ return &session->vuid_tracker;
+ case TRACKER_GID:
+ return &session->gid_tracker;
+ case TRACKER_VGID:
+ return &session->vgid_tracker;
+ default:
+ WARN_ON_ONCE(1);
+ return NULL;
+ }
+}
+
+int lttng_session_track_id(struct lttng_session *session,
+ enum tracker_type tracker_type, int id)
{
+ struct lttng_id_tracker *tracker;
int ret;
- if (pid < -1)
+ tracker = get_tracker(session, tracker_type);
+ if (!tracker)
+ return -EINVAL;
+ if (id < -1)
return -EINVAL;
mutex_lock(&sessions_mutex);
- if (pid == -1) {
- /* track all pids: destroy tracker. */
- if (session->pid_tracker) {
- struct lttng_pid_tracker *lpf;
-
- lpf = session->pid_tracker;
- rcu_assign_pointer(session->pid_tracker, NULL);
- synchronize_trace();
- lttng_pid_tracker_destroy(lpf);
- }
+ if (id == -1) {
+ /* track all ids: destroy tracker. */
+ lttng_id_tracker_destroy(tracker, true);
ret = 0;
} else {
- if (!session->pid_tracker) {
- struct lttng_pid_tracker *lpf;
-
- lpf = lttng_pid_tracker_create();
- if (!lpf) {
- ret = -ENOMEM;
- goto unlock;
- }
- ret = lttng_pid_tracker_add(lpf, pid);
- rcu_assign_pointer(session->pid_tracker, lpf);
- } else {
- ret = lttng_pid_tracker_add(session->pid_tracker, pid);
- }
+ ret = lttng_id_tracker_add(tracker, id);
}
-unlock:
mutex_unlock(&sessions_mutex);
return ret;
}
-int lttng_session_untrack_pid(struct lttng_session *session, int pid)
+int lttng_session_untrack_id(struct lttng_session *session,
+ enum tracker_type tracker_type, int id)
{
+ struct lttng_id_tracker *tracker;
int ret;
- if (pid < -1)
+ tracker = get_tracker(session, tracker_type);
+ if (!tracker)
+ return -EINVAL;
+ if (id < -1)
return -EINVAL;
mutex_lock(&sessions_mutex);
- if (pid == -1) {
- /* untrack all pids: replace by empty tracker. */
- struct lttng_pid_tracker *old_lpf = session->pid_tracker;
- struct lttng_pid_tracker *lpf;
-
- lpf = lttng_pid_tracker_create();
- if (!lpf) {
- ret = -ENOMEM;
- goto unlock;
- }
- rcu_assign_pointer(session->pid_tracker, lpf);
- synchronize_trace();
- if (old_lpf)
- lttng_pid_tracker_destroy(old_lpf);
- ret = 0;
+ if (id == -1) {
+ /* untrack all ids: replace by empty tracker. */
+ ret = lttng_id_tracker_empty_set(tracker);
} else {
- if (!session->pid_tracker) {
- ret = -ENOENT;
- goto unlock;
- }
- ret = lttng_pid_tracker_del(session->pid_tracker, pid);
+ ret = lttng_id_tracker_del(tracker, id);
}
-unlock:
mutex_unlock(&sessions_mutex);
return ret;
}
static
-void *pid_list_start(struct seq_file *m, loff_t *pos)
+void *id_list_start(struct seq_file *m, loff_t *pos)
{
- struct lttng_session *session = m->private;
- struct lttng_pid_tracker *lpf;
- struct lttng_pid_hash_node *e;
+ struct lttng_id_tracker *id_tracker = m->private;
+ struct lttng_id_tracker_rcu *id_tracker_p = id_tracker->p;
+ struct lttng_id_hash_node *e;
int iter = 0, i;
mutex_lock(&sessions_mutex);
- lpf = session->pid_tracker;
- if (lpf) {
- for (i = 0; i < LTTNG_PID_TABLE_SIZE; i++) {
- struct hlist_head *head = &lpf->pid_hash[i];
+ if (id_tracker_p) {
+ for (i = 0; i < LTTNG_ID_TABLE_SIZE; i++) {
+ struct hlist_head *head = &id_tracker_p->id_hash[i];
lttng_hlist_for_each_entry(e, head, hlist) {
if (iter++ >= *pos)
}
}
} else {
- /* PID tracker disabled. */
+ /* ID tracker disabled. */
if (iter >= *pos && iter == 0) {
- return session; /* empty tracker */
+ return id_tracker_p; /* empty tracker */
}
iter++;
}
/* Called with sessions_mutex held. */
static
-void *pid_list_next(struct seq_file *m, void *p, loff_t *ppos)
+void *id_list_next(struct seq_file *m, void *p, loff_t *ppos)
{
- struct lttng_session *session = m->private;
- struct lttng_pid_tracker *lpf;
- struct lttng_pid_hash_node *e;
+ struct lttng_id_tracker *id_tracker = m->private;
+ struct lttng_id_tracker_rcu *id_tracker_p = id_tracker->p;
+ struct lttng_id_hash_node *e;
int iter = 0, i;
(*ppos)++;
- lpf = session->pid_tracker;
- if (lpf) {
- for (i = 0; i < LTTNG_PID_TABLE_SIZE; i++) {
- struct hlist_head *head = &lpf->pid_hash[i];
+ if (id_tracker_p) {
+ for (i = 0; i < LTTNG_ID_TABLE_SIZE; i++) {
+ struct hlist_head *head = &id_tracker_p->id_hash[i];
lttng_hlist_for_each_entry(e, head, hlist) {
if (iter++ >= *ppos)
}
}
} else {
- /* PID tracker disabled. */
+ /* ID tracker disabled. */
if (iter >= *ppos && iter == 0)
- return session; /* empty tracker */
+ return p; /* empty tracker */
iter++;
}
}
static
-void pid_list_stop(struct seq_file *m, void *p)
+void id_list_stop(struct seq_file *m, void *p)
{
mutex_unlock(&sessions_mutex);
}
static
-int pid_list_show(struct seq_file *m, void *p)
+int id_list_show(struct seq_file *m, void *p)
{
- int pid;
+ struct lttng_id_tracker *id_tracker = m->private;
+ struct lttng_id_tracker_rcu *id_tracker_p = id_tracker->p;
+ int id;
- if (p == m->private) {
+ if (p == id_tracker_p) {
/* Tracker disabled. */
- pid = -1;
+ id = -1;
} else {
- const struct lttng_pid_hash_node *e = p;
+ const struct lttng_id_hash_node *e = p;
- pid = lttng_pid_tracker_get_node_pid(e);
+ id = lttng_id_tracker_get_node_id(e);
+ }
+ switch (id_tracker->tracker_type) {
+ case TRACKER_PID:
+ seq_printf(m, "process { pid = %d; };\n", id);
+ break;
+ case TRACKER_VPID:
+ seq_printf(m, "process { vpid = %d; };\n", id);
+ break;
+ case TRACKER_UID:
+ seq_printf(m, "user { uid = %d; };\n", id);
+ break;
+ case TRACKER_VUID:
+ seq_printf(m, "user { vuid = %d; };\n", id);
+ break;
+ case TRACKER_GID:
+ seq_printf(m, "group { gid = %d; };\n", id);
+ break;
+ case TRACKER_VGID:
+ seq_printf(m, "group { vgid = %d; };\n", id);
+ break;
+ default:
+ seq_printf(m, "UNKNOWN { field = %d };\n", id);
}
- seq_printf(m, "process { pid = %d; };\n", pid);
return 0;
}
static
-const struct seq_operations lttng_tracker_pids_list_seq_ops = {
- .start = pid_list_start,
- .next = pid_list_next,
- .stop = pid_list_stop,
- .show = pid_list_show,
+const struct seq_operations lttng_tracker_ids_list_seq_ops = {
+ .start = id_list_start,
+ .next = id_list_next,
+ .stop = id_list_stop,
+ .show = id_list_show,
};
static
-int lttng_tracker_pids_list_open(struct inode *inode, struct file *file)
+int lttng_tracker_ids_list_open(struct inode *inode, struct file *file)
{
- return seq_open(file, <tng_tracker_pids_list_seq_ops);
+ return seq_open(file, <tng_tracker_ids_list_seq_ops);
}
static
-int lttng_tracker_pids_list_release(struct inode *inode, struct file *file)
+int lttng_tracker_ids_list_release(struct inode *inode, struct file *file)
{
struct seq_file *m = file->private_data;
- struct lttng_session *session = m->private;
+ struct lttng_id_tracker *id_tracker = m->private;
int ret;
- WARN_ON_ONCE(!session);
+ WARN_ON_ONCE(!id_tracker);
ret = seq_release(inode, file);
- if (!ret && session)
- fput(session->file);
+ if (!ret)
+ fput(id_tracker->session->file);
return ret;
}
-const struct file_operations lttng_tracker_pids_list_fops = {
+const struct file_operations lttng_tracker_ids_list_fops = {
.owner = THIS_MODULE,
- .open = lttng_tracker_pids_list_open,
+ .open = lttng_tracker_ids_list_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = lttng_tracker_pids_list_release,
+ .release = lttng_tracker_ids_list_release,
};
-int lttng_session_list_tracker_pids(struct lttng_session *session)
+int lttng_session_list_tracker_ids(struct lttng_session *session,
+ enum tracker_type tracker_type)
{
- struct file *tracker_pids_list_file;
+ struct file *tracker_ids_list_file;
struct seq_file *m;
int file_fd, ret;
goto fd_error;
}
- tracker_pids_list_file = anon_inode_getfile("[lttng_tracker_pids_list]",
- <tng_tracker_pids_list_fops,
+ tracker_ids_list_file = anon_inode_getfile("[lttng_tracker_ids_list]",
+ <tng_tracker_ids_list_fops,
NULL, O_RDWR);
- if (IS_ERR(tracker_pids_list_file)) {
- ret = PTR_ERR(tracker_pids_list_file);
+ if (IS_ERR(tracker_ids_list_file)) {
+ ret = PTR_ERR(tracker_ids_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);
+ ret = lttng_tracker_ids_list_fops.open(NULL, tracker_ids_list_file);
if (ret < 0)
goto open_error;
- m = tracker_pids_list_file->private_data;
- m->private = session;
- fd_install(file_fd, tracker_pids_list_file);
+ m = tracker_ids_list_file->private_data;
+
+ m->private = get_tracker(session, tracker_type);
+ BUG_ON(!m->private);
+ fd_install(file_fd, tracker_ids_list_file);
return file_fd;
open_error:
atomic_long_dec(&session->file->f_count);
refcount_error:
- fput(tracker_pids_list_file);
+ fput(tracker_ids_list_file);
file_error:
put_unused_fd(file_fd);
fd_error:
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)
{
* 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;
+
+ mutex_unlock(&session->metadata_cache->lock);
+ list_for_each_entry(stream, &session->metadata_cache->metadata_stream, list)
+ wake_up_interruptible(&stream->read_wait);
+ }
+}
+
/*
* 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));
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;
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) {
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,
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,
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;
}
* 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)
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);
return offset;
}
+static
+int print_escaped_ctf_string(struct lttng_session *session, const char *string)
+{
+ int ret = 0;
+ 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.
{
unsigned char *uuid_c = session->uuid.b;
unsigned char uuid_s[37], clock_uuid_s[BOOT_ID_LEN];
+ const char *product_uuid;
struct lttng_channel *chan;
struct lttng_event *event;
int ret = 0;
if (!READ_ONCE(session->active))
return 0;
+
+ lttng_metadata_begin(session);
+
if (session->metadata_dumped)
goto skip_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,
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;
+
+ /* Add the product UUID to the 'env' section */
+ product_uuid = dmi_get_system_info(DMI_PRODUCT_UUID);
+ if (product_uuid) {
+ ret = lttng_metadata_printf(session,
+ " product_uuid = \"%s\";\n",
+ product_uuid
+ );
+ if (ret)
+ goto end;
+ }
+
+ /* Close the 'env' section */
+ ret = lttng_metadata_printf(session, "};\n\n");
+ if (ret)
+ goto end;
+
ret = lttng_metadata_printf(session,
"clock {\n"
" name = \"%s\";\n",
}
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);