Fix: Add granularity to RHEL kernel version checks
[lttng-modules.git] / lttng-tracker-pid.c
1 /*
2 * lttng-tracker-pid.c
3 *
4 * LTTng Process ID trackering.
5 *
6 * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 #include <linux/err.h>
26 #include <linux/seq_file.h>
27 #include <linux/stringify.h>
28 #include <linux/hash.h>
29 #include <linux/rcupdate.h>
30
31 #include <wrapper/tracepoint.h>
32 #include <wrapper/rcu.h>
33 #include <wrapper/list.h>
34 #include <lttng-events.h>
35
36 /*
37 * Hash table is allocated and freed when there are no possible
38 * concurrent lookups (ensured by the alloc/free caller). However,
39 * there can be concurrent RCU lookups vs add/del operations.
40 *
41 * Concurrent updates of the PID hash table are forbidden: the caller
42 * must ensure mutual exclusion. This is currently done by holding the
43 * sessions_mutex across calls to create, destroy, add, and del
44 * functions of this API.
45 */
46 int lttng_pid_tracker_get_node_pid(const struct lttng_pid_hash_node *node)
47 {
48 return node->pid;
49 }
50
51 /*
52 * Lookup performed from RCU read-side critical section (RCU sched),
53 * protected by preemption off at the tracepoint call site.
54 * Return 1 if found, 0 if not found.
55 */
56 bool lttng_pid_tracker_lookup(struct lttng_pid_tracker *lpf, int pid)
57 {
58 struct hlist_head *head;
59 struct lttng_pid_hash_node *e;
60 uint32_t hash = hash_32(pid, 32);
61
62 head = &lpf->pid_hash[hash & (LTTNG_PID_TABLE_SIZE - 1)];
63 lttng_hlist_for_each_entry_rcu(e, head, hlist) {
64 if (pid == e->pid)
65 return 1; /* Found */
66 }
67 return 0;
68 }
69 EXPORT_SYMBOL_GPL(lttng_pid_tracker_lookup);
70
71 /*
72 * Tracker add and del operations support concurrent RCU lookups.
73 */
74 int lttng_pid_tracker_add(struct lttng_pid_tracker *lpf, int pid)
75 {
76 struct hlist_head *head;
77 struct lttng_pid_hash_node *e;
78 uint32_t hash = hash_32(pid, 32);
79
80 head = &lpf->pid_hash[hash & (LTTNG_PID_TABLE_SIZE - 1)];
81 lttng_hlist_for_each_entry(e, head, hlist) {
82 if (pid == e->pid)
83 return -EEXIST;
84 }
85 e = kmalloc(sizeof(struct lttng_pid_hash_node), GFP_KERNEL);
86 if (!e)
87 return -ENOMEM;
88 e->pid = pid;
89 hlist_add_head_rcu(&e->hlist, head);
90 return 0;
91 }
92
93 static
94 void pid_tracker_del_node_rcu(struct lttng_pid_hash_node *e)
95 {
96 hlist_del_rcu(&e->hlist);
97 /*
98 * We choose to use a heavyweight synchronize on removal here,
99 * since removal of a PID from the tracker mask is a rare
100 * operation, and we don't want to use more cache lines than
101 * what we really need when doing the PID lookups, so we don't
102 * want to afford adding a rcu_head field to those pid hash
103 * node.
104 */
105 synchronize_trace();
106 kfree(e);
107 }
108
109 /*
110 * This removal is only used on destroy, so it does not need to support
111 * concurrent RCU lookups.
112 */
113 static
114 void pid_tracker_del_node(struct lttng_pid_hash_node *e)
115 {
116 hlist_del(&e->hlist);
117 kfree(e);
118 }
119
120 int lttng_pid_tracker_del(struct lttng_pid_tracker *lpf, int pid)
121 {
122 struct hlist_head *head;
123 struct lttng_pid_hash_node *e;
124 uint32_t hash = hash_32(pid, 32);
125
126 head = &lpf->pid_hash[hash & (LTTNG_PID_TABLE_SIZE - 1)];
127 /*
128 * No need of _safe iteration, because we stop traversal as soon
129 * as we remove the entry.
130 */
131 lttng_hlist_for_each_entry(e, head, hlist) {
132 if (pid == e->pid) {
133 pid_tracker_del_node_rcu(e);
134 return 0;
135 }
136 }
137 return -ENOENT; /* Not found */
138 }
139
140 struct lttng_pid_tracker *lttng_pid_tracker_create(void)
141 {
142 return kzalloc(sizeof(struct lttng_pid_tracker), GFP_KERNEL);
143 }
144
145 void lttng_pid_tracker_destroy(struct lttng_pid_tracker *lpf)
146 {
147 int i;
148
149 for (i = 0; i < LTTNG_PID_TABLE_SIZE; i++) {
150 struct hlist_head *head = &lpf->pid_hash[i];
151 struct lttng_pid_hash_node *e;
152 struct hlist_node *tmp;
153
154 lttng_hlist_for_each_entry_safe(e, tmp, head, hlist)
155 pid_tracker_del_node(e);
156 }
157 kfree(lpf);
158 }
This page took 0.046985 seconds and 4 git commands to generate.