Commit | Line | Data |
---|---|---|
a58c490f | 1 | /* |
ab5be9fa | 2 | * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com> |
a58c490f | 3 | * |
ab5be9fa | 4 | * SPDX-License-Identifier: LGPL-2.1-only |
a58c490f | 5 | * |
a58c490f JG |
6 | */ |
7 | ||
c9e313bc SM |
8 | #include <common/error.hpp> |
9 | #include <common/mi-lttng.hpp> | |
28ab034a | 10 | |
c9e313bc SM |
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> | |
a58c490f | 20 | |
10615eee | 21 | const char *lttng_action_type_string(enum lttng_action_type action_type) |
2666d352 SM |
22 | { |
23 | switch (action_type) { | |
24 | case LTTNG_ACTION_TYPE_UNKNOWN: | |
25 | return "UNKNOWN"; | |
7c2fae7c JG |
26 | case LTTNG_ACTION_TYPE_LIST: |
27 | return "LIST"; | |
2666d352 SM |
28 | case LTTNG_ACTION_TYPE_NOTIFY: |
29 | return "NOTIFY"; | |
bfb2ec6a SM |
30 | case LTTNG_ACTION_TYPE_ROTATE_SESSION: |
31 | return "ROTATE_SESSION"; | |
757c48a2 SM |
32 | case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION: |
33 | return "SNAPSHOT_SESSION"; | |
58397d0d SM |
34 | case LTTNG_ACTION_TYPE_START_SESSION: |
35 | return "START_SESSION"; | |
931bdbaa SM |
36 | case LTTNG_ACTION_TYPE_STOP_SESSION: |
37 | return "STOP_SESSION"; | |
2666d352 SM |
38 | default: |
39 | return "???"; | |
40 | } | |
41 | } | |
42 | ||
17182cfd | 43 | enum lttng_action_type lttng_action_get_type(const struct lttng_action *action) |
a58c490f JG |
44 | { |
45 | return action ? action->type : LTTNG_ACTION_TYPE_UNKNOWN; | |
46 | } | |
47 | ||
2d57482c | 48 | void lttng_action_init(struct lttng_action *action, |
28ab034a JG |
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) | |
6acb3f46 | 57 | { |
c852ce4e | 58 | urcu_ref_init(&action->ref); |
6acb3f46 SM |
59 | action->type = type; |
60 | action->validate = validate; | |
61 | action->serialize = serialize; | |
3dd04a6a | 62 | action->equal = equal; |
6acb3f46 | 63 | action->destroy = destroy; |
7f4d5b07 | 64 | action->get_rate_policy = get_rate_policy; |
588c4b0d | 65 | action->add_error_query_results = add_error_query_results; |
6a751b95 | 66 | action->mi_serialize = mi; |
2d57482c JR |
67 | |
68 | action->execution_request_counter = 0; | |
69 | action->execution_counter = 0; | |
70 | action->execution_failure_counter = 0; | |
6acb3f46 SM |
71 | } |
72 | ||
28ab034a | 73 | static void action_destroy_ref(struct urcu_ref *ref) |
c852ce4e | 74 | { |
28ab034a | 75 | struct lttng_action *action = lttng::utils::container_of(ref, <tng_action::ref); |
c852ce4e JG |
76 | |
77 | action->destroy(action); | |
78 | } | |
79 | ||
c852ce4e JG |
80 | void lttng_action_get(struct lttng_action *action) |
81 | { | |
82 | urcu_ref_get(&action->ref); | |
83 | } | |
84 | ||
c852ce4e | 85 | void lttng_action_put(struct lttng_action *action) |
a58c490f JG |
86 | { |
87 | if (!action) { | |
88 | return; | |
89 | } | |
90 | ||
a0377dfe | 91 | LTTNG_ASSERT(action->destroy); |
c852ce4e JG |
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); | |
a58c490f JG |
98 | } |
99 | ||
a58c490f JG |
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 | ||
28ab034a | 120 | int lttng_action_serialize(struct lttng_action *action, struct lttng_payload *payload) |
a58c490f | 121 | { |
3647288f JG |
122 | int ret; |
123 | struct lttng_action_comm action_comm = { | |
124 | .action_type = (int8_t) action->type, | |
125 | }; | |
126 | ||
28ab034a | 127 | ret = lttng_dynamic_buffer_append(&payload->buffer, &action_comm, sizeof(action_comm)); |
3647288f | 128 | if (ret) { |
a58c490f JG |
129 | goto end; |
130 | } | |
131 | ||
c0a66c84 | 132 | ret = action->serialize(action, payload); |
3647288f | 133 | if (ret) { |
a58c490f JG |
134 | goto end; |
135 | } | |
a58c490f JG |
136 | end: |
137 | return ret; | |
138 | } | |
139 | ||
c0a66c84 | 140 | ssize_t lttng_action_create_from_payload(struct lttng_payload_view *view, |
28ab034a | 141 | struct lttng_action **action) |
a58c490f | 142 | { |
869a3c2d | 143 | ssize_t consumed_len, specific_action_consumed_len; |
c0a66c84 | 144 | action_create_from_payload_cb create_from_payload_cb; |
3e6e0df2 JG |
145 | const struct lttng_action_comm *action_comm; |
146 | const struct lttng_payload_view action_comm_view = | |
28ab034a | 147 | lttng_payload_view_from_view(view, 0, sizeof(*action_comm)); |
a58c490f | 148 | |
869a3c2d SM |
149 | if (!view || !action) { |
150 | consumed_len = -1; | |
a58c490f JG |
151 | goto end; |
152 | } | |
153 | ||
3e6e0df2 JG |
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; | |
869a3c2d | 161 | |
c0a66c84 | 162 | DBG("Create action from payload: action-type=%s", |
28ab034a | 163 | lttng_action_type_string((lttng_action_type) action_comm->action_type)); |
2666d352 | 164 | |
a58c490f JG |
165 | switch (action_comm->action_type) { |
166 | case LTTNG_ACTION_TYPE_NOTIFY: | |
c0a66c84 | 167 | create_from_payload_cb = lttng_action_notify_create_from_payload; |
a58c490f | 168 | break; |
bfb2ec6a | 169 | case LTTNG_ACTION_TYPE_ROTATE_SESSION: |
28ab034a | 170 | create_from_payload_cb = lttng_action_rotate_session_create_from_payload; |
bfb2ec6a | 171 | break; |
757c48a2 | 172 | case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION: |
28ab034a | 173 | create_from_payload_cb = lttng_action_snapshot_session_create_from_payload; |
757c48a2 | 174 | break; |
58397d0d | 175 | case LTTNG_ACTION_TYPE_START_SESSION: |
28ab034a | 176 | create_from_payload_cb = lttng_action_start_session_create_from_payload; |
58397d0d | 177 | break; |
931bdbaa | 178 | case LTTNG_ACTION_TYPE_STOP_SESSION: |
28ab034a | 179 | create_from_payload_cb = lttng_action_stop_session_create_from_payload; |
931bdbaa | 180 | break; |
7c2fae7c | 181 | case LTTNG_ACTION_TYPE_LIST: |
702f26c8 | 182 | create_from_payload_cb = lttng_action_list_create_from_payload; |
0c51e8f3 | 183 | break; |
a58c490f | 184 | default: |
c0a66c84 | 185 | ERR("Failed to create action from payload, unhandled action type: action-type=%u (%s)", |
28ab034a JG |
186 | action_comm->action_type, |
187 | lttng_action_type_string((lttng_action_type) action_comm->action_type)); | |
869a3c2d | 188 | consumed_len = -1; |
a58c490f JG |
189 | goto end; |
190 | } | |
191 | ||
c0a66c84 JG |
192 | { |
193 | /* Create buffer view for the action-type-specific data. */ | |
194 | struct lttng_payload_view specific_action_view = | |
28ab034a | 195 | lttng_payload_view_from_view(view, sizeof(struct lttng_action_comm), -1); |
869a3c2d | 196 | |
28ab034a JG |
197 | specific_action_consumed_len = |
198 | create_from_payload_cb(&specific_action_view, action); | |
c0a66c84 | 199 | } |
869a3c2d SM |
200 | if (specific_action_consumed_len < 0) { |
201 | ERR("Failed to create specific action from buffer."); | |
202 | consumed_len = -1; | |
a58c490f JG |
203 | goto end; |
204 | } | |
869a3c2d | 205 | |
a0377dfe | 206 | LTTNG_ASSERT(*action); |
869a3c2d | 207 | |
28ab034a | 208 | consumed_len = sizeof(struct lttng_action_comm) + specific_action_consumed_len; |
869a3c2d | 209 | |
a58c490f | 210 | end: |
869a3c2d | 211 | return consumed_len; |
a58c490f | 212 | } |
3dd04a6a | 213 | |
28ab034a | 214 | bool lttng_action_is_equal(const struct lttng_action *a, const struct lttng_action *b) |
3dd04a6a JR |
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 | ||
a0377dfe | 231 | LTTNG_ASSERT(a->equal); |
3dd04a6a JR |
232 | is_equal = a->equal(a, b); |
233 | end: | |
234 | return is_equal; | |
235 | } | |
2d57482c | 236 | |
2d57482c JR |
237 | void lttng_action_increase_execution_request_count(struct lttng_action *action) |
238 | { | |
239 | action->execution_request_counter++; | |
240 | } | |
241 | ||
2d57482c JR |
242 | void lttng_action_increase_execution_count(struct lttng_action *action) |
243 | { | |
244 | action->execution_counter++; | |
245 | } | |
246 | ||
2d57482c JR |
247 | void lttng_action_increase_execution_failure_count(struct lttng_action *action) |
248 | { | |
588c4b0d | 249 | uatomic_inc(&action->execution_failure_counter); |
2d57482c JR |
250 | } |
251 | ||
2d57482c JR |
252 | bool lttng_action_should_execute(const struct lttng_action *action) |
253 | { | |
cd9adb8b | 254 | const struct lttng_rate_policy *policy = nullptr; |
2d57482c JR |
255 | bool execute = false; |
256 | ||
cd9adb8b | 257 | if (action->get_rate_policy == nullptr) { |
2d57482c JR |
258 | execute = true; |
259 | goto end; | |
260 | } | |
261 | ||
7f4d5b07 | 262 | policy = action->get_rate_policy(action); |
cd9adb8b | 263 | if (policy == nullptr) { |
2d57482c JR |
264 | execute = true; |
265 | goto end; | |
266 | } | |
267 | ||
28ab034a | 268 | execute = lttng_rate_policy_should_execute(policy, action->execution_request_counter); |
2d57482c JR |
269 | end: |
270 | return execute; | |
271 | } | |
588c4b0d | 272 | |
28ab034a JG |
273 | enum lttng_action_status |
274 | lttng_action_add_error_query_results(const struct lttng_action *action, | |
275 | struct lttng_error_query_results *results) | |
588c4b0d JG |
276 | { |
277 | return action->add_error_query_results(action, results); | |
278 | } | |
279 | ||
28ab034a JG |
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) | |
588c4b0d JG |
283 | { |
284 | enum lttng_action_status action_status; | |
cd9adb8b | 285 | struct lttng_error_query_result *error_counter = nullptr; |
28ab034a | 286 | const uint64_t execution_failure_counter = uatomic_read(&action->execution_failure_counter); |
588c4b0d JG |
287 | |
288 | error_counter = lttng_error_query_result_counter_create( | |
28ab034a JG |
289 | "total execution failures", |
290 | "Aggregated count of errors encountered when executing the action", | |
291 | execution_failure_counter); | |
588c4b0d JG |
292 | if (!error_counter) { |
293 | action_status = LTTNG_ACTION_STATUS_ERROR; | |
294 | goto end; | |
295 | } | |
296 | ||
28ab034a | 297 | if (lttng_error_query_results_add_result(results, error_counter)) { |
588c4b0d JG |
298 | action_status = LTTNG_ACTION_STATUS_ERROR; |
299 | goto end; | |
300 | } | |
301 | ||
302 | /* Ownership transferred to the results. */ | |
cd9adb8b | 303 | error_counter = nullptr; |
588c4b0d JG |
304 | action_status = LTTNG_ACTION_STATUS_OK; |
305 | end: | |
306 | lttng_error_query_result_destroy(error_counter); | |
307 | return action_status; | |
308 | } | |
6a751b95 | 309 | |
28ab034a JG |
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) | |
6a751b95 JR |
316 | { |
317 | int ret; | |
318 | enum lttng_error_code ret_code; | |
cd9adb8b JG |
319 | struct lttng_action_path *action_path = nullptr; |
320 | struct lttng_error_query_results *error_query_results = nullptr; | |
6a751b95 | 321 | |
a0377dfe FD |
322 | LTTNG_ASSERT(action); |
323 | LTTNG_ASSERT(writer); | |
6a751b95 JR |
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 | */ | |
28ab034a JG |
336 | ret_code = lttng_action_list_mi_serialize( |
337 | trigger, action, writer, error_query_callbacks, action_path_indexes); | |
6a751b95 JR |
338 | if (ret_code != LTTNG_OK) { |
339 | goto end; | |
340 | } | |
341 | ||
342 | /* Nothing else to do. */ | |
343 | goto close_action_element; | |
344 | } | |
345 | ||
a0377dfe | 346 | LTTNG_ASSERT(action->mi_serialize); |
6a751b95 JR |
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) { | |
cd9adb8b | 354 | const uint64_t *action_path_indexes_raw_pointer = nullptr; |
6a751b95 | 355 | const size_t action_path_indexes_size = |
28ab034a | 356 | lttng_dynamic_array_get_count(action_path_indexes); |
6a751b95 JR |
357 | |
358 | if (action_path_indexes_size != 0) { | |
359 | action_path_indexes_raw_pointer = | |
28ab034a | 360 | (const uint64_t *) action_path_indexes->buffer.data; |
6a751b95 JR |
361 | } |
362 | ||
28ab034a JG |
363 | action_path = lttng_action_path_create(action_path_indexes_raw_pointer, |
364 | action_path_indexes_size); | |
a0377dfe | 365 | LTTNG_ASSERT(action_path); |
6a751b95 JR |
366 | |
367 | ret_code = error_query_callbacks->action_cb( | |
28ab034a | 368 | trigger, action_path, &error_query_results); |
6a751b95 JR |
369 | if (ret_code != LTTNG_OK) { |
370 | goto end; | |
371 | } | |
372 | ||
373 | /* Serialize the error query results. */ | |
28ab034a | 374 | ret_code = lttng_error_query_results_mi_serialize(error_query_results, writer); |
6a751b95 JR |
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 | } |