.. | .. |
---|
7 | 7 | |
---|
8 | 8 | #include <linux/module.h> |
---|
9 | 9 | #include <linux/kallsyms.h> |
---|
| 10 | +#include <linux/security.h> |
---|
10 | 11 | #include <linux/mutex.h> |
---|
11 | 12 | #include <linux/slab.h> |
---|
12 | 13 | #include <linux/stacktrace.h> |
---|
13 | 14 | #include <linux/rculist.h> |
---|
14 | 15 | #include <linux/tracefs.h> |
---|
15 | 16 | |
---|
| 17 | +/* for gfp flag names */ |
---|
| 18 | +#include <linux/trace_events.h> |
---|
| 19 | +#include <trace/events/mmflags.h> |
---|
| 20 | + |
---|
16 | 21 | #include "tracing_map.h" |
---|
17 | | -#include "trace.h" |
---|
| 22 | +#include "trace_synth.h" |
---|
18 | 23 | |
---|
19 | | -#define SYNTH_SYSTEM "synthetic" |
---|
20 | | -#define SYNTH_FIELDS_MAX 16 |
---|
| 24 | +#define ERRORS \ |
---|
| 25 | + C(NONE, "No error"), \ |
---|
| 26 | + C(DUPLICATE_VAR, "Variable already defined"), \ |
---|
| 27 | + C(VAR_NOT_UNIQUE, "Variable name not unique, need to use fully qualified name (subsys.event.var) for variable"), \ |
---|
| 28 | + C(TOO_MANY_VARS, "Too many variables defined"), \ |
---|
| 29 | + C(MALFORMED_ASSIGNMENT, "Malformed assignment"), \ |
---|
| 30 | + C(NAMED_MISMATCH, "Named hist trigger doesn't match existing named trigger (includes variables)"), \ |
---|
| 31 | + C(TRIGGER_EEXIST, "Hist trigger already exists"), \ |
---|
| 32 | + C(TRIGGER_ENOENT_CLEAR, "Can't clear or continue a nonexistent hist trigger"), \ |
---|
| 33 | + C(SET_CLOCK_FAIL, "Couldn't set trace_clock"), \ |
---|
| 34 | + C(BAD_FIELD_MODIFIER, "Invalid field modifier"), \ |
---|
| 35 | + C(TOO_MANY_SUBEXPR, "Too many subexpressions (3 max)"), \ |
---|
| 36 | + C(TIMESTAMP_MISMATCH, "Timestamp units in expression don't match"), \ |
---|
| 37 | + C(TOO_MANY_FIELD_VARS, "Too many field variables defined"), \ |
---|
| 38 | + C(EVENT_FILE_NOT_FOUND, "Event file not found"), \ |
---|
| 39 | + C(HIST_NOT_FOUND, "Matching event histogram not found"), \ |
---|
| 40 | + C(HIST_CREATE_FAIL, "Couldn't create histogram for field"), \ |
---|
| 41 | + C(SYNTH_VAR_NOT_FOUND, "Couldn't find synthetic variable"), \ |
---|
| 42 | + C(SYNTH_EVENT_NOT_FOUND,"Couldn't find synthetic event"), \ |
---|
| 43 | + C(SYNTH_TYPE_MISMATCH, "Param type doesn't match synthetic event field type"), \ |
---|
| 44 | + C(SYNTH_COUNT_MISMATCH, "Param count doesn't match synthetic event field count"), \ |
---|
| 45 | + C(FIELD_VAR_PARSE_FAIL, "Couldn't parse field variable"), \ |
---|
| 46 | + C(VAR_CREATE_FIND_FAIL, "Couldn't create or find variable"), \ |
---|
| 47 | + C(ONX_NOT_VAR, "For onmax(x) or onchange(x), x must be a variable"), \ |
---|
| 48 | + C(ONX_VAR_NOT_FOUND, "Couldn't find onmax or onchange variable"), \ |
---|
| 49 | + C(ONX_VAR_CREATE_FAIL, "Couldn't create onmax or onchange variable"), \ |
---|
| 50 | + C(FIELD_VAR_CREATE_FAIL,"Couldn't create field variable"), \ |
---|
| 51 | + C(TOO_MANY_PARAMS, "Too many action params"), \ |
---|
| 52 | + C(PARAM_NOT_FOUND, "Couldn't find param"), \ |
---|
| 53 | + C(INVALID_PARAM, "Invalid action param"), \ |
---|
| 54 | + C(ACTION_NOT_FOUND, "No action found"), \ |
---|
| 55 | + C(NO_SAVE_PARAMS, "No params found for save()"), \ |
---|
| 56 | + C(TOO_MANY_SAVE_ACTIONS,"Can't have more than one save() action per hist"), \ |
---|
| 57 | + C(ACTION_MISMATCH, "Handler doesn't support action"), \ |
---|
| 58 | + C(NO_CLOSING_PAREN, "No closing paren found"), \ |
---|
| 59 | + C(SUBSYS_NOT_FOUND, "Missing subsystem"), \ |
---|
| 60 | + C(INVALID_SUBSYS_EVENT, "Invalid subsystem or event name"), \ |
---|
| 61 | + C(INVALID_REF_KEY, "Using variable references in keys not supported"), \ |
---|
| 62 | + C(VAR_NOT_FOUND, "Couldn't find variable"), \ |
---|
| 63 | + C(FIELD_NOT_FOUND, "Couldn't find field"), \ |
---|
| 64 | + C(EMPTY_ASSIGNMENT, "Empty assignment"), \ |
---|
| 65 | + C(INVALID_SORT_MODIFIER,"Invalid sort modifier"), \ |
---|
| 66 | + C(EMPTY_SORT_FIELD, "Empty sort field"), \ |
---|
| 67 | + C(TOO_MANY_SORT_FIELDS, "Too many sort fields (Max = 2)"), \ |
---|
| 68 | + C(INVALID_SORT_FIELD, "Sort field must be a key or a val"), \ |
---|
| 69 | + C(INVALID_STR_OPERAND, "String type can not be an operand in expression"), |
---|
21 | 70 | |
---|
22 | | -#define STR_VAR_LEN_MAX 32 /* must be multiple of sizeof(u64) */ |
---|
| 71 | +#undef C |
---|
| 72 | +#define C(a, b) HIST_ERR_##a |
---|
| 73 | + |
---|
| 74 | +enum { ERRORS }; |
---|
| 75 | + |
---|
| 76 | +#undef C |
---|
| 77 | +#define C(a, b) b |
---|
| 78 | + |
---|
| 79 | +static const char *err_text[] = { ERRORS }; |
---|
23 | 80 | |
---|
24 | 81 | struct hist_field; |
---|
25 | 82 | |
---|
.. | .. |
---|
39 | 96 | FIELD_OP_UNARY_MINUS, |
---|
40 | 97 | }; |
---|
41 | 98 | |
---|
| 99 | +/* |
---|
| 100 | + * A hist_var (histogram variable) contains variable information for |
---|
| 101 | + * hist_fields having the HIST_FIELD_FL_VAR or HIST_FIELD_FL_VAR_REF |
---|
| 102 | + * flag set. A hist_var has a variable name e.g. ts0, and is |
---|
| 103 | + * associated with a given histogram trigger, as specified by |
---|
| 104 | + * hist_data. The hist_var idx is the unique index assigned to the |
---|
| 105 | + * variable by the hist trigger's tracing_map. The idx is what is |
---|
| 106 | + * used to set a variable's value and, by a variable reference, to |
---|
| 107 | + * retrieve it. |
---|
| 108 | + */ |
---|
42 | 109 | struct hist_var { |
---|
43 | 110 | char *name; |
---|
44 | 111 | struct hist_trigger_data *hist_data; |
---|
.. | .. |
---|
56 | 123 | const char *type; |
---|
57 | 124 | struct hist_field *operands[HIST_FIELD_OPERANDS_MAX]; |
---|
58 | 125 | struct hist_trigger_data *hist_data; |
---|
| 126 | + |
---|
| 127 | + /* |
---|
| 128 | + * Variable fields contain variable-specific info in var. |
---|
| 129 | + */ |
---|
59 | 130 | struct hist_var var; |
---|
60 | 131 | enum field_op_id operator; |
---|
61 | 132 | char *system; |
---|
62 | 133 | char *event_name; |
---|
| 134 | + |
---|
| 135 | + /* |
---|
| 136 | + * The name field is used for EXPR and VAR_REF fields. VAR |
---|
| 137 | + * fields contain the variable name in var.name. |
---|
| 138 | + */ |
---|
63 | 139 | char *name; |
---|
64 | | - unsigned int var_idx; |
---|
| 140 | + |
---|
| 141 | + /* |
---|
| 142 | + * When a histogram trigger is hit, if it has any references |
---|
| 143 | + * to variables, the values of those variables are collected |
---|
| 144 | + * into a var_ref_vals array by resolve_var_refs(). The |
---|
| 145 | + * current value of each variable is read from the tracing_map |
---|
| 146 | + * using the hist field's hist_var.idx and entered into the |
---|
| 147 | + * var_ref_idx entry i.e. var_ref_vals[var_ref_idx]. |
---|
| 148 | + */ |
---|
65 | 149 | unsigned int var_ref_idx; |
---|
66 | 150 | bool read_once; |
---|
| 151 | + |
---|
| 152 | + unsigned int var_str_idx; |
---|
67 | 153 | }; |
---|
68 | 154 | |
---|
69 | 155 | static u64 hist_field_none(struct hist_field *field, |
---|
.. | .. |
---|
266 | 352 | unsigned int n_keys; |
---|
267 | 353 | unsigned int n_fields; |
---|
268 | 354 | unsigned int n_vars; |
---|
| 355 | + unsigned int n_var_str; |
---|
269 | 356 | unsigned int key_size; |
---|
270 | 357 | struct tracing_map_sort_key sort_keys[TRACING_MAP_SORT_KEYS_MAX]; |
---|
271 | 358 | unsigned int n_sort_keys; |
---|
.. | .. |
---|
280 | 367 | struct action_data *actions[HIST_ACTIONS_MAX]; |
---|
281 | 368 | unsigned int n_actions; |
---|
282 | 369 | |
---|
283 | | - struct hist_field *synth_var_refs[SYNTH_FIELDS_MAX]; |
---|
284 | | - unsigned int n_synth_var_refs; |
---|
285 | 370 | struct field_var *field_vars[SYNTH_FIELDS_MAX]; |
---|
286 | 371 | unsigned int n_field_vars; |
---|
287 | 372 | unsigned int n_field_var_str; |
---|
288 | 373 | struct field_var_hist *field_var_hists[SYNTH_FIELDS_MAX]; |
---|
289 | 374 | unsigned int n_field_var_hists; |
---|
290 | 375 | |
---|
291 | | - struct field_var *max_vars[SYNTH_FIELDS_MAX]; |
---|
292 | | - unsigned int n_max_vars; |
---|
293 | | - unsigned int n_max_var_str; |
---|
294 | | -}; |
---|
295 | | - |
---|
296 | | -struct synth_field { |
---|
297 | | - char *type; |
---|
298 | | - char *name; |
---|
299 | | - size_t size; |
---|
300 | | - bool is_signed; |
---|
301 | | - bool is_string; |
---|
302 | | -}; |
---|
303 | | - |
---|
304 | | -struct synth_event { |
---|
305 | | - struct list_head list; |
---|
306 | | - int ref; |
---|
307 | | - char *name; |
---|
308 | | - struct synth_field **fields; |
---|
309 | | - unsigned int n_fields; |
---|
310 | | - unsigned int n_u64; |
---|
311 | | - struct trace_event_class class; |
---|
312 | | - struct trace_event_call call; |
---|
313 | | - struct tracepoint *tp; |
---|
| 376 | + struct field_var *save_vars[SYNTH_FIELDS_MAX]; |
---|
| 377 | + unsigned int n_save_vars; |
---|
| 378 | + unsigned int n_save_var_str; |
---|
314 | 379 | }; |
---|
315 | 380 | |
---|
316 | 381 | struct action_data; |
---|
317 | 382 | |
---|
318 | 383 | typedef void (*action_fn_t) (struct hist_trigger_data *hist_data, |
---|
319 | 384 | struct tracing_map_elt *elt, void *rec, |
---|
320 | | - struct ring_buffer_event *rbe, |
---|
| 385 | + struct ring_buffer_event *rbe, void *key, |
---|
321 | 386 | struct action_data *data, u64 *var_ref_vals); |
---|
322 | 387 | |
---|
| 388 | +typedef bool (*check_track_val_fn_t) (u64 track_val, u64 var_val); |
---|
| 389 | + |
---|
| 390 | +enum handler_id { |
---|
| 391 | + HANDLER_ONMATCH = 1, |
---|
| 392 | + HANDLER_ONMAX, |
---|
| 393 | + HANDLER_ONCHANGE, |
---|
| 394 | +}; |
---|
| 395 | + |
---|
| 396 | +enum action_id { |
---|
| 397 | + ACTION_SAVE = 1, |
---|
| 398 | + ACTION_TRACE, |
---|
| 399 | + ACTION_SNAPSHOT, |
---|
| 400 | +}; |
---|
| 401 | + |
---|
323 | 402 | struct action_data { |
---|
| 403 | + enum handler_id handler; |
---|
| 404 | + enum action_id action; |
---|
| 405 | + char *action_name; |
---|
324 | 406 | action_fn_t fn; |
---|
| 407 | + |
---|
325 | 408 | unsigned int n_params; |
---|
326 | 409 | char *params[SYNTH_FIELDS_MAX]; |
---|
327 | 410 | |
---|
| 411 | + /* |
---|
| 412 | + * When a histogram trigger is hit, the values of any |
---|
| 413 | + * references to variables, including variables being passed |
---|
| 414 | + * as parameters to synthetic events, are collected into a |
---|
| 415 | + * var_ref_vals array. This var_ref_idx array is an array of |
---|
| 416 | + * indices into the var_ref_vals array, one for each synthetic |
---|
| 417 | + * event param, and is passed to the synthetic event |
---|
| 418 | + * invocation. |
---|
| 419 | + */ |
---|
| 420 | + unsigned int var_ref_idx[SYNTH_FIELDS_MAX]; |
---|
| 421 | + struct synth_event *synth_event; |
---|
| 422 | + bool use_trace_keyword; |
---|
| 423 | + char *synth_event_name; |
---|
| 424 | + |
---|
328 | 425 | union { |
---|
329 | 426 | struct { |
---|
330 | | - unsigned int var_ref_idx; |
---|
331 | | - char *match_event; |
---|
332 | | - char *match_event_system; |
---|
333 | | - char *synth_event_name; |
---|
334 | | - struct synth_event *synth_event; |
---|
335 | | - } onmatch; |
---|
| 427 | + char *event; |
---|
| 428 | + char *event_system; |
---|
| 429 | + } match_data; |
---|
336 | 430 | |
---|
337 | 431 | struct { |
---|
| 432 | + /* |
---|
| 433 | + * var_str contains the $-unstripped variable |
---|
| 434 | + * name referenced by var_ref, and used when |
---|
| 435 | + * printing the action. Because var_ref |
---|
| 436 | + * creation is deferred to create_actions(), |
---|
| 437 | + * we need a per-action way to save it until |
---|
| 438 | + * then, thus var_str. |
---|
| 439 | + */ |
---|
338 | 440 | char *var_str; |
---|
339 | | - char *fn_name; |
---|
340 | | - unsigned int max_var_ref_idx; |
---|
341 | | - struct hist_field *max_var; |
---|
342 | | - struct hist_field *var; |
---|
343 | | - } onmax; |
---|
| 441 | + |
---|
| 442 | + /* |
---|
| 443 | + * var_ref refers to the variable being |
---|
| 444 | + * tracked e.g onmax($var). |
---|
| 445 | + */ |
---|
| 446 | + struct hist_field *var_ref; |
---|
| 447 | + |
---|
| 448 | + /* |
---|
| 449 | + * track_var contains the 'invisible' tracking |
---|
| 450 | + * variable created to keep the current |
---|
| 451 | + * e.g. max value. |
---|
| 452 | + */ |
---|
| 453 | + struct hist_field *track_var; |
---|
| 454 | + |
---|
| 455 | + check_track_val_fn_t check_val; |
---|
| 456 | + action_fn_t save_data; |
---|
| 457 | + } track_data; |
---|
344 | 458 | }; |
---|
345 | 459 | }; |
---|
346 | 460 | |
---|
| 461 | +struct track_data { |
---|
| 462 | + u64 track_val; |
---|
| 463 | + bool updated; |
---|
347 | 464 | |
---|
348 | | -static char last_hist_cmd[MAX_FILTER_STR_VAL]; |
---|
349 | | -static char hist_err_str[MAX_FILTER_STR_VAL]; |
---|
| 465 | + unsigned int key_len; |
---|
| 466 | + void *key; |
---|
| 467 | + struct tracing_map_elt elt; |
---|
350 | 468 | |
---|
351 | | -static void last_cmd_set(char *str) |
---|
| 469 | + struct action_data *action_data; |
---|
| 470 | + struct hist_trigger_data *hist_data; |
---|
| 471 | +}; |
---|
| 472 | + |
---|
| 473 | +struct hist_elt_data { |
---|
| 474 | + char *comm; |
---|
| 475 | + u64 *var_ref_vals; |
---|
| 476 | + char *field_var_str[SYNTH_FIELDS_MAX]; |
---|
| 477 | +}; |
---|
| 478 | + |
---|
| 479 | +struct snapshot_context { |
---|
| 480 | + struct tracing_map_elt *elt; |
---|
| 481 | + void *key; |
---|
| 482 | +}; |
---|
| 483 | + |
---|
| 484 | +static void track_data_free(struct track_data *track_data) |
---|
352 | 485 | { |
---|
353 | | - if (!str) |
---|
| 486 | + struct hist_elt_data *elt_data; |
---|
| 487 | + |
---|
| 488 | + if (!track_data) |
---|
354 | 489 | return; |
---|
355 | 490 | |
---|
356 | | - strncpy(last_hist_cmd, str, MAX_FILTER_STR_VAL - 1); |
---|
| 491 | + kfree(track_data->key); |
---|
| 492 | + |
---|
| 493 | + elt_data = track_data->elt.private_data; |
---|
| 494 | + if (elt_data) { |
---|
| 495 | + kfree(elt_data->comm); |
---|
| 496 | + kfree(elt_data); |
---|
| 497 | + } |
---|
| 498 | + |
---|
| 499 | + kfree(track_data); |
---|
357 | 500 | } |
---|
358 | 501 | |
---|
359 | | -static void hist_err(char *str, char *var) |
---|
| 502 | +static struct track_data *track_data_alloc(unsigned int key_len, |
---|
| 503 | + struct action_data *action_data, |
---|
| 504 | + struct hist_trigger_data *hist_data) |
---|
360 | 505 | { |
---|
361 | | - int maxlen = MAX_FILTER_STR_VAL - 1; |
---|
| 506 | + struct track_data *data = kzalloc(sizeof(*data), GFP_KERNEL); |
---|
| 507 | + struct hist_elt_data *elt_data; |
---|
| 508 | + |
---|
| 509 | + if (!data) |
---|
| 510 | + return ERR_PTR(-ENOMEM); |
---|
| 511 | + |
---|
| 512 | + data->key = kzalloc(key_len, GFP_KERNEL); |
---|
| 513 | + if (!data->key) { |
---|
| 514 | + track_data_free(data); |
---|
| 515 | + return ERR_PTR(-ENOMEM); |
---|
| 516 | + } |
---|
| 517 | + |
---|
| 518 | + data->key_len = key_len; |
---|
| 519 | + data->action_data = action_data; |
---|
| 520 | + data->hist_data = hist_data; |
---|
| 521 | + |
---|
| 522 | + elt_data = kzalloc(sizeof(*elt_data), GFP_KERNEL); |
---|
| 523 | + if (!elt_data) { |
---|
| 524 | + track_data_free(data); |
---|
| 525 | + return ERR_PTR(-ENOMEM); |
---|
| 526 | + } |
---|
| 527 | + |
---|
| 528 | + data->elt.private_data = elt_data; |
---|
| 529 | + |
---|
| 530 | + elt_data->comm = kzalloc(TASK_COMM_LEN, GFP_KERNEL); |
---|
| 531 | + if (!elt_data->comm) { |
---|
| 532 | + track_data_free(data); |
---|
| 533 | + return ERR_PTR(-ENOMEM); |
---|
| 534 | + } |
---|
| 535 | + |
---|
| 536 | + return data; |
---|
| 537 | +} |
---|
| 538 | + |
---|
| 539 | +static char last_cmd[MAX_FILTER_STR_VAL]; |
---|
| 540 | +static char last_cmd_loc[MAX_FILTER_STR_VAL]; |
---|
| 541 | + |
---|
| 542 | +static int errpos(char *str) |
---|
| 543 | +{ |
---|
| 544 | + return err_pos(last_cmd, str); |
---|
| 545 | +} |
---|
| 546 | + |
---|
| 547 | +static void last_cmd_set(struct trace_event_file *file, char *str) |
---|
| 548 | +{ |
---|
| 549 | + const char *system = NULL, *name = NULL; |
---|
| 550 | + struct trace_event_call *call; |
---|
362 | 551 | |
---|
363 | 552 | if (!str) |
---|
364 | 553 | return; |
---|
365 | 554 | |
---|
366 | | - if (strlen(hist_err_str)) |
---|
367 | | - return; |
---|
| 555 | + strcpy(last_cmd, "hist:"); |
---|
| 556 | + strncat(last_cmd, str, MAX_FILTER_STR_VAL - 1 - sizeof("hist:")); |
---|
368 | 557 | |
---|
369 | | - if (!var) |
---|
370 | | - var = ""; |
---|
| 558 | + if (file) { |
---|
| 559 | + call = file->event_call; |
---|
| 560 | + system = call->class->system; |
---|
| 561 | + if (system) { |
---|
| 562 | + name = trace_event_name(call); |
---|
| 563 | + if (!name) |
---|
| 564 | + system = NULL; |
---|
| 565 | + } |
---|
| 566 | + } |
---|
371 | 567 | |
---|
372 | | - if (strlen(hist_err_str) + strlen(str) + strlen(var) > maxlen) |
---|
373 | | - return; |
---|
374 | | - |
---|
375 | | - strcat(hist_err_str, str); |
---|
376 | | - strcat(hist_err_str, var); |
---|
| 568 | + if (system) |
---|
| 569 | + snprintf(last_cmd_loc, MAX_FILTER_STR_VAL, "hist:%s:%s", system, name); |
---|
377 | 570 | } |
---|
378 | 571 | |
---|
379 | | -static void hist_err_event(char *str, char *system, char *event, char *var) |
---|
| 572 | +static void hist_err(struct trace_array *tr, u8 err_type, u8 err_pos) |
---|
380 | 573 | { |
---|
381 | | - char err[MAX_FILTER_STR_VAL]; |
---|
382 | | - |
---|
383 | | - if (system && var) |
---|
384 | | - snprintf(err, MAX_FILTER_STR_VAL, "%s.%s.%s", system, event, var); |
---|
385 | | - else if (system) |
---|
386 | | - snprintf(err, MAX_FILTER_STR_VAL, "%s.%s", system, event); |
---|
387 | | - else |
---|
388 | | - strscpy(err, var, MAX_FILTER_STR_VAL); |
---|
389 | | - |
---|
390 | | - hist_err(str, err); |
---|
| 574 | + tracing_log_err(tr, last_cmd_loc, last_cmd, err_text, |
---|
| 575 | + err_type, err_pos); |
---|
391 | 576 | } |
---|
392 | 577 | |
---|
393 | 578 | static void hist_err_clear(void) |
---|
394 | 579 | { |
---|
395 | | - hist_err_str[0] = '\0'; |
---|
396 | | -} |
---|
397 | | - |
---|
398 | | -static bool have_hist_err(void) |
---|
399 | | -{ |
---|
400 | | - if (strlen(hist_err_str)) |
---|
401 | | - return true; |
---|
402 | | - |
---|
403 | | - return false; |
---|
404 | | -} |
---|
405 | | - |
---|
406 | | -static LIST_HEAD(synth_event_list); |
---|
407 | | -static DEFINE_MUTEX(synth_event_mutex); |
---|
408 | | - |
---|
409 | | -struct synth_trace_event { |
---|
410 | | - struct trace_entry ent; |
---|
411 | | - u64 fields[]; |
---|
412 | | -}; |
---|
413 | | - |
---|
414 | | -static int synth_event_define_fields(struct trace_event_call *call) |
---|
415 | | -{ |
---|
416 | | - struct synth_trace_event trace; |
---|
417 | | - int offset = offsetof(typeof(trace), fields); |
---|
418 | | - struct synth_event *event = call->data; |
---|
419 | | - unsigned int i, size, n_u64; |
---|
420 | | - char *name, *type; |
---|
421 | | - bool is_signed; |
---|
422 | | - int ret = 0; |
---|
423 | | - |
---|
424 | | - for (i = 0, n_u64 = 0; i < event->n_fields; i++) { |
---|
425 | | - size = event->fields[i]->size; |
---|
426 | | - is_signed = event->fields[i]->is_signed; |
---|
427 | | - type = event->fields[i]->type; |
---|
428 | | - name = event->fields[i]->name; |
---|
429 | | - ret = trace_define_field(call, type, name, offset, size, |
---|
430 | | - is_signed, FILTER_OTHER); |
---|
431 | | - if (ret) |
---|
432 | | - break; |
---|
433 | | - |
---|
434 | | - if (event->fields[i]->is_string) { |
---|
435 | | - offset += STR_VAR_LEN_MAX; |
---|
436 | | - n_u64 += STR_VAR_LEN_MAX / sizeof(u64); |
---|
437 | | - } else { |
---|
438 | | - offset += sizeof(u64); |
---|
439 | | - n_u64++; |
---|
440 | | - } |
---|
441 | | - } |
---|
442 | | - |
---|
443 | | - event->n_u64 = n_u64; |
---|
444 | | - |
---|
445 | | - return ret; |
---|
446 | | -} |
---|
447 | | - |
---|
448 | | -static bool synth_field_signed(char *type) |
---|
449 | | -{ |
---|
450 | | - if (strncmp(type, "u", 1) == 0) |
---|
451 | | - return false; |
---|
452 | | - if (strcmp(type, "gfp_t") == 0) |
---|
453 | | - return false; |
---|
454 | | - |
---|
455 | | - return true; |
---|
456 | | -} |
---|
457 | | - |
---|
458 | | -static int synth_field_is_string(char *type) |
---|
459 | | -{ |
---|
460 | | - if (strstr(type, "char[") != NULL) |
---|
461 | | - return true; |
---|
462 | | - |
---|
463 | | - return false; |
---|
464 | | -} |
---|
465 | | - |
---|
466 | | -static int synth_field_string_size(char *type) |
---|
467 | | -{ |
---|
468 | | - char buf[4], *end, *start; |
---|
469 | | - unsigned int len; |
---|
470 | | - int size, err; |
---|
471 | | - |
---|
472 | | - start = strstr(type, "char["); |
---|
473 | | - if (start == NULL) |
---|
474 | | - return -EINVAL; |
---|
475 | | - start += strlen("char["); |
---|
476 | | - |
---|
477 | | - end = strchr(type, ']'); |
---|
478 | | - if (!end || end < start) |
---|
479 | | - return -EINVAL; |
---|
480 | | - |
---|
481 | | - len = end - start; |
---|
482 | | - if (len > 3) |
---|
483 | | - return -EINVAL; |
---|
484 | | - |
---|
485 | | - strncpy(buf, start, len); |
---|
486 | | - buf[len] = '\0'; |
---|
487 | | - |
---|
488 | | - err = kstrtouint(buf, 0, &size); |
---|
489 | | - if (err) |
---|
490 | | - return err; |
---|
491 | | - |
---|
492 | | - if (size > STR_VAR_LEN_MAX) |
---|
493 | | - return -EINVAL; |
---|
494 | | - |
---|
495 | | - return size; |
---|
496 | | -} |
---|
497 | | - |
---|
498 | | -static int synth_field_size(char *type) |
---|
499 | | -{ |
---|
500 | | - int size = 0; |
---|
501 | | - |
---|
502 | | - if (strcmp(type, "s64") == 0) |
---|
503 | | - size = sizeof(s64); |
---|
504 | | - else if (strcmp(type, "u64") == 0) |
---|
505 | | - size = sizeof(u64); |
---|
506 | | - else if (strcmp(type, "s32") == 0) |
---|
507 | | - size = sizeof(s32); |
---|
508 | | - else if (strcmp(type, "u32") == 0) |
---|
509 | | - size = sizeof(u32); |
---|
510 | | - else if (strcmp(type, "s16") == 0) |
---|
511 | | - size = sizeof(s16); |
---|
512 | | - else if (strcmp(type, "u16") == 0) |
---|
513 | | - size = sizeof(u16); |
---|
514 | | - else if (strcmp(type, "s8") == 0) |
---|
515 | | - size = sizeof(s8); |
---|
516 | | - else if (strcmp(type, "u8") == 0) |
---|
517 | | - size = sizeof(u8); |
---|
518 | | - else if (strcmp(type, "char") == 0) |
---|
519 | | - size = sizeof(char); |
---|
520 | | - else if (strcmp(type, "unsigned char") == 0) |
---|
521 | | - size = sizeof(unsigned char); |
---|
522 | | - else if (strcmp(type, "int") == 0) |
---|
523 | | - size = sizeof(int); |
---|
524 | | - else if (strcmp(type, "unsigned int") == 0) |
---|
525 | | - size = sizeof(unsigned int); |
---|
526 | | - else if (strcmp(type, "long") == 0) |
---|
527 | | - size = sizeof(long); |
---|
528 | | - else if (strcmp(type, "unsigned long") == 0) |
---|
529 | | - size = sizeof(unsigned long); |
---|
530 | | - else if (strcmp(type, "pid_t") == 0) |
---|
531 | | - size = sizeof(pid_t); |
---|
532 | | - else if (synth_field_is_string(type)) |
---|
533 | | - size = synth_field_string_size(type); |
---|
534 | | - |
---|
535 | | - return size; |
---|
536 | | -} |
---|
537 | | - |
---|
538 | | -static const char *synth_field_fmt(char *type) |
---|
539 | | -{ |
---|
540 | | - const char *fmt = "%llu"; |
---|
541 | | - |
---|
542 | | - if (strcmp(type, "s64") == 0) |
---|
543 | | - fmt = "%lld"; |
---|
544 | | - else if (strcmp(type, "u64") == 0) |
---|
545 | | - fmt = "%llu"; |
---|
546 | | - else if (strcmp(type, "s32") == 0) |
---|
547 | | - fmt = "%d"; |
---|
548 | | - else if (strcmp(type, "u32") == 0) |
---|
549 | | - fmt = "%u"; |
---|
550 | | - else if (strcmp(type, "s16") == 0) |
---|
551 | | - fmt = "%d"; |
---|
552 | | - else if (strcmp(type, "u16") == 0) |
---|
553 | | - fmt = "%u"; |
---|
554 | | - else if (strcmp(type, "s8") == 0) |
---|
555 | | - fmt = "%d"; |
---|
556 | | - else if (strcmp(type, "u8") == 0) |
---|
557 | | - fmt = "%u"; |
---|
558 | | - else if (strcmp(type, "char") == 0) |
---|
559 | | - fmt = "%d"; |
---|
560 | | - else if (strcmp(type, "unsigned char") == 0) |
---|
561 | | - fmt = "%u"; |
---|
562 | | - else if (strcmp(type, "int") == 0) |
---|
563 | | - fmt = "%d"; |
---|
564 | | - else if (strcmp(type, "unsigned int") == 0) |
---|
565 | | - fmt = "%u"; |
---|
566 | | - else if (strcmp(type, "long") == 0) |
---|
567 | | - fmt = "%ld"; |
---|
568 | | - else if (strcmp(type, "unsigned long") == 0) |
---|
569 | | - fmt = "%lu"; |
---|
570 | | - else if (strcmp(type, "pid_t") == 0) |
---|
571 | | - fmt = "%d"; |
---|
572 | | - else if (synth_field_is_string(type)) |
---|
573 | | - fmt = "%s"; |
---|
574 | | - |
---|
575 | | - return fmt; |
---|
576 | | -} |
---|
577 | | - |
---|
578 | | -static enum print_line_t print_synth_event(struct trace_iterator *iter, |
---|
579 | | - int flags, |
---|
580 | | - struct trace_event *event) |
---|
581 | | -{ |
---|
582 | | - struct trace_array *tr = iter->tr; |
---|
583 | | - struct trace_seq *s = &iter->seq; |
---|
584 | | - struct synth_trace_event *entry; |
---|
585 | | - struct synth_event *se; |
---|
586 | | - unsigned int i, n_u64; |
---|
587 | | - char print_fmt[32]; |
---|
588 | | - const char *fmt; |
---|
589 | | - |
---|
590 | | - entry = (struct synth_trace_event *)iter->ent; |
---|
591 | | - se = container_of(event, struct synth_event, call.event); |
---|
592 | | - |
---|
593 | | - trace_seq_printf(s, "%s: ", se->name); |
---|
594 | | - |
---|
595 | | - for (i = 0, n_u64 = 0; i < se->n_fields; i++) { |
---|
596 | | - if (trace_seq_has_overflowed(s)) |
---|
597 | | - goto end; |
---|
598 | | - |
---|
599 | | - fmt = synth_field_fmt(se->fields[i]->type); |
---|
600 | | - |
---|
601 | | - /* parameter types */ |
---|
602 | | - if (tr->trace_flags & TRACE_ITER_VERBOSE) |
---|
603 | | - trace_seq_printf(s, "%s ", fmt); |
---|
604 | | - |
---|
605 | | - snprintf(print_fmt, sizeof(print_fmt), "%%s=%s%%s", fmt); |
---|
606 | | - |
---|
607 | | - /* parameter values */ |
---|
608 | | - if (se->fields[i]->is_string) { |
---|
609 | | - trace_seq_printf(s, print_fmt, se->fields[i]->name, |
---|
610 | | - (char *)&entry->fields[n_u64], |
---|
611 | | - i == se->n_fields - 1 ? "" : " "); |
---|
612 | | - n_u64 += STR_VAR_LEN_MAX / sizeof(u64); |
---|
613 | | - } else { |
---|
614 | | - trace_seq_printf(s, print_fmt, se->fields[i]->name, |
---|
615 | | - entry->fields[n_u64], |
---|
616 | | - i == se->n_fields - 1 ? "" : " "); |
---|
617 | | - n_u64++; |
---|
618 | | - } |
---|
619 | | - } |
---|
620 | | -end: |
---|
621 | | - trace_seq_putc(s, '\n'); |
---|
622 | | - |
---|
623 | | - return trace_handle_return(s); |
---|
624 | | -} |
---|
625 | | - |
---|
626 | | -static struct trace_event_functions synth_event_funcs = { |
---|
627 | | - .trace = print_synth_event |
---|
628 | | -}; |
---|
629 | | - |
---|
630 | | -static notrace void trace_event_raw_event_synth(void *__data, |
---|
631 | | - u64 *var_ref_vals, |
---|
632 | | - unsigned int var_ref_idx) |
---|
633 | | -{ |
---|
634 | | - struct trace_event_file *trace_file = __data; |
---|
635 | | - struct synth_trace_event *entry; |
---|
636 | | - struct trace_event_buffer fbuffer; |
---|
637 | | - struct ring_buffer *buffer; |
---|
638 | | - struct synth_event *event; |
---|
639 | | - unsigned int i, n_u64; |
---|
640 | | - int fields_size = 0; |
---|
641 | | - |
---|
642 | | - event = trace_file->event_call->data; |
---|
643 | | - |
---|
644 | | - if (trace_trigger_soft_disabled(trace_file)) |
---|
645 | | - return; |
---|
646 | | - |
---|
647 | | - fields_size = event->n_u64 * sizeof(u64); |
---|
648 | | - |
---|
649 | | - /* |
---|
650 | | - * Avoid ring buffer recursion detection, as this event |
---|
651 | | - * is being performed within another event. |
---|
652 | | - */ |
---|
653 | | - buffer = trace_file->tr->trace_buffer.buffer; |
---|
654 | | - ring_buffer_nest_start(buffer); |
---|
655 | | - |
---|
656 | | - entry = trace_event_buffer_reserve(&fbuffer, trace_file, |
---|
657 | | - sizeof(*entry) + fields_size); |
---|
658 | | - if (!entry) |
---|
659 | | - goto out; |
---|
660 | | - |
---|
661 | | - for (i = 0, n_u64 = 0; i < event->n_fields; i++) { |
---|
662 | | - if (event->fields[i]->is_string) { |
---|
663 | | - char *str_val = (char *)(long)var_ref_vals[var_ref_idx + i]; |
---|
664 | | - char *str_field = (char *)&entry->fields[n_u64]; |
---|
665 | | - |
---|
666 | | - strscpy(str_field, str_val, STR_VAR_LEN_MAX); |
---|
667 | | - n_u64 += STR_VAR_LEN_MAX / sizeof(u64); |
---|
668 | | - } else { |
---|
669 | | - struct synth_field *field = event->fields[i]; |
---|
670 | | - u64 val = var_ref_vals[var_ref_idx + i]; |
---|
671 | | - |
---|
672 | | - switch (field->size) { |
---|
673 | | - case 1: |
---|
674 | | - *(u8 *)&entry->fields[n_u64] = (u8)val; |
---|
675 | | - break; |
---|
676 | | - |
---|
677 | | - case 2: |
---|
678 | | - *(u16 *)&entry->fields[n_u64] = (u16)val; |
---|
679 | | - break; |
---|
680 | | - |
---|
681 | | - case 4: |
---|
682 | | - *(u32 *)&entry->fields[n_u64] = (u32)val; |
---|
683 | | - break; |
---|
684 | | - |
---|
685 | | - default: |
---|
686 | | - entry->fields[n_u64] = val; |
---|
687 | | - break; |
---|
688 | | - } |
---|
689 | | - n_u64++; |
---|
690 | | - } |
---|
691 | | - } |
---|
692 | | - |
---|
693 | | - trace_event_buffer_commit(&fbuffer); |
---|
694 | | -out: |
---|
695 | | - ring_buffer_nest_end(buffer); |
---|
696 | | -} |
---|
697 | | - |
---|
698 | | -static void free_synth_event_print_fmt(struct trace_event_call *call) |
---|
699 | | -{ |
---|
700 | | - if (call) { |
---|
701 | | - kfree(call->print_fmt); |
---|
702 | | - call->print_fmt = NULL; |
---|
703 | | - } |
---|
704 | | -} |
---|
705 | | - |
---|
706 | | -static int __set_synth_event_print_fmt(struct synth_event *event, |
---|
707 | | - char *buf, int len) |
---|
708 | | -{ |
---|
709 | | - const char *fmt; |
---|
710 | | - int pos = 0; |
---|
711 | | - int i; |
---|
712 | | - |
---|
713 | | - /* When len=0, we just calculate the needed length */ |
---|
714 | | -#define LEN_OR_ZERO (len ? len - pos : 0) |
---|
715 | | - |
---|
716 | | - pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); |
---|
717 | | - for (i = 0; i < event->n_fields; i++) { |
---|
718 | | - fmt = synth_field_fmt(event->fields[i]->type); |
---|
719 | | - pos += snprintf(buf + pos, LEN_OR_ZERO, "%s=%s%s", |
---|
720 | | - event->fields[i]->name, fmt, |
---|
721 | | - i == event->n_fields - 1 ? "" : ", "); |
---|
722 | | - } |
---|
723 | | - pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); |
---|
724 | | - |
---|
725 | | - for (i = 0; i < event->n_fields; i++) { |
---|
726 | | - pos += snprintf(buf + pos, LEN_OR_ZERO, |
---|
727 | | - ", REC->%s", event->fields[i]->name); |
---|
728 | | - } |
---|
729 | | - |
---|
730 | | -#undef LEN_OR_ZERO |
---|
731 | | - |
---|
732 | | - /* return the length of print_fmt */ |
---|
733 | | - return pos; |
---|
734 | | -} |
---|
735 | | - |
---|
736 | | -static int set_synth_event_print_fmt(struct trace_event_call *call) |
---|
737 | | -{ |
---|
738 | | - struct synth_event *event = call->data; |
---|
739 | | - char *print_fmt; |
---|
740 | | - int len; |
---|
741 | | - |
---|
742 | | - /* First: called with 0 length to calculate the needed length */ |
---|
743 | | - len = __set_synth_event_print_fmt(event, NULL, 0); |
---|
744 | | - |
---|
745 | | - print_fmt = kmalloc(len + 1, GFP_KERNEL); |
---|
746 | | - if (!print_fmt) |
---|
747 | | - return -ENOMEM; |
---|
748 | | - |
---|
749 | | - /* Second: actually write the @print_fmt */ |
---|
750 | | - __set_synth_event_print_fmt(event, print_fmt, len + 1); |
---|
751 | | - call->print_fmt = print_fmt; |
---|
752 | | - |
---|
753 | | - return 0; |
---|
754 | | -} |
---|
755 | | - |
---|
756 | | -static void free_synth_field(struct synth_field *field) |
---|
757 | | -{ |
---|
758 | | - kfree(field->type); |
---|
759 | | - kfree(field->name); |
---|
760 | | - kfree(field); |
---|
761 | | -} |
---|
762 | | - |
---|
763 | | -static struct synth_field *parse_synth_field(int argc, char **argv, |
---|
764 | | - int *consumed) |
---|
765 | | -{ |
---|
766 | | - struct synth_field *field; |
---|
767 | | - const char *prefix = NULL; |
---|
768 | | - char *field_type = argv[0], *field_name; |
---|
769 | | - int len, ret = 0; |
---|
770 | | - char *array; |
---|
771 | | - |
---|
772 | | - if (field_type[0] == ';') |
---|
773 | | - field_type++; |
---|
774 | | - |
---|
775 | | - if (!strcmp(field_type, "unsigned")) { |
---|
776 | | - if (argc < 3) |
---|
777 | | - return ERR_PTR(-EINVAL); |
---|
778 | | - prefix = "unsigned "; |
---|
779 | | - field_type = argv[1]; |
---|
780 | | - field_name = argv[2]; |
---|
781 | | - *consumed = 3; |
---|
782 | | - } else { |
---|
783 | | - field_name = argv[1]; |
---|
784 | | - *consumed = 2; |
---|
785 | | - } |
---|
786 | | - |
---|
787 | | - len = strlen(field_name); |
---|
788 | | - if (field_name[len - 1] == ';') |
---|
789 | | - field_name[len - 1] = '\0'; |
---|
790 | | - |
---|
791 | | - field = kzalloc(sizeof(*field), GFP_KERNEL); |
---|
792 | | - if (!field) |
---|
793 | | - return ERR_PTR(-ENOMEM); |
---|
794 | | - |
---|
795 | | - len = strlen(field_type) + 1; |
---|
796 | | - array = strchr(field_name, '['); |
---|
797 | | - if (array) |
---|
798 | | - len += strlen(array); |
---|
799 | | - if (prefix) |
---|
800 | | - len += strlen(prefix); |
---|
801 | | - field->type = kzalloc(len, GFP_KERNEL); |
---|
802 | | - if (!field->type) { |
---|
803 | | - ret = -ENOMEM; |
---|
804 | | - goto free; |
---|
805 | | - } |
---|
806 | | - if (prefix) |
---|
807 | | - strcat(field->type, prefix); |
---|
808 | | - strcat(field->type, field_type); |
---|
809 | | - if (array) { |
---|
810 | | - strcat(field->type, array); |
---|
811 | | - *array = '\0'; |
---|
812 | | - } |
---|
813 | | - |
---|
814 | | - field->size = synth_field_size(field->type); |
---|
815 | | - if (!field->size) { |
---|
816 | | - ret = -EINVAL; |
---|
817 | | - goto free; |
---|
818 | | - } |
---|
819 | | - |
---|
820 | | - if (synth_field_is_string(field->type)) |
---|
821 | | - field->is_string = true; |
---|
822 | | - |
---|
823 | | - field->is_signed = synth_field_signed(field->type); |
---|
824 | | - |
---|
825 | | - field->name = kstrdup(field_name, GFP_KERNEL); |
---|
826 | | - if (!field->name) { |
---|
827 | | - ret = -ENOMEM; |
---|
828 | | - goto free; |
---|
829 | | - } |
---|
830 | | - out: |
---|
831 | | - return field; |
---|
832 | | - free: |
---|
833 | | - free_synth_field(field); |
---|
834 | | - field = ERR_PTR(ret); |
---|
835 | | - goto out; |
---|
836 | | -} |
---|
837 | | - |
---|
838 | | -static void free_synth_tracepoint(struct tracepoint *tp) |
---|
839 | | -{ |
---|
840 | | - if (!tp) |
---|
841 | | - return; |
---|
842 | | - |
---|
843 | | - kfree(tp->name); |
---|
844 | | - kfree(tp); |
---|
845 | | -} |
---|
846 | | - |
---|
847 | | -static struct tracepoint *alloc_synth_tracepoint(char *name) |
---|
848 | | -{ |
---|
849 | | - struct tracepoint *tp; |
---|
850 | | - |
---|
851 | | - tp = kzalloc(sizeof(*tp), GFP_KERNEL); |
---|
852 | | - if (!tp) |
---|
853 | | - return ERR_PTR(-ENOMEM); |
---|
854 | | - |
---|
855 | | - tp->name = kstrdup(name, GFP_KERNEL); |
---|
856 | | - if (!tp->name) { |
---|
857 | | - kfree(tp); |
---|
858 | | - return ERR_PTR(-ENOMEM); |
---|
859 | | - } |
---|
860 | | - |
---|
861 | | - return tp; |
---|
| 580 | + last_cmd[0] = '\0'; |
---|
| 581 | + last_cmd_loc[0] = '\0'; |
---|
862 | 582 | } |
---|
863 | 583 | |
---|
864 | 584 | typedef void (*synth_probe_func_t) (void *__data, u64 *var_ref_vals, |
---|
865 | | - unsigned int var_ref_idx); |
---|
| 585 | + unsigned int *var_ref_idx); |
---|
866 | 586 | |
---|
867 | 587 | static inline void trace_synth(struct synth_event *event, u64 *var_ref_vals, |
---|
868 | | - unsigned int var_ref_idx) |
---|
| 588 | + unsigned int *var_ref_idx) |
---|
869 | 589 | { |
---|
870 | 590 | struct tracepoint *tp = event->tp; |
---|
871 | 591 | |
---|
.. | .. |
---|
888 | 608 | } |
---|
889 | 609 | } |
---|
890 | 610 | |
---|
891 | | -static struct synth_event *find_synth_event(const char *name) |
---|
892 | | -{ |
---|
893 | | - struct synth_event *event; |
---|
894 | | - |
---|
895 | | - list_for_each_entry(event, &synth_event_list, list) { |
---|
896 | | - if (strcmp(event->name, name) == 0) |
---|
897 | | - return event; |
---|
898 | | - } |
---|
899 | | - |
---|
900 | | - return NULL; |
---|
901 | | -} |
---|
902 | | - |
---|
903 | | -static int register_synth_event(struct synth_event *event) |
---|
904 | | -{ |
---|
905 | | - struct trace_event_call *call = &event->call; |
---|
906 | | - int ret = 0; |
---|
907 | | - |
---|
908 | | - event->call.class = &event->class; |
---|
909 | | - event->class.system = kstrdup(SYNTH_SYSTEM, GFP_KERNEL); |
---|
910 | | - if (!event->class.system) { |
---|
911 | | - ret = -ENOMEM; |
---|
912 | | - goto out; |
---|
913 | | - } |
---|
914 | | - |
---|
915 | | - event->tp = alloc_synth_tracepoint(event->name); |
---|
916 | | - if (IS_ERR(event->tp)) { |
---|
917 | | - ret = PTR_ERR(event->tp); |
---|
918 | | - event->tp = NULL; |
---|
919 | | - goto out; |
---|
920 | | - } |
---|
921 | | - |
---|
922 | | - INIT_LIST_HEAD(&call->class->fields); |
---|
923 | | - call->event.funcs = &synth_event_funcs; |
---|
924 | | - call->class->define_fields = synth_event_define_fields; |
---|
925 | | - |
---|
926 | | - ret = register_trace_event(&call->event); |
---|
927 | | - if (!ret) { |
---|
928 | | - ret = -ENODEV; |
---|
929 | | - goto out; |
---|
930 | | - } |
---|
931 | | - call->flags = TRACE_EVENT_FL_TRACEPOINT; |
---|
932 | | - call->class->reg = trace_event_reg; |
---|
933 | | - call->class->probe = trace_event_raw_event_synth; |
---|
934 | | - call->data = event; |
---|
935 | | - call->tp = event->tp; |
---|
936 | | - |
---|
937 | | - ret = trace_add_event_call_nolock(call); |
---|
938 | | - if (ret) { |
---|
939 | | - pr_warn("Failed to register synthetic event: %s\n", |
---|
940 | | - trace_event_name(call)); |
---|
941 | | - goto err; |
---|
942 | | - } |
---|
943 | | - |
---|
944 | | - ret = set_synth_event_print_fmt(call); |
---|
945 | | - if (ret < 0) { |
---|
946 | | - trace_remove_event_call(call); |
---|
947 | | - goto err; |
---|
948 | | - } |
---|
949 | | - out: |
---|
950 | | - return ret; |
---|
951 | | - err: |
---|
952 | | - unregister_trace_event(&call->event); |
---|
953 | | - goto out; |
---|
954 | | -} |
---|
955 | | - |
---|
956 | | -static int unregister_synth_event(struct synth_event *event) |
---|
957 | | -{ |
---|
958 | | - struct trace_event_call *call = &event->call; |
---|
959 | | - int ret; |
---|
960 | | - |
---|
961 | | - ret = trace_remove_event_call_nolock(call); |
---|
962 | | - |
---|
963 | | - return ret; |
---|
964 | | -} |
---|
965 | | - |
---|
966 | | -static void free_synth_event(struct synth_event *event) |
---|
967 | | -{ |
---|
968 | | - unsigned int i; |
---|
969 | | - |
---|
970 | | - if (!event) |
---|
971 | | - return; |
---|
972 | | - |
---|
973 | | - for (i = 0; i < event->n_fields; i++) |
---|
974 | | - free_synth_field(event->fields[i]); |
---|
975 | | - |
---|
976 | | - kfree(event->fields); |
---|
977 | | - kfree(event->name); |
---|
978 | | - kfree(event->class.system); |
---|
979 | | - free_synth_tracepoint(event->tp); |
---|
980 | | - free_synth_event_print_fmt(&event->call); |
---|
981 | | - kfree(event); |
---|
982 | | -} |
---|
983 | | - |
---|
984 | | -static struct synth_event *alloc_synth_event(char *event_name, int n_fields, |
---|
985 | | - struct synth_field **fields) |
---|
986 | | -{ |
---|
987 | | - struct synth_event *event; |
---|
988 | | - unsigned int i; |
---|
989 | | - |
---|
990 | | - event = kzalloc(sizeof(*event), GFP_KERNEL); |
---|
991 | | - if (!event) { |
---|
992 | | - event = ERR_PTR(-ENOMEM); |
---|
993 | | - goto out; |
---|
994 | | - } |
---|
995 | | - |
---|
996 | | - event->name = kstrdup(event_name, GFP_KERNEL); |
---|
997 | | - if (!event->name) { |
---|
998 | | - kfree(event); |
---|
999 | | - event = ERR_PTR(-ENOMEM); |
---|
1000 | | - goto out; |
---|
1001 | | - } |
---|
1002 | | - |
---|
1003 | | - event->fields = kcalloc(n_fields, sizeof(*event->fields), GFP_KERNEL); |
---|
1004 | | - if (!event->fields) { |
---|
1005 | | - free_synth_event(event); |
---|
1006 | | - event = ERR_PTR(-ENOMEM); |
---|
1007 | | - goto out; |
---|
1008 | | - } |
---|
1009 | | - |
---|
1010 | | - for (i = 0; i < n_fields; i++) |
---|
1011 | | - event->fields[i] = fields[i]; |
---|
1012 | | - |
---|
1013 | | - event->n_fields = n_fields; |
---|
1014 | | - out: |
---|
1015 | | - return event; |
---|
1016 | | -} |
---|
1017 | | - |
---|
1018 | 611 | static void action_trace(struct hist_trigger_data *hist_data, |
---|
1019 | 612 | struct tracing_map_elt *elt, void *rec, |
---|
1020 | | - struct ring_buffer_event *rbe, |
---|
| 613 | + struct ring_buffer_event *rbe, void *key, |
---|
1021 | 614 | struct action_data *data, u64 *var_ref_vals) |
---|
1022 | 615 | { |
---|
1023 | | - struct synth_event *event = data->onmatch.synth_event; |
---|
| 616 | + struct synth_event *event = data->synth_event; |
---|
1024 | 617 | |
---|
1025 | | - trace_synth(event, var_ref_vals, data->onmatch.var_ref_idx); |
---|
| 618 | + trace_synth(event, var_ref_vals, data->var_ref_idx); |
---|
1026 | 619 | } |
---|
1027 | 620 | |
---|
1028 | 621 | struct hist_var_data { |
---|
1029 | 622 | struct list_head list; |
---|
1030 | 623 | struct hist_trigger_data *hist_data; |
---|
1031 | | -}; |
---|
1032 | | - |
---|
1033 | | -static void add_or_delete_synth_event(struct synth_event *event, int delete) |
---|
1034 | | -{ |
---|
1035 | | - if (delete) |
---|
1036 | | - free_synth_event(event); |
---|
1037 | | - else { |
---|
1038 | | - if (!find_synth_event(event->name)) |
---|
1039 | | - list_add(&event->list, &synth_event_list); |
---|
1040 | | - else |
---|
1041 | | - free_synth_event(event); |
---|
1042 | | - } |
---|
1043 | | -} |
---|
1044 | | - |
---|
1045 | | -static int create_synth_event(int argc, char **argv) |
---|
1046 | | -{ |
---|
1047 | | - struct synth_field *field, *fields[SYNTH_FIELDS_MAX]; |
---|
1048 | | - struct synth_event *event = NULL; |
---|
1049 | | - bool delete_event = false; |
---|
1050 | | - int i, consumed = 0, n_fields = 0, ret = 0; |
---|
1051 | | - char *name; |
---|
1052 | | - |
---|
1053 | | - mutex_lock(&event_mutex); |
---|
1054 | | - mutex_lock(&synth_event_mutex); |
---|
1055 | | - |
---|
1056 | | - /* |
---|
1057 | | - * Argument syntax: |
---|
1058 | | - * - Add synthetic event: <event_name> field[;field] ... |
---|
1059 | | - * - Remove synthetic event: !<event_name> field[;field] ... |
---|
1060 | | - * where 'field' = type field_name |
---|
1061 | | - */ |
---|
1062 | | - if (argc < 1) { |
---|
1063 | | - ret = -EINVAL; |
---|
1064 | | - goto out; |
---|
1065 | | - } |
---|
1066 | | - |
---|
1067 | | - name = argv[0]; |
---|
1068 | | - if (name[0] == '!') { |
---|
1069 | | - delete_event = true; |
---|
1070 | | - name++; |
---|
1071 | | - } |
---|
1072 | | - |
---|
1073 | | - event = find_synth_event(name); |
---|
1074 | | - if (event) { |
---|
1075 | | - if (delete_event) { |
---|
1076 | | - if (event->ref) { |
---|
1077 | | - event = NULL; |
---|
1078 | | - ret = -EBUSY; |
---|
1079 | | - goto out; |
---|
1080 | | - } |
---|
1081 | | - list_del(&event->list); |
---|
1082 | | - goto out; |
---|
1083 | | - } |
---|
1084 | | - event = NULL; |
---|
1085 | | - ret = -EEXIST; |
---|
1086 | | - goto out; |
---|
1087 | | - } else if (delete_event) { |
---|
1088 | | - ret = -ENOENT; |
---|
1089 | | - goto out; |
---|
1090 | | - } |
---|
1091 | | - |
---|
1092 | | - if (argc < 2) { |
---|
1093 | | - ret = -EINVAL; |
---|
1094 | | - goto out; |
---|
1095 | | - } |
---|
1096 | | - |
---|
1097 | | - for (i = 1; i < argc - 1; i++) { |
---|
1098 | | - if (strcmp(argv[i], ";") == 0) |
---|
1099 | | - continue; |
---|
1100 | | - if (n_fields == SYNTH_FIELDS_MAX) { |
---|
1101 | | - ret = -EINVAL; |
---|
1102 | | - goto err; |
---|
1103 | | - } |
---|
1104 | | - |
---|
1105 | | - field = parse_synth_field(argc - i, &argv[i], &consumed); |
---|
1106 | | - if (IS_ERR(field)) { |
---|
1107 | | - ret = PTR_ERR(field); |
---|
1108 | | - goto err; |
---|
1109 | | - } |
---|
1110 | | - fields[n_fields++] = field; |
---|
1111 | | - i += consumed - 1; |
---|
1112 | | - } |
---|
1113 | | - |
---|
1114 | | - if (i < argc && strcmp(argv[i], ";") != 0) { |
---|
1115 | | - ret = -EINVAL; |
---|
1116 | | - goto err; |
---|
1117 | | - } |
---|
1118 | | - |
---|
1119 | | - event = alloc_synth_event(name, n_fields, fields); |
---|
1120 | | - if (IS_ERR(event)) { |
---|
1121 | | - ret = PTR_ERR(event); |
---|
1122 | | - event = NULL; |
---|
1123 | | - goto err; |
---|
1124 | | - } |
---|
1125 | | - out: |
---|
1126 | | - if (event) { |
---|
1127 | | - if (delete_event) { |
---|
1128 | | - ret = unregister_synth_event(event); |
---|
1129 | | - add_or_delete_synth_event(event, !ret); |
---|
1130 | | - } else { |
---|
1131 | | - ret = register_synth_event(event); |
---|
1132 | | - add_or_delete_synth_event(event, ret); |
---|
1133 | | - } |
---|
1134 | | - } |
---|
1135 | | - mutex_unlock(&synth_event_mutex); |
---|
1136 | | - mutex_unlock(&event_mutex); |
---|
1137 | | - |
---|
1138 | | - return ret; |
---|
1139 | | - err: |
---|
1140 | | - mutex_unlock(&synth_event_mutex); |
---|
1141 | | - mutex_unlock(&event_mutex); |
---|
1142 | | - |
---|
1143 | | - for (i = 0; i < n_fields; i++) |
---|
1144 | | - free_synth_field(fields[i]); |
---|
1145 | | - free_synth_event(event); |
---|
1146 | | - |
---|
1147 | | - return ret; |
---|
1148 | | -} |
---|
1149 | | - |
---|
1150 | | -static int release_all_synth_events(void) |
---|
1151 | | -{ |
---|
1152 | | - struct synth_event *event, *e; |
---|
1153 | | - int ret = 0; |
---|
1154 | | - |
---|
1155 | | - mutex_lock(&event_mutex); |
---|
1156 | | - mutex_lock(&synth_event_mutex); |
---|
1157 | | - |
---|
1158 | | - list_for_each_entry(event, &synth_event_list, list) { |
---|
1159 | | - if (event->ref) { |
---|
1160 | | - mutex_unlock(&synth_event_mutex); |
---|
1161 | | - return -EBUSY; |
---|
1162 | | - } |
---|
1163 | | - } |
---|
1164 | | - |
---|
1165 | | - list_for_each_entry_safe(event, e, &synth_event_list, list) { |
---|
1166 | | - list_del(&event->list); |
---|
1167 | | - |
---|
1168 | | - ret = unregister_synth_event(event); |
---|
1169 | | - add_or_delete_synth_event(event, !ret); |
---|
1170 | | - } |
---|
1171 | | - mutex_unlock(&synth_event_mutex); |
---|
1172 | | - mutex_unlock(&event_mutex); |
---|
1173 | | - |
---|
1174 | | - return ret; |
---|
1175 | | -} |
---|
1176 | | - |
---|
1177 | | - |
---|
1178 | | -static void *synth_events_seq_start(struct seq_file *m, loff_t *pos) |
---|
1179 | | -{ |
---|
1180 | | - mutex_lock(&synth_event_mutex); |
---|
1181 | | - |
---|
1182 | | - return seq_list_start(&synth_event_list, *pos); |
---|
1183 | | -} |
---|
1184 | | - |
---|
1185 | | -static void *synth_events_seq_next(struct seq_file *m, void *v, loff_t *pos) |
---|
1186 | | -{ |
---|
1187 | | - return seq_list_next(v, &synth_event_list, pos); |
---|
1188 | | -} |
---|
1189 | | - |
---|
1190 | | -static void synth_events_seq_stop(struct seq_file *m, void *v) |
---|
1191 | | -{ |
---|
1192 | | - mutex_unlock(&synth_event_mutex); |
---|
1193 | | -} |
---|
1194 | | - |
---|
1195 | | -static int synth_events_seq_show(struct seq_file *m, void *v) |
---|
1196 | | -{ |
---|
1197 | | - struct synth_field *field; |
---|
1198 | | - struct synth_event *event = v; |
---|
1199 | | - unsigned int i; |
---|
1200 | | - |
---|
1201 | | - seq_printf(m, "%s\t", event->name); |
---|
1202 | | - |
---|
1203 | | - for (i = 0; i < event->n_fields; i++) { |
---|
1204 | | - field = event->fields[i]; |
---|
1205 | | - |
---|
1206 | | - /* parameter values */ |
---|
1207 | | - seq_printf(m, "%s %s%s", field->type, field->name, |
---|
1208 | | - i == event->n_fields - 1 ? "" : "; "); |
---|
1209 | | - } |
---|
1210 | | - |
---|
1211 | | - seq_putc(m, '\n'); |
---|
1212 | | - |
---|
1213 | | - return 0; |
---|
1214 | | -} |
---|
1215 | | - |
---|
1216 | | -static const struct seq_operations synth_events_seq_op = { |
---|
1217 | | - .start = synth_events_seq_start, |
---|
1218 | | - .next = synth_events_seq_next, |
---|
1219 | | - .stop = synth_events_seq_stop, |
---|
1220 | | - .show = synth_events_seq_show |
---|
1221 | | -}; |
---|
1222 | | - |
---|
1223 | | -static int synth_events_open(struct inode *inode, struct file *file) |
---|
1224 | | -{ |
---|
1225 | | - int ret; |
---|
1226 | | - |
---|
1227 | | - if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { |
---|
1228 | | - ret = release_all_synth_events(); |
---|
1229 | | - if (ret < 0) |
---|
1230 | | - return ret; |
---|
1231 | | - } |
---|
1232 | | - |
---|
1233 | | - return seq_open(file, &synth_events_seq_op); |
---|
1234 | | -} |
---|
1235 | | - |
---|
1236 | | -static ssize_t synth_events_write(struct file *file, |
---|
1237 | | - const char __user *buffer, |
---|
1238 | | - size_t count, loff_t *ppos) |
---|
1239 | | -{ |
---|
1240 | | - return trace_parse_run_command(file, buffer, count, ppos, |
---|
1241 | | - create_synth_event); |
---|
1242 | | -} |
---|
1243 | | - |
---|
1244 | | -static const struct file_operations synth_events_fops = { |
---|
1245 | | - .open = synth_events_open, |
---|
1246 | | - .write = synth_events_write, |
---|
1247 | | - .read = seq_read, |
---|
1248 | | - .llseek = seq_lseek, |
---|
1249 | | - .release = seq_release, |
---|
1250 | 624 | }; |
---|
1251 | 625 | |
---|
1252 | 626 | static u64 hist_field_timestamp(struct hist_field *hist_field, |
---|
.. | .. |
---|
1291 | 665 | struct hist_trigger_data *var_data, |
---|
1292 | 666 | unsigned int var_idx) |
---|
1293 | 667 | { |
---|
1294 | | - struct hist_field *found = NULL; |
---|
| 668 | + WARN_ON(!(hist_field && hist_field->flags & HIST_FIELD_FL_VAR_REF)); |
---|
1295 | 669 | |
---|
1296 | | - if (hist_field && hist_field->flags & HIST_FIELD_FL_VAR_REF) { |
---|
1297 | | - if (hist_field->var.idx == var_idx && |
---|
1298 | | - hist_field->var.hist_data == var_data) { |
---|
1299 | | - found = hist_field; |
---|
1300 | | - } |
---|
1301 | | - } |
---|
| 670 | + if (hist_field && hist_field->var.idx == var_idx && |
---|
| 671 | + hist_field->var.hist_data == var_data) |
---|
| 672 | + return hist_field; |
---|
1302 | 673 | |
---|
1303 | | - return found; |
---|
1304 | | -} |
---|
1305 | | - |
---|
1306 | | -static struct hist_field * |
---|
1307 | | -check_field_for_var_refs(struct hist_trigger_data *hist_data, |
---|
1308 | | - struct hist_field *hist_field, |
---|
1309 | | - struct hist_trigger_data *var_data, |
---|
1310 | | - unsigned int var_idx, |
---|
1311 | | - unsigned int level) |
---|
1312 | | -{ |
---|
1313 | | - struct hist_field *found = NULL; |
---|
1314 | | - unsigned int i; |
---|
1315 | | - |
---|
1316 | | - if (level > 3) |
---|
1317 | | - return found; |
---|
1318 | | - |
---|
1319 | | - if (!hist_field) |
---|
1320 | | - return found; |
---|
1321 | | - |
---|
1322 | | - found = check_field_for_var_ref(hist_field, var_data, var_idx); |
---|
1323 | | - if (found) |
---|
1324 | | - return found; |
---|
1325 | | - |
---|
1326 | | - for (i = 0; i < HIST_FIELD_OPERANDS_MAX; i++) { |
---|
1327 | | - struct hist_field *operand; |
---|
1328 | | - |
---|
1329 | | - operand = hist_field->operands[i]; |
---|
1330 | | - found = check_field_for_var_refs(hist_data, operand, var_data, |
---|
1331 | | - var_idx, level + 1); |
---|
1332 | | - if (found) |
---|
1333 | | - return found; |
---|
1334 | | - } |
---|
1335 | | - |
---|
1336 | | - return found; |
---|
| 674 | + return NULL; |
---|
1337 | 675 | } |
---|
1338 | 676 | |
---|
1339 | 677 | /** |
---|
.. | .. |
---|
1352 | 690 | struct hist_trigger_data *var_data, |
---|
1353 | 691 | unsigned int var_idx) |
---|
1354 | 692 | { |
---|
1355 | | - struct hist_field *hist_field, *found = NULL; |
---|
| 693 | + struct hist_field *hist_field; |
---|
1356 | 694 | unsigned int i; |
---|
1357 | 695 | |
---|
1358 | | - for_each_hist_field(i, hist_data) { |
---|
1359 | | - hist_field = hist_data->fields[i]; |
---|
1360 | | - found = check_field_for_var_refs(hist_data, hist_field, |
---|
1361 | | - var_data, var_idx, 0); |
---|
1362 | | - if (found) |
---|
1363 | | - return found; |
---|
| 696 | + for (i = 0; i < hist_data->n_var_refs; i++) { |
---|
| 697 | + hist_field = hist_data->var_refs[i]; |
---|
| 698 | + if (check_field_for_var_ref(hist_field, var_data, var_idx)) |
---|
| 699 | + return hist_field; |
---|
1364 | 700 | } |
---|
1365 | 701 | |
---|
1366 | | - for (i = 0; i < hist_data->n_synth_var_refs; i++) { |
---|
1367 | | - hist_field = hist_data->synth_var_refs[i]; |
---|
1368 | | - found = check_field_for_var_refs(hist_data, hist_field, |
---|
1369 | | - var_data, var_idx, 0); |
---|
1370 | | - if (found) |
---|
1371 | | - return found; |
---|
1372 | | - } |
---|
1373 | | - |
---|
1374 | | - return found; |
---|
| 702 | + return NULL; |
---|
1375 | 703 | } |
---|
1376 | 704 | |
---|
1377 | 705 | /** |
---|
.. | .. |
---|
1502 | 830 | if (var_data) |
---|
1503 | 831 | return 0; |
---|
1504 | 832 | |
---|
1505 | | - if (trace_array_get(tr) < 0) |
---|
| 833 | + if (tracing_check_open_get_tr(tr)) |
---|
1506 | 834 | return -ENODEV; |
---|
1507 | 835 | |
---|
1508 | 836 | var_data = kzalloc(sizeof(*var_data), GFP_KERNEL); |
---|
.. | .. |
---|
1600 | 928 | |
---|
1601 | 929 | if (find_var_field(var_hist_data, var_name)) { |
---|
1602 | 930 | if (found) { |
---|
1603 | | - hist_err_event("Variable name not unique, need to use fully qualified name (subsys.event.var) for variable: ", system, event_name, var_name); |
---|
| 931 | + hist_err(tr, HIST_ERR_VAR_NOT_UNIQUE, errpos(var_name)); |
---|
1604 | 932 | return NULL; |
---|
1605 | 933 | } |
---|
1606 | 934 | |
---|
.. | .. |
---|
1643 | 971 | for (i = 0; i < hist_data->n_actions; i++) { |
---|
1644 | 972 | struct action_data *data = hist_data->actions[i]; |
---|
1645 | 973 | |
---|
1646 | | - if (data->fn == action_trace) { |
---|
1647 | | - char *system = data->onmatch.match_event_system; |
---|
1648 | | - char *event_name = data->onmatch.match_event; |
---|
| 974 | + if (data->handler == HANDLER_ONMATCH) { |
---|
| 975 | + char *system = data->match_data.event_system; |
---|
| 976 | + char *event_name = data->match_data.event; |
---|
1649 | 977 | |
---|
1650 | 978 | file = find_var_file(tr, system, event_name, var_name); |
---|
1651 | 979 | if (!file) |
---|
.. | .. |
---|
1653 | 981 | hist_field = find_file_var(file, var_name); |
---|
1654 | 982 | if (hist_field) { |
---|
1655 | 983 | if (found) { |
---|
1656 | | - hist_err_event("Variable name not unique, need to use fully qualified name (subsys.event.var) for variable: ", system, event_name, var_name); |
---|
| 984 | + hist_err(tr, HIST_ERR_VAR_NOT_UNIQUE, |
---|
| 985 | + errpos(var_name)); |
---|
1657 | 986 | return ERR_PTR(-EINVAL); |
---|
1658 | 987 | } |
---|
1659 | 988 | |
---|
.. | .. |
---|
1689 | 1018 | |
---|
1690 | 1019 | return hist_field; |
---|
1691 | 1020 | } |
---|
1692 | | - |
---|
1693 | | -struct hist_elt_data { |
---|
1694 | | - char *comm; |
---|
1695 | | - u64 *var_ref_vals; |
---|
1696 | | - char *field_var_str[SYNTH_FIELDS_MAX]; |
---|
1697 | | -}; |
---|
1698 | 1021 | |
---|
1699 | 1022 | static u64 hist_field_var_ref(struct hist_field *hist_field, |
---|
1700 | 1023 | struct tracing_map_elt *elt, |
---|
.. | .. |
---|
1763 | 1086 | unsigned int level) |
---|
1764 | 1087 | { |
---|
1765 | 1088 | const char *field_name = ""; |
---|
| 1089 | + |
---|
| 1090 | + if (WARN_ON_ONCE(!field)) |
---|
| 1091 | + return field_name; |
---|
1766 | 1092 | |
---|
1767 | 1093 | if (level > 1) |
---|
1768 | 1094 | return field_name; |
---|
.. | .. |
---|
1835 | 1161 | unsigned long size, map_bits; |
---|
1836 | 1162 | int ret; |
---|
1837 | 1163 | |
---|
1838 | | - strsep(&str, "="); |
---|
1839 | | - if (!str) { |
---|
1840 | | - ret = -EINVAL; |
---|
1841 | | - goto out; |
---|
1842 | | - } |
---|
1843 | | - |
---|
1844 | 1164 | ret = kstrtoul(str, 0, &size); |
---|
1845 | 1165 | if (ret) |
---|
1846 | 1166 | goto out; |
---|
.. | .. |
---|
1883 | 1203 | if (attrs->n_actions >= HIST_ACTIONS_MAX) |
---|
1884 | 1204 | return ret; |
---|
1885 | 1205 | |
---|
1886 | | - if ((strncmp(str, "onmatch(", strlen("onmatch(")) == 0) || |
---|
1887 | | - (strncmp(str, "onmax(", strlen("onmax(")) == 0)) { |
---|
| 1206 | + if ((str_has_prefix(str, "onmatch(")) || |
---|
| 1207 | + (str_has_prefix(str, "onmax(")) || |
---|
| 1208 | + (str_has_prefix(str, "onchange("))) { |
---|
1888 | 1209 | attrs->action_str[attrs->n_actions] = kstrdup(str, GFP_KERNEL); |
---|
1889 | 1210 | if (!attrs->action_str[attrs->n_actions]) { |
---|
1890 | 1211 | ret = -ENOMEM; |
---|
.. | .. |
---|
1893 | 1214 | attrs->n_actions++; |
---|
1894 | 1215 | ret = 0; |
---|
1895 | 1216 | } |
---|
1896 | | - |
---|
1897 | 1217 | return ret; |
---|
1898 | 1218 | } |
---|
1899 | 1219 | |
---|
1900 | | -static int parse_assignment(char *str, struct hist_trigger_attrs *attrs) |
---|
| 1220 | +static int parse_assignment(struct trace_array *tr, |
---|
| 1221 | + char *str, struct hist_trigger_attrs *attrs) |
---|
1901 | 1222 | { |
---|
1902 | | - int ret = 0; |
---|
| 1223 | + int len, ret = 0; |
---|
1903 | 1224 | |
---|
1904 | | - if ((strncmp(str, "key=", strlen("key=")) == 0) || |
---|
1905 | | - (strncmp(str, "keys=", strlen("keys=")) == 0)) { |
---|
1906 | | - attrs->keys_str = kstrdup(str, GFP_KERNEL); |
---|
| 1225 | + if ((len = str_has_prefix(str, "key=")) || |
---|
| 1226 | + (len = str_has_prefix(str, "keys="))) { |
---|
| 1227 | + attrs->keys_str = kstrdup(str + len, GFP_KERNEL); |
---|
1907 | 1228 | if (!attrs->keys_str) { |
---|
1908 | 1229 | ret = -ENOMEM; |
---|
1909 | 1230 | goto out; |
---|
1910 | 1231 | } |
---|
1911 | | - } else if ((strncmp(str, "val=", strlen("val=")) == 0) || |
---|
1912 | | - (strncmp(str, "vals=", strlen("vals=")) == 0) || |
---|
1913 | | - (strncmp(str, "values=", strlen("values=")) == 0)) { |
---|
1914 | | - attrs->vals_str = kstrdup(str, GFP_KERNEL); |
---|
| 1232 | + } else if ((len = str_has_prefix(str, "val=")) || |
---|
| 1233 | + (len = str_has_prefix(str, "vals=")) || |
---|
| 1234 | + (len = str_has_prefix(str, "values="))) { |
---|
| 1235 | + attrs->vals_str = kstrdup(str + len, GFP_KERNEL); |
---|
1915 | 1236 | if (!attrs->vals_str) { |
---|
1916 | 1237 | ret = -ENOMEM; |
---|
1917 | 1238 | goto out; |
---|
1918 | 1239 | } |
---|
1919 | | - } else if (strncmp(str, "sort=", strlen("sort=")) == 0) { |
---|
1920 | | - attrs->sort_key_str = kstrdup(str, GFP_KERNEL); |
---|
| 1240 | + } else if ((len = str_has_prefix(str, "sort="))) { |
---|
| 1241 | + attrs->sort_key_str = kstrdup(str + len, GFP_KERNEL); |
---|
1921 | 1242 | if (!attrs->sort_key_str) { |
---|
1922 | 1243 | ret = -ENOMEM; |
---|
1923 | 1244 | goto out; |
---|
1924 | 1245 | } |
---|
1925 | | - } else if (strncmp(str, "name=", strlen("name=")) == 0) { |
---|
| 1246 | + } else if (str_has_prefix(str, "name=")) { |
---|
1926 | 1247 | attrs->name = kstrdup(str, GFP_KERNEL); |
---|
1927 | 1248 | if (!attrs->name) { |
---|
1928 | 1249 | ret = -ENOMEM; |
---|
1929 | 1250 | goto out; |
---|
1930 | 1251 | } |
---|
1931 | | - } else if (strncmp(str, "clock=", strlen("clock=")) == 0) { |
---|
1932 | | - strsep(&str, "="); |
---|
1933 | | - if (!str) { |
---|
1934 | | - ret = -EINVAL; |
---|
1935 | | - goto out; |
---|
1936 | | - } |
---|
| 1252 | + } else if ((len = str_has_prefix(str, "clock="))) { |
---|
| 1253 | + str += len; |
---|
1937 | 1254 | |
---|
1938 | 1255 | str = strstrip(str); |
---|
1939 | 1256 | attrs->clock = kstrdup(str, GFP_KERNEL); |
---|
.. | .. |
---|
1941 | 1258 | ret = -ENOMEM; |
---|
1942 | 1259 | goto out; |
---|
1943 | 1260 | } |
---|
1944 | | - } else if (strncmp(str, "size=", strlen("size=")) == 0) { |
---|
1945 | | - int map_bits = parse_map_size(str); |
---|
| 1261 | + } else if ((len = str_has_prefix(str, "size="))) { |
---|
| 1262 | + int map_bits = parse_map_size(str + len); |
---|
1946 | 1263 | |
---|
1947 | 1264 | if (map_bits < 0) { |
---|
1948 | 1265 | ret = map_bits; |
---|
.. | .. |
---|
1953 | 1270 | char *assignment; |
---|
1954 | 1271 | |
---|
1955 | 1272 | if (attrs->n_assignments == TRACING_MAP_VARS_MAX) { |
---|
1956 | | - hist_err("Too many variables defined: ", str); |
---|
| 1273 | + hist_err(tr, HIST_ERR_TOO_MANY_VARS, errpos(str)); |
---|
1957 | 1274 | ret = -EINVAL; |
---|
1958 | 1275 | goto out; |
---|
1959 | 1276 | } |
---|
.. | .. |
---|
1970 | 1287 | return ret; |
---|
1971 | 1288 | } |
---|
1972 | 1289 | |
---|
1973 | | -static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str) |
---|
| 1290 | +static struct hist_trigger_attrs * |
---|
| 1291 | +parse_hist_trigger_attrs(struct trace_array *tr, char *trigger_str) |
---|
1974 | 1292 | { |
---|
1975 | 1293 | struct hist_trigger_attrs *attrs; |
---|
1976 | 1294 | int ret = 0; |
---|
.. | .. |
---|
1981 | 1299 | |
---|
1982 | 1300 | while (trigger_str) { |
---|
1983 | 1301 | char *str = strsep(&trigger_str, ":"); |
---|
| 1302 | + char *rhs; |
---|
1984 | 1303 | |
---|
1985 | | - if (strchr(str, '=')) { |
---|
1986 | | - ret = parse_assignment(str, attrs); |
---|
| 1304 | + rhs = strchr(str, '='); |
---|
| 1305 | + if (rhs) { |
---|
| 1306 | + if (!strlen(++rhs)) { |
---|
| 1307 | + ret = -EINVAL; |
---|
| 1308 | + hist_err(tr, HIST_ERR_EMPTY_ASSIGNMENT, errpos(str)); |
---|
| 1309 | + goto free; |
---|
| 1310 | + } |
---|
| 1311 | + ret = parse_assignment(tr, str, attrs); |
---|
1987 | 1312 | if (ret) |
---|
1988 | 1313 | goto free; |
---|
1989 | 1314 | } else if (strcmp(str, "pause") == 0) |
---|
.. | .. |
---|
2032 | 1357 | return; |
---|
2033 | 1358 | } |
---|
2034 | 1359 | |
---|
2035 | | - memcpy(comm, task->comm, TASK_COMM_LEN); |
---|
| 1360 | + strncpy(comm, task->comm, TASK_COMM_LEN); |
---|
2036 | 1361 | } |
---|
2037 | 1362 | |
---|
2038 | 1363 | static void hist_elt_data_free(struct hist_elt_data *elt_data) |
---|
.. | .. |
---|
2078 | 1403 | } |
---|
2079 | 1404 | } |
---|
2080 | 1405 | |
---|
2081 | | - n_str = hist_data->n_field_var_str + hist_data->n_max_var_str; |
---|
| 1406 | + n_str = hist_data->n_field_var_str + hist_data->n_save_var_str + |
---|
| 1407 | + hist_data->n_var_str; |
---|
| 1408 | + if (n_str > SYNTH_FIELDS_MAX) { |
---|
| 1409 | + hist_elt_data_free(elt_data); |
---|
| 1410 | + return -EINVAL; |
---|
| 1411 | + } |
---|
| 1412 | + |
---|
| 1413 | + BUILD_BUG_ON(STR_VAR_LEN_MAX & (sizeof(u64) - 1)); |
---|
2082 | 1414 | |
---|
2083 | 1415 | size = STR_VAR_LEN_MAX; |
---|
2084 | 1416 | |
---|
.. | .. |
---|
2247 | 1579 | kfree(hist_field->name); |
---|
2248 | 1580 | kfree(hist_field->type); |
---|
2249 | 1581 | |
---|
| 1582 | + kfree(hist_field->system); |
---|
| 1583 | + kfree(hist_field->event_name); |
---|
| 1584 | + |
---|
2250 | 1585 | kfree(hist_field); |
---|
2251 | 1586 | } |
---|
2252 | 1587 | |
---|
.. | .. |
---|
2314 | 1649 | unsigned long fl = flags & ~HIST_FIELD_FL_LOG2; |
---|
2315 | 1650 | hist_field->fn = hist_field_log2; |
---|
2316 | 1651 | hist_field->operands[0] = create_hist_field(hist_data, field, fl, NULL); |
---|
| 1652 | + if (!hist_field->operands[0]) |
---|
| 1653 | + goto free; |
---|
2317 | 1654 | hist_field->size = hist_field->operands[0]->size; |
---|
2318 | 1655 | hist_field->type = kstrdup(hist_field->operands[0]->type, GFP_KERNEL); |
---|
2319 | 1656 | if (!hist_field->type) |
---|
.. | .. |
---|
2352 | 1689 | if (!hist_field->type) |
---|
2353 | 1690 | goto free; |
---|
2354 | 1691 | |
---|
2355 | | - if (field->filter_type == FILTER_STATIC_STRING) |
---|
| 1692 | + if (field->filter_type == FILTER_STATIC_STRING) { |
---|
2356 | 1693 | hist_field->fn = hist_field_string; |
---|
2357 | | - else if (field->filter_type == FILTER_DYN_STRING) |
---|
| 1694 | + hist_field->size = field->size; |
---|
| 1695 | + } else if (field->filter_type == FILTER_DYN_STRING) |
---|
2358 | 1696 | hist_field->fn = hist_field_dynstring; |
---|
2359 | 1697 | else |
---|
2360 | 1698 | hist_field->fn = hist_field_pstring; |
---|
.. | .. |
---|
2456 | 1794 | return err; |
---|
2457 | 1795 | free: |
---|
2458 | 1796 | kfree(ref_field->system); |
---|
| 1797 | + ref_field->system = NULL; |
---|
2459 | 1798 | kfree(ref_field->event_name); |
---|
| 1799 | + ref_field->event_name = NULL; |
---|
2460 | 1800 | kfree(ref_field->name); |
---|
| 1801 | + ref_field->name = NULL; |
---|
2461 | 1802 | |
---|
2462 | 1803 | goto out; |
---|
| 1804 | +} |
---|
| 1805 | + |
---|
| 1806 | +static int find_var_ref_idx(struct hist_trigger_data *hist_data, |
---|
| 1807 | + struct hist_field *var_field) |
---|
| 1808 | +{ |
---|
| 1809 | + struct hist_field *ref_field; |
---|
| 1810 | + int i; |
---|
| 1811 | + |
---|
| 1812 | + for (i = 0; i < hist_data->n_var_refs; i++) { |
---|
| 1813 | + ref_field = hist_data->var_refs[i]; |
---|
| 1814 | + if (ref_field->var.idx == var_field->var.idx && |
---|
| 1815 | + ref_field->var.hist_data == var_field->hist_data) |
---|
| 1816 | + return i; |
---|
| 1817 | + } |
---|
| 1818 | + |
---|
| 1819 | + return -ENOENT; |
---|
2463 | 1820 | } |
---|
2464 | 1821 | |
---|
2465 | 1822 | /** |
---|
.. | .. |
---|
2494 | 1851 | return ref_field; |
---|
2495 | 1852 | } |
---|
2496 | 1853 | } |
---|
2497 | | - |
---|
| 1854 | + /* Sanity check to avoid out-of-bound write on 'hist_data->var_refs' */ |
---|
| 1855 | + if (hist_data->n_var_refs >= TRACING_MAP_VARS_MAX) |
---|
| 1856 | + return NULL; |
---|
2498 | 1857 | ref_field = create_hist_field(var_field->hist_data, NULL, flags, NULL); |
---|
2499 | 1858 | if (ref_field) { |
---|
2500 | 1859 | if (init_var_ref(ref_field, var_field, system, event_name)) { |
---|
.. | .. |
---|
2569 | 1928 | char *var_name) |
---|
2570 | 1929 | { |
---|
2571 | 1930 | struct hist_field *var_field = NULL, *ref_field = NULL; |
---|
| 1931 | + struct trace_array *tr = hist_data->event_file->tr; |
---|
2572 | 1932 | |
---|
2573 | 1933 | if (!is_var_ref(var_name)) |
---|
2574 | 1934 | return NULL; |
---|
.. | .. |
---|
2581 | 1941 | system, event_name); |
---|
2582 | 1942 | |
---|
2583 | 1943 | if (!ref_field) |
---|
2584 | | - hist_err_event("Couldn't find variable: $", |
---|
2585 | | - system, event_name, var_name); |
---|
| 1944 | + hist_err(tr, HIST_ERR_VAR_NOT_FOUND, errpos(var_name)); |
---|
2586 | 1945 | |
---|
2587 | 1946 | return ref_field; |
---|
2588 | 1947 | } |
---|
.. | .. |
---|
2593 | 1952 | { |
---|
2594 | 1953 | struct ftrace_event_field *field = NULL; |
---|
2595 | 1954 | char *field_name, *modifier, *str; |
---|
| 1955 | + struct trace_array *tr = file->tr; |
---|
2596 | 1956 | |
---|
2597 | 1957 | modifier = str = kstrdup(field_str, GFP_KERNEL); |
---|
2598 | 1958 | if (!modifier) |
---|
.. | .. |
---|
2616 | 1976 | else if (strcmp(modifier, "usecs") == 0) |
---|
2617 | 1977 | *flags |= HIST_FIELD_FL_TIMESTAMP_USECS; |
---|
2618 | 1978 | else { |
---|
2619 | | - hist_err("Invalid field modifier: ", modifier); |
---|
| 1979 | + hist_err(tr, HIST_ERR_BAD_FIELD_MODIFIER, errpos(modifier)); |
---|
2620 | 1980 | field = ERR_PTR(-EINVAL); |
---|
2621 | 1981 | goto out; |
---|
2622 | 1982 | } |
---|
.. | .. |
---|
2635 | 1995 | /* |
---|
2636 | 1996 | * For backward compatibility, if field_name |
---|
2637 | 1997 | * was "cpu", then we treat this the same as |
---|
2638 | | - * common_cpu. |
---|
| 1998 | + * common_cpu. This also works for "CPU". |
---|
2639 | 1999 | */ |
---|
2640 | | - if (strcmp(field_name, "cpu") == 0) { |
---|
| 2000 | + if (field && field->filter_type == FILTER_CPU) { |
---|
2641 | 2001 | *flags |= HIST_FIELD_FL_CPU; |
---|
2642 | 2002 | } else { |
---|
2643 | | - hist_err("Couldn't find field: ", field_name); |
---|
| 2003 | + hist_err(tr, HIST_ERR_FIELD_NOT_FOUND, |
---|
| 2004 | + errpos(field_name)); |
---|
2644 | 2005 | field = ERR_PTR(-EINVAL); |
---|
2645 | 2006 | goto out; |
---|
2646 | 2007 | } |
---|
.. | .. |
---|
2705 | 2066 | |
---|
2706 | 2067 | s = local_field_var_ref(hist_data, ref_system, ref_event, ref_var); |
---|
2707 | 2068 | if (!s) { |
---|
2708 | | - hist_field = parse_var_ref(hist_data, ref_system, ref_event, ref_var); |
---|
| 2069 | + hist_field = parse_var_ref(hist_data, ref_system, |
---|
| 2070 | + ref_event, ref_var); |
---|
2709 | 2071 | if (hist_field) { |
---|
2710 | 2072 | if (var_name) { |
---|
2711 | 2073 | hist_field = create_alias(hist_data, hist_field, var_name); |
---|
.. | .. |
---|
2754 | 2116 | /* we support only -(xxx) i.e. explicit parens required */ |
---|
2755 | 2117 | |
---|
2756 | 2118 | if (level > 3) { |
---|
2757 | | - hist_err("Too many subexpressions (3 max): ", str); |
---|
| 2119 | + hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str)); |
---|
2758 | 2120 | ret = -EINVAL; |
---|
2759 | 2121 | goto free; |
---|
2760 | 2122 | } |
---|
.. | .. |
---|
2792 | 2154 | } |
---|
2793 | 2155 | if (operand1->flags & HIST_FIELD_FL_STRING) { |
---|
2794 | 2156 | /* String type can not be the operand of unary operator. */ |
---|
| 2157 | + hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(str)); |
---|
2795 | 2158 | destroy_hist_field(operand1, 0); |
---|
2796 | 2159 | ret = -EINVAL; |
---|
2797 | 2160 | goto free; |
---|
.. | .. |
---|
2801 | 2164 | (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS); |
---|
2802 | 2165 | expr->fn = hist_field_unary_minus; |
---|
2803 | 2166 | expr->operands[0] = operand1; |
---|
| 2167 | + expr->size = operand1->size; |
---|
| 2168 | + expr->is_signed = operand1->is_signed; |
---|
2804 | 2169 | expr->operator = FIELD_OP_UNARY_MINUS; |
---|
2805 | 2170 | expr->name = expr_str(expr, 0); |
---|
2806 | 2171 | expr->type = kstrdup(operand1->type, GFP_KERNEL); |
---|
.. | .. |
---|
2815 | 2180 | return ERR_PTR(ret); |
---|
2816 | 2181 | } |
---|
2817 | 2182 | |
---|
2818 | | -static int check_expr_operands(struct hist_field *operand1, |
---|
| 2183 | +static int check_expr_operands(struct trace_array *tr, |
---|
| 2184 | + struct hist_field *operand1, |
---|
2819 | 2185 | struct hist_field *operand2) |
---|
2820 | 2186 | { |
---|
2821 | 2187 | unsigned long operand1_flags = operand1->flags; |
---|
.. | .. |
---|
2843 | 2209 | |
---|
2844 | 2210 | if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS) != |
---|
2845 | 2211 | (operand2_flags & HIST_FIELD_FL_TIMESTAMP_USECS)) { |
---|
2846 | | - hist_err("Timestamp units in expression don't match", NULL); |
---|
| 2212 | + hist_err(tr, HIST_ERR_TIMESTAMP_MISMATCH, 0); |
---|
2847 | 2213 | return -EINVAL; |
---|
2848 | 2214 | } |
---|
2849 | 2215 | |
---|
.. | .. |
---|
2861 | 2227 | char *sep, *operand1_str; |
---|
2862 | 2228 | |
---|
2863 | 2229 | if (level > 3) { |
---|
2864 | | - hist_err("Too many subexpressions (3 max): ", str); |
---|
| 2230 | + hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str)); |
---|
2865 | 2231 | return ERR_PTR(-EINVAL); |
---|
2866 | 2232 | } |
---|
2867 | 2233 | |
---|
.. | .. |
---|
2897 | 2263 | goto free; |
---|
2898 | 2264 | } |
---|
2899 | 2265 | if (operand1->flags & HIST_FIELD_FL_STRING) { |
---|
| 2266 | + hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(operand1_str)); |
---|
2900 | 2267 | ret = -EINVAL; |
---|
2901 | 2268 | goto free; |
---|
2902 | 2269 | } |
---|
.. | .. |
---|
2910 | 2277 | goto free; |
---|
2911 | 2278 | } |
---|
2912 | 2279 | if (operand2->flags & HIST_FIELD_FL_STRING) { |
---|
| 2280 | + hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(str)); |
---|
2913 | 2281 | ret = -EINVAL; |
---|
2914 | 2282 | goto free; |
---|
2915 | 2283 | } |
---|
2916 | 2284 | |
---|
2917 | | - ret = check_expr_operands(operand1, operand2); |
---|
| 2285 | + ret = check_expr_operands(file->tr, operand1, operand2); |
---|
2918 | 2286 | if (ret) |
---|
2919 | 2287 | goto free; |
---|
2920 | 2288 | |
---|
.. | .. |
---|
2937 | 2305 | |
---|
2938 | 2306 | /* The operand sizes should be the same, so just pick one */ |
---|
2939 | 2307 | expr->size = operand1->size; |
---|
| 2308 | + expr->is_signed = operand1->is_signed; |
---|
2940 | 2309 | |
---|
2941 | 2310 | expr->operator = field_op; |
---|
2942 | 2311 | expr->name = expr_str(expr, 0); |
---|
.. | .. |
---|
3115 | 2484 | int ret; |
---|
3116 | 2485 | |
---|
3117 | 2486 | if (target_hist_data->n_field_var_hists >= SYNTH_FIELDS_MAX) { |
---|
3118 | | - hist_err_event("onmatch: Too many field variables defined: ", |
---|
3119 | | - subsys_name, event_name, field_name); |
---|
| 2487 | + hist_err(tr, HIST_ERR_TOO_MANY_FIELD_VARS, errpos(field_name)); |
---|
3120 | 2488 | return ERR_PTR(-EINVAL); |
---|
3121 | 2489 | } |
---|
3122 | 2490 | |
---|
3123 | 2491 | file = event_file(tr, subsys_name, event_name); |
---|
3124 | 2492 | |
---|
3125 | 2493 | if (IS_ERR(file)) { |
---|
3126 | | - hist_err_event("onmatch: Event file not found: ", |
---|
3127 | | - subsys_name, event_name, field_name); |
---|
| 2494 | + hist_err(tr, HIST_ERR_EVENT_FILE_NOT_FOUND, errpos(field_name)); |
---|
3128 | 2495 | ret = PTR_ERR(file); |
---|
3129 | 2496 | return ERR_PTR(ret); |
---|
3130 | 2497 | } |
---|
.. | .. |
---|
3137 | 2504 | */ |
---|
3138 | 2505 | hist_data = find_compatible_hist(target_hist_data, file); |
---|
3139 | 2506 | if (!hist_data) { |
---|
3140 | | - hist_err_event("onmatch: Matching event histogram not found: ", |
---|
3141 | | - subsys_name, event_name, field_name); |
---|
| 2507 | + hist_err(tr, HIST_ERR_HIST_NOT_FOUND, errpos(field_name)); |
---|
3142 | 2508 | return ERR_PTR(-EINVAL); |
---|
3143 | 2509 | } |
---|
3144 | 2510 | |
---|
.. | .. |
---|
3199 | 2565 | kfree(cmd); |
---|
3200 | 2566 | kfree(var_hist->cmd); |
---|
3201 | 2567 | kfree(var_hist); |
---|
3202 | | - hist_err_event("onmatch: Couldn't create histogram for field: ", |
---|
3203 | | - subsys_name, event_name, field_name); |
---|
| 2568 | + hist_err(tr, HIST_ERR_HIST_CREATE_FAIL, errpos(field_name)); |
---|
3204 | 2569 | return ERR_PTR(ret); |
---|
3205 | 2570 | } |
---|
3206 | 2571 | |
---|
.. | .. |
---|
3212 | 2577 | if (IS_ERR_OR_NULL(event_var)) { |
---|
3213 | 2578 | kfree(var_hist->cmd); |
---|
3214 | 2579 | kfree(var_hist); |
---|
3215 | | - hist_err_event("onmatch: Couldn't find synthetic variable: ", |
---|
3216 | | - subsys_name, event_name, field_name); |
---|
| 2580 | + hist_err(tr, HIST_ERR_SYNTH_VAR_NOT_FOUND, errpos(field_name)); |
---|
3217 | 2581 | return ERR_PTR(-EINVAL); |
---|
3218 | 2582 | } |
---|
3219 | 2583 | |
---|
.. | .. |
---|
3273 | 2637 | if (val->flags & HIST_FIELD_FL_STRING) { |
---|
3274 | 2638 | char *str = elt_data->field_var_str[j++]; |
---|
3275 | 2639 | char *val_str = (char *)(uintptr_t)var_val; |
---|
| 2640 | + unsigned int size; |
---|
3276 | 2641 | |
---|
3277 | | - strscpy(str, val_str, STR_VAR_LEN_MAX); |
---|
| 2642 | + size = min(val->size, STR_VAR_LEN_MAX); |
---|
| 2643 | + strscpy(str, val_str, size); |
---|
3278 | 2644 | var_val = (u64)(uintptr_t)str; |
---|
3279 | 2645 | } |
---|
3280 | 2646 | tracing_map_set_var(elt, var_idx, var_val); |
---|
.. | .. |
---|
3290 | 2656 | hist_data->n_field_vars, 0); |
---|
3291 | 2657 | } |
---|
3292 | 2658 | |
---|
3293 | | -static void update_max_vars(struct hist_trigger_data *hist_data, |
---|
3294 | | - struct tracing_map_elt *elt, |
---|
3295 | | - struct ring_buffer_event *rbe, |
---|
3296 | | - void *rec) |
---|
| 2659 | +static void save_track_data_vars(struct hist_trigger_data *hist_data, |
---|
| 2660 | + struct tracing_map_elt *elt, void *rec, |
---|
| 2661 | + struct ring_buffer_event *rbe, void *key, |
---|
| 2662 | + struct action_data *data, u64 *var_ref_vals) |
---|
3297 | 2663 | { |
---|
3298 | | - __update_field_vars(elt, rbe, rec, hist_data->max_vars, |
---|
3299 | | - hist_data->n_max_vars, hist_data->n_field_var_str); |
---|
| 2664 | + __update_field_vars(elt, rbe, rec, hist_data->save_vars, |
---|
| 2665 | + hist_data->n_save_vars, hist_data->n_field_var_str); |
---|
3300 | 2666 | } |
---|
3301 | 2667 | |
---|
3302 | 2668 | static struct hist_field *create_var(struct hist_trigger_data *hist_data, |
---|
.. | .. |
---|
3324 | 2690 | goto out; |
---|
3325 | 2691 | } |
---|
3326 | 2692 | |
---|
| 2693 | + var->ref = 1; |
---|
3327 | 2694 | var->flags = HIST_FIELD_FL_VAR; |
---|
3328 | 2695 | var->var.idx = idx; |
---|
3329 | 2696 | var->var.hist_data = var->hist_data = hist_data; |
---|
.. | .. |
---|
3346 | 2713 | { |
---|
3347 | 2714 | struct hist_field *val = NULL, *var = NULL; |
---|
3348 | 2715 | unsigned long flags = HIST_FIELD_FL_VAR; |
---|
| 2716 | + struct trace_array *tr = file->tr; |
---|
3349 | 2717 | struct field_var *field_var; |
---|
3350 | 2718 | int ret = 0; |
---|
3351 | 2719 | |
---|
3352 | 2720 | if (hist_data->n_field_vars >= SYNTH_FIELDS_MAX) { |
---|
3353 | | - hist_err("Too many field variables defined: ", field_name); |
---|
| 2721 | + hist_err(tr, HIST_ERR_TOO_MANY_FIELD_VARS, errpos(field_name)); |
---|
3354 | 2722 | ret = -EINVAL; |
---|
3355 | 2723 | goto err; |
---|
3356 | 2724 | } |
---|
3357 | 2725 | |
---|
3358 | 2726 | val = parse_atom(hist_data, file, field_name, &flags, NULL); |
---|
3359 | 2727 | if (IS_ERR(val)) { |
---|
3360 | | - hist_err("Couldn't parse field variable: ", field_name); |
---|
| 2728 | + hist_err(tr, HIST_ERR_FIELD_VAR_PARSE_FAIL, errpos(field_name)); |
---|
3361 | 2729 | ret = PTR_ERR(val); |
---|
3362 | 2730 | goto err; |
---|
3363 | 2731 | } |
---|
3364 | 2732 | |
---|
3365 | 2733 | var = create_var(hist_data, file, field_name, val->size, val->type); |
---|
3366 | 2734 | if (IS_ERR(var)) { |
---|
3367 | | - hist_err("Couldn't create or find variable: ", field_name); |
---|
| 2735 | + hist_err(tr, HIST_ERR_VAR_CREATE_FIND_FAIL, errpos(field_name)); |
---|
3368 | 2736 | kfree(val); |
---|
3369 | 2737 | ret = PTR_ERR(var); |
---|
3370 | 2738 | goto err; |
---|
.. | .. |
---|
3431 | 2799 | return create_field_var(target_hist_data, file, var_name); |
---|
3432 | 2800 | } |
---|
3433 | 2801 | |
---|
3434 | | -static void onmax_print(struct seq_file *m, |
---|
3435 | | - struct hist_trigger_data *hist_data, |
---|
3436 | | - struct tracing_map_elt *elt, |
---|
3437 | | - struct action_data *data) |
---|
| 2802 | +static bool check_track_val_max(u64 track_val, u64 var_val) |
---|
3438 | 2803 | { |
---|
3439 | | - unsigned int i, save_var_idx, max_idx = data->onmax.max_var->var.idx; |
---|
| 2804 | + if (var_val <= track_val) |
---|
| 2805 | + return false; |
---|
3440 | 2806 | |
---|
3441 | | - seq_printf(m, "\n\tmax: %10llu", tracing_map_read_var(elt, max_idx)); |
---|
| 2807 | + return true; |
---|
| 2808 | +} |
---|
3442 | 2809 | |
---|
3443 | | - for (i = 0; i < hist_data->n_max_vars; i++) { |
---|
3444 | | - struct hist_field *save_val = hist_data->max_vars[i]->val; |
---|
3445 | | - struct hist_field *save_var = hist_data->max_vars[i]->var; |
---|
| 2810 | +static bool check_track_val_changed(u64 track_val, u64 var_val) |
---|
| 2811 | +{ |
---|
| 2812 | + if (var_val == track_val) |
---|
| 2813 | + return false; |
---|
| 2814 | + |
---|
| 2815 | + return true; |
---|
| 2816 | +} |
---|
| 2817 | + |
---|
| 2818 | +static u64 get_track_val(struct hist_trigger_data *hist_data, |
---|
| 2819 | + struct tracing_map_elt *elt, |
---|
| 2820 | + struct action_data *data) |
---|
| 2821 | +{ |
---|
| 2822 | + unsigned int track_var_idx = data->track_data.track_var->var.idx; |
---|
| 2823 | + u64 track_val; |
---|
| 2824 | + |
---|
| 2825 | + track_val = tracing_map_read_var(elt, track_var_idx); |
---|
| 2826 | + |
---|
| 2827 | + return track_val; |
---|
| 2828 | +} |
---|
| 2829 | + |
---|
| 2830 | +static void save_track_val(struct hist_trigger_data *hist_data, |
---|
| 2831 | + struct tracing_map_elt *elt, |
---|
| 2832 | + struct action_data *data, u64 var_val) |
---|
| 2833 | +{ |
---|
| 2834 | + unsigned int track_var_idx = data->track_data.track_var->var.idx; |
---|
| 2835 | + |
---|
| 2836 | + tracing_map_set_var(elt, track_var_idx, var_val); |
---|
| 2837 | +} |
---|
| 2838 | + |
---|
| 2839 | +static void save_track_data(struct hist_trigger_data *hist_data, |
---|
| 2840 | + struct tracing_map_elt *elt, void *rec, |
---|
| 2841 | + struct ring_buffer_event *rbe, void *key, |
---|
| 2842 | + struct action_data *data, u64 *var_ref_vals) |
---|
| 2843 | +{ |
---|
| 2844 | + if (data->track_data.save_data) |
---|
| 2845 | + data->track_data.save_data(hist_data, elt, rec, rbe, key, data, var_ref_vals); |
---|
| 2846 | +} |
---|
| 2847 | + |
---|
| 2848 | +static bool check_track_val(struct tracing_map_elt *elt, |
---|
| 2849 | + struct action_data *data, |
---|
| 2850 | + u64 var_val) |
---|
| 2851 | +{ |
---|
| 2852 | + struct hist_trigger_data *hist_data; |
---|
| 2853 | + u64 track_val; |
---|
| 2854 | + |
---|
| 2855 | + hist_data = data->track_data.track_var->hist_data; |
---|
| 2856 | + track_val = get_track_val(hist_data, elt, data); |
---|
| 2857 | + |
---|
| 2858 | + return data->track_data.check_val(track_val, var_val); |
---|
| 2859 | +} |
---|
| 2860 | + |
---|
| 2861 | +#ifdef CONFIG_TRACER_SNAPSHOT |
---|
| 2862 | +static bool cond_snapshot_update(struct trace_array *tr, void *cond_data) |
---|
| 2863 | +{ |
---|
| 2864 | + /* called with tr->max_lock held */ |
---|
| 2865 | + struct track_data *track_data = tr->cond_snapshot->cond_data; |
---|
| 2866 | + struct hist_elt_data *elt_data, *track_elt_data; |
---|
| 2867 | + struct snapshot_context *context = cond_data; |
---|
| 2868 | + struct action_data *action; |
---|
| 2869 | + u64 track_val; |
---|
| 2870 | + |
---|
| 2871 | + if (!track_data) |
---|
| 2872 | + return false; |
---|
| 2873 | + |
---|
| 2874 | + action = track_data->action_data; |
---|
| 2875 | + |
---|
| 2876 | + track_val = get_track_val(track_data->hist_data, context->elt, |
---|
| 2877 | + track_data->action_data); |
---|
| 2878 | + |
---|
| 2879 | + if (!action->track_data.check_val(track_data->track_val, track_val)) |
---|
| 2880 | + return false; |
---|
| 2881 | + |
---|
| 2882 | + track_data->track_val = track_val; |
---|
| 2883 | + memcpy(track_data->key, context->key, track_data->key_len); |
---|
| 2884 | + |
---|
| 2885 | + elt_data = context->elt->private_data; |
---|
| 2886 | + track_elt_data = track_data->elt.private_data; |
---|
| 2887 | + if (elt_data->comm) |
---|
| 2888 | + strncpy(track_elt_data->comm, elt_data->comm, TASK_COMM_LEN); |
---|
| 2889 | + |
---|
| 2890 | + track_data->updated = true; |
---|
| 2891 | + |
---|
| 2892 | + return true; |
---|
| 2893 | +} |
---|
| 2894 | + |
---|
| 2895 | +static void save_track_data_snapshot(struct hist_trigger_data *hist_data, |
---|
| 2896 | + struct tracing_map_elt *elt, void *rec, |
---|
| 2897 | + struct ring_buffer_event *rbe, void *key, |
---|
| 2898 | + struct action_data *data, |
---|
| 2899 | + u64 *var_ref_vals) |
---|
| 2900 | +{ |
---|
| 2901 | + struct trace_event_file *file = hist_data->event_file; |
---|
| 2902 | + struct snapshot_context context; |
---|
| 2903 | + |
---|
| 2904 | + context.elt = elt; |
---|
| 2905 | + context.key = key; |
---|
| 2906 | + |
---|
| 2907 | + tracing_snapshot_cond(file->tr, &context); |
---|
| 2908 | +} |
---|
| 2909 | + |
---|
| 2910 | +static void hist_trigger_print_key(struct seq_file *m, |
---|
| 2911 | + struct hist_trigger_data *hist_data, |
---|
| 2912 | + void *key, |
---|
| 2913 | + struct tracing_map_elt *elt); |
---|
| 2914 | + |
---|
| 2915 | +static struct action_data *snapshot_action(struct hist_trigger_data *hist_data) |
---|
| 2916 | +{ |
---|
| 2917 | + unsigned int i; |
---|
| 2918 | + |
---|
| 2919 | + if (!hist_data->n_actions) |
---|
| 2920 | + return NULL; |
---|
| 2921 | + |
---|
| 2922 | + for (i = 0; i < hist_data->n_actions; i++) { |
---|
| 2923 | + struct action_data *data = hist_data->actions[i]; |
---|
| 2924 | + |
---|
| 2925 | + if (data->action == ACTION_SNAPSHOT) |
---|
| 2926 | + return data; |
---|
| 2927 | + } |
---|
| 2928 | + |
---|
| 2929 | + return NULL; |
---|
| 2930 | +} |
---|
| 2931 | + |
---|
| 2932 | +static void track_data_snapshot_print(struct seq_file *m, |
---|
| 2933 | + struct hist_trigger_data *hist_data) |
---|
| 2934 | +{ |
---|
| 2935 | + struct trace_event_file *file = hist_data->event_file; |
---|
| 2936 | + struct track_data *track_data; |
---|
| 2937 | + struct action_data *action; |
---|
| 2938 | + |
---|
| 2939 | + track_data = tracing_cond_snapshot_data(file->tr); |
---|
| 2940 | + if (!track_data) |
---|
| 2941 | + return; |
---|
| 2942 | + |
---|
| 2943 | + if (!track_data->updated) |
---|
| 2944 | + return; |
---|
| 2945 | + |
---|
| 2946 | + action = snapshot_action(hist_data); |
---|
| 2947 | + if (!action) |
---|
| 2948 | + return; |
---|
| 2949 | + |
---|
| 2950 | + seq_puts(m, "\nSnapshot taken (see tracing/snapshot). Details:\n"); |
---|
| 2951 | + seq_printf(m, "\ttriggering value { %s(%s) }: %10llu", |
---|
| 2952 | + action->handler == HANDLER_ONMAX ? "onmax" : "onchange", |
---|
| 2953 | + action->track_data.var_str, track_data->track_val); |
---|
| 2954 | + |
---|
| 2955 | + seq_puts(m, "\ttriggered by event with key: "); |
---|
| 2956 | + hist_trigger_print_key(m, hist_data, track_data->key, &track_data->elt); |
---|
| 2957 | + seq_putc(m, '\n'); |
---|
| 2958 | +} |
---|
| 2959 | +#else |
---|
| 2960 | +static bool cond_snapshot_update(struct trace_array *tr, void *cond_data) |
---|
| 2961 | +{ |
---|
| 2962 | + return false; |
---|
| 2963 | +} |
---|
| 2964 | +static void save_track_data_snapshot(struct hist_trigger_data *hist_data, |
---|
| 2965 | + struct tracing_map_elt *elt, void *rec, |
---|
| 2966 | + struct ring_buffer_event *rbe, void *key, |
---|
| 2967 | + struct action_data *data, |
---|
| 2968 | + u64 *var_ref_vals) {} |
---|
| 2969 | +static void track_data_snapshot_print(struct seq_file *m, |
---|
| 2970 | + struct hist_trigger_data *hist_data) {} |
---|
| 2971 | +#endif /* CONFIG_TRACER_SNAPSHOT */ |
---|
| 2972 | + |
---|
| 2973 | +static void track_data_print(struct seq_file *m, |
---|
| 2974 | + struct hist_trigger_data *hist_data, |
---|
| 2975 | + struct tracing_map_elt *elt, |
---|
| 2976 | + struct action_data *data) |
---|
| 2977 | +{ |
---|
| 2978 | + u64 track_val = get_track_val(hist_data, elt, data); |
---|
| 2979 | + unsigned int i, save_var_idx; |
---|
| 2980 | + |
---|
| 2981 | + if (data->handler == HANDLER_ONMAX) |
---|
| 2982 | + seq_printf(m, "\n\tmax: %10llu", track_val); |
---|
| 2983 | + else if (data->handler == HANDLER_ONCHANGE) |
---|
| 2984 | + seq_printf(m, "\n\tchanged: %10llu", track_val); |
---|
| 2985 | + |
---|
| 2986 | + if (data->action == ACTION_SNAPSHOT) |
---|
| 2987 | + return; |
---|
| 2988 | + |
---|
| 2989 | + for (i = 0; i < hist_data->n_save_vars; i++) { |
---|
| 2990 | + struct hist_field *save_val = hist_data->save_vars[i]->val; |
---|
| 2991 | + struct hist_field *save_var = hist_data->save_vars[i]->var; |
---|
3446 | 2992 | u64 val; |
---|
3447 | 2993 | |
---|
3448 | 2994 | save_var_idx = save_var->var.idx; |
---|
.. | .. |
---|
3457 | 3003 | } |
---|
3458 | 3004 | } |
---|
3459 | 3005 | |
---|
3460 | | -static void onmax_save(struct hist_trigger_data *hist_data, |
---|
3461 | | - struct tracing_map_elt *elt, void *rec, |
---|
3462 | | - struct ring_buffer_event *rbe, |
---|
3463 | | - struct action_data *data, u64 *var_ref_vals) |
---|
| 3006 | +static void ontrack_action(struct hist_trigger_data *hist_data, |
---|
| 3007 | + struct tracing_map_elt *elt, void *rec, |
---|
| 3008 | + struct ring_buffer_event *rbe, void *key, |
---|
| 3009 | + struct action_data *data, u64 *var_ref_vals) |
---|
3464 | 3010 | { |
---|
3465 | | - unsigned int max_idx = data->onmax.max_var->var.idx; |
---|
3466 | | - unsigned int max_var_ref_idx = data->onmax.max_var_ref_idx; |
---|
| 3011 | + u64 var_val = var_ref_vals[data->track_data.var_ref->var_ref_idx]; |
---|
3467 | 3012 | |
---|
3468 | | - u64 var_val, max_val; |
---|
3469 | | - |
---|
3470 | | - var_val = var_ref_vals[max_var_ref_idx]; |
---|
3471 | | - max_val = tracing_map_read_var(elt, max_idx); |
---|
3472 | | - |
---|
3473 | | - if (var_val <= max_val) |
---|
3474 | | - return; |
---|
3475 | | - |
---|
3476 | | - tracing_map_set_var(elt, max_idx, var_val); |
---|
3477 | | - |
---|
3478 | | - update_max_vars(hist_data, elt, rbe, rec); |
---|
| 3013 | + if (check_track_val(elt, data, var_val)) { |
---|
| 3014 | + save_track_val(hist_data, elt, data, var_val); |
---|
| 3015 | + save_track_data(hist_data, elt, rec, rbe, key, data, var_ref_vals); |
---|
| 3016 | + } |
---|
3479 | 3017 | } |
---|
3480 | 3018 | |
---|
3481 | | -static void onmax_destroy(struct action_data *data) |
---|
| 3019 | +static void action_data_destroy(struct action_data *data) |
---|
3482 | 3020 | { |
---|
3483 | 3021 | unsigned int i; |
---|
3484 | 3022 | |
---|
3485 | | - destroy_hist_field(data->onmax.max_var, 0); |
---|
3486 | | - destroy_hist_field(data->onmax.var, 0); |
---|
| 3023 | + lockdep_assert_held(&event_mutex); |
---|
3487 | 3024 | |
---|
3488 | | - kfree(data->onmax.var_str); |
---|
3489 | | - kfree(data->onmax.fn_name); |
---|
| 3025 | + kfree(data->action_name); |
---|
3490 | 3026 | |
---|
3491 | 3027 | for (i = 0; i < data->n_params; i++) |
---|
3492 | 3028 | kfree(data->params[i]); |
---|
3493 | 3029 | |
---|
| 3030 | + if (data->synth_event) |
---|
| 3031 | + data->synth_event->ref--; |
---|
| 3032 | + |
---|
| 3033 | + kfree(data->synth_event_name); |
---|
| 3034 | + |
---|
3494 | 3035 | kfree(data); |
---|
3495 | 3036 | } |
---|
3496 | 3037 | |
---|
3497 | | -static int onmax_create(struct hist_trigger_data *hist_data, |
---|
3498 | | - struct action_data *data) |
---|
| 3038 | +static void track_data_destroy(struct hist_trigger_data *hist_data, |
---|
| 3039 | + struct action_data *data) |
---|
3499 | 3040 | { |
---|
3500 | 3041 | struct trace_event_file *file = hist_data->event_file; |
---|
3501 | | - struct hist_field *var_field, *ref_field, *max_var; |
---|
3502 | | - unsigned int var_ref_idx = hist_data->n_var_refs; |
---|
3503 | | - struct field_var *field_var; |
---|
3504 | | - char *onmax_var_str, *param; |
---|
3505 | | - unsigned int i; |
---|
| 3042 | + |
---|
| 3043 | + destroy_hist_field(data->track_data.track_var, 0); |
---|
| 3044 | + |
---|
| 3045 | + if (data->action == ACTION_SNAPSHOT) { |
---|
| 3046 | + struct track_data *track_data; |
---|
| 3047 | + |
---|
| 3048 | + track_data = tracing_cond_snapshot_data(file->tr); |
---|
| 3049 | + if (track_data && track_data->hist_data == hist_data) { |
---|
| 3050 | + tracing_snapshot_cond_disable(file->tr); |
---|
| 3051 | + track_data_free(track_data); |
---|
| 3052 | + } |
---|
| 3053 | + } |
---|
| 3054 | + |
---|
| 3055 | + kfree(data->track_data.var_str); |
---|
| 3056 | + |
---|
| 3057 | + action_data_destroy(data); |
---|
| 3058 | +} |
---|
| 3059 | + |
---|
| 3060 | +static int action_create(struct hist_trigger_data *hist_data, |
---|
| 3061 | + struct action_data *data); |
---|
| 3062 | + |
---|
| 3063 | +static int track_data_create(struct hist_trigger_data *hist_data, |
---|
| 3064 | + struct action_data *data) |
---|
| 3065 | +{ |
---|
| 3066 | + struct hist_field *var_field, *ref_field, *track_var = NULL; |
---|
| 3067 | + struct trace_event_file *file = hist_data->event_file; |
---|
| 3068 | + struct trace_array *tr = file->tr; |
---|
| 3069 | + char *track_data_var_str; |
---|
3506 | 3070 | int ret = 0; |
---|
3507 | 3071 | |
---|
3508 | | - onmax_var_str = data->onmax.var_str; |
---|
3509 | | - if (onmax_var_str[0] != '$') { |
---|
3510 | | - hist_err("onmax: For onmax(x), x must be a variable: ", onmax_var_str); |
---|
| 3072 | + track_data_var_str = data->track_data.var_str; |
---|
| 3073 | + if (track_data_var_str[0] != '$') { |
---|
| 3074 | + hist_err(tr, HIST_ERR_ONX_NOT_VAR, errpos(track_data_var_str)); |
---|
3511 | 3075 | return -EINVAL; |
---|
3512 | 3076 | } |
---|
3513 | | - onmax_var_str++; |
---|
| 3077 | + track_data_var_str++; |
---|
3514 | 3078 | |
---|
3515 | | - var_field = find_target_event_var(hist_data, NULL, NULL, onmax_var_str); |
---|
| 3079 | + var_field = find_target_event_var(hist_data, NULL, NULL, track_data_var_str); |
---|
3516 | 3080 | if (!var_field) { |
---|
3517 | | - hist_err("onmax: Couldn't find onmax variable: ", onmax_var_str); |
---|
| 3081 | + hist_err(tr, HIST_ERR_ONX_VAR_NOT_FOUND, errpos(track_data_var_str)); |
---|
3518 | 3082 | return -EINVAL; |
---|
3519 | 3083 | } |
---|
3520 | 3084 | |
---|
.. | .. |
---|
3522 | 3086 | if (!ref_field) |
---|
3523 | 3087 | return -ENOMEM; |
---|
3524 | 3088 | |
---|
3525 | | - data->onmax.var = ref_field; |
---|
| 3089 | + data->track_data.var_ref = ref_field; |
---|
3526 | 3090 | |
---|
3527 | | - data->fn = onmax_save; |
---|
3528 | | - data->onmax.max_var_ref_idx = var_ref_idx; |
---|
3529 | | - max_var = create_var(hist_data, file, "max", sizeof(u64), "u64"); |
---|
3530 | | - if (IS_ERR(max_var)) { |
---|
3531 | | - hist_err("onmax: Couldn't create onmax variable: ", "max"); |
---|
3532 | | - ret = PTR_ERR(max_var); |
---|
| 3091 | + if (data->handler == HANDLER_ONMAX) |
---|
| 3092 | + track_var = create_var(hist_data, file, "__max", sizeof(u64), "u64"); |
---|
| 3093 | + if (IS_ERR(track_var)) { |
---|
| 3094 | + hist_err(tr, HIST_ERR_ONX_VAR_CREATE_FAIL, 0); |
---|
| 3095 | + ret = PTR_ERR(track_var); |
---|
3533 | 3096 | goto out; |
---|
3534 | 3097 | } |
---|
3535 | | - data->onmax.max_var = max_var; |
---|
3536 | 3098 | |
---|
3537 | | - for (i = 0; i < data->n_params; i++) { |
---|
3538 | | - param = kstrdup(data->params[i], GFP_KERNEL); |
---|
3539 | | - if (!param) { |
---|
3540 | | - ret = -ENOMEM; |
---|
3541 | | - goto out; |
---|
3542 | | - } |
---|
3543 | | - |
---|
3544 | | - field_var = create_target_field_var(hist_data, NULL, NULL, param); |
---|
3545 | | - if (IS_ERR(field_var)) { |
---|
3546 | | - hist_err("onmax: Couldn't create field variable: ", param); |
---|
3547 | | - ret = PTR_ERR(field_var); |
---|
3548 | | - kfree(param); |
---|
3549 | | - goto out; |
---|
3550 | | - } |
---|
3551 | | - |
---|
3552 | | - hist_data->max_vars[hist_data->n_max_vars++] = field_var; |
---|
3553 | | - if (field_var->val->flags & HIST_FIELD_FL_STRING) |
---|
3554 | | - hist_data->n_max_var_str++; |
---|
3555 | | - |
---|
3556 | | - kfree(param); |
---|
| 3099 | + if (data->handler == HANDLER_ONCHANGE) |
---|
| 3100 | + track_var = create_var(hist_data, file, "__change", sizeof(u64), "u64"); |
---|
| 3101 | + if (IS_ERR(track_var)) { |
---|
| 3102 | + hist_err(tr, HIST_ERR_ONX_VAR_CREATE_FAIL, 0); |
---|
| 3103 | + ret = PTR_ERR(track_var); |
---|
| 3104 | + goto out; |
---|
3557 | 3105 | } |
---|
| 3106 | + data->track_data.track_var = track_var; |
---|
| 3107 | + |
---|
| 3108 | + ret = action_create(hist_data, data); |
---|
3558 | 3109 | out: |
---|
3559 | 3110 | return ret; |
---|
3560 | 3111 | } |
---|
3561 | 3112 | |
---|
3562 | | -static int parse_action_params(char *params, struct action_data *data) |
---|
| 3113 | +static int parse_action_params(struct trace_array *tr, char *params, |
---|
| 3114 | + struct action_data *data) |
---|
3563 | 3115 | { |
---|
3564 | 3116 | char *param, *saved_param; |
---|
| 3117 | + bool first_param = true; |
---|
3565 | 3118 | int ret = 0; |
---|
3566 | 3119 | |
---|
3567 | 3120 | while (params) { |
---|
3568 | | - if (data->n_params >= SYNTH_FIELDS_MAX) |
---|
| 3121 | + if (data->n_params >= SYNTH_FIELDS_MAX) { |
---|
| 3122 | + hist_err(tr, HIST_ERR_TOO_MANY_PARAMS, 0); |
---|
| 3123 | + ret = -EINVAL; |
---|
3569 | 3124 | goto out; |
---|
| 3125 | + } |
---|
3570 | 3126 | |
---|
3571 | 3127 | param = strsep(¶ms, ","); |
---|
3572 | 3128 | if (!param) { |
---|
| 3129 | + hist_err(tr, HIST_ERR_PARAM_NOT_FOUND, 0); |
---|
3573 | 3130 | ret = -EINVAL; |
---|
3574 | 3131 | goto out; |
---|
3575 | 3132 | } |
---|
3576 | 3133 | |
---|
3577 | 3134 | param = strstrip(param); |
---|
3578 | 3135 | if (strlen(param) < 2) { |
---|
3579 | | - hist_err("Invalid action param: ", param); |
---|
| 3136 | + hist_err(tr, HIST_ERR_INVALID_PARAM, errpos(param)); |
---|
3580 | 3137 | ret = -EINVAL; |
---|
3581 | 3138 | goto out; |
---|
3582 | 3139 | } |
---|
.. | .. |
---|
3587 | 3144 | goto out; |
---|
3588 | 3145 | } |
---|
3589 | 3146 | |
---|
| 3147 | + if (first_param && data->use_trace_keyword) { |
---|
| 3148 | + data->synth_event_name = saved_param; |
---|
| 3149 | + first_param = false; |
---|
| 3150 | + continue; |
---|
| 3151 | + } |
---|
| 3152 | + first_param = false; |
---|
| 3153 | + |
---|
3590 | 3154 | data->params[data->n_params++] = saved_param; |
---|
3591 | 3155 | } |
---|
3592 | 3156 | out: |
---|
3593 | 3157 | return ret; |
---|
3594 | 3158 | } |
---|
3595 | 3159 | |
---|
3596 | | -static struct action_data *onmax_parse(char *str) |
---|
| 3160 | +static int action_parse(struct trace_array *tr, char *str, struct action_data *data, |
---|
| 3161 | + enum handler_id handler) |
---|
3597 | 3162 | { |
---|
3598 | | - char *onmax_fn_name, *onmax_var_str; |
---|
| 3163 | + char *action_name; |
---|
| 3164 | + int ret = 0; |
---|
| 3165 | + |
---|
| 3166 | + strsep(&str, "."); |
---|
| 3167 | + if (!str) { |
---|
| 3168 | + hist_err(tr, HIST_ERR_ACTION_NOT_FOUND, 0); |
---|
| 3169 | + ret = -EINVAL; |
---|
| 3170 | + goto out; |
---|
| 3171 | + } |
---|
| 3172 | + |
---|
| 3173 | + action_name = strsep(&str, "("); |
---|
| 3174 | + if (!action_name || !str) { |
---|
| 3175 | + hist_err(tr, HIST_ERR_ACTION_NOT_FOUND, 0); |
---|
| 3176 | + ret = -EINVAL; |
---|
| 3177 | + goto out; |
---|
| 3178 | + } |
---|
| 3179 | + |
---|
| 3180 | + if (str_has_prefix(action_name, "save")) { |
---|
| 3181 | + char *params = strsep(&str, ")"); |
---|
| 3182 | + |
---|
| 3183 | + if (!params) { |
---|
| 3184 | + hist_err(tr, HIST_ERR_NO_SAVE_PARAMS, 0); |
---|
| 3185 | + ret = -EINVAL; |
---|
| 3186 | + goto out; |
---|
| 3187 | + } |
---|
| 3188 | + |
---|
| 3189 | + ret = parse_action_params(tr, params, data); |
---|
| 3190 | + if (ret) |
---|
| 3191 | + goto out; |
---|
| 3192 | + |
---|
| 3193 | + if (handler == HANDLER_ONMAX) |
---|
| 3194 | + data->track_data.check_val = check_track_val_max; |
---|
| 3195 | + else if (handler == HANDLER_ONCHANGE) |
---|
| 3196 | + data->track_data.check_val = check_track_val_changed; |
---|
| 3197 | + else { |
---|
| 3198 | + hist_err(tr, HIST_ERR_ACTION_MISMATCH, errpos(action_name)); |
---|
| 3199 | + ret = -EINVAL; |
---|
| 3200 | + goto out; |
---|
| 3201 | + } |
---|
| 3202 | + |
---|
| 3203 | + data->track_data.save_data = save_track_data_vars; |
---|
| 3204 | + data->fn = ontrack_action; |
---|
| 3205 | + data->action = ACTION_SAVE; |
---|
| 3206 | + } else if (str_has_prefix(action_name, "snapshot")) { |
---|
| 3207 | + char *params = strsep(&str, ")"); |
---|
| 3208 | + |
---|
| 3209 | + if (!str) { |
---|
| 3210 | + hist_err(tr, HIST_ERR_NO_CLOSING_PAREN, errpos(params)); |
---|
| 3211 | + ret = -EINVAL; |
---|
| 3212 | + goto out; |
---|
| 3213 | + } |
---|
| 3214 | + |
---|
| 3215 | + if (handler == HANDLER_ONMAX) |
---|
| 3216 | + data->track_data.check_val = check_track_val_max; |
---|
| 3217 | + else if (handler == HANDLER_ONCHANGE) |
---|
| 3218 | + data->track_data.check_val = check_track_val_changed; |
---|
| 3219 | + else { |
---|
| 3220 | + hist_err(tr, HIST_ERR_ACTION_MISMATCH, errpos(action_name)); |
---|
| 3221 | + ret = -EINVAL; |
---|
| 3222 | + goto out; |
---|
| 3223 | + } |
---|
| 3224 | + |
---|
| 3225 | + data->track_data.save_data = save_track_data_snapshot; |
---|
| 3226 | + data->fn = ontrack_action; |
---|
| 3227 | + data->action = ACTION_SNAPSHOT; |
---|
| 3228 | + } else { |
---|
| 3229 | + char *params = strsep(&str, ")"); |
---|
| 3230 | + |
---|
| 3231 | + if (str_has_prefix(action_name, "trace")) |
---|
| 3232 | + data->use_trace_keyword = true; |
---|
| 3233 | + |
---|
| 3234 | + if (params) { |
---|
| 3235 | + ret = parse_action_params(tr, params, data); |
---|
| 3236 | + if (ret) |
---|
| 3237 | + goto out; |
---|
| 3238 | + } |
---|
| 3239 | + |
---|
| 3240 | + if (handler == HANDLER_ONMAX) |
---|
| 3241 | + data->track_data.check_val = check_track_val_max; |
---|
| 3242 | + else if (handler == HANDLER_ONCHANGE) |
---|
| 3243 | + data->track_data.check_val = check_track_val_changed; |
---|
| 3244 | + |
---|
| 3245 | + if (handler != HANDLER_ONMATCH) { |
---|
| 3246 | + data->track_data.save_data = action_trace; |
---|
| 3247 | + data->fn = ontrack_action; |
---|
| 3248 | + } else |
---|
| 3249 | + data->fn = action_trace; |
---|
| 3250 | + |
---|
| 3251 | + data->action = ACTION_TRACE; |
---|
| 3252 | + } |
---|
| 3253 | + |
---|
| 3254 | + data->action_name = kstrdup(action_name, GFP_KERNEL); |
---|
| 3255 | + if (!data->action_name) { |
---|
| 3256 | + ret = -ENOMEM; |
---|
| 3257 | + goto out; |
---|
| 3258 | + } |
---|
| 3259 | + |
---|
| 3260 | + data->handler = handler; |
---|
| 3261 | + out: |
---|
| 3262 | + return ret; |
---|
| 3263 | +} |
---|
| 3264 | + |
---|
| 3265 | +static struct action_data *track_data_parse(struct hist_trigger_data *hist_data, |
---|
| 3266 | + char *str, enum handler_id handler) |
---|
| 3267 | +{ |
---|
3599 | 3268 | struct action_data *data; |
---|
3600 | 3269 | int ret = -EINVAL; |
---|
| 3270 | + char *var_str; |
---|
3601 | 3271 | |
---|
3602 | 3272 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
---|
3603 | 3273 | if (!data) |
---|
3604 | 3274 | return ERR_PTR(-ENOMEM); |
---|
3605 | 3275 | |
---|
3606 | | - onmax_var_str = strsep(&str, ")"); |
---|
3607 | | - if (!onmax_var_str || !str) { |
---|
| 3276 | + var_str = strsep(&str, ")"); |
---|
| 3277 | + if (!var_str || !str) { |
---|
3608 | 3278 | ret = -EINVAL; |
---|
3609 | 3279 | goto free; |
---|
3610 | 3280 | } |
---|
3611 | 3281 | |
---|
3612 | | - data->onmax.var_str = kstrdup(onmax_var_str, GFP_KERNEL); |
---|
3613 | | - if (!data->onmax.var_str) { |
---|
| 3282 | + data->track_data.var_str = kstrdup(var_str, GFP_KERNEL); |
---|
| 3283 | + if (!data->track_data.var_str) { |
---|
3614 | 3284 | ret = -ENOMEM; |
---|
3615 | 3285 | goto free; |
---|
3616 | 3286 | } |
---|
3617 | 3287 | |
---|
3618 | | - strsep(&str, "."); |
---|
3619 | | - if (!str) |
---|
| 3288 | + ret = action_parse(hist_data->event_file->tr, str, data, handler); |
---|
| 3289 | + if (ret) |
---|
3620 | 3290 | goto free; |
---|
3621 | | - |
---|
3622 | | - onmax_fn_name = strsep(&str, "("); |
---|
3623 | | - if (!onmax_fn_name || !str) |
---|
3624 | | - goto free; |
---|
3625 | | - |
---|
3626 | | - if (strncmp(onmax_fn_name, "save", strlen("save")) == 0) { |
---|
3627 | | - char *params = strsep(&str, ")"); |
---|
3628 | | - |
---|
3629 | | - if (!params) { |
---|
3630 | | - ret = -EINVAL; |
---|
3631 | | - goto free; |
---|
3632 | | - } |
---|
3633 | | - |
---|
3634 | | - ret = parse_action_params(params, data); |
---|
3635 | | - if (ret) |
---|
3636 | | - goto free; |
---|
3637 | | - } else |
---|
3638 | | - goto free; |
---|
3639 | | - |
---|
3640 | | - data->onmax.fn_name = kstrdup(onmax_fn_name, GFP_KERNEL); |
---|
3641 | | - if (!data->onmax.fn_name) { |
---|
3642 | | - ret = -ENOMEM; |
---|
3643 | | - goto free; |
---|
3644 | | - } |
---|
3645 | 3291 | out: |
---|
3646 | 3292 | return data; |
---|
3647 | 3293 | free: |
---|
3648 | | - onmax_destroy(data); |
---|
| 3294 | + track_data_destroy(hist_data, data); |
---|
3649 | 3295 | data = ERR_PTR(ret); |
---|
3650 | 3296 | goto out; |
---|
3651 | 3297 | } |
---|
3652 | 3298 | |
---|
3653 | 3299 | static void onmatch_destroy(struct action_data *data) |
---|
3654 | 3300 | { |
---|
3655 | | - unsigned int i; |
---|
| 3301 | + kfree(data->match_data.event); |
---|
| 3302 | + kfree(data->match_data.event_system); |
---|
3656 | 3303 | |
---|
3657 | | - mutex_lock(&synth_event_mutex); |
---|
3658 | | - |
---|
3659 | | - kfree(data->onmatch.match_event); |
---|
3660 | | - kfree(data->onmatch.match_event_system); |
---|
3661 | | - kfree(data->onmatch.synth_event_name); |
---|
3662 | | - |
---|
3663 | | - for (i = 0; i < data->n_params; i++) |
---|
3664 | | - kfree(data->params[i]); |
---|
3665 | | - |
---|
3666 | | - if (data->onmatch.synth_event) |
---|
3667 | | - data->onmatch.synth_event->ref--; |
---|
3668 | | - |
---|
3669 | | - kfree(data); |
---|
3670 | | - |
---|
3671 | | - mutex_unlock(&synth_event_mutex); |
---|
| 3304 | + action_data_destroy(data); |
---|
3672 | 3305 | } |
---|
3673 | 3306 | |
---|
3674 | 3307 | static void destroy_field_var(struct field_var *field_var) |
---|
.. | .. |
---|
3688 | 3321 | |
---|
3689 | 3322 | for (i = 0; i < hist_data->n_field_vars; i++) |
---|
3690 | 3323 | destroy_field_var(hist_data->field_vars[i]); |
---|
| 3324 | + |
---|
| 3325 | + for (i = 0; i < hist_data->n_save_vars; i++) |
---|
| 3326 | + destroy_field_var(hist_data->save_vars[i]); |
---|
3691 | 3327 | } |
---|
3692 | 3328 | |
---|
3693 | 3329 | static void save_field_var(struct hist_trigger_data *hist_data, |
---|
.. | .. |
---|
3700 | 3336 | } |
---|
3701 | 3337 | |
---|
3702 | 3338 | |
---|
3703 | | -static void destroy_synth_var_refs(struct hist_trigger_data *hist_data) |
---|
3704 | | -{ |
---|
3705 | | - unsigned int i; |
---|
3706 | | - |
---|
3707 | | - for (i = 0; i < hist_data->n_synth_var_refs; i++) |
---|
3708 | | - destroy_hist_field(hist_data->synth_var_refs[i], 0); |
---|
3709 | | -} |
---|
3710 | | - |
---|
3711 | | -static void save_synth_var_ref(struct hist_trigger_data *hist_data, |
---|
3712 | | - struct hist_field *var_ref) |
---|
3713 | | -{ |
---|
3714 | | - hist_data->synth_var_refs[hist_data->n_synth_var_refs++] = var_ref; |
---|
3715 | | -} |
---|
3716 | | - |
---|
3717 | 3339 | static int check_synth_field(struct synth_event *event, |
---|
3718 | 3340 | struct hist_field *hist_field, |
---|
3719 | 3341 | unsigned int field_pos) |
---|
.. | .. |
---|
3725 | 3347 | |
---|
3726 | 3348 | field = event->fields[field_pos]; |
---|
3727 | 3349 | |
---|
3728 | | - if (strcmp(field->type, hist_field->type) != 0) |
---|
3729 | | - return -EINVAL; |
---|
| 3350 | + /* |
---|
| 3351 | + * A dynamic string synth field can accept static or |
---|
| 3352 | + * dynamic. A static string synth field can only accept a |
---|
| 3353 | + * same-sized static string, which is checked for later. |
---|
| 3354 | + */ |
---|
| 3355 | + if (strstr(hist_field->type, "char[") && field->is_string |
---|
| 3356 | + && field->is_dynamic) |
---|
| 3357 | + return 0; |
---|
| 3358 | + |
---|
| 3359 | + if (strcmp(field->type, hist_field->type) != 0) { |
---|
| 3360 | + if (field->size != hist_field->size || |
---|
| 3361 | + (!field->is_string && field->is_signed != hist_field->is_signed)) |
---|
| 3362 | + return -EINVAL; |
---|
| 3363 | + } |
---|
3730 | 3364 | |
---|
3731 | 3365 | return 0; |
---|
3732 | 3366 | } |
---|
3733 | 3367 | |
---|
3734 | 3368 | static struct hist_field * |
---|
3735 | | -onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data, |
---|
3736 | | - char *system, char *event, char *var) |
---|
| 3369 | +trace_action_find_var(struct hist_trigger_data *hist_data, |
---|
| 3370 | + struct action_data *data, |
---|
| 3371 | + char *system, char *event, char *var) |
---|
3737 | 3372 | { |
---|
| 3373 | + struct trace_array *tr = hist_data->event_file->tr; |
---|
3738 | 3374 | struct hist_field *hist_field; |
---|
3739 | 3375 | |
---|
3740 | 3376 | var++; /* skip '$' */ |
---|
3741 | 3377 | |
---|
3742 | 3378 | hist_field = find_target_event_var(hist_data, system, event, var); |
---|
3743 | 3379 | if (!hist_field) { |
---|
3744 | | - if (!system) { |
---|
3745 | | - system = data->onmatch.match_event_system; |
---|
3746 | | - event = data->onmatch.match_event; |
---|
| 3380 | + if (!system && data->handler == HANDLER_ONMATCH) { |
---|
| 3381 | + system = data->match_data.event_system; |
---|
| 3382 | + event = data->match_data.event; |
---|
3747 | 3383 | } |
---|
3748 | 3384 | |
---|
3749 | 3385 | hist_field = find_event_var(hist_data, system, event, var); |
---|
3750 | 3386 | } |
---|
3751 | 3387 | |
---|
3752 | 3388 | if (!hist_field) |
---|
3753 | | - hist_err_event("onmatch: Couldn't find onmatch param: $", system, event, var); |
---|
| 3389 | + hist_err(tr, HIST_ERR_PARAM_NOT_FOUND, errpos(var)); |
---|
3754 | 3390 | |
---|
3755 | 3391 | return hist_field; |
---|
3756 | 3392 | } |
---|
3757 | 3393 | |
---|
3758 | 3394 | static struct hist_field * |
---|
3759 | | -onmatch_create_field_var(struct hist_trigger_data *hist_data, |
---|
3760 | | - struct action_data *data, char *system, |
---|
3761 | | - char *event, char *var) |
---|
| 3395 | +trace_action_create_field_var(struct hist_trigger_data *hist_data, |
---|
| 3396 | + struct action_data *data, char *system, |
---|
| 3397 | + char *event, char *var) |
---|
3762 | 3398 | { |
---|
3763 | 3399 | struct hist_field *hist_field = NULL; |
---|
3764 | 3400 | struct field_var *field_var; |
---|
.. | .. |
---|
3781 | 3417 | * looking for fields on the onmatch(system.event.xxx) |
---|
3782 | 3418 | * event. |
---|
3783 | 3419 | */ |
---|
3784 | | - if (!system) { |
---|
3785 | | - system = data->onmatch.match_event_system; |
---|
3786 | | - event = data->onmatch.match_event; |
---|
| 3420 | + if (!system && data->handler == HANDLER_ONMATCH) { |
---|
| 3421 | + system = data->match_data.event_system; |
---|
| 3422 | + event = data->match_data.event; |
---|
3787 | 3423 | } |
---|
3788 | 3424 | |
---|
3789 | 3425 | if (!event) |
---|
.. | .. |
---|
3807 | 3443 | goto out; |
---|
3808 | 3444 | } |
---|
3809 | 3445 | |
---|
3810 | | -static int onmatch_create(struct hist_trigger_data *hist_data, |
---|
3811 | | - struct trace_event_file *file, |
---|
3812 | | - struct action_data *data) |
---|
| 3446 | +static int trace_action_create(struct hist_trigger_data *hist_data, |
---|
| 3447 | + struct action_data *data) |
---|
3813 | 3448 | { |
---|
| 3449 | + struct trace_array *tr = hist_data->event_file->tr; |
---|
3814 | 3450 | char *event_name, *param, *system = NULL; |
---|
3815 | 3451 | struct hist_field *hist_field, *var_ref; |
---|
3816 | | - unsigned int i, var_ref_idx; |
---|
| 3452 | + unsigned int i; |
---|
3817 | 3453 | unsigned int field_pos = 0; |
---|
3818 | 3454 | struct synth_event *event; |
---|
3819 | | - int ret = 0; |
---|
| 3455 | + char *synth_event_name; |
---|
| 3456 | + int var_ref_idx, ret = 0; |
---|
3820 | 3457 | |
---|
3821 | | - mutex_lock(&synth_event_mutex); |
---|
3822 | | - event = find_synth_event(data->onmatch.synth_event_name); |
---|
| 3458 | + lockdep_assert_held(&event_mutex); |
---|
| 3459 | + |
---|
| 3460 | + /* Sanity check to avoid out-of-bound write on 'data->var_ref_idx' */ |
---|
| 3461 | + if (data->n_params > SYNTH_FIELDS_MAX) |
---|
| 3462 | + return -EINVAL; |
---|
| 3463 | + |
---|
| 3464 | + if (data->use_trace_keyword) |
---|
| 3465 | + synth_event_name = data->synth_event_name; |
---|
| 3466 | + else |
---|
| 3467 | + synth_event_name = data->action_name; |
---|
| 3468 | + |
---|
| 3469 | + event = find_synth_event(synth_event_name); |
---|
3823 | 3470 | if (!event) { |
---|
3824 | | - hist_err("onmatch: Couldn't find synthetic event: ", data->onmatch.synth_event_name); |
---|
3825 | | - mutex_unlock(&synth_event_mutex); |
---|
| 3471 | + hist_err(tr, HIST_ERR_SYNTH_EVENT_NOT_FOUND, errpos(synth_event_name)); |
---|
3826 | 3472 | return -EINVAL; |
---|
3827 | 3473 | } |
---|
3828 | | - event->ref++; |
---|
3829 | | - mutex_unlock(&synth_event_mutex); |
---|
3830 | 3474 | |
---|
3831 | | - var_ref_idx = hist_data->n_var_refs; |
---|
| 3475 | + event->ref++; |
---|
3832 | 3476 | |
---|
3833 | 3477 | for (i = 0; i < data->n_params; i++) { |
---|
3834 | 3478 | char *p; |
---|
.. | .. |
---|
3853 | 3497 | } |
---|
3854 | 3498 | |
---|
3855 | 3499 | if (param[0] == '$') |
---|
3856 | | - hist_field = onmatch_find_var(hist_data, data, system, |
---|
3857 | | - event_name, param); |
---|
| 3500 | + hist_field = trace_action_find_var(hist_data, data, |
---|
| 3501 | + system, event_name, |
---|
| 3502 | + param); |
---|
3858 | 3503 | else |
---|
3859 | | - hist_field = onmatch_create_field_var(hist_data, data, |
---|
3860 | | - system, |
---|
3861 | | - event_name, |
---|
3862 | | - param); |
---|
| 3504 | + hist_field = trace_action_create_field_var(hist_data, |
---|
| 3505 | + data, |
---|
| 3506 | + system, |
---|
| 3507 | + event_name, |
---|
| 3508 | + param); |
---|
3863 | 3509 | |
---|
3864 | 3510 | if (!hist_field) { |
---|
3865 | 3511 | kfree(p); |
---|
.. | .. |
---|
3876 | 3522 | goto err; |
---|
3877 | 3523 | } |
---|
3878 | 3524 | |
---|
3879 | | - save_synth_var_ref(hist_data, var_ref); |
---|
| 3525 | + var_ref_idx = find_var_ref_idx(hist_data, var_ref); |
---|
| 3526 | + if (WARN_ON(var_ref_idx < 0)) { |
---|
| 3527 | + kfree(p); |
---|
| 3528 | + ret = var_ref_idx; |
---|
| 3529 | + goto err; |
---|
| 3530 | + } |
---|
| 3531 | + |
---|
| 3532 | + data->var_ref_idx[i] = var_ref_idx; |
---|
| 3533 | + |
---|
3880 | 3534 | field_pos++; |
---|
3881 | 3535 | kfree(p); |
---|
3882 | 3536 | continue; |
---|
3883 | 3537 | } |
---|
3884 | 3538 | |
---|
3885 | | - hist_err_event("onmatch: Param type doesn't match synthetic event field type: ", |
---|
3886 | | - system, event_name, param); |
---|
| 3539 | + hist_err(tr, HIST_ERR_SYNTH_TYPE_MISMATCH, errpos(param)); |
---|
3887 | 3540 | kfree(p); |
---|
3888 | 3541 | ret = -EINVAL; |
---|
3889 | 3542 | goto err; |
---|
3890 | 3543 | } |
---|
3891 | 3544 | |
---|
3892 | 3545 | if (field_pos != event->n_fields) { |
---|
3893 | | - hist_err("onmatch: Param count doesn't match synthetic event field count: ", event->name); |
---|
| 3546 | + hist_err(tr, HIST_ERR_SYNTH_COUNT_MISMATCH, errpos(event->name)); |
---|
3894 | 3547 | ret = -EINVAL; |
---|
3895 | 3548 | goto err; |
---|
3896 | 3549 | } |
---|
3897 | 3550 | |
---|
3898 | | - data->fn = action_trace; |
---|
3899 | | - data->onmatch.synth_event = event; |
---|
3900 | | - data->onmatch.var_ref_idx = var_ref_idx; |
---|
| 3551 | + data->synth_event = event; |
---|
3901 | 3552 | out: |
---|
3902 | 3553 | return ret; |
---|
3903 | 3554 | err: |
---|
3904 | | - mutex_lock(&synth_event_mutex); |
---|
3905 | 3555 | event->ref--; |
---|
3906 | | - mutex_unlock(&synth_event_mutex); |
---|
3907 | 3556 | |
---|
3908 | 3557 | goto out; |
---|
| 3558 | +} |
---|
| 3559 | + |
---|
| 3560 | +static int action_create(struct hist_trigger_data *hist_data, |
---|
| 3561 | + struct action_data *data) |
---|
| 3562 | +{ |
---|
| 3563 | + struct trace_event_file *file = hist_data->event_file; |
---|
| 3564 | + struct trace_array *tr = file->tr; |
---|
| 3565 | + struct track_data *track_data; |
---|
| 3566 | + struct field_var *field_var; |
---|
| 3567 | + unsigned int i; |
---|
| 3568 | + char *param; |
---|
| 3569 | + int ret = 0; |
---|
| 3570 | + |
---|
| 3571 | + if (data->action == ACTION_TRACE) |
---|
| 3572 | + return trace_action_create(hist_data, data); |
---|
| 3573 | + |
---|
| 3574 | + if (data->action == ACTION_SNAPSHOT) { |
---|
| 3575 | + track_data = track_data_alloc(hist_data->key_size, data, hist_data); |
---|
| 3576 | + if (IS_ERR(track_data)) { |
---|
| 3577 | + ret = PTR_ERR(track_data); |
---|
| 3578 | + goto out; |
---|
| 3579 | + } |
---|
| 3580 | + |
---|
| 3581 | + ret = tracing_snapshot_cond_enable(file->tr, track_data, |
---|
| 3582 | + cond_snapshot_update); |
---|
| 3583 | + if (ret) |
---|
| 3584 | + track_data_free(track_data); |
---|
| 3585 | + |
---|
| 3586 | + goto out; |
---|
| 3587 | + } |
---|
| 3588 | + |
---|
| 3589 | + if (data->action == ACTION_SAVE) { |
---|
| 3590 | + if (hist_data->n_save_vars) { |
---|
| 3591 | + ret = -EEXIST; |
---|
| 3592 | + hist_err(tr, HIST_ERR_TOO_MANY_SAVE_ACTIONS, 0); |
---|
| 3593 | + goto out; |
---|
| 3594 | + } |
---|
| 3595 | + |
---|
| 3596 | + for (i = 0; i < data->n_params; i++) { |
---|
| 3597 | + param = kstrdup(data->params[i], GFP_KERNEL); |
---|
| 3598 | + if (!param) { |
---|
| 3599 | + ret = -ENOMEM; |
---|
| 3600 | + goto out; |
---|
| 3601 | + } |
---|
| 3602 | + |
---|
| 3603 | + field_var = create_target_field_var(hist_data, NULL, NULL, param); |
---|
| 3604 | + if (IS_ERR(field_var)) { |
---|
| 3605 | + hist_err(tr, HIST_ERR_FIELD_VAR_CREATE_FAIL, |
---|
| 3606 | + errpos(param)); |
---|
| 3607 | + ret = PTR_ERR(field_var); |
---|
| 3608 | + kfree(param); |
---|
| 3609 | + goto out; |
---|
| 3610 | + } |
---|
| 3611 | + |
---|
| 3612 | + hist_data->save_vars[hist_data->n_save_vars++] = field_var; |
---|
| 3613 | + if (field_var->val->flags & HIST_FIELD_FL_STRING) |
---|
| 3614 | + hist_data->n_save_var_str++; |
---|
| 3615 | + kfree(param); |
---|
| 3616 | + } |
---|
| 3617 | + } |
---|
| 3618 | + out: |
---|
| 3619 | + return ret; |
---|
| 3620 | +} |
---|
| 3621 | + |
---|
| 3622 | +static int onmatch_create(struct hist_trigger_data *hist_data, |
---|
| 3623 | + struct action_data *data) |
---|
| 3624 | +{ |
---|
| 3625 | + return action_create(hist_data, data); |
---|
3909 | 3626 | } |
---|
3910 | 3627 | |
---|
3911 | 3628 | static struct action_data *onmatch_parse(struct trace_array *tr, char *str) |
---|
3912 | 3629 | { |
---|
3913 | 3630 | char *match_event, *match_event_system; |
---|
3914 | | - char *synth_event_name, *params; |
---|
3915 | 3631 | struct action_data *data; |
---|
3916 | 3632 | int ret = -EINVAL; |
---|
3917 | 3633 | |
---|
.. | .. |
---|
3921 | 3637 | |
---|
3922 | 3638 | match_event = strsep(&str, ")"); |
---|
3923 | 3639 | if (!match_event || !str) { |
---|
3924 | | - hist_err("onmatch: Missing closing paren: ", match_event); |
---|
| 3640 | + hist_err(tr, HIST_ERR_NO_CLOSING_PAREN, errpos(match_event)); |
---|
3925 | 3641 | goto free; |
---|
3926 | 3642 | } |
---|
3927 | 3643 | |
---|
3928 | 3644 | match_event_system = strsep(&match_event, "."); |
---|
3929 | 3645 | if (!match_event) { |
---|
3930 | | - hist_err("onmatch: Missing subsystem for match event: ", match_event_system); |
---|
| 3646 | + hist_err(tr, HIST_ERR_SUBSYS_NOT_FOUND, errpos(match_event_system)); |
---|
3931 | 3647 | goto free; |
---|
3932 | 3648 | } |
---|
3933 | 3649 | |
---|
3934 | 3650 | if (IS_ERR(event_file(tr, match_event_system, match_event))) { |
---|
3935 | | - hist_err_event("onmatch: Invalid subsystem or event name: ", |
---|
3936 | | - match_event_system, match_event, NULL); |
---|
| 3651 | + hist_err(tr, HIST_ERR_INVALID_SUBSYS_EVENT, errpos(match_event)); |
---|
3937 | 3652 | goto free; |
---|
3938 | 3653 | } |
---|
3939 | 3654 | |
---|
3940 | | - data->onmatch.match_event = kstrdup(match_event, GFP_KERNEL); |
---|
3941 | | - if (!data->onmatch.match_event) { |
---|
| 3655 | + data->match_data.event = kstrdup(match_event, GFP_KERNEL); |
---|
| 3656 | + if (!data->match_data.event) { |
---|
3942 | 3657 | ret = -ENOMEM; |
---|
3943 | 3658 | goto free; |
---|
3944 | 3659 | } |
---|
3945 | 3660 | |
---|
3946 | | - data->onmatch.match_event_system = kstrdup(match_event_system, GFP_KERNEL); |
---|
3947 | | - if (!data->onmatch.match_event_system) { |
---|
| 3661 | + data->match_data.event_system = kstrdup(match_event_system, GFP_KERNEL); |
---|
| 3662 | + if (!data->match_data.event_system) { |
---|
3948 | 3663 | ret = -ENOMEM; |
---|
3949 | 3664 | goto free; |
---|
3950 | 3665 | } |
---|
3951 | 3666 | |
---|
3952 | | - strsep(&str, "."); |
---|
3953 | | - if (!str) { |
---|
3954 | | - hist_err("onmatch: Missing . after onmatch(): ", str); |
---|
3955 | | - goto free; |
---|
3956 | | - } |
---|
3957 | | - |
---|
3958 | | - synth_event_name = strsep(&str, "("); |
---|
3959 | | - if (!synth_event_name || !str) { |
---|
3960 | | - hist_err("onmatch: Missing opening paramlist paren: ", synth_event_name); |
---|
3961 | | - goto free; |
---|
3962 | | - } |
---|
3963 | | - |
---|
3964 | | - data->onmatch.synth_event_name = kstrdup(synth_event_name, GFP_KERNEL); |
---|
3965 | | - if (!data->onmatch.synth_event_name) { |
---|
3966 | | - ret = -ENOMEM; |
---|
3967 | | - goto free; |
---|
3968 | | - } |
---|
3969 | | - |
---|
3970 | | - params = strsep(&str, ")"); |
---|
3971 | | - if (!params || !str || (str && strlen(str))) { |
---|
3972 | | - hist_err("onmatch: Missing closing paramlist paren: ", params); |
---|
3973 | | - goto free; |
---|
3974 | | - } |
---|
3975 | | - |
---|
3976 | | - ret = parse_action_params(params, data); |
---|
| 3667 | + ret = action_parse(tr, str, data, HANDLER_ONMATCH); |
---|
3977 | 3668 | if (ret) |
---|
3978 | 3669 | goto free; |
---|
3979 | 3670 | out: |
---|
.. | .. |
---|
4042 | 3733 | struct trace_event_file *file, |
---|
4043 | 3734 | char *var_name, char *expr_str) |
---|
4044 | 3735 | { |
---|
| 3736 | + struct trace_array *tr = hist_data->event_file->tr; |
---|
4045 | 3737 | unsigned long flags = 0; |
---|
| 3738 | + int ret; |
---|
4046 | 3739 | |
---|
4047 | 3740 | if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX + TRACING_MAP_VARS_MAX)) |
---|
4048 | 3741 | return -EINVAL; |
---|
4049 | 3742 | |
---|
4050 | 3743 | if (find_var(hist_data, file, var_name) && !hist_data->remove) { |
---|
4051 | | - hist_err("Variable already defined: ", var_name); |
---|
| 3744 | + hist_err(tr, HIST_ERR_DUPLICATE_VAR, errpos(var_name)); |
---|
4052 | 3745 | return -EINVAL; |
---|
4053 | 3746 | } |
---|
4054 | 3747 | |
---|
.. | .. |
---|
4057 | 3750 | if (WARN_ON(hist_data->n_vars > TRACING_MAP_VARS_MAX)) |
---|
4058 | 3751 | return -EINVAL; |
---|
4059 | 3752 | |
---|
4060 | | - return __create_val_field(hist_data, val_idx, file, var_name, expr_str, flags); |
---|
| 3753 | + ret = __create_val_field(hist_data, val_idx, file, var_name, expr_str, flags); |
---|
| 3754 | + |
---|
| 3755 | + if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_STRING) |
---|
| 3756 | + hist_data->fields[val_idx]->var_str_idx = hist_data->n_var_str++; |
---|
| 3757 | + |
---|
| 3758 | + return ret; |
---|
4061 | 3759 | } |
---|
4062 | 3760 | |
---|
4063 | 3761 | static int create_val_fields(struct hist_trigger_data *hist_data, |
---|
.. | .. |
---|
4072 | 3770 | goto out; |
---|
4073 | 3771 | |
---|
4074 | 3772 | fields_str = hist_data->attrs->vals_str; |
---|
4075 | | - if (!fields_str) |
---|
4076 | | - goto out; |
---|
4077 | | - |
---|
4078 | | - strsep(&fields_str, "="); |
---|
4079 | 3773 | if (!fields_str) |
---|
4080 | 3774 | goto out; |
---|
4081 | 3775 | |
---|
.. | .. |
---|
4105 | 3799 | struct trace_event_file *file, |
---|
4106 | 3800 | char *field_str) |
---|
4107 | 3801 | { |
---|
| 3802 | + struct trace_array *tr = hist_data->event_file->tr; |
---|
4108 | 3803 | struct hist_field *hist_field = NULL; |
---|
4109 | | - |
---|
4110 | 3804 | unsigned long flags = 0; |
---|
4111 | 3805 | unsigned int key_size; |
---|
4112 | 3806 | int ret = 0; |
---|
.. | .. |
---|
4128 | 3822 | goto out; |
---|
4129 | 3823 | } |
---|
4130 | 3824 | |
---|
4131 | | - if (hist_field->flags & HIST_FIELD_FL_VAR_REF) { |
---|
4132 | | - hist_err("Using variable references as keys not supported: ", field_str); |
---|
| 3825 | + if (field_has_hist_vars(hist_field, 0)) { |
---|
| 3826 | + hist_err(tr, HIST_ERR_INVALID_REF_KEY, errpos(field_str)); |
---|
4133 | 3827 | destroy_hist_field(hist_field, 0); |
---|
4134 | 3828 | ret = -EINVAL; |
---|
4135 | 3829 | goto out; |
---|
.. | .. |
---|
4170 | 3864 | int ret = -EINVAL; |
---|
4171 | 3865 | |
---|
4172 | 3866 | fields_str = hist_data->attrs->keys_str; |
---|
4173 | | - if (!fields_str) |
---|
4174 | | - goto out; |
---|
4175 | | - |
---|
4176 | | - strsep(&fields_str, "="); |
---|
4177 | 3867 | if (!fields_str) |
---|
4178 | 3868 | goto out; |
---|
4179 | 3869 | |
---|
.. | .. |
---|
4230 | 3920 | |
---|
4231 | 3921 | static int parse_var_defs(struct hist_trigger_data *hist_data) |
---|
4232 | 3922 | { |
---|
| 3923 | + struct trace_array *tr = hist_data->event_file->tr; |
---|
4233 | 3924 | char *s, *str, *var_name, *field_str; |
---|
4234 | 3925 | unsigned int i, j, n_vars = 0; |
---|
4235 | 3926 | int ret = 0; |
---|
.. | .. |
---|
4243 | 3934 | |
---|
4244 | 3935 | var_name = strsep(&field_str, "="); |
---|
4245 | 3936 | if (!var_name || !field_str) { |
---|
4246 | | - hist_err("Malformed assignment: ", var_name); |
---|
| 3937 | + hist_err(tr, HIST_ERR_MALFORMED_ASSIGNMENT, |
---|
| 3938 | + errpos(var_name)); |
---|
4247 | 3939 | ret = -EINVAL; |
---|
4248 | 3940 | goto free; |
---|
4249 | 3941 | } |
---|
4250 | 3942 | |
---|
4251 | 3943 | if (n_vars == TRACING_MAP_VARS_MAX) { |
---|
4252 | | - hist_err("Too many variables defined: ", var_name); |
---|
| 3944 | + hist_err(tr, HIST_ERR_TOO_MANY_VARS, errpos(var_name)); |
---|
4253 | 3945 | ret = -EINVAL; |
---|
4254 | 3946 | goto free; |
---|
4255 | 3947 | } |
---|
.. | .. |
---|
4263 | 3955 | |
---|
4264 | 3956 | s = kstrdup(field_str, GFP_KERNEL); |
---|
4265 | 3957 | if (!s) { |
---|
| 3958 | + kfree(hist_data->attrs->var_defs.name[n_vars]); |
---|
| 3959 | + hist_data->attrs->var_defs.name[n_vars] = NULL; |
---|
4266 | 3960 | ret = -ENOMEM; |
---|
4267 | 3961 | goto free; |
---|
4268 | 3962 | } |
---|
.. | .. |
---|
4305 | 3999 | return ret; |
---|
4306 | 4000 | } |
---|
4307 | 4001 | |
---|
4308 | | -static int is_descending(const char *str) |
---|
| 4002 | +static int is_descending(struct trace_array *tr, const char *str) |
---|
4309 | 4003 | { |
---|
4310 | 4004 | if (!str) |
---|
4311 | 4005 | return 0; |
---|
.. | .. |
---|
4316 | 4010 | if (strcmp(str, "ascending") == 0) |
---|
4317 | 4011 | return 0; |
---|
4318 | 4012 | |
---|
| 4013 | + hist_err(tr, HIST_ERR_INVALID_SORT_MODIFIER, errpos((char *)str)); |
---|
| 4014 | + |
---|
4319 | 4015 | return -EINVAL; |
---|
4320 | 4016 | } |
---|
4321 | 4017 | |
---|
4322 | 4018 | static int create_sort_keys(struct hist_trigger_data *hist_data) |
---|
4323 | 4019 | { |
---|
| 4020 | + struct trace_array *tr = hist_data->event_file->tr; |
---|
4324 | 4021 | char *fields_str = hist_data->attrs->sort_key_str; |
---|
4325 | 4022 | struct tracing_map_sort_key *sort_key; |
---|
4326 | 4023 | int descending, ret = 0; |
---|
.. | .. |
---|
4331 | 4028 | if (!fields_str) |
---|
4332 | 4029 | goto out; |
---|
4333 | 4030 | |
---|
4334 | | - strsep(&fields_str, "="); |
---|
4335 | | - if (!fields_str) { |
---|
4336 | | - ret = -EINVAL; |
---|
4337 | | - goto out; |
---|
4338 | | - } |
---|
4339 | | - |
---|
4340 | 4031 | for (i = 0; i < TRACING_MAP_SORT_KEYS_MAX; i++) { |
---|
4341 | 4032 | struct hist_field *hist_field; |
---|
4342 | 4033 | char *field_str, *field_name; |
---|
.. | .. |
---|
4345 | 4036 | sort_key = &hist_data->sort_keys[i]; |
---|
4346 | 4037 | |
---|
4347 | 4038 | field_str = strsep(&fields_str, ","); |
---|
4348 | | - if (!field_str) { |
---|
4349 | | - if (i == 0) |
---|
4350 | | - ret = -EINVAL; |
---|
| 4039 | + if (!field_str) |
---|
| 4040 | + break; |
---|
| 4041 | + |
---|
| 4042 | + if (!*field_str) { |
---|
| 4043 | + ret = -EINVAL; |
---|
| 4044 | + hist_err(tr, HIST_ERR_EMPTY_SORT_FIELD, errpos("sort=")); |
---|
4351 | 4045 | break; |
---|
4352 | 4046 | } |
---|
4353 | 4047 | |
---|
4354 | 4048 | if ((i == TRACING_MAP_SORT_KEYS_MAX - 1) && fields_str) { |
---|
| 4049 | + hist_err(tr, HIST_ERR_TOO_MANY_SORT_FIELDS, errpos("sort=")); |
---|
4355 | 4050 | ret = -EINVAL; |
---|
4356 | 4051 | break; |
---|
4357 | 4052 | } |
---|
4358 | 4053 | |
---|
4359 | 4054 | field_name = strsep(&field_str, "."); |
---|
4360 | | - if (!field_name) { |
---|
| 4055 | + if (!field_name || !*field_name) { |
---|
4361 | 4056 | ret = -EINVAL; |
---|
| 4057 | + hist_err(tr, HIST_ERR_EMPTY_SORT_FIELD, errpos("sort=")); |
---|
4362 | 4058 | break; |
---|
4363 | 4059 | } |
---|
4364 | 4060 | |
---|
4365 | 4061 | if (strcmp(field_name, "hitcount") == 0) { |
---|
4366 | | - descending = is_descending(field_str); |
---|
| 4062 | + descending = is_descending(tr, field_str); |
---|
4367 | 4063 | if (descending < 0) { |
---|
4368 | 4064 | ret = descending; |
---|
4369 | 4065 | break; |
---|
.. | .. |
---|
4385 | 4081 | |
---|
4386 | 4082 | if (strcmp(field_name, test_name) == 0) { |
---|
4387 | 4083 | sort_key->field_idx = idx; |
---|
4388 | | - descending = is_descending(field_str); |
---|
| 4084 | + descending = is_descending(tr, field_str); |
---|
4389 | 4085 | if (descending < 0) { |
---|
4390 | 4086 | ret = descending; |
---|
4391 | 4087 | goto out; |
---|
.. | .. |
---|
4396 | 4092 | } |
---|
4397 | 4093 | if (j == hist_data->n_fields) { |
---|
4398 | 4094 | ret = -EINVAL; |
---|
| 4095 | + hist_err(tr, HIST_ERR_INVALID_SORT_FIELD, errpos(field_name)); |
---|
4399 | 4096 | break; |
---|
4400 | 4097 | } |
---|
4401 | 4098 | } |
---|
.. | .. |
---|
4412 | 4109 | for (i = 0; i < hist_data->n_actions; i++) { |
---|
4413 | 4110 | struct action_data *data = hist_data->actions[i]; |
---|
4414 | 4111 | |
---|
4415 | | - if (data->fn == action_trace) |
---|
| 4112 | + if (data->handler == HANDLER_ONMATCH) |
---|
4416 | 4113 | onmatch_destroy(data); |
---|
4417 | | - else if (data->fn == onmax_save) |
---|
4418 | | - onmax_destroy(data); |
---|
| 4114 | + else if (data->handler == HANDLER_ONMAX || |
---|
| 4115 | + data->handler == HANDLER_ONCHANGE) |
---|
| 4116 | + track_data_destroy(hist_data, data); |
---|
4419 | 4117 | else |
---|
4420 | 4118 | kfree(data); |
---|
4421 | 4119 | } |
---|
.. | .. |
---|
4428 | 4126 | unsigned int i; |
---|
4429 | 4127 | int ret = 0; |
---|
4430 | 4128 | char *str; |
---|
| 4129 | + int len; |
---|
4431 | 4130 | |
---|
4432 | 4131 | for (i = 0; i < hist_data->attrs->n_actions; i++) { |
---|
4433 | 4132 | str = hist_data->attrs->action_str[i]; |
---|
4434 | 4133 | |
---|
4435 | | - if (strncmp(str, "onmatch(", strlen("onmatch(")) == 0) { |
---|
4436 | | - char *action_str = str + strlen("onmatch("); |
---|
| 4134 | + if ((len = str_has_prefix(str, "onmatch("))) { |
---|
| 4135 | + char *action_str = str + len; |
---|
4437 | 4136 | |
---|
4438 | 4137 | data = onmatch_parse(tr, action_str); |
---|
4439 | 4138 | if (IS_ERR(data)) { |
---|
4440 | 4139 | ret = PTR_ERR(data); |
---|
4441 | 4140 | break; |
---|
4442 | 4141 | } |
---|
4443 | | - data->fn = action_trace; |
---|
4444 | | - } else if (strncmp(str, "onmax(", strlen("onmax(")) == 0) { |
---|
4445 | | - char *action_str = str + strlen("onmax("); |
---|
| 4142 | + } else if ((len = str_has_prefix(str, "onmax("))) { |
---|
| 4143 | + char *action_str = str + len; |
---|
4446 | 4144 | |
---|
4447 | | - data = onmax_parse(action_str); |
---|
| 4145 | + data = track_data_parse(hist_data, action_str, |
---|
| 4146 | + HANDLER_ONMAX); |
---|
4448 | 4147 | if (IS_ERR(data)) { |
---|
4449 | 4148 | ret = PTR_ERR(data); |
---|
4450 | 4149 | break; |
---|
4451 | 4150 | } |
---|
4452 | | - data->fn = onmax_save; |
---|
| 4151 | + } else if ((len = str_has_prefix(str, "onchange("))) { |
---|
| 4152 | + char *action_str = str + len; |
---|
| 4153 | + |
---|
| 4154 | + data = track_data_parse(hist_data, action_str, |
---|
| 4155 | + HANDLER_ONCHANGE); |
---|
| 4156 | + if (IS_ERR(data)) { |
---|
| 4157 | + ret = PTR_ERR(data); |
---|
| 4158 | + break; |
---|
| 4159 | + } |
---|
4453 | 4160 | } else { |
---|
4454 | 4161 | ret = -EINVAL; |
---|
4455 | 4162 | break; |
---|
.. | .. |
---|
4461 | 4168 | return ret; |
---|
4462 | 4169 | } |
---|
4463 | 4170 | |
---|
4464 | | -static int create_actions(struct hist_trigger_data *hist_data, |
---|
4465 | | - struct trace_event_file *file) |
---|
| 4171 | +static int create_actions(struct hist_trigger_data *hist_data) |
---|
4466 | 4172 | { |
---|
4467 | 4173 | struct action_data *data; |
---|
4468 | 4174 | unsigned int i; |
---|
.. | .. |
---|
4471 | 4177 | for (i = 0; i < hist_data->attrs->n_actions; i++) { |
---|
4472 | 4178 | data = hist_data->actions[i]; |
---|
4473 | 4179 | |
---|
4474 | | - if (data->fn == action_trace) { |
---|
4475 | | - ret = onmatch_create(hist_data, file, data); |
---|
| 4180 | + if (data->handler == HANDLER_ONMATCH) { |
---|
| 4181 | + ret = onmatch_create(hist_data, data); |
---|
4476 | 4182 | if (ret) |
---|
4477 | | - return ret; |
---|
4478 | | - } else if (data->fn == onmax_save) { |
---|
4479 | | - ret = onmax_create(hist_data, data); |
---|
| 4183 | + break; |
---|
| 4184 | + } else if (data->handler == HANDLER_ONMAX || |
---|
| 4185 | + data->handler == HANDLER_ONCHANGE) { |
---|
| 4186 | + ret = track_data_create(hist_data, data); |
---|
4480 | 4187 | if (ret) |
---|
4481 | | - return ret; |
---|
| 4188 | + break; |
---|
| 4189 | + } else { |
---|
| 4190 | + ret = -EINVAL; |
---|
| 4191 | + break; |
---|
4482 | 4192 | } |
---|
4483 | 4193 | } |
---|
4484 | 4194 | |
---|
.. | .. |
---|
4494 | 4204 | for (i = 0; i < hist_data->n_actions; i++) { |
---|
4495 | 4205 | struct action_data *data = hist_data->actions[i]; |
---|
4496 | 4206 | |
---|
4497 | | - if (data->fn == onmax_save) |
---|
4498 | | - onmax_print(m, hist_data, elt, data); |
---|
| 4207 | + if (data->action == ACTION_SNAPSHOT) |
---|
| 4208 | + continue; |
---|
| 4209 | + |
---|
| 4210 | + if (data->handler == HANDLER_ONMAX || |
---|
| 4211 | + data->handler == HANDLER_ONCHANGE) |
---|
| 4212 | + track_data_print(m, hist_data, elt, data); |
---|
4499 | 4213 | } |
---|
4500 | 4214 | } |
---|
4501 | 4215 | |
---|
4502 | | -static void print_onmax_spec(struct seq_file *m, |
---|
4503 | | - struct hist_trigger_data *hist_data, |
---|
4504 | | - struct action_data *data) |
---|
| 4216 | +static void print_action_spec(struct seq_file *m, |
---|
| 4217 | + struct hist_trigger_data *hist_data, |
---|
| 4218 | + struct action_data *data) |
---|
4505 | 4219 | { |
---|
4506 | 4220 | unsigned int i; |
---|
4507 | 4221 | |
---|
4508 | | - seq_puts(m, ":onmax("); |
---|
4509 | | - seq_printf(m, "%s", data->onmax.var_str); |
---|
4510 | | - seq_printf(m, ").%s(", data->onmax.fn_name); |
---|
4511 | | - |
---|
4512 | | - for (i = 0; i < hist_data->n_max_vars; i++) { |
---|
4513 | | - seq_printf(m, "%s", hist_data->max_vars[i]->var->var.name); |
---|
4514 | | - if (i < hist_data->n_max_vars - 1) |
---|
4515 | | - seq_puts(m, ","); |
---|
| 4222 | + if (data->action == ACTION_SAVE) { |
---|
| 4223 | + for (i = 0; i < hist_data->n_save_vars; i++) { |
---|
| 4224 | + seq_printf(m, "%s", hist_data->save_vars[i]->var->var.name); |
---|
| 4225 | + if (i < hist_data->n_save_vars - 1) |
---|
| 4226 | + seq_puts(m, ","); |
---|
| 4227 | + } |
---|
| 4228 | + } else if (data->action == ACTION_TRACE) { |
---|
| 4229 | + if (data->use_trace_keyword) |
---|
| 4230 | + seq_printf(m, "%s", data->synth_event_name); |
---|
| 4231 | + for (i = 0; i < data->n_params; i++) { |
---|
| 4232 | + if (i || data->use_trace_keyword) |
---|
| 4233 | + seq_puts(m, ","); |
---|
| 4234 | + seq_printf(m, "%s", data->params[i]); |
---|
| 4235 | + } |
---|
4516 | 4236 | } |
---|
| 4237 | +} |
---|
| 4238 | + |
---|
| 4239 | +static void print_track_data_spec(struct seq_file *m, |
---|
| 4240 | + struct hist_trigger_data *hist_data, |
---|
| 4241 | + struct action_data *data) |
---|
| 4242 | +{ |
---|
| 4243 | + if (data->handler == HANDLER_ONMAX) |
---|
| 4244 | + seq_puts(m, ":onmax("); |
---|
| 4245 | + else if (data->handler == HANDLER_ONCHANGE) |
---|
| 4246 | + seq_puts(m, ":onchange("); |
---|
| 4247 | + seq_printf(m, "%s", data->track_data.var_str); |
---|
| 4248 | + seq_printf(m, ").%s(", data->action_name); |
---|
| 4249 | + |
---|
| 4250 | + print_action_spec(m, hist_data, data); |
---|
| 4251 | + |
---|
4517 | 4252 | seq_puts(m, ")"); |
---|
4518 | 4253 | } |
---|
4519 | 4254 | |
---|
.. | .. |
---|
4521 | 4256 | struct hist_trigger_data *hist_data, |
---|
4522 | 4257 | struct action_data *data) |
---|
4523 | 4258 | { |
---|
4524 | | - unsigned int i; |
---|
| 4259 | + seq_printf(m, ":onmatch(%s.%s).", data->match_data.event_system, |
---|
| 4260 | + data->match_data.event); |
---|
4525 | 4261 | |
---|
4526 | | - seq_printf(m, ":onmatch(%s.%s).", data->onmatch.match_event_system, |
---|
4527 | | - data->onmatch.match_event); |
---|
| 4262 | + seq_printf(m, "%s(", data->action_name); |
---|
4528 | 4263 | |
---|
4529 | | - seq_printf(m, "%s(", data->onmatch.synth_event->name); |
---|
4530 | | - |
---|
4531 | | - for (i = 0; i < data->n_params; i++) { |
---|
4532 | | - if (i) |
---|
4533 | | - seq_puts(m, ","); |
---|
4534 | | - seq_printf(m, "%s", data->params[i]); |
---|
4535 | | - } |
---|
| 4264 | + print_action_spec(m, hist_data, data); |
---|
4536 | 4265 | |
---|
4537 | 4266 | seq_puts(m, ")"); |
---|
4538 | 4267 | } |
---|
.. | .. |
---|
4548 | 4277 | for (i = 0; i < hist_data->n_actions; i++) { |
---|
4549 | 4278 | struct action_data *data = hist_data->actions[i]; |
---|
4550 | 4279 | struct action_data *data_test = hist_data_test->actions[i]; |
---|
| 4280 | + char *action_name, *action_name_test; |
---|
4551 | 4281 | |
---|
4552 | | - if (data->fn != data_test->fn) |
---|
| 4282 | + if (data->handler != data_test->handler) |
---|
| 4283 | + return false; |
---|
| 4284 | + if (data->action != data_test->action) |
---|
4553 | 4285 | return false; |
---|
4554 | 4286 | |
---|
4555 | 4287 | if (data->n_params != data_test->n_params) |
---|
.. | .. |
---|
4560 | 4292 | return false; |
---|
4561 | 4293 | } |
---|
4562 | 4294 | |
---|
4563 | | - if (data->fn == action_trace) { |
---|
4564 | | - if (strcmp(data->onmatch.synth_event_name, |
---|
4565 | | - data_test->onmatch.synth_event_name) != 0) |
---|
| 4295 | + if (data->use_trace_keyword) |
---|
| 4296 | + action_name = data->synth_event_name; |
---|
| 4297 | + else |
---|
| 4298 | + action_name = data->action_name; |
---|
| 4299 | + |
---|
| 4300 | + if (data_test->use_trace_keyword) |
---|
| 4301 | + action_name_test = data_test->synth_event_name; |
---|
| 4302 | + else |
---|
| 4303 | + action_name_test = data_test->action_name; |
---|
| 4304 | + |
---|
| 4305 | + if (strcmp(action_name, action_name_test) != 0) |
---|
| 4306 | + return false; |
---|
| 4307 | + |
---|
| 4308 | + if (data->handler == HANDLER_ONMATCH) { |
---|
| 4309 | + if (strcmp(data->match_data.event_system, |
---|
| 4310 | + data_test->match_data.event_system) != 0) |
---|
4566 | 4311 | return false; |
---|
4567 | | - if (strcmp(data->onmatch.match_event_system, |
---|
4568 | | - data_test->onmatch.match_event_system) != 0) |
---|
| 4312 | + if (strcmp(data->match_data.event, |
---|
| 4313 | + data_test->match_data.event) != 0) |
---|
4569 | 4314 | return false; |
---|
4570 | | - if (strcmp(data->onmatch.match_event, |
---|
4571 | | - data_test->onmatch.match_event) != 0) |
---|
4572 | | - return false; |
---|
4573 | | - } else if (data->fn == onmax_save) { |
---|
4574 | | - if (strcmp(data->onmax.var_str, |
---|
4575 | | - data_test->onmax.var_str) != 0) |
---|
4576 | | - return false; |
---|
4577 | | - if (strcmp(data->onmax.fn_name, |
---|
4578 | | - data_test->onmax.fn_name) != 0) |
---|
| 4315 | + } else if (data->handler == HANDLER_ONMAX || |
---|
| 4316 | + data->handler == HANDLER_ONCHANGE) { |
---|
| 4317 | + if (strcmp(data->track_data.var_str, |
---|
| 4318 | + data_test->track_data.var_str) != 0) |
---|
4579 | 4319 | return false; |
---|
4580 | 4320 | } |
---|
4581 | 4321 | } |
---|
.. | .. |
---|
4592 | 4332 | for (i = 0; i < hist_data->n_actions; i++) { |
---|
4593 | 4333 | struct action_data *data = hist_data->actions[i]; |
---|
4594 | 4334 | |
---|
4595 | | - if (data->fn == action_trace) |
---|
| 4335 | + if (data->handler == HANDLER_ONMATCH) |
---|
4596 | 4336 | print_onmatch_spec(m, hist_data, data); |
---|
4597 | | - else if (data->fn == onmax_save) |
---|
4598 | | - print_onmax_spec(m, hist_data, data); |
---|
| 4337 | + else if (data->handler == HANDLER_ONMAX || |
---|
| 4338 | + data->handler == HANDLER_ONCHANGE) |
---|
| 4339 | + print_track_data_spec(m, hist_data, data); |
---|
4599 | 4340 | } |
---|
4600 | 4341 | } |
---|
4601 | 4342 | |
---|
.. | .. |
---|
4621 | 4362 | destroy_actions(hist_data); |
---|
4622 | 4363 | destroy_field_vars(hist_data); |
---|
4623 | 4364 | destroy_field_var_hists(hist_data); |
---|
4624 | | - destroy_synth_var_refs(hist_data); |
---|
4625 | 4365 | |
---|
4626 | 4366 | kfree(hist_data); |
---|
4627 | 4367 | } |
---|
.. | .. |
---|
4642 | 4382 | |
---|
4643 | 4383 | if (hist_field->flags & HIST_FIELD_FL_STACKTRACE) |
---|
4644 | 4384 | cmp_fn = tracing_map_cmp_none; |
---|
4645 | | - else if (!field) |
---|
| 4385 | + else if (!field || hist_field->flags & HIST_FIELD_FL_CPU) |
---|
4646 | 4386 | cmp_fn = tracing_map_cmp_num(hist_field->size, |
---|
4647 | 4387 | hist_field->is_signed); |
---|
4648 | 4388 | else if (is_string_field(field)) |
---|
.. | .. |
---|
4744 | 4484 | hist_val = hist_field->fn(hist_field, elt, rbe, rec); |
---|
4745 | 4485 | if (hist_field->flags & HIST_FIELD_FL_VAR) { |
---|
4746 | 4486 | var_idx = hist_field->var.idx; |
---|
| 4487 | + |
---|
| 4488 | + if (hist_field->flags & HIST_FIELD_FL_STRING) { |
---|
| 4489 | + unsigned int str_start, var_str_idx, idx; |
---|
| 4490 | + char *str, *val_str; |
---|
| 4491 | + unsigned int size; |
---|
| 4492 | + |
---|
| 4493 | + str_start = hist_data->n_field_var_str + |
---|
| 4494 | + hist_data->n_save_var_str; |
---|
| 4495 | + var_str_idx = hist_field->var_str_idx; |
---|
| 4496 | + idx = str_start + var_str_idx; |
---|
| 4497 | + |
---|
| 4498 | + str = elt_data->field_var_str[idx]; |
---|
| 4499 | + val_str = (char *)(uintptr_t)hist_val; |
---|
| 4500 | + |
---|
| 4501 | + size = min(hist_field->size, STR_VAR_LEN_MAX); |
---|
| 4502 | + strscpy(str, val_str, size); |
---|
| 4503 | + |
---|
| 4504 | + hist_val = (u64)(uintptr_t)str; |
---|
| 4505 | + } |
---|
4747 | 4506 | tracing_map_set_var(elt, var_idx, hist_val); |
---|
4748 | 4507 | continue; |
---|
4749 | 4508 | } |
---|
.. | .. |
---|
4788 | 4547 | static void |
---|
4789 | 4548 | hist_trigger_actions(struct hist_trigger_data *hist_data, |
---|
4790 | 4549 | struct tracing_map_elt *elt, void *rec, |
---|
4791 | | - struct ring_buffer_event *rbe, u64 *var_ref_vals) |
---|
| 4550 | + struct ring_buffer_event *rbe, void *key, |
---|
| 4551 | + u64 *var_ref_vals) |
---|
4792 | 4552 | { |
---|
4793 | 4553 | struct action_data *data; |
---|
4794 | 4554 | unsigned int i; |
---|
4795 | 4555 | |
---|
4796 | 4556 | for (i = 0; i < hist_data->n_actions; i++) { |
---|
4797 | 4557 | data = hist_data->actions[i]; |
---|
4798 | | - data->fn(hist_data, elt, rec, rbe, data, var_ref_vals); |
---|
| 4558 | + data->fn(hist_data, elt, rec, rbe, key, data, var_ref_vals); |
---|
4799 | 4559 | } |
---|
4800 | 4560 | } |
---|
4801 | 4561 | |
---|
.. | .. |
---|
4808 | 4568 | u64 var_ref_vals[TRACING_MAP_VARS_MAX]; |
---|
4809 | 4569 | char compound_key[HIST_KEY_SIZE_MAX]; |
---|
4810 | 4570 | struct tracing_map_elt *elt = NULL; |
---|
4811 | | - struct stack_trace stacktrace; |
---|
4812 | 4571 | struct hist_field *key_field; |
---|
4813 | 4572 | u64 field_contents; |
---|
4814 | 4573 | void *key = NULL; |
---|
.. | .. |
---|
4820 | 4579 | key_field = hist_data->fields[i]; |
---|
4821 | 4580 | |
---|
4822 | 4581 | if (key_field->flags & HIST_FIELD_FL_STACKTRACE) { |
---|
4823 | | - stacktrace.max_entries = HIST_STACKTRACE_DEPTH; |
---|
4824 | | - stacktrace.entries = entries; |
---|
4825 | | - stacktrace.nr_entries = 0; |
---|
4826 | | - stacktrace.skip = HIST_STACKTRACE_SKIP; |
---|
4827 | | - |
---|
4828 | | - memset(stacktrace.entries, 0, HIST_STACKTRACE_SIZE); |
---|
4829 | | - save_stack_trace(&stacktrace); |
---|
4830 | | - |
---|
| 4582 | + memset(entries, 0, HIST_STACKTRACE_SIZE); |
---|
| 4583 | + stack_trace_save(entries, HIST_STACKTRACE_DEPTH, |
---|
| 4584 | + HIST_STACKTRACE_SKIP); |
---|
4831 | 4585 | key = entries; |
---|
4832 | 4586 | } else { |
---|
4833 | 4587 | field_contents = key_field->fn(key_field, elt, rbe, rec); |
---|
.. | .. |
---|
4856 | 4610 | hist_trigger_elt_update(hist_data, elt, rec, rbe, var_ref_vals); |
---|
4857 | 4611 | |
---|
4858 | 4612 | if (resolve_var_refs(hist_data, key, var_ref_vals, true)) |
---|
4859 | | - hist_trigger_actions(hist_data, elt, rec, rbe, var_ref_vals); |
---|
| 4613 | + hist_trigger_actions(hist_data, elt, rec, rbe, key, var_ref_vals); |
---|
4860 | 4614 | } |
---|
4861 | 4615 | |
---|
4862 | 4616 | static void hist_trigger_stacktrace_print(struct seq_file *m, |
---|
.. | .. |
---|
4868 | 4622 | unsigned int i; |
---|
4869 | 4623 | |
---|
4870 | 4624 | for (i = 0; i < max_entries; i++) { |
---|
4871 | | - if (stacktrace_entries[i] == ULONG_MAX) |
---|
| 4625 | + if (!stacktrace_entries[i]) |
---|
4872 | 4626 | return; |
---|
4873 | 4627 | |
---|
4874 | 4628 | seq_printf(m, "%*c", 1 + spaces, ' '); |
---|
.. | .. |
---|
4877 | 4631 | } |
---|
4878 | 4632 | } |
---|
4879 | 4633 | |
---|
4880 | | -static void |
---|
4881 | | -hist_trigger_entry_print(struct seq_file *m, |
---|
4882 | | - struct hist_trigger_data *hist_data, void *key, |
---|
4883 | | - struct tracing_map_elt *elt) |
---|
| 4634 | +static void hist_trigger_print_key(struct seq_file *m, |
---|
| 4635 | + struct hist_trigger_data *hist_data, |
---|
| 4636 | + void *key, |
---|
| 4637 | + struct tracing_map_elt *elt) |
---|
4884 | 4638 | { |
---|
4885 | 4639 | struct hist_field *key_field; |
---|
4886 | 4640 | char str[KSYM_SYMBOL_LEN]; |
---|
.. | .. |
---|
4956 | 4710 | seq_puts(m, " "); |
---|
4957 | 4711 | |
---|
4958 | 4712 | seq_puts(m, "}"); |
---|
| 4713 | +} |
---|
| 4714 | + |
---|
| 4715 | +static void hist_trigger_entry_print(struct seq_file *m, |
---|
| 4716 | + struct hist_trigger_data *hist_data, |
---|
| 4717 | + void *key, |
---|
| 4718 | + struct tracing_map_elt *elt) |
---|
| 4719 | +{ |
---|
| 4720 | + const char *field_name; |
---|
| 4721 | + unsigned int i; |
---|
| 4722 | + |
---|
| 4723 | + hist_trigger_print_key(m, hist_data, key, elt); |
---|
4959 | 4724 | |
---|
4960 | 4725 | seq_printf(m, " hitcount: %10llu", |
---|
4961 | 4726 | tracing_map_read_sum(elt, HITCOUNT_IDX)); |
---|
.. | .. |
---|
5022 | 4787 | if (n_entries < 0) |
---|
5023 | 4788 | n_entries = 0; |
---|
5024 | 4789 | |
---|
| 4790 | + track_data_snapshot_print(m, hist_data); |
---|
| 4791 | + |
---|
5025 | 4792 | seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n", |
---|
5026 | 4793 | (u64)atomic64_read(&hist_data->map->hits), |
---|
5027 | 4794 | n_entries, (u64)atomic64_read(&hist_data->map->drops)); |
---|
.. | .. |
---|
5046 | 4813 | hist_trigger_show(m, data, n++); |
---|
5047 | 4814 | } |
---|
5048 | 4815 | |
---|
5049 | | - if (have_hist_err()) { |
---|
5050 | | - seq_printf(m, "\nERROR: %s\n", hist_err_str); |
---|
5051 | | - seq_printf(m, " Last command: %s\n", last_hist_cmd); |
---|
5052 | | - } |
---|
5053 | | - |
---|
5054 | 4816 | out_unlock: |
---|
5055 | 4817 | mutex_unlock(&event_mutex); |
---|
5056 | 4818 | |
---|
.. | .. |
---|
5059 | 4821 | |
---|
5060 | 4822 | static int event_hist_open(struct inode *inode, struct file *file) |
---|
5061 | 4823 | { |
---|
| 4824 | + int ret; |
---|
| 4825 | + |
---|
| 4826 | + ret = security_locked_down(LOCKDOWN_TRACEFS); |
---|
| 4827 | + if (ret) |
---|
| 4828 | + return ret; |
---|
| 4829 | + |
---|
5062 | 4830 | return single_open(file, hist_show, file); |
---|
5063 | 4831 | } |
---|
5064 | 4832 | |
---|
.. | .. |
---|
5068 | 4836 | .llseek = seq_lseek, |
---|
5069 | 4837 | .release = single_release, |
---|
5070 | 4838 | }; |
---|
| 4839 | + |
---|
| 4840 | +#ifdef CONFIG_HIST_TRIGGERS_DEBUG |
---|
| 4841 | +static void hist_field_debug_show_flags(struct seq_file *m, |
---|
| 4842 | + unsigned long flags) |
---|
| 4843 | +{ |
---|
| 4844 | + seq_puts(m, " flags:\n"); |
---|
| 4845 | + |
---|
| 4846 | + if (flags & HIST_FIELD_FL_KEY) |
---|
| 4847 | + seq_puts(m, " HIST_FIELD_FL_KEY\n"); |
---|
| 4848 | + else if (flags & HIST_FIELD_FL_HITCOUNT) |
---|
| 4849 | + seq_puts(m, " VAL: HIST_FIELD_FL_HITCOUNT\n"); |
---|
| 4850 | + else if (flags & HIST_FIELD_FL_VAR) |
---|
| 4851 | + seq_puts(m, " HIST_FIELD_FL_VAR\n"); |
---|
| 4852 | + else if (flags & HIST_FIELD_FL_VAR_REF) |
---|
| 4853 | + seq_puts(m, " HIST_FIELD_FL_VAR_REF\n"); |
---|
| 4854 | + else |
---|
| 4855 | + seq_puts(m, " VAL: normal u64 value\n"); |
---|
| 4856 | + |
---|
| 4857 | + if (flags & HIST_FIELD_FL_ALIAS) |
---|
| 4858 | + seq_puts(m, " HIST_FIELD_FL_ALIAS\n"); |
---|
| 4859 | +} |
---|
| 4860 | + |
---|
| 4861 | +static int hist_field_debug_show(struct seq_file *m, |
---|
| 4862 | + struct hist_field *field, unsigned long flags) |
---|
| 4863 | +{ |
---|
| 4864 | + if ((field->flags & flags) != flags) { |
---|
| 4865 | + seq_printf(m, "ERROR: bad flags - %lx\n", flags); |
---|
| 4866 | + return -EINVAL; |
---|
| 4867 | + } |
---|
| 4868 | + |
---|
| 4869 | + hist_field_debug_show_flags(m, field->flags); |
---|
| 4870 | + if (field->field) |
---|
| 4871 | + seq_printf(m, " ftrace_event_field name: %s\n", |
---|
| 4872 | + field->field->name); |
---|
| 4873 | + |
---|
| 4874 | + if (field->flags & HIST_FIELD_FL_VAR) { |
---|
| 4875 | + seq_printf(m, " var.name: %s\n", field->var.name); |
---|
| 4876 | + seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n", |
---|
| 4877 | + field->var.idx); |
---|
| 4878 | + } |
---|
| 4879 | + |
---|
| 4880 | + if (field->flags & HIST_FIELD_FL_ALIAS) |
---|
| 4881 | + seq_printf(m, " var_ref_idx (into hist_data->var_refs[]): %u\n", |
---|
| 4882 | + field->var_ref_idx); |
---|
| 4883 | + |
---|
| 4884 | + if (field->flags & HIST_FIELD_FL_VAR_REF) { |
---|
| 4885 | + seq_printf(m, " name: %s\n", field->name); |
---|
| 4886 | + seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n", |
---|
| 4887 | + field->var.idx); |
---|
| 4888 | + seq_printf(m, " var.hist_data: %p\n", field->var.hist_data); |
---|
| 4889 | + seq_printf(m, " var_ref_idx (into hist_data->var_refs[]): %u\n", |
---|
| 4890 | + field->var_ref_idx); |
---|
| 4891 | + if (field->system) |
---|
| 4892 | + seq_printf(m, " system: %s\n", field->system); |
---|
| 4893 | + if (field->event_name) |
---|
| 4894 | + seq_printf(m, " event_name: %s\n", field->event_name); |
---|
| 4895 | + } |
---|
| 4896 | + |
---|
| 4897 | + seq_printf(m, " type: %s\n", field->type); |
---|
| 4898 | + seq_printf(m, " size: %u\n", field->size); |
---|
| 4899 | + seq_printf(m, " is_signed: %u\n", field->is_signed); |
---|
| 4900 | + |
---|
| 4901 | + return 0; |
---|
| 4902 | +} |
---|
| 4903 | + |
---|
| 4904 | +static int field_var_debug_show(struct seq_file *m, |
---|
| 4905 | + struct field_var *field_var, unsigned int i, |
---|
| 4906 | + bool save_vars) |
---|
| 4907 | +{ |
---|
| 4908 | + const char *vars_name = save_vars ? "save_vars" : "field_vars"; |
---|
| 4909 | + struct hist_field *field; |
---|
| 4910 | + int ret = 0; |
---|
| 4911 | + |
---|
| 4912 | + seq_printf(m, "\n hist_data->%s[%d]:\n", vars_name, i); |
---|
| 4913 | + |
---|
| 4914 | + field = field_var->var; |
---|
| 4915 | + |
---|
| 4916 | + seq_printf(m, "\n %s[%d].var:\n", vars_name, i); |
---|
| 4917 | + |
---|
| 4918 | + hist_field_debug_show_flags(m, field->flags); |
---|
| 4919 | + seq_printf(m, " var.name: %s\n", field->var.name); |
---|
| 4920 | + seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n", |
---|
| 4921 | + field->var.idx); |
---|
| 4922 | + |
---|
| 4923 | + field = field_var->val; |
---|
| 4924 | + |
---|
| 4925 | + seq_printf(m, "\n %s[%d].val:\n", vars_name, i); |
---|
| 4926 | + if (field->field) |
---|
| 4927 | + seq_printf(m, " ftrace_event_field name: %s\n", |
---|
| 4928 | + field->field->name); |
---|
| 4929 | + else { |
---|
| 4930 | + ret = -EINVAL; |
---|
| 4931 | + goto out; |
---|
| 4932 | + } |
---|
| 4933 | + |
---|
| 4934 | + seq_printf(m, " type: %s\n", field->type); |
---|
| 4935 | + seq_printf(m, " size: %u\n", field->size); |
---|
| 4936 | + seq_printf(m, " is_signed: %u\n", field->is_signed); |
---|
| 4937 | +out: |
---|
| 4938 | + return ret; |
---|
| 4939 | +} |
---|
| 4940 | + |
---|
| 4941 | +static int hist_action_debug_show(struct seq_file *m, |
---|
| 4942 | + struct action_data *data, int i) |
---|
| 4943 | +{ |
---|
| 4944 | + int ret = 0; |
---|
| 4945 | + |
---|
| 4946 | + if (data->handler == HANDLER_ONMAX || |
---|
| 4947 | + data->handler == HANDLER_ONCHANGE) { |
---|
| 4948 | + seq_printf(m, "\n hist_data->actions[%d].track_data.var_ref:\n", i); |
---|
| 4949 | + ret = hist_field_debug_show(m, data->track_data.var_ref, |
---|
| 4950 | + HIST_FIELD_FL_VAR_REF); |
---|
| 4951 | + if (ret) |
---|
| 4952 | + goto out; |
---|
| 4953 | + |
---|
| 4954 | + seq_printf(m, "\n hist_data->actions[%d].track_data.track_var:\n", i); |
---|
| 4955 | + ret = hist_field_debug_show(m, data->track_data.track_var, |
---|
| 4956 | + HIST_FIELD_FL_VAR); |
---|
| 4957 | + if (ret) |
---|
| 4958 | + goto out; |
---|
| 4959 | + } |
---|
| 4960 | + |
---|
| 4961 | + if (data->handler == HANDLER_ONMATCH) { |
---|
| 4962 | + seq_printf(m, "\n hist_data->actions[%d].match_data.event_system: %s\n", |
---|
| 4963 | + i, data->match_data.event_system); |
---|
| 4964 | + seq_printf(m, " hist_data->actions[%d].match_data.event: %s\n", |
---|
| 4965 | + i, data->match_data.event); |
---|
| 4966 | + } |
---|
| 4967 | +out: |
---|
| 4968 | + return ret; |
---|
| 4969 | +} |
---|
| 4970 | + |
---|
| 4971 | +static int hist_actions_debug_show(struct seq_file *m, |
---|
| 4972 | + struct hist_trigger_data *hist_data) |
---|
| 4973 | +{ |
---|
| 4974 | + int i, ret = 0; |
---|
| 4975 | + |
---|
| 4976 | + if (hist_data->n_actions) |
---|
| 4977 | + seq_puts(m, "\n action tracking variables (for onmax()/onchange()/onmatch()):\n"); |
---|
| 4978 | + |
---|
| 4979 | + for (i = 0; i < hist_data->n_actions; i++) { |
---|
| 4980 | + struct action_data *action = hist_data->actions[i]; |
---|
| 4981 | + |
---|
| 4982 | + ret = hist_action_debug_show(m, action, i); |
---|
| 4983 | + if (ret) |
---|
| 4984 | + goto out; |
---|
| 4985 | + } |
---|
| 4986 | + |
---|
| 4987 | + if (hist_data->n_save_vars) |
---|
| 4988 | + seq_puts(m, "\n save action variables (save() params):\n"); |
---|
| 4989 | + |
---|
| 4990 | + for (i = 0; i < hist_data->n_save_vars; i++) { |
---|
| 4991 | + ret = field_var_debug_show(m, hist_data->save_vars[i], i, true); |
---|
| 4992 | + if (ret) |
---|
| 4993 | + goto out; |
---|
| 4994 | + } |
---|
| 4995 | +out: |
---|
| 4996 | + return ret; |
---|
| 4997 | +} |
---|
| 4998 | + |
---|
| 4999 | +static void hist_trigger_debug_show(struct seq_file *m, |
---|
| 5000 | + struct event_trigger_data *data, int n) |
---|
| 5001 | +{ |
---|
| 5002 | + struct hist_trigger_data *hist_data; |
---|
| 5003 | + int i, ret; |
---|
| 5004 | + |
---|
| 5005 | + if (n > 0) |
---|
| 5006 | + seq_puts(m, "\n\n"); |
---|
| 5007 | + |
---|
| 5008 | + seq_puts(m, "# event histogram\n#\n# trigger info: "); |
---|
| 5009 | + data->ops->print(m, data->ops, data); |
---|
| 5010 | + seq_puts(m, "#\n\n"); |
---|
| 5011 | + |
---|
| 5012 | + hist_data = data->private_data; |
---|
| 5013 | + |
---|
| 5014 | + seq_printf(m, "hist_data: %p\n\n", hist_data); |
---|
| 5015 | + seq_printf(m, " n_vals: %u\n", hist_data->n_vals); |
---|
| 5016 | + seq_printf(m, " n_keys: %u\n", hist_data->n_keys); |
---|
| 5017 | + seq_printf(m, " n_fields: %u\n", hist_data->n_fields); |
---|
| 5018 | + |
---|
| 5019 | + seq_puts(m, "\n val fields:\n\n"); |
---|
| 5020 | + |
---|
| 5021 | + seq_puts(m, " hist_data->fields[0]:\n"); |
---|
| 5022 | + ret = hist_field_debug_show(m, hist_data->fields[0], |
---|
| 5023 | + HIST_FIELD_FL_HITCOUNT); |
---|
| 5024 | + if (ret) |
---|
| 5025 | + return; |
---|
| 5026 | + |
---|
| 5027 | + for (i = 1; i < hist_data->n_vals; i++) { |
---|
| 5028 | + seq_printf(m, "\n hist_data->fields[%d]:\n", i); |
---|
| 5029 | + ret = hist_field_debug_show(m, hist_data->fields[i], 0); |
---|
| 5030 | + if (ret) |
---|
| 5031 | + return; |
---|
| 5032 | + } |
---|
| 5033 | + |
---|
| 5034 | + seq_puts(m, "\n key fields:\n"); |
---|
| 5035 | + |
---|
| 5036 | + for (i = hist_data->n_vals; i < hist_data->n_fields; i++) { |
---|
| 5037 | + seq_printf(m, "\n hist_data->fields[%d]:\n", i); |
---|
| 5038 | + ret = hist_field_debug_show(m, hist_data->fields[i], |
---|
| 5039 | + HIST_FIELD_FL_KEY); |
---|
| 5040 | + if (ret) |
---|
| 5041 | + return; |
---|
| 5042 | + } |
---|
| 5043 | + |
---|
| 5044 | + if (hist_data->n_var_refs) |
---|
| 5045 | + seq_puts(m, "\n variable reference fields:\n"); |
---|
| 5046 | + |
---|
| 5047 | + for (i = 0; i < hist_data->n_var_refs; i++) { |
---|
| 5048 | + seq_printf(m, "\n hist_data->var_refs[%d]:\n", i); |
---|
| 5049 | + ret = hist_field_debug_show(m, hist_data->var_refs[i], |
---|
| 5050 | + HIST_FIELD_FL_VAR_REF); |
---|
| 5051 | + if (ret) |
---|
| 5052 | + return; |
---|
| 5053 | + } |
---|
| 5054 | + |
---|
| 5055 | + if (hist_data->n_field_vars) |
---|
| 5056 | + seq_puts(m, "\n field variables:\n"); |
---|
| 5057 | + |
---|
| 5058 | + for (i = 0; i < hist_data->n_field_vars; i++) { |
---|
| 5059 | + ret = field_var_debug_show(m, hist_data->field_vars[i], i, false); |
---|
| 5060 | + if (ret) |
---|
| 5061 | + return; |
---|
| 5062 | + } |
---|
| 5063 | + |
---|
| 5064 | + ret = hist_actions_debug_show(m, hist_data); |
---|
| 5065 | + if (ret) |
---|
| 5066 | + return; |
---|
| 5067 | +} |
---|
| 5068 | + |
---|
| 5069 | +static int hist_debug_show(struct seq_file *m, void *v) |
---|
| 5070 | +{ |
---|
| 5071 | + struct event_trigger_data *data; |
---|
| 5072 | + struct trace_event_file *event_file; |
---|
| 5073 | + int n = 0, ret = 0; |
---|
| 5074 | + |
---|
| 5075 | + mutex_lock(&event_mutex); |
---|
| 5076 | + |
---|
| 5077 | + event_file = event_file_data(m->private); |
---|
| 5078 | + if (unlikely(!event_file)) { |
---|
| 5079 | + ret = -ENODEV; |
---|
| 5080 | + goto out_unlock; |
---|
| 5081 | + } |
---|
| 5082 | + |
---|
| 5083 | + list_for_each_entry(data, &event_file->triggers, list) { |
---|
| 5084 | + if (data->cmd_ops->trigger_type == ETT_EVENT_HIST) |
---|
| 5085 | + hist_trigger_debug_show(m, data, n++); |
---|
| 5086 | + } |
---|
| 5087 | + |
---|
| 5088 | + out_unlock: |
---|
| 5089 | + mutex_unlock(&event_mutex); |
---|
| 5090 | + |
---|
| 5091 | + return ret; |
---|
| 5092 | +} |
---|
| 5093 | + |
---|
| 5094 | +static int event_hist_debug_open(struct inode *inode, struct file *file) |
---|
| 5095 | +{ |
---|
| 5096 | + int ret; |
---|
| 5097 | + |
---|
| 5098 | + ret = security_locked_down(LOCKDOWN_TRACEFS); |
---|
| 5099 | + if (ret) |
---|
| 5100 | + return ret; |
---|
| 5101 | + |
---|
| 5102 | + return single_open(file, hist_debug_show, file); |
---|
| 5103 | +} |
---|
| 5104 | + |
---|
| 5105 | +const struct file_operations event_hist_debug_fops = { |
---|
| 5106 | + .open = event_hist_debug_open, |
---|
| 5107 | + .read = seq_read, |
---|
| 5108 | + .llseek = seq_lseek, |
---|
| 5109 | + .release = single_release, |
---|
| 5110 | +}; |
---|
| 5111 | +#endif |
---|
5071 | 5112 | |
---|
5072 | 5113 | static void hist_field_print(struct seq_file *m, struct hist_field *hist_field) |
---|
5073 | 5114 | { |
---|
.. | .. |
---|
5415 | 5456 | { |
---|
5416 | 5457 | struct hist_trigger_data *hist_data = data->private_data; |
---|
5417 | 5458 | struct event_trigger_data *test, *named_data = NULL; |
---|
| 5459 | + struct trace_array *tr = file->tr; |
---|
5418 | 5460 | int ret = 0; |
---|
5419 | 5461 | |
---|
5420 | 5462 | if (hist_data->attrs->name) { |
---|
.. | .. |
---|
5422 | 5464 | if (named_data) { |
---|
5423 | 5465 | if (!hist_trigger_match(data, named_data, named_data, |
---|
5424 | 5466 | true)) { |
---|
5425 | | - hist_err("Named hist trigger doesn't match existing named trigger (includes variables): ", hist_data->attrs->name); |
---|
| 5467 | + hist_err(tr, HIST_ERR_NAMED_MISMATCH, errpos(hist_data->attrs->name)); |
---|
5426 | 5468 | ret = -EINVAL; |
---|
5427 | 5469 | goto out; |
---|
5428 | 5470 | } |
---|
.. | .. |
---|
5445 | 5487 | else if (hist_data->attrs->clear) |
---|
5446 | 5488 | hist_clear(test); |
---|
5447 | 5489 | else { |
---|
5448 | | - hist_err("Hist trigger already exists", NULL); |
---|
| 5490 | + hist_err(tr, HIST_ERR_TRIGGER_EEXIST, 0); |
---|
5449 | 5491 | ret = -EEXIST; |
---|
5450 | 5492 | } |
---|
5451 | 5493 | goto out; |
---|
.. | .. |
---|
5453 | 5495 | } |
---|
5454 | 5496 | new: |
---|
5455 | 5497 | if (hist_data->attrs->cont || hist_data->attrs->clear) { |
---|
5456 | | - hist_err("Can't clear or continue a nonexistent hist trigger", NULL); |
---|
| 5498 | + hist_err(tr, HIST_ERR_TRIGGER_ENOENT_CLEAR, 0); |
---|
5457 | 5499 | ret = -ENOENT; |
---|
5458 | 5500 | goto out; |
---|
5459 | 5501 | } |
---|
.. | .. |
---|
5478 | 5520 | |
---|
5479 | 5521 | ret = tracing_set_clock(file->tr, hist_data->attrs->clock); |
---|
5480 | 5522 | if (ret) { |
---|
5481 | | - hist_err("Couldn't set trace_clock: ", clock); |
---|
| 5523 | + hist_err(tr, HIST_ERR_SET_CLOCK_FAIL, errpos(clock)); |
---|
5482 | 5524 | goto out; |
---|
5483 | 5525 | } |
---|
5484 | 5526 | |
---|
.. | .. |
---|
5619 | 5661 | struct synth_event *se; |
---|
5620 | 5662 | const char *se_name; |
---|
5621 | 5663 | |
---|
| 5664 | + lockdep_assert_held(&event_mutex); |
---|
| 5665 | + |
---|
5622 | 5666 | if (hist_file_check_refs(file)) |
---|
5623 | 5667 | return; |
---|
5624 | 5668 | |
---|
.. | .. |
---|
5628 | 5672 | list_del_rcu(&test->list); |
---|
5629 | 5673 | trace_event_trigger_enable_disable(file, 0); |
---|
5630 | 5674 | |
---|
5631 | | - mutex_lock(&synth_event_mutex); |
---|
5632 | 5675 | se_name = trace_event_name(file->event_call); |
---|
5633 | 5676 | se = find_synth_event(se_name); |
---|
5634 | 5677 | if (se) |
---|
5635 | 5678 | se->ref--; |
---|
5636 | | - mutex_unlock(&synth_event_mutex); |
---|
5637 | 5679 | |
---|
5638 | 5680 | update_cond_flag(file); |
---|
5639 | 5681 | if (hist_data->enable_timestamps) |
---|
.. | .. |
---|
5659 | 5701 | char *trigger, *p; |
---|
5660 | 5702 | int ret = 0; |
---|
5661 | 5703 | |
---|
| 5704 | + lockdep_assert_held(&event_mutex); |
---|
| 5705 | + |
---|
5662 | 5706 | if (glob && strlen(glob)) { |
---|
5663 | | - last_cmd_set(param); |
---|
5664 | 5707 | hist_err_clear(); |
---|
| 5708 | + last_cmd_set(file, param); |
---|
5665 | 5709 | } |
---|
5666 | 5710 | |
---|
5667 | 5711 | if (!param) |
---|
.. | .. |
---|
5685 | 5729 | p++; |
---|
5686 | 5730 | continue; |
---|
5687 | 5731 | } |
---|
5688 | | - if (p >= param + strlen(param) - strlen("if") - 1) |
---|
| 5732 | + if (p >= param + strlen(param) - (sizeof("if") - 1) - 1) |
---|
5689 | 5733 | return -EINVAL; |
---|
5690 | | - if (*(p + strlen("if")) != ' ' && *(p + strlen("if")) != '\t') { |
---|
| 5734 | + if (*(p + sizeof("if") - 1) != ' ' && *(p + sizeof("if") - 1) != '\t') { |
---|
5691 | 5735 | p++; |
---|
5692 | 5736 | continue; |
---|
5693 | 5737 | } |
---|
.. | .. |
---|
5702 | 5746 | trigger = strstrip(trigger); |
---|
5703 | 5747 | } |
---|
5704 | 5748 | |
---|
5705 | | - attrs = parse_hist_trigger_attrs(trigger); |
---|
| 5749 | + attrs = parse_hist_trigger_attrs(file->tr, trigger); |
---|
5706 | 5750 | if (IS_ERR(attrs)) |
---|
5707 | 5751 | return PTR_ERR(attrs); |
---|
5708 | 5752 | |
---|
.. | .. |
---|
5749 | 5793 | } |
---|
5750 | 5794 | |
---|
5751 | 5795 | cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file); |
---|
5752 | | - |
---|
5753 | | - mutex_lock(&synth_event_mutex); |
---|
5754 | 5796 | se_name = trace_event_name(file->event_call); |
---|
5755 | 5797 | se = find_synth_event(se_name); |
---|
5756 | 5798 | if (se) |
---|
5757 | 5799 | se->ref--; |
---|
5758 | | - mutex_unlock(&synth_event_mutex); |
---|
5759 | | - |
---|
5760 | 5800 | ret = 0; |
---|
5761 | 5801 | goto out_free; |
---|
5762 | 5802 | } |
---|
.. | .. |
---|
5777 | 5817 | if (get_named_trigger_data(trigger_data)) |
---|
5778 | 5818 | goto enable; |
---|
5779 | 5819 | |
---|
5780 | | - if (has_hist_vars(hist_data)) |
---|
5781 | | - save_hist_vars(hist_data); |
---|
5782 | | - |
---|
5783 | | - ret = create_actions(hist_data, file); |
---|
| 5820 | + ret = create_actions(hist_data); |
---|
5784 | 5821 | if (ret) |
---|
5785 | 5822 | goto out_unreg; |
---|
| 5823 | + |
---|
| 5824 | + if (has_hist_vars(hist_data) || hist_data->n_var_refs) { |
---|
| 5825 | + ret = save_hist_vars(hist_data); |
---|
| 5826 | + if (ret) |
---|
| 5827 | + goto out_unreg; |
---|
| 5828 | + } |
---|
5786 | 5829 | |
---|
5787 | 5830 | ret = tracing_map_init(hist_data->map); |
---|
5788 | 5831 | if (ret) |
---|
.. | .. |
---|
5792 | 5835 | if (ret) |
---|
5793 | 5836 | goto out_unreg; |
---|
5794 | 5837 | |
---|
5795 | | - mutex_lock(&synth_event_mutex); |
---|
5796 | 5838 | se_name = trace_event_name(file->event_call); |
---|
5797 | 5839 | se = find_synth_event(se_name); |
---|
5798 | 5840 | if (se) |
---|
5799 | 5841 | se->ref++; |
---|
5800 | | - mutex_unlock(&synth_event_mutex); |
---|
5801 | | - |
---|
5802 | 5842 | /* Just return zero, not the number of registered triggers */ |
---|
5803 | 5843 | ret = 0; |
---|
5804 | 5844 | out: |
---|
5805 | | - if (ret == 0) |
---|
| 5845 | + if (ret == 0 && glob[0]) |
---|
5806 | 5846 | hist_err_clear(); |
---|
5807 | 5847 | |
---|
5808 | 5848 | return ret; |
---|
.. | .. |
---|
5849 | 5889 | struct enable_trigger_data *enable_data = data->private_data; |
---|
5850 | 5890 | struct event_trigger_data *test; |
---|
5851 | 5891 | |
---|
5852 | | - list_for_each_entry_rcu(test, &enable_data->file->triggers, list) { |
---|
| 5892 | + list_for_each_entry_rcu(test, &enable_data->file->triggers, list, |
---|
| 5893 | + lockdep_is_held(&event_mutex)) { |
---|
5853 | 5894 | if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) { |
---|
5854 | 5895 | if (enable_data->enable) |
---|
5855 | 5896 | test->paused = false; |
---|
.. | .. |
---|
5974 | 6015 | |
---|
5975 | 6016 | return ret; |
---|
5976 | 6017 | } |
---|
5977 | | - |
---|
5978 | | -static __init int trace_events_hist_init(void) |
---|
5979 | | -{ |
---|
5980 | | - struct dentry *entry = NULL; |
---|
5981 | | - struct dentry *d_tracer; |
---|
5982 | | - int err = 0; |
---|
5983 | | - |
---|
5984 | | - d_tracer = tracing_init_dentry(); |
---|
5985 | | - if (IS_ERR(d_tracer)) { |
---|
5986 | | - err = PTR_ERR(d_tracer); |
---|
5987 | | - goto err; |
---|
5988 | | - } |
---|
5989 | | - |
---|
5990 | | - entry = tracefs_create_file("synthetic_events", 0644, d_tracer, |
---|
5991 | | - NULL, &synth_events_fops); |
---|
5992 | | - if (!entry) { |
---|
5993 | | - err = -ENODEV; |
---|
5994 | | - goto err; |
---|
5995 | | - } |
---|
5996 | | - |
---|
5997 | | - return err; |
---|
5998 | | - err: |
---|
5999 | | - pr_warn("Could not create tracefs 'synthetic_events' entry\n"); |
---|
6000 | | - |
---|
6001 | | - return err; |
---|
6002 | | -} |
---|
6003 | | - |
---|
6004 | | -fs_initcall(trace_events_hist_init); |
---|