rculfhash: check for callers from RCU read-side C.S.
[lttng-tools.git] / src / bin / lttng-sessiond / buffer-registry.c
CommitLineData
7972aab2
DG
1/*
2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _GNU_SOURCE
19#include <inttypes.h>
20
21#include <common/common.h>
22#include <common/hashtable/utils.h>
23
24#include "buffer-registry.h"
25#include "fd-limit.h"
26#include "ust-consumer.h"
27#include "ust-ctl.h"
28
29/*
30 * Set in main.c during initialization process of the daemon. This contains
31 * buffer_reg_uid object which are global registry for per UID buffer. Object
32 * are indexed by session id and matched by the triplet
33 * <session_id/bits_per_long/uid>.
34 */
35static struct lttng_ht *buffer_registry_uid;
36
37/*
38 * Initialized at the daemon start. This contains buffer_reg_pid object and
39 * indexed by session id.
40 */
41static struct lttng_ht *buffer_registry_pid;
42
43/*
44 * Match function for the per UID registry hash table. It matches a registry
45 * uid object with the triplet <session_id/abi/uid>.
46 */
47static int ht_match_reg_uid(struct cds_lfht_node *node, const void *_key)
48{
49 struct buffer_reg_uid *reg;
50 const struct buffer_reg_uid *key;
51
52 assert(node);
53 assert(_key);
54
55 reg = caa_container_of(node, struct buffer_reg_uid, node.node);
56 assert(reg);
57 key = _key;
58
59 if (key->session_id != reg->session_id ||
60 key->bits_per_long != reg->bits_per_long ||
61 key->uid != reg->uid) {
62 goto no_match;
63 }
64
65 /* Match */
66 return 1;
67no_match:
68 return 0;
69}
70
71/*
72 * Hash function for the per UID registry hash table. This XOR the triplet
73 * together.
74 */
75static unsigned long ht_hash_reg_uid(void *_key, unsigned long seed)
76{
77 uint64_t xored_key;
78 struct buffer_reg_uid *key = _key;
79
80 assert(key);
81
82 xored_key = (uint64_t)(key->session_id ^ key->bits_per_long ^ key->uid);
83 return hash_key_u64(&xored_key, seed);
84}
85
86/*
87 * Initialize global buffer per UID registry. Should only be called ONCE!.
88 */
89void buffer_reg_init_uid_registry(void)
90{
91 /* Should be called once. */
92 assert(!buffer_registry_uid);
93 buffer_registry_uid = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
94 assert(buffer_registry_uid);
95 buffer_registry_uid->match_fct = ht_match_reg_uid;
96 buffer_registry_uid->hash_fct = ht_hash_reg_uid;
97
98 DBG3("Global buffer per UID registry initialized");
99}
100
101/*
102 * Allocate and initialize object. Set regp with the object pointer.
103 *
104 * Return 0 on success else a negative value and regp is untouched.
105 */
106int buffer_reg_uid_create(int session_id, uint32_t bits_per_long, uid_t uid,
107 enum lttng_domain_type domain, struct buffer_reg_uid **regp)
108{
109 int ret = 0;
110 struct buffer_reg_uid *reg = NULL;
111
112 assert(regp);
113
114 reg = zmalloc(sizeof(*reg));
115 if (!reg) {
116 PERROR("zmalloc buffer registry uid");
117 ret = -ENOMEM;
118 goto error;
119 }
120
121 reg->registry = zmalloc(sizeof(struct buffer_reg_session));
122 if (!reg) {
123 PERROR("zmalloc buffer registry uid session");
124 ret = -ENOMEM;
125 goto error;
126 }
127
128 reg->session_id = session_id;
129 reg->bits_per_long = bits_per_long;
130 reg->uid = uid;
131 reg->domain = domain;
132
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
139 cds_lfht_node_init(&reg->node.node);
140 *regp = reg;
141
142 DBG3("Buffer registry per UID created id: %d, ABI: %u, uid: %d, domain: %d",
143 session_id, bits_per_long, uid, domain);
144
145 return 0;
146
147error_session:
148 free(reg->registry);
149error:
150 free(reg);
151 return ret;
152}
153
154/*
155 * Add a buffer registry per UID object to the global registry.
156 */
157void buffer_reg_uid_add(struct buffer_reg_uid *reg)
158{
159 struct cds_lfht_node *nodep;
160 struct lttng_ht *ht = buffer_registry_uid;
161
162 assert(reg);
163
164 DBG3("Buffer registry per UID adding to global registry with id: %d",
165 reg->session_id);
166
167 rcu_read_lock();
168 nodep = cds_lfht_add_unique(ht->ht, ht->hash_fct(reg, lttng_ht_seed),
169 ht->match_fct, reg, &reg->node.node);
170 assert(nodep == &reg->node.node);
171 rcu_read_unlock();
172}
173
174/*
175 * Find a buffer registry per UID object with given params. RCU read side lock
176 * MUST be acquired before calling this and hold on to protect the object.
177 *
178 * Return the object pointer or NULL on error.
179 */
180struct buffer_reg_uid *buffer_reg_uid_find(int session_id,
181 uint32_t bits_per_long, uid_t uid)
182{
183 struct lttng_ht_node_u64 *node;
184 struct lttng_ht_iter iter;
185 struct buffer_reg_uid *reg = NULL, key;
186 struct lttng_ht *ht = buffer_registry_uid;
187
188 /* Setup key we are looking for. */
189 key.session_id = session_id;
190 key.bits_per_long = bits_per_long;
191 key.uid = uid;
192
193 DBG3("Buffer registry per UID find id: %d, ABI: %u, uid: %d",
194 session_id, bits_per_long, uid);
195
196 /* Custom lookup function since it's a different key. */
197 cds_lfht_lookup(ht->ht, ht->hash_fct(&key, lttng_ht_seed), ht->match_fct,
198 &key, &iter.iter);
199 node = lttng_ht_iter_get_node_u64(&iter);
200 if (!node) {
201 goto end;
202 }
203 reg = caa_container_of(node, struct buffer_reg_uid, node);
204
205end:
206 return reg;
207}
208
209/*
210 * Initialize global buffer per PID registry. Should only be called ONCE!.
211 */
212void buffer_reg_init_pid_registry(void)
213{
214 /* Should be called once. */
215 assert(!buffer_registry_pid);
216 buffer_registry_pid = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
217 assert(buffer_registry_pid);
218
219 DBG3("Global buffer per PID registry initialized");
220}
221
222/*
223 * Allocate and initialize object. Set regp with the object pointer.
224 *
225 * Return 0 on success else a negative value and regp is untouched.
226 */
227int buffer_reg_pid_create(int session_id, struct buffer_reg_pid **regp)
228{
229 int ret = 0;
230 struct buffer_reg_pid *reg = NULL;
231
232 assert(regp);
233
234 reg = zmalloc(sizeof(*reg));
235 if (!reg) {
236 PERROR("zmalloc buffer registry pid");
237 ret = -ENOMEM;
238 goto error;
239 }
240
241 reg->registry = zmalloc(sizeof(struct buffer_reg_session));
242 if (!reg) {
243 PERROR("zmalloc buffer registry pid session");
244 ret = -ENOMEM;
245 goto error;
246 }
247
248 /* A cast is done here so we can use the session ID as a u64 ht node. */
249 reg->session_id = session_id;
250
251 reg->registry->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
252 if (!reg->registry->channels) {
253 ret = -ENOMEM;
254 goto error_session;
255 }
256
257 lttng_ht_node_init_ulong(&reg->node, reg->session_id);
258 *regp = reg;
259
260 DBG3("Buffer registry per PID created with session id: %d", session_id);
261
262 return 0;
263
264error_session:
265 free(reg->registry);
266error:
267 free(reg);
268 return ret;
269}
270
271/*
272 * Add a buffer registry per PID object to the global registry.
273 */
274void buffer_reg_pid_add(struct buffer_reg_pid *reg)
275{
276 assert(reg);
277
278 DBG3("Buffer registry per PID adding to global registry with id: %d",
279 reg->session_id);
280
281 rcu_read_lock();
282 lttng_ht_add_unique_ulong(buffer_registry_pid, &reg->node);
283 rcu_read_unlock();
284}
285
286/*
287 * Find a buffer registry per PID object with given params. RCU read side lock
288 * MUST be acquired before calling this and hold on to protect the object.
289 *
290 * Return the object pointer or NULL on error.
291 */
292struct buffer_reg_pid *buffer_reg_pid_find(int session_id)
293{
294 struct lttng_ht_node_ulong *node;
295 struct lttng_ht_iter iter;
296 struct buffer_reg_pid *reg = NULL;
297 struct lttng_ht *ht = buffer_registry_pid;
298
299 DBG3("Buffer registry per PID find id: %d", session_id);
300
301 lttng_ht_lookup(ht, (void *)((unsigned long) session_id), &iter);
302 node = lttng_ht_iter_get_node_ulong(&iter);
303 if (!node) {
304 goto end;
305 }
306 reg = caa_container_of(node, struct buffer_reg_pid, node);
307
308end:
309 return reg;
310}
311
312/*
313 * Allocate and initialize a buffer registry channel with the given key. Set
314 * regp with the object pointer.
315 *
316 * Return 0 on success or else a negative value keeping regp untouched.
317 */
318int buffer_reg_channel_create(uint64_t key, struct buffer_reg_channel **regp)
319{
320 struct buffer_reg_channel *reg;
321
322 assert(regp);
323
324 DBG3("Buffer registry channel create with key: %" PRIu64, key);
325
326 reg = zmalloc(sizeof(*reg));
327 if (!reg) {
328 PERROR("zmalloc buffer registry channel");
329 return -ENOMEM;
330 }
331
332 reg->key = key;
333 CDS_INIT_LIST_HEAD(&reg->streams);
334 pthread_mutex_init(&reg->stream_list_lock, NULL);
335
336 lttng_ht_node_init_u64(&reg->node, key);
337 *regp = reg;
338
339 return 0;
340}
341
342/*
343 * Allocate and initialize a buffer registry stream. Set regp with the object
344 * pointer.
345 *
346 * Return 0 on success or else a negative value keeping regp untouched.
347 */
348int buffer_reg_stream_create(struct buffer_reg_stream **regp)
349{
350 struct buffer_reg_stream *reg;
351
352 assert(regp);
353
354 DBG3("Buffer registry creating stream");
355
356 reg = zmalloc(sizeof(*reg));
357 if (!reg) {
358 PERROR("zmalloc buffer registry stream");
359 return -ENOMEM;
360 }
361
362 *regp = reg;
363
364 return 0;
365}
366
367/*
368 * Add stream to the list in the channel.
369 */
370void buffer_reg_stream_add(struct buffer_reg_stream *stream,
371 struct buffer_reg_channel *channel)
372{
373 assert(stream);
374 assert(channel);
375
376 pthread_mutex_lock(&channel->stream_list_lock);
377 cds_list_add_tail(&stream->lnode, &channel->streams);
378 pthread_mutex_unlock(&channel->stream_list_lock);
379}
380
381/*
382 * Add a buffer registry channel object to the given session.
383 */
384void buffer_reg_channel_add(struct buffer_reg_session *session,
385 struct buffer_reg_channel *channel)
386{
387 assert(session);
388 assert(channel);
389
390 rcu_read_lock();
391 lttng_ht_add_unique_u64(session->channels, &channel->node);
392 rcu_read_unlock();
393}
394
395/*
396 * Find a buffer registry channel object with the given key. RCU read side lock
397 * MUST be acquired and hold on until the object reference is not needed
398 * anymore.
399 *
400 * Return the object pointer or NULL on error.
401 */
402struct buffer_reg_channel *buffer_reg_channel_find(uint64_t key,
403 struct buffer_reg_uid *reg)
404{
405 struct lttng_ht_node_u64 *node;
406 struct lttng_ht_iter iter;
407 struct buffer_reg_channel *chan = NULL;
408 struct lttng_ht *ht;
409
410 assert(reg);
411
412 switch (reg->domain) {
413 case LTTNG_DOMAIN_UST:
414 ht = reg->registry->channels;
415 break;
416 default:
417 assert(0);
418 goto end;
419 }
420
421 lttng_ht_lookup(ht, &key, &iter);
422 node = lttng_ht_iter_get_node_u64(&iter);
423 if (!node) {
424 goto end;
425 }
426 chan = caa_container_of(node, struct buffer_reg_channel, node);
427
428end:
429 return chan;
430}
431
432/*
433 * Destroy a buffer registry stream with the given domain.
434 */
435void buffer_reg_stream_destroy(struct buffer_reg_stream *regp,
436 enum lttng_domain_type domain)
437{
438 if (!regp) {
439 return;
440 }
441
442 DBG3("Buffer registry stream destroy with handle %d",
443 regp->obj.ust->handle);
444
445 switch (domain) {
446 case LTTNG_DOMAIN_UST:
447 {
448 int ret;
449
450 ret = ust_ctl_release_object(-1, regp->obj.ust);
451 if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
452 ERR("Buffer reg stream release obj handle %d failed with ret %d",
453 regp->obj.ust->handle, ret);
454 }
455 free(regp->obj.ust);
456 lttng_fd_put(LTTNG_FD_APPS, 2);
457 break;
458 }
459 default:
460 assert(0);
461 }
462
463 free(regp);
464 return;
465}
466
467/*
468 * Remove buffer registry channel object from the session hash table. RCU read
469 * side lock MUST be acquired before calling this.
470 */
471void buffer_reg_channel_remove(struct buffer_reg_session *session,
472 struct buffer_reg_channel *regp)
473{
474 int ret;
475 struct lttng_ht_iter iter;
476
477 assert(session);
478 assert(regp);
479
480 iter.iter.node = &regp->node.node;
481 ret = lttng_ht_del(session->channels, &iter);
482 assert(!ret);
483}
484
485/*
486 * Destroy a buffer registry channel with the given domain.
487 */
488void buffer_reg_channel_destroy(struct buffer_reg_channel *regp,
489 enum lttng_domain_type domain)
490{
491 if (!regp) {
492 return;
493 }
494
495 DBG3("Buffer registry channel destroy with key %" PRIu32 " and handle %d",
496 regp->key, regp->obj.ust->handle);
497
498 switch (domain) {
499 case LTTNG_DOMAIN_UST:
500 {
501 int ret;
502 struct buffer_reg_stream *sreg, *stmp;
503 /* Wipe stream */
504 cds_list_for_each_entry_safe(sreg, stmp, &regp->streams, lnode) {
505 cds_list_del(&sreg->lnode);
506 buffer_reg_stream_destroy(sreg, domain);
507 }
508
55d7e860
MD
509 if (regp->obj.ust) {
510 ret = ust_ctl_release_object(-1, regp->obj.ust);
511 if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
512 ERR("Buffer reg channel release obj handle %d failed with ret %d",
513 regp->obj.ust->handle, ret);
514 }
515 free(regp->obj.ust);
7972aab2 516 }
7972aab2
DG
517 lttng_fd_put(LTTNG_FD_APPS, 1);
518 break;
519 }
520 default:
521 assert(0);
522 }
523
524 free(regp);
525 return;
526}
527
528/*
529 * Destroy a buffer registry session with the given domain.
530 */
531void buffer_reg_session_destroy(struct buffer_reg_session *regp,
532 enum lttng_domain_type domain)
533{
534 int ret;
535 struct lttng_ht_iter iter;
536 struct buffer_reg_channel *reg_chan;
537
538 DBG3("Buffer registry session destroy");
539
540 /* Destroy all channels. */
541 rcu_read_lock();
542 cds_lfht_for_each_entry(regp->channels->ht, &iter.iter, reg_chan,
543 node.node) {
544 ret = lttng_ht_del(regp->channels, &iter);
545 assert(!ret);
546 buffer_reg_channel_destroy(reg_chan, domain);
547 }
548 lttng_ht_destroy(regp->channels);
549 rcu_read_unlock();
550
551 switch (domain) {
552 case LTTNG_DOMAIN_UST:
553 ust_registry_session_destroy(regp->reg.ust);
554 free(regp->reg.ust);
555 break;
556 default:
557 assert(0);
558 }
559
560 free(regp);
561 return;
562}
563
564/*
565 * Remove buffer registry UID object from the global hash table. RCU read side
566 * lock MUST be acquired before calling this.
567 */
568void buffer_reg_uid_remove(struct buffer_reg_uid *regp)
569{
570 int ret;
571 struct lttng_ht_iter iter;
572
573 assert(regp);
574
575 iter.iter.node = &regp->node.node;
576 ret = lttng_ht_del(buffer_registry_uid, &iter);
577 assert(!ret);
578}
579
580static void rcu_free_buffer_reg_uid(struct rcu_head *head)
581{
582 struct lttng_ht_node_u64 *node =
583 caa_container_of(head, struct lttng_ht_node_u64, head);
584 struct buffer_reg_uid *reg =
585 caa_container_of(node, struct buffer_reg_uid, node);
586
587 buffer_reg_session_destroy(reg->registry, reg->domain);
588 free(reg);
589}
590
591static void rcu_free_buffer_reg_pid(struct rcu_head *head)
592{
593 struct lttng_ht_node_ulong *node =
594 caa_container_of(head, struct lttng_ht_node_ulong, head);
595 struct buffer_reg_pid *reg =
596 caa_container_of(node, struct buffer_reg_pid, node);
597
598 buffer_reg_session_destroy(reg->registry, LTTNG_DOMAIN_UST);
599 free(reg);
600}
601
602/*
603 * Destroy buffer registry per UID. The given pointer is NOT removed from any
604 * list or hash table. Use buffer_reg_pid_remove() before calling this function
605 * for the case that the object is in the global hash table.
606 */
607void buffer_reg_uid_destroy(struct buffer_reg_uid *regp,
608 struct consumer_output *consumer)
609{
610 struct consumer_socket *socket;
611
612 if (!regp) {
613 return;
614 }
615
616 DBG3("Buffer registry per UID destroy with id: %d, ABI: %u, uid: %d",
617 regp->session_id, regp->bits_per_long, regp->uid);
618
619 if (!consumer) {
620 goto destroy;
621 }
622
623 /* Get the right socket from the consumer object. */
624 socket = consumer_find_socket_by_bitness(regp->bits_per_long,
625 consumer);
626 if (!socket) {
627 goto destroy;
628 }
629
630 switch (regp->domain) {
631 case LTTNG_DOMAIN_UST:
632 if (regp->registry->reg.ust->metadata_key) {
633 /* Return value does not matter. This call will print errors. */
634 (void) consumer_close_metadata(socket,
635 regp->registry->reg.ust->metadata_key);
636 }
637 break;
638 default:
639 assert(0);
640 return;
641 }
642
643destroy:
644 call_rcu(&regp->node.head, rcu_free_buffer_reg_uid);
645}
646
647/*
648 * Remove buffer registry UID object from the global hash table. RCU read side
649 * lock MUST be acquired before calling this.
650 */
651void buffer_reg_pid_remove(struct buffer_reg_pid *regp)
652{
653 int ret;
654 struct lttng_ht_iter iter;
655
656 assert(regp);
657
658 iter.iter.node = &regp->node.node;
659 ret = lttng_ht_del(buffer_registry_pid, &iter);
660 assert(!ret);
661}
662
663/*
664 * Destroy buffer registry per PID. The pointer is NOT removed from the global
665 * hash table. Call buffer_reg_pid_remove() before that if the object was
666 * previously added to the global hash table.
667 */
668void buffer_reg_pid_destroy(struct buffer_reg_pid *regp)
669{
670 if (!regp) {
671 return;
672 }
673
674 DBG3("Buffer registry per PID destroy with id: %d", regp->session_id);
675
676 /* This registry is only used by UST. */
677 call_rcu(&regp->node.head, rcu_free_buffer_reg_pid);
678}
679
680/*
681 * Destroy per PID and UID registry hash table.
682 */
683void buffer_reg_destroy_registries(void)
684{
685 DBG3("Buffer registry destroy all registry");
686 lttng_ht_destroy(buffer_registry_uid);
687 lttng_ht_destroy(buffer_registry_pid);
688}
This page took 0.076646 seconds and 4 git commands to generate.