Commit | Line | Data |
---|---|---|
7972aab2 | 1 | /* |
ab5be9fa | 2 | * Copyright (C) 2013 David Goulet <dgoulet@efficios.com> |
7972aab2 | 3 | * |
ab5be9fa | 4 | * SPDX-License-Identifier: GPL-2.0-only |
7972aab2 | 5 | * |
7972aab2 DG |
6 | */ |
7 | ||
6c1c0768 | 8 | #define _LGPL_SOURCE |
7972aab2 DG |
9 | #include <inttypes.h> |
10 | ||
11 | #include <common/common.h> | |
12 | #include <common/hashtable/utils.h> | |
13 | ||
14 | #include "buffer-registry.h" | |
15 | #include "fd-limit.h" | |
16 | #include "ust-consumer.h" | |
75018ab6 JG |
17 | #include "lttng-ust-ctl.h" |
18 | #include "lttng-ust-error.h" | |
0b2dc8df | 19 | #include "utils.h" |
7972aab2 DG |
20 | |
21 | /* | |
22 | * Set in main.c during initialization process of the daemon. This contains | |
23 | * buffer_reg_uid object which are global registry for per UID buffer. Object | |
24 | * are indexed by session id and matched by the triplet | |
25 | * <session_id/bits_per_long/uid>. | |
26 | */ | |
27 | static struct lttng_ht *buffer_registry_uid; | |
28 | ||
29 | /* | |
30 | * Initialized at the daemon start. This contains buffer_reg_pid object and | |
31 | * indexed by session id. | |
32 | */ | |
33 | static struct lttng_ht *buffer_registry_pid; | |
34 | ||
35 | /* | |
36 | * Match function for the per UID registry hash table. It matches a registry | |
37 | * uid object with the triplet <session_id/abi/uid>. | |
38 | */ | |
39 | static int ht_match_reg_uid(struct cds_lfht_node *node, const void *_key) | |
40 | { | |
41 | struct buffer_reg_uid *reg; | |
42 | const struct buffer_reg_uid *key; | |
43 | ||
44 | assert(node); | |
45 | assert(_key); | |
46 | ||
47 | reg = caa_container_of(node, struct buffer_reg_uid, node.node); | |
48 | assert(reg); | |
49 | key = _key; | |
50 | ||
51 | if (key->session_id != reg->session_id || | |
52 | key->bits_per_long != reg->bits_per_long || | |
53 | key->uid != reg->uid) { | |
54 | goto no_match; | |
55 | } | |
56 | ||
57 | /* Match */ | |
58 | return 1; | |
59 | no_match: | |
60 | return 0; | |
61 | } | |
62 | ||
63 | /* | |
64 | * Hash function for the per UID registry hash table. This XOR the triplet | |
65 | * together. | |
66 | */ | |
bcd52dd9 | 67 | static unsigned long ht_hash_reg_uid(const void *_key, unsigned long seed) |
7972aab2 DG |
68 | { |
69 | uint64_t xored_key; | |
bcd52dd9 | 70 | const struct buffer_reg_uid *key = _key; |
7972aab2 DG |
71 | |
72 | assert(key); | |
73 | ||
74 | xored_key = (uint64_t)(key->session_id ^ key->bits_per_long ^ key->uid); | |
75 | return hash_key_u64(&xored_key, seed); | |
76 | } | |
77 | ||
78 | /* | |
79 | * Initialize global buffer per UID registry. Should only be called ONCE!. | |
80 | */ | |
81 | void buffer_reg_init_uid_registry(void) | |
82 | { | |
83 | /* Should be called once. */ | |
84 | assert(!buffer_registry_uid); | |
85 | buffer_registry_uid = lttng_ht_new(0, LTTNG_HT_TYPE_U64); | |
86 | assert(buffer_registry_uid); | |
87 | buffer_registry_uid->match_fct = ht_match_reg_uid; | |
88 | buffer_registry_uid->hash_fct = ht_hash_reg_uid; | |
89 | ||
90 | DBG3("Global buffer per UID registry initialized"); | |
91 | } | |
92 | ||
93 | /* | |
94 | * Allocate and initialize object. Set regp with the object pointer. | |
95 | * | |
96 | * Return 0 on success else a negative value and regp is untouched. | |
97 | */ | |
d9bf3ca4 | 98 | int buffer_reg_uid_create(uint64_t session_id, uint32_t bits_per_long, uid_t uid, |
d7ba1388 | 99 | enum lttng_domain_type domain, struct buffer_reg_uid **regp, |
3d071855 | 100 | const char *root_shm_path, const char *shm_path) |
7972aab2 DG |
101 | { |
102 | int ret = 0; | |
103 | struct buffer_reg_uid *reg = NULL; | |
104 | ||
105 | assert(regp); | |
106 | ||
107 | reg = zmalloc(sizeof(*reg)); | |
108 | if (!reg) { | |
109 | PERROR("zmalloc buffer registry uid"); | |
110 | ret = -ENOMEM; | |
111 | goto error; | |
112 | } | |
113 | ||
114 | reg->registry = zmalloc(sizeof(struct buffer_reg_session)); | |
63c861bd | 115 | if (!reg->registry) { |
7972aab2 DG |
116 | PERROR("zmalloc buffer registry uid session"); |
117 | ret = -ENOMEM; | |
118 | goto error; | |
119 | } | |
120 | ||
121 | reg->session_id = session_id; | |
122 | reg->bits_per_long = bits_per_long; | |
123 | reg->uid = uid; | |
124 | reg->domain = domain; | |
d7ba1388 | 125 | if (shm_path[0]) { |
3d071855 MD |
126 | strncpy(reg->root_shm_path, root_shm_path, sizeof(reg->root_shm_path)); |
127 | reg->root_shm_path[sizeof(reg->root_shm_path) - 1] = '\0'; | |
d7ba1388 MD |
128 | strncpy(reg->shm_path, shm_path, sizeof(reg->shm_path)); |
129 | reg->shm_path[sizeof(reg->shm_path) - 1] = '\0'; | |
130 | DBG3("shm path '%s' is assigned to uid buffer registry for session id %" PRIu64, | |
131 | reg->shm_path, session_id); | |
132 | } | |
7972aab2 DG |
133 | reg->registry->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64); |
134 | if (!reg->registry->channels) { | |
135 | ret = -ENOMEM; | |
136 | goto error_session; | |
137 | } | |
138 | ||
ebdb334b JR |
139 | reg->registry->maps = lttng_ht_new(0, LTTNG_HT_TYPE_U64); |
140 | if (!reg->registry->maps) { | |
141 | lttng_ht_destroy(reg->registry->channels); | |
142 | ret = -ENOMEM; | |
143 | goto error_session; | |
144 | } | |
145 | ||
146 | ||
7972aab2 DG |
147 | cds_lfht_node_init(®->node.node); |
148 | *regp = reg; | |
149 | ||
d9bf3ca4 | 150 | DBG3("Buffer registry per UID created id: %" PRIu64 ", ABI: %u, uid: %d, domain: %d", |
7972aab2 DG |
151 | session_id, bits_per_long, uid, domain); |
152 | ||
153 | return 0; | |
154 | ||
155 | error_session: | |
156 | free(reg->registry); | |
157 | error: | |
158 | free(reg); | |
159 | return ret; | |
160 | } | |
161 | ||
162 | /* | |
163 | * Add a buffer registry per UID object to the global registry. | |
164 | */ | |
165 | void buffer_reg_uid_add(struct buffer_reg_uid *reg) | |
166 | { | |
167 | struct cds_lfht_node *nodep; | |
168 | struct lttng_ht *ht = buffer_registry_uid; | |
169 | ||
170 | assert(reg); | |
171 | ||
d9bf3ca4 | 172 | DBG3("Buffer registry per UID adding to global registry with id: %" PRIu64 , |
7972aab2 DG |
173 | reg->session_id); |
174 | ||
175 | rcu_read_lock(); | |
176 | nodep = cds_lfht_add_unique(ht->ht, ht->hash_fct(reg, lttng_ht_seed), | |
177 | ht->match_fct, reg, ®->node.node); | |
178 | assert(nodep == ®->node.node); | |
179 | rcu_read_unlock(); | |
180 | } | |
181 | ||
182 | /* | |
183 | * Find a buffer registry per UID object with given params. RCU read side lock | |
184 | * MUST be acquired before calling this and hold on to protect the object. | |
185 | * | |
186 | * Return the object pointer or NULL on error. | |
187 | */ | |
d9bf3ca4 | 188 | struct buffer_reg_uid *buffer_reg_uid_find(uint64_t session_id, |
7972aab2 DG |
189 | uint32_t bits_per_long, uid_t uid) |
190 | { | |
191 | struct lttng_ht_node_u64 *node; | |
192 | struct lttng_ht_iter iter; | |
193 | struct buffer_reg_uid *reg = NULL, key; | |
194 | struct lttng_ht *ht = buffer_registry_uid; | |
195 | ||
196 | /* Setup key we are looking for. */ | |
197 | key.session_id = session_id; | |
198 | key.bits_per_long = bits_per_long; | |
199 | key.uid = uid; | |
200 | ||
d9bf3ca4 | 201 | DBG3("Buffer registry per UID find id: %" PRIu64 ", ABI: %u, uid: %d", |
7972aab2 DG |
202 | session_id, bits_per_long, uid); |
203 | ||
204 | /* Custom lookup function since it's a different key. */ | |
205 | cds_lfht_lookup(ht->ht, ht->hash_fct(&key, lttng_ht_seed), ht->match_fct, | |
206 | &key, &iter.iter); | |
207 | node = lttng_ht_iter_get_node_u64(&iter); | |
208 | if (!node) { | |
209 | goto end; | |
210 | } | |
211 | reg = caa_container_of(node, struct buffer_reg_uid, node); | |
212 | ||
213 | end: | |
214 | return reg; | |
215 | } | |
216 | ||
217 | /* | |
218 | * Initialize global buffer per PID registry. Should only be called ONCE!. | |
219 | */ | |
220 | void buffer_reg_init_pid_registry(void) | |
221 | { | |
222 | /* Should be called once. */ | |
223 | assert(!buffer_registry_pid); | |
d9bf3ca4 | 224 | buffer_registry_pid = lttng_ht_new(0, LTTNG_HT_TYPE_U64); |
7972aab2 DG |
225 | assert(buffer_registry_pid); |
226 | ||
227 | DBG3("Global buffer per PID registry initialized"); | |
228 | } | |
229 | ||
230 | /* | |
231 | * Allocate and initialize object. Set regp with the object pointer. | |
232 | * | |
233 | * Return 0 on success else a negative value and regp is untouched. | |
234 | */ | |
d7ba1388 | 235 | int buffer_reg_pid_create(uint64_t session_id, struct buffer_reg_pid **regp, |
3d071855 | 236 | const char *root_shm_path, const char *shm_path) |
7972aab2 DG |
237 | { |
238 | int ret = 0; | |
239 | struct buffer_reg_pid *reg = NULL; | |
240 | ||
241 | assert(regp); | |
242 | ||
243 | reg = zmalloc(sizeof(*reg)); | |
244 | if (!reg) { | |
245 | PERROR("zmalloc buffer registry pid"); | |
246 | ret = -ENOMEM; | |
247 | goto error; | |
248 | } | |
249 | ||
250 | reg->registry = zmalloc(sizeof(struct buffer_reg_session)); | |
63c861bd | 251 | if (!reg->registry) { |
7972aab2 DG |
252 | PERROR("zmalloc buffer registry pid session"); |
253 | ret = -ENOMEM; | |
254 | goto error; | |
255 | } | |
256 | ||
257 | /* A cast is done here so we can use the session ID as a u64 ht node. */ | |
258 | reg->session_id = session_id; | |
d7ba1388 | 259 | if (shm_path[0]) { |
3d071855 MD |
260 | strncpy(reg->root_shm_path, root_shm_path, sizeof(reg->root_shm_path)); |
261 | reg->root_shm_path[sizeof(reg->root_shm_path) - 1] = '\0'; | |
d7ba1388 MD |
262 | strncpy(reg->shm_path, shm_path, sizeof(reg->shm_path)); |
263 | reg->shm_path[sizeof(reg->shm_path) - 1] = '\0'; | |
264 | DBG3("shm path '%s' is assigned to pid buffer registry for session id %" PRIu64, | |
265 | reg->shm_path, session_id); | |
266 | } | |
7972aab2 DG |
267 | reg->registry->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64); |
268 | if (!reg->registry->channels) { | |
269 | ret = -ENOMEM; | |
270 | goto error_session; | |
271 | } | |
272 | ||
ebdb334b JR |
273 | reg->registry->maps = lttng_ht_new(0, LTTNG_HT_TYPE_U64); |
274 | if (!reg->registry->maps) { | |
275 | lttng_ht_destroy(reg->registry->channels); | |
276 | ret = -ENOMEM; | |
277 | goto error_session; | |
278 | } | |
279 | ||
d9bf3ca4 | 280 | lttng_ht_node_init_u64(®->node, reg->session_id); |
7972aab2 DG |
281 | *regp = reg; |
282 | ||
d9bf3ca4 MD |
283 | DBG3("Buffer registry per PID created with session id: %" PRIu64, |
284 | session_id); | |
7972aab2 DG |
285 | |
286 | return 0; | |
287 | ||
288 | error_session: | |
289 | free(reg->registry); | |
290 | error: | |
291 | free(reg); | |
292 | return ret; | |
293 | } | |
294 | ||
295 | /* | |
296 | * Add a buffer registry per PID object to the global registry. | |
297 | */ | |
298 | void buffer_reg_pid_add(struct buffer_reg_pid *reg) | |
299 | { | |
300 | assert(reg); | |
301 | ||
d9bf3ca4 | 302 | DBG3("Buffer registry per PID adding to global registry with id: %" PRIu64, |
7972aab2 DG |
303 | reg->session_id); |
304 | ||
305 | rcu_read_lock(); | |
d9bf3ca4 | 306 | lttng_ht_add_unique_u64(buffer_registry_pid, ®->node); |
7972aab2 DG |
307 | rcu_read_unlock(); |
308 | } | |
309 | ||
310 | /* | |
311 | * Find a buffer registry per PID object with given params. RCU read side lock | |
312 | * MUST be acquired before calling this and hold on to protect the object. | |
313 | * | |
314 | * Return the object pointer or NULL on error. | |
315 | */ | |
d9bf3ca4 | 316 | struct buffer_reg_pid *buffer_reg_pid_find(uint64_t session_id) |
7972aab2 | 317 | { |
d9bf3ca4 | 318 | struct lttng_ht_node_u64 *node; |
7972aab2 DG |
319 | struct lttng_ht_iter iter; |
320 | struct buffer_reg_pid *reg = NULL; | |
321 | struct lttng_ht *ht = buffer_registry_pid; | |
322 | ||
d9bf3ca4 | 323 | DBG3("Buffer registry per PID find id: %" PRIu64, session_id); |
7972aab2 | 324 | |
d9bf3ca4 MD |
325 | lttng_ht_lookup(ht, &session_id, &iter); |
326 | node = lttng_ht_iter_get_node_u64(&iter); | |
7972aab2 DG |
327 | if (!node) { |
328 | goto end; | |
329 | } | |
330 | reg = caa_container_of(node, struct buffer_reg_pid, node); | |
331 | ||
332 | end: | |
333 | return reg; | |
334 | } | |
335 | ||
fb83fe64 JD |
336 | /* |
337 | * Find the consumer channel key from a UST session per-uid channel key. | |
338 | * | |
339 | * Return the matching key or -1 if not found. | |
340 | */ | |
341 | int buffer_reg_uid_consumer_channel_key( | |
342 | struct cds_list_head *buffer_reg_uid_list, | |
76604852 | 343 | uint64_t chan_key, uint64_t *consumer_chan_key) |
fb83fe64 JD |
344 | { |
345 | struct lttng_ht_iter iter; | |
346 | struct buffer_reg_uid *uid_reg = NULL; | |
347 | struct buffer_reg_session *session_reg = NULL; | |
348 | struct buffer_reg_channel *reg_chan; | |
349 | int ret = -1; | |
350 | ||
351 | rcu_read_lock(); | |
352 | /* | |
353 | * For the per-uid registry, we have to iterate since we don't have the | |
354 | * uid and bitness key. | |
355 | */ | |
356 | cds_list_for_each_entry(uid_reg, buffer_reg_uid_list, lnode) { | |
357 | session_reg = uid_reg->registry; | |
358 | cds_lfht_for_each_entry(session_reg->channels->ht, | |
359 | &iter.iter, reg_chan, node.node) { | |
360 | if (reg_chan->key == chan_key) { | |
361 | *consumer_chan_key = reg_chan->consumer_key; | |
362 | ret = 0; | |
363 | goto end; | |
364 | } | |
365 | } | |
366 | } | |
367 | ||
368 | end: | |
369 | rcu_read_unlock(); | |
370 | return ret; | |
371 | } | |
372 | ||
7972aab2 DG |
373 | /* |
374 | * Allocate and initialize a buffer registry channel with the given key. Set | |
375 | * regp with the object pointer. | |
376 | * | |
377 | * Return 0 on success or else a negative value keeping regp untouched. | |
378 | */ | |
379 | int buffer_reg_channel_create(uint64_t key, struct buffer_reg_channel **regp) | |
380 | { | |
381 | struct buffer_reg_channel *reg; | |
382 | ||
383 | assert(regp); | |
384 | ||
385 | DBG3("Buffer registry channel create with key: %" PRIu64, key); | |
386 | ||
387 | reg = zmalloc(sizeof(*reg)); | |
388 | if (!reg) { | |
389 | PERROR("zmalloc buffer registry channel"); | |
390 | return -ENOMEM; | |
391 | } | |
392 | ||
393 | reg->key = key; | |
394 | CDS_INIT_LIST_HEAD(®->streams); | |
395 | pthread_mutex_init(®->stream_list_lock, NULL); | |
396 | ||
397 | lttng_ht_node_init_u64(®->node, key); | |
398 | *regp = reg; | |
399 | ||
400 | return 0; | |
401 | } | |
402 | ||
ebdb334b JR |
403 | /* |
404 | * Allocate and initialize a buffer registry map with the given key. Set | |
405 | * regp with the object pointer. | |
406 | * | |
407 | * Return 0 on success or else a negative value keeping regp untouched. | |
408 | */ | |
409 | int buffer_reg_map_create(uint64_t key, struct buffer_reg_map **regp) | |
410 | { | |
411 | struct buffer_reg_map *reg; | |
412 | ||
413 | assert(regp); | |
414 | ||
415 | DBG3("Buffer registry map create with key: %" PRIu64, key); | |
416 | ||
417 | reg = zmalloc(sizeof(*reg)); | |
418 | if (!reg) { | |
419 | PERROR("zmalloc buffer registry map"); | |
420 | return -ENOMEM; | |
421 | } | |
422 | ||
423 | reg->key = key; | |
424 | CDS_INIT_LIST_HEAD(®->counters); | |
425 | pthread_mutex_init(®->counter_list_lock, NULL); | |
426 | ||
427 | lttng_ht_node_init_u64(®->node, key); | |
428 | *regp = reg; | |
429 | ||
430 | return 0; | |
431 | } | |
432 | ||
7972aab2 DG |
433 | /* |
434 | * Allocate and initialize a buffer registry stream. Set regp with the object | |
435 | * pointer. | |
436 | * | |
437 | * Return 0 on success or else a negative value keeping regp untouched. | |
438 | */ | |
439 | int buffer_reg_stream_create(struct buffer_reg_stream **regp) | |
440 | { | |
441 | struct buffer_reg_stream *reg; | |
442 | ||
443 | assert(regp); | |
444 | ||
445 | DBG3("Buffer registry creating stream"); | |
446 | ||
447 | reg = zmalloc(sizeof(*reg)); | |
448 | if (!reg) { | |
449 | PERROR("zmalloc buffer registry stream"); | |
450 | return -ENOMEM; | |
451 | } | |
452 | ||
453 | *regp = reg; | |
454 | ||
455 | return 0; | |
456 | } | |
457 | ||
ebdb334b JR |
458 | /* |
459 | * Allocate and initialize a buffer registry map_counter. Set regp with the object | |
460 | * pointer. | |
461 | * | |
462 | * Return 0 on success or else a negative value keeping regp untouched. | |
463 | */ | |
464 | int buffer_reg_map_counter_create(struct buffer_reg_map_counter **regp) | |
465 | { | |
466 | struct buffer_reg_map_counter *reg; | |
467 | ||
468 | assert(regp); | |
469 | ||
470 | DBG3("Buffer registry creating map_counter"); | |
471 | ||
472 | reg = zmalloc(sizeof(*reg)); | |
473 | if (!reg) { | |
474 | PERROR("zmalloc buffer registry map_counter"); | |
475 | return -ENOMEM; | |
476 | } | |
477 | ||
478 | *regp = reg; | |
479 | ||
480 | return 0; | |
481 | } | |
482 | ||
7972aab2 DG |
483 | /* |
484 | * Add stream to the list in the channel. | |
485 | */ | |
486 | void buffer_reg_stream_add(struct buffer_reg_stream *stream, | |
487 | struct buffer_reg_channel *channel) | |
488 | { | |
489 | assert(stream); | |
490 | assert(channel); | |
491 | ||
492 | pthread_mutex_lock(&channel->stream_list_lock); | |
493 | cds_list_add_tail(&stream->lnode, &channel->streams); | |
5c786ded | 494 | channel->stream_count++; |
7972aab2 DG |
495 | pthread_mutex_unlock(&channel->stream_list_lock); |
496 | } | |
497 | ||
ebdb334b JR |
498 | /* |
499 | * Add map_counter to the list in the map. | |
500 | */ | |
501 | void buffer_reg_map_counter_add(struct buffer_reg_map_counter *map_counter, | |
502 | struct buffer_reg_map *map) | |
503 | { | |
504 | assert(map_counter); | |
505 | assert(map); | |
506 | ||
507 | pthread_mutex_lock(&map->counter_list_lock); | |
508 | cds_list_add_tail(&map_counter->lnode, &map->counters); | |
509 | map->counter_count++; | |
510 | pthread_mutex_unlock(&map->counter_list_lock); | |
511 | } | |
512 | ||
7972aab2 DG |
513 | /* |
514 | * Add a buffer registry channel object to the given session. | |
515 | */ | |
516 | void buffer_reg_channel_add(struct buffer_reg_session *session, | |
517 | struct buffer_reg_channel *channel) | |
518 | { | |
519 | assert(session); | |
520 | assert(channel); | |
521 | ||
522 | rcu_read_lock(); | |
523 | lttng_ht_add_unique_u64(session->channels, &channel->node); | |
524 | rcu_read_unlock(); | |
525 | } | |
526 | ||
ebdb334b JR |
527 | /* |
528 | * Add a buffer registry map object to the given session. | |
529 | */ | |
530 | void buffer_reg_map_add(struct buffer_reg_session *session, | |
531 | struct buffer_reg_map *map) | |
532 | { | |
533 | assert(session); | |
534 | assert(map); | |
535 | ||
536 | rcu_read_lock(); | |
537 | lttng_ht_add_unique_u64(session->maps, &map->node); | |
538 | rcu_read_unlock(); | |
539 | } | |
540 | ||
7972aab2 DG |
541 | /* |
542 | * Find a buffer registry channel object with the given key. RCU read side lock | |
543 | * MUST be acquired and hold on until the object reference is not needed | |
544 | * anymore. | |
545 | * | |
546 | * Return the object pointer or NULL on error. | |
547 | */ | |
548 | struct buffer_reg_channel *buffer_reg_channel_find(uint64_t key, | |
549 | struct buffer_reg_uid *reg) | |
550 | { | |
551 | struct lttng_ht_node_u64 *node; | |
552 | struct lttng_ht_iter iter; | |
553 | struct buffer_reg_channel *chan = NULL; | |
554 | struct lttng_ht *ht; | |
555 | ||
556 | assert(reg); | |
557 | ||
558 | switch (reg->domain) { | |
559 | case LTTNG_DOMAIN_UST: | |
560 | ht = reg->registry->channels; | |
561 | break; | |
562 | default: | |
563 | assert(0); | |
564 | goto end; | |
565 | } | |
566 | ||
567 | lttng_ht_lookup(ht, &key, &iter); | |
568 | node = lttng_ht_iter_get_node_u64(&iter); | |
569 | if (!node) { | |
570 | goto end; | |
571 | } | |
572 | chan = caa_container_of(node, struct buffer_reg_channel, node); | |
573 | ||
574 | end: | |
575 | return chan; | |
576 | } | |
577 | ||
ebdb334b JR |
578 | /* |
579 | * Find a buffer registry map object with the given key. RCU read side lock | |
580 | * MUST be acquired and hold on until the object reference is not needed | |
581 | * anymore. | |
582 | * | |
583 | * Return the object pointer or NULL on error. | |
584 | */ | |
585 | struct buffer_reg_map *buffer_reg_map_find(uint64_t key, | |
586 | struct buffer_reg_uid *reg) | |
587 | { | |
588 | struct lttng_ht_node_u64 *node; | |
589 | struct lttng_ht_iter iter; | |
590 | struct buffer_reg_map *map = NULL; | |
591 | struct lttng_ht *ht; | |
592 | ||
593 | assert(reg); | |
594 | ||
595 | switch (reg->domain) { | |
596 | case LTTNG_DOMAIN_UST: | |
597 | ht = reg->registry->maps; | |
598 | break; | |
599 | default: | |
600 | assert(0); | |
601 | goto end; | |
602 | } | |
603 | ||
604 | lttng_ht_lookup(ht, &key, &iter); | |
605 | node = lttng_ht_iter_get_node_u64(&iter); | |
606 | if (!node) { | |
607 | goto end; | |
608 | } | |
609 | map = caa_container_of(node, struct buffer_reg_map, node); | |
610 | ||
611 | end: | |
612 | return map; | |
613 | } | |
614 | ||
7972aab2 DG |
615 | /* |
616 | * Destroy a buffer registry stream with the given domain. | |
617 | */ | |
618 | void buffer_reg_stream_destroy(struct buffer_reg_stream *regp, | |
619 | enum lttng_domain_type domain) | |
620 | { | |
621 | if (!regp) { | |
622 | return; | |
623 | } | |
624 | ||
625 | DBG3("Buffer registry stream destroy with handle %d", | |
626 | regp->obj.ust->handle); | |
627 | ||
628 | switch (domain) { | |
629 | case LTTNG_DOMAIN_UST: | |
630 | { | |
631 | int ret; | |
632 | ||
fb45065e | 633 | ret = ust_app_release_object(NULL, regp->obj.ust); |
7972aab2 DG |
634 | if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) { |
635 | ERR("Buffer reg stream release obj handle %d failed with ret %d", | |
636 | regp->obj.ust->handle, ret); | |
637 | } | |
638 | free(regp->obj.ust); | |
639 | lttng_fd_put(LTTNG_FD_APPS, 2); | |
640 | break; | |
641 | } | |
642 | default: | |
643 | assert(0); | |
644 | } | |
645 | ||
646 | free(regp); | |
647 | return; | |
648 | } | |
649 | ||
ebdb334b JR |
650 | /* |
651 | * Destroy a buffer registry map_counter with the given domain. | |
652 | */ | |
653 | void buffer_reg_map_counter_destroy(struct buffer_reg_map_counter *regp, | |
654 | enum lttng_domain_type domain) | |
655 | { | |
656 | if (!regp) { | |
657 | return; | |
658 | } | |
659 | ||
660 | DBG3("Buffer registry map counter destroy with handle %d", | |
661 | regp->obj.ust->handle); | |
662 | ||
663 | switch (domain) { | |
664 | case LTTNG_DOMAIN_UST: | |
665 | { | |
666 | int ret; | |
667 | ||
668 | ret = ust_app_release_object(NULL, regp->obj.ust); | |
669 | if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) { | |
670 | ERR("Buffer reg map counter release obj handle %d failed with ret %d", | |
671 | regp->obj.ust->handle, ret); | |
672 | } | |
673 | free(regp->obj.ust); | |
674 | lttng_fd_put(LTTNG_FD_APPS, 2); | |
675 | break; | |
676 | } | |
677 | default: | |
678 | assert(0); | |
679 | } | |
680 | ||
681 | free(regp); | |
682 | return; | |
683 | } | |
684 | ||
7972aab2 DG |
685 | /* |
686 | * Remove buffer registry channel object from the session hash table. RCU read | |
687 | * side lock MUST be acquired before calling this. | |
688 | */ | |
689 | void buffer_reg_channel_remove(struct buffer_reg_session *session, | |
690 | struct buffer_reg_channel *regp) | |
691 | { | |
692 | int ret; | |
693 | struct lttng_ht_iter iter; | |
694 | ||
695 | assert(session); | |
696 | assert(regp); | |
697 | ||
698 | iter.iter.node = ®p->node.node; | |
699 | ret = lttng_ht_del(session->channels, &iter); | |
700 | assert(!ret); | |
701 | } | |
702 | ||
ebdb334b JR |
703 | /* |
704 | * Remove buffer registry map object from the session hash table. RCU read | |
705 | * side lock MUST be acquired before calling this. | |
706 | */ | |
707 | void buffer_reg_map_remove(struct buffer_reg_session *session, | |
708 | struct buffer_reg_map *regp) | |
709 | { | |
710 | int ret; | |
711 | struct lttng_ht_iter iter; | |
712 | ||
713 | assert(session); | |
714 | assert(regp); | |
715 | ||
716 | iter.iter.node = ®p->node.node; | |
717 | ret = lttng_ht_del(session->maps, &iter); | |
718 | assert(!ret); | |
719 | } | |
720 | ||
7972aab2 DG |
721 | /* |
722 | * Destroy a buffer registry channel with the given domain. | |
723 | */ | |
724 | void buffer_reg_channel_destroy(struct buffer_reg_channel *regp, | |
725 | enum lttng_domain_type domain) | |
726 | { | |
727 | if (!regp) { | |
728 | return; | |
729 | } | |
730 | ||
07d2ae95 | 731 | DBG3("Buffer registry channel destroy with key %" PRIu32, regp->key); |
7972aab2 DG |
732 | |
733 | switch (domain) { | |
734 | case LTTNG_DOMAIN_UST: | |
735 | { | |
736 | int ret; | |
737 | struct buffer_reg_stream *sreg, *stmp; | |
738 | /* Wipe stream */ | |
739 | cds_list_for_each_entry_safe(sreg, stmp, ®p->streams, lnode) { | |
740 | cds_list_del(&sreg->lnode); | |
5c786ded | 741 | regp->stream_count--; |
7972aab2 DG |
742 | buffer_reg_stream_destroy(sreg, domain); |
743 | } | |
744 | ||
55d7e860 | 745 | if (regp->obj.ust) { |
fb45065e | 746 | ret = ust_app_release_object(NULL, regp->obj.ust); |
55d7e860 MD |
747 | if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) { |
748 | ERR("Buffer reg channel release obj handle %d failed with ret %d", | |
749 | regp->obj.ust->handle, ret); | |
750 | } | |
751 | free(regp->obj.ust); | |
7972aab2 | 752 | } |
7972aab2 DG |
753 | lttng_fd_put(LTTNG_FD_APPS, 1); |
754 | break; | |
755 | } | |
756 | default: | |
757 | assert(0); | |
758 | } | |
759 | ||
760 | free(regp); | |
761 | return; | |
762 | } | |
763 | ||
ebdb334b JR |
764 | /* |
765 | * Destroy a buffer registry map with the given domain. | |
766 | */ | |
767 | void buffer_reg_map_destroy(struct buffer_reg_map *regp, | |
768 | enum lttng_domain_type domain) | |
769 | { | |
770 | if (!regp) { | |
771 | return; | |
772 | } | |
773 | ||
774 | DBG3("Buffer registry map destroy with key %" PRIu32, regp->key); | |
775 | ||
776 | switch (domain) { | |
777 | case LTTNG_DOMAIN_UST: | |
778 | { | |
779 | int ret; | |
780 | struct buffer_reg_map_counter *map_counter_reg, *tmp; | |
781 | /* Wipe counter */ | |
782 | cds_list_for_each_entry_safe(map_counter_reg, tmp, ®p->counters, lnode) { | |
783 | cds_list_del(&map_counter_reg->lnode); | |
784 | regp->counter_count--; | |
785 | buffer_reg_map_counter_destroy(map_counter_reg, domain); | |
786 | } | |
787 | ||
788 | if (regp->obj.ust) { | |
789 | ret = ust_app_release_object(NULL, regp->obj.ust); | |
790 | if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) { | |
791 | ERR("Buffer reg map release obj handle %d failed with ret %d", | |
792 | regp->obj.ust->handle, ret); | |
793 | } | |
794 | free(regp->obj.ust); | |
795 | } | |
796 | lttng_fd_put(LTTNG_FD_APPS, 1); | |
797 | break; | |
798 | } | |
799 | default: | |
800 | assert(0); | |
801 | } | |
802 | ||
803 | free(regp); | |
804 | return; | |
805 | } | |
806 | ||
7972aab2 DG |
807 | /* |
808 | * Destroy a buffer registry session with the given domain. | |
36b588ed MD |
809 | * |
810 | * Should *NOT* be called with RCU read-side lock held. | |
7972aab2 | 811 | */ |
36b588ed | 812 | static void buffer_reg_session_destroy(struct buffer_reg_session *regp, |
7972aab2 DG |
813 | enum lttng_domain_type domain) |
814 | { | |
815 | int ret; | |
816 | struct lttng_ht_iter iter; | |
817 | struct buffer_reg_channel *reg_chan; | |
ebdb334b | 818 | struct buffer_reg_map *reg_map; |
7972aab2 DG |
819 | |
820 | DBG3("Buffer registry session destroy"); | |
821 | ||
822 | /* Destroy all channels. */ | |
823 | rcu_read_lock(); | |
824 | cds_lfht_for_each_entry(regp->channels->ht, &iter.iter, reg_chan, | |
825 | node.node) { | |
826 | ret = lttng_ht_del(regp->channels, &iter); | |
827 | assert(!ret); | |
828 | buffer_reg_channel_destroy(reg_chan, domain); | |
829 | } | |
ebdb334b JR |
830 | cds_lfht_for_each_entry(regp->maps->ht, &iter.iter, reg_map, |
831 | node.node) { | |
832 | ret = lttng_ht_del(regp->maps, &iter); | |
833 | assert(!ret); | |
834 | buffer_reg_map_destroy(reg_map, domain); | |
835 | } | |
7972aab2 DG |
836 | rcu_read_unlock(); |
837 | ||
0b2dc8df | 838 | ht_cleanup_push(regp->channels); |
ebdb334b | 839 | ht_cleanup_push(regp->maps); |
36b588ed | 840 | |
7972aab2 DG |
841 | switch (domain) { |
842 | case LTTNG_DOMAIN_UST: | |
843 | ust_registry_session_destroy(regp->reg.ust); | |
844 | free(regp->reg.ust); | |
845 | break; | |
846 | default: | |
847 | assert(0); | |
848 | } | |
849 | ||
850 | free(regp); | |
851 | return; | |
852 | } | |
853 | ||
854 | /* | |
36b588ed | 855 | * Remove buffer registry UID object from the global hash table. |
7972aab2 DG |
856 | */ |
857 | void buffer_reg_uid_remove(struct buffer_reg_uid *regp) | |
858 | { | |
859 | int ret; | |
860 | struct lttng_ht_iter iter; | |
861 | ||
862 | assert(regp); | |
863 | ||
36b588ed | 864 | rcu_read_lock(); |
7972aab2 DG |
865 | iter.iter.node = ®p->node.node; |
866 | ret = lttng_ht_del(buffer_registry_uid, &iter); | |
867 | assert(!ret); | |
36b588ed | 868 | rcu_read_unlock(); |
7972aab2 DG |
869 | } |
870 | ||
871 | static void rcu_free_buffer_reg_uid(struct rcu_head *head) | |
872 | { | |
873 | struct lttng_ht_node_u64 *node = | |
874 | caa_container_of(head, struct lttng_ht_node_u64, head); | |
875 | struct buffer_reg_uid *reg = | |
876 | caa_container_of(node, struct buffer_reg_uid, node); | |
877 | ||
878 | buffer_reg_session_destroy(reg->registry, reg->domain); | |
879 | free(reg); | |
880 | } | |
881 | ||
882 | static void rcu_free_buffer_reg_pid(struct rcu_head *head) | |
883 | { | |
d9bf3ca4 MD |
884 | struct lttng_ht_node_u64 *node = |
885 | caa_container_of(head, struct lttng_ht_node_u64, head); | |
7972aab2 DG |
886 | struct buffer_reg_pid *reg = |
887 | caa_container_of(node, struct buffer_reg_pid, node); | |
888 | ||
889 | buffer_reg_session_destroy(reg->registry, LTTNG_DOMAIN_UST); | |
890 | free(reg); | |
891 | } | |
892 | ||
893 | /* | |
894 | * Destroy buffer registry per UID. The given pointer is NOT removed from any | |
895 | * list or hash table. Use buffer_reg_pid_remove() before calling this function | |
896 | * for the case that the object is in the global hash table. | |
897 | */ | |
898 | void buffer_reg_uid_destroy(struct buffer_reg_uid *regp, | |
899 | struct consumer_output *consumer) | |
900 | { | |
901 | struct consumer_socket *socket; | |
902 | ||
903 | if (!regp) { | |
904 | return; | |
905 | } | |
906 | ||
d9bf3ca4 | 907 | DBG3("Buffer registry per UID destroy with id: %" PRIu64 ", ABI: %u, uid: %d", |
7972aab2 DG |
908 | regp->session_id, regp->bits_per_long, regp->uid); |
909 | ||
910 | if (!consumer) { | |
911 | goto destroy; | |
912 | } | |
913 | ||
36b588ed | 914 | rcu_read_lock(); |
7972aab2 DG |
915 | /* Get the right socket from the consumer object. */ |
916 | socket = consumer_find_socket_by_bitness(regp->bits_per_long, | |
917 | consumer); | |
918 | if (!socket) { | |
36b588ed | 919 | goto unlock; |
7972aab2 DG |
920 | } |
921 | ||
922 | switch (regp->domain) { | |
923 | case LTTNG_DOMAIN_UST: | |
924 | if (regp->registry->reg.ust->metadata_key) { | |
925 | /* Return value does not matter. This call will print errors. */ | |
926 | (void) consumer_close_metadata(socket, | |
927 | regp->registry->reg.ust->metadata_key); | |
928 | } | |
929 | break; | |
930 | default: | |
931 | assert(0); | |
36b588ed | 932 | rcu_read_unlock(); |
7972aab2 DG |
933 | return; |
934 | } | |
935 | ||
36b588ed MD |
936 | unlock: |
937 | rcu_read_unlock(); | |
7972aab2 DG |
938 | destroy: |
939 | call_rcu(®p->node.head, rcu_free_buffer_reg_uid); | |
940 | } | |
941 | ||
942 | /* | |
943 | * Remove buffer registry UID object from the global hash table. RCU read side | |
944 | * lock MUST be acquired before calling this. | |
945 | */ | |
946 | void buffer_reg_pid_remove(struct buffer_reg_pid *regp) | |
947 | { | |
948 | int ret; | |
949 | struct lttng_ht_iter iter; | |
950 | ||
951 | assert(regp); | |
952 | ||
953 | iter.iter.node = ®p->node.node; | |
954 | ret = lttng_ht_del(buffer_registry_pid, &iter); | |
955 | assert(!ret); | |
956 | } | |
957 | ||
958 | /* | |
959 | * Destroy buffer registry per PID. The pointer is NOT removed from the global | |
960 | * hash table. Call buffer_reg_pid_remove() before that if the object was | |
961 | * previously added to the global hash table. | |
962 | */ | |
963 | void buffer_reg_pid_destroy(struct buffer_reg_pid *regp) | |
964 | { | |
965 | if (!regp) { | |
966 | return; | |
967 | } | |
968 | ||
d9bf3ca4 MD |
969 | DBG3("Buffer registry per PID destroy with id: %" PRIu64, |
970 | regp->session_id); | |
7972aab2 DG |
971 | |
972 | /* This registry is only used by UST. */ | |
973 | call_rcu(®p->node.head, rcu_free_buffer_reg_pid); | |
974 | } | |
975 | ||
976 | /* | |
977 | * Destroy per PID and UID registry hash table. | |
36b588ed MD |
978 | * |
979 | * Should *NOT* be called with RCU read-side lock held. | |
7972aab2 DG |
980 | */ |
981 | void buffer_reg_destroy_registries(void) | |
982 | { | |
983 | DBG3("Buffer registry destroy all registry"); | |
0b2dc8df MD |
984 | ht_cleanup_push(buffer_registry_uid); |
985 | ht_cleanup_push(buffer_registry_pid); | |
7972aab2 | 986 | } |