Implement list.h wrapper for hlist in older kernels
[lttng-modules.git] / lttng-events.c
index 135c8c527123acd43266c7191148d9bc314121a8..7055c3ed05af5f812edf319d8d7323a93b4a3c84 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #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"
 #include "wrapper/tracepoint.h"
+#include "wrapper/list.h"
 #include "lttng-kernel-version.h"
 #include "lttng-events.h"
 #include "lttng-tracer.h"
@@ -147,6 +151,8 @@ void lttng_session_destroy(struct lttng_session *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);
@@ -586,6 +592,235 @@ void _lttng_event_destroy(struct lttng_event *event)
        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];
+
+                       lttng_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];
+
+                       lttng_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, &lttng_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]",
+                                         &lttng_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.
This page took 0.025454 seconds and 4 git commands to generate.