Add variant type support to ust registry and metadata
[lttng-tools.git] / src / bin / lttng-sessiond / ust-registry.c
CommitLineData
d0b96690
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 */
890d8fe4 17
6c1c0768 18#define _LGPL_SOURCE
d0b96690 19#include <assert.h>
7972aab2 20#include <inttypes.h>
d0b96690
DG
21
22#include <common/common.h>
7972aab2
DG
23#include <common/hashtable/utils.h>
24#include <lttng/lttng.h>
25
d0b96690 26#include "ust-registry.h"
8494bda5 27#include "ust-app.h"
0b2dc8df 28#include "utils.h"
d0b96690
DG
29
30/*
31 * Hash table match function for event in the registry.
32 */
33static int ht_match_event(struct cds_lfht_node *node, const void *_key)
34{
35 struct ust_registry_event *event;
36 const struct ust_registry_event *key;
37
38 assert(node);
39 assert(_key);
40
41 event = caa_container_of(node, struct ust_registry_event, node.node);
42 assert(event);
43 key = _key;
44
45 /* It has to be a perfect match. */
b4d096a6 46 if (strncmp(event->name, key->name, sizeof(event->name))) {
d0b96690
DG
47 goto no_match;
48 }
49
50 /* It has to be a perfect match. */
51 if (strncmp(event->signature, key->signature,
b4d096a6 52 strlen(event->signature))) {
d0b96690
DG
53 goto no_match;
54 }
55
56 /* Match */
57 return 1;
58
59no_match:
60 return 0;
61}
62
7972aab2
DG
63static unsigned long ht_hash_event(void *_key, unsigned long seed)
64{
65 uint64_t xored_key;
66 struct ust_registry_event *key = _key;
67
68 assert(key);
69
70 xored_key = (uint64_t) (hash_key_str(key->name, seed) ^
71 hash_key_str(key->signature, seed));
72
73 return hash_key_u64(&xored_key, seed);
74}
75
10b56aef
MD
76static int compare_enums(const struct ust_registry_enum *reg_enum_a,
77 const struct ust_registry_enum *reg_enum_b)
78{
79 int ret = 0;
80 size_t i;
81
82 assert(strcmp(reg_enum_a->name, reg_enum_b->name) == 0);
83 if (reg_enum_a->nr_entries != reg_enum_b->nr_entries) {
84 ret = -1;
85 goto end;
86 }
87 for (i = 0; i < reg_enum_a->nr_entries; i++) {
88 const struct ustctl_enum_entry *entries_a, *entries_b;
89
90 entries_a = &reg_enum_a->entries[i];
91 entries_b = &reg_enum_b->entries[i];
92 if (entries_a->start != entries_b->start) {
93 ret = -1;
94 goto end;
95 }
96 if (entries_a->end != entries_b->end) {
97 ret = -1;
98 goto end;
99 }
100 if (strcmp(entries_a->string, entries_b->string)) {
101 ret = -1;
102 goto end;
103 }
104 }
105end:
106 return ret;
107}
108
109/*
110 * Hash table match function for enumerations in the session. Match is
111 * performed on enumeration name, and confirmed by comparing the enum
112 * entries.
113 */
114static int ht_match_enum(struct cds_lfht_node *node, const void *_key)
115{
116 struct ust_registry_enum *_enum;
117 const struct ust_registry_enum *key;
118
119 assert(node);
120 assert(_key);
121
122 _enum = caa_container_of(node, struct ust_registry_enum,
123 node.node);
124 assert(_enum);
125 key = _key;
126
127 if (strncmp(_enum->name, key->name, LTTNG_UST_SYM_NAME_LEN)) {
128 goto no_match;
129 }
130 if (compare_enums(_enum, key)) {
131 goto no_match;
132 }
133
134 /* Match. */
135 return 1;
136
137no_match:
138 return 0;
139}
140
141/*
142 * Hash table match function for enumerations in the session. Match is
143 * performed by enumeration ID.
144 */
145static int ht_match_enum_id(struct cds_lfht_node *node, const void *_key)
146{
147 struct ust_registry_enum *_enum;
148 const struct ust_registry_enum *key = _key;
149
150 assert(node);
151 assert(_key);
152
153 _enum = caa_container_of(node, struct ust_registry_enum, node.node);
154 assert(_enum);
155
156 if (_enum->id != key->id) {
157 goto no_match;
158 }
159
160 /* Match. */
161 return 1;
162
163no_match:
164 return 0;
165}
166
167/*
168 * Hash table hash function for enumerations in the session. The
169 * enumeration name is used for hashing.
170 */
171static unsigned long ht_hash_enum(void *_key, unsigned long seed)
172{
173 struct ust_registry_enum *key = _key;
174
175 assert(key);
176 return hash_key_str(key->name, seed);
177}
178
8494bda5
MD
179/*
180 * Return negative value on error, 0 if OK.
181 *
182 * TODO: we could add stricter verification of more types to catch
183 * errors in liblttng-ust implementation earlier than consumption by the
184 * trace reader.
185 */
186static
187int validate_event_field(struct ustctl_field *field,
188 const char *event_name,
189 struct ust_app *app)
190{
da860cab
MD
191 int ret = 0;
192
8494bda5
MD
193 switch(field->type.atype) {
194 case ustctl_atype_integer:
195 case ustctl_atype_enum:
196 case ustctl_atype_array:
197 case ustctl_atype_sequence:
198 case ustctl_atype_string:
da860cab
MD
199 case ustctl_atype_variant:
200 break;
201 case ustctl_atype_struct:
202 if (field->type.u._struct.nr_fields != 0) {
203 WARN("Unsupported non-empty struct field.");
204 ret = -EINVAL;
205 goto end;
206 }
8494bda5
MD
207 break;
208
209 case ustctl_atype_float:
210 switch (field->type.u.basic._float.mant_dig) {
211 case 0:
212 WARN("UST application '%s' (pid: %d) has unknown float mantissa '%u' "
213 "in field '%s', rejecting event '%s'",
214 app->name, app->pid,
215 field->type.u.basic._float.mant_dig,
216 field->name,
217 event_name);
da860cab
MD
218 ret = -EINVAL;
219 goto end;
8494bda5
MD
220 default:
221 break;
222 }
223 break;
224
225 default:
da860cab
MD
226 ret = -ENOENT;
227 goto end;
8494bda5 228 }
da860cab
MD
229end:
230 return ret;
8494bda5
MD
231}
232
233static
234int validate_event_fields(size_t nr_fields, struct ustctl_field *fields,
235 const char *event_name, struct ust_app *app)
236{
237 unsigned int i;
238
239 for (i = 0; i < nr_fields; i++) {
240 if (validate_event_field(&fields[i], event_name, app) < 0)
241 return -EINVAL;
242 }
243 return 0;
244}
245
d0b96690
DG
246/*
247 * Allocate event and initialize it. This does NOT set a valid event id from a
248 * registry.
249 */
250static struct ust_registry_event *alloc_event(int session_objd,
251 int channel_objd, char *name, char *sig, size_t nr_fields,
2106efa0
PP
252 struct ustctl_field *fields, int loglevel_value,
253 char *model_emf_uri, struct ust_app *app)
d0b96690
DG
254{
255 struct ust_registry_event *event = NULL;
256
8494bda5
MD
257 /*
258 * Ensure that the field content is valid.
259 */
260 if (validate_event_fields(nr_fields, fields, name, app) < 0) {
261 return NULL;
262 }
263
d0b96690
DG
264 event = zmalloc(sizeof(*event));
265 if (!event) {
266 PERROR("zmalloc ust registry event");
267 goto error;
268 }
269
270 event->session_objd = session_objd;
271 event->channel_objd = channel_objd;
272 /* Allocated by ustctl. */
273 event->signature = sig;
274 event->nr_fields = nr_fields;
275 event->fields = fields;
2106efa0 276 event->loglevel_value = loglevel_value;
d0b96690
DG
277 event->model_emf_uri = model_emf_uri;
278 if (name) {
279 /* Copy event name and force NULL byte. */
280 strncpy(event->name, name, sizeof(event->name));
281 event->name[sizeof(event->name) - 1] = '\0';
282 }
7972aab2 283 cds_lfht_node_init(&event->node.node);
d0b96690
DG
284
285error:
286 return event;
287}
288
289/*
290 * Free event data structure. This does NOT delete it from any hash table. It's
291 * safe to pass a NULL pointer. This shoudl be called inside a call RCU if the
292 * event is previously deleted from a rcu hash table.
293 */
294static void destroy_event(struct ust_registry_event *event)
295{
296 if (!event) {
297 return;
298 }
299
300 free(event->fields);
301 free(event->model_emf_uri);
302 free(event->signature);
303 free(event);
304}
305
306/*
307 * Destroy event function call of the call RCU.
308 */
309static void destroy_event_rcu(struct rcu_head *head)
310{
7972aab2
DG
311 struct lttng_ht_node_u64 *node =
312 caa_container_of(head, struct lttng_ht_node_u64, head);
d0b96690
DG
313 struct ust_registry_event *event =
314 caa_container_of(node, struct ust_registry_event, node);
315
316 destroy_event(event);
317}
318
319/*
320 * Find an event using the name and signature in the given registry. RCU read
321 * side lock MUST be acquired before calling this function and as long as the
322 * event reference is kept by the caller.
323 *
324 * On success, the event pointer is returned else NULL.
325 */
326struct ust_registry_event *ust_registry_find_event(
327 struct ust_registry_channel *chan, char *name, char *sig)
328{
7972aab2 329 struct lttng_ht_node_u64 *node;
d0b96690
DG
330 struct lttng_ht_iter iter;
331 struct ust_registry_event *event = NULL;
332 struct ust_registry_event key;
333
334 assert(chan);
335 assert(name);
336 assert(sig);
337
338 /* Setup key for the match function. */
339 strncpy(key.name, name, sizeof(key.name));
340 key.name[sizeof(key.name) - 1] = '\0';
341 key.signature = sig;
342
7972aab2 343 cds_lfht_lookup(chan->ht->ht, chan->ht->hash_fct(&key, lttng_ht_seed),
d0b96690 344 chan->ht->match_fct, &key, &iter.iter);
7972aab2 345 node = lttng_ht_iter_get_node_u64(&iter);
d0b96690
DG
346 if (!node) {
347 goto end;
348 }
349 event = caa_container_of(node, struct ust_registry_event, node);
350
351end:
352 return event;
353}
354
355/*
356 * Create a ust_registry_event from the given parameters and add it to the
357 * registry hash table. If event_id is valid, it is set with the newly created
358 * event id.
359 *
360 * On success, return 0 else a negative value. The created event MUST be unique
361 * so on duplicate entry -EINVAL is returned. On error, event_id is untouched.
362 *
363 * Should be called with session registry mutex held.
364 */
365int ust_registry_create_event(struct ust_registry_session *session,
45893984 366 uint64_t chan_key, int session_objd, int channel_objd, char *name,
2106efa0
PP
367 char *sig, size_t nr_fields, struct ustctl_field *fields,
368 int loglevel_value, char *model_emf_uri, int buffer_type,
369 uint32_t *event_id_p, struct ust_app *app)
d0b96690
DG
370{
371 int ret;
7972aab2 372 uint32_t event_id;
d0b96690
DG
373 struct cds_lfht_node *nptr;
374 struct ust_registry_event *event = NULL;
45893984 375 struct ust_registry_channel *chan;
d0b96690
DG
376
377 assert(session);
d0b96690
DG
378 assert(name);
379 assert(sig);
7972aab2 380 assert(event_id_p);
d0b96690 381
d5d629b5
DG
382 rcu_read_lock();
383
d0b96690
DG
384 /*
385 * This should not happen but since it comes from the UST tracer, an
386 * external party, don't assert and simply validate values.
387 */
388 if (session_objd < 0 || channel_objd < 0) {
389 ret = -EINVAL;
d5d629b5 390 goto error_free;
d0b96690
DG
391 }
392
45893984
DG
393 chan = ust_registry_channel_find(session, chan_key);
394 if (!chan) {
395 ret = -EINVAL;
d5d629b5 396 goto error_free;
45893984
DG
397 }
398
d0b96690
DG
399 /* Check if we've reached the maximum possible id. */
400 if (ust_registry_is_max_id(chan->used_event_id)) {
401 ret = -ENOENT;
d5d629b5 402 goto error_free;
d0b96690
DG
403 }
404
405 event = alloc_event(session_objd, channel_objd, name, sig, nr_fields,
2106efa0 406 fields, loglevel_value, model_emf_uri, app);
d0b96690
DG
407 if (!event) {
408 ret = -ENOMEM;
d5d629b5 409 goto error_free;
d0b96690
DG
410 }
411
d0b96690 412 DBG3("UST registry creating event with event: %s, sig: %s, id: %u, "
7972aab2
DG
413 "chan_objd: %u, sess_objd: %u, chan_id: %u", event->name,
414 event->signature, event->id, event->channel_objd,
415 event->session_objd, chan->chan_id);
d0b96690 416
d0b96690
DG
417 /*
418 * This is an add unique with a custom match function for event. The node
419 * are matched using the event name and signature.
420 */
7972aab2 421 nptr = cds_lfht_add_unique(chan->ht->ht, chan->ht->hash_fct(event,
d0b96690
DG
422 lttng_ht_seed), chan->ht->match_fct, event, &event->node.node);
423 if (nptr != &event->node.node) {
7972aab2
DG
424 if (buffer_type == LTTNG_BUFFER_PER_UID) {
425 /*
426 * This is normal, we just have to send the event id of the
427 * returned node and make sure we destroy the previously allocated
428 * event object.
429 */
430 destroy_event(event);
431 event = caa_container_of(nptr, struct ust_registry_event,
432 node.node);
433 assert(event);
434 event_id = event->id;
435 } else {
436 ERR("UST registry create event add unique failed for event: %s, "
437 "sig: %s, id: %u, chan_objd: %u, sess_objd: %u",
438 event->name, event->signature, event->id,
439 event->channel_objd, event->session_objd);
440 ret = -EINVAL;
441 goto error_unlock;
442 }
443 } else {
444 /* Request next event id if the node was successfully added. */
445 event_id = event->id = ust_registry_get_next_event_id(chan);
d0b96690
DG
446 }
447
7972aab2 448 *event_id_p = event_id;
d0b96690 449
7972aab2
DG
450 if (!event->metadata_dumped) {
451 /* Append to metadata */
452 ret = ust_metadata_event_statedump(session, chan, event);
453 if (ret) {
454 ERR("Error appending event metadata (errno = %d)", ret);
455 rcu_read_unlock();
456 return ret;
457 }
d0b96690
DG
458 }
459
45893984 460 rcu_read_unlock();
d0b96690
DG
461 return 0;
462
d5d629b5
DG
463error_free:
464 free(sig);
465 free(fields);
466 free(model_emf_uri);
d0b96690
DG
467error_unlock:
468 rcu_read_unlock();
d0b96690
DG
469 destroy_event(event);
470 return ret;
471}
472
473/*
474 * For a given event in a registry, delete the entry and destroy the event.
475 * This MUST be called within a RCU read side lock section.
476 */
477void ust_registry_destroy_event(struct ust_registry_channel *chan,
478 struct ust_registry_event *event)
479{
480 int ret;
481 struct lttng_ht_iter iter;
482
483 assert(chan);
484 assert(event);
485
486 /* Delete the node first. */
487 iter.iter.node = &event->node.node;
488 ret = lttng_ht_del(chan->ht, &iter);
489 assert(!ret);
490
491 call_rcu(&event->node.head, destroy_event_rcu);
492
493 return;
494}
495
10b56aef
MD
496static void destroy_enum(struct ust_registry_enum *reg_enum)
497{
498 if (!reg_enum) {
499 return;
500 }
501 free(reg_enum->entries);
502 free(reg_enum);
503}
504
505static void destroy_enum_rcu(struct rcu_head *head)
506{
507 struct ust_registry_enum *reg_enum =
508 caa_container_of(head, struct ust_registry_enum, rcu_head);
509
510 destroy_enum(reg_enum);
511}
512
513/*
514 * Lookup enumeration by name and comparing enumeration entries.
515 * Needs to be called from RCU read-side critical section.
516 */
517struct ust_registry_enum *
518 ust_registry_lookup_enum(struct ust_registry_session *session,
519 const struct ust_registry_enum *reg_enum_lookup)
520{
521 struct ust_registry_enum *reg_enum = NULL;
522 struct lttng_ht_node_str *node;
523 struct lttng_ht_iter iter;
524
525 cds_lfht_lookup(session->enums->ht,
526 ht_hash_enum((void *) &reg_enum_lookup, lttng_ht_seed),
527 ht_match_enum, &reg_enum_lookup, &iter.iter);
528 node = lttng_ht_iter_get_node_str(&iter);
529 if (!node) {
530 goto end;
531 }
532 reg_enum = caa_container_of(node, struct ust_registry_enum, node);
533end:
534 return reg_enum;
535}
536
537/*
538 * Lookup enumeration by enum ID.
539 * Needs to be called from RCU read-side critical section.
540 */
541struct ust_registry_enum *
542 ust_registry_lookup_enum_by_id(struct ust_registry_session *session,
543 const char *enum_name, uint64_t enum_id)
544{
545 struct ust_registry_enum *reg_enum = NULL;
546 struct lttng_ht_node_str *node;
547 struct lttng_ht_iter iter;
548 struct ust_registry_enum reg_enum_lookup;
549
550 memset(&reg_enum_lookup, 0, sizeof(reg_enum_lookup));
551 strncpy(reg_enum_lookup.name, enum_name, LTTNG_UST_SYM_NAME_LEN);
552 reg_enum_lookup.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
553 reg_enum_lookup.id = enum_id;
554 cds_lfht_lookup(session->enums->ht,
555 ht_hash_enum((void *) &reg_enum_lookup, lttng_ht_seed),
556 ht_match_enum_id, &reg_enum_lookup, &iter.iter);
557 node = lttng_ht_iter_get_node_str(&iter);
558 if (!node) {
559 goto end;
560 }
561 reg_enum = caa_container_of(node, struct ust_registry_enum, node);
562end:
563 return reg_enum;
564}
565
566/*
567 * Create a ust_registry_enum from the given parameters and add it to the
568 * registry hash table, or find it if already there.
569 *
570 * On success, return 0 else a negative value.
571 *
572 * Should be called with session registry mutex held.
573 *
574 * We receive ownership of entries.
575 */
576int ust_registry_create_or_find_enum(struct ust_registry_session *session,
577 int session_objd, char *enum_name,
578 struct ustctl_enum_entry *entries, size_t nr_entries,
579 uint64_t *enum_id)
580{
581 int ret = 0;
582 struct cds_lfht_node *nodep;
583 struct ust_registry_enum *reg_enum = NULL, *old_reg_enum;
584
585 assert(session);
586 assert(enum_name);
587
588 rcu_read_lock();
589
590 /*
591 * This should not happen but since it comes from the UST tracer, an
592 * external party, don't assert and simply validate values.
593 */
594 if (session_objd < 0) {
595 ret = -EINVAL;
596 goto end;
597 }
598
599 /* Check if the enumeration was already dumped */
600 reg_enum = zmalloc(sizeof(*reg_enum));
601 if (!reg_enum) {
602 PERROR("zmalloc ust registry enumeration");
603 ret = -ENOMEM;
604 goto end;
605 }
606 strncpy(reg_enum->name, enum_name, LTTNG_UST_SYM_NAME_LEN);
607 reg_enum->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
608 /* entries will be owned by reg_enum. */
609 reg_enum->entries = entries;
610 reg_enum->nr_entries = nr_entries;
611 entries = NULL;
612
613 old_reg_enum = ust_registry_lookup_enum(session, reg_enum);
614 if (old_reg_enum) {
615 DBG("enum %s already in sess_objd: %u", enum_name, session_objd);
616 /* Fall through. Use prior enum. */
617 destroy_enum(reg_enum);
618 reg_enum = old_reg_enum;
619 } else {
620 DBG("UST registry creating enum: %s, sess_objd: %u",
621 enum_name, session_objd);
622 if (session->next_enum_id == -1ULL) {
623 ret = -EOVERFLOW;
624 destroy_enum(reg_enum);
625 goto end;
626 }
627 reg_enum->id = session->next_enum_id++;
628 cds_lfht_node_init(&reg_enum->node.node);
629 nodep = cds_lfht_add_unique(session->enums->ht,
630 ht_hash_enum(reg_enum, lttng_ht_seed),
631 ht_match_enum_id, reg_enum,
632 &reg_enum->node.node);
633 assert(nodep == &reg_enum->node.node);
634 }
635 DBG("UST registry reply with enum %s with id %" PRIu64 " in sess_objd: %u",
636 enum_name, reg_enum->id, session_objd);
637 *enum_id = reg_enum->id;
638end:
639 free(entries);
640 rcu_read_unlock();
641 return ret;
642}
643
644/*
645 * For a given enumeration in a registry, delete the entry and destroy
646 * the enumeration.
647 * This MUST be called within a RCU read side lock section.
648 */
649void ust_registry_destroy_enum(struct ust_registry_session *reg_session,
650 struct ust_registry_enum *reg_enum)
651{
652 int ret;
653 struct lttng_ht_iter iter;
654
655 assert(reg_session);
656 assert(reg_enum);
657
658 /* Delete the node first. */
659 iter.iter.node = &reg_enum->node.node;
660 ret = lttng_ht_del(reg_session->enums, &iter);
661 assert(!ret);
662 call_rcu(&reg_enum->rcu_head, destroy_enum_rcu);
663}
664
36b588ed
MD
665/*
666 * We need to execute ht_destroy outside of RCU read-side critical
0b2dc8df
MD
667 * section and outside of call_rcu thread, so we postpone its execution
668 * using ht_cleanup_push. It is simpler than to change the semantic of
669 * the many callers of delete_ust_app_session().
36b588ed
MD
670 */
671static
672void destroy_channel_rcu(struct rcu_head *head)
673{
674 struct ust_registry_channel *chan =
675 caa_container_of(head, struct ust_registry_channel, rcu_head);
676
9dbcf332 677 if (chan->ht) {
0b2dc8df 678 ht_cleanup_push(chan->ht);
9dbcf332 679 }
3295105b 680 free(chan->ctx_fields);
36b588ed
MD
681 free(chan);
682}
683
d0b96690
DG
684/*
685 * Destroy every element of the registry and free the memory. This does NOT
686 * free the registry pointer since it might not have been allocated before so
687 * it's the caller responsability.
d0b96690 688 */
45893984 689static void destroy_channel(struct ust_registry_channel *chan)
d0b96690
DG
690{
691 struct lttng_ht_iter iter;
692 struct ust_registry_event *event;
693
694 assert(chan);
695
9209cee7 696 rcu_read_lock();
d0b96690
DG
697 /* Destroy all event associated with this registry. */
698 cds_lfht_for_each_entry(chan->ht->ht, &iter.iter, event, node.node) {
699 /* Delete the node from the ht and free it. */
700 ust_registry_destroy_event(chan, event);
701 }
9209cee7 702 rcu_read_unlock();
36b588ed 703 call_rcu(&chan->rcu_head, destroy_channel_rcu);
d0b96690
DG
704}
705
706/*
707 * Initialize registry with default values.
708 */
45893984
DG
709int ust_registry_channel_add(struct ust_registry_session *session,
710 uint64_t key)
711{
712 int ret = 0;
713 struct ust_registry_channel *chan;
714
715 assert(session);
716
717 chan = zmalloc(sizeof(*chan));
718 if (!chan) {
719 PERROR("zmalloc ust registry channel");
720 ret = -ENOMEM;
9dbcf332 721 goto error_alloc;
45893984
DG
722 }
723
724 chan->ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
725 if (!chan->ht) {
726 ret = -ENOMEM;
727 goto error;
728 }
729
730 /* Set custom match function. */
731 chan->ht->match_fct = ht_match_event;
7972aab2
DG
732 chan->ht->hash_fct = ht_hash_event;
733
734 /*
735 * Assign a channel ID right now since the event notification comes
736 * *before* the channel notify so the ID needs to be set at this point so
737 * the metadata can be dumped for that event.
738 */
739 if (ust_registry_is_max_id(session->used_channel_id)) {
740 ret = -1;
741 goto error;
742 }
743 chan->chan_id = ust_registry_get_next_chan_id(session);
45893984
DG
744
745 rcu_read_lock();
746 lttng_ht_node_init_u64(&chan->node, key);
747 lttng_ht_add_unique_u64(session->channels, &chan->node);
748 rcu_read_unlock();
749
9dbcf332
DG
750 return 0;
751
45893984 752error:
9dbcf332
DG
753 destroy_channel(chan);
754error_alloc:
45893984
DG
755 return ret;
756}
757
758/*
759 * Find a channel in the given registry. RCU read side lock MUST be acquired
760 * before calling this function and as long as the event reference is kept by
761 * the caller.
762 *
763 * On success, the pointer is returned else NULL.
764 */
765struct ust_registry_channel *ust_registry_channel_find(
766 struct ust_registry_session *session, uint64_t key)
767{
768 struct lttng_ht_node_u64 *node;
769 struct lttng_ht_iter iter;
770 struct ust_registry_channel *chan = NULL;
771
772 assert(session);
773 assert(session->channels);
774
7972aab2
DG
775 DBG3("UST registry channel finding key %" PRIu64, key);
776
45893984
DG
777 lttng_ht_lookup(session->channels, &key, &iter);
778 node = lttng_ht_iter_get_node_u64(&iter);
779 if (!node) {
780 goto end;
781 }
782 chan = caa_container_of(node, struct ust_registry_channel, node);
783
784end:
785 return chan;
786}
787
788/*
789 * Remove channel using key from registry and free memory.
790 */
791void ust_registry_channel_del_free(struct ust_registry_session *session,
792 uint64_t key)
793{
794 struct lttng_ht_iter iter;
795 struct ust_registry_channel *chan;
9209cee7 796 int ret;
45893984
DG
797
798 assert(session);
799
800 rcu_read_lock();
801 chan = ust_registry_channel_find(session, key);
802 if (!chan) {
9209cee7 803 rcu_read_unlock();
45893984
DG
804 goto end;
805 }
806
807 iter.iter.node = &chan->node.node;
9209cee7
MD
808 ret = lttng_ht_del(session->channels, &iter);
809 assert(!ret);
810 rcu_read_unlock();
45893984
DG
811 destroy_channel(chan);
812
813end:
45893984
DG
814 return;
815}
816
817/*
818 * Initialize registry with default values and set the newly allocated session
819 * pointer to sessionp.
820 *
821 * Return 0 on success and sessionp is set or else return -1 and sessionp is
822 * kept untouched.
823 */
824int ust_registry_session_init(struct ust_registry_session **sessionp,
d0b96690
DG
825 struct ust_app *app,
826 uint32_t bits_per_long,
827 uint32_t uint8_t_alignment,
828 uint32_t uint16_t_alignment,
829 uint32_t uint32_t_alignment,
830 uint32_t uint64_t_alignment,
831 uint32_t long_alignment,
af6142cf
MD
832 int byte_order,
833 uint32_t major,
d7ba1388 834 uint32_t minor,
3d071855 835 const char *root_shm_path,
d7ba1388
MD
836 const char *shm_path,
837 uid_t euid,
838 gid_t egid)
d0b96690
DG
839{
840 int ret;
45893984 841 struct ust_registry_session *session;
d0b96690 842
45893984 843 assert(sessionp);
d0b96690 844
45893984
DG
845 session = zmalloc(sizeof(*session));
846 if (!session) {
847 PERROR("zmalloc ust registry session");
9dbcf332 848 goto error_alloc;
45893984 849 }
d0b96690
DG
850
851 pthread_mutex_init(&session->lock, NULL);
852 session->bits_per_long = bits_per_long;
853 session->uint8_t_alignment = uint8_t_alignment;
854 session->uint16_t_alignment = uint16_t_alignment;
855 session->uint32_t_alignment = uint32_t_alignment;
856 session->uint64_t_alignment = uint64_t_alignment;
857 session->long_alignment = long_alignment;
858 session->byte_order = byte_order;
d7ba1388 859 session->metadata_fd = -1;
4628484a
MD
860 session->uid = euid;
861 session->gid = egid;
10b56aef 862 session->next_enum_id = 0;
3d071855
MD
863 strncpy(session->root_shm_path, root_shm_path,
864 sizeof(session->root_shm_path));
865 session->root_shm_path[sizeof(session->root_shm_path) - 1] = '\0';
d7ba1388
MD
866 if (shm_path[0]) {
867 strncpy(session->shm_path, shm_path,
868 sizeof(session->shm_path));
869 session->shm_path[sizeof(session->shm_path) - 1] = '\0';
870 strncpy(session->metadata_path, shm_path,
871 sizeof(session->metadata_path));
872 session->metadata_path[sizeof(session->metadata_path) - 1] = '\0';
873 strncat(session->metadata_path, "/metadata",
874 sizeof(session->metadata_path)
875 - strlen(session->metadata_path) - 1);
876 }
877 if (session->shm_path[0]) {
878 ret = run_as_mkdir_recursive(session->shm_path,
879 S_IRWXU | S_IRWXG,
880 euid, egid);
881 if (ret) {
882 PERROR("run_as_mkdir_recursive");
883 goto error;
884 }
885 }
886 if (session->metadata_path[0]) {
887 /* Create metadata file */
4628484a 888 ret = run_as_open(session->metadata_path,
d7ba1388 889 O_WRONLY | O_CREAT | O_EXCL,
4628484a 890 S_IRUSR | S_IWUSR, euid, egid);
d7ba1388
MD
891 if (ret < 0) {
892 PERROR("Opening metadata file");
893 goto error;
894 }
895 session->metadata_fd = ret;
896 }
d0b96690 897
10b56aef
MD
898 session->enums = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
899 if (!session->enums) {
900 ret = -ENOMEM;
901 goto error;
902 }
903 /* hash/match functions are specified at call site. */
904 session->enums->match_fct = NULL;
905 session->enums->hash_fct = NULL;
906
45893984
DG
907 session->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
908 if (!session->channels) {
909 goto error;
910 }
911
d0b96690
DG
912 ret = lttng_uuid_generate(session->uuid);
913 if (ret) {
914 ERR("Failed to generate UST uuid (errno = %d)", ret);
915 goto error;
916 }
917
918 pthread_mutex_lock(&session->lock);
af6142cf 919 ret = ust_metadata_session_statedump(session, app, major, minor);
d0b96690
DG
920 pthread_mutex_unlock(&session->lock);
921 if (ret) {
922 ERR("Failed to generate session metadata (errno = %d)", ret);
923 goto error;
924 }
925
45893984
DG
926 *sessionp = session;
927
d0b96690
DG
928 return 0;
929
930error:
9dbcf332 931 ust_registry_session_destroy(session);
d24ff3fd 932 free(session);
9dbcf332 933error_alloc:
d0b96690
DG
934 return -1;
935}
936
937/*
938 * Destroy session registry. This does NOT free the given pointer since it
939 * might get passed as a reference. The registry lock should NOT be acquired.
940 */
941void ust_registry_session_destroy(struct ust_registry_session *reg)
942{
943 int ret;
45893984
DG
944 struct lttng_ht_iter iter;
945 struct ust_registry_channel *chan;
10b56aef 946 struct ust_registry_enum *reg_enum;
d0b96690 947
286c991a
MD
948 if (!reg) {
949 return;
950 }
9d8efb0e 951
d0b96690
DG
952 /* On error, EBUSY can be returned if lock. Code flow error. */
953 ret = pthread_mutex_destroy(&reg->lock);
954 assert(!ret);
955
9d8efb0e
DG
956 if (reg->channels) {
957 rcu_read_lock();
958 /* Destroy all event associated with this registry. */
959 cds_lfht_for_each_entry(reg->channels->ht, &iter.iter, chan,
960 node.node) {
961 /* Delete the node from the ht and free it. */
962 ret = lttng_ht_del(reg->channels, &iter);
963 assert(!ret);
964 destroy_channel(chan);
965 }
966 rcu_read_unlock();
967 ht_cleanup_push(reg->channels);
45893984 968 }
45893984 969
d0b96690 970 free(reg->metadata);
d7ba1388
MD
971 if (reg->metadata_fd >= 0) {
972 ret = close(reg->metadata_fd);
973 if (ret) {
974 PERROR("close");
975 }
4628484a
MD
976 ret = run_as_unlink(reg->metadata_path,
977 reg->uid, reg->gid);
d7ba1388
MD
978 if (ret) {
979 PERROR("unlink");
980 }
981 }
3d071855
MD
982 if (reg->root_shm_path[0]) {
983 /*
984 * Try deleting the directory hierarchy.
985 */
4628484a
MD
986 (void) run_as_recursive_rmdir(reg->root_shm_path,
987 reg->uid, reg->gid);
3d071855 988 }
10b56aef
MD
989 /* Destroy the enum hash table */
990 if (reg->enums) {
991 rcu_read_lock();
992 /* Destroy all enum entries associated with this registry. */
993 cds_lfht_for_each_entry(reg->enums->ht, &iter.iter, reg_enum,
994 node.node) {
995 ust_registry_destroy_enum(reg, reg_enum);
996 }
997 rcu_read_unlock();
998 ht_cleanup_push(reg->enums);
999 }
d0b96690 1000}
This page took 0.075646 seconds and 4 git commands to generate.