Add extra version information framework
[deliverable/lttng-modules.git] / lttng-tracker-id.c
CommitLineData
e0130fab
MD
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>
e0130fab
MD
28#include <linux/hash.h>
29#include <linux/rcupdate.h>
30
241ae9a8
MD
31#include <wrapper/tracepoint.h>
32#include <wrapper/rcu.h>
33#include <wrapper/list.h>
34#include <lttng-events.h>
e0130fab
MD
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 */
6599a4eb 46int lttng_id_tracker_get_node_id(const struct lttng_id_hash_node *node)
7e6f9ef6 47{
6599a4eb 48 return node->id;
7e6f9ef6 49}
e0130fab
MD
50
51/*
52 * Lookup performed from RCU read-side critical section (RCU sched),
53 * protected by preemption off at the tracepoint call site.
6599a4eb 54 * Return true if found, false if not found.
e0130fab 55 */
6599a4eb 56bool lttng_id_tracker_lookup(struct lttng_id_tracker_rcu *p, int id)
e0130fab
MD
57{
58 struct hlist_head *head;
6599a4eb
MD
59 struct lttng_id_hash_node *e;
60 uint32_t hash = hash_32(id, 32);
e0130fab 61
6599a4eb 62 head = &p->id_hash[hash & (LTTNG_ID_TABLE_SIZE - 1)];
7a09dcb7 63 lttng_hlist_for_each_entry_rcu(e, head, hlist) {
6599a4eb
MD
64 if (id == e->id)
65 return true; /* Found */
e0130fab 66 }
6599a4eb
MD
67 return false;
68}
69EXPORT_SYMBOL_GPL(lttng_id_tracker_lookup);
70
71static struct lttng_id_tracker_rcu *lttng_id_tracker_rcu_create(void)
72{
73 struct lttng_id_tracker_rcu *tracker;
74
75 tracker = kzalloc(sizeof(struct lttng_id_tracker_rcu), GFP_KERNEL);
76 if (!tracker)
77 return NULL;
78 return tracker;
e0130fab 79}
e0130fab
MD
80
81/*
82 * Tracker add and del operations support concurrent RCU lookups.
83 */
6599a4eb 84int lttng_id_tracker_add(struct lttng_id_tracker *lf, int id)
e0130fab
MD
85{
86 struct hlist_head *head;
6599a4eb
MD
87 struct lttng_id_hash_node *e;
88 struct lttng_id_tracker_rcu *p = lf->p;
89 uint32_t hash = hash_32(id, 32);
90 bool allocated = false;
e0130fab 91
6599a4eb
MD
92 if (!p) {
93 p = lttng_id_tracker_rcu_create();
94 if (!p)
95 return -ENOMEM;
96 allocated = true;
97 }
98 head = &p->id_hash[hash & (LTTNG_ID_TABLE_SIZE - 1)];
f934e302 99 lttng_hlist_for_each_entry(e, head, hlist) {
6599a4eb 100 if (id == e->id)
e0130fab
MD
101 return -EEXIST;
102 }
6599a4eb 103 e = kmalloc(sizeof(struct lttng_id_hash_node), GFP_KERNEL);
e0130fab
MD
104 if (!e)
105 return -ENOMEM;
6599a4eb 106 e->id = id;
e0130fab 107 hlist_add_head_rcu(&e->hlist, head);
6599a4eb
MD
108 if (allocated) {
109 rcu_assign_pointer(lf->p, p);
110 }
e0130fab
MD
111 return 0;
112}
113
114static
6599a4eb 115void id_tracker_del_node_rcu(struct lttng_id_hash_node *e)
e0130fab
MD
116{
117 hlist_del_rcu(&e->hlist);
118 /*
119 * We choose to use a heavyweight synchronize on removal here,
6599a4eb 120 * since removal of an ID from the tracker mask is a rare
e0130fab 121 * operation, and we don't want to use more cache lines than
6599a4eb 122 * what we really need when doing the ID lookups, so we don't
e0130fab
MD
123 * want to afford adding a rcu_head field to those pid hash
124 * node.
125 */
126 synchronize_trace();
127 kfree(e);
128}
129
130/*
131 * This removal is only used on destroy, so it does not need to support
132 * concurrent RCU lookups.
133 */
134static
6599a4eb 135void id_tracker_del_node(struct lttng_id_hash_node *e)
e0130fab
MD
136{
137 hlist_del(&e->hlist);
138 kfree(e);
139}
140
6599a4eb 141int lttng_id_tracker_del(struct lttng_id_tracker *lf, int id)
e0130fab
MD
142{
143 struct hlist_head *head;
6599a4eb
MD
144 struct lttng_id_hash_node *e;
145 struct lttng_id_tracker_rcu *p = lf->p;
146 uint32_t hash = hash_32(id, 32);
e0130fab 147
6599a4eb
MD
148 if (!p)
149 return -ENOENT;
150 head = &p->id_hash[hash & (LTTNG_ID_TABLE_SIZE - 1)];
e0130fab
MD
151 /*
152 * No need of _safe iteration, because we stop traversal as soon
153 * as we remove the entry.
154 */
f934e302 155 lttng_hlist_for_each_entry(e, head, hlist) {
6599a4eb
MD
156 if (id == e->id) {
157 id_tracker_del_node_rcu(e);
e0130fab
MD
158 return 0;
159 }
160 }
161 return -ENOENT; /* Not found */
162}
163
6599a4eb 164static void lttng_id_tracker_rcu_destroy(struct lttng_id_tracker_rcu *p)
e0130fab
MD
165{
166 int i;
167
6599a4eb
MD
168 if (!p)
169 return;
170 for (i = 0; i < LTTNG_ID_TABLE_SIZE; i++) {
171 struct hlist_head *head = &p->id_hash[i];
172 struct lttng_id_hash_node *e;
e0130fab
MD
173 struct hlist_node *tmp;
174
f934e302 175 lttng_hlist_for_each_entry_safe(e, tmp, head, hlist)
6599a4eb 176 id_tracker_del_node(e);
e0130fab 177 }
6599a4eb
MD
178 kfree(p);
179}
180
181int lttng_id_tracker_empty_set(struct lttng_id_tracker *lf)
182{
183 struct lttng_id_tracker_rcu *p, *oldp;
184
185 p = lttng_id_tracker_rcu_create();
186 if (!p)
187 return -ENOMEM;
188 oldp = lf->p;
189 rcu_assign_pointer(lf->p, p);
190 synchronize_trace();
191 lttng_id_tracker_rcu_destroy(oldp);
192 return 0;
193}
194
195void lttng_id_tracker_destroy(struct lttng_id_tracker *lf, bool rcu)
196{
197 struct lttng_id_tracker_rcu *p = lf->p;
198
199 if (!lf->p)
200 return;
201 rcu_assign_pointer(lf->p, NULL);
202 if (rcu)
203 synchronize_trace();
204 lttng_id_tracker_rcu_destroy(p);
e0130fab 205}
This page took 0.036251 seconds and 5 git commands to generate.