#include <linux/jiffies.h>
#include <linux/utsname.h>
#include <linux/err.h>
+#include <linux/seq_file.h>
+#include <linux/file.h>
+#include <linux/anon_inodes.h>
+#include "wrapper/file.h"
#include "wrapper/uuid.h"
#include "wrapper/vmalloc.h" /* for wrapper_vmalloc_sync_all() */
#include "wrapper/random.h"
kref_init(&metadata_cache->refcount);
session->metadata_cache = metadata_cache;
INIT_LIST_HEAD(&metadata_cache->metadata_stream);
+ memcpy(&metadata_cache->uuid, &session->uuid,
+ sizeof(metadata_cache->uuid));
list_add(&session->list, &sessions);
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);
kref_put(&session->metadata_cache->refcount, metadata_cache_destroy);
list_del(&session->list);
mutex_unlock(&sessions_mutex);
*/
list_for_each_entry(event, &chan->session->events, list) {
if (!strcmp(event->desc->name, event_param->name)) {
- ret = -EEXIST;
- goto exist;
+ /*
+ * Allow events with the same name to appear in
+ * different channels.
+ */
+ if (event->chan == chan) {
+ ret = -EEXIST;
+ goto exist;
+ }
}
}
event = kmem_cache_zalloc(event_cache, GFP_KERNEL);
ret = -ENOENT;
goto register_error;
}
- ret = kabi_2635_tracepoint_probe_register(event->desc->kname,
+ ret = lttng_wrapper_tracepoint_probe_register(event->desc->kname,
event->desc->probe_callback,
event);
if (ret) {
switch (event->instrumentation) {
case LTTNG_KERNEL_TRACEPOINT:
- ret = kabi_2635_tracepoint_probe_unregister(event->desc->name,
+ ret = lttng_wrapper_tracepoint_probe_unregister(event->desc->kname,
event->desc->probe_callback,
event);
if (ret)
kmem_cache_free(event_cache, event);
}
+int lttng_session_track_pid(struct lttng_session *session, int pid)
+{
+ int ret;
+
+ if (pid < -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);
+ }
+ 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);
+ }
+ }
+unlock:
+ mutex_unlock(&sessions_mutex);
+ return ret;
+}
+
+int lttng_session_untrack_pid(struct lttng_session *session, int pid)
+{
+ int ret;
+
+ if (pid < -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;
+ } else {
+ if (!session->pid_tracker) {
+ ret = -ENOENT;
+ goto unlock;
+ }
+ ret = lttng_pid_tracker_del(session->pid_tracker, pid);
+ }
+unlock:
+ mutex_unlock(&sessions_mutex);
+ return ret;
+}
+
+static
+void *pid_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;
+ 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];
+
+ hlist_for_each_entry(e, head, hlist) {
+ if (iter++ >= *pos)
+ return e;
+ }
+ }
+ } else {
+ /* PID tracker disabled. */
+ if (iter >= *pos && iter == 0) {
+ return session; /* empty tracker */
+ }
+ iter++;
+ }
+ /* End of list */
+ return NULL;
+}
+
+/* Called with sessions_mutex held. */
+static
+void *pid_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;
+ 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];
+
+ hlist_for_each_entry(e, head, hlist) {
+ if (iter++ >= *ppos)
+ return e;
+ }
+ }
+ } else {
+ /* PID tracker disabled. */
+ if (iter >= *ppos && iter == 0)
+ return session; /* empty tracker */
+ iter++;
+ }
+
+ /* End of list */
+ return NULL;
+}
+
+static
+void pid_list_stop(struct seq_file *m, void *p)
+{
+ mutex_unlock(&sessions_mutex);
+}
+
+static
+int pid_list_show(struct seq_file *m, void *p)
+{
+ int pid;
+
+ if (p == m->private) {
+ /* Tracker disabled. */
+ pid = -1;
+ } else {
+ const struct lttng_pid_hash_node *e = p;
+
+ pid = lttng_pid_tracker_get_node_pid(e);
+ }
+ 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,
+};
+
+static
+int lttng_tracker_pids_list_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, <tng_tracker_pids_list_seq_ops);
+}
+
+static
+int lttng_tracker_pids_list_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *m = file->private_data;
+ struct lttng_session *session = m->private;
+ int ret;
+
+ WARN_ON_ONCE(!session);
+ ret = seq_release(inode, file);
+ if (!ret && session)
+ fput(session->file);
+ return ret;
+}
+
+const struct file_operations lttng_tracker_pids_list_fops = {
+ .owner = THIS_MODULE,
+ .open = lttng_tracker_pids_list_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = lttng_tracker_pids_list_release,
+};
+
+int lttng_session_list_tracker_pids(struct lttng_session *session)
+{
+ struct file *tracker_pids_list_file;
+ struct seq_file *m;
+ int file_fd, ret;
+
+ file_fd = lttng_get_unused_fd();
+ if (file_fd < 0) {
+ ret = file_fd;
+ goto fd_error;
+ }
+
+ tracker_pids_list_file = anon_inode_getfile("[lttng_tracker_pids_list]",
+ <tng_tracker_pids_list_fops,
+ NULL, O_RDWR);
+ if (IS_ERR(tracker_pids_list_file)) {
+ ret = PTR_ERR(tracker_pids_list_file);
+ goto file_error;
+ }
+ ret = lttng_tracker_pids_list_fops.open(NULL, tracker_pids_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);
+ atomic_long_inc(&session->file->f_count);
+
+ return file_fd;
+
+open_error:
+ fput(tracker_pids_list_file);
+file_error:
+ put_unused_fd(file_fd);
+fd_error:
+ return ret;
+}
+
/*
* Serialize at most one packet worth of metadata into a metadata
* channel.
/*
* Ensure we support mutiple get_next / put sequences followed
- * by put_next.
+ * by put_next. The metadata stream lock internally protects
+ * reading the metadata cache. It can indeed be read
+ * concurrently by "get_next_subbuf" and "flush" operations on
+ * the buffer invoked by different processes.
*/
+ mutex_lock(&stream->lock);
WARN_ON(stream->metadata_in < stream->metadata_out);
if (stream->metadata_in != stream->metadata_out)
- return 0;
+ goto end;
len = stream->metadata_cache->metadata_written -
stream->metadata_in;
if (!len)
- return 0;
+ goto end;
reserve_len = min_t(size_t,
stream->transport->ops.packet_avail_size(chan),
len);
ret = reserve_len;
end:
+ mutex_unlock(&stream->lock);
return ret;
}
{
int ret;
+ ret = wrapper_lttng_fixup_sig(THIS_MODULE);
+ if (ret)
+ return ret;
+
+ ret = lttng_tracepoint_init();
+ if (ret)
+ return ret;
event_cache = KMEM_CACHE(lttng_event, 0);
- if (!event_cache)
- return -ENOMEM;
+ if (!event_cache) {
+ ret = -ENOMEM;
+ goto error_kmem;
+ }
ret = lttng_abi_init();
if (ret)
goto error_abi;
+ ret = lttng_logger_init();
+ if (ret)
+ goto error_logger;
return 0;
+
+error_logger:
+ lttng_abi_exit();
error_abi:
kmem_cache_destroy(event_cache);
+error_kmem:
+ lttng_tracepoint_exit();
return ret;
}
{
struct lttng_session *session, *tmpsession;
+ lttng_logger_exit();
lttng_abi_exit();
list_for_each_entry_safe(session, tmpsession, &sessions, list)
lttng_session_destroy(session);
kmem_cache_destroy(event_cache);
+ lttng_tracepoint_exit();
}
module_exit(lttng_events_exit);
MODULE_DESCRIPTION("LTTng Events");
MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "."
__stringify(LTTNG_MODULES_MINOR_VERSION) "."
- __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION));
+ __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION)
+ LTTNG_MODULES_EXTRAVERSION);