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"
14 #include "ust-registry-session-pid.hpp"
15 #include "ust-registry-session-uid.hpp"
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>
27 namespace ls
= lttng::sessiond
;
28 namespace lst
= lttng::sessiond::trace
;
29 namespace lsu
= lttng::sessiond::ust
;
32 * Hash table match function for enumerations in the session. Match is
33 * performed on enumeration name, and confirmed by comparing the enum
36 static int ht_match_enum(struct cds_lfht_node
*node
, const void *_key
)
38 lsu::registry_enum
*_enum
;
39 const lsu::registry_enum
*key
;
45 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
46 _enum
= caa_container_of(node
, lsu::registry_enum
,
51 key
= (lsu::registry_enum
*) _key
;
53 return *_enum
== *key
;
57 * Hash table match function for enumerations in the session. Match is
58 * performed by enumeration ID.
60 static int ht_match_enum_id(struct cds_lfht_node
*node
, const void *_key
)
62 lsu::registry_enum
*_enum
;
63 const lsu::registry_enum
*key
= (lsu::registry_enum
*) _key
;
69 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
70 _enum
= caa_container_of(node
, lsu::registry_enum
, node
.node
);
75 if (_enum
->id
!= key
->id
) {
87 * Hash table hash function for enumerations in the session. The
88 * enumeration name is used for hashing.
90 static unsigned long ht_hash_enum(void *_key
, unsigned long seed
)
92 lsu::registry_enum
*key
= (lsu::registry_enum
*) _key
;
95 return hash_key_str(key
->name
.c_str(), seed
);
99 * Destroy event function call of the call RCU.
101 static void ust_registry_event_destroy_rcu(struct rcu_head
*head
)
103 struct lttng_ht_node_u64
*node
= caa_container_of(head
, struct lttng_ht_node_u64
, head
);
105 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
106 lttng::sessiond::ust::registry_event
*event
=
107 caa_container_of(node
, lttng::sessiond::ust::registry_event
, _node
);
110 lttng::sessiond::ust::registry_event_destroy(event
);
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.
117 void ust_registry_channel_destroy_event(lsu::registry_channel
*chan
,
118 lttng::sessiond::ust::registry_event
*event
)
121 struct lttng_ht_iter iter
;
125 ASSERT_RCU_READ_LOCKED();
127 /* Delete the node first. */
128 iter
.iter
.node
= &event
->_node
.node
;
129 ret
= lttng_ht_del(chan
->_events
, &iter
);
132 call_rcu(&event
->_node
.head
, ust_registry_event_destroy_rcu
);
137 static void destroy_enum(lsu::registry_enum
*reg_enum
)
146 static void destroy_enum_rcu(struct rcu_head
*head
)
149 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
150 lsu::registry_enum
*reg_enum
=
151 caa_container_of(head
, lsu::registry_enum
, rcu_head
);
154 destroy_enum(reg_enum
);
158 * Lookup enumeration by name and comparing enumeration entries.
159 * Needs to be called from RCU read-side critical section.
161 static lsu::registry_enum
*ust_registry_lookup_enum(
162 lsu::registry_session
*session
,
163 const lsu::registry_enum
*reg_enum_lookup
)
165 lsu::registry_enum
*reg_enum
= NULL
;
166 struct lttng_ht_node_str
*node
;
167 struct lttng_ht_iter iter
;
169 ASSERT_RCU_READ_LOCKED();
171 cds_lfht_lookup(session
->_enums
->ht
,
172 ht_hash_enum((void *) reg_enum_lookup
, lttng_ht_seed
),
173 ht_match_enum
, reg_enum_lookup
, &iter
.iter
);
174 node
= lttng_ht_iter_get_node_str(&iter
);
180 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
181 reg_enum
= caa_container_of(node
, lsu::registry_enum
, node
);
189 * Lookup enumeration by enum ID.
191 lsu::registry_enum::const_rcu_protected_reference
192 ust_registry_lookup_enum_by_id(const lsu::registry_session
*session
,
193 const char *enum_name
, uint64_t enum_id
)
195 lsu::registry_enum
*reg_enum
= NULL
;
196 struct lttng_ht_node_str
*node
;
197 struct lttng_ht_iter iter
;
198 lttng::urcu::unique_read_lock rcu_lock
;
200 * Hack: only the name is used for hashing; the rest of the attributes
203 lsu::registry_signed_enum
reg_enum_lookup(enum_name
, nullptr, 0);
205 ASSERT_RCU_READ_LOCKED();
207 reg_enum_lookup
.id
= enum_id
;
208 cds_lfht_lookup(session
->_enums
->ht
,
209 ht_hash_enum((void *) ®_enum_lookup
, lttng_ht_seed
),
210 ht_match_enum_id
, ®_enum_lookup
, &iter
.iter
);
211 node
= lttng_ht_iter_get_node_str(&iter
);
213 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
214 "Unknown enumeration referenced by application event field: enum name = `{}`, enum id = {}",
215 enum_name
, enum_id
));
219 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
220 reg_enum
= caa_container_of(node
, lsu::registry_enum
, node
);
223 return lsu::registry_enum::const_rcu_protected_reference
{*reg_enum
, std::move(rcu_lock
)};
227 * Create a lsu::registry_enum from the given parameters and add it to the
228 * registry hash table, or find it if already there.
230 * On success, return 0 else a negative value.
232 * Should be called with session registry mutex held.
234 * We receive ownership of entries.
236 int ust_registry_create_or_find_enum(lsu::registry_session
*session
,
237 int session_objd
, char *enum_name
,
238 struct lttng_ust_ctl_enum_entry
*raw_entries
, size_t nr_entries
,
242 struct cds_lfht_node
*nodep
;
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
);
246 LTTNG_ASSERT(session
);
247 LTTNG_ASSERT(enum_name
);
252 * This should not happen but since it comes from the UST tracer, an
253 * external party, don't assert and simply validate values.
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
) {
263 if (entries
->start
.signedness
) {
264 reg_enum
= new lsu::registry_signed_enum(
265 enum_name
, entries
.get(), nr_entries
);
267 reg_enum
= new lsu::registry_unsigned_enum(
268 enum_name
, entries
.get(), nr_entries
);
270 } catch (const std::exception
& ex
) {
271 ERR("Failed to create ust registry enumeration: %s", ex
.what());
276 old_reg_enum
= ust_registry_lookup_enum(session
, 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
;
283 DBG("UST registry creating enum: %s, sess_objd: %u",
284 enum_name
, session_objd
);
285 if (session
->_next_enum_id
== -1ULL) {
287 destroy_enum(reg_enum
);
290 reg_enum
->id
= session
->_next_enum_id
++;
291 nodep
= cds_lfht_add_unique(session
->_enums
->ht
,
292 ht_hash_enum(reg_enum
, lttng_ht_seed
),
293 ht_match_enum_id
, reg_enum
,
294 ®_enum
->node
.node
);
295 LTTNG_ASSERT(nodep
== ®_enum
->node
.node
);
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
;
306 * For a given enumeration in a registry, delete the entry and destroy
308 * This MUST be called within a RCU read side lock section.
310 void ust_registry_destroy_enum(lsu::registry_session
*reg_session
,
311 lsu::registry_enum
*reg_enum
)
314 struct lttng_ht_iter iter
;
316 LTTNG_ASSERT(reg_session
);
317 LTTNG_ASSERT(reg_enum
);
318 ASSERT_RCU_READ_LOCKED();
320 /* Delete the node first. */
321 iter
.iter
.node
= ®_enum
->node
.node
;
322 ret
= lttng_ht_del(reg_session
->_enums
.get(), &iter
);
324 call_rcu(®_enum
->rcu_head
, destroy_enum_rcu
);
327 lsu::registry_session
*ust_registry_session_per_uid_create(const lttng::sessiond::trace::abi
& abi
,
330 const char *root_shm_path
,
331 const char *shm_path
,
338 return new lsu::registry_session_per_uid(abi
, major
, minor
, root_shm_path
, shm_path
,
339 euid
, egid
, tracing_id
, tracing_uid
);
340 } catch (const std::exception
& ex
) {
341 ERR("Failed to create per-uid registry session: %s", ex
.what());
346 lsu::registry_session
*ust_registry_session_per_pid_create(struct ust_app
*app
,
347 const lttng::sessiond::trace::abi
& abi
,
350 const char *root_shm_path
,
351 const char *shm_path
,
357 return new lsu::registry_session_per_pid(*app
, abi
, major
, minor
, root_shm_path
,
358 shm_path
, euid
, egid
, tracing_id
);
359 } catch (const std::exception
& ex
) {
360 ERR("Failed to create per-pid registry session: %s", ex
.what());
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.
369 void ust_registry_session_destroy(lsu::registry_session
*reg
)
374 lsu::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
}
378 cds_lfht_node_init(&this->node
.node
);
382 bool lsu::operator==(const lsu::registry_enum
& lhs
, const lsu::registry_enum
& rhs
) noexcept
384 if (lhs
.signedness
!= rhs
.signedness
) {
388 return lhs
._is_equal(rhs
);