fix: relayd: unaligned access in trace_chunk_registry_ht_key_hash
[lttng-tools.git] / src / common / actions / action.cpp
1 /*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <common/error.hpp>
9 #include <common/mi-lttng.hpp>
10
11 #include <lttng/action/action-internal.hpp>
12 #include <lttng/action/list-internal.hpp>
13 #include <lttng/action/notify-internal.hpp>
14 #include <lttng/action/rate-policy-internal.hpp>
15 #include <lttng/action/rotate-session-internal.hpp>
16 #include <lttng/action/snapshot-session-internal.hpp>
17 #include <lttng/action/start-session-internal.hpp>
18 #include <lttng/action/stop-session-internal.hpp>
19 #include <lttng/error-query-internal.hpp>
20
21 const char *lttng_action_type_string(enum lttng_action_type action_type)
22 {
23 switch (action_type) {
24 case LTTNG_ACTION_TYPE_UNKNOWN:
25 return "UNKNOWN";
26 case LTTNG_ACTION_TYPE_LIST:
27 return "LIST";
28 case LTTNG_ACTION_TYPE_NOTIFY:
29 return "NOTIFY";
30 case LTTNG_ACTION_TYPE_ROTATE_SESSION:
31 return "ROTATE_SESSION";
32 case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
33 return "SNAPSHOT_SESSION";
34 case LTTNG_ACTION_TYPE_START_SESSION:
35 return "START_SESSION";
36 case LTTNG_ACTION_TYPE_STOP_SESSION:
37 return "STOP_SESSION";
38 default:
39 return "???";
40 }
41 }
42
43 enum lttng_action_type lttng_action_get_type(const struct lttng_action *action)
44 {
45 return action ? action->type : LTTNG_ACTION_TYPE_UNKNOWN;
46 }
47
48 void lttng_action_init(struct lttng_action *action,
49 enum lttng_action_type type,
50 action_validate_cb validate,
51 action_serialize_cb serialize,
52 action_equal_cb equal,
53 action_destroy_cb destroy,
54 action_get_rate_policy_cb get_rate_policy,
55 action_add_error_query_results_cb add_error_query_results,
56 action_mi_serialize_cb mi)
57 {
58 urcu_ref_init(&action->ref);
59 action->type = type;
60 action->validate = validate;
61 action->serialize = serialize;
62 action->equal = equal;
63 action->destroy = destroy;
64 action->get_rate_policy = get_rate_policy;
65 action->add_error_query_results = add_error_query_results;
66 action->mi_serialize = mi;
67
68 action->execution_request_counter = 0;
69 action->execution_counter = 0;
70 action->execution_failure_counter = 0;
71 }
72
73 static void action_destroy_ref(struct urcu_ref *ref)
74 {
75 struct lttng_action *action = lttng::utils::container_of(ref, &lttng_action::ref);
76
77 action->destroy(action);
78 }
79
80 void lttng_action_get(struct lttng_action *action)
81 {
82 urcu_ref_get(&action->ref);
83 }
84
85 void lttng_action_put(struct lttng_action *action)
86 {
87 if (!action) {
88 return;
89 }
90
91 LTTNG_ASSERT(action->destroy);
92 urcu_ref_put(&action->ref, action_destroy_ref);
93 }
94
95 void lttng_action_destroy(struct lttng_action *action)
96 {
97 lttng_action_put(action);
98 }
99
100 bool lttng_action_validate(struct lttng_action *action)
101 {
102 bool valid;
103
104 if (!action) {
105 valid = false;
106 goto end;
107 }
108
109 if (!action->validate) {
110 /* Sub-class guarantees that it can never be invalid. */
111 valid = true;
112 goto end;
113 }
114
115 valid = action->validate(action);
116 end:
117 return valid;
118 }
119
120 int lttng_action_serialize(struct lttng_action *action, struct lttng_payload *payload)
121 {
122 int ret;
123 struct lttng_action_comm action_comm = {
124 .action_type = (int8_t) action->type,
125 };
126
127 ret = lttng_dynamic_buffer_append(&payload->buffer, &action_comm, sizeof(action_comm));
128 if (ret) {
129 goto end;
130 }
131
132 ret = action->serialize(action, payload);
133 if (ret) {
134 goto end;
135 }
136 end:
137 return ret;
138 }
139
140 ssize_t lttng_action_create_from_payload(struct lttng_payload_view *view,
141 struct lttng_action **action)
142 {
143 ssize_t consumed_len, specific_action_consumed_len;
144 action_create_from_payload_cb create_from_payload_cb;
145 const struct lttng_action_comm *action_comm;
146 const struct lttng_payload_view action_comm_view =
147 lttng_payload_view_from_view(view, 0, sizeof(*action_comm));
148
149 if (!view || !action) {
150 consumed_len = -1;
151 goto end;
152 }
153
154 if (!lttng_payload_view_is_valid(&action_comm_view)) {
155 /* Payload not large enough to contain the header. */
156 consumed_len = -1;
157 goto end;
158 }
159
160 action_comm = (const struct lttng_action_comm *) action_comm_view.buffer.data;
161
162 DBG("Create action from payload: action-type=%s",
163 lttng_action_type_string((lttng_action_type) action_comm->action_type));
164
165 switch (action_comm->action_type) {
166 case LTTNG_ACTION_TYPE_NOTIFY:
167 create_from_payload_cb = lttng_action_notify_create_from_payload;
168 break;
169 case LTTNG_ACTION_TYPE_ROTATE_SESSION:
170 create_from_payload_cb = lttng_action_rotate_session_create_from_payload;
171 break;
172 case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
173 create_from_payload_cb = lttng_action_snapshot_session_create_from_payload;
174 break;
175 case LTTNG_ACTION_TYPE_START_SESSION:
176 create_from_payload_cb = lttng_action_start_session_create_from_payload;
177 break;
178 case LTTNG_ACTION_TYPE_STOP_SESSION:
179 create_from_payload_cb = lttng_action_stop_session_create_from_payload;
180 break;
181 case LTTNG_ACTION_TYPE_LIST:
182 create_from_payload_cb = lttng_action_list_create_from_payload;
183 break;
184 default:
185 ERR("Failed to create action from payload, unhandled action type: action-type=%u (%s)",
186 action_comm->action_type,
187 lttng_action_type_string((lttng_action_type) action_comm->action_type));
188 consumed_len = -1;
189 goto end;
190 }
191
192 {
193 /* Create buffer view for the action-type-specific data. */
194 struct lttng_payload_view specific_action_view =
195 lttng_payload_view_from_view(view, sizeof(struct lttng_action_comm), -1);
196
197 specific_action_consumed_len =
198 create_from_payload_cb(&specific_action_view, action);
199 }
200 if (specific_action_consumed_len < 0) {
201 ERR("Failed to create specific action from buffer.");
202 consumed_len = -1;
203 goto end;
204 }
205
206 LTTNG_ASSERT(*action);
207
208 consumed_len = sizeof(struct lttng_action_comm) + specific_action_consumed_len;
209
210 end:
211 return consumed_len;
212 }
213
214 bool lttng_action_is_equal(const struct lttng_action *a, const struct lttng_action *b)
215 {
216 bool is_equal = false;
217
218 if (!a || !b) {
219 goto end;
220 }
221
222 if (a->type != b->type) {
223 goto end;
224 }
225
226 if (a == b) {
227 is_equal = true;
228 goto end;
229 }
230
231 LTTNG_ASSERT(a->equal);
232 is_equal = a->equal(a, b);
233 end:
234 return is_equal;
235 }
236
237 void lttng_action_increase_execution_request_count(struct lttng_action *action)
238 {
239 action->execution_request_counter++;
240 }
241
242 void lttng_action_increase_execution_count(struct lttng_action *action)
243 {
244 action->execution_counter++;
245 }
246
247 void lttng_action_increase_execution_failure_count(struct lttng_action *action)
248 {
249 uatomic_inc(&action->execution_failure_counter);
250 }
251
252 bool lttng_action_should_execute(const struct lttng_action *action)
253 {
254 const struct lttng_rate_policy *policy = nullptr;
255 bool execute = false;
256
257 if (action->get_rate_policy == nullptr) {
258 execute = true;
259 goto end;
260 }
261
262 policy = action->get_rate_policy(action);
263 if (policy == nullptr) {
264 execute = true;
265 goto end;
266 }
267
268 execute = lttng_rate_policy_should_execute(policy, action->execution_request_counter);
269 end:
270 return execute;
271 }
272
273 enum lttng_action_status
274 lttng_action_add_error_query_results(const struct lttng_action *action,
275 struct lttng_error_query_results *results)
276 {
277 return action->add_error_query_results(action, results);
278 }
279
280 enum lttng_action_status
281 lttng_action_generic_add_error_query_results(const struct lttng_action *action,
282 struct lttng_error_query_results *results)
283 {
284 enum lttng_action_status action_status;
285 struct lttng_error_query_result *error_counter = nullptr;
286 const uint64_t execution_failure_counter = uatomic_read(&action->execution_failure_counter);
287
288 error_counter = lttng_error_query_result_counter_create(
289 "total execution failures",
290 "Aggregated count of errors encountered when executing the action",
291 execution_failure_counter);
292 if (!error_counter) {
293 action_status = LTTNG_ACTION_STATUS_ERROR;
294 goto end;
295 }
296
297 if (lttng_error_query_results_add_result(results, error_counter)) {
298 action_status = LTTNG_ACTION_STATUS_ERROR;
299 goto end;
300 }
301
302 /* Ownership transferred to the results. */
303 error_counter = nullptr;
304 action_status = LTTNG_ACTION_STATUS_OK;
305 end:
306 lttng_error_query_result_destroy(error_counter);
307 return action_status;
308 }
309
310 enum lttng_error_code
311 lttng_action_mi_serialize(const struct lttng_trigger *trigger,
312 const struct lttng_action *action,
313 struct mi_writer *writer,
314 const struct mi_lttng_error_query_callbacks *error_query_callbacks,
315 struct lttng_dynamic_array *action_path_indexes)
316 {
317 int ret;
318 enum lttng_error_code ret_code;
319 struct lttng_action_path *action_path = nullptr;
320 struct lttng_error_query_results *error_query_results = nullptr;
321
322 LTTNG_ASSERT(action);
323 LTTNG_ASSERT(writer);
324
325 /* Open action. */
326 ret = mi_lttng_writer_open_element(writer, mi_lttng_element_action);
327 if (ret) {
328 goto mi_error;
329 }
330
331 if (action->type == LTTNG_ACTION_TYPE_LIST) {
332 /*
333 * Recursion is safe since action lists can't be nested for
334 * the moment.
335 */
336 ret_code = lttng_action_list_mi_serialize(
337 trigger, action, writer, error_query_callbacks, action_path_indexes);
338 if (ret_code != LTTNG_OK) {
339 goto end;
340 }
341
342 /* Nothing else to do. */
343 goto close_action_element;
344 }
345
346 LTTNG_ASSERT(action->mi_serialize);
347 ret_code = action->mi_serialize(action, writer);
348 if (ret_code != LTTNG_OK) {
349 goto end;
350 }
351
352 /* Error query for the action. */
353 if (error_query_callbacks && error_query_callbacks->action_cb) {
354 const uint64_t *action_path_indexes_raw_pointer = nullptr;
355 const size_t action_path_indexes_size =
356 lttng_dynamic_array_get_count(action_path_indexes);
357
358 if (action_path_indexes_size != 0) {
359 action_path_indexes_raw_pointer =
360 (const uint64_t *) action_path_indexes->buffer.data;
361 }
362
363 action_path = lttng_action_path_create(action_path_indexes_raw_pointer,
364 action_path_indexes_size);
365 LTTNG_ASSERT(action_path);
366
367 ret_code = error_query_callbacks->action_cb(
368 trigger, action_path, &error_query_results);
369 if (ret_code != LTTNG_OK) {
370 goto end;
371 }
372
373 /* Serialize the error query results. */
374 ret_code = lttng_error_query_results_mi_serialize(error_query_results, writer);
375 if (ret_code != LTTNG_OK) {
376 goto end;
377 }
378 }
379
380 close_action_element:
381 /* Close action. */
382 ret = mi_lttng_writer_close_element(writer);
383 if (ret) {
384 goto mi_error;
385 }
386
387 ret_code = LTTNG_OK;
388 goto end;
389
390 mi_error:
391 ret_code = LTTNG_ERR_MI_IO_FAIL;
392 end:
393 lttng_action_path_destroy(action_path);
394 lttng_error_query_results_destroy(error_query_results);
395 return ret_code;
396 }
This page took 0.04543 seconds and 4 git commands to generate.