Commit | Line | Data |
---|---|---|
a8c3ad3e | 1 | /* |
ab5be9fa | 2 | * Copyright (C) 2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
159b042f | 3 | * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com> |
a8c3ad3e | 4 | * |
ab5be9fa | 5 | * SPDX-License-Identifier: GPL-2.0-only |
a8c3ad3e | 6 | * |
a8c3ad3e MD |
7 | */ |
8 | ||
159b042f JG |
9 | #include "lttng/tracker.h" |
10 | #include "common/dynamic-array.h" | |
11 | #include "common/macros.h" | |
a8c3ad3e MD |
12 | #define _LGPL_SOURCE |
13 | #include <grp.h> | |
14 | #include <pwd.h> | |
15 | #include <sys/types.h> | |
16 | #include <unistd.h> | |
159b042f JG |
17 | #include <urcu.h> |
18 | #include <urcu/list.h> | |
19 | #include <urcu/rculfhash.h> | |
a8c3ad3e MD |
20 | |
21 | #include "tracker.h" | |
22 | #include <common/defaults.h> | |
23 | #include <common/error.h> | |
24 | #include <common/hashtable/hashtable.h> | |
25 | #include <common/hashtable/utils.h> | |
159b042f | 26 | #include <common/tracker.h> |
a8c3ad3e MD |
27 | #include <lttng/lttng-error.h> |
28 | ||
159b042f JG |
29 | struct process_attr_tracker_value_node { |
30 | struct process_attr_value *value; | |
31 | struct cds_lfht_node inclusion_set_ht_node; | |
32 | struct rcu_head rcu_head; | |
33 | }; | |
a8c3ad3e | 34 | |
159b042f JG |
35 | struct process_attr_tracker { |
36 | enum lttng_tracking_policy policy; | |
37 | struct cds_lfht *inclusion_set_ht; | |
38 | }; | |
39 | ||
40 | static void process_attr_tracker_value_node_rcu_free(struct rcu_head *rcu_head) | |
41 | { | |
42 | struct process_attr_tracker_value_node *node = | |
43 | container_of(rcu_head, typeof(*node), rcu_head); | |
44 | ||
45 | free(node); | |
46 | } | |
47 | ||
48 | struct process_attr_tracker *process_attr_tracker_create(void) | |
a8c3ad3e | 49 | { |
159b042f | 50 | struct process_attr_tracker *tracker; |
a8c3ad3e | 51 | |
159b042f JG |
52 | tracker = zmalloc(sizeof(*tracker)); |
53 | if (!tracker) { | |
a8c3ad3e MD |
54 | return NULL; |
55 | } | |
159b042f JG |
56 | |
57 | (void) process_attr_tracker_set_tracking_policy( | |
58 | tracker, LTTNG_TRACKING_POLICY_INCLUDE_ALL); | |
59 | ||
60 | tracker->inclusion_set_ht = cds_lfht_new(DEFAULT_HT_SIZE, 1, 0, | |
a8c3ad3e | 61 | CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL); |
159b042f | 62 | if (!tracker->inclusion_set_ht) { |
a8c3ad3e MD |
63 | goto error; |
64 | } | |
a8c3ad3e | 65 | |
159b042f | 66 | return tracker; |
a8c3ad3e | 67 | error: |
159b042f | 68 | process_attr_tracker_destroy(tracker); |
a8c3ad3e MD |
69 | return NULL; |
70 | } | |
71 | ||
159b042f JG |
72 | static void process_attr_tracker_remove_value_node( |
73 | struct process_attr_tracker *tracker, | |
74 | struct process_attr_tracker_value_node *value_node) | |
a8c3ad3e | 75 | { |
159b042f JG |
76 | cds_lfht_del(tracker->inclusion_set_ht, |
77 | &value_node->inclusion_set_ht_node); | |
78 | process_attr_value_destroy(value_node->value); | |
79 | call_rcu(&value_node->rcu_head, | |
80 | process_attr_tracker_value_node_rcu_free); | |
a8c3ad3e MD |
81 | } |
82 | ||
159b042f JG |
83 | static void process_attr_tracker_clear_inclusion_set( |
84 | struct process_attr_tracker *tracker) | |
a8c3ad3e | 85 | { |
159b042f JG |
86 | int ret; |
87 | struct lttng_ht_iter iter; | |
88 | struct process_attr_tracker_value_node *value_node; | |
a8c3ad3e | 89 | |
159b042f JG |
90 | if (!tracker->inclusion_set_ht) { |
91 | return; | |
92 | } | |
a8c3ad3e | 93 | |
159b042f JG |
94 | rcu_read_lock(); |
95 | cds_lfht_for_each_entry (tracker->inclusion_set_ht, &iter.iter, | |
96 | value_node, inclusion_set_ht_node) { | |
97 | process_attr_tracker_remove_value_node(tracker, value_node); | |
a8c3ad3e | 98 | } |
159b042f JG |
99 | rcu_read_unlock(); |
100 | ret = cds_lfht_destroy(tracker->inclusion_set_ht, NULL); | |
101 | assert(ret == 0); | |
102 | tracker->inclusion_set_ht = NULL; | |
a8c3ad3e MD |
103 | } |
104 | ||
159b042f JG |
105 | static int process_attr_tracker_create_inclusion_set( |
106 | struct process_attr_tracker *tracker) | |
a8c3ad3e | 107 | { |
159b042f JG |
108 | assert(!tracker->inclusion_set_ht); |
109 | tracker->inclusion_set_ht = cds_lfht_new(DEFAULT_HT_SIZE, 1, 0, | |
110 | CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL); | |
111 | return tracker->inclusion_set_ht ? 0 : -1; | |
a8c3ad3e MD |
112 | } |
113 | ||
159b042f | 114 | void process_attr_tracker_destroy(struct process_attr_tracker *tracker) |
a8c3ad3e | 115 | { |
159b042f JG |
116 | if (!tracker) { |
117 | return; | |
118 | } | |
a8c3ad3e | 119 | |
159b042f JG |
120 | process_attr_tracker_clear_inclusion_set(tracker); |
121 | free(tracker); | |
a8c3ad3e MD |
122 | } |
123 | ||
159b042f JG |
124 | enum lttng_tracking_policy process_attr_tracker_get_tracking_policy( |
125 | const struct process_attr_tracker *tracker) | |
a8c3ad3e | 126 | { |
159b042f | 127 | return tracker->policy; |
a8c3ad3e MD |
128 | } |
129 | ||
159b042f JG |
130 | int process_attr_tracker_set_tracking_policy( |
131 | struct process_attr_tracker *tracker, | |
132 | enum lttng_tracking_policy tracking_policy) | |
a8c3ad3e | 133 | { |
159b042f | 134 | int ret = 0; |
a8c3ad3e | 135 | |
159b042f JG |
136 | if (tracker->policy == tracking_policy) { |
137 | goto end; | |
a8c3ad3e | 138 | } |
2d97a006 | 139 | |
159b042f JG |
140 | process_attr_tracker_clear_inclusion_set(tracker); |
141 | ret = process_attr_tracker_create_inclusion_set(tracker); | |
142 | if (ret) { | |
143 | goto end; | |
a8c3ad3e | 144 | } |
159b042f JG |
145 | tracker->policy = tracking_policy; |
146 | end: | |
a8c3ad3e MD |
147 | return ret; |
148 | } | |
149 | ||
159b042f JG |
150 | static int match_inclusion_set_value( |
151 | struct cds_lfht_node *node, const void *key) | |
a8c3ad3e | 152 | { |
159b042f JG |
153 | const struct process_attr_value *value_key = key; |
154 | const struct process_attr_tracker_value_node *value_node = | |
155 | caa_container_of(node, | |
156 | struct process_attr_tracker_value_node, | |
157 | inclusion_set_ht_node); | |
a8c3ad3e | 158 | |
159b042f JG |
159 | return process_attr_tracker_value_equal(value_node->value, value_key); |
160 | } | |
a8c3ad3e | 161 | |
159b042f JG |
162 | static struct process_attr_tracker_value_node *process_attr_tracker_lookup( |
163 | const struct process_attr_tracker *tracker, | |
164 | const struct process_attr_value *value) | |
165 | { | |
166 | struct cds_lfht_iter iter; | |
167 | struct cds_lfht_node *node; | |
a8c3ad3e | 168 | |
159b042f JG |
169 | assert(tracker->policy == LTTNG_TRACKING_POLICY_INCLUDE_SET); |
170 | ||
171 | rcu_read_lock(); | |
172 | cds_lfht_lookup(tracker->inclusion_set_ht, | |
173 | process_attr_value_hash(value), | |
174 | match_inclusion_set_value, value, &iter); | |
175 | node = cds_lfht_iter_get_node(&iter); | |
a8c3ad3e | 176 | rcu_read_unlock(); |
159b042f JG |
177 | |
178 | return node ? container_of(node, struct process_attr_tracker_value_node, | |
179 | inclusion_set_ht_node) : | |
180 | NULL; | |
a8c3ad3e MD |
181 | } |
182 | ||
159b042f JG |
183 | /* Protected by session mutex held by caller. */ |
184 | enum process_attr_tracker_status process_attr_tracker_inclusion_set_add_value( | |
185 | struct process_attr_tracker *tracker, | |
186 | const struct process_attr_value *value) | |
a8c3ad3e | 187 | { |
159b042f JG |
188 | enum process_attr_tracker_status status = |
189 | PROCESS_ATTR_TRACKER_STATUS_OK; | |
190 | struct process_attr_value *value_copy = NULL; | |
191 | struct process_attr_tracker_value_node *value_node = NULL; | |
b7e1aba3 | 192 | |
159b042f JG |
193 | rcu_read_lock(); |
194 | if (tracker->policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) { | |
195 | status = PROCESS_ATTR_TRACKER_STATUS_INVALID_TRACKING_POLICY; | |
196 | goto end; | |
a8c3ad3e | 197 | } |
a8c3ad3e | 198 | |
159b042f JG |
199 | if (process_attr_tracker_lookup(tracker, value)) { |
200 | status = PROCESS_ATTR_TRACKER_STATUS_EXISTS; | |
a8c3ad3e MD |
201 | goto end; |
202 | } | |
a8c3ad3e | 203 | |
159b042f JG |
204 | value_node = zmalloc(sizeof(*value_node)); |
205 | if (!value_node) { | |
206 | status = PROCESS_ATTR_TRACKER_STATUS_ERROR; | |
207 | goto end; | |
a8c3ad3e | 208 | } |
159b042f JG |
209 | |
210 | value_copy = process_attr_value_copy(value); | |
211 | if (!value_copy) { | |
212 | status = PROCESS_ATTR_TRACKER_STATUS_ERROR; | |
a8c3ad3e MD |
213 | goto end; |
214 | } | |
159b042f JG |
215 | |
216 | value_node->value = value_copy; | |
217 | cds_lfht_add(tracker->inclusion_set_ht, | |
218 | process_attr_value_hash(value_copy), | |
219 | &value_node->inclusion_set_ht_node); | |
220 | value_copy = NULL; | |
221 | value_node = NULL; | |
222 | end: | |
223 | if (value_copy) { | |
224 | process_attr_value_destroy(value_copy); | |
a8c3ad3e | 225 | } |
159b042f JG |
226 | if (value_node) { |
227 | free(value_node); | |
a8c3ad3e | 228 | } |
159b042f JG |
229 | rcu_read_unlock(); |
230 | return status; | |
a8c3ad3e MD |
231 | } |
232 | ||
159b042f JG |
233 | /* Protected by session mutex held by caller. */ |
234 | enum process_attr_tracker_status | |
235 | process_attr_tracker_inclusion_set_remove_value( | |
236 | struct process_attr_tracker *tracker, | |
237 | const struct process_attr_value *value) | |
a8c3ad3e | 238 | { |
159b042f JG |
239 | struct process_attr_tracker_value_node *value_node; |
240 | enum process_attr_tracker_status status = | |
241 | PROCESS_ATTR_TRACKER_STATUS_OK; | |
a8c3ad3e | 242 | |
159b042f JG |
243 | rcu_read_lock(); |
244 | if (tracker->policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) { | |
245 | status = PROCESS_ATTR_TRACKER_STATUS_INVALID_TRACKING_POLICY; | |
246 | goto end; | |
247 | } | |
a7a533cd | 248 | |
159b042f JG |
249 | value_node = process_attr_tracker_lookup(tracker, value); |
250 | if (!value_node) { | |
251 | status = PROCESS_ATTR_TRACKER_STATUS_MISSING; | |
252 | goto end; | |
a8c3ad3e | 253 | } |
a7a533cd | 254 | |
159b042f | 255 | process_attr_tracker_remove_value_node(tracker, value_node); |
a8c3ad3e | 256 | end: |
159b042f JG |
257 | rcu_read_unlock(); |
258 | return status; | |
a8c3ad3e MD |
259 | } |
260 | ||
159b042f JG |
261 | enum process_attr_tracker_status process_attr_tracker_get_inclusion_set( |
262 | const struct process_attr_tracker *tracker, | |
263 | struct lttng_process_attr_values **_values) | |
a8c3ad3e | 264 | { |
159b042f JG |
265 | struct lttng_ht_iter iter; |
266 | struct process_attr_tracker_value_node *value_node; | |
267 | enum process_attr_tracker_status status = | |
268 | PROCESS_ATTR_TRACKER_STATUS_OK; | |
269 | struct lttng_process_attr_values *values; | |
270 | struct process_attr_value *new_value = NULL; | |
271 | ||
272 | values = lttng_process_attr_values_create(); | |
273 | if (!values) { | |
274 | status = PROCESS_ATTR_TRACKER_STATUS_ERROR; | |
275 | goto error; | |
e283e4a0 | 276 | } |
a7a533cd | 277 | |
159b042f JG |
278 | if (tracker->policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) { |
279 | status = PROCESS_ATTR_TRACKER_STATUS_INVALID_TRACKING_POLICY; | |
280 | goto error; | |
a8c3ad3e | 281 | } |
a7a533cd | 282 | |
159b042f JG |
283 | rcu_read_lock(); |
284 | cds_lfht_for_each_entry (tracker->inclusion_set_ht, &iter.iter, | |
285 | value_node, inclusion_set_ht_node) { | |
286 | int ret; | |
287 | ||
288 | new_value = process_attr_value_copy(value_node->value); | |
289 | if (!new_value) { | |
290 | status = PROCESS_ATTR_TRACKER_STATUS_ERROR; | |
291 | goto error_unlock; | |
a7a533cd | 292 | } |
a7a533cd | 293 | |
159b042f JG |
294 | ret = lttng_dynamic_pointer_array_add_pointer( |
295 | &values->array, new_value); | |
296 | if (ret) { | |
297 | status = PROCESS_ATTR_TRACKER_STATUS_ERROR; | |
298 | goto error_unlock; | |
a8c3ad3e | 299 | } |
159b042f JG |
300 | |
301 | new_value = NULL; | |
a8c3ad3e | 302 | } |
159b042f JG |
303 | rcu_read_unlock(); |
304 | *_values = values; | |
305 | return status; | |
306 | error_unlock: | |
307 | rcu_read_unlock(); | |
308 | error: | |
309 | lttng_process_attr_values_destroy(values); | |
310 | process_attr_value_destroy(new_value); | |
311 | return status; | |
a8c3ad3e | 312 | } |