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