wrapper: remove tracepoint wrapper
[lttng-modules.git] / lttng-tracker-id.c
1 /* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
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/rcu.h>
19 #include <wrapper/list.h>
20 #include <lttng-events.h>
21
22 /*
23 * Hash table is allocated and freed when there are no possible
24 * concurrent lookups (ensured by the alloc/free caller). However,
25 * there can be concurrent RCU lookups vs add/del operations.
26 *
27 * Concurrent updates of the PID hash table are forbidden: the caller
28 * must ensure mutual exclusion. This is currently done by holding the
29 * sessions_mutex across calls to create, destroy, add, and del
30 * functions of this API.
31 */
32 int lttng_id_tracker_get_node_id(const struct lttng_id_hash_node *node)
33 {
34 return node->id;
35 }
36
37 /*
38 * Lookup performed from RCU read-side critical section (RCU sched),
39 * protected by preemption off at the tracepoint call site.
40 * Return true if found, false if not found.
41 */
42 bool lttng_id_tracker_lookup(struct lttng_id_tracker_rcu *p, int id)
43 {
44 struct hlist_head *head;
45 struct lttng_id_hash_node *e;
46 uint32_t hash = hash_32(id, 32);
47
48 head = &p->id_hash[hash & (LTTNG_ID_TABLE_SIZE - 1)];
49 lttng_hlist_for_each_entry_rcu(e, head, hlist) {
50 if (id == e->id)
51 return true; /* Found */
52 }
53 return false;
54 }
55 EXPORT_SYMBOL_GPL(lttng_id_tracker_lookup);
56
57 static struct lttng_id_tracker_rcu *lttng_id_tracker_rcu_create(void)
58 {
59 struct lttng_id_tracker_rcu *tracker;
60
61 tracker = kzalloc(sizeof(struct lttng_id_tracker_rcu), GFP_KERNEL);
62 if (!tracker)
63 return NULL;
64 return tracker;
65 }
66
67 /*
68 * Tracker add and del operations support concurrent RCU lookups.
69 */
70 int lttng_id_tracker_add(struct lttng_id_tracker *lf, int id)
71 {
72 struct hlist_head *head;
73 struct lttng_id_hash_node *e;
74 struct lttng_id_tracker_rcu *p = lf->p;
75 uint32_t hash = hash_32(id, 32);
76 bool allocated = false;
77
78 if (!p) {
79 p = lttng_id_tracker_rcu_create();
80 if (!p)
81 return -ENOMEM;
82 allocated = true;
83 }
84 head = &p->id_hash[hash & (LTTNG_ID_TABLE_SIZE - 1)];
85 lttng_hlist_for_each_entry(e, head, hlist) {
86 if (id == e->id)
87 return -EEXIST;
88 }
89 e = kmalloc(sizeof(struct lttng_id_hash_node), GFP_KERNEL);
90 if (!e)
91 return -ENOMEM;
92 e->id = id;
93 hlist_add_head_rcu(&e->hlist, head);
94 if (allocated) {
95 rcu_assign_pointer(lf->p, p);
96 }
97 return 0;
98 }
99
100 static
101 void id_tracker_del_node_rcu(struct lttng_id_hash_node *e)
102 {
103 hlist_del_rcu(&e->hlist);
104 /*
105 * We choose to use a heavyweight synchronize on removal here,
106 * since removal of an ID from the tracker mask is a rare
107 * operation, and we don't want to use more cache lines than
108 * what we really need when doing the ID lookups, so we don't
109 * want to afford adding a rcu_head field to those pid hash
110 * node.
111 */
112 synchronize_trace();
113 kfree(e);
114 }
115
116 /*
117 * This removal is only used on destroy, so it does not need to support
118 * concurrent RCU lookups.
119 */
120 static
121 void id_tracker_del_node(struct lttng_id_hash_node *e)
122 {
123 hlist_del(&e->hlist);
124 kfree(e);
125 }
126
127 int lttng_id_tracker_del(struct lttng_id_tracker *lf, int id)
128 {
129 struct hlist_head *head;
130 struct lttng_id_hash_node *e;
131 struct lttng_id_tracker_rcu *p = lf->p;
132 uint32_t hash = hash_32(id, 32);
133
134 if (!p)
135 return -ENOENT;
136 head = &p->id_hash[hash & (LTTNG_ID_TABLE_SIZE - 1)];
137 /*
138 * No need of _safe iteration, because we stop traversal as soon
139 * as we remove the entry.
140 */
141 lttng_hlist_for_each_entry(e, head, hlist) {
142 if (id == e->id) {
143 id_tracker_del_node_rcu(e);
144 return 0;
145 }
146 }
147 return -ENOENT; /* Not found */
148 }
149
150 static void lttng_id_tracker_rcu_destroy(struct lttng_id_tracker_rcu *p)
151 {
152 int i;
153
154 if (!p)
155 return;
156 for (i = 0; i < LTTNG_ID_TABLE_SIZE; i++) {
157 struct hlist_head *head = &p->id_hash[i];
158 struct lttng_id_hash_node *e;
159 struct hlist_node *tmp;
160
161 lttng_hlist_for_each_entry_safe(e, tmp, head, hlist)
162 id_tracker_del_node(e);
163 }
164 kfree(p);
165 }
166
167 int lttng_id_tracker_empty_set(struct lttng_id_tracker *lf)
168 {
169 struct lttng_id_tracker_rcu *p, *oldp;
170
171 p = lttng_id_tracker_rcu_create();
172 if (!p)
173 return -ENOMEM;
174 oldp = lf->p;
175 rcu_assign_pointer(lf->p, p);
176 synchronize_trace();
177 lttng_id_tracker_rcu_destroy(oldp);
178 return 0;
179 }
180
181 void lttng_id_tracker_destroy(struct lttng_id_tracker *lf, bool rcu)
182 {
183 struct lttng_id_tracker_rcu *p = lf->p;
184
185 if (!lf->p)
186 return;
187 rcu_assign_pointer(lf->p, NULL);
188 if (rcu)
189 synchronize_trace();
190 lttng_id_tracker_rcu_destroy(p);
191 }
This page took 0.031983 seconds and 4 git commands to generate.