sessiond: transition from lttng-ust to tracer agnostic API
[lttng-tools.git] / src / bin / lttng-sessiond / ust-registry.cpp
CommitLineData
d0b96690 1/*
ab5be9fa 2 * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
d0b96690 3 *
ab5be9fa 4 * SPDX-License-Identifier: GPL-2.0-only
d0b96690 5 *
d0b96690 6 */
890d8fe4 7
6c1c0768 8#define _LGPL_SOURCE
7972aab2 9
c9e313bc 10#include "ust-registry.hpp"
c9e313bc
SM
11#include "lttng-sessiond.hpp"
12#include "notification-thread-commands.hpp"
d7bfb9b0
JG
13#include "ust-app.hpp"
14#include "utils.hpp"
d0b96690 15
d7bfb9b0
JG
16#include <common/common.hpp>
17#include <common/exception.hpp>
18#include <common/format.hpp>
19#include <common/hashtable/utils.hpp>
20#include <common/make-unique-wrapper.hpp>
21#include <lttng/lttng.h>
10b56aef 22
d7bfb9b0 23#include <inttypes.h>
3b016e58 24
d7bfb9b0
JG
25namespace ls = lttng::sessiond;
26namespace lst = lttng::sessiond::trace;
27namespace lsu = lttng::sessiond::ust;
10b56aef
MD
28
29/*
30 * Hash table match function for enumerations in the session. Match is
31 * performed on enumeration name, and confirmed by comparing the enum
32 * entries.
33 */
34static int ht_match_enum(struct cds_lfht_node *node, const void *_key)
35{
d7bfb9b0
JG
36 lsu::registry_enum *_enum;
37 const lsu::registry_enum *key;
10b56aef 38
a0377dfe
FD
39 LTTNG_ASSERT(node);
40 LTTNG_ASSERT(_key);
10b56aef 41
d7bfb9b0
JG
42 DIAGNOSTIC_PUSH
43 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
44 _enum = caa_container_of(node, lsu::registry_enum,
10b56aef 45 node.node);
d7bfb9b0 46 DIAGNOSTIC_POP
10b56aef 47
d7bfb9b0
JG
48 LTTNG_ASSERT(_enum);
49 key = (lsu::registry_enum *) _key;
10b56aef 50
d7bfb9b0 51 return *_enum == *key;
10b56aef
MD
52}
53
54/*
55 * Hash table match function for enumerations in the session. Match is
56 * performed by enumeration ID.
57 */
58static int ht_match_enum_id(struct cds_lfht_node *node, const void *_key)
59{
d7bfb9b0
JG
60 lsu::registry_enum *_enum;
61 const lsu::registry_enum *key = (lsu::registry_enum *) _key;
10b56aef 62
a0377dfe
FD
63 LTTNG_ASSERT(node);
64 LTTNG_ASSERT(_key);
10b56aef 65
d7bfb9b0
JG
66 DIAGNOSTIC_PUSH
67 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
68 _enum = caa_container_of(node, lsu::registry_enum, node.node);
69 DIAGNOSTIC_POP
70
a0377dfe 71 LTTNG_ASSERT(_enum);
10b56aef
MD
72
73 if (_enum->id != key->id) {
74 goto no_match;
75 }
76
77 /* Match. */
78 return 1;
79
80no_match:
81 return 0;
82}
83
84/*
85 * Hash table hash function for enumerations in the session. The
86 * enumeration name is used for hashing.
87 */
88static unsigned long ht_hash_enum(void *_key, unsigned long seed)
89{
d7bfb9b0 90 lsu::registry_enum *key = (lsu::registry_enum *) _key;
10b56aef 91
a0377dfe 92 LTTNG_ASSERT(key);
d7bfb9b0 93 return hash_key_str(key->name.c_str(), seed);
d0b96690
DG
94}
95
96/*
97 * Destroy event function call of the call RCU.
98 */
d7bfb9b0 99static void ust_registry_event_destroy_rcu(struct rcu_head *head)
d0b96690 100{
d7bfb9b0
JG
101 struct lttng_ht_node_u64 *node = caa_container_of(head, struct lttng_ht_node_u64, head);
102 DIAGNOSTIC_PUSH
103 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
104 lttng::sessiond::ust::registry_event *event =
105 caa_container_of(node, lttng::sessiond::ust::registry_event, _node);
106 DIAGNOSTIC_POP
107
108 lttng::sessiond::ust::registry_event_destroy(event);
d0b96690
DG
109}
110
111/*
112 * For a given event in a registry, delete the entry and destroy the event.
113 * This MUST be called within a RCU read side lock section.
114 */
d7bfb9b0
JG
115void ust_registry_channel_destroy_event(lsu::registry_channel *chan,
116 lttng::sessiond::ust::registry_event *event)
d0b96690
DG
117{
118 int ret;
119 struct lttng_ht_iter iter;
120
a0377dfe
FD
121 LTTNG_ASSERT(chan);
122 LTTNG_ASSERT(event);
48b7cdc2 123 ASSERT_RCU_READ_LOCKED();
d0b96690
DG
124
125 /* Delete the node first. */
d7bfb9b0
JG
126 iter.iter.node = &event->_node.node;
127 ret = lttng_ht_del(chan->_events, &iter);
a0377dfe 128 LTTNG_ASSERT(!ret);
d0b96690 129
d7bfb9b0 130 call_rcu(&event->_node.head, ust_registry_event_destroy_rcu);
d0b96690
DG
131
132 return;
133}
134
d7bfb9b0 135static void destroy_enum(lsu::registry_enum *reg_enum)
10b56aef
MD
136{
137 if (!reg_enum) {
138 return;
139 }
d7bfb9b0
JG
140
141 delete reg_enum;
10b56aef
MD
142}
143
144static void destroy_enum_rcu(struct rcu_head *head)
145{
d7bfb9b0
JG
146 DIAGNOSTIC_PUSH
147 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
148 lsu::registry_enum *reg_enum =
149 caa_container_of(head, lsu::registry_enum, rcu_head);
150 DIAGNOSTIC_POP
10b56aef
MD
151
152 destroy_enum(reg_enum);
153}
154
155/*
156 * Lookup enumeration by name and comparing enumeration entries.
157 * Needs to be called from RCU read-side critical section.
158 */
d7bfb9b0 159static lsu::registry_enum *ust_registry_lookup_enum(
aeeb48c6 160 ust_registry_session *session,
d7bfb9b0 161 const lsu::registry_enum *reg_enum_lookup)
10b56aef 162{
d7bfb9b0 163 lsu::registry_enum *reg_enum = NULL;
10b56aef
MD
164 struct lttng_ht_node_str *node;
165 struct lttng_ht_iter iter;
166
48b7cdc2
FD
167 ASSERT_RCU_READ_LOCKED();
168
aeeb48c6 169 cds_lfht_lookup(session->_enums->ht,
a752d6fa
FD
170 ht_hash_enum((void *) reg_enum_lookup, lttng_ht_seed),
171 ht_match_enum, reg_enum_lookup, &iter.iter);
10b56aef
MD
172 node = lttng_ht_iter_get_node_str(&iter);
173 if (!node) {
174 goto end;
175 }
d7bfb9b0
JG
176
177 DIAGNOSTIC_PUSH
178 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
179 reg_enum = caa_container_of(node, lsu::registry_enum, node);
180 DIAGNOSTIC_POP
181
10b56aef
MD
182end:
183 return reg_enum;
184}
185
186/*
187 * Lookup enumeration by enum ID.
10b56aef 188 */
d7bfb9b0
JG
189lsu::registry_enum::const_rcu_protected_reference
190ust_registry_lookup_enum_by_id(const ust_registry_session *session,
10b56aef
MD
191 const char *enum_name, uint64_t enum_id)
192{
d7bfb9b0 193 lsu::registry_enum *reg_enum = NULL;
10b56aef
MD
194 struct lttng_ht_node_str *node;
195 struct lttng_ht_iter iter;
d7bfb9b0
JG
196 lttng::urcu::unique_read_lock rcu_lock;
197 /*
198 * Hack: only the name is used for hashing; the rest of the attributes
199 * can be fudged.
200 */
201 lsu::registry_signed_enum reg_enum_lookup(enum_name, nullptr, 0);
10b56aef 202
48b7cdc2
FD
203 ASSERT_RCU_READ_LOCKED();
204
10b56aef 205 reg_enum_lookup.id = enum_id;
aeeb48c6 206 cds_lfht_lookup(session->_enums->ht,
10b56aef
MD
207 ht_hash_enum((void *) &reg_enum_lookup, lttng_ht_seed),
208 ht_match_enum_id, &reg_enum_lookup, &iter.iter);
209 node = lttng_ht_iter_get_node_str(&iter);
210 if (!node) {
d7bfb9b0
JG
211 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
212 "Unknown enumeration referenced by application event field: enum name = `{}`, enum id = {}",
213 enum_name, enum_id));
10b56aef 214 }
d7bfb9b0
JG
215
216 DIAGNOSTIC_PUSH
217 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
218 reg_enum = caa_container_of(node, lsu::registry_enum, node);
219 DIAGNOSTIC_POP
220
221 return lsu::registry_enum::const_rcu_protected_reference{*reg_enum, std::move(rcu_lock)};
10b56aef
MD
222}
223
224/*
d7bfb9b0 225 * Create a lsu::registry_enum from the given parameters and add it to the
10b56aef
MD
226 * registry hash table, or find it if already there.
227 *
228 * On success, return 0 else a negative value.
229 *
230 * Should be called with session registry mutex held.
231 *
232 * We receive ownership of entries.
233 */
aeeb48c6 234int ust_registry_create_or_find_enum(ust_registry_session *session,
10b56aef 235 int session_objd, char *enum_name,
d7bfb9b0 236 struct lttng_ust_ctl_enum_entry *raw_entries, size_t nr_entries,
10b56aef
MD
237 uint64_t *enum_id)
238{
239 int ret = 0;
240 struct cds_lfht_node *nodep;
d7bfb9b0
JG
241 lsu::registry_enum *reg_enum = NULL, *old_reg_enum;
242 auto entries = lttng::make_unique_wrapper<lttng_ust_ctl_enum_entry, lttng::free>(raw_entries);
10b56aef 243
a0377dfe
FD
244 LTTNG_ASSERT(session);
245 LTTNG_ASSERT(enum_name);
10b56aef
MD
246
247 rcu_read_lock();
248
249 /*
250 * This should not happen but since it comes from the UST tracer, an
251 * external party, don't assert and simply validate values.
252 */
d7bfb9b0
JG
253 if (session_objd < 0 || nr_entries == 0 ||
254 lttng_strnlen(enum_name, LTTNG_UST_ABI_SYM_NAME_LEN) ==
255 LTTNG_UST_ABI_SYM_NAME_LEN) {
10b56aef
MD
256 ret = -EINVAL;
257 goto end;
258 }
259
d7bfb9b0
JG
260 try {
261 if (entries->start.signedness) {
262 reg_enum = new lsu::registry_signed_enum(
263 enum_name, entries.get(), nr_entries);
264 } else {
265 reg_enum = new lsu::registry_unsigned_enum(
266 enum_name, entries.get(), nr_entries);
267 }
268 } catch (const std::exception& ex) {
269 ERR("Failed to create ust registry enumeration: %s", ex.what());
10b56aef
MD
270 ret = -ENOMEM;
271 goto end;
272 }
10b56aef
MD
273
274 old_reg_enum = ust_registry_lookup_enum(session, reg_enum);
275 if (old_reg_enum) {
276 DBG("enum %s already in sess_objd: %u", enum_name, session_objd);
277 /* Fall through. Use prior enum. */
278 destroy_enum(reg_enum);
279 reg_enum = old_reg_enum;
280 } else {
281 DBG("UST registry creating enum: %s, sess_objd: %u",
282 enum_name, session_objd);
aeeb48c6 283 if (session->_next_enum_id == -1ULL) {
10b56aef
MD
284 ret = -EOVERFLOW;
285 destroy_enum(reg_enum);
286 goto end;
287 }
aeeb48c6 288 reg_enum->id = session->_next_enum_id++;
aeeb48c6 289 nodep = cds_lfht_add_unique(session->_enums->ht,
10b56aef
MD
290 ht_hash_enum(reg_enum, lttng_ht_seed),
291 ht_match_enum_id, reg_enum,
292 &reg_enum->node.node);
a0377dfe 293 LTTNG_ASSERT(nodep == &reg_enum->node.node);
10b56aef
MD
294 }
295 DBG("UST registry reply with enum %s with id %" PRIu64 " in sess_objd: %u",
296 enum_name, reg_enum->id, session_objd);
297 *enum_id = reg_enum->id;
298end:
10b56aef
MD
299 rcu_read_unlock();
300 return ret;
301}
302
303/*
304 * For a given enumeration in a registry, delete the entry and destroy
305 * the enumeration.
306 * This MUST be called within a RCU read side lock section.
307 */
aeeb48c6 308void ust_registry_destroy_enum(ust_registry_session *reg_session,
d7bfb9b0 309 lsu::registry_enum *reg_enum)
10b56aef
MD
310{
311 int ret;
312 struct lttng_ht_iter iter;
313
a0377dfe
FD
314 LTTNG_ASSERT(reg_session);
315 LTTNG_ASSERT(reg_enum);
48b7cdc2 316 ASSERT_RCU_READ_LOCKED();
10b56aef
MD
317
318 /* Delete the node first. */
319 iter.iter.node = &reg_enum->node.node;
aeeb48c6 320 ret = lttng_ht_del(reg_session->_enums.get(), &iter);
a0377dfe 321 LTTNG_ASSERT(!ret);
10b56aef
MD
322 call_rcu(&reg_enum->rcu_head, destroy_enum_rcu);
323}
324
d7bfb9b0 325ust_registry_session *ust_registry_session_per_uid_create(const lttng::sessiond::trace::abi& abi,
af6142cf 326 uint32_t major,
d7ba1388 327 uint32_t minor,
3d071855 328 const char *root_shm_path,
d7ba1388
MD
329 const char *shm_path,
330 uid_t euid,
8de88061
JR
331 gid_t egid,
332 uint64_t tracing_id,
333 uid_t tracing_uid)
d0b96690 334{
aeeb48c6 335 try {
d7bfb9b0 336 return new ust_registry_session_per_uid(abi, major, minor, root_shm_path, shm_path,
aeeb48c6 337 euid, egid, tracing_id, tracing_uid);
d7bfb9b0 338 } catch (const std::exception& ex) {
aeeb48c6
JG
339 ERR("Failed to create per-uid registry session: %s", ex.what());
340 return nullptr;
d7ba1388 341 }
aeeb48c6 342}
8de88061 343
aeeb48c6 344ust_registry_session *ust_registry_session_per_pid_create(struct ust_app *app,
d7bfb9b0 345 const lttng::sessiond::trace::abi& abi,
aeeb48c6
JG
346 uint32_t major,
347 uint32_t minor,
348 const char *root_shm_path,
349 const char *shm_path,
350 uid_t euid,
351 gid_t egid,
352 uint64_t tracing_id)
353{
354 try {
d7bfb9b0
JG
355 return new ust_registry_session_per_pid(*app, abi, major, minor, root_shm_path,
356 shm_path, euid, egid, tracing_id);
357 } catch (const std::exception& ex) {
aeeb48c6
JG
358 ERR("Failed to create per-pid registry session: %s", ex.what());
359 return nullptr;
d0b96690 360 }
d0b96690
DG
361}
362
363/*
364 * Destroy session registry. This does NOT free the given pointer since it
365 * might get passed as a reference. The registry lock should NOT be acquired.
366 */
aeeb48c6 367void ust_registry_session_destroy(ust_registry_session *reg)
d0b96690 368{
aeeb48c6 369 delete reg;
d0b96690 370}
d7bfb9b0
JG
371
372lsu::registry_enum::registry_enum(
373 std::string in_name, enum lst::integer_type::signedness in_signedness) :
374 name{std::move(in_name)}, signedness{in_signedness}
375{
376 cds_lfht_node_init(&this->node.node);
377 this->rcu_head = {};
378}
379
380bool lsu::operator==(const lsu::registry_enum& lhs, const lsu::registry_enum& rhs) noexcept
381{
382 if (lhs.signedness != rhs.signedness) {
383 return false;
384 }
385
386 return lhs._is_equal(rhs);
387}
This page took 0.10861 seconds and 4 git commands to generate.