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