Split ID tracker into public/private structures
[lttng-modules.git] / src / lttng-tracker-id.c
CommitLineData
b7cdc182 1/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
d1f652f8
MD
2 *
3 * lttng-tracker-pid.c
4 *
5 * LTTng Process ID tracking.
6 *
7 * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 */
9
10#include <linux/module.h>
11#include <linux/slab.h>
12#include <linux/err.h>
13#include <linux/seq_file.h>
14#include <linux/stringify.h>
15#include <linux/hash.h>
16#include <linux/rcupdate.h>
17
18#include <wrapper/tracepoint.h>
19#include <wrapper/rcu.h>
20#include <wrapper/list.h>
2df37e95 21#include <lttng/events.h>
e8c0bbd3 22#include <lttng/events-internal.h>
d1f652f8
MD
23
24/*
25 * Hash table is allocated and freed when there are no possible
26 * concurrent lookups (ensured by the alloc/free caller). However,
27 * there can be concurrent RCU lookups vs add/del operations.
28 *
29 * Concurrent updates of the PID hash table are forbidden: the caller
30 * must ensure mutual exclusion. This is currently done by holding the
31 * sessions_mutex across calls to create, destroy, add, and del
32 * functions of this API.
33 */
34int lttng_id_tracker_get_node_id(const struct lttng_id_hash_node *node)
35{
36 return node->id;
37}
38
39/*
40 * Lookup performed from RCU read-side critical section (RCU sched),
41 * protected by preemption off at the tracepoint call site.
42 * Return true if found, false if not found.
43 */
8c0393c3 44bool lttng_id_tracker_lookup(struct lttng_kernel_id_tracker_rcu *p, int id)
d1f652f8
MD
45{
46 struct hlist_head *head;
47 struct lttng_id_hash_node *e;
48 uint32_t hash = hash_32(id, 32);
49
50 head = &p->id_hash[hash & (LTTNG_ID_TABLE_SIZE - 1)];
51 lttng_hlist_for_each_entry_rcu(e, head, hlist) {
52 if (id == e->id)
53 return true; /* Found */
54 }
55 return false;
56}
57EXPORT_SYMBOL_GPL(lttng_id_tracker_lookup);
58
8c0393c3 59static struct lttng_kernel_id_tracker_rcu *lttng_id_tracker_rcu_create(void)
d1f652f8 60{
8c0393c3 61 struct lttng_kernel_id_tracker_rcu *tracker;
d1f652f8 62
8c0393c3 63 tracker = kzalloc(sizeof(struct lttng_kernel_id_tracker_rcu), GFP_KERNEL);
d1f652f8
MD
64 if (!tracker)
65 return NULL;
66 return tracker;
67}
68
69/*
70 * Tracker add and del operations support concurrent RCU lookups.
71 */
8c0393c3 72int lttng_id_tracker_add(struct lttng_kernel_id_tracker *lf, int id)
d1f652f8
MD
73{
74 struct hlist_head *head;
75 struct lttng_id_hash_node *e;
8c0393c3 76 struct lttng_kernel_id_tracker_rcu *p = lf->p;
d1f652f8
MD
77 uint32_t hash = hash_32(id, 32);
78 bool allocated = false;
88533d65 79 int ret;
d1f652f8
MD
80
81 if (!p) {
82 p = lttng_id_tracker_rcu_create();
83 if (!p)
84 return -ENOMEM;
85 allocated = true;
86 }
87 head = &p->id_hash[hash & (LTTNG_ID_TABLE_SIZE - 1)];
88 lttng_hlist_for_each_entry(e, head, hlist) {
88533d65
MD
89 if (id == e->id) {
90 ret = -EEXIST;
91 goto error;
92 }
d1f652f8
MD
93 }
94 e = kmalloc(sizeof(struct lttng_id_hash_node), GFP_KERNEL);
88533d65
MD
95 if (!e) {
96 ret = -ENOMEM;
97 goto error;
98 }
d1f652f8
MD
99 e->id = id;
100 hlist_add_head_rcu(&e->hlist, head);
101 if (allocated) {
102 rcu_assign_pointer(lf->p, p);
103 }
104 return 0;
88533d65
MD
105
106error:
107 if (allocated) {
108 kfree(p);
109 }
110 return ret;
d1f652f8
MD
111}
112
113static
114void id_tracker_del_node_rcu(struct lttng_id_hash_node *e)
115{
116 hlist_del_rcu(&e->hlist);
117 /*
118 * We choose to use a heavyweight synchronize on removal here,
119 * since removal of an ID from the tracker mask is a rare
120 * operation, and we don't want to use more cache lines than
121 * what we really need when doing the ID lookups, so we don't
122 * want to afford adding a rcu_head field to those pid hash
123 * node.
124 */
125 synchronize_trace();
126 kfree(e);
127}
128
129/*
130 * This removal is only used on destroy, so it does not need to support
131 * concurrent RCU lookups.
132 */
133static
134void id_tracker_del_node(struct lttng_id_hash_node *e)
135{
136 hlist_del(&e->hlist);
137 kfree(e);
138}
139
8c0393c3 140int lttng_id_tracker_del(struct lttng_kernel_id_tracker *lf, int id)
d1f652f8
MD
141{
142 struct hlist_head *head;
143 struct lttng_id_hash_node *e;
8c0393c3 144 struct lttng_kernel_id_tracker_rcu *p = lf->p;
d1f652f8
MD
145 uint32_t hash = hash_32(id, 32);
146
147 if (!p)
148 return -ENOENT;
149 head = &p->id_hash[hash & (LTTNG_ID_TABLE_SIZE - 1)];
150 /*
151 * No need of _safe iteration, because we stop traversal as soon
152 * as we remove the entry.
153 */
154 lttng_hlist_for_each_entry(e, head, hlist) {
155 if (id == e->id) {
156 id_tracker_del_node_rcu(e);
157 return 0;
158 }
159 }
160 return -ENOENT; /* Not found */
161}
162
8c0393c3 163static void lttng_id_tracker_rcu_destroy(struct lttng_kernel_id_tracker_rcu *p)
d1f652f8
MD
164{
165 int i;
166
167 if (!p)
168 return;
169 for (i = 0; i < LTTNG_ID_TABLE_SIZE; i++) {
170 struct hlist_head *head = &p->id_hash[i];
171 struct lttng_id_hash_node *e;
172 struct hlist_node *tmp;
173
174 lttng_hlist_for_each_entry_safe(e, tmp, head, hlist)
175 id_tracker_del_node(e);
176 }
177 kfree(p);
178}
179
8c0393c3 180int lttng_id_tracker_empty_set(struct lttng_kernel_id_tracker *lf)
d1f652f8 181{
8c0393c3 182 struct lttng_kernel_id_tracker_rcu *p, *oldp;
d1f652f8
MD
183
184 p = lttng_id_tracker_rcu_create();
185 if (!p)
186 return -ENOMEM;
187 oldp = lf->p;
188 rcu_assign_pointer(lf->p, p);
189 synchronize_trace();
190 lttng_id_tracker_rcu_destroy(oldp);
191 return 0;
192}
193
8c0393c3
MD
194int lttng_id_tracker_init(struct lttng_kernel_id_tracker *lf,
195 struct lttng_kernel_session *session,
196 enum tracker_type type)
d1f652f8 197{
8c0393c3
MD
198 lf->priv = kzalloc(sizeof(*lf->priv), GFP_KERNEL);
199 if (!lf->priv)
200 return -ENOMEM;
201 lf->priv->session = session;
202 lf->priv->tracker_type = type;
203 return 0;
204}
205
206void lttng_id_tracker_destroy(struct lttng_kernel_id_tracker *lf, bool rcu)
207{
208 struct lttng_kernel_id_tracker_rcu *p = lf->p;
d1f652f8 209
8c0393c3 210 if (!p)
d1f652f8
MD
211 return;
212 rcu_assign_pointer(lf->p, NULL);
213 if (rcu)
214 synchronize_trace();
215 lttng_id_tracker_rcu_destroy(p);
216}
8c0393c3
MD
217
218void lttng_id_tracker_fini(struct lttng_kernel_id_tracker *lf)
219{
220 if (!lf)
221 return;
222 lttng_id_tracker_destroy(lf, false);
223 kfree(lf->priv);
224}
This page took 0.042421 seconds and 4 git commands to generate.