Implement PID tracking
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Sat, 27 Sep 2014 20:20:31 +0000 (16:20 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 31 Mar 2015 18:34:02 +0000 (14:34 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Makefile
lttng-abi.c
lttng-abi.h
lttng-events.c
lttng-events.h
lttng-tracker-pid.c [new file with mode: 0644]
probes/lttng-events.h

index eeffdfe976b6e51296373c65e59703906341da20..23049ca34582b5e3f22e5b28465145c6111319c2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,8 @@ lttng-tracer-objs :=  lttng-events.o lttng-abi.o \
                        lttng-context-vtid.o lttng-context-ppid.o \
                        lttng-context-vppid.o lttng-calibrate.o \
                        lttng-context-hostname.o wrapper/random.o \
-                       probes/lttng.o wrapper/trace-clock.o
+                       probes/lttng.o wrapper/trace-clock.o \
+                       lttng-tracker-pid.o
 
 obj-m += lttng-statedump.o
 lttng-statedump-objs := lttng-statedump-impl.o wrapper/irqdesc.o \
index 5823a1db042d6fa8aa5e88bef4a35235bf5eea4e..f3d98fc1fd561fc4244854bcc4d3396bdfbcbabf 100644 (file)
@@ -423,6 +423,10 @@ fd_error:
  *             Disables tracing for a session (strong disable)
  *     LTTNG_KERNEL_METADATA
  *             Returns a LTTng metadata file descriptor
+ *     LTTNG_KERNEL_SESSION_TRACK_PID
+ *             Add PID to session tracker
+ *     LTTNG_KERNEL_SESSION_UNTRACK_PID
+ *             Remove PID from session tracker
  *
  * The returned channel will be deleted when its file descriptor is closed.
  */
@@ -502,6 +506,10 @@ long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return lttng_abi_create_channel(file, &chan_param,
                                METADATA_CHANNEL);
        }
+       case LTTNG_KERNEL_SESSION_TRACK_PID:
+               return lttng_session_track_pid(session, (int) arg);
+       case LTTNG_KERNEL_SESSION_UNTRACK_PID:
+               return lttng_session_untrack_pid(session, (int) arg);
        default:
                return -ENOIOCTLCMD;
        }
index b63ead8d134c636838bf38baa9b3e2dcdf62879f..bcea06e33b1cf3f2cb916711ca127b9d31e212b6 100644 (file)
@@ -185,6 +185,10 @@ struct lttng_kernel_context {
        _IOW(0xF6, 0x55, struct lttng_kernel_channel)
 #define LTTNG_KERNEL_SESSION_START             _IO(0xF6, 0x56)
 #define LTTNG_KERNEL_SESSION_STOP              _IO(0xF6, 0x57)
+#define LTTNG_KERNEL_SESSION_TRACK_PID         \
+       _IOR(0xF6, 0x58, int32_t)
+#define LTTNG_KERNEL_SESSION_UNTRACK_PID       \
+       _IOR(0xF6, 0x59, int32_t)
 
 /* Channel FD ioctl */
 #define LTTNG_KERNEL_STREAM                    _IO(0xF6, 0x62)
index 135c8c527123acd43266c7191148d9bc314121a8..8a48c6b5dc6f094132b24ed7640415a6cbd74ae1 100644 (file)
@@ -147,6 +147,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 +588,78 @@ 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;
+}
+
 /*
  * Serialize at most one packet worth of metadata into a metadata
  * channel.
index 118ea3b0db52d82e6072e17aa901c1850e22e43c..7d3314590384906fbd95b2406f593c59d1806cd0 100644 (file)
@@ -324,6 +324,18 @@ struct lttng_metadata_stream {
        struct mutex lock;
 };
 
+
+/*
+ * struct lttng_pid_tracker declared in header due to deferencing of *v
+ * in RCU_INITIALIZER(v).
+ */
+#define LTTNG_PID_HASH_BITS    6
+#define LTTNG_PID_TABLE_SIZE   (1 << LTTNG_PID_HASH_BITS)
+
+struct lttng_pid_tracker {
+       struct hlist_head pid_hash[LTTNG_PID_TABLE_SIZE];
+};
+
 struct lttng_session {
        int active;                     /* Is trace session active ? */
        int been_active;                /* Has trace session been active ? */
@@ -334,6 +346,7 @@ struct lttng_session {
        unsigned int free_chan_id;      /* Next chan ID to allocate */
        uuid_le uuid;                   /* Trace session unique ID */
        struct lttng_metadata_cache *metadata_cache;
+       struct lttng_pid_tracker *pid_tracker;
        unsigned int metadata_dumped:1;
 };
 
@@ -399,6 +412,15 @@ void lttng_probes_exit(void);
 int lttng_metadata_output_channel(struct lttng_metadata_stream *stream,
                struct channel *chan);
 
+struct lttng_pid_tracker *lttng_pid_tracker_create(void);
+void lttng_pid_tracker_destroy(struct lttng_pid_tracker *lpf);
+bool lttng_pid_tracker_lookup(struct lttng_pid_tracker *lpf, int pid);
+int lttng_pid_tracker_add(struct lttng_pid_tracker *lpf, int pid);
+int lttng_pid_tracker_del(struct lttng_pid_tracker *lpf, int pid);
+
+int lttng_session_track_pid(struct lttng_session *session, int pid);
+int lttng_session_untrack_pid(struct lttng_session *session, int pid);
+
 #if defined(CONFIG_HAVE_SYSCALL_TRACEPOINTS)
 int lttng_syscalls_register(struct lttng_channel *chan, void *filter);
 int lttng_syscalls_unregister(struct lttng_channel *chan);
diff --git a/lttng-tracker-pid.c b/lttng-tracker-pid.c
new file mode 100644 (file)
index 0000000..f8f0a51
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * lttng-tracker-pid.c
+ *
+ * LTTng Process ID trackering.
+ *
+ * Copyright (C) 2014 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/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/seq_file.h>
+#include <linux/stringify.h>
+#include <linux/rculist.h>
+#include <linux/hash.h>
+#include <linux/rcupdate.h>
+
+#include "wrapper/tracepoint.h"
+#include "lttng-events.h"
+
+/*
+ * Hash table is allocated and freed when there are no possible
+ * concurrent lookups (ensured by the alloc/free caller). However,
+ * there can be concurrent RCU lookups vs add/del operations.
+ *
+ * Concurrent updates of the PID hash table are forbidden: the caller
+ * must ensure mutual exclusion. This is currently done by holding the
+ * sessions_mutex across calls to create, destroy, add, and del
+ * functions of this API.
+ */
+struct lttng_pid_hash_node {
+       struct hlist_node hlist;
+       int pid;
+};
+
+/*
+ * Lookup performed from RCU read-side critical section (RCU sched),
+ * protected by preemption off at the tracepoint call site.
+ * Return 1 if found, 0 if not found.
+ */
+bool lttng_pid_tracker_lookup(struct lttng_pid_tracker *lpf, int pid)
+{
+       struct hlist_head *head;
+       struct lttng_pid_hash_node *e;
+       uint32_t hash = hash_32(pid, 32);
+
+       head = &lpf->pid_hash[hash & (LTTNG_PID_TABLE_SIZE - 1)];
+       hlist_for_each_entry_rcu_notrace(e, head, hlist) {
+               if (pid == e->pid)
+                       return 1;       /* Found */
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lttng_pid_tracker_lookup);
+
+/*
+ * Tracker add and del operations support concurrent RCU lookups.
+ */
+int lttng_pid_tracker_add(struct lttng_pid_tracker *lpf, int pid)
+{
+       struct hlist_head *head;
+       struct lttng_pid_hash_node *e;
+       uint32_t hash = hash_32(pid, 32);
+
+       head = &lpf->pid_hash[hash & (LTTNG_PID_TABLE_SIZE - 1)];
+       hlist_for_each_entry(e, head, hlist) {
+               if (pid == e->pid)
+                       return -EEXIST;
+       }
+       e = kmalloc(sizeof(struct lttng_pid_hash_node), GFP_KERNEL);
+       if (!e)
+               return -ENOMEM;
+       e->pid = pid;
+       hlist_add_head_rcu(&e->hlist, head);
+       return 0;
+}
+
+static
+void pid_tracker_del_node_rcu(struct lttng_pid_hash_node *e)
+{
+       hlist_del_rcu(&e->hlist);
+       /*
+        * We choose to use a heavyweight synchronize on removal here,
+        * since removal of a PID from the tracker mask is a rare
+        * operation, and we don't want to use more cache lines than
+        * what we really need when doing the PID lookups, so we don't
+        * want to afford adding a rcu_head field to those pid hash
+        * node.
+        */
+       synchronize_trace();
+       kfree(e);
+}
+
+/*
+ * This removal is only used on destroy, so it does not need to support
+ * concurrent RCU lookups.
+ */
+static
+void pid_tracker_del_node(struct lttng_pid_hash_node *e)
+{
+       hlist_del(&e->hlist);
+       kfree(e);
+}
+
+int lttng_pid_tracker_del(struct lttng_pid_tracker *lpf, int pid)
+{
+       struct hlist_head *head;
+       struct lttng_pid_hash_node *e;
+       uint32_t hash = hash_32(pid, 32);
+
+       head = &lpf->pid_hash[hash & (LTTNG_PID_TABLE_SIZE - 1)];
+       /*
+        * No need of _safe iteration, because we stop traversal as soon
+        * as we remove the entry.
+        */
+       hlist_for_each_entry(e, head, hlist) {
+               if (pid == e->pid) {
+                       pid_tracker_del_node_rcu(e);
+                       return 0;
+               }
+       }
+       return -ENOENT; /* Not found */
+}
+
+struct lttng_pid_tracker *lttng_pid_tracker_create(void)
+{
+       return kzalloc(sizeof(struct lttng_pid_tracker), GFP_KERNEL);
+}
+
+void lttng_pid_tracker_destroy(struct lttng_pid_tracker *lpf)
+{
+       int i;
+
+       for (i = 0; i < LTTNG_PID_TABLE_SIZE; i++) {
+               struct hlist_head *head = &lpf->pid_hash[i];
+               struct lttng_pid_hash_node *e;
+               struct hlist_node *tmp;
+
+               hlist_for_each_entry_safe(e, tmp, head, hlist)
+                       pid_tracker_del_node(e);
+       }
+       kfree(lpf);
+}
index 22cabbaa50a996b5acc5733e76b2d4ea97478254..b885fa1831e0fdc5704fbaa1e593c9212ea42154 100644 (file)
@@ -837,6 +837,7 @@ static void __event_probe__##_name(void *__data, _proto)                  \
        struct probe_local_vars { _locvar };                                  \
        struct lttng_event *__event = __data;                                 \
        struct lttng_channel *__chan = __event->chan;                         \
+       struct lttng_session *__session = __chan->session;                    \
        struct lib_ring_buffer_ctx __ctx;                                     \
        size_t __event_len, __event_align;                                    \
        size_t __dynamic_len_idx __attribute__((unused)) = 0;                 \
@@ -846,15 +847,19 @@ static void __event_probe__##_name(void *__data, _proto)                \
        struct probe_local_vars __tp_locvar;                                  \
        struct probe_local_vars *tp_locvar __attribute__((unused)) =          \
                        &__tp_locvar;                                         \
+       struct lttng_pid_tracker *__lpf;                                      \
                                                                              \
-       if (!_TP_SESSION_CHECK(session, __chan->session))                     \
+       if (!_TP_SESSION_CHECK(session, __session))                           \
                return;                                                       \
-       if (unlikely(!ACCESS_ONCE(__chan->session->active)))                  \
+       if (unlikely(!ACCESS_ONCE(__session->active)))                        \
                return;                                                       \
        if (unlikely(!ACCESS_ONCE(__chan->enabled)))                          \
                return;                                                       \
        if (unlikely(!ACCESS_ONCE(__event->enabled)))                         \
                return;                                                       \
+       __lpf = rcu_dereference(__session->pid_tracker);                      \
+       if (__lpf && likely(!lttng_pid_tracker_lookup(__lpf, current->pid)))  \
+               return;                                                       \
        _code                                                                 \
        __event_len = __event_get_size__##_name(__dynamic_len, tp_locvar,     \
                                _args);                                       \
@@ -879,6 +884,7 @@ static void __event_probe__##_name(void *__data)                          \
        struct probe_local_vars { _locvar };                                  \
        struct lttng_event *__event = __data;                                 \
        struct lttng_channel *__chan = __event->chan;                         \
+       struct lttng_session *__session = __chan->session;                    \
        struct lib_ring_buffer_ctx __ctx;                                     \
        size_t __event_len, __event_align;                                    \
        size_t __dynamic_len_idx __attribute__((unused)) = 0;                 \
@@ -888,15 +894,19 @@ static void __event_probe__##_name(void *__data)                        \
        struct probe_local_vars __tp_locvar;                                  \
        struct probe_local_vars *tp_locvar __attribute__((unused)) =          \
                        &__tp_locvar;                                         \
+       struct lttng_pid_tracker *__lpf;                                      \
                                                                              \
-       if (!_TP_SESSION_CHECK(session, __chan->session))                     \
+       if (!_TP_SESSION_CHECK(session, __session))                           \
                return;                                                       \
-       if (unlikely(!ACCESS_ONCE(__chan->session->active)))                  \
+       if (unlikely(!ACCESS_ONCE(__session->active)))                        \
                return;                                                       \
        if (unlikely(!ACCESS_ONCE(__chan->enabled)))                          \
                return;                                                       \
        if (unlikely(!ACCESS_ONCE(__event->enabled)))                         \
                return;                                                       \
+       __lpf = rcu_dereference(__session->pid_tracker);                      \
+       if (__lpf && likely(!lttng_pid_tracker_lookup(__lpf, current->pid)))  \
+               return;                                                       \
        _code                                                                 \
        __event_len = __event_get_size__##_name(__dynamic_len, tp_locvar);    \
        __event_align = __event_get_align__##_name(tp_locvar);                \
This page took 0.033722 seconds and 4 git commands to generate.