rculfhash: check for callers from RCU read-side C.S.
[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 */
17#define _GNU_SOURCE
18#include <assert.h>
7972aab2 19#include <inttypes.h>
d0b96690
DG
20
21#include <common/common.h>
7972aab2
DG
22#include <common/hashtable/utils.h>
23#include <lttng/lttng.h>
24
d0b96690
DG
25#include "ust-registry.h"
26
27/*
28 * Hash table match function for event in the registry.
29 */
30static int ht_match_event(struct cds_lfht_node *node, const void *_key)
31{
32 struct ust_registry_event *event;
33 const struct ust_registry_event *key;
34
35 assert(node);
36 assert(_key);
37
38 event = caa_container_of(node, struct ust_registry_event, node.node);
39 assert(event);
40 key = _key;
41
42 /* It has to be a perfect match. */
43 if (strncmp(event->name, key->name, sizeof(event->name)) != 0) {
44 goto no_match;
45 }
46
47 /* It has to be a perfect match. */
48 if (strncmp(event->signature, key->signature,
49 strlen(event->signature) != 0)) {
50 goto no_match;
51 }
52
53 /* Match */
54 return 1;
55
56no_match:
57 return 0;
58}
59
7972aab2
DG
60static unsigned long ht_hash_event(void *_key, unsigned long seed)
61{
62 uint64_t xored_key;
63 struct ust_registry_event *key = _key;
64
65 assert(key);
66
67 xored_key = (uint64_t) (hash_key_str(key->name, seed) ^
68 hash_key_str(key->signature, seed));
69
70 return hash_key_u64(&xored_key, seed);
71}
72
d0b96690
DG
73/*
74 * Allocate event and initialize it. This does NOT set a valid event id from a
75 * registry.
76 */
77static struct ust_registry_event *alloc_event(int session_objd,
78 int channel_objd, char *name, char *sig, size_t nr_fields,
79 struct ustctl_field *fields, int loglevel, char *model_emf_uri)
80{
81 struct ust_registry_event *event = NULL;
82
83 event = zmalloc(sizeof(*event));
84 if (!event) {
85 PERROR("zmalloc ust registry event");
86 goto error;
87 }
88
89 event->session_objd = session_objd;
90 event->channel_objd = channel_objd;
91 /* Allocated by ustctl. */
92 event->signature = sig;
93 event->nr_fields = nr_fields;
94 event->fields = fields;
95 event->loglevel = loglevel;
96 event->model_emf_uri = model_emf_uri;
97 if (name) {
98 /* Copy event name and force NULL byte. */
99 strncpy(event->name, name, sizeof(event->name));
100 event->name[sizeof(event->name) - 1] = '\0';
101 }
7972aab2 102 cds_lfht_node_init(&event->node.node);
d0b96690
DG
103
104error:
105 return event;
106}
107
108/*
109 * Free event data structure. This does NOT delete it from any hash table. It's
110 * safe to pass a NULL pointer. This shoudl be called inside a call RCU if the
111 * event is previously deleted from a rcu hash table.
112 */
113static void destroy_event(struct ust_registry_event *event)
114{
115 if (!event) {
116 return;
117 }
118
119 free(event->fields);
120 free(event->model_emf_uri);
121 free(event->signature);
122 free(event);
123}
124
125/*
126 * Destroy event function call of the call RCU.
127 */
128static void destroy_event_rcu(struct rcu_head *head)
129{
7972aab2
DG
130 struct lttng_ht_node_u64 *node =
131 caa_container_of(head, struct lttng_ht_node_u64, head);
d0b96690
DG
132 struct ust_registry_event *event =
133 caa_container_of(node, struct ust_registry_event, node);
134
135 destroy_event(event);
136}
137
138/*
139 * Find an event using the name and signature in the given registry. RCU read
140 * side lock MUST be acquired before calling this function and as long as the
141 * event reference is kept by the caller.
142 *
143 * On success, the event pointer is returned else NULL.
144 */
145struct ust_registry_event *ust_registry_find_event(
146 struct ust_registry_channel *chan, char *name, char *sig)
147{
7972aab2 148 struct lttng_ht_node_u64 *node;
d0b96690
DG
149 struct lttng_ht_iter iter;
150 struct ust_registry_event *event = NULL;
151 struct ust_registry_event key;
152
153 assert(chan);
154 assert(name);
155 assert(sig);
156
157 /* Setup key for the match function. */
158 strncpy(key.name, name, sizeof(key.name));
159 key.name[sizeof(key.name) - 1] = '\0';
160 key.signature = sig;
161
7972aab2 162 cds_lfht_lookup(chan->ht->ht, chan->ht->hash_fct(&key, lttng_ht_seed),
d0b96690 163 chan->ht->match_fct, &key, &iter.iter);
7972aab2 164 node = lttng_ht_iter_get_node_u64(&iter);
d0b96690
DG
165 if (!node) {
166 goto end;
167 }
168 event = caa_container_of(node, struct ust_registry_event, node);
169
170end:
171 return event;
172}
173
174/*
175 * Create a ust_registry_event from the given parameters and add it to the
176 * registry hash table. If event_id is valid, it is set with the newly created
177 * event id.
178 *
179 * On success, return 0 else a negative value. The created event MUST be unique
180 * so on duplicate entry -EINVAL is returned. On error, event_id is untouched.
181 *
182 * Should be called with session registry mutex held.
183 */
184int ust_registry_create_event(struct ust_registry_session *session,
45893984
DG
185 uint64_t chan_key, int session_objd, int channel_objd, char *name,
186 char *sig, size_t nr_fields, struct ustctl_field *fields, int loglevel,
7972aab2 187 char *model_emf_uri, int buffer_type, uint32_t *event_id_p)
d0b96690
DG
188{
189 int ret;
7972aab2 190 uint32_t event_id;
d0b96690
DG
191 struct cds_lfht_node *nptr;
192 struct ust_registry_event *event = NULL;
45893984 193 struct ust_registry_channel *chan;
d0b96690
DG
194
195 assert(session);
d0b96690
DG
196 assert(name);
197 assert(sig);
7972aab2 198 assert(event_id_p);
d0b96690
DG
199
200 /*
201 * This should not happen but since it comes from the UST tracer, an
202 * external party, don't assert and simply validate values.
203 */
204 if (session_objd < 0 || channel_objd < 0) {
205 ret = -EINVAL;
206 goto error;
207 }
208
45893984
DG
209 rcu_read_lock();
210
211 chan = ust_registry_channel_find(session, chan_key);
212 if (!chan) {
213 ret = -EINVAL;
214 goto error_unlock;
215 }
216
d0b96690
DG
217 /* Check if we've reached the maximum possible id. */
218 if (ust_registry_is_max_id(chan->used_event_id)) {
219 ret = -ENOENT;
45893984 220 goto error_unlock;
d0b96690
DG
221 }
222
223 event = alloc_event(session_objd, channel_objd, name, sig, nr_fields,
224 fields, loglevel, model_emf_uri);
225 if (!event) {
226 ret = -ENOMEM;
45893984 227 goto error_unlock;
d0b96690
DG
228 }
229
d0b96690 230 DBG3("UST registry creating event with event: %s, sig: %s, id: %u, "
7972aab2
DG
231 "chan_objd: %u, sess_objd: %u, chan_id: %u", event->name,
232 event->signature, event->id, event->channel_objd,
233 event->session_objd, chan->chan_id);
d0b96690 234
d0b96690
DG
235 /*
236 * This is an add unique with a custom match function for event. The node
237 * are matched using the event name and signature.
238 */
7972aab2 239 nptr = cds_lfht_add_unique(chan->ht->ht, chan->ht->hash_fct(event,
d0b96690
DG
240 lttng_ht_seed), chan->ht->match_fct, event, &event->node.node);
241 if (nptr != &event->node.node) {
7972aab2
DG
242 if (buffer_type == LTTNG_BUFFER_PER_UID) {
243 /*
244 * This is normal, we just have to send the event id of the
245 * returned node and make sure we destroy the previously allocated
246 * event object.
247 */
248 destroy_event(event);
249 event = caa_container_of(nptr, struct ust_registry_event,
250 node.node);
251 assert(event);
252 event_id = event->id;
253 } else {
254 ERR("UST registry create event add unique failed for event: %s, "
255 "sig: %s, id: %u, chan_objd: %u, sess_objd: %u",
256 event->name, event->signature, event->id,
257 event->channel_objd, event->session_objd);
258 ret = -EINVAL;
259 goto error_unlock;
260 }
261 } else {
262 /* Request next event id if the node was successfully added. */
263 event_id = event->id = ust_registry_get_next_event_id(chan);
d0b96690
DG
264 }
265
7972aab2 266 *event_id_p = event_id;
d0b96690 267
7972aab2
DG
268 if (!event->metadata_dumped) {
269 /* Append to metadata */
270 ret = ust_metadata_event_statedump(session, chan, event);
271 if (ret) {
272 ERR("Error appending event metadata (errno = %d)", ret);
273 rcu_read_unlock();
274 return ret;
275 }
d0b96690
DG
276 }
277
45893984 278 rcu_read_unlock();
d0b96690
DG
279 return 0;
280
281error_unlock:
282 rcu_read_unlock();
283error:
284 destroy_event(event);
285 return ret;
286}
287
288/*
289 * For a given event in a registry, delete the entry and destroy the event.
290 * This MUST be called within a RCU read side lock section.
291 */
292void ust_registry_destroy_event(struct ust_registry_channel *chan,
293 struct ust_registry_event *event)
294{
295 int ret;
296 struct lttng_ht_iter iter;
297
298 assert(chan);
299 assert(event);
300
301 /* Delete the node first. */
302 iter.iter.node = &event->node.node;
303 ret = lttng_ht_del(chan->ht, &iter);
304 assert(!ret);
305
306 call_rcu(&event->node.head, destroy_event_rcu);
307
308 return;
309}
310
d0b96690
DG
311/*
312 * Destroy every element of the registry and free the memory. This does NOT
313 * free the registry pointer since it might not have been allocated before so
314 * it's the caller responsability.
315 *
9209cee7 316 * This *MUST NOT* be called within a RCU read side lock section.
d0b96690 317 */
45893984 318static void destroy_channel(struct ust_registry_channel *chan)
d0b96690
DG
319{
320 struct lttng_ht_iter iter;
321 struct ust_registry_event *event;
322
323 assert(chan);
324
9209cee7 325 rcu_read_lock();
d0b96690
DG
326 /* Destroy all event associated with this registry. */
327 cds_lfht_for_each_entry(chan->ht->ht, &iter.iter, event, node.node) {
328 /* Delete the node from the ht and free it. */
329 ust_registry_destroy_event(chan, event);
330 }
9209cee7 331 rcu_read_unlock();
45893984 332
9209cee7 333 lttng_ht_destroy(chan->ht);
45893984 334 free(chan);
d0b96690
DG
335}
336
337/*
338 * Initialize registry with default values.
339 */
45893984
DG
340int ust_registry_channel_add(struct ust_registry_session *session,
341 uint64_t key)
342{
343 int ret = 0;
344 struct ust_registry_channel *chan;
345
346 assert(session);
347
348 chan = zmalloc(sizeof(*chan));
349 if (!chan) {
350 PERROR("zmalloc ust registry channel");
351 ret = -ENOMEM;
352 goto error;
353 }
354
355 chan->ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
356 if (!chan->ht) {
357 ret = -ENOMEM;
358 goto error;
359 }
360
361 /* Set custom match function. */
362 chan->ht->match_fct = ht_match_event;
7972aab2
DG
363 chan->ht->hash_fct = ht_hash_event;
364
365 /*
366 * Assign a channel ID right now since the event notification comes
367 * *before* the channel notify so the ID needs to be set at this point so
368 * the metadata can be dumped for that event.
369 */
370 if (ust_registry_is_max_id(session->used_channel_id)) {
371 ret = -1;
372 goto error;
373 }
374 chan->chan_id = ust_registry_get_next_chan_id(session);
45893984
DG
375
376 rcu_read_lock();
377 lttng_ht_node_init_u64(&chan->node, key);
378 lttng_ht_add_unique_u64(session->channels, &chan->node);
379 rcu_read_unlock();
380
381error:
382 return ret;
383}
384
385/*
386 * Find a channel in the given registry. RCU read side lock MUST be acquired
387 * before calling this function and as long as the event reference is kept by
388 * the caller.
389 *
390 * On success, the pointer is returned else NULL.
391 */
392struct ust_registry_channel *ust_registry_channel_find(
393 struct ust_registry_session *session, uint64_t key)
394{
395 struct lttng_ht_node_u64 *node;
396 struct lttng_ht_iter iter;
397 struct ust_registry_channel *chan = NULL;
398
399 assert(session);
400 assert(session->channels);
401
7972aab2
DG
402 DBG3("UST registry channel finding key %" PRIu64, key);
403
45893984
DG
404 lttng_ht_lookup(session->channels, &key, &iter);
405 node = lttng_ht_iter_get_node_u64(&iter);
406 if (!node) {
407 goto end;
408 }
409 chan = caa_container_of(node, struct ust_registry_channel, node);
410
411end:
412 return chan;
413}
414
415/*
416 * Remove channel using key from registry and free memory.
417 */
418void ust_registry_channel_del_free(struct ust_registry_session *session,
419 uint64_t key)
420{
421 struct lttng_ht_iter iter;
422 struct ust_registry_channel *chan;
9209cee7 423 int ret;
45893984
DG
424
425 assert(session);
426
427 rcu_read_lock();
428 chan = ust_registry_channel_find(session, key);
429 if (!chan) {
9209cee7 430 rcu_read_unlock();
45893984
DG
431 goto end;
432 }
433
434 iter.iter.node = &chan->node.node;
9209cee7
MD
435 ret = lttng_ht_del(session->channels, &iter);
436 assert(!ret);
437 rcu_read_unlock();
45893984 438
9209cee7
MD
439 /*
440 * Destroying the hash table should be done without RCU
441 * read-side lock held. Since we own "chan" now, it is OK to use
442 * it outside of RCU read-side critical section.
443 */
45893984
DG
444 destroy_channel(chan);
445
446end:
45893984
DG
447 return;
448}
449
450/*
451 * Initialize registry with default values and set the newly allocated session
452 * pointer to sessionp.
453 *
454 * Return 0 on success and sessionp is set or else return -1 and sessionp is
455 * kept untouched.
456 */
457int ust_registry_session_init(struct ust_registry_session **sessionp,
d0b96690
DG
458 struct ust_app *app,
459 uint32_t bits_per_long,
460 uint32_t uint8_t_alignment,
461 uint32_t uint16_t_alignment,
462 uint32_t uint32_t_alignment,
463 uint32_t uint64_t_alignment,
464 uint32_t long_alignment,
af6142cf
MD
465 int byte_order,
466 uint32_t major,
467 uint32_t minor)
d0b96690
DG
468{
469 int ret;
45893984 470 struct ust_registry_session *session;
d0b96690 471
45893984 472 assert(sessionp);
d0b96690 473
45893984
DG
474 session = zmalloc(sizeof(*session));
475 if (!session) {
476 PERROR("zmalloc ust registry session");
477 goto error;
478 }
d0b96690
DG
479
480 pthread_mutex_init(&session->lock, NULL);
481 session->bits_per_long = bits_per_long;
482 session->uint8_t_alignment = uint8_t_alignment;
483 session->uint16_t_alignment = uint16_t_alignment;
484 session->uint32_t_alignment = uint32_t_alignment;
485 session->uint64_t_alignment = uint64_t_alignment;
486 session->long_alignment = long_alignment;
487 session->byte_order = byte_order;
488
45893984
DG
489 session->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
490 if (!session->channels) {
491 goto error;
492 }
493
d0b96690
DG
494 ret = lttng_uuid_generate(session->uuid);
495 if (ret) {
496 ERR("Failed to generate UST uuid (errno = %d)", ret);
497 goto error;
498 }
499
500 pthread_mutex_lock(&session->lock);
af6142cf 501 ret = ust_metadata_session_statedump(session, app, major, minor);
d0b96690
DG
502 pthread_mutex_unlock(&session->lock);
503 if (ret) {
504 ERR("Failed to generate session metadata (errno = %d)", ret);
505 goto error;
506 }
507
45893984
DG
508 *sessionp = session;
509
d0b96690
DG
510 return 0;
511
512error:
513 return -1;
514}
515
516/*
517 * Destroy session registry. This does NOT free the given pointer since it
518 * might get passed as a reference. The registry lock should NOT be acquired.
519 */
520void ust_registry_session_destroy(struct ust_registry_session *reg)
521{
522 int ret;
45893984
DG
523 struct lttng_ht_iter iter;
524 struct ust_registry_channel *chan;
d0b96690
DG
525
526 /* On error, EBUSY can be returned if lock. Code flow error. */
527 ret = pthread_mutex_destroy(&reg->lock);
528 assert(!ret);
529
45893984
DG
530 rcu_read_lock();
531 /* Destroy all event associated with this registry. */
532 cds_lfht_for_each_entry(reg->channels->ht, &iter.iter, chan, node.node) {
533 /* Delete the node from the ht and free it. */
534 ret = lttng_ht_del(reg->channels, &iter);
535 assert(!ret);
536 destroy_channel(chan);
537 }
538 lttng_ht_destroy(reg->channels);
539 rcu_read_unlock();
540
d0b96690
DG
541 free(reg->metadata);
542}
This page took 0.045004 seconds and 4 git commands to generate.