2 * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
10 #include "ust-registry.hpp"
11 #include "lttng-sessiond.hpp"
12 #include "notification-thread-commands.hpp"
13 #include "ust-app.hpp"
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>
25 namespace ls
= lttng::sessiond
;
26 namespace lst
= lttng::sessiond::trace
;
27 namespace lsu
= lttng::sessiond::ust
;
30 * Hash table match function for enumerations in the session. Match is
31 * performed on enumeration name, and confirmed by comparing the enum
34 static int ht_match_enum(struct cds_lfht_node
*node
, const void *_key
)
36 lsu::registry_enum
*_enum
;
37 const lsu::registry_enum
*key
;
43 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
44 _enum
= caa_container_of(node
, lsu::registry_enum
,
49 key
= (lsu::registry_enum
*) _key
;
51 return *_enum
== *key
;
55 * Hash table match function for enumerations in the session. Match is
56 * performed by enumeration ID.
58 static int ht_match_enum_id(struct cds_lfht_node
*node
, const void *_key
)
60 lsu::registry_enum
*_enum
;
61 const lsu::registry_enum
*key
= (lsu::registry_enum
*) _key
;
67 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
68 _enum
= caa_container_of(node
, lsu::registry_enum
, node
.node
);
73 if (_enum
->id
!= key
->id
) {
85 * Hash table hash function for enumerations in the session. The
86 * enumeration name is used for hashing.
88 static unsigned long ht_hash_enum(void *_key
, unsigned long seed
)
90 lsu::registry_enum
*key
= (lsu::registry_enum
*) _key
;
93 return hash_key_str(key
->name
.c_str(), seed
);
97 * Destroy event function call of the call RCU.
99 static void ust_registry_event_destroy_rcu(struct rcu_head
*head
)
101 struct lttng_ht_node_u64
*node
= caa_container_of(head
, struct lttng_ht_node_u64
, head
);
103 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
104 lttng::sessiond::ust::registry_event
*event
=
105 caa_container_of(node
, lttng::sessiond::ust::registry_event
, _node
);
108 lttng::sessiond::ust::registry_event_destroy(event
);
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.
115 void ust_registry_channel_destroy_event(lsu::registry_channel
*chan
,
116 lttng::sessiond::ust::registry_event
*event
)
119 struct lttng_ht_iter iter
;
123 ASSERT_RCU_READ_LOCKED();
125 /* Delete the node first. */
126 iter
.iter
.node
= &event
->_node
.node
;
127 ret
= lttng_ht_del(chan
->_events
, &iter
);
130 call_rcu(&event
->_node
.head
, ust_registry_event_destroy_rcu
);
135 static void destroy_enum(lsu::registry_enum
*reg_enum
)
144 static void destroy_enum_rcu(struct rcu_head
*head
)
147 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
148 lsu::registry_enum
*reg_enum
=
149 caa_container_of(head
, lsu::registry_enum
, rcu_head
);
152 destroy_enum(reg_enum
);
156 * Lookup enumeration by name and comparing enumeration entries.
157 * Needs to be called from RCU read-side critical section.
159 static lsu::registry_enum
*ust_registry_lookup_enum(
160 ust_registry_session
*session
,
161 const lsu::registry_enum
*reg_enum_lookup
)
163 lsu::registry_enum
*reg_enum
= NULL
;
164 struct lttng_ht_node_str
*node
;
165 struct lttng_ht_iter iter
;
167 ASSERT_RCU_READ_LOCKED();
169 cds_lfht_lookup(session
->_enums
->ht
,
170 ht_hash_enum((void *) reg_enum_lookup
, lttng_ht_seed
),
171 ht_match_enum
, reg_enum_lookup
, &iter
.iter
);
172 node
= lttng_ht_iter_get_node_str(&iter
);
178 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
179 reg_enum
= caa_container_of(node
, lsu::registry_enum
, node
);
187 * Lookup enumeration by enum ID.
189 lsu::registry_enum::const_rcu_protected_reference
190 ust_registry_lookup_enum_by_id(const ust_registry_session
*session
,
191 const char *enum_name
, uint64_t enum_id
)
193 lsu::registry_enum
*reg_enum
= NULL
;
194 struct lttng_ht_node_str
*node
;
195 struct lttng_ht_iter iter
;
196 lttng::urcu::unique_read_lock rcu_lock
;
198 * Hack: only the name is used for hashing; the rest of the attributes
201 lsu::registry_signed_enum
reg_enum_lookup(enum_name
, nullptr, 0);
203 ASSERT_RCU_READ_LOCKED();
205 reg_enum_lookup
.id
= enum_id
;
206 cds_lfht_lookup(session
->_enums
->ht
,
207 ht_hash_enum((void *) ®_enum_lookup
, lttng_ht_seed
),
208 ht_match_enum_id
, ®_enum_lookup
, &iter
.iter
);
209 node
= lttng_ht_iter_get_node_str(&iter
);
211 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
212 "Unknown enumeration referenced by application event field: enum name = `{}`, enum id = {}",
213 enum_name
, enum_id
));
217 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
218 reg_enum
= caa_container_of(node
, lsu::registry_enum
, node
);
221 return lsu::registry_enum::const_rcu_protected_reference
{*reg_enum
, std::move(rcu_lock
)};
225 * Create a lsu::registry_enum from the given parameters and add it to the
226 * registry hash table, or find it if already there.
228 * On success, return 0 else a negative value.
230 * Should be called with session registry mutex held.
232 * We receive ownership of entries.
234 int ust_registry_create_or_find_enum(ust_registry_session
*session
,
235 int session_objd
, char *enum_name
,
236 struct lttng_ust_ctl_enum_entry
*raw_entries
, size_t nr_entries
,
240 struct cds_lfht_node
*nodep
;
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
);
244 LTTNG_ASSERT(session
);
245 LTTNG_ASSERT(enum_name
);
250 * This should not happen but since it comes from the UST tracer, an
251 * external party, don't assert and simply validate values.
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
) {
261 if (entries
->start
.signedness
) {
262 reg_enum
= new lsu::registry_signed_enum(
263 enum_name
, entries
.get(), nr_entries
);
265 reg_enum
= new lsu::registry_unsigned_enum(
266 enum_name
, entries
.get(), nr_entries
);
268 } catch (const std::exception
& ex
) {
269 ERR("Failed to create ust registry enumeration: %s", ex
.what());
274 old_reg_enum
= ust_registry_lookup_enum(session
, 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
;
281 DBG("UST registry creating enum: %s, sess_objd: %u",
282 enum_name
, session_objd
);
283 if (session
->_next_enum_id
== -1ULL) {
285 destroy_enum(reg_enum
);
288 reg_enum
->id
= session
->_next_enum_id
++;
289 nodep
= cds_lfht_add_unique(session
->_enums
->ht
,
290 ht_hash_enum(reg_enum
, lttng_ht_seed
),
291 ht_match_enum_id
, reg_enum
,
292 ®_enum
->node
.node
);
293 LTTNG_ASSERT(nodep
== ®_enum
->node
.node
);
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
;
304 * For a given enumeration in a registry, delete the entry and destroy
306 * This MUST be called within a RCU read side lock section.
308 void ust_registry_destroy_enum(ust_registry_session
*reg_session
,
309 lsu::registry_enum
*reg_enum
)
312 struct lttng_ht_iter iter
;
314 LTTNG_ASSERT(reg_session
);
315 LTTNG_ASSERT(reg_enum
);
316 ASSERT_RCU_READ_LOCKED();
318 /* Delete the node first. */
319 iter
.iter
.node
= ®_enum
->node
.node
;
320 ret
= lttng_ht_del(reg_session
->_enums
.get(), &iter
);
322 call_rcu(®_enum
->rcu_head
, destroy_enum_rcu
);
325 ust_registry_session
*ust_registry_session_per_uid_create(const lttng::sessiond::trace::abi
& abi
,
328 const char *root_shm_path
,
329 const char *shm_path
,
336 return new ust_registry_session_per_uid(abi
, major
, minor
, root_shm_path
, shm_path
,
337 euid
, egid
, tracing_id
, tracing_uid
);
338 } catch (const std::exception
& ex
) {
339 ERR("Failed to create per-uid registry session: %s", ex
.what());
344 ust_registry_session
*ust_registry_session_per_pid_create(struct ust_app
*app
,
345 const lttng::sessiond::trace::abi
& abi
,
348 const char *root_shm_path
,
349 const char *shm_path
,
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
) {
358 ERR("Failed to create per-pid registry session: %s", ex
.what());
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.
367 void ust_registry_session_destroy(ust_registry_session
*reg
)
372 lsu::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
}
376 cds_lfht_node_init(&this->node
.node
);
380 bool lsu::operator==(const lsu::registry_enum
& lhs
, const lsu::registry_enum
& rhs
) noexcept
382 if (lhs
.signedness
!= rhs
.signedness
) {
386 return lhs
._is_equal(rhs
);