blob: ada87bfb5bb85da4430ff6cb6d3ed295a8a1a084 [file] [log] [blame]
Steven Rostedt (VMware)bcea3f92018-08-16 11:23:53 -04001// SPDX-License-Identifier: GPL-2.0
Tom Zanussi7ef224d2016-03-03 12:54:42 -06002/*
3 * trace_events_hist - trace event hist triggers
4 *
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005 * Copyright (C) 2015 Tom Zanussi <tom.zanussi@linux.intel.com>
6 */
7
8#include <linux/module.h>
9#include <linux/kallsyms.h>
Steven Rostedt (VMware)17911ff2019-10-11 17:22:50 -040010#include <linux/security.h>
Tom Zanussi7ef224d2016-03-03 12:54:42 -060011#include <linux/mutex.h>
12#include <linux/slab.h>
13#include <linux/stacktrace.h>
Ingo Molnarb2d09102017-02-04 01:27:20 +010014#include <linux/rculist.h>
Tom Zanussi4b147932018-01-15 20:51:58 -060015#include <linux/tracefs.h>
Tom Zanussi7ef224d2016-03-03 12:54:42 -060016
Zhengjun Xingac681542019-07-12 09:53:08 +080017/* for gfp flag names */
18#include <linux/trace_events.h>
19#include <trace/events/mmflags.h>
20
Tom Zanussi7ef224d2016-03-03 12:54:42 -060021#include "tracing_map.h"
Tom Zanussi726721a2020-05-28 14:32:37 -050022#include "trace_synth.h"
Tom Zanussi4b147932018-01-15 20:51:58 -060023
Tom Zanussid566c5e2019-03-31 18:48:17 -050024#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"), \
Tom Zanussic8d94a12019-04-18 10:18:51 -050061 C(INVALID_REF_KEY, "Using variable references in keys not supported"), \
Tom Zanussid566c5e2019-03-31 18:48:17 -050062 C(VAR_NOT_FOUND, "Couldn't find variable"), \
Tom Zanussi4de26c82019-06-28 12:40:21 -050063 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)"), \
Masami Hiramatsua9d10ca2021-07-28 07:55:43 +090068 C(INVALID_SORT_FIELD, "Sort field must be a key or a val"), \
Kalesh Singh52cfb372021-10-25 13:08:33 -070069 C(INVALID_STR_OPERAND, "String type can not be an operand in expression"), \
Kalesh Singh9710b2f2021-10-25 13:08:35 -070070 C(EXPECT_NUMBER, "Expecting numeric literal"), \
Kalesh Singh8b5d46f2021-10-29 16:24:10 -070071 C(UNARY_MINUS_SUBEXPR, "Unary minus not supported in sub-expressions"), \
72 C(DIVISION_BY_ZERO, "Division by zero"),
Tom Zanussid566c5e2019-03-31 18:48:17 -050073
74#undef C
75#define C(a, b) HIST_ERR_##a
76
77enum { ERRORS };
78
79#undef C
80#define C(a, b) b
81
82static const char *err_text[] = { ERRORS };
83
Tom Zanussi7ef224d2016-03-03 12:54:42 -060084struct hist_field;
85
Tom Zanussidf35d932018-01-15 20:51:54 -060086typedef u64 (*hist_field_fn_t) (struct hist_field *field,
87 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -040088 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -060089 struct ring_buffer_event *rbe,
90 void *event);
Tom Zanussi7ef224d2016-03-03 12:54:42 -060091
Tom Zanussi5819ead2017-09-22 14:58:23 -050092#define HIST_FIELD_OPERANDS_MAX 2
Tom Zanussi30350d62018-01-15 20:51:49 -060093#define HIST_FIELDS_MAX (TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX)
Tom Zanussi0212e2a2018-01-15 20:51:57 -060094#define HIST_ACTIONS_MAX 8
Kalesh Singh52cfb372021-10-25 13:08:33 -070095#define HIST_CONST_DIGITS_MAX 21
Kalesh Singh8b5d46f2021-10-29 16:24:10 -070096#define HIST_DIV_SHIFT 20 /* For optimizing division by constants */
Tom Zanussi30350d62018-01-15 20:51:49 -060097
Tom Zanussi100719d2018-01-15 20:51:52 -060098enum field_op_id {
99 FIELD_OP_NONE,
100 FIELD_OP_PLUS,
101 FIELD_OP_MINUS,
102 FIELD_OP_UNARY_MINUS,
Kalesh Singhbcef0442021-10-25 13:08:34 -0700103 FIELD_OP_DIV,
104 FIELD_OP_MULT,
Tom Zanussi100719d2018-01-15 20:51:52 -0600105};
106
Tom Zanussi05ddb252018-12-18 14:33:26 -0600107/*
108 * A hist_var (histogram variable) contains variable information for
109 * hist_fields having the HIST_FIELD_FL_VAR or HIST_FIELD_FL_VAR_REF
110 * flag set. A hist_var has a variable name e.g. ts0, and is
111 * associated with a given histogram trigger, as specified by
112 * hist_data. The hist_var idx is the unique index assigned to the
113 * variable by the hist trigger's tracing_map. The idx is what is
114 * used to set a variable's value and, by a variable reference, to
115 * retrieve it.
116 */
Tom Zanussi30350d62018-01-15 20:51:49 -0600117struct hist_var {
118 char *name;
119 struct hist_trigger_data *hist_data;
120 unsigned int idx;
121};
Tom Zanussi5819ead2017-09-22 14:58:23 -0500122
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600123struct hist_field {
124 struct ftrace_event_field *field;
125 unsigned long flags;
126 hist_field_fn_t fn;
Steven Rostedt (VMware)8bcebc72020-01-20 13:07:31 -0500127 unsigned int ref;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600128 unsigned int size;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -0600129 unsigned int offset;
Tom Zanussi5819ead2017-09-22 14:58:23 -0500130 unsigned int is_signed;
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -0400131 unsigned long buckets;
Tom Zanussi19a9fac2018-01-15 20:51:55 -0600132 const char *type;
Tom Zanussi5819ead2017-09-22 14:58:23 -0500133 struct hist_field *operands[HIST_FIELD_OPERANDS_MAX];
Tom Zanussib559d002018-01-15 20:51:47 -0600134 struct hist_trigger_data *hist_data;
Tom Zanussi05ddb252018-12-18 14:33:26 -0600135
136 /*
137 * Variable fields contain variable-specific info in var.
138 */
Tom Zanussi30350d62018-01-15 20:51:49 -0600139 struct hist_var var;
Tom Zanussi100719d2018-01-15 20:51:52 -0600140 enum field_op_id operator;
Tom Zanussi067fe032018-01-15 20:51:56 -0600141 char *system;
142 char *event_name;
Tom Zanussi05ddb252018-12-18 14:33:26 -0600143
144 /*
145 * The name field is used for EXPR and VAR_REF fields. VAR
146 * fields contain the variable name in var.name.
147 */
Tom Zanussi100719d2018-01-15 20:51:52 -0600148 char *name;
Tom Zanussi05ddb252018-12-18 14:33:26 -0600149
150 /*
151 * When a histogram trigger is hit, if it has any references
152 * to variables, the values of those variables are collected
153 * into a var_ref_vals array by resolve_var_refs(). The
154 * current value of each variable is read from the tracing_map
155 * using the hist field's hist_var.idx and entered into the
156 * var_ref_idx entry i.e. var_ref_vals[var_ref_idx].
157 */
Tom Zanussi067fe032018-01-15 20:51:56 -0600158 unsigned int var_ref_idx;
159 bool read_once;
Tom Zanussi63a1e5d2020-10-04 17:14:05 -0500160
161 unsigned int var_str_idx;
Kalesh Singh52cfb372021-10-25 13:08:33 -0700162
163 /* Numeric literals are represented as u64 */
164 u64 constant;
Kalesh Singh8b5d46f2021-10-29 16:24:10 -0700165 /* Used to optimize division by constants */
166 u64 div_multiplier;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600167};
168
Tom Zanussidf35d932018-01-15 20:51:54 -0600169static u64 hist_field_none(struct hist_field *field,
170 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400171 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -0600172 struct ring_buffer_event *rbe,
173 void *event)
Tom Zanussi69a02002016-03-03 12:54:52 -0600174{
175 return 0;
176}
177
Kalesh Singh52cfb372021-10-25 13:08:33 -0700178static u64 hist_field_const(struct hist_field *field,
179 struct tracing_map_elt *elt,
180 struct trace_buffer *buffer,
181 struct ring_buffer_event *rbe,
182 void *event)
183{
184 return field->constant;
185}
186
Tom Zanussidf35d932018-01-15 20:51:54 -0600187static u64 hist_field_counter(struct hist_field *field,
188 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400189 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -0600190 struct ring_buffer_event *rbe,
191 void *event)
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600192{
193 return 1;
194}
195
Tom Zanussidf35d932018-01-15 20:51:54 -0600196static u64 hist_field_string(struct hist_field *hist_field,
197 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400198 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -0600199 struct ring_buffer_event *rbe,
200 void *event)
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600201{
202 char *addr = (char *)(event + hist_field->field->offset);
203
204 return (u64)(unsigned long)addr;
205}
206
Tom Zanussidf35d932018-01-15 20:51:54 -0600207static u64 hist_field_dynstring(struct hist_field *hist_field,
208 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400209 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -0600210 struct ring_buffer_event *rbe,
211 void *event)
Namhyung Kim79e577c2016-03-03 12:54:53 -0600212{
213 u32 str_item = *(u32 *)(event + hist_field->field->offset);
214 int str_loc = str_item & 0xffff;
215 char *addr = (char *)(event + str_loc);
216
217 return (u64)(unsigned long)addr;
218}
219
Masami Hiramatsu05770dd2021-11-22 18:30:12 +0900220static u64 hist_field_reldynstring(struct hist_field *hist_field,
221 struct tracing_map_elt *elt,
222 struct trace_buffer *buffer,
223 struct ring_buffer_event *rbe,
224 void *event)
225{
226 u32 *item = event + hist_field->field->offset;
227 u32 str_item = *item;
228 int str_loc = str_item & 0xffff;
229 char *addr = (char *)&item[1] + str_loc;
230
231 return (u64)(unsigned long)addr;
232}
233
Tom Zanussidf35d932018-01-15 20:51:54 -0600234static u64 hist_field_pstring(struct hist_field *hist_field,
235 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400236 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -0600237 struct ring_buffer_event *rbe,
238 void *event)
Namhyung Kim79e577c2016-03-03 12:54:53 -0600239{
240 char **addr = (char **)(event + hist_field->field->offset);
241
242 return (u64)(unsigned long)*addr;
243}
244
Tom Zanussidf35d932018-01-15 20:51:54 -0600245static u64 hist_field_log2(struct hist_field *hist_field,
246 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400247 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -0600248 struct ring_buffer_event *rbe,
249 void *event)
Namhyung Kim4b94f5b2016-03-03 12:55:02 -0600250{
Tom Zanussi5819ead2017-09-22 14:58:23 -0500251 struct hist_field *operand = hist_field->operands[0];
252
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400253 u64 val = operand->fn(operand, elt, buffer, rbe, event);
Namhyung Kim4b94f5b2016-03-03 12:55:02 -0600254
255 return (u64) ilog2(roundup_pow_of_two(val));
256}
257
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -0400258static u64 hist_field_bucket(struct hist_field *hist_field,
259 struct tracing_map_elt *elt,
260 struct trace_buffer *buffer,
261 struct ring_buffer_event *rbe,
262 void *event)
263{
264 struct hist_field *operand = hist_field->operands[0];
265 unsigned long buckets = hist_field->buckets;
266
267 u64 val = operand->fn(operand, elt, buffer, rbe, event);
268
269 if (WARN_ON_ONCE(!buckets))
270 return val;
271
272 if (val >= LONG_MAX)
273 val = div64_ul(val, buckets);
274 else
275 val = (u64)((unsigned long)val / buckets);
276 return val * buckets;
277}
278
Tom Zanussidf35d932018-01-15 20:51:54 -0600279static u64 hist_field_plus(struct hist_field *hist_field,
280 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400281 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -0600282 struct ring_buffer_event *rbe,
283 void *event)
Tom Zanussi100719d2018-01-15 20:51:52 -0600284{
285 struct hist_field *operand1 = hist_field->operands[0];
286 struct hist_field *operand2 = hist_field->operands[1];
287
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400288 u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
289 u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event);
Tom Zanussi100719d2018-01-15 20:51:52 -0600290
291 return val1 + val2;
292}
293
Tom Zanussidf35d932018-01-15 20:51:54 -0600294static u64 hist_field_minus(struct hist_field *hist_field,
295 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400296 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -0600297 struct ring_buffer_event *rbe,
298 void *event)
Tom Zanussi100719d2018-01-15 20:51:52 -0600299{
300 struct hist_field *operand1 = hist_field->operands[0];
301 struct hist_field *operand2 = hist_field->operands[1];
302
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400303 u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
304 u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event);
Tom Zanussi100719d2018-01-15 20:51:52 -0600305
306 return val1 - val2;
307}
308
Kalesh Singhbcef0442021-10-25 13:08:34 -0700309static u64 hist_field_div(struct hist_field *hist_field,
310 struct tracing_map_elt *elt,
311 struct trace_buffer *buffer,
312 struct ring_buffer_event *rbe,
313 void *event)
314{
315 struct hist_field *operand1 = hist_field->operands[0];
316 struct hist_field *operand2 = hist_field->operands[1];
317
318 u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
319 u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event);
320
321 /* Return -1 for the undefined case */
322 if (!val2)
323 return -1;
324
Kalesh Singh722edda2021-10-25 13:08:38 -0700325 /* Use shift if the divisor is a power of 2 */
326 if (!(val2 & (val2 - 1)))
327 return val1 >> __ffs64(val2);
328
Kalesh Singhbcef0442021-10-25 13:08:34 -0700329 return div64_u64(val1, val2);
330}
331
Kalesh Singh8b5d46f2021-10-29 16:24:10 -0700332static u64 div_by_power_of_two(struct hist_field *hist_field,
333 struct tracing_map_elt *elt,
334 struct trace_buffer *buffer,
335 struct ring_buffer_event *rbe,
336 void *event)
337{
338 struct hist_field *operand1 = hist_field->operands[0];
339 struct hist_field *operand2 = hist_field->operands[1];
340
341 u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
342
343 return val1 >> __ffs64(operand2->constant);
344}
345
346static u64 div_by_not_power_of_two(struct hist_field *hist_field,
347 struct tracing_map_elt *elt,
348 struct trace_buffer *buffer,
349 struct ring_buffer_event *rbe,
350 void *event)
351{
352 struct hist_field *operand1 = hist_field->operands[0];
353 struct hist_field *operand2 = hist_field->operands[1];
354
355 u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
356
357 return div64_u64(val1, operand2->constant);
358}
359
360static u64 div_by_mult_and_shift(struct hist_field *hist_field,
361 struct tracing_map_elt *elt,
362 struct trace_buffer *buffer,
363 struct ring_buffer_event *rbe,
364 void *event)
365{
366 struct hist_field *operand1 = hist_field->operands[0];
367 struct hist_field *operand2 = hist_field->operands[1];
368
369 u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
370
371 /*
372 * If the divisor is a constant, do a multiplication and shift instead.
373 *
374 * Choose Z = some power of 2. If Y <= Z, then:
375 * X / Y = (X * (Z / Y)) / Z
376 *
377 * (Z / Y) is a constant (mult) which is calculated at parse time, so:
378 * X / Y = (X * mult) / Z
379 *
380 * The division by Z can be replaced by a shift since Z is a power of 2:
381 * X / Y = (X * mult) >> HIST_DIV_SHIFT
382 *
383 * As long, as X < Z the results will not be off by more than 1.
384 */
385 if (val1 < (1 << HIST_DIV_SHIFT)) {
386 u64 mult = operand2->div_multiplier;
387
388 return (val1 * mult + ((1 << HIST_DIV_SHIFT) - 1)) >> HIST_DIV_SHIFT;
389 }
390
391 return div64_u64(val1, operand2->constant);
392}
393
Kalesh Singhbcef0442021-10-25 13:08:34 -0700394static u64 hist_field_mult(struct hist_field *hist_field,
395 struct tracing_map_elt *elt,
396 struct trace_buffer *buffer,
397 struct ring_buffer_event *rbe,
398 void *event)
399{
400 struct hist_field *operand1 = hist_field->operands[0];
401 struct hist_field *operand2 = hist_field->operands[1];
402
403 u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
404 u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event);
405
406 return val1 * val2;
407}
408
Tom Zanussidf35d932018-01-15 20:51:54 -0600409static u64 hist_field_unary_minus(struct hist_field *hist_field,
410 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400411 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -0600412 struct ring_buffer_event *rbe,
413 void *event)
Tom Zanussi100719d2018-01-15 20:51:52 -0600414{
415 struct hist_field *operand = hist_field->operands[0];
416
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400417 s64 sval = (s64)operand->fn(operand, elt, buffer, rbe, event);
Tom Zanussi100719d2018-01-15 20:51:52 -0600418 u64 val = (u64)-sval;
419
420 return val;
421}
422
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600423#define DEFINE_HIST_FIELD_FN(type) \
Tom Zanussifbd302c2018-01-15 20:51:43 -0600424 static u64 hist_field_##type(struct hist_field *hist_field, \
Tom Zanussidf35d932018-01-15 20:51:54 -0600425 struct tracing_map_elt *elt, \
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400426 struct trace_buffer *buffer, \
Tom Zanussidf35d932018-01-15 20:51:54 -0600427 struct ring_buffer_event *rbe, \
428 void *event) \
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600429{ \
430 type *addr = (type *)(event + hist_field->field->offset); \
431 \
Namhyung Kim79e577c2016-03-03 12:54:53 -0600432 return (u64)(unsigned long)*addr; \
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600433}
434
435DEFINE_HIST_FIELD_FN(s64);
436DEFINE_HIST_FIELD_FN(u64);
437DEFINE_HIST_FIELD_FN(s32);
438DEFINE_HIST_FIELD_FN(u32);
439DEFINE_HIST_FIELD_FN(s16);
440DEFINE_HIST_FIELD_FN(u16);
441DEFINE_HIST_FIELD_FN(s8);
442DEFINE_HIST_FIELD_FN(u8);
443
444#define for_each_hist_field(i, hist_data) \
445 for ((i) = 0; (i) < (hist_data)->n_fields; (i)++)
446
447#define for_each_hist_val_field(i, hist_data) \
448 for ((i) = 0; (i) < (hist_data)->n_vals; (i)++)
449
450#define for_each_hist_key_field(i, hist_data) \
451 for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++)
452
Tom Zanussi69a02002016-03-03 12:54:52 -0600453#define HIST_STACKTRACE_DEPTH 16
454#define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
455#define HIST_STACKTRACE_SKIP 5
456
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600457#define HITCOUNT_IDX 0
Tom Zanussi69a02002016-03-03 12:54:52 -0600458#define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE)
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600459
460enum hist_field_flags {
Tom Zanussi0d7a8322017-09-22 14:58:21 -0500461 HIST_FIELD_FL_HITCOUNT = 1 << 0,
462 HIST_FIELD_FL_KEY = 1 << 1,
463 HIST_FIELD_FL_STRING = 1 << 2,
464 HIST_FIELD_FL_HEX = 1 << 3,
465 HIST_FIELD_FL_SYM = 1 << 4,
466 HIST_FIELD_FL_SYM_OFFSET = 1 << 5,
467 HIST_FIELD_FL_EXECNAME = 1 << 6,
468 HIST_FIELD_FL_SYSCALL = 1 << 7,
469 HIST_FIELD_FL_STACKTRACE = 1 << 8,
470 HIST_FIELD_FL_LOG2 = 1 << 9,
Tom Zanussiad42feb2018-01-15 20:51:45 -0600471 HIST_FIELD_FL_TIMESTAMP = 1 << 10,
Tom Zanussi860f9f62018-01-15 20:51:48 -0600472 HIST_FIELD_FL_TIMESTAMP_USECS = 1 << 11,
Tom Zanussi30350d62018-01-15 20:51:49 -0600473 HIST_FIELD_FL_VAR = 1 << 12,
Tom Zanussi100719d2018-01-15 20:51:52 -0600474 HIST_FIELD_FL_EXPR = 1 << 13,
Tom Zanussi067fe032018-01-15 20:51:56 -0600475 HIST_FIELD_FL_VAR_REF = 1 << 14,
Tom Zanussi8b7622b2018-01-15 20:52:03 -0600476 HIST_FIELD_FL_CPU = 1 << 15,
Tom Zanussi7e8b88a2018-01-15 20:52:04 -0600477 HIST_FIELD_FL_ALIAS = 1 << 16,
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -0400478 HIST_FIELD_FL_BUCKET = 1 << 17,
Kalesh Singh52cfb372021-10-25 13:08:33 -0700479 HIST_FIELD_FL_CONST = 1 << 18,
Tom Zanussi30350d62018-01-15 20:51:49 -0600480};
481
482struct var_defs {
483 unsigned int n_vars;
484 char *name[TRACING_MAP_VARS_MAX];
485 char *expr[TRACING_MAP_VARS_MAX];
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600486};
487
488struct hist_trigger_attrs {
489 char *keys_str;
Tom Zanussif2606832016-03-03 12:54:43 -0600490 char *vals_str;
Tom Zanussie62347d2016-03-03 12:54:45 -0600491 char *sort_key_str;
Tom Zanussi5463bfd2016-03-03 12:54:59 -0600492 char *name;
Tom Zanussia4072fe2018-01-15 20:52:08 -0600493 char *clock;
Tom Zanussi83e99912016-03-03 12:54:46 -0600494 bool pause;
495 bool cont;
Tom Zanussie86ae9b2016-03-03 12:54:47 -0600496 bool clear;
Tom Zanussi860f9f62018-01-15 20:51:48 -0600497 bool ts_in_usecs;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600498 unsigned int map_bits;
Tom Zanussi30350d62018-01-15 20:51:49 -0600499
500 char *assignment_str[TRACING_MAP_VARS_MAX];
501 unsigned int n_assignments;
502
Tom Zanussi0212e2a2018-01-15 20:51:57 -0600503 char *action_str[HIST_ACTIONS_MAX];
504 unsigned int n_actions;
505
Tom Zanussi30350d62018-01-15 20:51:49 -0600506 struct var_defs var_defs;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600507};
508
Tom Zanussi02205a62018-01-15 20:51:59 -0600509struct field_var {
510 struct hist_field *var;
511 struct hist_field *val;
512};
513
514struct field_var_hist {
515 struct hist_trigger_data *hist_data;
516 char *cmd;
517};
518
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600519struct hist_trigger_data {
Tom Zanussi30350d62018-01-15 20:51:49 -0600520 struct hist_field *fields[HIST_FIELDS_MAX];
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600521 unsigned int n_vals;
522 unsigned int n_keys;
523 unsigned int n_fields;
Tom Zanussi30350d62018-01-15 20:51:49 -0600524 unsigned int n_vars;
Tom Zanussi63a1e5d2020-10-04 17:14:05 -0500525 unsigned int n_var_str;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600526 unsigned int key_size;
527 struct tracing_map_sort_key sort_keys[TRACING_MAP_SORT_KEYS_MAX];
528 unsigned int n_sort_keys;
529 struct trace_event_file *event_file;
530 struct hist_trigger_attrs *attrs;
531 struct tracing_map *map;
Tom Zanussiad42feb2018-01-15 20:51:45 -0600532 bool enable_timestamps;
Tom Zanussi30350d62018-01-15 20:51:49 -0600533 bool remove;
Tom Zanussi067fe032018-01-15 20:51:56 -0600534 struct hist_field *var_refs[TRACING_MAP_VARS_MAX];
535 unsigned int n_var_refs;
Tom Zanussi0212e2a2018-01-15 20:51:57 -0600536
537 struct action_data *actions[HIST_ACTIONS_MAX];
538 unsigned int n_actions;
Tom Zanussi02205a62018-01-15 20:51:59 -0600539
540 struct field_var *field_vars[SYNTH_FIELDS_MAX];
541 unsigned int n_field_vars;
542 unsigned int n_field_var_str;
543 struct field_var_hist *field_var_hists[SYNTH_FIELDS_MAX];
544 unsigned int n_field_var_hists;
Tom Zanussi50450602018-01-15 20:52:01 -0600545
Tom Zanussi7d18a102019-02-13 17:42:41 -0600546 struct field_var *save_vars[SYNTH_FIELDS_MAX];
547 unsigned int n_save_vars;
548 unsigned int n_save_var_str;
Tom Zanussi0212e2a2018-01-15 20:51:57 -0600549};
550
551struct action_data;
552
553typedef void (*action_fn_t) (struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400554 struct tracing_map_elt *elt,
555 struct trace_buffer *buffer, void *rec,
Tom Zanussi7d18a102019-02-13 17:42:41 -0600556 struct ring_buffer_event *rbe, void *key,
Tom Zanussi0212e2a2018-01-15 20:51:57 -0600557 struct action_data *data, u64 *var_ref_vals);
558
Tom Zanussi466f4522019-02-13 17:42:44 -0600559typedef bool (*check_track_val_fn_t) (u64 track_val, u64 var_val);
560
Tom Zanussi7d18a102019-02-13 17:42:41 -0600561enum handler_id {
562 HANDLER_ONMATCH = 1,
563 HANDLER_ONMAX,
Tom Zanussidff81f52019-02-13 17:42:48 -0600564 HANDLER_ONCHANGE,
Tom Zanussi7d18a102019-02-13 17:42:41 -0600565};
566
567enum action_id {
568 ACTION_SAVE = 1,
569 ACTION_TRACE,
Tom Zanussia3785b72019-02-13 17:42:46 -0600570 ACTION_SNAPSHOT,
Tom Zanussi7d18a102019-02-13 17:42:41 -0600571};
572
Tom Zanussi0212e2a2018-01-15 20:51:57 -0600573struct action_data {
Tom Zanussi7d18a102019-02-13 17:42:41 -0600574 enum handler_id handler;
575 enum action_id action;
576 char *action_name;
Tom Zanussi0212e2a2018-01-15 20:51:57 -0600577 action_fn_t fn;
Tom Zanussi7d18a102019-02-13 17:42:41 -0600578
Tom Zanussic282a382018-01-15 20:52:00 -0600579 unsigned int n_params;
580 char *params[SYNTH_FIELDS_MAX];
581
Tom Zanussic3e49502019-02-13 17:42:43 -0600582 /*
583 * When a histogram trigger is hit, the values of any
584 * references to variables, including variables being passed
585 * as parameters to synthetic events, are collected into a
Tom Zanussid380dcd2020-01-29 21:18:18 -0500586 * var_ref_vals array. This var_ref_idx array is an array of
587 * indices into the var_ref_vals array, one for each synthetic
588 * event param, and is passed to the synthetic event
589 * invocation.
Tom Zanussic3e49502019-02-13 17:42:43 -0600590 */
Tom Zanussid380dcd2020-01-29 21:18:18 -0500591 unsigned int var_ref_idx[TRACING_MAP_VARS_MAX];
Tom Zanussic3e49502019-02-13 17:42:43 -0600592 struct synth_event *synth_event;
Tom Zanussie91eefd72019-02-13 17:42:50 -0600593 bool use_trace_keyword;
594 char *synth_event_name;
Tom Zanussic3e49502019-02-13 17:42:43 -0600595
Tom Zanussic282a382018-01-15 20:52:00 -0600596 union {
597 struct {
Tom Zanussic3e49502019-02-13 17:42:43 -0600598 char *event;
599 char *event_system;
600 } match_data;
Tom Zanussi50450602018-01-15 20:52:01 -0600601
602 struct {
Tom Zanussi466f4522019-02-13 17:42:44 -0600603 /*
604 * var_str contains the $-unstripped variable
605 * name referenced by var_ref, and used when
606 * printing the action. Because var_ref
607 * creation is deferred to create_actions(),
608 * we need a per-action way to save it until
609 * then, thus var_str.
610 */
Tom Zanussi50450602018-01-15 20:52:01 -0600611 char *var_str;
Tom Zanussi466f4522019-02-13 17:42:44 -0600612
613 /*
614 * var_ref refers to the variable being
615 * tracked e.g onmax($var).
616 */
617 struct hist_field *var_ref;
618
619 /*
620 * track_var contains the 'invisible' tracking
621 * variable created to keep the current
622 * e.g. max value.
623 */
624 struct hist_field *track_var;
625
626 check_track_val_fn_t check_val;
627 action_fn_t save_data;
628 } track_data;
Tom Zanussic282a382018-01-15 20:52:00 -0600629 };
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600630};
631
Tom Zanussia3785b72019-02-13 17:42:46 -0600632struct track_data {
633 u64 track_val;
634 bool updated;
635
636 unsigned int key_len;
637 void *key;
638 struct tracing_map_elt elt;
639
640 struct action_data *action_data;
641 struct hist_trigger_data *hist_data;
642};
643
644struct hist_elt_data {
645 char *comm;
646 u64 *var_ref_vals;
Tom Zanussic910db92021-09-02 15:57:12 -0500647 char **field_var_str;
648 int n_field_var_str;
Tom Zanussia3785b72019-02-13 17:42:46 -0600649};
650
651struct snapshot_context {
652 struct tracing_map_elt *elt;
653 void *key;
654};
655
Kalesh Singh8b5d46f2021-10-29 16:24:10 -0700656/*
657 * Returns the specific division function to use if the divisor
658 * is constant. This avoids extra branches when the trigger is hit.
659 */
660static hist_field_fn_t hist_field_get_div_fn(struct hist_field *divisor)
661{
662 u64 div = divisor->constant;
663
664 if (!(div & (div - 1)))
665 return div_by_power_of_two;
666
667 /* If the divisor is too large, do a regular division */
668 if (div > (1 << HIST_DIV_SHIFT))
669 return div_by_not_power_of_two;
670
671 divisor->div_multiplier = div64_u64((u64)(1 << HIST_DIV_SHIFT), div);
672 return div_by_mult_and_shift;
673}
674
Tom Zanussia3785b72019-02-13 17:42:46 -0600675static void track_data_free(struct track_data *track_data)
676{
677 struct hist_elt_data *elt_data;
678
679 if (!track_data)
680 return;
681
682 kfree(track_data->key);
683
684 elt_data = track_data->elt.private_data;
685 if (elt_data) {
686 kfree(elt_data->comm);
687 kfree(elt_data);
688 }
689
690 kfree(track_data);
691}
692
693static struct track_data *track_data_alloc(unsigned int key_len,
694 struct action_data *action_data,
695 struct hist_trigger_data *hist_data)
696{
697 struct track_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
698 struct hist_elt_data *elt_data;
699
700 if (!data)
701 return ERR_PTR(-ENOMEM);
702
703 data->key = kzalloc(key_len, GFP_KERNEL);
704 if (!data->key) {
705 track_data_free(data);
706 return ERR_PTR(-ENOMEM);
707 }
708
709 data->key_len = key_len;
710 data->action_data = action_data;
711 data->hist_data = hist_data;
712
713 elt_data = kzalloc(sizeof(*elt_data), GFP_KERNEL);
714 if (!elt_data) {
715 track_data_free(data);
716 return ERR_PTR(-ENOMEM);
717 }
Tom Zanussi726721a2020-05-28 14:32:37 -0500718
Tom Zanussia3785b72019-02-13 17:42:46 -0600719 data->elt.private_data = elt_data;
720
721 elt_data->comm = kzalloc(TASK_COMM_LEN, GFP_KERNEL);
722 if (!elt_data->comm) {
723 track_data_free(data);
724 return ERR_PTR(-ENOMEM);
725 }
726
727 return data;
728}
729
Tom Zanussia1a05bb2019-03-31 18:48:16 -0500730static char last_cmd[MAX_FILTER_STR_VAL];
731static char last_cmd_loc[MAX_FILTER_STR_VAL];
Tom Zanussif404da62018-01-15 20:52:05 -0600732
Tom Zanussid566c5e2019-03-31 18:48:17 -0500733static int errpos(char *str)
Tom Zanussif404da62018-01-15 20:52:05 -0600734{
Tom Zanussid566c5e2019-03-31 18:48:17 -0500735 return err_pos(last_cmd, str);
Tom Zanussif404da62018-01-15 20:52:05 -0600736}
737
Tom Zanussia1a05bb2019-03-31 18:48:16 -0500738static void last_cmd_set(struct trace_event_file *file, char *str)
Tom Zanussif404da62018-01-15 20:52:05 -0600739{
Tom Zanussia1a05bb2019-03-31 18:48:16 -0500740 const char *system = NULL, *name = NULL;
741 struct trace_event_call *call;
Tom Zanussif404da62018-01-15 20:52:05 -0600742
743 if (!str)
744 return;
745
Tom Zanussid0a49702019-06-28 12:40:22 -0500746 strcpy(last_cmd, "hist:");
747 strncat(last_cmd, str, MAX_FILTER_STR_VAL - 1 - sizeof("hist:"));
Tom Zanussif404da62018-01-15 20:52:05 -0600748
Tom Zanussia1a05bb2019-03-31 18:48:16 -0500749 if (file) {
750 call = file->event_call;
Tom Zanussia1a05bb2019-03-31 18:48:16 -0500751 system = call->class->system;
752 if (system) {
753 name = trace_event_name(call);
754 if (!name)
755 system = NULL;
756 }
757 }
Tom Zanussif404da62018-01-15 20:52:05 -0600758
Tom Zanussia1a05bb2019-03-31 18:48:16 -0500759 if (system)
760 snprintf(last_cmd_loc, MAX_FILTER_STR_VAL, "hist:%s:%s", system, name);
Tom Zanussif404da62018-01-15 20:52:05 -0600761}
762
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -0400763static void hist_err(struct trace_array *tr, u8 err_type, u8 err_pos)
Tom Zanussif404da62018-01-15 20:52:05 -0600764{
Steven Rostedt (VMware)2f754e72019-04-01 22:52:21 -0400765 tracing_log_err(tr, last_cmd_loc, last_cmd, err_text,
766 err_type, err_pos);
Tom Zanussif404da62018-01-15 20:52:05 -0600767}
768
769static void hist_err_clear(void)
770{
Tom Zanussia1a05bb2019-03-31 18:48:16 -0500771 last_cmd[0] = '\0';
772 last_cmd_loc[0] = '\0';
Tom Zanussif404da62018-01-15 20:52:05 -0600773}
774
Tom Zanussi4b147932018-01-15 20:51:58 -0600775typedef void (*synth_probe_func_t) (void *__data, u64 *var_ref_vals,
Tom Zanussid380dcd2020-01-29 21:18:18 -0500776 unsigned int *var_ref_idx);
Tom Zanussi4b147932018-01-15 20:51:58 -0600777
778static inline void trace_synth(struct synth_event *event, u64 *var_ref_vals,
Tom Zanussid380dcd2020-01-29 21:18:18 -0500779 unsigned int *var_ref_idx)
Tom Zanussi4b147932018-01-15 20:51:58 -0600780{
781 struct tracepoint *tp = event->tp;
782
783 if (unlikely(atomic_read(&tp->key.enabled) > 0)) {
784 struct tracepoint_func *probe_func_ptr;
785 synth_probe_func_t probe_func;
786 void *__data;
787
788 if (!(cpu_online(raw_smp_processor_id())))
789 return;
790
791 probe_func_ptr = rcu_dereference_sched((tp)->funcs);
792 if (probe_func_ptr) {
793 do {
794 probe_func = probe_func_ptr->func;
795 __data = probe_func_ptr->data;
796 probe_func(__data, var_ref_vals, var_ref_idx);
797 } while ((++probe_func_ptr)->func);
798 }
799 }
800}
801
Tom Zanussic282a382018-01-15 20:52:00 -0600802static void action_trace(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400803 struct tracing_map_elt *elt,
804 struct trace_buffer *buffer, void *rec,
Tom Zanussi7d18a102019-02-13 17:42:41 -0600805 struct ring_buffer_event *rbe, void *key,
Tom Zanussic282a382018-01-15 20:52:00 -0600806 struct action_data *data, u64 *var_ref_vals)
807{
Tom Zanussic3e49502019-02-13 17:42:43 -0600808 struct synth_event *event = data->synth_event;
Tom Zanussic282a382018-01-15 20:52:00 -0600809
Tom Zanussic3e49502019-02-13 17:42:43 -0600810 trace_synth(event, var_ref_vals, data->var_ref_idx);
Tom Zanussic282a382018-01-15 20:52:00 -0600811}
812
813struct hist_var_data {
814 struct list_head list;
815 struct hist_trigger_data *hist_data;
816};
817
Tom Zanussidf35d932018-01-15 20:51:54 -0600818static u64 hist_field_timestamp(struct hist_field *hist_field,
819 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400820 struct trace_buffer *buffer,
Tom Zanussidf35d932018-01-15 20:51:54 -0600821 struct ring_buffer_event *rbe,
822 void *event)
Tom Zanussi860f9f62018-01-15 20:51:48 -0600823{
824 struct hist_trigger_data *hist_data = hist_field->hist_data;
825 struct trace_array *tr = hist_data->event_file->tr;
826
Steven Rostedt (VMware)efe61962021-03-16 12:41:04 -0400827 u64 ts = ring_buffer_event_time_stamp(buffer, rbe);
Tom Zanussi860f9f62018-01-15 20:51:48 -0600828
829 if (hist_data->attrs->ts_in_usecs && trace_clock_in_ns(tr))
830 ts = ns2usecs(ts);
831
832 return ts;
833}
834
Tom Zanussi8b7622b2018-01-15 20:52:03 -0600835static u64 hist_field_cpu(struct hist_field *hist_field,
836 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -0400837 struct trace_buffer *buffer,
Tom Zanussi8b7622b2018-01-15 20:52:03 -0600838 struct ring_buffer_event *rbe,
839 void *event)
840{
841 int cpu = smp_processor_id();
842
843 return cpu;
844}
845
Tom Zanusside40f032018-12-18 14:33:23 -0600846/**
847 * check_field_for_var_ref - Check if a VAR_REF field references a variable
848 * @hist_field: The VAR_REF field to check
849 * @var_data: The hist trigger that owns the variable
850 * @var_idx: The trigger variable identifier
851 *
852 * Check the given VAR_REF field to see whether or not it references
853 * the given variable associated with the given trigger.
854 *
855 * Return: The VAR_REF field if it does reference the variable, NULL if not
856 */
Tom Zanussi067fe032018-01-15 20:51:56 -0600857static struct hist_field *
858check_field_for_var_ref(struct hist_field *hist_field,
859 struct hist_trigger_data *var_data,
860 unsigned int var_idx)
861{
Tom Zanussie4f6d242018-12-19 13:09:16 -0600862 WARN_ON(!(hist_field && hist_field->flags & HIST_FIELD_FL_VAR_REF));
Tom Zanussi067fe032018-01-15 20:51:56 -0600863
Tom Zanussie4f6d242018-12-19 13:09:16 -0600864 if (hist_field && hist_field->var.idx == var_idx &&
865 hist_field->var.hist_data == var_data)
866 return hist_field;
Tom Zanussi067fe032018-01-15 20:51:56 -0600867
Tom Zanussie4f6d242018-12-19 13:09:16 -0600868 return NULL;
Tom Zanussi067fe032018-01-15 20:51:56 -0600869}
870
Tom Zanusside40f032018-12-18 14:33:23 -0600871/**
872 * find_var_ref - Check if a trigger has a reference to a trigger variable
873 * @hist_data: The hist trigger that might have a reference to the variable
874 * @var_data: The hist trigger that owns the variable
875 * @var_idx: The trigger variable identifier
876 *
877 * Check the list of var_refs[] on the first hist trigger to see
878 * whether any of them are references to the variable on the second
879 * trigger.
880 *
881 * Return: The VAR_REF field referencing the variable if so, NULL if not
882 */
Tom Zanussi067fe032018-01-15 20:51:56 -0600883static struct hist_field *find_var_ref(struct hist_trigger_data *hist_data,
884 struct hist_trigger_data *var_data,
885 unsigned int var_idx)
886{
Tom Zanussie4f6d242018-12-19 13:09:16 -0600887 struct hist_field *hist_field;
Tom Zanussi067fe032018-01-15 20:51:56 -0600888 unsigned int i;
889
Tom Zanussie4f6d242018-12-19 13:09:16 -0600890 for (i = 0; i < hist_data->n_var_refs; i++) {
891 hist_field = hist_data->var_refs[i];
892 if (check_field_for_var_ref(hist_field, var_data, var_idx))
893 return hist_field;
Tom Zanussi067fe032018-01-15 20:51:56 -0600894 }
895
Tom Zanussie4f6d242018-12-19 13:09:16 -0600896 return NULL;
Tom Zanussi067fe032018-01-15 20:51:56 -0600897}
898
Tom Zanusside40f032018-12-18 14:33:23 -0600899/**
900 * find_any_var_ref - Check if there is a reference to a given trigger variable
901 * @hist_data: The hist trigger
902 * @var_idx: The trigger variable identifier
903 *
904 * Check to see whether the given variable is currently referenced by
905 * any other trigger.
906 *
907 * The trigger the variable is defined on is explicitly excluded - the
908 * assumption being that a self-reference doesn't prevent a trigger
909 * from being removed.
910 *
911 * Return: The VAR_REF field referencing the variable if so, NULL if not
912 */
Tom Zanussi067fe032018-01-15 20:51:56 -0600913static struct hist_field *find_any_var_ref(struct hist_trigger_data *hist_data,
914 unsigned int var_idx)
915{
916 struct trace_array *tr = hist_data->event_file->tr;
917 struct hist_field *found = NULL;
918 struct hist_var_data *var_data;
919
920 list_for_each_entry(var_data, &tr->hist_vars, list) {
921 if (var_data->hist_data == hist_data)
922 continue;
923 found = find_var_ref(var_data->hist_data, hist_data, var_idx);
924 if (found)
925 break;
926 }
927
928 return found;
929}
930
Tom Zanusside40f032018-12-18 14:33:23 -0600931/**
932 * check_var_refs - Check if there is a reference to any of trigger's variables
933 * @hist_data: The hist trigger
934 *
935 * A trigger can define one or more variables. If any one of them is
936 * currently referenced by any other trigger, this function will
937 * determine that.
938
939 * Typically used to determine whether or not a trigger can be removed
940 * - if there are any references to a trigger's variables, it cannot.
941 *
942 * Return: True if there is a reference to any of trigger's variables
943 */
Tom Zanussi067fe032018-01-15 20:51:56 -0600944static bool check_var_refs(struct hist_trigger_data *hist_data)
945{
946 struct hist_field *field;
947 bool found = false;
948 int i;
949
950 for_each_hist_field(i, hist_data) {
951 field = hist_data->fields[i];
952 if (field && field->flags & HIST_FIELD_FL_VAR) {
953 if (find_any_var_ref(hist_data, field->var.idx)) {
954 found = true;
955 break;
956 }
957 }
958 }
959
960 return found;
961}
962
963static struct hist_var_data *find_hist_vars(struct hist_trigger_data *hist_data)
964{
965 struct trace_array *tr = hist_data->event_file->tr;
966 struct hist_var_data *var_data, *found = NULL;
967
968 list_for_each_entry(var_data, &tr->hist_vars, list) {
969 if (var_data->hist_data == hist_data) {
970 found = var_data;
971 break;
972 }
973 }
974
975 return found;
976}
977
978static bool field_has_hist_vars(struct hist_field *hist_field,
979 unsigned int level)
980{
981 int i;
982
983 if (level > 3)
984 return false;
985
986 if (!hist_field)
987 return false;
988
989 if (hist_field->flags & HIST_FIELD_FL_VAR ||
990 hist_field->flags & HIST_FIELD_FL_VAR_REF)
991 return true;
992
993 for (i = 0; i < HIST_FIELD_OPERANDS_MAX; i++) {
994 struct hist_field *operand;
995
996 operand = hist_field->operands[i];
997 if (field_has_hist_vars(operand, level + 1))
998 return true;
999 }
1000
1001 return false;
1002}
1003
1004static bool has_hist_vars(struct hist_trigger_data *hist_data)
1005{
1006 struct hist_field *hist_field;
1007 int i;
1008
1009 for_each_hist_field(i, hist_data) {
1010 hist_field = hist_data->fields[i];
1011 if (field_has_hist_vars(hist_field, 0))
1012 return true;
1013 }
1014
1015 return false;
1016}
1017
1018static int save_hist_vars(struct hist_trigger_data *hist_data)
1019{
1020 struct trace_array *tr = hist_data->event_file->tr;
1021 struct hist_var_data *var_data;
1022
1023 var_data = find_hist_vars(hist_data);
1024 if (var_data)
1025 return 0;
1026
Steven Rostedt (VMware)8530dec2019-10-11 17:39:57 -04001027 if (tracing_check_open_get_tr(tr))
Tom Zanussi067fe032018-01-15 20:51:56 -06001028 return -ENODEV;
1029
1030 var_data = kzalloc(sizeof(*var_data), GFP_KERNEL);
1031 if (!var_data) {
1032 trace_array_put(tr);
1033 return -ENOMEM;
1034 }
1035
1036 var_data->hist_data = hist_data;
1037 list_add(&var_data->list, &tr->hist_vars);
1038
1039 return 0;
1040}
1041
1042static void remove_hist_vars(struct hist_trigger_data *hist_data)
1043{
1044 struct trace_array *tr = hist_data->event_file->tr;
1045 struct hist_var_data *var_data;
1046
1047 var_data = find_hist_vars(hist_data);
1048 if (!var_data)
1049 return;
1050
1051 if (WARN_ON(check_var_refs(hist_data)))
1052 return;
1053
1054 list_del(&var_data->list);
1055
1056 kfree(var_data);
1057
1058 trace_array_put(tr);
1059}
1060
Tom Zanussi30350d62018-01-15 20:51:49 -06001061static struct hist_field *find_var_field(struct hist_trigger_data *hist_data,
1062 const char *var_name)
1063{
1064 struct hist_field *hist_field, *found = NULL;
1065 int i;
1066
1067 for_each_hist_field(i, hist_data) {
1068 hist_field = hist_data->fields[i];
1069 if (hist_field && hist_field->flags & HIST_FIELD_FL_VAR &&
1070 strcmp(hist_field->var.name, var_name) == 0) {
1071 found = hist_field;
1072 break;
1073 }
1074 }
1075
1076 return found;
1077}
1078
1079static struct hist_field *find_var(struct hist_trigger_data *hist_data,
1080 struct trace_event_file *file,
1081 const char *var_name)
1082{
1083 struct hist_trigger_data *test_data;
1084 struct event_trigger_data *test;
1085 struct hist_field *hist_field;
1086
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09001087 lockdep_assert_held(&event_mutex);
1088
Tom Zanussi30350d62018-01-15 20:51:49 -06001089 hist_field = find_var_field(hist_data, var_name);
1090 if (hist_field)
1091 return hist_field;
1092
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09001093 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi30350d62018-01-15 20:51:49 -06001094 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
1095 test_data = test->private_data;
1096 hist_field = find_var_field(test_data, var_name);
1097 if (hist_field)
1098 return hist_field;
1099 }
1100 }
1101
1102 return NULL;
1103}
1104
Tom Zanussi067fe032018-01-15 20:51:56 -06001105static struct trace_event_file *find_var_file(struct trace_array *tr,
1106 char *system,
1107 char *event_name,
1108 char *var_name)
1109{
1110 struct hist_trigger_data *var_hist_data;
1111 struct hist_var_data *var_data;
1112 struct trace_event_file *file, *found = NULL;
1113
1114 if (system)
1115 return find_event_file(tr, system, event_name);
1116
1117 list_for_each_entry(var_data, &tr->hist_vars, list) {
1118 var_hist_data = var_data->hist_data;
1119 file = var_hist_data->event_file;
1120 if (file == found)
1121 continue;
1122
1123 if (find_var_field(var_hist_data, var_name)) {
Tom Zanussif404da62018-01-15 20:52:05 -06001124 if (found) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04001125 hist_err(tr, HIST_ERR_VAR_NOT_UNIQUE, errpos(var_name));
Tom Zanussi067fe032018-01-15 20:51:56 -06001126 return NULL;
Tom Zanussif404da62018-01-15 20:52:05 -06001127 }
Tom Zanussi067fe032018-01-15 20:51:56 -06001128
1129 found = file;
1130 }
1131 }
1132
1133 return found;
1134}
1135
1136static struct hist_field *find_file_var(struct trace_event_file *file,
1137 const char *var_name)
1138{
1139 struct hist_trigger_data *test_data;
1140 struct event_trigger_data *test;
1141 struct hist_field *hist_field;
1142
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09001143 lockdep_assert_held(&event_mutex);
1144
1145 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi067fe032018-01-15 20:51:56 -06001146 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
1147 test_data = test->private_data;
1148 hist_field = find_var_field(test_data, var_name);
1149 if (hist_field)
1150 return hist_field;
1151 }
1152 }
1153
1154 return NULL;
1155}
1156
Tom Zanussic282a382018-01-15 20:52:00 -06001157static struct hist_field *
1158find_match_var(struct hist_trigger_data *hist_data, char *var_name)
1159{
1160 struct trace_array *tr = hist_data->event_file->tr;
1161 struct hist_field *hist_field, *found = NULL;
1162 struct trace_event_file *file;
1163 unsigned int i;
1164
1165 for (i = 0; i < hist_data->n_actions; i++) {
1166 struct action_data *data = hist_data->actions[i];
1167
Tom Zanussi7d18a102019-02-13 17:42:41 -06001168 if (data->handler == HANDLER_ONMATCH) {
Tom Zanussic3e49502019-02-13 17:42:43 -06001169 char *system = data->match_data.event_system;
1170 char *event_name = data->match_data.event;
Tom Zanussic282a382018-01-15 20:52:00 -06001171
1172 file = find_var_file(tr, system, event_name, var_name);
1173 if (!file)
1174 continue;
1175 hist_field = find_file_var(file, var_name);
1176 if (hist_field) {
1177 if (found) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04001178 hist_err(tr, HIST_ERR_VAR_NOT_UNIQUE,
1179 errpos(var_name));
Tom Zanussic282a382018-01-15 20:52:00 -06001180 return ERR_PTR(-EINVAL);
1181 }
1182
1183 found = hist_field;
1184 }
1185 }
1186 }
1187 return found;
1188}
1189
Tom Zanussi067fe032018-01-15 20:51:56 -06001190static struct hist_field *find_event_var(struct hist_trigger_data *hist_data,
1191 char *system,
1192 char *event_name,
1193 char *var_name)
1194{
1195 struct trace_array *tr = hist_data->event_file->tr;
1196 struct hist_field *hist_field = NULL;
1197 struct trace_event_file *file;
1198
Tom Zanussic282a382018-01-15 20:52:00 -06001199 if (!system || !event_name) {
1200 hist_field = find_match_var(hist_data, var_name);
1201 if (IS_ERR(hist_field))
1202 return NULL;
1203 if (hist_field)
1204 return hist_field;
1205 }
1206
Tom Zanussi067fe032018-01-15 20:51:56 -06001207 file = find_var_file(tr, system, event_name, var_name);
1208 if (!file)
1209 return NULL;
1210
1211 hist_field = find_file_var(file, var_name);
1212
1213 return hist_field;
1214}
1215
Tom Zanussi067fe032018-01-15 20:51:56 -06001216static u64 hist_field_var_ref(struct hist_field *hist_field,
1217 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04001218 struct trace_buffer *buffer,
Tom Zanussi067fe032018-01-15 20:51:56 -06001219 struct ring_buffer_event *rbe,
1220 void *event)
1221{
1222 struct hist_elt_data *elt_data;
1223 u64 var_val = 0;
1224
Tom Zanussi55267c82019-04-18 10:18:50 -05001225 if (WARN_ON_ONCE(!elt))
1226 return var_val;
1227
Tom Zanussi067fe032018-01-15 20:51:56 -06001228 elt_data = elt->private_data;
1229 var_val = elt_data->var_ref_vals[hist_field->var_ref_idx];
1230
1231 return var_val;
1232}
1233
1234static bool resolve_var_refs(struct hist_trigger_data *hist_data, void *key,
1235 u64 *var_ref_vals, bool self)
1236{
1237 struct hist_trigger_data *var_data;
1238 struct tracing_map_elt *var_elt;
1239 struct hist_field *hist_field;
1240 unsigned int i, var_idx;
1241 bool resolved = true;
1242 u64 var_val = 0;
1243
1244 for (i = 0; i < hist_data->n_var_refs; i++) {
1245 hist_field = hist_data->var_refs[i];
1246 var_idx = hist_field->var.idx;
1247 var_data = hist_field->var.hist_data;
1248
1249 if (var_data == NULL) {
1250 resolved = false;
1251 break;
1252 }
1253
1254 if ((self && var_data != hist_data) ||
1255 (!self && var_data == hist_data))
1256 continue;
1257
1258 var_elt = tracing_map_lookup(var_data->map, key);
1259 if (!var_elt) {
1260 resolved = false;
1261 break;
1262 }
1263
1264 if (!tracing_map_var_set(var_elt, var_idx)) {
1265 resolved = false;
1266 break;
1267 }
1268
1269 if (self || !hist_field->read_once)
1270 var_val = tracing_map_read_var(var_elt, var_idx);
1271 else
1272 var_val = tracing_map_read_var_once(var_elt, var_idx);
1273
1274 var_ref_vals[i] = var_val;
1275 }
1276
1277 return resolved;
1278}
1279
Tom Zanussi85013252017-09-22 14:58:22 -05001280static const char *hist_field_name(struct hist_field *field,
1281 unsigned int level)
1282{
1283 const char *field_name = "";
1284
1285 if (level > 1)
1286 return field_name;
1287
1288 if (field->field)
1289 field_name = field->field->name;
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06001290 else if (field->flags & HIST_FIELD_FL_LOG2 ||
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04001291 field->flags & HIST_FIELD_FL_ALIAS ||
1292 field->flags & HIST_FIELD_FL_BUCKET)
Tom Zanussi5819ead2017-09-22 14:58:23 -05001293 field_name = hist_field_name(field->operands[0], ++level);
Tom Zanussi8b7622b2018-01-15 20:52:03 -06001294 else if (field->flags & HIST_FIELD_FL_CPU)
Steven Rostedt (VMware)1e3bac72021-07-21 11:00:53 -04001295 field_name = "common_cpu";
Tom Zanussi067fe032018-01-15 20:51:56 -06001296 else if (field->flags & HIST_FIELD_FL_EXPR ||
1297 field->flags & HIST_FIELD_FL_VAR_REF) {
1298 if (field->system) {
1299 static char full_name[MAX_FILTER_STR_VAL];
1300
1301 strcat(full_name, field->system);
1302 strcat(full_name, ".");
1303 strcat(full_name, field->event_name);
1304 strcat(full_name, ".");
1305 strcat(full_name, field->name);
1306 field_name = full_name;
1307 } else
1308 field_name = field->name;
Tom Zanussi0ae79612018-03-28 15:10:53 -05001309 } else if (field->flags & HIST_FIELD_FL_TIMESTAMP)
1310 field_name = "common_timestamp";
Tom Zanussi85013252017-09-22 14:58:22 -05001311
1312 if (field_name == NULL)
1313 field_name = "";
1314
1315 return field_name;
1316}
1317
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001318static hist_field_fn_t select_value_fn(int field_size, int field_is_signed)
1319{
1320 hist_field_fn_t fn = NULL;
1321
1322 switch (field_size) {
1323 case 8:
1324 if (field_is_signed)
1325 fn = hist_field_s64;
1326 else
1327 fn = hist_field_u64;
1328 break;
1329 case 4:
1330 if (field_is_signed)
1331 fn = hist_field_s32;
1332 else
1333 fn = hist_field_u32;
1334 break;
1335 case 2:
1336 if (field_is_signed)
1337 fn = hist_field_s16;
1338 else
1339 fn = hist_field_u16;
1340 break;
1341 case 1:
1342 if (field_is_signed)
1343 fn = hist_field_s8;
1344 else
1345 fn = hist_field_u8;
1346 break;
1347 }
1348
1349 return fn;
1350}
1351
1352static int parse_map_size(char *str)
1353{
1354 unsigned long size, map_bits;
1355 int ret;
1356
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001357 ret = kstrtoul(str, 0, &size);
1358 if (ret)
1359 goto out;
1360
1361 map_bits = ilog2(roundup_pow_of_two(size));
1362 if (map_bits < TRACING_MAP_BITS_MIN ||
1363 map_bits > TRACING_MAP_BITS_MAX)
1364 ret = -EINVAL;
1365 else
1366 ret = map_bits;
1367 out:
1368 return ret;
1369}
1370
1371static void destroy_hist_trigger_attrs(struct hist_trigger_attrs *attrs)
1372{
Tom Zanussi30350d62018-01-15 20:51:49 -06001373 unsigned int i;
1374
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001375 if (!attrs)
1376 return;
1377
Tom Zanussi30350d62018-01-15 20:51:49 -06001378 for (i = 0; i < attrs->n_assignments; i++)
1379 kfree(attrs->assignment_str[i]);
1380
Tom Zanussi0212e2a2018-01-15 20:51:57 -06001381 for (i = 0; i < attrs->n_actions; i++)
1382 kfree(attrs->action_str[i]);
1383
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001384 kfree(attrs->name);
Tom Zanussie62347d2016-03-03 12:54:45 -06001385 kfree(attrs->sort_key_str);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001386 kfree(attrs->keys_str);
Tom Zanussif2606832016-03-03 12:54:43 -06001387 kfree(attrs->vals_str);
Tom Zanussia4072fe2018-01-15 20:52:08 -06001388 kfree(attrs->clock);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001389 kfree(attrs);
1390}
1391
Tom Zanussi0212e2a2018-01-15 20:51:57 -06001392static int parse_action(char *str, struct hist_trigger_attrs *attrs)
1393{
Tom Zanussic282a382018-01-15 20:52:00 -06001394 int ret = -EINVAL;
Tom Zanussi0212e2a2018-01-15 20:51:57 -06001395
1396 if (attrs->n_actions >= HIST_ACTIONS_MAX)
1397 return ret;
1398
Steven Rostedt (VMware)754481e2018-12-19 22:38:21 -05001399 if ((str_has_prefix(str, "onmatch(")) ||
Tom Zanussidff81f52019-02-13 17:42:48 -06001400 (str_has_prefix(str, "onmax(")) ||
1401 (str_has_prefix(str, "onchange("))) {
Tom Zanussic282a382018-01-15 20:52:00 -06001402 attrs->action_str[attrs->n_actions] = kstrdup(str, GFP_KERNEL);
1403 if (!attrs->action_str[attrs->n_actions]) {
1404 ret = -ENOMEM;
1405 return ret;
1406 }
1407 attrs->n_actions++;
1408 ret = 0;
1409 }
Tom Zanussi0212e2a2018-01-15 20:51:57 -06001410 return ret;
1411}
1412
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04001413static int parse_assignment(struct trace_array *tr,
1414 char *str, struct hist_trigger_attrs *attrs)
Tom Zanussi9b1ae032018-01-15 20:51:44 -06001415{
Tom Zanussib527b632019-06-28 12:40:20 -05001416 int len, ret = 0;
Tom Zanussi9b1ae032018-01-15 20:51:44 -06001417
Tom Zanussib527b632019-06-28 12:40:20 -05001418 if ((len = str_has_prefix(str, "key=")) ||
1419 (len = str_has_prefix(str, "keys="))) {
1420 attrs->keys_str = kstrdup(str + len, GFP_KERNEL);
Tom Zanussi9b1ae032018-01-15 20:51:44 -06001421 if (!attrs->keys_str) {
1422 ret = -ENOMEM;
1423 goto out;
1424 }
Tom Zanussib527b632019-06-28 12:40:20 -05001425 } else if ((len = str_has_prefix(str, "val=")) ||
1426 (len = str_has_prefix(str, "vals=")) ||
1427 (len = str_has_prefix(str, "values="))) {
1428 attrs->vals_str = kstrdup(str + len, GFP_KERNEL);
Tom Zanussi9b1ae032018-01-15 20:51:44 -06001429 if (!attrs->vals_str) {
1430 ret = -ENOMEM;
1431 goto out;
1432 }
Tom Zanussib527b632019-06-28 12:40:20 -05001433 } else if ((len = str_has_prefix(str, "sort="))) {
1434 attrs->sort_key_str = kstrdup(str + len, GFP_KERNEL);
Tom Zanussi9b1ae032018-01-15 20:51:44 -06001435 if (!attrs->sort_key_str) {
1436 ret = -ENOMEM;
1437 goto out;
1438 }
Steven Rostedt (VMware)754481e2018-12-19 22:38:21 -05001439 } else if (str_has_prefix(str, "name=")) {
Tom Zanussi9b1ae032018-01-15 20:51:44 -06001440 attrs->name = kstrdup(str, GFP_KERNEL);
1441 if (!attrs->name) {
1442 ret = -ENOMEM;
1443 goto out;
1444 }
Tom Zanussib527b632019-06-28 12:40:20 -05001445 } else if ((len = str_has_prefix(str, "clock="))) {
1446 str += len;
Tom Zanussia4072fe2018-01-15 20:52:08 -06001447
1448 str = strstrip(str);
1449 attrs->clock = kstrdup(str, GFP_KERNEL);
1450 if (!attrs->clock) {
1451 ret = -ENOMEM;
1452 goto out;
1453 }
Tom Zanussib527b632019-06-28 12:40:20 -05001454 } else if ((len = str_has_prefix(str, "size="))) {
1455 int map_bits = parse_map_size(str + len);
Tom Zanussi9b1ae032018-01-15 20:51:44 -06001456
1457 if (map_bits < 0) {
1458 ret = map_bits;
1459 goto out;
1460 }
1461 attrs->map_bits = map_bits;
Tom Zanussi30350d62018-01-15 20:51:49 -06001462 } else {
1463 char *assignment;
1464
1465 if (attrs->n_assignments == TRACING_MAP_VARS_MAX) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04001466 hist_err(tr, HIST_ERR_TOO_MANY_VARS, errpos(str));
Tom Zanussi30350d62018-01-15 20:51:49 -06001467 ret = -EINVAL;
1468 goto out;
1469 }
1470
1471 assignment = kstrdup(str, GFP_KERNEL);
1472 if (!assignment) {
1473 ret = -ENOMEM;
1474 goto out;
1475 }
1476
1477 attrs->assignment_str[attrs->n_assignments++] = assignment;
1478 }
Tom Zanussi9b1ae032018-01-15 20:51:44 -06001479 out:
1480 return ret;
1481}
1482
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04001483static struct hist_trigger_attrs *
1484parse_hist_trigger_attrs(struct trace_array *tr, char *trigger_str)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001485{
1486 struct hist_trigger_attrs *attrs;
1487 int ret = 0;
1488
1489 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
1490 if (!attrs)
1491 return ERR_PTR(-ENOMEM);
1492
1493 while (trigger_str) {
1494 char *str = strsep(&trigger_str, ":");
Tom Zanussib527b632019-06-28 12:40:20 -05001495 char *rhs;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001496
Tom Zanussib527b632019-06-28 12:40:20 -05001497 rhs = strchr(str, '=');
1498 if (rhs) {
1499 if (!strlen(++rhs)) {
1500 ret = -EINVAL;
Tom Zanussi4de26c82019-06-28 12:40:21 -05001501 hist_err(tr, HIST_ERR_EMPTY_ASSIGNMENT, errpos(str));
Tom Zanussib527b632019-06-28 12:40:20 -05001502 goto free;
1503 }
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04001504 ret = parse_assignment(tr, str, attrs);
Tom Zanussi9b1ae032018-01-15 20:51:44 -06001505 if (ret)
1506 goto free;
1507 } else if (strcmp(str, "pause") == 0)
Tom Zanussi83e99912016-03-03 12:54:46 -06001508 attrs->pause = true;
1509 else if ((strcmp(str, "cont") == 0) ||
1510 (strcmp(str, "continue") == 0))
1511 attrs->cont = true;
Tom Zanussie86ae9b2016-03-03 12:54:47 -06001512 else if (strcmp(str, "clear") == 0)
1513 attrs->clear = true;
Tom Zanussi9b1ae032018-01-15 20:51:44 -06001514 else {
Tom Zanussi0212e2a2018-01-15 20:51:57 -06001515 ret = parse_action(str, attrs);
1516 if (ret)
1517 goto free;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001518 }
1519 }
1520
1521 if (!attrs->keys_str) {
1522 ret = -EINVAL;
1523 goto free;
1524 }
1525
Tom Zanussia4072fe2018-01-15 20:52:08 -06001526 if (!attrs->clock) {
1527 attrs->clock = kstrdup("global", GFP_KERNEL);
1528 if (!attrs->clock) {
1529 ret = -ENOMEM;
1530 goto free;
1531 }
1532 }
1533
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001534 return attrs;
1535 free:
1536 destroy_hist_trigger_attrs(attrs);
1537
1538 return ERR_PTR(ret);
1539}
1540
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001541static inline void save_comm(char *comm, struct task_struct *task)
1542{
1543 if (!task->pid) {
1544 strcpy(comm, "<idle>");
1545 return;
1546 }
1547
1548 if (WARN_ON_ONCE(task->pid < 0)) {
1549 strcpy(comm, "<XXX>");
1550 return;
1551 }
1552
Tom Zanussi27242c62019-03-05 10:11:59 -06001553 strncpy(comm, task->comm, TASK_COMM_LEN);
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001554}
1555
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001556static void hist_elt_data_free(struct hist_elt_data *elt_data)
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001557{
Tom Zanussi02205a62018-01-15 20:51:59 -06001558 unsigned int i;
1559
Tom Zanussic910db92021-09-02 15:57:12 -05001560 for (i = 0; i < elt_data->n_field_var_str; i++)
Tom Zanussi02205a62018-01-15 20:51:59 -06001561 kfree(elt_data->field_var_str[i]);
1562
Tom Zanussic910db92021-09-02 15:57:12 -05001563 kfree(elt_data->field_var_str);
1564
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001565 kfree(elt_data->comm);
1566 kfree(elt_data);
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001567}
1568
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001569static void hist_trigger_elt_data_free(struct tracing_map_elt *elt)
1570{
1571 struct hist_elt_data *elt_data = elt->private_data;
1572
1573 hist_elt_data_free(elt_data);
1574}
1575
1576static int hist_trigger_elt_data_alloc(struct tracing_map_elt *elt)
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001577{
1578 struct hist_trigger_data *hist_data = elt->map->private_data;
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001579 unsigned int size = TASK_COMM_LEN;
1580 struct hist_elt_data *elt_data;
Steven Rostedt (VMware)ed2cf902021-07-22 10:27:07 -04001581 struct hist_field *hist_field;
Tom Zanussi02205a62018-01-15 20:51:59 -06001582 unsigned int i, n_str;
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001583
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001584 elt_data = kzalloc(sizeof(*elt_data), GFP_KERNEL);
1585 if (!elt_data)
1586 return -ENOMEM;
1587
Steven Rostedt (VMware)ed2cf902021-07-22 10:27:07 -04001588 for_each_hist_field(i, hist_data) {
1589 hist_field = hist_data->fields[i];
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001590
Steven Rostedt (VMware)ed2cf902021-07-22 10:27:07 -04001591 if (hist_field->flags & HIST_FIELD_FL_EXECNAME) {
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001592 elt_data->comm = kzalloc(size, GFP_KERNEL);
1593 if (!elt_data->comm) {
1594 kfree(elt_data);
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001595 return -ENOMEM;
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001596 }
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001597 break;
1598 }
1599 }
1600
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05001601 n_str = hist_data->n_field_var_str + hist_data->n_save_var_str +
1602 hist_data->n_var_str;
1603 if (n_str > SYNTH_FIELDS_MAX) {
1604 hist_elt_data_free(elt_data);
1605 return -EINVAL;
1606 }
Tom Zanussi02205a62018-01-15 20:51:59 -06001607
Tom Zanussi4a4a56b2020-10-04 17:14:03 -05001608 BUILD_BUG_ON(STR_VAR_LEN_MAX & (sizeof(u64) - 1));
1609
Tom Zanussi02205a62018-01-15 20:51:59 -06001610 size = STR_VAR_LEN_MAX;
1611
Tom Zanussic910db92021-09-02 15:57:12 -05001612 elt_data->field_var_str = kcalloc(n_str, sizeof(char *), GFP_KERNEL);
1613 if (!elt_data->field_var_str) {
1614 hist_elt_data_free(elt_data);
1615 return -EINVAL;
1616 }
1617 elt_data->n_field_var_str = n_str;
1618
Tom Zanussi02205a62018-01-15 20:51:59 -06001619 for (i = 0; i < n_str; i++) {
1620 elt_data->field_var_str[i] = kzalloc(size, GFP_KERNEL);
1621 if (!elt_data->field_var_str[i]) {
1622 hist_elt_data_free(elt_data);
1623 return -ENOMEM;
1624 }
1625 }
1626
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001627 elt->private_data = elt_data;
1628
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001629 return 0;
1630}
1631
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001632static void hist_trigger_elt_data_init(struct tracing_map_elt *elt)
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001633{
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001634 struct hist_elt_data *elt_data = elt->private_data;
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001635
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001636 if (elt_data->comm)
1637 save_comm(elt_data->comm, current);
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001638}
1639
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06001640static const struct tracing_map_ops hist_trigger_elt_data_ops = {
1641 .elt_alloc = hist_trigger_elt_data_alloc,
1642 .elt_free = hist_trigger_elt_data_free,
1643 .elt_init = hist_trigger_elt_data_init,
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001644};
1645
Tom Zanussi2ece94f2018-01-15 20:51:51 -06001646static const char *get_hist_field_flags(struct hist_field *hist_field)
1647{
1648 const char *flags_str = NULL;
1649
1650 if (hist_field->flags & HIST_FIELD_FL_HEX)
1651 flags_str = "hex";
1652 else if (hist_field->flags & HIST_FIELD_FL_SYM)
1653 flags_str = "sym";
1654 else if (hist_field->flags & HIST_FIELD_FL_SYM_OFFSET)
1655 flags_str = "sym-offset";
1656 else if (hist_field->flags & HIST_FIELD_FL_EXECNAME)
1657 flags_str = "execname";
1658 else if (hist_field->flags & HIST_FIELD_FL_SYSCALL)
1659 flags_str = "syscall";
1660 else if (hist_field->flags & HIST_FIELD_FL_LOG2)
1661 flags_str = "log2";
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04001662 else if (hist_field->flags & HIST_FIELD_FL_BUCKET)
1663 flags_str = "buckets";
Tom Zanussi2ece94f2018-01-15 20:51:51 -06001664 else if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP_USECS)
1665 flags_str = "usecs";
1666
1667 return flags_str;
1668}
1669
Tom Zanussi100719d2018-01-15 20:51:52 -06001670static void expr_field_str(struct hist_field *field, char *expr)
1671{
Tom Zanussi067fe032018-01-15 20:51:56 -06001672 if (field->flags & HIST_FIELD_FL_VAR_REF)
1673 strcat(expr, "$");
Kalesh Singh52cfb372021-10-25 13:08:33 -07001674 else if (field->flags & HIST_FIELD_FL_CONST) {
1675 char str[HIST_CONST_DIGITS_MAX];
1676
1677 snprintf(str, HIST_CONST_DIGITS_MAX, "%llu", field->constant);
1678 strcat(expr, str);
1679 }
Tom Zanussi067fe032018-01-15 20:51:56 -06001680
Tom Zanussi100719d2018-01-15 20:51:52 -06001681 strcat(expr, hist_field_name(field, 0));
1682
Tom Zanussi76690942018-03-28 15:10:54 -05001683 if (field->flags && !(field->flags & HIST_FIELD_FL_VAR_REF)) {
Tom Zanussi100719d2018-01-15 20:51:52 -06001684 const char *flags_str = get_hist_field_flags(field);
1685
1686 if (flags_str) {
1687 strcat(expr, ".");
1688 strcat(expr, flags_str);
1689 }
1690 }
1691}
1692
1693static char *expr_str(struct hist_field *field, unsigned int level)
1694{
1695 char *expr;
1696
1697 if (level > 1)
1698 return NULL;
1699
1700 expr = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
1701 if (!expr)
1702 return NULL;
1703
1704 if (!field->operands[0]) {
1705 expr_field_str(field, expr);
1706 return expr;
1707 }
1708
1709 if (field->operator == FIELD_OP_UNARY_MINUS) {
1710 char *subexpr;
1711
1712 strcat(expr, "-(");
1713 subexpr = expr_str(field->operands[0], ++level);
1714 if (!subexpr) {
1715 kfree(expr);
1716 return NULL;
1717 }
1718 strcat(expr, subexpr);
1719 strcat(expr, ")");
1720
1721 kfree(subexpr);
1722
1723 return expr;
1724 }
1725
1726 expr_field_str(field->operands[0], expr);
1727
1728 switch (field->operator) {
1729 case FIELD_OP_MINUS:
1730 strcat(expr, "-");
1731 break;
1732 case FIELD_OP_PLUS:
1733 strcat(expr, "+");
1734 break;
Kalesh Singhbcef0442021-10-25 13:08:34 -07001735 case FIELD_OP_DIV:
1736 strcat(expr, "/");
1737 break;
1738 case FIELD_OP_MULT:
1739 strcat(expr, "*");
1740 break;
Tom Zanussi100719d2018-01-15 20:51:52 -06001741 default:
1742 kfree(expr);
1743 return NULL;
1744 }
1745
1746 expr_field_str(field->operands[1], expr);
1747
1748 return expr;
1749}
1750
Kalesh Singh9710b2f2021-10-25 13:08:35 -07001751/*
1752 * If field_op != FIELD_OP_NONE, *sep points to the root operator
1753 * of the expression tree to be evaluated.
1754 */
1755static int contains_operator(char *str, char **sep)
Tom Zanussi100719d2018-01-15 20:51:52 -06001756{
1757 enum field_op_id field_op = FIELD_OP_NONE;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07001758 char *minus_op, *plus_op, *div_op, *mult_op;
Tom Zanussi100719d2018-01-15 20:51:52 -06001759
Tom Zanussi100719d2018-01-15 20:51:52 -06001760
Kalesh Singh9710b2f2021-10-25 13:08:35 -07001761 /*
1762 * Report the last occurrence of the operators first, so that the
1763 * expression is evaluated left to right. This is important since
1764 * subtraction and division are not associative.
1765 *
1766 * e.g
1767 * 64/8/4/2 is 1, i.e 64/8/4/2 = ((64/8)/4)/2
1768 * 14-7-5-2 is 0, i.e 14-7-5-2 = ((14-7)-5)-2
1769 */
1770
1771 /*
1772 * First, find lower precedence addition and subtraction
1773 * since the expression will be evaluated recursively.
1774 */
1775 minus_op = strrchr(str, '-');
1776 if (minus_op) {
Steven Rostedt (VMware)26c56372021-07-07 11:08:21 -04001777 /*
Kalesh Singh9710b2f2021-10-25 13:08:35 -07001778 * Unary minus is not supported in sub-expressions. If
1779 * present, it is always the next root operator.
Steven Rostedt (VMware)26c56372021-07-07 11:08:21 -04001780 */
Kalesh Singh9710b2f2021-10-25 13:08:35 -07001781 if (minus_op == str) {
Tom Zanussi100719d2018-01-15 20:51:52 -06001782 field_op = FIELD_OP_UNARY_MINUS;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07001783 goto out;
1784 }
1785
1786 field_op = FIELD_OP_MINUS;
1787 }
1788
1789 plus_op = strrchr(str, '+');
1790 if (plus_op || minus_op) {
1791 /*
1792 * For operators of the same precedence use to rightmost as the
1793 * root, so that the expression is evaluated left to right.
1794 */
1795 if (plus_op > minus_op)
1796 field_op = FIELD_OP_PLUS;
1797 goto out;
1798 }
1799
1800 /*
1801 * Multiplication and division have higher precedence than addition and
1802 * subtraction.
1803 */
1804 div_op = strrchr(str, '/');
1805 if (div_op)
Kalesh Singhbcef0442021-10-25 13:08:34 -07001806 field_op = FIELD_OP_DIV;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07001807
1808 mult_op = strrchr(str, '*');
1809 /*
1810 * For operators of the same precedence use to rightmost as the
1811 * root, so that the expression is evaluated left to right.
1812 */
1813 if (mult_op > div_op)
Kalesh Singhbcef0442021-10-25 13:08:34 -07001814 field_op = FIELD_OP_MULT;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07001815
1816out:
1817 if (sep) {
1818 switch (field_op) {
1819 case FIELD_OP_UNARY_MINUS:
1820 case FIELD_OP_MINUS:
1821 *sep = minus_op;
1822 break;
1823 case FIELD_OP_PLUS:
1824 *sep = plus_op;
1825 break;
1826 case FIELD_OP_DIV:
1827 *sep = div_op;
1828 break;
1829 case FIELD_OP_MULT:
1830 *sep = mult_op;
1831 break;
1832 case FIELD_OP_NONE:
1833 default:
1834 *sep = NULL;
1835 break;
1836 }
Tom Zanussi100719d2018-01-15 20:51:52 -06001837 }
1838
1839 return field_op;
1840}
1841
Steven Rostedt (VMware)8bcebc72020-01-20 13:07:31 -05001842static void get_hist_field(struct hist_field *hist_field)
1843{
1844 hist_field->ref++;
1845}
1846
Tom Zanussi656fe2b2018-12-18 14:33:24 -06001847static void __destroy_hist_field(struct hist_field *hist_field)
1848{
Steven Rostedt (VMware)8bcebc72020-01-20 13:07:31 -05001849 if (--hist_field->ref > 1)
1850 return;
1851
Tom Zanussi656fe2b2018-12-18 14:33:24 -06001852 kfree(hist_field->var.name);
1853 kfree(hist_field->name);
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04001854
1855 /* Can likely be a const */
1856 kfree_const(hist_field->type);
Tom Zanussi656fe2b2018-12-18 14:33:24 -06001857
Vamshi K Sthambamkadi9da73972020-04-22 11:45:06 +05301858 kfree(hist_field->system);
1859 kfree(hist_field->event_name);
1860
Tom Zanussi656fe2b2018-12-18 14:33:24 -06001861 kfree(hist_field);
1862}
1863
Tom Zanussi5819ead2017-09-22 14:58:23 -05001864static void destroy_hist_field(struct hist_field *hist_field,
1865 unsigned int level)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001866{
Tom Zanussi5819ead2017-09-22 14:58:23 -05001867 unsigned int i;
1868
Tom Zanussi100719d2018-01-15 20:51:52 -06001869 if (level > 3)
Tom Zanussi5819ead2017-09-22 14:58:23 -05001870 return;
1871
1872 if (!hist_field)
1873 return;
1874
Tom Zanussi656fe2b2018-12-18 14:33:24 -06001875 if (hist_field->flags & HIST_FIELD_FL_VAR_REF)
1876 return; /* var refs will be destroyed separately */
1877
Tom Zanussi5819ead2017-09-22 14:58:23 -05001878 for (i = 0; i < HIST_FIELD_OPERANDS_MAX; i++)
1879 destroy_hist_field(hist_field->operands[i], level + 1);
1880
Tom Zanussi656fe2b2018-12-18 14:33:24 -06001881 __destroy_hist_field(hist_field);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001882}
1883
Tom Zanussib559d002018-01-15 20:51:47 -06001884static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
1885 struct ftrace_event_field *field,
Tom Zanussi30350d62018-01-15 20:51:49 -06001886 unsigned long flags,
1887 char *var_name)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001888{
1889 struct hist_field *hist_field;
1890
1891 if (field && is_function_field(field))
1892 return NULL;
1893
1894 hist_field = kzalloc(sizeof(struct hist_field), GFP_KERNEL);
1895 if (!hist_field)
1896 return NULL;
1897
Steven Rostedt (VMware)8bcebc72020-01-20 13:07:31 -05001898 hist_field->ref = 1;
1899
Tom Zanussib559d002018-01-15 20:51:47 -06001900 hist_field->hist_data = hist_data;
1901
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06001902 if (flags & HIST_FIELD_FL_EXPR || flags & HIST_FIELD_FL_ALIAS)
Tom Zanussi100719d2018-01-15 20:51:52 -06001903 goto out; /* caller will populate */
1904
Tom Zanussi067fe032018-01-15 20:51:56 -06001905 if (flags & HIST_FIELD_FL_VAR_REF) {
1906 hist_field->fn = hist_field_var_ref;
1907 goto out;
1908 }
1909
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001910 if (flags & HIST_FIELD_FL_HITCOUNT) {
1911 hist_field->fn = hist_field_counter;
Tom Zanussi19a9fac2018-01-15 20:51:55 -06001912 hist_field->size = sizeof(u64);
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04001913 hist_field->type = "u64";
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001914 goto out;
1915 }
1916
Kalesh Singh52cfb372021-10-25 13:08:33 -07001917 if (flags & HIST_FIELD_FL_CONST) {
1918 hist_field->fn = hist_field_const;
1919 hist_field->size = sizeof(u64);
1920 hist_field->type = kstrdup("u64", GFP_KERNEL);
1921 if (!hist_field->type)
1922 goto free;
1923 goto out;
1924 }
1925
Tom Zanussi69a02002016-03-03 12:54:52 -06001926 if (flags & HIST_FIELD_FL_STACKTRACE) {
1927 hist_field->fn = hist_field_none;
1928 goto out;
1929 }
1930
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04001931 if (flags & (HIST_FIELD_FL_LOG2 | HIST_FIELD_FL_BUCKET)) {
1932 unsigned long fl = flags & ~(HIST_FIELD_FL_LOG2 | HIST_FIELD_FL_BUCKET);
1933 hist_field->fn = flags & HIST_FIELD_FL_LOG2 ? hist_field_log2 :
1934 hist_field_bucket;
Tom Zanussi30350d62018-01-15 20:51:49 -06001935 hist_field->operands[0] = create_hist_field(hist_data, field, fl, NULL);
Tom Zanussi5819ead2017-09-22 14:58:23 -05001936 hist_field->size = hist_field->operands[0]->size;
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04001937 hist_field->type = kstrdup_const(hist_field->operands[0]->type, GFP_KERNEL);
Tom Zanussi19a9fac2018-01-15 20:51:55 -06001938 if (!hist_field->type)
1939 goto free;
Namhyung Kim4b94f5b2016-03-03 12:55:02 -06001940 goto out;
1941 }
1942
Tom Zanussiad42feb2018-01-15 20:51:45 -06001943 if (flags & HIST_FIELD_FL_TIMESTAMP) {
1944 hist_field->fn = hist_field_timestamp;
1945 hist_field->size = sizeof(u64);
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04001946 hist_field->type = "u64";
Tom Zanussiad42feb2018-01-15 20:51:45 -06001947 goto out;
1948 }
1949
Tom Zanussi8b7622b2018-01-15 20:52:03 -06001950 if (flags & HIST_FIELD_FL_CPU) {
1951 hist_field->fn = hist_field_cpu;
1952 hist_field->size = sizeof(int);
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04001953 hist_field->type = "unsigned int";
Tom Zanussi8b7622b2018-01-15 20:52:03 -06001954 goto out;
1955 }
1956
Tom Zanussi432480c2016-04-25 14:01:27 -05001957 if (WARN_ON_ONCE(!field))
1958 goto out;
1959
Steven Rostedt (VMware)704adfb2021-07-15 00:02:06 -04001960 /* Pointers to strings are just pointers and dangerous to dereference */
1961 if (is_string_field(field) &&
1962 (field->filter_type != FILTER_PTR_STRING)) {
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001963 flags |= HIST_FIELD_FL_STRING;
Namhyung Kim79e577c2016-03-03 12:54:53 -06001964
Tom Zanussi19a9fac2018-01-15 20:51:55 -06001965 hist_field->size = MAX_FILTER_STR_VAL;
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04001966 hist_field->type = kstrdup_const(field->type, GFP_KERNEL);
Tom Zanussi19a9fac2018-01-15 20:51:55 -06001967 if (!hist_field->type)
1968 goto free;
1969
Masami Hiramatsu63f84ae2021-11-13 01:02:08 +09001970 if (field->filter_type == FILTER_STATIC_STRING) {
Namhyung Kim79e577c2016-03-03 12:54:53 -06001971 hist_field->fn = hist_field_string;
Masami Hiramatsu63f84ae2021-11-13 01:02:08 +09001972 hist_field->size = field->size;
Masami Hiramatsu05770dd2021-11-22 18:30:12 +09001973 } else if (field->filter_type == FILTER_DYN_STRING) {
Namhyung Kim79e577c2016-03-03 12:54:53 -06001974 hist_field->fn = hist_field_dynstring;
Masami Hiramatsu05770dd2021-11-22 18:30:12 +09001975 } else if (field->filter_type == FILTER_RDYN_STRING)
1976 hist_field->fn = hist_field_reldynstring;
Namhyung Kim79e577c2016-03-03 12:54:53 -06001977 else
1978 hist_field->fn = hist_field_pstring;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001979 } else {
Tom Zanussi19a9fac2018-01-15 20:51:55 -06001980 hist_field->size = field->size;
1981 hist_field->is_signed = field->is_signed;
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04001982 hist_field->type = kstrdup_const(field->type, GFP_KERNEL);
Tom Zanussi19a9fac2018-01-15 20:51:55 -06001983 if (!hist_field->type)
1984 goto free;
1985
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001986 hist_field->fn = select_value_fn(field->size,
1987 field->is_signed);
1988 if (!hist_field->fn) {
Tom Zanussi5819ead2017-09-22 14:58:23 -05001989 destroy_hist_field(hist_field, 0);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001990 return NULL;
1991 }
1992 }
1993 out:
1994 hist_field->field = field;
1995 hist_field->flags = flags;
1996
Tom Zanussi30350d62018-01-15 20:51:49 -06001997 if (var_name) {
1998 hist_field->var.name = kstrdup(var_name, GFP_KERNEL);
1999 if (!hist_field->var.name)
2000 goto free;
2001 }
2002
Tom Zanussi7ef224d2016-03-03 12:54:42 -06002003 return hist_field;
Tom Zanussi30350d62018-01-15 20:51:49 -06002004 free:
2005 destroy_hist_field(hist_field, 0);
2006 return NULL;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06002007}
2008
2009static void destroy_hist_fields(struct hist_trigger_data *hist_data)
2010{
2011 unsigned int i;
2012
Tom Zanussi30350d62018-01-15 20:51:49 -06002013 for (i = 0; i < HIST_FIELDS_MAX; i++) {
Tom Zanussi7ef224d2016-03-03 12:54:42 -06002014 if (hist_data->fields[i]) {
Tom Zanussi5819ead2017-09-22 14:58:23 -05002015 destroy_hist_field(hist_data->fields[i], 0);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06002016 hist_data->fields[i] = NULL;
2017 }
2018 }
Tom Zanussi656fe2b2018-12-18 14:33:24 -06002019
2020 for (i = 0; i < hist_data->n_var_refs; i++) {
2021 WARN_ON(!(hist_data->var_refs[i]->flags & HIST_FIELD_FL_VAR_REF));
2022 __destroy_hist_field(hist_data->var_refs[i]);
2023 hist_data->var_refs[i] = NULL;
2024 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06002025}
2026
Tom Zanussi067fe032018-01-15 20:51:56 -06002027static int init_var_ref(struct hist_field *ref_field,
2028 struct hist_field *var_field,
2029 char *system, char *event_name)
2030{
2031 int err = 0;
2032
2033 ref_field->var.idx = var_field->var.idx;
2034 ref_field->var.hist_data = var_field->hist_data;
2035 ref_field->size = var_field->size;
2036 ref_field->is_signed = var_field->is_signed;
2037 ref_field->flags |= var_field->flags &
2038 (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
2039
2040 if (system) {
2041 ref_field->system = kstrdup(system, GFP_KERNEL);
2042 if (!ref_field->system)
2043 return -ENOMEM;
2044 }
2045
2046 if (event_name) {
2047 ref_field->event_name = kstrdup(event_name, GFP_KERNEL);
2048 if (!ref_field->event_name) {
2049 err = -ENOMEM;
2050 goto free;
2051 }
2052 }
2053
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06002054 if (var_field->var.name) {
2055 ref_field->name = kstrdup(var_field->var.name, GFP_KERNEL);
2056 if (!ref_field->name) {
2057 err = -ENOMEM;
2058 goto free;
2059 }
2060 } else if (var_field->name) {
2061 ref_field->name = kstrdup(var_field->name, GFP_KERNEL);
2062 if (!ref_field->name) {
2063 err = -ENOMEM;
2064 goto free;
2065 }
Tom Zanussi067fe032018-01-15 20:51:56 -06002066 }
2067
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04002068 ref_field->type = kstrdup_const(var_field->type, GFP_KERNEL);
Tom Zanussi067fe032018-01-15 20:51:56 -06002069 if (!ref_field->type) {
2070 err = -ENOMEM;
2071 goto free;
2072 }
2073 out:
2074 return err;
2075 free:
2076 kfree(ref_field->system);
2077 kfree(ref_field->event_name);
2078 kfree(ref_field->name);
2079
2080 goto out;
2081}
2082
Tom Zanussid380dcd2020-01-29 21:18:18 -05002083static int find_var_ref_idx(struct hist_trigger_data *hist_data,
2084 struct hist_field *var_field)
2085{
2086 struct hist_field *ref_field;
2087 int i;
2088
2089 for (i = 0; i < hist_data->n_var_refs; i++) {
2090 ref_field = hist_data->var_refs[i];
2091 if (ref_field->var.idx == var_field->var.idx &&
2092 ref_field->var.hist_data == var_field->hist_data)
2093 return i;
2094 }
2095
2096 return -ENOENT;
2097}
2098
Tom Zanusside40f032018-12-18 14:33:23 -06002099/**
2100 * create_var_ref - Create a variable reference and attach it to trigger
2101 * @hist_data: The trigger that will be referencing the variable
2102 * @var_field: The VAR field to create a reference to
2103 * @system: The optional system string
2104 * @event_name: The optional event_name string
2105 *
2106 * Given a variable hist_field, create a VAR_REF hist_field that
2107 * represents a reference to it.
2108 *
2109 * This function also adds the reference to the trigger that
2110 * now references the variable.
2111 *
2112 * Return: The VAR_REF field if successful, NULL if not
2113 */
2114static struct hist_field *create_var_ref(struct hist_trigger_data *hist_data,
2115 struct hist_field *var_field,
Tom Zanussi067fe032018-01-15 20:51:56 -06002116 char *system, char *event_name)
2117{
2118 unsigned long flags = HIST_FIELD_FL_VAR_REF;
2119 struct hist_field *ref_field;
Steven Rostedt (VMware)8bcebc72020-01-20 13:07:31 -05002120 int i;
2121
2122 /* Check if the variable already exists */
2123 for (i = 0; i < hist_data->n_var_refs; i++) {
2124 ref_field = hist_data->var_refs[i];
2125 if (ref_field->var.idx == var_field->var.idx &&
2126 ref_field->var.hist_data == var_field->hist_data) {
2127 get_hist_field(ref_field);
2128 return ref_field;
2129 }
2130 }
Tom Zanussi067fe032018-01-15 20:51:56 -06002131
2132 ref_field = create_hist_field(var_field->hist_data, NULL, flags, NULL);
2133 if (ref_field) {
2134 if (init_var_ref(ref_field, var_field, system, event_name)) {
2135 destroy_hist_field(ref_field, 0);
2136 return NULL;
2137 }
Tom Zanusside40f032018-12-18 14:33:23 -06002138
2139 hist_data->var_refs[hist_data->n_var_refs] = ref_field;
2140 ref_field->var_ref_idx = hist_data->n_var_refs++;
Tom Zanussi067fe032018-01-15 20:51:56 -06002141 }
2142
2143 return ref_field;
2144}
2145
2146static bool is_var_ref(char *var_name)
2147{
2148 if (!var_name || strlen(var_name) < 2 || var_name[0] != '$')
2149 return false;
2150
2151 return true;
2152}
2153
2154static char *field_name_from_var(struct hist_trigger_data *hist_data,
2155 char *var_name)
2156{
2157 char *name, *field;
2158 unsigned int i;
2159
2160 for (i = 0; i < hist_data->attrs->var_defs.n_vars; i++) {
2161 name = hist_data->attrs->var_defs.name[i];
2162
2163 if (strcmp(var_name, name) == 0) {
2164 field = hist_data->attrs->var_defs.expr[i];
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002165 if (contains_operator(field, NULL) || is_var_ref(field))
Tom Zanussi067fe032018-01-15 20:51:56 -06002166 continue;
2167 return field;
2168 }
2169 }
2170
2171 return NULL;
2172}
2173
2174static char *local_field_var_ref(struct hist_trigger_data *hist_data,
2175 char *system, char *event_name,
2176 char *var_name)
2177{
2178 struct trace_event_call *call;
2179
2180 if (system && event_name) {
2181 call = hist_data->event_file->event_call;
2182
2183 if (strcmp(system, call->class->system) != 0)
2184 return NULL;
2185
2186 if (strcmp(event_name, trace_event_name(call)) != 0)
2187 return NULL;
2188 }
2189
2190 if (!!system != !!event_name)
2191 return NULL;
2192
2193 if (!is_var_ref(var_name))
2194 return NULL;
2195
2196 var_name++;
2197
2198 return field_name_from_var(hist_data, var_name);
2199}
2200
2201static struct hist_field *parse_var_ref(struct hist_trigger_data *hist_data,
2202 char *system, char *event_name,
2203 char *var_name)
2204{
2205 struct hist_field *var_field = NULL, *ref_field = NULL;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002206 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussi067fe032018-01-15 20:51:56 -06002207
2208 if (!is_var_ref(var_name))
2209 return NULL;
2210
2211 var_name++;
2212
2213 var_field = find_event_var(hist_data, system, event_name, var_name);
2214 if (var_field)
Tom Zanusside40f032018-12-18 14:33:23 -06002215 ref_field = create_var_ref(hist_data, var_field,
2216 system, event_name);
Tom Zanussi067fe032018-01-15 20:51:56 -06002217
Tom Zanussif404da62018-01-15 20:52:05 -06002218 if (!ref_field)
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002219 hist_err(tr, HIST_ERR_VAR_NOT_FOUND, errpos(var_name));
Tom Zanussif404da62018-01-15 20:52:05 -06002220
Tom Zanussi067fe032018-01-15 20:51:56 -06002221 return ref_field;
2222}
2223
Tom Zanussi100719d2018-01-15 20:51:52 -06002224static struct ftrace_event_field *
2225parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04002226 char *field_str, unsigned long *flags, unsigned long *buckets)
Tom Zanussi100719d2018-01-15 20:51:52 -06002227{
2228 struct ftrace_event_field *field = NULL;
2229 char *field_name, *modifier, *str;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002230 struct trace_array *tr = file->tr;
Tom Zanussi100719d2018-01-15 20:51:52 -06002231
2232 modifier = str = kstrdup(field_str, GFP_KERNEL);
2233 if (!modifier)
2234 return ERR_PTR(-ENOMEM);
2235
2236 field_name = strsep(&modifier, ".");
2237 if (modifier) {
2238 if (strcmp(modifier, "hex") == 0)
2239 *flags |= HIST_FIELD_FL_HEX;
2240 else if (strcmp(modifier, "sym") == 0)
2241 *flags |= HIST_FIELD_FL_SYM;
Kalesh Singhc5eac6e2021-10-25 13:08:36 -07002242 /*
2243 * 'sym-offset' occurrences in the trigger string are modified
2244 * to 'symXoffset' to simplify arithmetic expression parsing.
2245 */
2246 else if (strcmp(modifier, "symXoffset") == 0)
Tom Zanussi100719d2018-01-15 20:51:52 -06002247 *flags |= HIST_FIELD_FL_SYM_OFFSET;
2248 else if ((strcmp(modifier, "execname") == 0) &&
2249 (strcmp(field_name, "common_pid") == 0))
2250 *flags |= HIST_FIELD_FL_EXECNAME;
2251 else if (strcmp(modifier, "syscall") == 0)
2252 *flags |= HIST_FIELD_FL_SYSCALL;
2253 else if (strcmp(modifier, "log2") == 0)
2254 *flags |= HIST_FIELD_FL_LOG2;
2255 else if (strcmp(modifier, "usecs") == 0)
2256 *flags |= HIST_FIELD_FL_TIMESTAMP_USECS;
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04002257 else if (strncmp(modifier, "bucket", 6) == 0) {
2258 int ret;
2259
2260 modifier += 6;
2261
2262 if (*modifier == 's')
2263 modifier++;
2264 if (*modifier != '=')
2265 goto error;
2266 modifier++;
2267 ret = kstrtoul(modifier, 0, buckets);
2268 if (ret || !(*buckets))
2269 goto error;
2270 *flags |= HIST_FIELD_FL_BUCKET;
2271 } else {
2272 error:
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002273 hist_err(tr, HIST_ERR_BAD_FIELD_MODIFIER, errpos(modifier));
Tom Zanussi100719d2018-01-15 20:51:52 -06002274 field = ERR_PTR(-EINVAL);
2275 goto out;
2276 }
2277 }
2278
2279 if (strcmp(field_name, "common_timestamp") == 0) {
2280 *flags |= HIST_FIELD_FL_TIMESTAMP;
2281 hist_data->enable_timestamps = true;
2282 if (*flags & HIST_FIELD_FL_TIMESTAMP_USECS)
2283 hist_data->attrs->ts_in_usecs = true;
Steven Rostedt (VMware)1e3bac72021-07-21 11:00:53 -04002284 } else if (strcmp(field_name, "common_cpu") == 0)
Tom Zanussi8b7622b2018-01-15 20:52:03 -06002285 *flags |= HIST_FIELD_FL_CPU;
2286 else {
Tom Zanussi100719d2018-01-15 20:51:52 -06002287 field = trace_find_event_field(file->event_call, field_name);
2288 if (!field || !field->size) {
Steven Rostedt (VMware)1e3bac72021-07-21 11:00:53 -04002289 /*
2290 * For backward compatibility, if field_name
2291 * was "cpu", then we treat this the same as
2292 * common_cpu.
2293 */
2294 if (strcmp(field_name, "cpu") == 0) {
2295 *flags |= HIST_FIELD_FL_CPU;
2296 } else {
2297 hist_err(tr, HIST_ERR_FIELD_NOT_FOUND,
2298 errpos(field_name));
2299 field = ERR_PTR(-EINVAL);
2300 goto out;
2301 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002302 }
2303 }
2304 out:
2305 kfree(str);
2306
2307 return field;
2308}
2309
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06002310static struct hist_field *create_alias(struct hist_trigger_data *hist_data,
2311 struct hist_field *var_ref,
2312 char *var_name)
2313{
2314 struct hist_field *alias = NULL;
2315 unsigned long flags = HIST_FIELD_FL_ALIAS | HIST_FIELD_FL_VAR;
2316
2317 alias = create_hist_field(hist_data, NULL, flags, var_name);
2318 if (!alias)
2319 return NULL;
2320
2321 alias->fn = var_ref->fn;
2322 alias->operands[0] = var_ref;
2323
2324 if (init_var_ref(alias, var_ref, var_ref->system, var_ref->event_name)) {
2325 destroy_hist_field(alias, 0);
2326 return NULL;
2327 }
2328
Tom Zanussi17f86072019-09-01 17:02:01 -05002329 alias->var_ref_idx = var_ref->var_ref_idx;
2330
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06002331 return alias;
2332}
2333
Kalesh Singh52cfb372021-10-25 13:08:33 -07002334static struct hist_field *parse_const(struct hist_trigger_data *hist_data,
2335 char *str, char *var_name,
2336 unsigned long *flags)
2337{
2338 struct trace_array *tr = hist_data->event_file->tr;
2339 struct hist_field *field = NULL;
2340 u64 constant;
2341
2342 if (kstrtoull(str, 0, &constant)) {
2343 hist_err(tr, HIST_ERR_EXPECT_NUMBER, errpos(str));
2344 return NULL;
2345 }
2346
2347 *flags |= HIST_FIELD_FL_CONST;
2348 field = create_hist_field(hist_data, NULL, *flags, var_name);
2349 if (!field)
2350 return NULL;
2351
2352 field->constant = constant;
2353
2354 return field;
2355}
2356
Tom Zanussi100719d2018-01-15 20:51:52 -06002357static struct hist_field *parse_atom(struct hist_trigger_data *hist_data,
2358 struct trace_event_file *file, char *str,
2359 unsigned long *flags, char *var_name)
2360{
Tom Zanussi067fe032018-01-15 20:51:56 -06002361 char *s, *ref_system = NULL, *ref_event = NULL, *ref_var = str;
Tom Zanussi100719d2018-01-15 20:51:52 -06002362 struct ftrace_event_field *field = NULL;
2363 struct hist_field *hist_field = NULL;
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04002364 unsigned long buckets = 0;
Tom Zanussi100719d2018-01-15 20:51:52 -06002365 int ret = 0;
2366
Kalesh Singh52cfb372021-10-25 13:08:33 -07002367 if (isdigit(str[0])) {
2368 hist_field = parse_const(hist_data, str, var_name, flags);
2369 if (!hist_field) {
2370 ret = -EINVAL;
2371 goto out;
2372 }
2373 return hist_field;
2374 }
2375
Tom Zanussi067fe032018-01-15 20:51:56 -06002376 s = strchr(str, '.');
2377 if (s) {
2378 s = strchr(++s, '.');
2379 if (s) {
2380 ref_system = strsep(&str, ".");
2381 if (!str) {
2382 ret = -EINVAL;
2383 goto out;
2384 }
2385 ref_event = strsep(&str, ".");
2386 if (!str) {
2387 ret = -EINVAL;
2388 goto out;
2389 }
2390 ref_var = str;
2391 }
2392 }
2393
2394 s = local_field_var_ref(hist_data, ref_system, ref_event, ref_var);
2395 if (!s) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002396 hist_field = parse_var_ref(hist_data, ref_system,
2397 ref_event, ref_var);
Tom Zanussi067fe032018-01-15 20:51:56 -06002398 if (hist_field) {
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06002399 if (var_name) {
2400 hist_field = create_alias(hist_data, hist_field, var_name);
2401 if (!hist_field) {
2402 ret = -ENOMEM;
2403 goto out;
2404 }
2405 }
Tom Zanussi067fe032018-01-15 20:51:56 -06002406 return hist_field;
2407 }
2408 } else
2409 str = s;
2410
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04002411 field = parse_field(hist_data, file, str, flags, &buckets);
Tom Zanussi100719d2018-01-15 20:51:52 -06002412 if (IS_ERR(field)) {
2413 ret = PTR_ERR(field);
2414 goto out;
2415 }
2416
2417 hist_field = create_hist_field(hist_data, field, *flags, var_name);
2418 if (!hist_field) {
2419 ret = -ENOMEM;
2420 goto out;
2421 }
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04002422 hist_field->buckets = buckets;
Tom Zanussi100719d2018-01-15 20:51:52 -06002423
2424 return hist_field;
2425 out:
2426 return ERR_PTR(ret);
2427}
2428
2429static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
2430 struct trace_event_file *file,
2431 char *str, unsigned long flags,
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002432 char *var_name, unsigned int *n_subexprs);
Tom Zanussi100719d2018-01-15 20:51:52 -06002433
2434static struct hist_field *parse_unary(struct hist_trigger_data *hist_data,
2435 struct trace_event_file *file,
2436 char *str, unsigned long flags,
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002437 char *var_name, unsigned int *n_subexprs)
Tom Zanussi100719d2018-01-15 20:51:52 -06002438{
2439 struct hist_field *operand1, *expr = NULL;
2440 unsigned long operand_flags;
2441 int ret = 0;
2442 char *s;
2443
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002444 /* Unary minus operator, increment n_subexprs */
2445 ++*n_subexprs;
2446
Tom Zanussi100719d2018-01-15 20:51:52 -06002447 /* we support only -(xxx) i.e. explicit parens required */
2448
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002449 if (*n_subexprs > 3) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002450 hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str));
Tom Zanussi100719d2018-01-15 20:51:52 -06002451 ret = -EINVAL;
2452 goto free;
2453 }
2454
2455 str++; /* skip leading '-' */
2456
2457 s = strchr(str, '(');
2458 if (s)
2459 str++;
2460 else {
2461 ret = -EINVAL;
2462 goto free;
2463 }
2464
2465 s = strrchr(str, ')');
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002466 if (s) {
2467 /* unary minus not supported in sub-expressions */
2468 if (*(s+1) != '\0') {
2469 hist_err(file->tr, HIST_ERR_UNARY_MINUS_SUBEXPR,
2470 errpos(str));
2471 ret = -EINVAL;
2472 goto free;
2473 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002474 *s = '\0';
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002475 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002476 else {
2477 ret = -EINVAL; /* no closing ')' */
2478 goto free;
2479 }
2480
2481 flags |= HIST_FIELD_FL_EXPR;
2482 expr = create_hist_field(hist_data, NULL, flags, var_name);
2483 if (!expr) {
2484 ret = -ENOMEM;
2485 goto free;
2486 }
2487
2488 operand_flags = 0;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002489 operand1 = parse_expr(hist_data, file, str, operand_flags, NULL, n_subexprs);
Tom Zanussi100719d2018-01-15 20:51:52 -06002490 if (IS_ERR(operand1)) {
2491 ret = PTR_ERR(operand1);
2492 goto free;
2493 }
Masami Hiramatsua9d10ca2021-07-28 07:55:43 +09002494 if (operand1->flags & HIST_FIELD_FL_STRING) {
2495 /* String type can not be the operand of unary operator. */
2496 hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(str));
2497 destroy_hist_field(operand1, 0);
2498 ret = -EINVAL;
2499 goto free;
2500 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002501
2502 expr->flags |= operand1->flags &
2503 (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
2504 expr->fn = hist_field_unary_minus;
2505 expr->operands[0] = operand1;
Tom Zanussi097f1ee2022-01-27 15:44:17 -06002506 expr->size = operand1->size;
2507 expr->is_signed = operand1->is_signed;
Tom Zanussi100719d2018-01-15 20:51:52 -06002508 expr->operator = FIELD_OP_UNARY_MINUS;
2509 expr->name = expr_str(expr, 0);
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04002510 expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
Tom Zanussi19a9fac2018-01-15 20:51:55 -06002511 if (!expr->type) {
2512 ret = -ENOMEM;
2513 goto free;
2514 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002515
2516 return expr;
2517 free:
2518 destroy_hist_field(expr, 0);
2519 return ERR_PTR(ret);
2520}
2521
Kalesh Singhf47716b2021-10-25 13:08:37 -07002522/*
2523 * If the operands are var refs, return pointers the
2524 * variable(s) referenced in var1 and var2, else NULL.
2525 */
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002526static int check_expr_operands(struct trace_array *tr,
2527 struct hist_field *operand1,
Kalesh Singhf47716b2021-10-25 13:08:37 -07002528 struct hist_field *operand2,
2529 struct hist_field **var1,
2530 struct hist_field **var2)
Tom Zanussi100719d2018-01-15 20:51:52 -06002531{
2532 unsigned long operand1_flags = operand1->flags;
2533 unsigned long operand2_flags = operand2->flags;
2534
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06002535 if ((operand1_flags & HIST_FIELD_FL_VAR_REF) ||
2536 (operand1_flags & HIST_FIELD_FL_ALIAS)) {
2537 struct hist_field *var;
2538
2539 var = find_var_field(operand1->var.hist_data, operand1->name);
2540 if (!var)
2541 return -EINVAL;
2542 operand1_flags = var->flags;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002543 *var1 = var;
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06002544 }
2545
2546 if ((operand2_flags & HIST_FIELD_FL_VAR_REF) ||
2547 (operand2_flags & HIST_FIELD_FL_ALIAS)) {
2548 struct hist_field *var;
2549
2550 var = find_var_field(operand2->var.hist_data, operand2->name);
2551 if (!var)
2552 return -EINVAL;
2553 operand2_flags = var->flags;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002554 *var2 = var;
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06002555 }
2556
Tom Zanussi100719d2018-01-15 20:51:52 -06002557 if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS) !=
Tom Zanussif404da62018-01-15 20:52:05 -06002558 (operand2_flags & HIST_FIELD_FL_TIMESTAMP_USECS)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002559 hist_err(tr, HIST_ERR_TIMESTAMP_MISMATCH, 0);
Tom Zanussi100719d2018-01-15 20:51:52 -06002560 return -EINVAL;
Tom Zanussif404da62018-01-15 20:52:05 -06002561 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002562
2563 return 0;
2564}
2565
2566static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
2567 struct trace_event_file *file,
2568 char *str, unsigned long flags,
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002569 char *var_name, unsigned int *n_subexprs)
Tom Zanussi100719d2018-01-15 20:51:52 -06002570{
2571 struct hist_field *operand1 = NULL, *operand2 = NULL, *expr = NULL;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002572 struct hist_field *var1 = NULL, *var2 = NULL;
2573 unsigned long operand_flags, operand2_flags;
Tom Zanussi100719d2018-01-15 20:51:52 -06002574 int field_op, ret = -EINVAL;
2575 char *sep, *operand1_str;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002576 hist_field_fn_t op_fn;
2577 bool combine_consts;
Tom Zanussi100719d2018-01-15 20:51:52 -06002578
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002579 if (*n_subexprs > 3) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002580 hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str));
Tom Zanussi100719d2018-01-15 20:51:52 -06002581 return ERR_PTR(-EINVAL);
Tom Zanussif404da62018-01-15 20:52:05 -06002582 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002583
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002584 field_op = contains_operator(str, &sep);
Tom Zanussi100719d2018-01-15 20:51:52 -06002585
2586 if (field_op == FIELD_OP_NONE)
2587 return parse_atom(hist_data, file, str, &flags, var_name);
2588
2589 if (field_op == FIELD_OP_UNARY_MINUS)
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002590 return parse_unary(hist_data, file, str, flags, var_name, n_subexprs);
Tom Zanussi100719d2018-01-15 20:51:52 -06002591
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002592 /* Binary operator found, increment n_subexprs */
2593 ++*n_subexprs;
2594
2595 /* Split the expression string at the root operator */
2596 if (!sep)
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002597 return ERR_PTR(-EINVAL);
2598
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002599 *sep = '\0';
2600 operand1_str = str;
2601 str = sep+1;
Tom Zanussi100719d2018-01-15 20:51:52 -06002602
Kalesh Singh1cab6bc2021-11-12 11:13:24 -08002603 /* Binary operator requires both operands */
2604 if (*operand1_str == '\0' || *str == '\0')
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002605 return ERR_PTR(-EINVAL);
Tom Zanussi100719d2018-01-15 20:51:52 -06002606
2607 operand_flags = 0;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002608
2609 /* LHS of string is an expression e.g. a+b in a+b+c */
2610 operand1 = parse_expr(hist_data, file, operand1_str, operand_flags, NULL, n_subexprs);
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002611 if (IS_ERR(operand1))
2612 return ERR_CAST(operand1);
2613
Masami Hiramatsua9d10ca2021-07-28 07:55:43 +09002614 if (operand1->flags & HIST_FIELD_FL_STRING) {
2615 hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(operand1_str));
2616 ret = -EINVAL;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002617 goto free_op1;
Masami Hiramatsua9d10ca2021-07-28 07:55:43 +09002618 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002619
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002620 /* RHS of string is another expression e.g. c in a+b+c */
Tom Zanussi100719d2018-01-15 20:51:52 -06002621 operand_flags = 0;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002622 operand2 = parse_expr(hist_data, file, str, operand_flags, NULL, n_subexprs);
Tom Zanussi100719d2018-01-15 20:51:52 -06002623 if (IS_ERR(operand2)) {
2624 ret = PTR_ERR(operand2);
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002625 goto free_op1;
Tom Zanussi100719d2018-01-15 20:51:52 -06002626 }
Masami Hiramatsua9d10ca2021-07-28 07:55:43 +09002627 if (operand2->flags & HIST_FIELD_FL_STRING) {
2628 hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(str));
2629 ret = -EINVAL;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002630 goto free_operands;
Masami Hiramatsua9d10ca2021-07-28 07:55:43 +09002631 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002632
Kalesh Singhf47716b2021-10-25 13:08:37 -07002633 switch (field_op) {
2634 case FIELD_OP_MINUS:
2635 op_fn = hist_field_minus;
2636 break;
2637 case FIELD_OP_PLUS:
2638 op_fn = hist_field_plus;
2639 break;
2640 case FIELD_OP_DIV:
2641 op_fn = hist_field_div;
2642 break;
2643 case FIELD_OP_MULT:
2644 op_fn = hist_field_mult;
2645 break;
2646 default:
2647 ret = -EINVAL;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002648 goto free_operands;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002649 }
2650
2651 ret = check_expr_operands(file->tr, operand1, operand2, &var1, &var2);
Tom Zanussi100719d2018-01-15 20:51:52 -06002652 if (ret)
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002653 goto free_operands;
Tom Zanussi100719d2018-01-15 20:51:52 -06002654
Kalesh Singhf47716b2021-10-25 13:08:37 -07002655 operand_flags = var1 ? var1->flags : operand1->flags;
2656 operand2_flags = var2 ? var2->flags : operand2->flags;
2657
2658 /*
2659 * If both operands are constant, the expression can be
2660 * collapsed to a single constant.
2661 */
2662 combine_consts = operand_flags & operand2_flags & HIST_FIELD_FL_CONST;
2663
2664 flags |= combine_consts ? HIST_FIELD_FL_CONST : HIST_FIELD_FL_EXPR;
Tom Zanussi100719d2018-01-15 20:51:52 -06002665
2666 flags |= operand1->flags &
2667 (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
2668
2669 expr = create_hist_field(hist_data, NULL, flags, var_name);
2670 if (!expr) {
2671 ret = -ENOMEM;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002672 goto free_operands;
Tom Zanussi100719d2018-01-15 20:51:52 -06002673 }
2674
Tom Zanussi067fe032018-01-15 20:51:56 -06002675 operand1->read_once = true;
2676 operand2->read_once = true;
2677
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002678 /* The operands are now owned and free'd by 'expr' */
Tom Zanussi100719d2018-01-15 20:51:52 -06002679 expr->operands[0] = operand1;
2680 expr->operands[1] = operand2;
Steven Rostedt (VMware)2c05caa2021-07-30 17:19:51 -04002681
Kalesh Singh8b5d46f2021-10-29 16:24:10 -07002682 if (field_op == FIELD_OP_DIV &&
2683 operand2_flags & HIST_FIELD_FL_CONST) {
2684 u64 divisor = var2 ? var2->constant : operand2->constant;
2685
2686 if (!divisor) {
2687 hist_err(file->tr, HIST_ERR_DIVISION_BY_ZERO, errpos(str));
2688 ret = -EDOM;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002689 goto free_expr;
Kalesh Singh8b5d46f2021-10-29 16:24:10 -07002690 }
2691
2692 /*
2693 * Copy the divisor here so we don't have to look it up
2694 * later if this is a var ref
2695 */
2696 operand2->constant = divisor;
2697 op_fn = hist_field_get_div_fn(operand2);
2698 }
2699
Kalesh Singhf47716b2021-10-25 13:08:37 -07002700 if (combine_consts) {
2701 if (var1)
2702 expr->operands[0] = var1;
2703 if (var2)
2704 expr->operands[1] = var2;
Steven Rostedt (VMware)2c05caa2021-07-30 17:19:51 -04002705
Kalesh Singhf47716b2021-10-25 13:08:37 -07002706 expr->constant = op_fn(expr, NULL, NULL, NULL, NULL);
Tom Zanussi100719d2018-01-15 20:51:52 -06002707
Kalesh Singhf47716b2021-10-25 13:08:37 -07002708 expr->operands[0] = NULL;
2709 expr->operands[1] = NULL;
2710
2711 /*
2712 * var refs won't be destroyed immediately
2713 * See: destroy_hist_field()
2714 */
2715 destroy_hist_field(operand2, 0);
2716 destroy_hist_field(operand1, 0);
2717
2718 expr->name = expr_str(expr, 0);
2719 } else {
2720 expr->fn = op_fn;
2721
2722 /* The operand sizes should be the same, so just pick one */
2723 expr->size = operand1->size;
Tom Zanussi097f1ee2022-01-27 15:44:17 -06002724 expr->is_signed = operand1->is_signed;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002725
2726 expr->operator = field_op;
2727 expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
2728 if (!expr->type) {
2729 ret = -ENOMEM;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002730 goto free_expr;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002731 }
2732
2733 expr->name = expr_str(expr, 0);
Tom Zanussi100719d2018-01-15 20:51:52 -06002734 }
2735
2736 return expr;
Tom Zanussi100719d2018-01-15 20:51:52 -06002737
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002738free_operands:
2739 destroy_hist_field(operand2, 0);
2740free_op1:
2741 destroy_hist_field(operand1, 0);
2742 return ERR_PTR(ret);
2743
2744free_expr:
2745 destroy_hist_field(expr, 0);
Tom Zanussi100719d2018-01-15 20:51:52 -06002746 return ERR_PTR(ret);
2747}
2748
Tom Zanussi02205a62018-01-15 20:51:59 -06002749static char *find_trigger_filter(struct hist_trigger_data *hist_data,
2750 struct trace_event_file *file)
2751{
2752 struct event_trigger_data *test;
2753
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09002754 lockdep_assert_held(&event_mutex);
2755
2756 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi02205a62018-01-15 20:51:59 -06002757 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
2758 if (test->private_data == hist_data)
2759 return test->filter_str;
2760 }
2761 }
2762
2763 return NULL;
2764}
2765
2766static struct event_command trigger_hist_cmd;
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06002767static int event_hist_trigger_parse(struct event_command *cmd_ops,
2768 struct trace_event_file *file,
2769 char *glob, char *cmd, char *param);
Tom Zanussi02205a62018-01-15 20:51:59 -06002770
2771static bool compatible_keys(struct hist_trigger_data *target_hist_data,
2772 struct hist_trigger_data *hist_data,
2773 unsigned int n_keys)
2774{
2775 struct hist_field *target_hist_field, *hist_field;
2776 unsigned int n, i, j;
2777
2778 if (hist_data->n_fields - hist_data->n_vals != n_keys)
2779 return false;
2780
2781 i = hist_data->n_vals;
2782 j = target_hist_data->n_vals;
2783
2784 for (n = 0; n < n_keys; n++) {
2785 hist_field = hist_data->fields[i + n];
2786 target_hist_field = target_hist_data->fields[j + n];
2787
2788 if (strcmp(hist_field->type, target_hist_field->type) != 0)
2789 return false;
2790 if (hist_field->size != target_hist_field->size)
2791 return false;
2792 if (hist_field->is_signed != target_hist_field->is_signed)
2793 return false;
2794 }
2795
2796 return true;
2797}
2798
2799static struct hist_trigger_data *
2800find_compatible_hist(struct hist_trigger_data *target_hist_data,
2801 struct trace_event_file *file)
2802{
2803 struct hist_trigger_data *hist_data;
2804 struct event_trigger_data *test;
2805 unsigned int n_keys;
2806
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09002807 lockdep_assert_held(&event_mutex);
2808
Tom Zanussi02205a62018-01-15 20:51:59 -06002809 n_keys = target_hist_data->n_fields - target_hist_data->n_vals;
2810
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09002811 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi02205a62018-01-15 20:51:59 -06002812 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
2813 hist_data = test->private_data;
2814
2815 if (compatible_keys(target_hist_data, hist_data, n_keys))
2816 return hist_data;
2817 }
2818 }
2819
2820 return NULL;
2821}
2822
2823static struct trace_event_file *event_file(struct trace_array *tr,
2824 char *system, char *event_name)
2825{
2826 struct trace_event_file *file;
2827
Steven Rostedt (VMware)3be4c1e2018-05-10 12:42:10 -04002828 file = __find_event_file(tr, system, event_name);
Tom Zanussi02205a62018-01-15 20:51:59 -06002829 if (!file)
2830 return ERR_PTR(-EINVAL);
2831
2832 return file;
2833}
2834
2835static struct hist_field *
2836find_synthetic_field_var(struct hist_trigger_data *target_hist_data,
2837 char *system, char *event_name, char *field_name)
2838{
2839 struct hist_field *event_var;
2840 char *synthetic_name;
2841
2842 synthetic_name = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
2843 if (!synthetic_name)
2844 return ERR_PTR(-ENOMEM);
2845
2846 strcpy(synthetic_name, "synthetic_");
2847 strcat(synthetic_name, field_name);
2848
2849 event_var = find_event_var(target_hist_data, system, event_name, synthetic_name);
2850
2851 kfree(synthetic_name);
2852
2853 return event_var;
2854}
2855
2856/**
2857 * create_field_var_hist - Automatically create a histogram and var for a field
2858 * @target_hist_data: The target hist trigger
2859 * @subsys_name: Optional subsystem name
2860 * @event_name: Optional event name
2861 * @field_name: The name of the field (and the resulting variable)
2862 *
2863 * Hist trigger actions fetch data from variables, not directly from
2864 * events. However, for convenience, users are allowed to directly
2865 * specify an event field in an action, which will be automatically
2866 * converted into a variable on their behalf.
Colin Ian Kingb26503b2021-10-06 18:28:30 +01002867 *
Tom Zanussi02205a62018-01-15 20:51:59 -06002868 * If a user specifies a field on an event that isn't the event the
2869 * histogram currently being defined (the target event histogram), the
2870 * only way that can be accomplished is if a new hist trigger is
2871 * created and the field variable defined on that.
2872 *
2873 * This function creates a new histogram compatible with the target
2874 * event (meaning a histogram with the same key as the target
2875 * histogram), and creates a variable for the specified field, but
2876 * with 'synthetic_' prepended to the variable name in order to avoid
2877 * collision with normal field variables.
2878 *
2879 * Return: The variable created for the field.
2880 */
Tom Zanussic282a382018-01-15 20:52:00 -06002881static struct hist_field *
Tom Zanussi02205a62018-01-15 20:51:59 -06002882create_field_var_hist(struct hist_trigger_data *target_hist_data,
2883 char *subsys_name, char *event_name, char *field_name)
2884{
2885 struct trace_array *tr = target_hist_data->event_file->tr;
Tom Zanussi02205a62018-01-15 20:51:59 -06002886 struct hist_trigger_data *hist_data;
2887 unsigned int i, n, first = true;
2888 struct field_var_hist *var_hist;
2889 struct trace_event_file *file;
2890 struct hist_field *key_field;
Jiapeng Chong614db492021-05-08 18:37:16 +08002891 struct hist_field *event_var;
Tom Zanussi02205a62018-01-15 20:51:59 -06002892 char *saved_filter;
2893 char *cmd;
2894 int ret;
2895
Tom Zanussif404da62018-01-15 20:52:05 -06002896 if (target_hist_data->n_field_var_hists >= SYNTH_FIELDS_MAX) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002897 hist_err(tr, HIST_ERR_TOO_MANY_FIELD_VARS, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06002898 return ERR_PTR(-EINVAL);
Tom Zanussif404da62018-01-15 20:52:05 -06002899 }
Tom Zanussi02205a62018-01-15 20:51:59 -06002900
2901 file = event_file(tr, subsys_name, event_name);
2902
2903 if (IS_ERR(file)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002904 hist_err(tr, HIST_ERR_EVENT_FILE_NOT_FOUND, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06002905 ret = PTR_ERR(file);
2906 return ERR_PTR(ret);
2907 }
2908
2909 /*
2910 * Look for a histogram compatible with target. We'll use the
2911 * found histogram specification to create a new matching
2912 * histogram with our variable on it. target_hist_data is not
2913 * yet a registered histogram so we can't use that.
2914 */
2915 hist_data = find_compatible_hist(target_hist_data, file);
Tom Zanussif404da62018-01-15 20:52:05 -06002916 if (!hist_data) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002917 hist_err(tr, HIST_ERR_HIST_NOT_FOUND, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06002918 return ERR_PTR(-EINVAL);
Tom Zanussif404da62018-01-15 20:52:05 -06002919 }
Tom Zanussi02205a62018-01-15 20:51:59 -06002920
2921 /* See if a synthetic field variable has already been created */
2922 event_var = find_synthetic_field_var(target_hist_data, subsys_name,
2923 event_name, field_name);
2924 if (!IS_ERR_OR_NULL(event_var))
2925 return event_var;
2926
2927 var_hist = kzalloc(sizeof(*var_hist), GFP_KERNEL);
2928 if (!var_hist)
2929 return ERR_PTR(-ENOMEM);
2930
2931 cmd = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
2932 if (!cmd) {
2933 kfree(var_hist);
2934 return ERR_PTR(-ENOMEM);
2935 }
2936
2937 /* Use the same keys as the compatible histogram */
2938 strcat(cmd, "keys=");
2939
2940 for_each_hist_key_field(i, hist_data) {
2941 key_field = hist_data->fields[i];
2942 if (!first)
2943 strcat(cmd, ",");
2944 strcat(cmd, key_field->field->name);
2945 first = false;
2946 }
2947
2948 /* Create the synthetic field variable specification */
2949 strcat(cmd, ":synthetic_");
2950 strcat(cmd, field_name);
2951 strcat(cmd, "=");
2952 strcat(cmd, field_name);
2953
2954 /* Use the same filter as the compatible histogram */
2955 saved_filter = find_trigger_filter(hist_data, file);
2956 if (saved_filter) {
2957 strcat(cmd, " if ");
2958 strcat(cmd, saved_filter);
2959 }
2960
2961 var_hist->cmd = kstrdup(cmd, GFP_KERNEL);
2962 if (!var_hist->cmd) {
2963 kfree(cmd);
2964 kfree(var_hist);
2965 return ERR_PTR(-ENOMEM);
2966 }
2967
2968 /* Save the compatible histogram information */
2969 var_hist->hist_data = hist_data;
2970
2971 /* Create the new histogram with our variable */
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06002972 ret = event_hist_trigger_parse(&trigger_hist_cmd, file,
2973 "", "hist", cmd);
Tom Zanussi02205a62018-01-15 20:51:59 -06002974 if (ret) {
2975 kfree(cmd);
2976 kfree(var_hist->cmd);
2977 kfree(var_hist);
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002978 hist_err(tr, HIST_ERR_HIST_CREATE_FAIL, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06002979 return ERR_PTR(ret);
2980 }
2981
2982 kfree(cmd);
2983
2984 /* If we can't find the variable, something went wrong */
2985 event_var = find_synthetic_field_var(target_hist_data, subsys_name,
2986 event_name, field_name);
2987 if (IS_ERR_OR_NULL(event_var)) {
2988 kfree(var_hist->cmd);
2989 kfree(var_hist);
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002990 hist_err(tr, HIST_ERR_SYNTH_VAR_NOT_FOUND, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06002991 return ERR_PTR(-EINVAL);
2992 }
2993
2994 n = target_hist_data->n_field_var_hists;
2995 target_hist_data->field_var_hists[n] = var_hist;
2996 target_hist_data->n_field_var_hists++;
2997
2998 return event_var;
2999}
3000
Tom Zanussic282a382018-01-15 20:52:00 -06003001static struct hist_field *
Tom Zanussi02205a62018-01-15 20:51:59 -06003002find_target_event_var(struct hist_trigger_data *hist_data,
3003 char *subsys_name, char *event_name, char *var_name)
3004{
3005 struct trace_event_file *file = hist_data->event_file;
3006 struct hist_field *hist_field = NULL;
3007
3008 if (subsys_name) {
3009 struct trace_event_call *call;
3010
3011 if (!event_name)
3012 return NULL;
3013
3014 call = file->event_call;
3015
3016 if (strcmp(subsys_name, call->class->system) != 0)
3017 return NULL;
3018
3019 if (strcmp(event_name, trace_event_name(call)) != 0)
3020 return NULL;
3021 }
3022
3023 hist_field = find_var_field(hist_data, var_name);
3024
3025 return hist_field;
3026}
3027
3028static inline void __update_field_vars(struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003029 struct trace_buffer *buffer,
Tom Zanussi02205a62018-01-15 20:51:59 -06003030 struct ring_buffer_event *rbe,
3031 void *rec,
3032 struct field_var **field_vars,
3033 unsigned int n_field_vars,
3034 unsigned int field_var_str_start)
3035{
3036 struct hist_elt_data *elt_data = elt->private_data;
3037 unsigned int i, j, var_idx;
3038 u64 var_val;
3039
3040 for (i = 0, j = field_var_str_start; i < n_field_vars; i++) {
3041 struct field_var *field_var = field_vars[i];
3042 struct hist_field *var = field_var->var;
3043 struct hist_field *val = field_var->val;
3044
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003045 var_val = val->fn(val, elt, buffer, rbe, rec);
Tom Zanussi02205a62018-01-15 20:51:59 -06003046 var_idx = var->var.idx;
3047
3048 if (val->flags & HIST_FIELD_FL_STRING) {
3049 char *str = elt_data->field_var_str[j++];
3050 char *val_str = (char *)(uintptr_t)var_val;
Steven Rostedt (VMware)938aa332021-11-14 13:28:34 -05003051 unsigned int size;
Tom Zanussi02205a62018-01-15 20:51:59 -06003052
Steven Rostedt (VMware)938aa332021-11-14 13:28:34 -05003053 size = min(val->size, STR_VAR_LEN_MAX);
3054 strscpy(str, val_str, size);
Tom Zanussi02205a62018-01-15 20:51:59 -06003055 var_val = (u64)(uintptr_t)str;
3056 }
3057 tracing_map_set_var(elt, var_idx, var_val);
3058 }
3059}
3060
3061static void update_field_vars(struct hist_trigger_data *hist_data,
3062 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003063 struct trace_buffer *buffer,
Tom Zanussi02205a62018-01-15 20:51:59 -06003064 struct ring_buffer_event *rbe,
3065 void *rec)
3066{
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003067 __update_field_vars(elt, buffer, rbe, rec, hist_data->field_vars,
Tom Zanussi02205a62018-01-15 20:51:59 -06003068 hist_data->n_field_vars, 0);
3069}
3070
Tom Zanussi466f4522019-02-13 17:42:44 -06003071static void save_track_data_vars(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003072 struct tracing_map_elt *elt,
3073 struct trace_buffer *buffer, void *rec,
Tom Zanussi466f4522019-02-13 17:42:44 -06003074 struct ring_buffer_event *rbe, void *key,
3075 struct action_data *data, u64 *var_ref_vals)
Tom Zanussi50450602018-01-15 20:52:01 -06003076{
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003077 __update_field_vars(elt, buffer, rbe, rec, hist_data->save_vars,
Tom Zanussi7d18a102019-02-13 17:42:41 -06003078 hist_data->n_save_vars, hist_data->n_field_var_str);
Tom Zanussi50450602018-01-15 20:52:01 -06003079}
3080
Tom Zanussi02205a62018-01-15 20:51:59 -06003081static struct hist_field *create_var(struct hist_trigger_data *hist_data,
3082 struct trace_event_file *file,
3083 char *name, int size, const char *type)
3084{
3085 struct hist_field *var;
3086 int idx;
3087
3088 if (find_var(hist_data, file, name) && !hist_data->remove) {
3089 var = ERR_PTR(-EINVAL);
3090 goto out;
3091 }
3092
3093 var = kzalloc(sizeof(struct hist_field), GFP_KERNEL);
3094 if (!var) {
3095 var = ERR_PTR(-ENOMEM);
3096 goto out;
3097 }
3098
3099 idx = tracing_map_add_var(hist_data->map);
3100 if (idx < 0) {
3101 kfree(var);
3102 var = ERR_PTR(-EINVAL);
3103 goto out;
3104 }
3105
Vamshi K Sthambamkadi9da73972020-04-22 11:45:06 +05303106 var->ref = 1;
Tom Zanussi02205a62018-01-15 20:51:59 -06003107 var->flags = HIST_FIELD_FL_VAR;
3108 var->var.idx = idx;
3109 var->var.hist_data = var->hist_data = hist_data;
3110 var->size = size;
3111 var->var.name = kstrdup(name, GFP_KERNEL);
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04003112 var->type = kstrdup_const(type, GFP_KERNEL);
Tom Zanussi02205a62018-01-15 20:51:59 -06003113 if (!var->var.name || !var->type) {
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04003114 kfree_const(var->type);
Tom Zanussi02205a62018-01-15 20:51:59 -06003115 kfree(var->var.name);
Tom Zanussi02205a62018-01-15 20:51:59 -06003116 kfree(var);
3117 var = ERR_PTR(-ENOMEM);
3118 }
3119 out:
3120 return var;
3121}
3122
3123static struct field_var *create_field_var(struct hist_trigger_data *hist_data,
3124 struct trace_event_file *file,
3125 char *field_name)
3126{
3127 struct hist_field *val = NULL, *var = NULL;
3128 unsigned long flags = HIST_FIELD_FL_VAR;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003129 struct trace_array *tr = file->tr;
Tom Zanussi02205a62018-01-15 20:51:59 -06003130 struct field_var *field_var;
3131 int ret = 0;
3132
3133 if (hist_data->n_field_vars >= SYNTH_FIELDS_MAX) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003134 hist_err(tr, HIST_ERR_TOO_MANY_FIELD_VARS, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06003135 ret = -EINVAL;
3136 goto err;
3137 }
3138
3139 val = parse_atom(hist_data, file, field_name, &flags, NULL);
3140 if (IS_ERR(val)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003141 hist_err(tr, HIST_ERR_FIELD_VAR_PARSE_FAIL, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06003142 ret = PTR_ERR(val);
3143 goto err;
3144 }
3145
3146 var = create_var(hist_data, file, field_name, val->size, val->type);
3147 if (IS_ERR(var)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003148 hist_err(tr, HIST_ERR_VAR_CREATE_FIND_FAIL, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06003149 kfree(val);
3150 ret = PTR_ERR(var);
3151 goto err;
3152 }
3153
3154 field_var = kzalloc(sizeof(struct field_var), GFP_KERNEL);
3155 if (!field_var) {
3156 kfree(val);
3157 kfree(var);
3158 ret = -ENOMEM;
3159 goto err;
3160 }
3161
3162 field_var->var = var;
3163 field_var->val = val;
3164 out:
3165 return field_var;
3166 err:
3167 field_var = ERR_PTR(ret);
3168 goto out;
3169}
3170
3171/**
3172 * create_target_field_var - Automatically create a variable for a field
3173 * @target_hist_data: The target hist trigger
3174 * @subsys_name: Optional subsystem name
3175 * @event_name: Optional event name
3176 * @var_name: The name of the field (and the resulting variable)
3177 *
3178 * Hist trigger actions fetch data from variables, not directly from
3179 * events. However, for convenience, users are allowed to directly
3180 * specify an event field in an action, which will be automatically
3181 * converted into a variable on their behalf.
3182
3183 * This function creates a field variable with the name var_name on
3184 * the hist trigger currently being defined on the target event. If
3185 * subsys_name and event_name are specified, this function simply
3186 * verifies that they do in fact match the target event subsystem and
3187 * event name.
3188 *
3189 * Return: The variable created for the field.
3190 */
Tom Zanussic282a382018-01-15 20:52:00 -06003191static struct field_var *
Tom Zanussi02205a62018-01-15 20:51:59 -06003192create_target_field_var(struct hist_trigger_data *target_hist_data,
3193 char *subsys_name, char *event_name, char *var_name)
3194{
3195 struct trace_event_file *file = target_hist_data->event_file;
3196
3197 if (subsys_name) {
3198 struct trace_event_call *call;
3199
3200 if (!event_name)
3201 return NULL;
3202
3203 call = file->event_call;
3204
3205 if (strcmp(subsys_name, call->class->system) != 0)
3206 return NULL;
3207
3208 if (strcmp(event_name, trace_event_name(call)) != 0)
3209 return NULL;
3210 }
3211
3212 return create_field_var(target_hist_data, file, var_name);
3213}
3214
Tom Zanussi466f4522019-02-13 17:42:44 -06003215static bool check_track_val_max(u64 track_val, u64 var_val)
Tom Zanussi50450602018-01-15 20:52:01 -06003216{
Tom Zanussi466f4522019-02-13 17:42:44 -06003217 if (var_val <= track_val)
3218 return false;
Tom Zanussi50450602018-01-15 20:52:01 -06003219
Tom Zanussi466f4522019-02-13 17:42:44 -06003220 return true;
3221}
3222
Tom Zanussidff81f52019-02-13 17:42:48 -06003223static bool check_track_val_changed(u64 track_val, u64 var_val)
3224{
3225 if (var_val == track_val)
3226 return false;
3227
3228 return true;
3229}
3230
Tom Zanussi466f4522019-02-13 17:42:44 -06003231static u64 get_track_val(struct hist_trigger_data *hist_data,
3232 struct tracing_map_elt *elt,
3233 struct action_data *data)
3234{
3235 unsigned int track_var_idx = data->track_data.track_var->var.idx;
3236 u64 track_val;
3237
3238 track_val = tracing_map_read_var(elt, track_var_idx);
3239
3240 return track_val;
3241}
3242
3243static void save_track_val(struct hist_trigger_data *hist_data,
3244 struct tracing_map_elt *elt,
3245 struct action_data *data, u64 var_val)
3246{
3247 unsigned int track_var_idx = data->track_data.track_var->var.idx;
3248
3249 tracing_map_set_var(elt, track_var_idx, var_val);
3250}
3251
3252static void save_track_data(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003253 struct tracing_map_elt *elt,
3254 struct trace_buffer *buffer, void *rec,
Tom Zanussi466f4522019-02-13 17:42:44 -06003255 struct ring_buffer_event *rbe, void *key,
3256 struct action_data *data, u64 *var_ref_vals)
3257{
3258 if (data->track_data.save_data)
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003259 data->track_data.save_data(hist_data, elt, buffer, rec, rbe,
3260 key, data, var_ref_vals);
Tom Zanussi466f4522019-02-13 17:42:44 -06003261}
3262
3263static bool check_track_val(struct tracing_map_elt *elt,
3264 struct action_data *data,
3265 u64 var_val)
3266{
3267 struct hist_trigger_data *hist_data;
3268 u64 track_val;
3269
3270 hist_data = data->track_data.track_var->hist_data;
3271 track_val = get_track_val(hist_data, elt, data);
3272
3273 return data->track_data.check_val(track_val, var_val);
3274}
3275
Tom Zanussia3785b72019-02-13 17:42:46 -06003276#ifdef CONFIG_TRACER_SNAPSHOT
3277static bool cond_snapshot_update(struct trace_array *tr, void *cond_data)
3278{
3279 /* called with tr->max_lock held */
3280 struct track_data *track_data = tr->cond_snapshot->cond_data;
3281 struct hist_elt_data *elt_data, *track_elt_data;
3282 struct snapshot_context *context = cond_data;
Tom Zanussi9b2ca372019-04-18 10:18:52 -05003283 struct action_data *action;
Tom Zanussia3785b72019-02-13 17:42:46 -06003284 u64 track_val;
3285
3286 if (!track_data)
3287 return false;
3288
Tom Zanussi9b2ca372019-04-18 10:18:52 -05003289 action = track_data->action_data;
3290
Tom Zanussia3785b72019-02-13 17:42:46 -06003291 track_val = get_track_val(track_data->hist_data, context->elt,
3292 track_data->action_data);
3293
Tom Zanussi9b2ca372019-04-18 10:18:52 -05003294 if (!action->track_data.check_val(track_data->track_val, track_val))
3295 return false;
3296
Tom Zanussia3785b72019-02-13 17:42:46 -06003297 track_data->track_val = track_val;
3298 memcpy(track_data->key, context->key, track_data->key_len);
3299
3300 elt_data = context->elt->private_data;
3301 track_elt_data = track_data->elt.private_data;
3302 if (elt_data->comm)
Tom Zanussi27242c62019-03-05 10:11:59 -06003303 strncpy(track_elt_data->comm, elt_data->comm, TASK_COMM_LEN);
Tom Zanussia3785b72019-02-13 17:42:46 -06003304
3305 track_data->updated = true;
3306
3307 return true;
3308}
3309
3310static void save_track_data_snapshot(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003311 struct tracing_map_elt *elt,
3312 struct trace_buffer *buffer, void *rec,
Tom Zanussia3785b72019-02-13 17:42:46 -06003313 struct ring_buffer_event *rbe, void *key,
3314 struct action_data *data,
3315 u64 *var_ref_vals)
3316{
3317 struct trace_event_file *file = hist_data->event_file;
3318 struct snapshot_context context;
3319
3320 context.elt = elt;
3321 context.key = key;
3322
3323 tracing_snapshot_cond(file->tr, &context);
3324}
3325
3326static void hist_trigger_print_key(struct seq_file *m,
3327 struct hist_trigger_data *hist_data,
3328 void *key,
3329 struct tracing_map_elt *elt);
3330
3331static struct action_data *snapshot_action(struct hist_trigger_data *hist_data)
3332{
3333 unsigned int i;
3334
3335 if (!hist_data->n_actions)
3336 return NULL;
3337
3338 for (i = 0; i < hist_data->n_actions; i++) {
3339 struct action_data *data = hist_data->actions[i];
3340
3341 if (data->action == ACTION_SNAPSHOT)
3342 return data;
3343 }
3344
3345 return NULL;
3346}
3347
3348static void track_data_snapshot_print(struct seq_file *m,
3349 struct hist_trigger_data *hist_data)
3350{
3351 struct trace_event_file *file = hist_data->event_file;
3352 struct track_data *track_data;
3353 struct action_data *action;
3354
3355 track_data = tracing_cond_snapshot_data(file->tr);
3356 if (!track_data)
3357 return;
3358
3359 if (!track_data->updated)
3360 return;
3361
3362 action = snapshot_action(hist_data);
3363 if (!action)
3364 return;
3365
3366 seq_puts(m, "\nSnapshot taken (see tracing/snapshot). Details:\n");
3367 seq_printf(m, "\ttriggering value { %s(%s) }: %10llu",
3368 action->handler == HANDLER_ONMAX ? "onmax" : "onchange",
3369 action->track_data.var_str, track_data->track_val);
3370
3371 seq_puts(m, "\ttriggered by event with key: ");
3372 hist_trigger_print_key(m, hist_data, track_data->key, &track_data->elt);
3373 seq_putc(m, '\n');
3374}
3375#else
3376static bool cond_snapshot_update(struct trace_array *tr, void *cond_data)
3377{
3378 return false;
3379}
3380static void save_track_data_snapshot(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003381 struct tracing_map_elt *elt,
3382 struct trace_buffer *buffer, void *rec,
Tom Zanussia3785b72019-02-13 17:42:46 -06003383 struct ring_buffer_event *rbe, void *key,
3384 struct action_data *data,
3385 u64 *var_ref_vals) {}
3386static void track_data_snapshot_print(struct seq_file *m,
3387 struct hist_trigger_data *hist_data) {}
3388#endif /* CONFIG_TRACER_SNAPSHOT */
3389
Tom Zanussi466f4522019-02-13 17:42:44 -06003390static void track_data_print(struct seq_file *m,
3391 struct hist_trigger_data *hist_data,
3392 struct tracing_map_elt *elt,
3393 struct action_data *data)
3394{
3395 u64 track_val = get_track_val(hist_data, elt, data);
3396 unsigned int i, save_var_idx;
3397
3398 if (data->handler == HANDLER_ONMAX)
3399 seq_printf(m, "\n\tmax: %10llu", track_val);
Tom Zanussidff81f52019-02-13 17:42:48 -06003400 else if (data->handler == HANDLER_ONCHANGE)
3401 seq_printf(m, "\n\tchanged: %10llu", track_val);
Tom Zanussi50450602018-01-15 20:52:01 -06003402
Tom Zanussia3785b72019-02-13 17:42:46 -06003403 if (data->action == ACTION_SNAPSHOT)
3404 return;
3405
Tom Zanussi7d18a102019-02-13 17:42:41 -06003406 for (i = 0; i < hist_data->n_save_vars; i++) {
3407 struct hist_field *save_val = hist_data->save_vars[i]->val;
3408 struct hist_field *save_var = hist_data->save_vars[i]->var;
Tom Zanussi50450602018-01-15 20:52:01 -06003409 u64 val;
3410
3411 save_var_idx = save_var->var.idx;
3412
3413 val = tracing_map_read_var(elt, save_var_idx);
3414
3415 if (save_val->flags & HIST_FIELD_FL_STRING) {
3416 seq_printf(m, " %s: %-32s", save_var->var.name,
3417 (char *)(uintptr_t)(val));
3418 } else
3419 seq_printf(m, " %s: %10llu", save_var->var.name, val);
3420 }
3421}
3422
Tom Zanussi466f4522019-02-13 17:42:44 -06003423static void ontrack_action(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003424 struct tracing_map_elt *elt,
3425 struct trace_buffer *buffer, void *rec,
Tom Zanussi466f4522019-02-13 17:42:44 -06003426 struct ring_buffer_event *rbe, void *key,
3427 struct action_data *data, u64 *var_ref_vals)
Tom Zanussi50450602018-01-15 20:52:01 -06003428{
Tom Zanussi466f4522019-02-13 17:42:44 -06003429 u64 var_val = var_ref_vals[data->track_data.var_ref->var_ref_idx];
Tom Zanussi50450602018-01-15 20:52:01 -06003430
Tom Zanussi466f4522019-02-13 17:42:44 -06003431 if (check_track_val(elt, data, var_val)) {
3432 save_track_val(hist_data, elt, data, var_val);
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003433 save_track_data(hist_data, elt, buffer, rec, rbe,
3434 key, data, var_ref_vals);
Tom Zanussi466f4522019-02-13 17:42:44 -06003435 }
Tom Zanussi50450602018-01-15 20:52:01 -06003436}
3437
Tom Zanussic3e49502019-02-13 17:42:43 -06003438static void action_data_destroy(struct action_data *data)
Tom Zanussi50450602018-01-15 20:52:01 -06003439{
3440 unsigned int i;
3441
Tom Zanussic3e49502019-02-13 17:42:43 -06003442 lockdep_assert_held(&event_mutex);
Tom Zanussi50450602018-01-15 20:52:01 -06003443
Tom Zanussi7d18a102019-02-13 17:42:41 -06003444 kfree(data->action_name);
Tom Zanussi50450602018-01-15 20:52:01 -06003445
3446 for (i = 0; i < data->n_params; i++)
3447 kfree(data->params[i]);
3448
Tom Zanussic3e49502019-02-13 17:42:43 -06003449 if (data->synth_event)
3450 data->synth_event->ref--;
3451
Tom Zanussie91eefd72019-02-13 17:42:50 -06003452 kfree(data->synth_event_name);
3453
Tom Zanussi50450602018-01-15 20:52:01 -06003454 kfree(data);
3455}
3456
Tom Zanussi466f4522019-02-13 17:42:44 -06003457static void track_data_destroy(struct hist_trigger_data *hist_data,
3458 struct action_data *data)
Tom Zanussic3e49502019-02-13 17:42:43 -06003459{
Tom Zanussia3785b72019-02-13 17:42:46 -06003460 struct trace_event_file *file = hist_data->event_file;
3461
Tom Zanussi466f4522019-02-13 17:42:44 -06003462 destroy_hist_field(data->track_data.track_var, 0);
Tom Zanussic3e49502019-02-13 17:42:43 -06003463
Tom Zanussia3785b72019-02-13 17:42:46 -06003464 if (data->action == ACTION_SNAPSHOT) {
3465 struct track_data *track_data;
3466
3467 track_data = tracing_cond_snapshot_data(file->tr);
3468 if (track_data && track_data->hist_data == hist_data) {
3469 tracing_snapshot_cond_disable(file->tr);
3470 track_data_free(track_data);
3471 }
3472 }
3473
Tom Zanussi466f4522019-02-13 17:42:44 -06003474 kfree(data->track_data.var_str);
Tom Zanussic3e49502019-02-13 17:42:43 -06003475
3476 action_data_destroy(data);
3477}
3478
Tom Zanussi7d18a102019-02-13 17:42:41 -06003479static int action_create(struct hist_trigger_data *hist_data,
3480 struct action_data *data);
3481
Tom Zanussi466f4522019-02-13 17:42:44 -06003482static int track_data_create(struct hist_trigger_data *hist_data,
3483 struct action_data *data)
Tom Zanussi50450602018-01-15 20:52:01 -06003484{
Tom Zanussi466f4522019-02-13 17:42:44 -06003485 struct hist_field *var_field, *ref_field, *track_var = NULL;
Tom Zanussi50450602018-01-15 20:52:01 -06003486 struct trace_event_file *file = hist_data->event_file;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003487 struct trace_array *tr = file->tr;
Tom Zanussi466f4522019-02-13 17:42:44 -06003488 char *track_data_var_str;
Tom Zanussi50450602018-01-15 20:52:01 -06003489 int ret = 0;
3490
Tom Zanussi466f4522019-02-13 17:42:44 -06003491 track_data_var_str = data->track_data.var_str;
3492 if (track_data_var_str[0] != '$') {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003493 hist_err(tr, HIST_ERR_ONX_NOT_VAR, errpos(track_data_var_str));
Tom Zanussi50450602018-01-15 20:52:01 -06003494 return -EINVAL;
Tom Zanussif404da62018-01-15 20:52:05 -06003495 }
Tom Zanussi466f4522019-02-13 17:42:44 -06003496 track_data_var_str++;
Tom Zanussi50450602018-01-15 20:52:01 -06003497
Tom Zanussi466f4522019-02-13 17:42:44 -06003498 var_field = find_target_event_var(hist_data, NULL, NULL, track_data_var_str);
Tom Zanussif404da62018-01-15 20:52:05 -06003499 if (!var_field) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003500 hist_err(tr, HIST_ERR_ONX_VAR_NOT_FOUND, errpos(track_data_var_str));
Tom Zanussi50450602018-01-15 20:52:01 -06003501 return -EINVAL;
Tom Zanussif404da62018-01-15 20:52:05 -06003502 }
Tom Zanussi50450602018-01-15 20:52:01 -06003503
Tom Zanusside40f032018-12-18 14:33:23 -06003504 ref_field = create_var_ref(hist_data, var_field, NULL, NULL);
Tom Zanussi50450602018-01-15 20:52:01 -06003505 if (!ref_field)
3506 return -ENOMEM;
3507
Tom Zanussi466f4522019-02-13 17:42:44 -06003508 data->track_data.var_ref = ref_field;
Tom Zanussi50450602018-01-15 20:52:01 -06003509
Tom Zanussi466f4522019-02-13 17:42:44 -06003510 if (data->handler == HANDLER_ONMAX)
3511 track_var = create_var(hist_data, file, "__max", sizeof(u64), "u64");
3512 if (IS_ERR(track_var)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003513 hist_err(tr, HIST_ERR_ONX_VAR_CREATE_FAIL, 0);
Tom Zanussi466f4522019-02-13 17:42:44 -06003514 ret = PTR_ERR(track_var);
Tom Zanussi50450602018-01-15 20:52:01 -06003515 goto out;
3516 }
Tom Zanussidff81f52019-02-13 17:42:48 -06003517
3518 if (data->handler == HANDLER_ONCHANGE)
3519 track_var = create_var(hist_data, file, "__change", sizeof(u64), "u64");
3520 if (IS_ERR(track_var)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003521 hist_err(tr, HIST_ERR_ONX_VAR_CREATE_FAIL, 0);
Tom Zanussidff81f52019-02-13 17:42:48 -06003522 ret = PTR_ERR(track_var);
3523 goto out;
3524 }
Tom Zanussi466f4522019-02-13 17:42:44 -06003525 data->track_data.track_var = track_var;
Tom Zanussi50450602018-01-15 20:52:01 -06003526
Tom Zanussi7d18a102019-02-13 17:42:41 -06003527 ret = action_create(hist_data, data);
Tom Zanussi50450602018-01-15 20:52:01 -06003528 out:
3529 return ret;
3530}
3531
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003532static int parse_action_params(struct trace_array *tr, char *params,
3533 struct action_data *data)
Tom Zanussi50450602018-01-15 20:52:01 -06003534{
3535 char *param, *saved_param;
Tom Zanussie91eefd72019-02-13 17:42:50 -06003536 bool first_param = true;
Tom Zanussi50450602018-01-15 20:52:01 -06003537 int ret = 0;
3538
3539 while (params) {
Tom Zanussi7d18a102019-02-13 17:42:41 -06003540 if (data->n_params >= SYNTH_FIELDS_MAX) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003541 hist_err(tr, HIST_ERR_TOO_MANY_PARAMS, 0);
Tom Zanussi50450602018-01-15 20:52:01 -06003542 goto out;
Tom Zanussi7d18a102019-02-13 17:42:41 -06003543 }
Tom Zanussi50450602018-01-15 20:52:01 -06003544
3545 param = strsep(&params, ",");
3546 if (!param) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003547 hist_err(tr, HIST_ERR_PARAM_NOT_FOUND, 0);
Tom Zanussi50450602018-01-15 20:52:01 -06003548 ret = -EINVAL;
3549 goto out;
3550 }
3551
3552 param = strstrip(param);
3553 if (strlen(param) < 2) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003554 hist_err(tr, HIST_ERR_INVALID_PARAM, errpos(param));
Tom Zanussi50450602018-01-15 20:52:01 -06003555 ret = -EINVAL;
3556 goto out;
3557 }
3558
3559 saved_param = kstrdup(param, GFP_KERNEL);
3560 if (!saved_param) {
3561 ret = -ENOMEM;
3562 goto out;
3563 }
3564
Tom Zanussie91eefd72019-02-13 17:42:50 -06003565 if (first_param && data->use_trace_keyword) {
3566 data->synth_event_name = saved_param;
3567 first_param = false;
3568 continue;
3569 }
3570 first_param = false;
3571
Tom Zanussi50450602018-01-15 20:52:01 -06003572 data->params[data->n_params++] = saved_param;
3573 }
3574 out:
3575 return ret;
3576}
3577
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003578static int action_parse(struct trace_array *tr, char *str, struct action_data *data,
Tom Zanussi7d18a102019-02-13 17:42:41 -06003579 enum handler_id handler)
Tom Zanussi50450602018-01-15 20:52:01 -06003580{
Tom Zanussi7d18a102019-02-13 17:42:41 -06003581 char *action_name;
3582 int ret = 0;
3583
3584 strsep(&str, ".");
3585 if (!str) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003586 hist_err(tr, HIST_ERR_ACTION_NOT_FOUND, 0);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003587 ret = -EINVAL;
3588 goto out;
3589 }
3590
3591 action_name = strsep(&str, "(");
3592 if (!action_name || !str) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003593 hist_err(tr, HIST_ERR_ACTION_NOT_FOUND, 0);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003594 ret = -EINVAL;
3595 goto out;
3596 }
3597
3598 if (str_has_prefix(action_name, "save")) {
3599 char *params = strsep(&str, ")");
3600
3601 if (!params) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003602 hist_err(tr, HIST_ERR_NO_SAVE_PARAMS, 0);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003603 ret = -EINVAL;
3604 goto out;
3605 }
3606
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003607 ret = parse_action_params(tr, params, data);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003608 if (ret)
3609 goto out;
3610
3611 if (handler == HANDLER_ONMAX)
Tom Zanussi466f4522019-02-13 17:42:44 -06003612 data->track_data.check_val = check_track_val_max;
Tom Zanussidff81f52019-02-13 17:42:48 -06003613 else if (handler == HANDLER_ONCHANGE)
3614 data->track_data.check_val = check_track_val_changed;
Tom Zanussi466f4522019-02-13 17:42:44 -06003615 else {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003616 hist_err(tr, HIST_ERR_ACTION_MISMATCH, errpos(action_name));
Tom Zanussi466f4522019-02-13 17:42:44 -06003617 ret = -EINVAL;
3618 goto out;
3619 }
Tom Zanussi7d18a102019-02-13 17:42:41 -06003620
Tom Zanussi466f4522019-02-13 17:42:44 -06003621 data->track_data.save_data = save_track_data_vars;
3622 data->fn = ontrack_action;
Tom Zanussi7d18a102019-02-13 17:42:41 -06003623 data->action = ACTION_SAVE;
Tom Zanussia3785b72019-02-13 17:42:46 -06003624 } else if (str_has_prefix(action_name, "snapshot")) {
3625 char *params = strsep(&str, ")");
3626
3627 if (!str) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003628 hist_err(tr, HIST_ERR_NO_CLOSING_PAREN, errpos(params));
Tom Zanussia3785b72019-02-13 17:42:46 -06003629 ret = -EINVAL;
3630 goto out;
3631 }
3632
3633 if (handler == HANDLER_ONMAX)
3634 data->track_data.check_val = check_track_val_max;
Tom Zanussidff81f52019-02-13 17:42:48 -06003635 else if (handler == HANDLER_ONCHANGE)
3636 data->track_data.check_val = check_track_val_changed;
Tom Zanussia3785b72019-02-13 17:42:46 -06003637 else {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003638 hist_err(tr, HIST_ERR_ACTION_MISMATCH, errpos(action_name));
Tom Zanussia3785b72019-02-13 17:42:46 -06003639 ret = -EINVAL;
3640 goto out;
3641 }
3642
3643 data->track_data.save_data = save_track_data_snapshot;
3644 data->fn = ontrack_action;
3645 data->action = ACTION_SNAPSHOT;
Tom Zanussi7d18a102019-02-13 17:42:41 -06003646 } else {
3647 char *params = strsep(&str, ")");
3648
Tom Zanussie91eefd72019-02-13 17:42:50 -06003649 if (str_has_prefix(action_name, "trace"))
3650 data->use_trace_keyword = true;
3651
Tom Zanussi7d18a102019-02-13 17:42:41 -06003652 if (params) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003653 ret = parse_action_params(tr, params, data);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003654 if (ret)
3655 goto out;
3656 }
3657
Tom Zanussi466f4522019-02-13 17:42:44 -06003658 if (handler == HANDLER_ONMAX)
3659 data->track_data.check_val = check_track_val_max;
Tom Zanussidff81f52019-02-13 17:42:48 -06003660 else if (handler == HANDLER_ONCHANGE)
3661 data->track_data.check_val = check_track_val_changed;
Tom Zanussi466f4522019-02-13 17:42:44 -06003662
3663 if (handler != HANDLER_ONMATCH) {
3664 data->track_data.save_data = action_trace;
3665 data->fn = ontrack_action;
3666 } else
3667 data->fn = action_trace;
3668
Tom Zanussi7d18a102019-02-13 17:42:41 -06003669 data->action = ACTION_TRACE;
3670 }
3671
3672 data->action_name = kstrdup(action_name, GFP_KERNEL);
3673 if (!data->action_name) {
3674 ret = -ENOMEM;
3675 goto out;
3676 }
3677
3678 data->handler = handler;
3679 out:
3680 return ret;
3681}
3682
Tom Zanussi466f4522019-02-13 17:42:44 -06003683static struct action_data *track_data_parse(struct hist_trigger_data *hist_data,
3684 char *str, enum handler_id handler)
Tom Zanussi7d18a102019-02-13 17:42:41 -06003685{
Tom Zanussi50450602018-01-15 20:52:01 -06003686 struct action_data *data;
3687 int ret = -EINVAL;
Tom Zanussi466f4522019-02-13 17:42:44 -06003688 char *var_str;
Tom Zanussi50450602018-01-15 20:52:01 -06003689
3690 data = kzalloc(sizeof(*data), GFP_KERNEL);
3691 if (!data)
3692 return ERR_PTR(-ENOMEM);
3693
Tom Zanussi466f4522019-02-13 17:42:44 -06003694 var_str = strsep(&str, ")");
3695 if (!var_str || !str) {
Tom Zanussi50450602018-01-15 20:52:01 -06003696 ret = -EINVAL;
3697 goto free;
3698 }
3699
Tom Zanussi466f4522019-02-13 17:42:44 -06003700 data->track_data.var_str = kstrdup(var_str, GFP_KERNEL);
3701 if (!data->track_data.var_str) {
Tom Zanussi50450602018-01-15 20:52:01 -06003702 ret = -ENOMEM;
3703 goto free;
3704 }
3705
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003706 ret = action_parse(hist_data->event_file->tr, str, data, handler);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003707 if (ret)
Tom Zanussi50450602018-01-15 20:52:01 -06003708 goto free;
Tom Zanussi50450602018-01-15 20:52:01 -06003709 out:
3710 return data;
3711 free:
Tom Zanussi466f4522019-02-13 17:42:44 -06003712 track_data_destroy(hist_data, data);
Tom Zanussi50450602018-01-15 20:52:01 -06003713 data = ERR_PTR(ret);
3714 goto out;
3715}
3716
Tom Zanussic282a382018-01-15 20:52:00 -06003717static void onmatch_destroy(struct action_data *data)
3718{
Tom Zanussic3e49502019-02-13 17:42:43 -06003719 kfree(data->match_data.event);
3720 kfree(data->match_data.event_system);
Tom Zanussic282a382018-01-15 20:52:00 -06003721
Tom Zanussic3e49502019-02-13 17:42:43 -06003722 action_data_destroy(data);
Tom Zanussic282a382018-01-15 20:52:00 -06003723}
3724
Tom Zanussi02205a62018-01-15 20:51:59 -06003725static void destroy_field_var(struct field_var *field_var)
3726{
3727 if (!field_var)
3728 return;
3729
3730 destroy_hist_field(field_var->var, 0);
3731 destroy_hist_field(field_var->val, 0);
3732
3733 kfree(field_var);
3734}
3735
3736static void destroy_field_vars(struct hist_trigger_data *hist_data)
3737{
3738 unsigned int i;
3739
3740 for (i = 0; i < hist_data->n_field_vars; i++)
3741 destroy_field_var(hist_data->field_vars[i]);
Vamshi K Sthambamkadi9da73972020-04-22 11:45:06 +05303742
3743 for (i = 0; i < hist_data->n_save_vars; i++)
3744 destroy_field_var(hist_data->save_vars[i]);
Tom Zanussi02205a62018-01-15 20:51:59 -06003745}
3746
Tom Zanussic282a382018-01-15 20:52:00 -06003747static void save_field_var(struct hist_trigger_data *hist_data,
3748 struct field_var *field_var)
Tom Zanussi02205a62018-01-15 20:51:59 -06003749{
3750 hist_data->field_vars[hist_data->n_field_vars++] = field_var;
3751
3752 if (field_var->val->flags & HIST_FIELD_FL_STRING)
3753 hist_data->n_field_var_str++;
3754}
3755
Tom Zanussic282a382018-01-15 20:52:00 -06003756
Tom Zanussic282a382018-01-15 20:52:00 -06003757static int check_synth_field(struct synth_event *event,
3758 struct hist_field *hist_field,
3759 unsigned int field_pos)
3760{
3761 struct synth_field *field;
3762
3763 if (field_pos >= event->n_fields)
3764 return -EINVAL;
3765
3766 field = event->fields[field_pos];
3767
Tom Zanussibd826312020-10-04 17:14:06 -05003768 /*
3769 * A dynamic string synth field can accept static or
3770 * dynamic. A static string synth field can only accept a
3771 * same-sized static string, which is checked for later.
3772 */
3773 if (strstr(hist_field->type, "char[") && field->is_string
3774 && field->is_dynamic)
3775 return 0;
3776
Masami Hiramatsub05e89a2020-01-11 01:05:53 +09003777 if (strcmp(field->type, hist_field->type) != 0) {
3778 if (field->size != hist_field->size ||
Steven Rostedt (VMware)450fec12021-11-30 12:31:23 -05003779 (!field->is_string && field->is_signed != hist_field->is_signed))
Masami Hiramatsub05e89a2020-01-11 01:05:53 +09003780 return -EINVAL;
3781 }
Tom Zanussic282a382018-01-15 20:52:00 -06003782
3783 return 0;
3784}
3785
Tom Zanussic282a382018-01-15 20:52:00 -06003786static struct hist_field *
Tom Zanussi7d18a102019-02-13 17:42:41 -06003787trace_action_find_var(struct hist_trigger_data *hist_data,
3788 struct action_data *data,
3789 char *system, char *event, char *var)
Tom Zanussic282a382018-01-15 20:52:00 -06003790{
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003791 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussic282a382018-01-15 20:52:00 -06003792 struct hist_field *hist_field;
3793
3794 var++; /* skip '$' */
3795
3796 hist_field = find_target_event_var(hist_data, system, event, var);
3797 if (!hist_field) {
Tom Zanussi7d18a102019-02-13 17:42:41 -06003798 if (!system && data->handler == HANDLER_ONMATCH) {
Tom Zanussic3e49502019-02-13 17:42:43 -06003799 system = data->match_data.event_system;
3800 event = data->match_data.event;
Tom Zanussic282a382018-01-15 20:52:00 -06003801 }
3802
3803 hist_field = find_event_var(hist_data, system, event, var);
3804 }
3805
Tom Zanussif404da62018-01-15 20:52:05 -06003806 if (!hist_field)
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003807 hist_err(tr, HIST_ERR_PARAM_NOT_FOUND, errpos(var));
Tom Zanussif404da62018-01-15 20:52:05 -06003808
Tom Zanussic282a382018-01-15 20:52:00 -06003809 return hist_field;
3810}
3811
3812static struct hist_field *
Tom Zanussi7d18a102019-02-13 17:42:41 -06003813trace_action_create_field_var(struct hist_trigger_data *hist_data,
3814 struct action_data *data, char *system,
3815 char *event, char *var)
Tom Zanussic282a382018-01-15 20:52:00 -06003816{
3817 struct hist_field *hist_field = NULL;
3818 struct field_var *field_var;
3819
3820 /*
3821 * First try to create a field var on the target event (the
3822 * currently being defined). This will create a variable for
3823 * unqualified fields on the target event, or if qualified,
3824 * target fields that have qualified names matching the target.
3825 */
3826 field_var = create_target_field_var(hist_data, system, event, var);
3827
3828 if (field_var && !IS_ERR(field_var)) {
3829 save_field_var(hist_data, field_var);
3830 hist_field = field_var->var;
3831 } else {
3832 field_var = NULL;
3833 /*
Qiujun Huang2b5894c2020-10-29 23:05:54 +08003834 * If no explicit system.event is specified, default to
Tom Zanussic282a382018-01-15 20:52:00 -06003835 * looking for fields on the onmatch(system.event.xxx)
3836 * event.
3837 */
Tom Zanussi7d18a102019-02-13 17:42:41 -06003838 if (!system && data->handler == HANDLER_ONMATCH) {
Tom Zanussic3e49502019-02-13 17:42:43 -06003839 system = data->match_data.event_system;
3840 event = data->match_data.event;
Tom Zanussic282a382018-01-15 20:52:00 -06003841 }
3842
Steven Rostedt (VMware)5acce0b2021-08-08 00:30:11 -04003843 if (!event)
3844 goto free;
Tom Zanussic282a382018-01-15 20:52:00 -06003845 /*
3846 * At this point, we're looking at a field on another
3847 * event. Because we can't modify a hist trigger on
3848 * another event to add a variable for a field, we need
3849 * to create a new trigger on that event and create the
3850 * variable at the same time.
3851 */
3852 hist_field = create_field_var_hist(hist_data, system, event, var);
3853 if (IS_ERR(hist_field))
3854 goto free;
3855 }
3856 out:
3857 return hist_field;
3858 free:
3859 destroy_field_var(field_var);
3860 hist_field = NULL;
3861 goto out;
3862}
3863
Tom Zanussi7d18a102019-02-13 17:42:41 -06003864static int trace_action_create(struct hist_trigger_data *hist_data,
3865 struct action_data *data)
Tom Zanussic282a382018-01-15 20:52:00 -06003866{
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003867 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussic282a382018-01-15 20:52:00 -06003868 char *event_name, *param, *system = NULL;
3869 struct hist_field *hist_field, *var_ref;
Tom Zanussid380dcd2020-01-29 21:18:18 -05003870 unsigned int i;
Tom Zanussic282a382018-01-15 20:52:00 -06003871 unsigned int field_pos = 0;
3872 struct synth_event *event;
Tom Zanussie91eefd72019-02-13 17:42:50 -06003873 char *synth_event_name;
Tom Zanussid380dcd2020-01-29 21:18:18 -05003874 int var_ref_idx, ret = 0;
Tom Zanussic282a382018-01-15 20:52:00 -06003875
Masami Hiramatsu0e2b81f72018-11-05 18:04:01 +09003876 lockdep_assert_held(&event_mutex);
3877
Tom Zanussie91eefd72019-02-13 17:42:50 -06003878 if (data->use_trace_keyword)
3879 synth_event_name = data->synth_event_name;
3880 else
3881 synth_event_name = data->action_name;
3882
3883 event = find_synth_event(synth_event_name);
Tom Zanussic282a382018-01-15 20:52:00 -06003884 if (!event) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003885 hist_err(tr, HIST_ERR_SYNTH_EVENT_NOT_FOUND, errpos(synth_event_name));
Tom Zanussic282a382018-01-15 20:52:00 -06003886 return -EINVAL;
3887 }
Tom Zanussi7d18a102019-02-13 17:42:41 -06003888
Tom Zanussic282a382018-01-15 20:52:00 -06003889 event->ref++;
Tom Zanussic282a382018-01-15 20:52:00 -06003890
Tom Zanussic282a382018-01-15 20:52:00 -06003891 for (i = 0; i < data->n_params; i++) {
3892 char *p;
3893
3894 p = param = kstrdup(data->params[i], GFP_KERNEL);
3895 if (!param) {
3896 ret = -ENOMEM;
3897 goto err;
3898 }
3899
3900 system = strsep(&param, ".");
3901 if (!param) {
3902 param = (char *)system;
3903 system = event_name = NULL;
3904 } else {
3905 event_name = strsep(&param, ".");
3906 if (!param) {
3907 kfree(p);
3908 ret = -EINVAL;
3909 goto err;
3910 }
3911 }
3912
3913 if (param[0] == '$')
Tom Zanussi7d18a102019-02-13 17:42:41 -06003914 hist_field = trace_action_find_var(hist_data, data,
3915 system, event_name,
3916 param);
Tom Zanussic282a382018-01-15 20:52:00 -06003917 else
Tom Zanussi7d18a102019-02-13 17:42:41 -06003918 hist_field = trace_action_create_field_var(hist_data,
3919 data,
3920 system,
3921 event_name,
3922 param);
Tom Zanussic282a382018-01-15 20:52:00 -06003923
3924 if (!hist_field) {
3925 kfree(p);
3926 ret = -EINVAL;
3927 goto err;
3928 }
3929
3930 if (check_synth_field(event, hist_field, field_pos) == 0) {
Tom Zanusside40f032018-12-18 14:33:23 -06003931 var_ref = create_var_ref(hist_data, hist_field,
3932 system, event_name);
Tom Zanussic282a382018-01-15 20:52:00 -06003933 if (!var_ref) {
3934 kfree(p);
3935 ret = -ENOMEM;
3936 goto err;
3937 }
3938
Tom Zanussid380dcd2020-01-29 21:18:18 -05003939 var_ref_idx = find_var_ref_idx(hist_data, var_ref);
3940 if (WARN_ON(var_ref_idx < 0)) {
Xiaoke Wange629e7b2022-01-25 12:07:15 +08003941 kfree(p);
Tom Zanussid380dcd2020-01-29 21:18:18 -05003942 ret = var_ref_idx;
3943 goto err;
3944 }
3945
3946 data->var_ref_idx[i] = var_ref_idx;
3947
Tom Zanussic282a382018-01-15 20:52:00 -06003948 field_pos++;
3949 kfree(p);
3950 continue;
3951 }
3952
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003953 hist_err(tr, HIST_ERR_SYNTH_TYPE_MISMATCH, errpos(param));
Tom Zanussic282a382018-01-15 20:52:00 -06003954 kfree(p);
3955 ret = -EINVAL;
3956 goto err;
3957 }
3958
3959 if (field_pos != event->n_fields) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003960 hist_err(tr, HIST_ERR_SYNTH_COUNT_MISMATCH, errpos(event->name));
Tom Zanussic282a382018-01-15 20:52:00 -06003961 ret = -EINVAL;
3962 goto err;
3963 }
3964
Tom Zanussic3e49502019-02-13 17:42:43 -06003965 data->synth_event = event;
Tom Zanussic282a382018-01-15 20:52:00 -06003966 out:
3967 return ret;
3968 err:
Tom Zanussic282a382018-01-15 20:52:00 -06003969 event->ref--;
Tom Zanussic282a382018-01-15 20:52:00 -06003970
3971 goto out;
3972}
3973
Tom Zanussi7d18a102019-02-13 17:42:41 -06003974static int action_create(struct hist_trigger_data *hist_data,
3975 struct action_data *data)
3976{
Tom Zanussia3785b72019-02-13 17:42:46 -06003977 struct trace_event_file *file = hist_data->event_file;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003978 struct trace_array *tr = file->tr;
Tom Zanussia3785b72019-02-13 17:42:46 -06003979 struct track_data *track_data;
Tom Zanussi7d18a102019-02-13 17:42:41 -06003980 struct field_var *field_var;
3981 unsigned int i;
3982 char *param;
3983 int ret = 0;
3984
3985 if (data->action == ACTION_TRACE)
3986 return trace_action_create(hist_data, data);
3987
Tom Zanussia3785b72019-02-13 17:42:46 -06003988 if (data->action == ACTION_SNAPSHOT) {
3989 track_data = track_data_alloc(hist_data->key_size, data, hist_data);
3990 if (IS_ERR(track_data)) {
3991 ret = PTR_ERR(track_data);
3992 goto out;
3993 }
3994
3995 ret = tracing_snapshot_cond_enable(file->tr, track_data,
3996 cond_snapshot_update);
3997 if (ret)
3998 track_data_free(track_data);
3999
4000 goto out;
4001 }
4002
Tom Zanussi7d18a102019-02-13 17:42:41 -06004003 if (data->action == ACTION_SAVE) {
4004 if (hist_data->n_save_vars) {
4005 ret = -EEXIST;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004006 hist_err(tr, HIST_ERR_TOO_MANY_SAVE_ACTIONS, 0);
Tom Zanussi7d18a102019-02-13 17:42:41 -06004007 goto out;
4008 }
4009
4010 for (i = 0; i < data->n_params; i++) {
4011 param = kstrdup(data->params[i], GFP_KERNEL);
4012 if (!param) {
4013 ret = -ENOMEM;
4014 goto out;
4015 }
4016
4017 field_var = create_target_field_var(hist_data, NULL, NULL, param);
4018 if (IS_ERR(field_var)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004019 hist_err(tr, HIST_ERR_FIELD_VAR_CREATE_FAIL,
4020 errpos(param));
Tom Zanussi7d18a102019-02-13 17:42:41 -06004021 ret = PTR_ERR(field_var);
4022 kfree(param);
4023 goto out;
4024 }
4025
4026 hist_data->save_vars[hist_data->n_save_vars++] = field_var;
4027 if (field_var->val->flags & HIST_FIELD_FL_STRING)
4028 hist_data->n_save_var_str++;
4029 kfree(param);
4030 }
4031 }
4032 out:
4033 return ret;
4034}
4035
4036static int onmatch_create(struct hist_trigger_data *hist_data,
4037 struct action_data *data)
4038{
4039 return action_create(hist_data, data);
4040}
4041
Tom Zanussic282a382018-01-15 20:52:00 -06004042static struct action_data *onmatch_parse(struct trace_array *tr, char *str)
4043{
4044 char *match_event, *match_event_system;
Tom Zanussic282a382018-01-15 20:52:00 -06004045 struct action_data *data;
4046 int ret = -EINVAL;
4047
4048 data = kzalloc(sizeof(*data), GFP_KERNEL);
4049 if (!data)
4050 return ERR_PTR(-ENOMEM);
4051
4052 match_event = strsep(&str, ")");
Tom Zanussif404da62018-01-15 20:52:05 -06004053 if (!match_event || !str) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004054 hist_err(tr, HIST_ERR_NO_CLOSING_PAREN, errpos(match_event));
Tom Zanussic282a382018-01-15 20:52:00 -06004055 goto free;
Tom Zanussif404da62018-01-15 20:52:05 -06004056 }
Tom Zanussic282a382018-01-15 20:52:00 -06004057
4058 match_event_system = strsep(&match_event, ".");
Tom Zanussif404da62018-01-15 20:52:05 -06004059 if (!match_event) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004060 hist_err(tr, HIST_ERR_SUBSYS_NOT_FOUND, errpos(match_event_system));
Tom Zanussic282a382018-01-15 20:52:00 -06004061 goto free;
Tom Zanussif404da62018-01-15 20:52:05 -06004062 }
Tom Zanussic282a382018-01-15 20:52:00 -06004063
Tom Zanussif404da62018-01-15 20:52:05 -06004064 if (IS_ERR(event_file(tr, match_event_system, match_event))) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004065 hist_err(tr, HIST_ERR_INVALID_SUBSYS_EVENT, errpos(match_event));
Tom Zanussic282a382018-01-15 20:52:00 -06004066 goto free;
Tom Zanussif404da62018-01-15 20:52:05 -06004067 }
Tom Zanussic282a382018-01-15 20:52:00 -06004068
Tom Zanussic3e49502019-02-13 17:42:43 -06004069 data->match_data.event = kstrdup(match_event, GFP_KERNEL);
4070 if (!data->match_data.event) {
Tom Zanussic282a382018-01-15 20:52:00 -06004071 ret = -ENOMEM;
4072 goto free;
4073 }
4074
Tom Zanussic3e49502019-02-13 17:42:43 -06004075 data->match_data.event_system = kstrdup(match_event_system, GFP_KERNEL);
4076 if (!data->match_data.event_system) {
Tom Zanussic282a382018-01-15 20:52:00 -06004077 ret = -ENOMEM;
4078 goto free;
4079 }
4080
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004081 ret = action_parse(tr, str, data, HANDLER_ONMATCH);
Tom Zanussic282a382018-01-15 20:52:00 -06004082 if (ret)
4083 goto free;
4084 out:
4085 return data;
4086 free:
4087 onmatch_destroy(data);
4088 data = ERR_PTR(ret);
4089 goto out;
4090}
4091
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004092static int create_hitcount_val(struct hist_trigger_data *hist_data)
4093{
4094 hist_data->fields[HITCOUNT_IDX] =
Tom Zanussi30350d62018-01-15 20:51:49 -06004095 create_hist_field(hist_data, NULL, HIST_FIELD_FL_HITCOUNT, NULL);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004096 if (!hist_data->fields[HITCOUNT_IDX])
4097 return -ENOMEM;
4098
4099 hist_data->n_vals++;
Tom Zanussi30350d62018-01-15 20:51:49 -06004100 hist_data->n_fields++;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004101
4102 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
4103 return -EINVAL;
4104
4105 return 0;
4106}
4107
Tom Zanussi30350d62018-01-15 20:51:49 -06004108static int __create_val_field(struct hist_trigger_data *hist_data,
4109 unsigned int val_idx,
4110 struct trace_event_file *file,
4111 char *var_name, char *field_str,
4112 unsigned long flags)
Tom Zanussif2606832016-03-03 12:54:43 -06004113{
Tom Zanussi100719d2018-01-15 20:51:52 -06004114 struct hist_field *hist_field;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07004115 int ret = 0, n_subexprs = 0;
Tom Zanussif2606832016-03-03 12:54:43 -06004116
Kalesh Singh9710b2f2021-10-25 13:08:35 -07004117 hist_field = parse_expr(hist_data, file, field_str, flags, var_name, &n_subexprs);
Tom Zanussi100719d2018-01-15 20:51:52 -06004118 if (IS_ERR(hist_field)) {
4119 ret = PTR_ERR(hist_field);
Tom Zanussif2606832016-03-03 12:54:43 -06004120 goto out;
4121 }
4122
Tom Zanussi100719d2018-01-15 20:51:52 -06004123 hist_data->fields[val_idx] = hist_field;
4124
Tom Zanussif2606832016-03-03 12:54:43 -06004125 ++hist_data->n_vals;
Tom Zanussi30350d62018-01-15 20:51:49 -06004126 ++hist_data->n_fields;
Tom Zanussif2606832016-03-03 12:54:43 -06004127
Tom Zanussi30350d62018-01-15 20:51:49 -06004128 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX + TRACING_MAP_VARS_MAX))
Tom Zanussif2606832016-03-03 12:54:43 -06004129 ret = -EINVAL;
4130 out:
4131 return ret;
4132}
4133
Tom Zanussi30350d62018-01-15 20:51:49 -06004134static int create_val_field(struct hist_trigger_data *hist_data,
4135 unsigned int val_idx,
4136 struct trace_event_file *file,
4137 char *field_str)
4138{
4139 if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX))
4140 return -EINVAL;
4141
4142 return __create_val_field(hist_data, val_idx, file, NULL, field_str, 0);
4143}
4144
Steven Rostedt (VMware)ed2cf902021-07-22 10:27:07 -04004145static const char *no_comm = "(no comm)";
4146
4147static u64 hist_field_execname(struct hist_field *hist_field,
4148 struct tracing_map_elt *elt,
4149 struct trace_buffer *buffer,
4150 struct ring_buffer_event *rbe,
4151 void *event)
4152{
4153 struct hist_elt_data *elt_data;
4154
4155 if (WARN_ON_ONCE(!elt))
4156 return (u64)(unsigned long)no_comm;
4157
4158 elt_data = elt->private_data;
4159
4160 if (WARN_ON_ONCE(!elt_data->comm))
4161 return (u64)(unsigned long)no_comm;
4162
4163 return (u64)(unsigned long)(elt_data->comm);
4164}
4165
4166/* Convert a var that points to common_pid.execname to a string */
4167static void update_var_execname(struct hist_field *hist_field)
4168{
4169 hist_field->flags = HIST_FIELD_FL_STRING | HIST_FIELD_FL_VAR |
4170 HIST_FIELD_FL_EXECNAME;
4171 hist_field->size = MAX_FILTER_STR_VAL;
4172 hist_field->is_signed = 0;
4173
4174 kfree_const(hist_field->type);
4175 hist_field->type = "char[]";
4176
4177 hist_field->fn = hist_field_execname;
4178}
4179
Tom Zanussi30350d62018-01-15 20:51:49 -06004180static int create_var_field(struct hist_trigger_data *hist_data,
4181 unsigned int val_idx,
4182 struct trace_event_file *file,
4183 char *var_name, char *expr_str)
4184{
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004185 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussi30350d62018-01-15 20:51:49 -06004186 unsigned long flags = 0;
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004187 int ret;
Tom Zanussi30350d62018-01-15 20:51:49 -06004188
4189 if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX + TRACING_MAP_VARS_MAX))
4190 return -EINVAL;
Tom Zanussif404da62018-01-15 20:52:05 -06004191
Tom Zanussi30350d62018-01-15 20:51:49 -06004192 if (find_var(hist_data, file, var_name) && !hist_data->remove) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004193 hist_err(tr, HIST_ERR_DUPLICATE_VAR, errpos(var_name));
Tom Zanussi30350d62018-01-15 20:51:49 -06004194 return -EINVAL;
4195 }
4196
4197 flags |= HIST_FIELD_FL_VAR;
4198 hist_data->n_vars++;
4199 if (WARN_ON(hist_data->n_vars > TRACING_MAP_VARS_MAX))
4200 return -EINVAL;
4201
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004202 ret = __create_val_field(hist_data, val_idx, file, var_name, expr_str, flags);
4203
Steven Rostedt (VMware)ed2cf902021-07-22 10:27:07 -04004204 if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_EXECNAME)
4205 update_var_execname(hist_data->fields[val_idx]);
4206
Steven Rostedt (VMware)6d9bd132020-10-13 15:48:52 -04004207 if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_STRING)
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004208 hist_data->fields[val_idx]->var_str_idx = hist_data->n_var_str++;
4209
4210 return ret;
Tom Zanussi30350d62018-01-15 20:51:49 -06004211}
4212
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004213static int create_val_fields(struct hist_trigger_data *hist_data,
4214 struct trace_event_file *file)
4215{
Tom Zanussif2606832016-03-03 12:54:43 -06004216 char *fields_str, *field_str;
Tom Zanussi30350d62018-01-15 20:51:49 -06004217 unsigned int i, j = 1;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004218 int ret;
4219
4220 ret = create_hitcount_val(hist_data);
Tom Zanussif2606832016-03-03 12:54:43 -06004221 if (ret)
4222 goto out;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004223
Tom Zanussif2606832016-03-03 12:54:43 -06004224 fields_str = hist_data->attrs->vals_str;
4225 if (!fields_str)
4226 goto out;
4227
Tom Zanussif2606832016-03-03 12:54:43 -06004228 for (i = 0, j = 1; i < TRACING_MAP_VALS_MAX &&
4229 j < TRACING_MAP_VALS_MAX; i++) {
4230 field_str = strsep(&fields_str, ",");
4231 if (!field_str)
4232 break;
Tom Zanussi30350d62018-01-15 20:51:49 -06004233
Tom Zanussif2606832016-03-03 12:54:43 -06004234 if (strcmp(field_str, "hitcount") == 0)
4235 continue;
Tom Zanussi30350d62018-01-15 20:51:49 -06004236
Tom Zanussif2606832016-03-03 12:54:43 -06004237 ret = create_val_field(hist_data, j++, file, field_str);
4238 if (ret)
4239 goto out;
4240 }
Tom Zanussi30350d62018-01-15 20:51:49 -06004241
Tom Zanussif2606832016-03-03 12:54:43 -06004242 if (fields_str && (strcmp(fields_str, "hitcount") != 0))
4243 ret = -EINVAL;
4244 out:
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004245 return ret;
4246}
4247
4248static int create_key_field(struct hist_trigger_data *hist_data,
4249 unsigned int key_idx,
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004250 unsigned int key_offset,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004251 struct trace_event_file *file,
4252 char *field_str)
4253{
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004254 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussi30350d62018-01-15 20:51:49 -06004255 struct hist_field *hist_field = NULL;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004256 unsigned long flags = 0;
4257 unsigned int key_size;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07004258 int ret = 0, n_subexprs = 0;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004259
Tom Zanussi30350d62018-01-15 20:51:49 -06004260 if (WARN_ON(key_idx >= HIST_FIELDS_MAX))
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004261 return -EINVAL;
4262
4263 flags |= HIST_FIELD_FL_KEY;
4264
Tom Zanussi69a02002016-03-03 12:54:52 -06004265 if (strcmp(field_str, "stacktrace") == 0) {
4266 flags |= HIST_FIELD_FL_STACKTRACE;
4267 key_size = sizeof(unsigned long) * HIST_STACKTRACE_DEPTH;
Tom Zanussi30350d62018-01-15 20:51:49 -06004268 hist_field = create_hist_field(hist_data, NULL, flags, NULL);
Tom Zanussi69a02002016-03-03 12:54:52 -06004269 } else {
Tom Zanussi100719d2018-01-15 20:51:52 -06004270 hist_field = parse_expr(hist_data, file, field_str, flags,
Kalesh Singh9710b2f2021-10-25 13:08:35 -07004271 NULL, &n_subexprs);
Tom Zanussi100719d2018-01-15 20:51:52 -06004272 if (IS_ERR(hist_field)) {
4273 ret = PTR_ERR(hist_field);
4274 goto out;
Tom Zanussi69a02002016-03-03 12:54:52 -06004275 }
4276
Tom Zanussic8d94a12019-04-18 10:18:51 -05004277 if (field_has_hist_vars(hist_field, 0)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004278 hist_err(tr, HIST_ERR_INVALID_REF_KEY, errpos(field_str));
Tom Zanussi067fe032018-01-15 20:51:56 -06004279 destroy_hist_field(hist_field, 0);
4280 ret = -EINVAL;
4281 goto out;
4282 }
4283
Tom Zanussi100719d2018-01-15 20:51:52 -06004284 key_size = hist_field->size;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004285 }
4286
Tom Zanussi100719d2018-01-15 20:51:52 -06004287 hist_data->fields[key_idx] = hist_field;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004288
4289 key_size = ALIGN(key_size, sizeof(u64));
4290 hist_data->fields[key_idx]->size = key_size;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004291 hist_data->fields[key_idx]->offset = key_offset;
Tom Zanussi100719d2018-01-15 20:51:52 -06004292
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004293 hist_data->key_size += key_size;
Tom Zanussi100719d2018-01-15 20:51:52 -06004294
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004295 if (hist_data->key_size > HIST_KEY_SIZE_MAX) {
4296 ret = -EINVAL;
4297 goto out;
4298 }
4299
4300 hist_data->n_keys++;
Tom Zanussi30350d62018-01-15 20:51:49 -06004301 hist_data->n_fields++;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004302
4303 if (WARN_ON(hist_data->n_keys > TRACING_MAP_KEYS_MAX))
4304 return -EINVAL;
4305
4306 ret = key_size;
4307 out:
4308 return ret;
4309}
4310
4311static int create_key_fields(struct hist_trigger_data *hist_data,
4312 struct trace_event_file *file)
4313{
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004314 unsigned int i, key_offset = 0, n_vals = hist_data->n_vals;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004315 char *fields_str, *field_str;
4316 int ret = -EINVAL;
4317
4318 fields_str = hist_data->attrs->keys_str;
4319 if (!fields_str)
4320 goto out;
4321
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004322 for (i = n_vals; i < n_vals + TRACING_MAP_KEYS_MAX; i++) {
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004323 field_str = strsep(&fields_str, ",");
4324 if (!field_str)
4325 break;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004326 ret = create_key_field(hist_data, i, key_offset,
4327 file, field_str);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004328 if (ret < 0)
4329 goto out;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004330 key_offset += ret;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004331 }
4332 if (fields_str) {
4333 ret = -EINVAL;
4334 goto out;
4335 }
4336 ret = 0;
4337 out:
4338 return ret;
4339}
4340
Tom Zanussi30350d62018-01-15 20:51:49 -06004341static int create_var_fields(struct hist_trigger_data *hist_data,
4342 struct trace_event_file *file)
4343{
4344 unsigned int i, j = hist_data->n_vals;
4345 int ret = 0;
4346
4347 unsigned int n_vars = hist_data->attrs->var_defs.n_vars;
4348
4349 for (i = 0; i < n_vars; i++) {
4350 char *var_name = hist_data->attrs->var_defs.name[i];
4351 char *expr = hist_data->attrs->var_defs.expr[i];
4352
4353 ret = create_var_field(hist_data, j++, file, var_name, expr);
4354 if (ret)
4355 goto out;
4356 }
4357 out:
4358 return ret;
4359}
4360
4361static void free_var_defs(struct hist_trigger_data *hist_data)
4362{
4363 unsigned int i;
4364
4365 for (i = 0; i < hist_data->attrs->var_defs.n_vars; i++) {
4366 kfree(hist_data->attrs->var_defs.name[i]);
4367 kfree(hist_data->attrs->var_defs.expr[i]);
4368 }
4369
4370 hist_data->attrs->var_defs.n_vars = 0;
4371}
4372
4373static int parse_var_defs(struct hist_trigger_data *hist_data)
4374{
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004375 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussi30350d62018-01-15 20:51:49 -06004376 char *s, *str, *var_name, *field_str;
4377 unsigned int i, j, n_vars = 0;
4378 int ret = 0;
4379
4380 for (i = 0; i < hist_data->attrs->n_assignments; i++) {
4381 str = hist_data->attrs->assignment_str[i];
4382 for (j = 0; j < TRACING_MAP_VARS_MAX; j++) {
4383 field_str = strsep(&str, ",");
4384 if (!field_str)
4385 break;
4386
4387 var_name = strsep(&field_str, "=");
4388 if (!var_name || !field_str) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004389 hist_err(tr, HIST_ERR_MALFORMED_ASSIGNMENT,
4390 errpos(var_name));
Tom Zanussi30350d62018-01-15 20:51:49 -06004391 ret = -EINVAL;
4392 goto free;
4393 }
4394
4395 if (n_vars == TRACING_MAP_VARS_MAX) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004396 hist_err(tr, HIST_ERR_TOO_MANY_VARS, errpos(var_name));
Tom Zanussi30350d62018-01-15 20:51:49 -06004397 ret = -EINVAL;
4398 goto free;
4399 }
4400
4401 s = kstrdup(var_name, GFP_KERNEL);
4402 if (!s) {
4403 ret = -ENOMEM;
4404 goto free;
4405 }
4406 hist_data->attrs->var_defs.name[n_vars] = s;
4407
4408 s = kstrdup(field_str, GFP_KERNEL);
4409 if (!s) {
Tom Zanussi30350d62018-01-15 20:51:49 -06004410 ret = -ENOMEM;
4411 goto free;
4412 }
4413 hist_data->attrs->var_defs.expr[n_vars++] = s;
4414
4415 hist_data->attrs->var_defs.n_vars = n_vars;
4416 }
4417 }
4418
4419 return ret;
4420 free:
4421 free_var_defs(hist_data);
4422
4423 return ret;
4424}
4425
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004426static int create_hist_fields(struct hist_trigger_data *hist_data,
4427 struct trace_event_file *file)
4428{
4429 int ret;
4430
Tom Zanussi30350d62018-01-15 20:51:49 -06004431 ret = parse_var_defs(hist_data);
4432 if (ret)
4433 goto out;
4434
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004435 ret = create_val_fields(hist_data, file);
4436 if (ret)
4437 goto out;
4438
Tom Zanussi30350d62018-01-15 20:51:49 -06004439 ret = create_var_fields(hist_data, file);
4440 if (ret)
4441 goto out;
4442
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004443 ret = create_key_fields(hist_data, file);
4444 if (ret)
4445 goto out;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004446 out:
Tom Zanussi30350d62018-01-15 20:51:49 -06004447 free_var_defs(hist_data);
4448
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004449 return ret;
4450}
4451
Tom Zanussi4de26c82019-06-28 12:40:21 -05004452static int is_descending(struct trace_array *tr, const char *str)
Tom Zanussie62347d2016-03-03 12:54:45 -06004453{
4454 if (!str)
4455 return 0;
4456
4457 if (strcmp(str, "descending") == 0)
4458 return 1;
4459
4460 if (strcmp(str, "ascending") == 0)
4461 return 0;
4462
Tom Zanussi4de26c82019-06-28 12:40:21 -05004463 hist_err(tr, HIST_ERR_INVALID_SORT_MODIFIER, errpos((char *)str));
4464
Tom Zanussie62347d2016-03-03 12:54:45 -06004465 return -EINVAL;
4466}
4467
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004468static int create_sort_keys(struct hist_trigger_data *hist_data)
4469{
Tom Zanussi4de26c82019-06-28 12:40:21 -05004470 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussie62347d2016-03-03 12:54:45 -06004471 char *fields_str = hist_data->attrs->sort_key_str;
Tom Zanussie62347d2016-03-03 12:54:45 -06004472 struct tracing_map_sort_key *sort_key;
4473 int descending, ret = 0;
Tom Zanussi30350d62018-01-15 20:51:49 -06004474 unsigned int i, j, k;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004475
Tom Zanussie62347d2016-03-03 12:54:45 -06004476 hist_data->n_sort_keys = 1; /* we always have at least one, hitcount */
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004477
Tom Zanussie62347d2016-03-03 12:54:45 -06004478 if (!fields_str)
4479 goto out;
4480
Tom Zanussie62347d2016-03-03 12:54:45 -06004481 for (i = 0; i < TRACING_MAP_SORT_KEYS_MAX; i++) {
Tom Zanussi85013252017-09-22 14:58:22 -05004482 struct hist_field *hist_field;
Tom Zanussie62347d2016-03-03 12:54:45 -06004483 char *field_str, *field_name;
Tom Zanussi85013252017-09-22 14:58:22 -05004484 const char *test_name;
Tom Zanussie62347d2016-03-03 12:54:45 -06004485
4486 sort_key = &hist_data->sort_keys[i];
4487
4488 field_str = strsep(&fields_str, ",");
Tom Zanussib527b632019-06-28 12:40:20 -05004489 if (!field_str)
4490 break;
4491
4492 if (!*field_str) {
4493 ret = -EINVAL;
Tom Zanussi4de26c82019-06-28 12:40:21 -05004494 hist_err(tr, HIST_ERR_EMPTY_SORT_FIELD, errpos("sort="));
Tom Zanussie62347d2016-03-03 12:54:45 -06004495 break;
4496 }
4497
4498 if ((i == TRACING_MAP_SORT_KEYS_MAX - 1) && fields_str) {
Tom Zanussi4de26c82019-06-28 12:40:21 -05004499 hist_err(tr, HIST_ERR_TOO_MANY_SORT_FIELDS, errpos("sort="));
Tom Zanussie62347d2016-03-03 12:54:45 -06004500 ret = -EINVAL;
4501 break;
4502 }
4503
4504 field_name = strsep(&field_str, ".");
Tom Zanussib527b632019-06-28 12:40:20 -05004505 if (!field_name || !*field_name) {
Tom Zanussie62347d2016-03-03 12:54:45 -06004506 ret = -EINVAL;
Tom Zanussi4de26c82019-06-28 12:40:21 -05004507 hist_err(tr, HIST_ERR_EMPTY_SORT_FIELD, errpos("sort="));
Tom Zanussie62347d2016-03-03 12:54:45 -06004508 break;
4509 }
4510
4511 if (strcmp(field_name, "hitcount") == 0) {
Tom Zanussi4de26c82019-06-28 12:40:21 -05004512 descending = is_descending(tr, field_str);
Tom Zanussie62347d2016-03-03 12:54:45 -06004513 if (descending < 0) {
4514 ret = descending;
4515 break;
4516 }
4517 sort_key->descending = descending;
4518 continue;
4519 }
4520
Tom Zanussi30350d62018-01-15 20:51:49 -06004521 for (j = 1, k = 1; j < hist_data->n_fields; j++) {
4522 unsigned int idx;
4523
Tom Zanussi85013252017-09-22 14:58:22 -05004524 hist_field = hist_data->fields[j];
Tom Zanussi30350d62018-01-15 20:51:49 -06004525 if (hist_field->flags & HIST_FIELD_FL_VAR)
4526 continue;
4527
4528 idx = k++;
4529
Tom Zanussi85013252017-09-22 14:58:22 -05004530 test_name = hist_field_name(hist_field, 0);
4531
4532 if (strcmp(field_name, test_name) == 0) {
Tom Zanussi30350d62018-01-15 20:51:49 -06004533 sort_key->field_idx = idx;
Tom Zanussi4de26c82019-06-28 12:40:21 -05004534 descending = is_descending(tr, field_str);
Tom Zanussie62347d2016-03-03 12:54:45 -06004535 if (descending < 0) {
4536 ret = descending;
4537 goto out;
4538 }
4539 sort_key->descending = descending;
4540 break;
4541 }
4542 }
4543 if (j == hist_data->n_fields) {
4544 ret = -EINVAL;
Tom Zanussi4de26c82019-06-28 12:40:21 -05004545 hist_err(tr, HIST_ERR_INVALID_SORT_FIELD, errpos(field_name));
Tom Zanussie62347d2016-03-03 12:54:45 -06004546 break;
4547 }
4548 }
Tom Zanussi30350d62018-01-15 20:51:49 -06004549
Tom Zanussie62347d2016-03-03 12:54:45 -06004550 hist_data->n_sort_keys = i;
4551 out:
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004552 return ret;
4553}
4554
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004555static void destroy_actions(struct hist_trigger_data *hist_data)
4556{
4557 unsigned int i;
4558
4559 for (i = 0; i < hist_data->n_actions; i++) {
4560 struct action_data *data = hist_data->actions[i];
4561
Tom Zanussi7d18a102019-02-13 17:42:41 -06004562 if (data->handler == HANDLER_ONMATCH)
Tom Zanussic282a382018-01-15 20:52:00 -06004563 onmatch_destroy(data);
Tom Zanussidff81f52019-02-13 17:42:48 -06004564 else if (data->handler == HANDLER_ONMAX ||
4565 data->handler == HANDLER_ONCHANGE)
Tom Zanussi466f4522019-02-13 17:42:44 -06004566 track_data_destroy(hist_data, data);
Tom Zanussic282a382018-01-15 20:52:00 -06004567 else
4568 kfree(data);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004569 }
4570}
4571
4572static int parse_actions(struct hist_trigger_data *hist_data)
4573{
Tom Zanussic282a382018-01-15 20:52:00 -06004574 struct trace_array *tr = hist_data->event_file->tr;
4575 struct action_data *data;
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004576 unsigned int i;
4577 int ret = 0;
4578 char *str;
Steven Rostedt (VMware)036876f2018-12-21 18:40:46 -05004579 int len;
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004580
4581 for (i = 0; i < hist_data->attrs->n_actions; i++) {
4582 str = hist_data->attrs->action_str[i];
Tom Zanussic282a382018-01-15 20:52:00 -06004583
Steven Rostedt (VMware)036876f2018-12-21 18:40:46 -05004584 if ((len = str_has_prefix(str, "onmatch("))) {
4585 char *action_str = str + len;
Tom Zanussic282a382018-01-15 20:52:00 -06004586
4587 data = onmatch_parse(tr, action_str);
4588 if (IS_ERR(data)) {
4589 ret = PTR_ERR(data);
4590 break;
4591 }
Steven Rostedt (VMware)036876f2018-12-21 18:40:46 -05004592 } else if ((len = str_has_prefix(str, "onmax("))) {
4593 char *action_str = str + len;
Tom Zanussi50450602018-01-15 20:52:01 -06004594
Tom Zanussi466f4522019-02-13 17:42:44 -06004595 data = track_data_parse(hist_data, action_str,
4596 HANDLER_ONMAX);
Tom Zanussi50450602018-01-15 20:52:01 -06004597 if (IS_ERR(data)) {
4598 ret = PTR_ERR(data);
4599 break;
4600 }
Tom Zanussidff81f52019-02-13 17:42:48 -06004601 } else if ((len = str_has_prefix(str, "onchange("))) {
4602 char *action_str = str + len;
4603
4604 data = track_data_parse(hist_data, action_str,
4605 HANDLER_ONCHANGE);
4606 if (IS_ERR(data)) {
4607 ret = PTR_ERR(data);
4608 break;
4609 }
Tom Zanussic282a382018-01-15 20:52:00 -06004610 } else {
4611 ret = -EINVAL;
4612 break;
4613 }
4614
4615 hist_data->actions[hist_data->n_actions++] = data;
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004616 }
4617
4618 return ret;
4619}
4620
Tom Zanussi7d18a102019-02-13 17:42:41 -06004621static int create_actions(struct hist_trigger_data *hist_data)
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004622{
4623 struct action_data *data;
4624 unsigned int i;
4625 int ret = 0;
4626
4627 for (i = 0; i < hist_data->attrs->n_actions; i++) {
4628 data = hist_data->actions[i];
Tom Zanussic282a382018-01-15 20:52:00 -06004629
Tom Zanussi7d18a102019-02-13 17:42:41 -06004630 if (data->handler == HANDLER_ONMATCH) {
4631 ret = onmatch_create(hist_data, data);
Tom Zanussic282a382018-01-15 20:52:00 -06004632 if (ret)
Tom Zanussi7d18a102019-02-13 17:42:41 -06004633 break;
Tom Zanussidff81f52019-02-13 17:42:48 -06004634 } else if (data->handler == HANDLER_ONMAX ||
4635 data->handler == HANDLER_ONCHANGE) {
Tom Zanussi466f4522019-02-13 17:42:44 -06004636 ret = track_data_create(hist_data, data);
Tom Zanussi50450602018-01-15 20:52:01 -06004637 if (ret)
Tom Zanussi7d18a102019-02-13 17:42:41 -06004638 break;
4639 } else {
4640 ret = -EINVAL;
4641 break;
Tom Zanussic282a382018-01-15 20:52:00 -06004642 }
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004643 }
4644
4645 return ret;
4646}
4647
Tom Zanussi50450602018-01-15 20:52:01 -06004648static void print_actions(struct seq_file *m,
4649 struct hist_trigger_data *hist_data,
4650 struct tracing_map_elt *elt)
4651{
4652 unsigned int i;
4653
4654 for (i = 0; i < hist_data->n_actions; i++) {
4655 struct action_data *data = hist_data->actions[i];
4656
Tom Zanussia3785b72019-02-13 17:42:46 -06004657 if (data->action == ACTION_SNAPSHOT)
4658 continue;
4659
Tom Zanussidff81f52019-02-13 17:42:48 -06004660 if (data->handler == HANDLER_ONMAX ||
4661 data->handler == HANDLER_ONCHANGE)
Tom Zanussi466f4522019-02-13 17:42:44 -06004662 track_data_print(m, hist_data, elt, data);
Tom Zanussi50450602018-01-15 20:52:01 -06004663 }
4664}
4665
Tom Zanussi7d18a102019-02-13 17:42:41 -06004666static void print_action_spec(struct seq_file *m,
4667 struct hist_trigger_data *hist_data,
4668 struct action_data *data)
4669{
4670 unsigned int i;
4671
4672 if (data->action == ACTION_SAVE) {
4673 for (i = 0; i < hist_data->n_save_vars; i++) {
4674 seq_printf(m, "%s", hist_data->save_vars[i]->var->var.name);
4675 if (i < hist_data->n_save_vars - 1)
4676 seq_puts(m, ",");
4677 }
4678 } else if (data->action == ACTION_TRACE) {
Tom Zanussie91eefd72019-02-13 17:42:50 -06004679 if (data->use_trace_keyword)
4680 seq_printf(m, "%s", data->synth_event_name);
Tom Zanussi7d18a102019-02-13 17:42:41 -06004681 for (i = 0; i < data->n_params; i++) {
Tom Zanussie91eefd72019-02-13 17:42:50 -06004682 if (i || data->use_trace_keyword)
Tom Zanussi7d18a102019-02-13 17:42:41 -06004683 seq_puts(m, ",");
4684 seq_printf(m, "%s", data->params[i]);
4685 }
4686 }
4687}
4688
Tom Zanussi466f4522019-02-13 17:42:44 -06004689static void print_track_data_spec(struct seq_file *m,
4690 struct hist_trigger_data *hist_data,
4691 struct action_data *data)
Tom Zanussi50450602018-01-15 20:52:01 -06004692{
Tom Zanussi466f4522019-02-13 17:42:44 -06004693 if (data->handler == HANDLER_ONMAX)
4694 seq_puts(m, ":onmax(");
Tom Zanussidff81f52019-02-13 17:42:48 -06004695 else if (data->handler == HANDLER_ONCHANGE)
4696 seq_puts(m, ":onchange(");
Tom Zanussi466f4522019-02-13 17:42:44 -06004697 seq_printf(m, "%s", data->track_data.var_str);
Tom Zanussi7d18a102019-02-13 17:42:41 -06004698 seq_printf(m, ").%s(", data->action_name);
Tom Zanussi50450602018-01-15 20:52:01 -06004699
Tom Zanussi7d18a102019-02-13 17:42:41 -06004700 print_action_spec(m, hist_data, data);
4701
Tom Zanussi50450602018-01-15 20:52:01 -06004702 seq_puts(m, ")");
4703}
4704
Tom Zanussic282a382018-01-15 20:52:00 -06004705static void print_onmatch_spec(struct seq_file *m,
4706 struct hist_trigger_data *hist_data,
4707 struct action_data *data)
4708{
Tom Zanussic3e49502019-02-13 17:42:43 -06004709 seq_printf(m, ":onmatch(%s.%s).", data->match_data.event_system,
4710 data->match_data.event);
Tom Zanussic282a382018-01-15 20:52:00 -06004711
Tom Zanussi7d18a102019-02-13 17:42:41 -06004712 seq_printf(m, "%s(", data->action_name);
Tom Zanussic282a382018-01-15 20:52:00 -06004713
Tom Zanussi7d18a102019-02-13 17:42:41 -06004714 print_action_spec(m, hist_data, data);
Tom Zanussic282a382018-01-15 20:52:00 -06004715
4716 seq_puts(m, ")");
4717}
4718
Tom Zanussi48f79472018-03-28 15:10:55 -05004719static bool actions_match(struct hist_trigger_data *hist_data,
4720 struct hist_trigger_data *hist_data_test)
4721{
4722 unsigned int i, j;
4723
4724 if (hist_data->n_actions != hist_data_test->n_actions)
4725 return false;
4726
4727 for (i = 0; i < hist_data->n_actions; i++) {
4728 struct action_data *data = hist_data->actions[i];
4729 struct action_data *data_test = hist_data_test->actions[i];
Tom Zanussie91eefd72019-02-13 17:42:50 -06004730 char *action_name, *action_name_test;
Tom Zanussi48f79472018-03-28 15:10:55 -05004731
Tom Zanussi7d18a102019-02-13 17:42:41 -06004732 if (data->handler != data_test->handler)
4733 return false;
4734 if (data->action != data_test->action)
Tom Zanussi48f79472018-03-28 15:10:55 -05004735 return false;
4736
4737 if (data->n_params != data_test->n_params)
4738 return false;
4739
4740 for (j = 0; j < data->n_params; j++) {
4741 if (strcmp(data->params[j], data_test->params[j]) != 0)
4742 return false;
4743 }
4744
Tom Zanussie91eefd72019-02-13 17:42:50 -06004745 if (data->use_trace_keyword)
4746 action_name = data->synth_event_name;
4747 else
4748 action_name = data->action_name;
4749
4750 if (data_test->use_trace_keyword)
4751 action_name_test = data_test->synth_event_name;
4752 else
4753 action_name_test = data_test->action_name;
4754
4755 if (strcmp(action_name, action_name_test) != 0)
Tom Zanussi7d18a102019-02-13 17:42:41 -06004756 return false;
4757
4758 if (data->handler == HANDLER_ONMATCH) {
Tom Zanussic3e49502019-02-13 17:42:43 -06004759 if (strcmp(data->match_data.event_system,
4760 data_test->match_data.event_system) != 0)
Tom Zanussi48f79472018-03-28 15:10:55 -05004761 return false;
Tom Zanussic3e49502019-02-13 17:42:43 -06004762 if (strcmp(data->match_data.event,
4763 data_test->match_data.event) != 0)
Tom Zanussi48f79472018-03-28 15:10:55 -05004764 return false;
Tom Zanussidff81f52019-02-13 17:42:48 -06004765 } else if (data->handler == HANDLER_ONMAX ||
4766 data->handler == HANDLER_ONCHANGE) {
Tom Zanussi466f4522019-02-13 17:42:44 -06004767 if (strcmp(data->track_data.var_str,
4768 data_test->track_data.var_str) != 0)
Tom Zanussi48f79472018-03-28 15:10:55 -05004769 return false;
Tom Zanussi48f79472018-03-28 15:10:55 -05004770 }
4771 }
4772
4773 return true;
4774}
4775
4776
Tom Zanussic282a382018-01-15 20:52:00 -06004777static void print_actions_spec(struct seq_file *m,
4778 struct hist_trigger_data *hist_data)
4779{
4780 unsigned int i;
4781
4782 for (i = 0; i < hist_data->n_actions; i++) {
4783 struct action_data *data = hist_data->actions[i];
4784
Tom Zanussi7d18a102019-02-13 17:42:41 -06004785 if (data->handler == HANDLER_ONMATCH)
Tom Zanussic282a382018-01-15 20:52:00 -06004786 print_onmatch_spec(m, hist_data, data);
Tom Zanussidff81f52019-02-13 17:42:48 -06004787 else if (data->handler == HANDLER_ONMAX ||
4788 data->handler == HANDLER_ONCHANGE)
Tom Zanussi466f4522019-02-13 17:42:44 -06004789 print_track_data_spec(m, hist_data, data);
Tom Zanussic282a382018-01-15 20:52:00 -06004790 }
4791}
4792
Tom Zanussi02205a62018-01-15 20:51:59 -06004793static void destroy_field_var_hists(struct hist_trigger_data *hist_data)
4794{
4795 unsigned int i;
4796
4797 for (i = 0; i < hist_data->n_field_var_hists; i++) {
4798 kfree(hist_data->field_var_hists[i]->cmd);
4799 kfree(hist_data->field_var_hists[i]);
4800 }
4801}
4802
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004803static void destroy_hist_data(struct hist_trigger_data *hist_data)
4804{
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004805 if (!hist_data)
4806 return;
4807
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004808 destroy_hist_trigger_attrs(hist_data->attrs);
4809 destroy_hist_fields(hist_data);
4810 tracing_map_destroy(hist_data->map);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004811
4812 destroy_actions(hist_data);
Tom Zanussi02205a62018-01-15 20:51:59 -06004813 destroy_field_vars(hist_data);
4814 destroy_field_var_hists(hist_data);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004815
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004816 kfree(hist_data);
4817}
4818
4819static int create_tracing_map_fields(struct hist_trigger_data *hist_data)
4820{
4821 struct tracing_map *map = hist_data->map;
4822 struct ftrace_event_field *field;
4823 struct hist_field *hist_field;
Dan Carpenterb28d7b22018-03-28 14:48:15 +03004824 int i, idx = 0;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004825
4826 for_each_hist_field(i, hist_data) {
4827 hist_field = hist_data->fields[i];
4828 if (hist_field->flags & HIST_FIELD_FL_KEY) {
4829 tracing_map_cmp_fn_t cmp_fn;
4830
4831 field = hist_field->field;
4832
Tom Zanussi69a02002016-03-03 12:54:52 -06004833 if (hist_field->flags & HIST_FIELD_FL_STACKTRACE)
4834 cmp_fn = tracing_map_cmp_none;
Tom Zanussiad42feb2018-01-15 20:51:45 -06004835 else if (!field)
4836 cmp_fn = tracing_map_cmp_num(hist_field->size,
4837 hist_field->is_signed);
Tom Zanussi69a02002016-03-03 12:54:52 -06004838 else if (is_string_field(field))
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004839 cmp_fn = tracing_map_cmp_string;
4840 else
4841 cmp_fn = tracing_map_cmp_num(field->size,
4842 field->is_signed);
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004843 idx = tracing_map_add_key_field(map,
4844 hist_field->offset,
4845 cmp_fn);
Tom Zanussi30350d62018-01-15 20:51:49 -06004846 } else if (!(hist_field->flags & HIST_FIELD_FL_VAR))
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004847 idx = tracing_map_add_sum_field(map);
4848
4849 if (idx < 0)
4850 return idx;
Tom Zanussi30350d62018-01-15 20:51:49 -06004851
4852 if (hist_field->flags & HIST_FIELD_FL_VAR) {
4853 idx = tracing_map_add_var(map);
4854 if (idx < 0)
4855 return idx;
4856 hist_field->var.idx = idx;
4857 hist_field->var.hist_data = hist_data;
4858 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004859 }
4860
4861 return 0;
4862}
4863
4864static struct hist_trigger_data *
4865create_hist_data(unsigned int map_bits,
4866 struct hist_trigger_attrs *attrs,
Tom Zanussi30350d62018-01-15 20:51:49 -06004867 struct trace_event_file *file,
4868 bool remove)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004869{
Tom Zanussi6b4827a2016-03-03 12:54:50 -06004870 const struct tracing_map_ops *map_ops = NULL;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004871 struct hist_trigger_data *hist_data;
4872 int ret = 0;
4873
4874 hist_data = kzalloc(sizeof(*hist_data), GFP_KERNEL);
4875 if (!hist_data)
4876 return ERR_PTR(-ENOMEM);
4877
4878 hist_data->attrs = attrs;
Tom Zanussi30350d62018-01-15 20:51:49 -06004879 hist_data->remove = remove;
Tom Zanussi067fe032018-01-15 20:51:56 -06004880 hist_data->event_file = file;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004881
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004882 ret = parse_actions(hist_data);
4883 if (ret)
4884 goto free;
4885
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004886 ret = create_hist_fields(hist_data, file);
4887 if (ret)
4888 goto free;
4889
4890 ret = create_sort_keys(hist_data);
4891 if (ret)
4892 goto free;
4893
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06004894 map_ops = &hist_trigger_elt_data_ops;
Tom Zanussi6b4827a2016-03-03 12:54:50 -06004895
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004896 hist_data->map = tracing_map_create(map_bits, hist_data->key_size,
Tom Zanussi6b4827a2016-03-03 12:54:50 -06004897 map_ops, hist_data);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004898 if (IS_ERR(hist_data->map)) {
4899 ret = PTR_ERR(hist_data->map);
4900 hist_data->map = NULL;
4901 goto free;
4902 }
4903
4904 ret = create_tracing_map_fields(hist_data);
4905 if (ret)
4906 goto free;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004907 out:
4908 return hist_data;
4909 free:
4910 hist_data->attrs = NULL;
4911
4912 destroy_hist_data(hist_data);
4913
4914 hist_data = ERR_PTR(ret);
4915
4916 goto out;
4917}
4918
4919static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04004920 struct tracing_map_elt *elt,
4921 struct trace_buffer *buffer, void *rec,
Tom Zanussi067fe032018-01-15 20:51:56 -06004922 struct ring_buffer_event *rbe,
4923 u64 *var_ref_vals)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004924{
Tom Zanussi067fe032018-01-15 20:51:56 -06004925 struct hist_elt_data *elt_data;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004926 struct hist_field *hist_field;
Tom Zanussi30350d62018-01-15 20:51:49 -06004927 unsigned int i, var_idx;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004928 u64 hist_val;
4929
Tom Zanussi067fe032018-01-15 20:51:56 -06004930 elt_data = elt->private_data;
4931 elt_data->var_ref_vals = var_ref_vals;
4932
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004933 for_each_hist_val_field(i, hist_data) {
4934 hist_field = hist_data->fields[i];
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04004935 hist_val = hist_field->fn(hist_field, elt, buffer, rbe, rec);
Tom Zanussi30350d62018-01-15 20:51:49 -06004936 if (hist_field->flags & HIST_FIELD_FL_VAR) {
4937 var_idx = hist_field->var.idx;
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004938
4939 if (hist_field->flags & HIST_FIELD_FL_STRING) {
4940 unsigned int str_start, var_str_idx, idx;
4941 char *str, *val_str;
Steven Rostedt (VMware)938aa332021-11-14 13:28:34 -05004942 unsigned int size;
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004943
4944 str_start = hist_data->n_field_var_str +
4945 hist_data->n_save_var_str;
4946 var_str_idx = hist_field->var_str_idx;
4947 idx = str_start + var_str_idx;
4948
4949 str = elt_data->field_var_str[idx];
4950 val_str = (char *)(uintptr_t)hist_val;
Steven Rostedt (VMware)938aa332021-11-14 13:28:34 -05004951
4952 size = min(hist_field->size, STR_VAR_LEN_MAX);
4953 strscpy(str, val_str, size);
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004954
4955 hist_val = (u64)(uintptr_t)str;
4956 }
Tom Zanussi30350d62018-01-15 20:51:49 -06004957 tracing_map_set_var(elt, var_idx, hist_val);
4958 continue;
4959 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004960 tracing_map_update_sum(elt, i, hist_val);
4961 }
Tom Zanussi30350d62018-01-15 20:51:49 -06004962
4963 for_each_hist_key_field(i, hist_data) {
4964 hist_field = hist_data->fields[i];
4965 if (hist_field->flags & HIST_FIELD_FL_VAR) {
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04004966 hist_val = hist_field->fn(hist_field, elt, buffer, rbe, rec);
Tom Zanussi30350d62018-01-15 20:51:49 -06004967 var_idx = hist_field->var.idx;
4968 tracing_map_set_var(elt, var_idx, hist_val);
4969 }
4970 }
Tom Zanussi02205a62018-01-15 20:51:59 -06004971
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04004972 update_field_vars(hist_data, elt, buffer, rbe, rec);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004973}
4974
Tom Zanussi6a475cb2016-03-03 12:54:54 -06004975static inline void add_to_key(char *compound_key, void *key,
4976 struct hist_field *key_field, void *rec)
4977{
4978 size_t size = key_field->size;
4979
4980 if (key_field->flags & HIST_FIELD_FL_STRING) {
4981 struct ftrace_event_field *field;
4982
4983 field = key_field->field;
Masami Hiramatsu05770dd2021-11-22 18:30:12 +09004984 if (field->filter_type == FILTER_DYN_STRING ||
4985 field->filter_type == FILTER_RDYN_STRING)
Tom Zanussi6a475cb2016-03-03 12:54:54 -06004986 size = *(u32 *)(rec + field->offset) >> 16;
Tom Zanussi6a475cb2016-03-03 12:54:54 -06004987 else if (field->filter_type == FILTER_STATIC_STRING)
4988 size = field->size;
4989
4990 /* ensure NULL-termination */
4991 if (size > key_field->size - 1)
4992 size = key_field->size - 1;
Tom Zanussi6a475cb2016-03-03 12:54:54 -06004993
Tom Zanussi9f0bbf32019-02-04 15:07:24 -06004994 strncpy(compound_key + key_field->offset, (char *)key, size);
4995 } else
4996 memcpy(compound_key + key_field->offset, key, size);
Tom Zanussi6a475cb2016-03-03 12:54:54 -06004997}
4998
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004999static void
5000hist_trigger_actions(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005001 struct tracing_map_elt *elt,
5002 struct trace_buffer *buffer, void *rec,
Tom Zanussi7d18a102019-02-13 17:42:41 -06005003 struct ring_buffer_event *rbe, void *key,
5004 u64 *var_ref_vals)
Tom Zanussi0212e2a2018-01-15 20:51:57 -06005005{
5006 struct action_data *data;
5007 unsigned int i;
5008
5009 for (i = 0; i < hist_data->n_actions; i++) {
5010 data = hist_data->actions[i];
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005011 data->fn(hist_data, elt, buffer, rec, rbe, key, data, var_ref_vals);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06005012 }
5013}
5014
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005015static void event_hist_trigger(struct event_trigger_data *data,
5016 struct trace_buffer *buffer, void *rec,
Tom Zanussifbd302c2018-01-15 20:51:43 -06005017 struct ring_buffer_event *rbe)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005018{
5019 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005020 bool use_compound_key = (hist_data->n_keys > 1);
Tom Zanussi69a02002016-03-03 12:54:52 -06005021 unsigned long entries[HIST_STACKTRACE_DEPTH];
Tom Zanussi067fe032018-01-15 20:51:56 -06005022 u64 var_ref_vals[TRACING_MAP_VARS_MAX];
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005023 char compound_key[HIST_KEY_SIZE_MAX];
Tom Zanussidf35d932018-01-15 20:51:54 -06005024 struct tracing_map_elt *elt = NULL;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005025 struct hist_field *key_field;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005026 u64 field_contents;
5027 void *key = NULL;
5028 unsigned int i;
5029
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005030 memset(compound_key, 0, hist_data->key_size);
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005031
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005032 for_each_hist_key_field(i, hist_data) {
5033 key_field = hist_data->fields[i];
5034
Tom Zanussi69a02002016-03-03 12:54:52 -06005035 if (key_field->flags & HIST_FIELD_FL_STACKTRACE) {
Thomas Gleixnere7d91662019-04-25 11:45:13 +02005036 memset(entries, 0, HIST_STACKTRACE_SIZE);
5037 stack_trace_save(entries, HIST_STACKTRACE_DEPTH,
5038 HIST_STACKTRACE_SKIP);
Tom Zanussi69a02002016-03-03 12:54:52 -06005039 key = entries;
5040 } else {
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005041 field_contents = key_field->fn(key_field, elt, buffer, rbe, rec);
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005042 if (key_field->flags & HIST_FIELD_FL_STRING) {
Tom Zanussi69a02002016-03-03 12:54:52 -06005043 key = (void *)(unsigned long)field_contents;
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005044 use_compound_key = true;
5045 } else
Tom Zanussi69a02002016-03-03 12:54:52 -06005046 key = (void *)&field_contents;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005047 }
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005048
5049 if (use_compound_key)
5050 add_to_key(compound_key, key, key_field, rec);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005051 }
5052
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005053 if (use_compound_key)
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005054 key = compound_key;
5055
Tom Zanussi067fe032018-01-15 20:51:56 -06005056 if (hist_data->n_var_refs &&
5057 !resolve_var_refs(hist_data, key, var_ref_vals, false))
5058 return;
5059
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005060 elt = tracing_map_insert(hist_data->map, key);
Tom Zanussi067fe032018-01-15 20:51:56 -06005061 if (!elt)
5062 return;
5063
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005064 hist_trigger_elt_update(hist_data, elt, buffer, rec, rbe, var_ref_vals);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06005065
5066 if (resolve_var_refs(hist_data, key, var_ref_vals, true))
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005067 hist_trigger_actions(hist_data, elt, buffer, rec, rbe, key, var_ref_vals);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005068}
5069
Tom Zanussi69a02002016-03-03 12:54:52 -06005070static void hist_trigger_stacktrace_print(struct seq_file *m,
5071 unsigned long *stacktrace_entries,
5072 unsigned int max_entries)
5073{
Tom Zanussi69a02002016-03-03 12:54:52 -06005074 unsigned int spaces = 8;
5075 unsigned int i;
5076
5077 for (i = 0; i < max_entries; i++) {
Thomas Gleixner4285f2f2019-04-10 12:28:10 +02005078 if (!stacktrace_entries[i])
Tom Zanussi69a02002016-03-03 12:54:52 -06005079 return;
5080
5081 seq_printf(m, "%*c", 1 + spaces, ' ');
Arnd Bergmann8720aee2021-10-19 17:33:13 +02005082 seq_printf(m, "%pS\n", (void*)stacktrace_entries[i]);
Tom Zanussi69a02002016-03-03 12:54:52 -06005083 }
5084}
5085
Tom Zanussia3785b72019-02-13 17:42:46 -06005086static void hist_trigger_print_key(struct seq_file *m,
5087 struct hist_trigger_data *hist_data,
5088 void *key,
5089 struct tracing_map_elt *elt)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005090{
5091 struct hist_field *key_field;
Tom Zanussi69a02002016-03-03 12:54:52 -06005092 bool multiline = false;
Tom Zanussi85013252017-09-22 14:58:22 -05005093 const char *field_name;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005094 unsigned int i;
5095 u64 uval;
5096
5097 seq_puts(m, "{ ");
5098
5099 for_each_hist_key_field(i, hist_data) {
5100 key_field = hist_data->fields[i];
5101
5102 if (i > hist_data->n_vals)
5103 seq_puts(m, ", ");
5104
Tom Zanussi85013252017-09-22 14:58:22 -05005105 field_name = hist_field_name(key_field, 0);
5106
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06005107 if (key_field->flags & HIST_FIELD_FL_HEX) {
5108 uval = *(u64 *)(key + key_field->offset);
Tom Zanussi85013252017-09-22 14:58:22 -05005109 seq_printf(m, "%s: %llx", field_name, uval);
Tom Zanussic6afad42016-03-03 12:54:49 -06005110 } else if (key_field->flags & HIST_FIELD_FL_SYM) {
5111 uval = *(u64 *)(key + key_field->offset);
Arnd Bergmann8720aee2021-10-19 17:33:13 +02005112 seq_printf(m, "%s: [%llx] %-45ps", field_name,
5113 uval, (void *)(uintptr_t)uval);
Tom Zanussic6afad42016-03-03 12:54:49 -06005114 } else if (key_field->flags & HIST_FIELD_FL_SYM_OFFSET) {
5115 uval = *(u64 *)(key + key_field->offset);
Arnd Bergmann8720aee2021-10-19 17:33:13 +02005116 seq_printf(m, "%s: [%llx] %-55pS", field_name,
5117 uval, (void *)(uintptr_t)uval);
Tom Zanussi6b4827a2016-03-03 12:54:50 -06005118 } else if (key_field->flags & HIST_FIELD_FL_EXECNAME) {
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06005119 struct hist_elt_data *elt_data = elt->private_data;
5120 char *comm;
5121
5122 if (WARN_ON_ONCE(!elt_data))
5123 return;
5124
5125 comm = elt_data->comm;
Tom Zanussi6b4827a2016-03-03 12:54:50 -06005126
5127 uval = *(u64 *)(key + key_field->offset);
Tom Zanussi85013252017-09-22 14:58:22 -05005128 seq_printf(m, "%s: %-16s[%10llu]", field_name,
5129 comm, uval);
Tom Zanussi31696192016-03-03 12:54:51 -06005130 } else if (key_field->flags & HIST_FIELD_FL_SYSCALL) {
5131 const char *syscall_name;
5132
5133 uval = *(u64 *)(key + key_field->offset);
5134 syscall_name = get_syscall_name(uval);
5135 if (!syscall_name)
5136 syscall_name = "unknown_syscall";
5137
Tom Zanussi85013252017-09-22 14:58:22 -05005138 seq_printf(m, "%s: %-30s[%3llu]", field_name,
5139 syscall_name, uval);
Tom Zanussi69a02002016-03-03 12:54:52 -06005140 } else if (key_field->flags & HIST_FIELD_FL_STACKTRACE) {
5141 seq_puts(m, "stacktrace:\n");
5142 hist_trigger_stacktrace_print(m,
5143 key + key_field->offset,
5144 HIST_STACKTRACE_DEPTH);
5145 multiline = true;
Namhyung Kim4b94f5b2016-03-03 12:55:02 -06005146 } else if (key_field->flags & HIST_FIELD_FL_LOG2) {
Tom Zanussi85013252017-09-22 14:58:22 -05005147 seq_printf(m, "%s: ~ 2^%-2llu", field_name,
Namhyung Kim4b94f5b2016-03-03 12:55:02 -06005148 *(u64 *)(key + key_field->offset));
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04005149 } else if (key_field->flags & HIST_FIELD_FL_BUCKET) {
5150 unsigned long buckets = key_field->buckets;
5151 uval = *(u64 *)(key + key_field->offset);
5152 seq_printf(m, "%s: ~ %llu-%llu", field_name,
5153 uval, uval + buckets -1);
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06005154 } else if (key_field->flags & HIST_FIELD_FL_STRING) {
Tom Zanussi85013252017-09-22 14:58:22 -05005155 seq_printf(m, "%s: %-50s", field_name,
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005156 (char *)(key + key_field->offset));
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005157 } else {
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005158 uval = *(u64 *)(key + key_field->offset);
Tom Zanussi85013252017-09-22 14:58:22 -05005159 seq_printf(m, "%s: %10llu", field_name, uval);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005160 }
5161 }
5162
Tom Zanussi69a02002016-03-03 12:54:52 -06005163 if (!multiline)
5164 seq_puts(m, " ");
5165
5166 seq_puts(m, "}");
Tom Zanussia3785b72019-02-13 17:42:46 -06005167}
5168
5169static void hist_trigger_entry_print(struct seq_file *m,
5170 struct hist_trigger_data *hist_data,
5171 void *key,
5172 struct tracing_map_elt *elt)
5173{
5174 const char *field_name;
5175 unsigned int i;
5176
5177 hist_trigger_print_key(m, hist_data, key, elt);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005178
5179 seq_printf(m, " hitcount: %10llu",
5180 tracing_map_read_sum(elt, HITCOUNT_IDX));
5181
Tom Zanussif2606832016-03-03 12:54:43 -06005182 for (i = 1; i < hist_data->n_vals; i++) {
Tom Zanussi85013252017-09-22 14:58:22 -05005183 field_name = hist_field_name(hist_data->fields[i], 0);
5184
Tom Zanussi100719d2018-01-15 20:51:52 -06005185 if (hist_data->fields[i]->flags & HIST_FIELD_FL_VAR ||
5186 hist_data->fields[i]->flags & HIST_FIELD_FL_EXPR)
Tom Zanussi30350d62018-01-15 20:51:49 -06005187 continue;
5188
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06005189 if (hist_data->fields[i]->flags & HIST_FIELD_FL_HEX) {
Tom Zanussi85013252017-09-22 14:58:22 -05005190 seq_printf(m, " %s: %10llx", field_name,
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06005191 tracing_map_read_sum(elt, i));
5192 } else {
Tom Zanussi85013252017-09-22 14:58:22 -05005193 seq_printf(m, " %s: %10llu", field_name,
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06005194 tracing_map_read_sum(elt, i));
5195 }
Tom Zanussif2606832016-03-03 12:54:43 -06005196 }
5197
Tom Zanussi50450602018-01-15 20:52:01 -06005198 print_actions(m, hist_data, elt);
5199
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005200 seq_puts(m, "\n");
5201}
5202
5203static int print_entries(struct seq_file *m,
5204 struct hist_trigger_data *hist_data)
5205{
5206 struct tracing_map_sort_entry **sort_entries = NULL;
5207 struct tracing_map *map = hist_data->map;
Steven Rostedt (Red Hat)d50c7442016-03-08 17:17:15 -05005208 int i, n_entries;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005209
5210 n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
5211 hist_data->n_sort_keys,
5212 &sort_entries);
5213 if (n_entries < 0)
5214 return n_entries;
5215
5216 for (i = 0; i < n_entries; i++)
5217 hist_trigger_entry_print(m, hist_data,
5218 sort_entries[i]->key,
5219 sort_entries[i]->elt);
5220
5221 tracing_map_destroy_sort_entries(sort_entries, n_entries);
5222
5223 return n_entries;
5224}
5225
Tom Zanussi52a7f162016-03-03 12:54:57 -06005226static void hist_trigger_show(struct seq_file *m,
5227 struct event_trigger_data *data, int n)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005228{
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005229 struct hist_trigger_data *hist_data;
Colin Ian King6e7a2392017-08-23 12:23:09 +01005230 int n_entries;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005231
Tom Zanussi52a7f162016-03-03 12:54:57 -06005232 if (n > 0)
5233 seq_puts(m, "\n\n");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005234
5235 seq_puts(m, "# event histogram\n#\n# trigger info: ");
5236 data->ops->print(m, data->ops, data);
Tom Zanussi52a7f162016-03-03 12:54:57 -06005237 seq_puts(m, "#\n\n");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005238
5239 hist_data = data->private_data;
5240 n_entries = print_entries(m, hist_data);
Colin Ian King6e7a2392017-08-23 12:23:09 +01005241 if (n_entries < 0)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005242 n_entries = 0;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005243
Tom Zanussia3785b72019-02-13 17:42:46 -06005244 track_data_snapshot_print(m, hist_data);
5245
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005246 seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n",
5247 (u64)atomic64_read(&hist_data->map->hits),
5248 n_entries, (u64)atomic64_read(&hist_data->map->drops));
Tom Zanussi52a7f162016-03-03 12:54:57 -06005249}
5250
5251static int hist_show(struct seq_file *m, void *v)
5252{
5253 struct event_trigger_data *data;
5254 struct trace_event_file *event_file;
5255 int n = 0, ret = 0;
5256
5257 mutex_lock(&event_mutex);
5258
5259 event_file = event_file_data(m->private);
5260 if (unlikely(!event_file)) {
5261 ret = -ENODEV;
5262 goto out_unlock;
5263 }
5264
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09005265 list_for_each_entry(data, &event_file->triggers, list) {
Tom Zanussi52a7f162016-03-03 12:54:57 -06005266 if (data->cmd_ops->trigger_type == ETT_EVENT_HIST)
5267 hist_trigger_show(m, data, n++);
5268 }
5269
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005270 out_unlock:
5271 mutex_unlock(&event_mutex);
5272
5273 return ret;
5274}
5275
5276static int event_hist_open(struct inode *inode, struct file *file)
5277{
Steven Rostedt (VMware)17911ff2019-10-11 17:22:50 -04005278 int ret;
5279
5280 ret = security_locked_down(LOCKDOWN_TRACEFS);
5281 if (ret)
5282 return ret;
5283
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005284 return single_open(file, hist_show, file);
5285}
5286
5287const struct file_operations event_hist_fops = {
5288 .open = event_hist_open,
5289 .read = seq_read,
5290 .llseek = seq_lseek,
5291 .release = single_release,
5292};
5293
Tom Zanussi2d19bd72020-04-03 14:31:21 -05005294#ifdef CONFIG_HIST_TRIGGERS_DEBUG
5295static void hist_field_debug_show_flags(struct seq_file *m,
5296 unsigned long flags)
5297{
5298 seq_puts(m, " flags:\n");
5299
5300 if (flags & HIST_FIELD_FL_KEY)
5301 seq_puts(m, " HIST_FIELD_FL_KEY\n");
5302 else if (flags & HIST_FIELD_FL_HITCOUNT)
5303 seq_puts(m, " VAL: HIST_FIELD_FL_HITCOUNT\n");
5304 else if (flags & HIST_FIELD_FL_VAR)
5305 seq_puts(m, " HIST_FIELD_FL_VAR\n");
5306 else if (flags & HIST_FIELD_FL_VAR_REF)
5307 seq_puts(m, " HIST_FIELD_FL_VAR_REF\n");
5308 else
5309 seq_puts(m, " VAL: normal u64 value\n");
5310
5311 if (flags & HIST_FIELD_FL_ALIAS)
5312 seq_puts(m, " HIST_FIELD_FL_ALIAS\n");
Kalesh Singh52cfb372021-10-25 13:08:33 -07005313 else if (flags & HIST_FIELD_FL_CONST)
5314 seq_puts(m, " HIST_FIELD_FL_CONST\n");
Tom Zanussi2d19bd72020-04-03 14:31:21 -05005315}
5316
5317static int hist_field_debug_show(struct seq_file *m,
5318 struct hist_field *field, unsigned long flags)
5319{
5320 if ((field->flags & flags) != flags) {
5321 seq_printf(m, "ERROR: bad flags - %lx\n", flags);
5322 return -EINVAL;
5323 }
5324
5325 hist_field_debug_show_flags(m, field->flags);
5326 if (field->field)
5327 seq_printf(m, " ftrace_event_field name: %s\n",
5328 field->field->name);
5329
5330 if (field->flags & HIST_FIELD_FL_VAR) {
5331 seq_printf(m, " var.name: %s\n", field->var.name);
5332 seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n",
5333 field->var.idx);
5334 }
5335
Kalesh Singh52cfb372021-10-25 13:08:33 -07005336 if (field->flags & HIST_FIELD_FL_CONST)
5337 seq_printf(m, " constant: %llu\n", field->constant);
5338
Tom Zanussi2d19bd72020-04-03 14:31:21 -05005339 if (field->flags & HIST_FIELD_FL_ALIAS)
5340 seq_printf(m, " var_ref_idx (into hist_data->var_refs[]): %u\n",
5341 field->var_ref_idx);
5342
5343 if (field->flags & HIST_FIELD_FL_VAR_REF) {
5344 seq_printf(m, " name: %s\n", field->name);
5345 seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n",
5346 field->var.idx);
5347 seq_printf(m, " var.hist_data: %p\n", field->var.hist_data);
5348 seq_printf(m, " var_ref_idx (into hist_data->var_refs[]): %u\n",
5349 field->var_ref_idx);
5350 if (field->system)
5351 seq_printf(m, " system: %s\n", field->system);
5352 if (field->event_name)
5353 seq_printf(m, " event_name: %s\n", field->event_name);
5354 }
5355
5356 seq_printf(m, " type: %s\n", field->type);
5357 seq_printf(m, " size: %u\n", field->size);
5358 seq_printf(m, " is_signed: %u\n", field->is_signed);
5359
5360 return 0;
5361}
5362
5363static int field_var_debug_show(struct seq_file *m,
5364 struct field_var *field_var, unsigned int i,
5365 bool save_vars)
5366{
5367 const char *vars_name = save_vars ? "save_vars" : "field_vars";
5368 struct hist_field *field;
5369 int ret = 0;
5370
5371 seq_printf(m, "\n hist_data->%s[%d]:\n", vars_name, i);
5372
5373 field = field_var->var;
5374
5375 seq_printf(m, "\n %s[%d].var:\n", vars_name, i);
5376
5377 hist_field_debug_show_flags(m, field->flags);
5378 seq_printf(m, " var.name: %s\n", field->var.name);
5379 seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n",
5380 field->var.idx);
5381
5382 field = field_var->val;
5383
5384 seq_printf(m, "\n %s[%d].val:\n", vars_name, i);
5385 if (field->field)
5386 seq_printf(m, " ftrace_event_field name: %s\n",
5387 field->field->name);
5388 else {
5389 ret = -EINVAL;
5390 goto out;
5391 }
5392
5393 seq_printf(m, " type: %s\n", field->type);
5394 seq_printf(m, " size: %u\n", field->size);
5395 seq_printf(m, " is_signed: %u\n", field->is_signed);
5396out:
5397 return ret;
5398}
5399
5400static int hist_action_debug_show(struct seq_file *m,
5401 struct action_data *data, int i)
5402{
5403 int ret = 0;
5404
5405 if (data->handler == HANDLER_ONMAX ||
5406 data->handler == HANDLER_ONCHANGE) {
5407 seq_printf(m, "\n hist_data->actions[%d].track_data.var_ref:\n", i);
5408 ret = hist_field_debug_show(m, data->track_data.var_ref,
5409 HIST_FIELD_FL_VAR_REF);
5410 if (ret)
5411 goto out;
5412
5413 seq_printf(m, "\n hist_data->actions[%d].track_data.track_var:\n", i);
5414 ret = hist_field_debug_show(m, data->track_data.track_var,
5415 HIST_FIELD_FL_VAR);
5416 if (ret)
5417 goto out;
5418 }
5419
5420 if (data->handler == HANDLER_ONMATCH) {
5421 seq_printf(m, "\n hist_data->actions[%d].match_data.event_system: %s\n",
5422 i, data->match_data.event_system);
5423 seq_printf(m, " hist_data->actions[%d].match_data.event: %s\n",
5424 i, data->match_data.event);
5425 }
5426out:
5427 return ret;
5428}
5429
5430static int hist_actions_debug_show(struct seq_file *m,
5431 struct hist_trigger_data *hist_data)
5432{
5433 int i, ret = 0;
5434
5435 if (hist_data->n_actions)
5436 seq_puts(m, "\n action tracking variables (for onmax()/onchange()/onmatch()):\n");
5437
5438 for (i = 0; i < hist_data->n_actions; i++) {
5439 struct action_data *action = hist_data->actions[i];
5440
5441 ret = hist_action_debug_show(m, action, i);
5442 if (ret)
5443 goto out;
5444 }
5445
5446 if (hist_data->n_save_vars)
5447 seq_puts(m, "\n save action variables (save() params):\n");
5448
5449 for (i = 0; i < hist_data->n_save_vars; i++) {
5450 ret = field_var_debug_show(m, hist_data->save_vars[i], i, true);
5451 if (ret)
5452 goto out;
5453 }
5454out:
5455 return ret;
5456}
5457
5458static void hist_trigger_debug_show(struct seq_file *m,
5459 struct event_trigger_data *data, int n)
5460{
5461 struct hist_trigger_data *hist_data;
5462 int i, ret;
5463
5464 if (n > 0)
5465 seq_puts(m, "\n\n");
5466
5467 seq_puts(m, "# event histogram\n#\n# trigger info: ");
5468 data->ops->print(m, data->ops, data);
5469 seq_puts(m, "#\n\n");
5470
5471 hist_data = data->private_data;
5472
5473 seq_printf(m, "hist_data: %p\n\n", hist_data);
5474 seq_printf(m, " n_vals: %u\n", hist_data->n_vals);
5475 seq_printf(m, " n_keys: %u\n", hist_data->n_keys);
5476 seq_printf(m, " n_fields: %u\n", hist_data->n_fields);
5477
5478 seq_puts(m, "\n val fields:\n\n");
5479
5480 seq_puts(m, " hist_data->fields[0]:\n");
5481 ret = hist_field_debug_show(m, hist_data->fields[0],
5482 HIST_FIELD_FL_HITCOUNT);
5483 if (ret)
5484 return;
5485
5486 for (i = 1; i < hist_data->n_vals; i++) {
5487 seq_printf(m, "\n hist_data->fields[%d]:\n", i);
5488 ret = hist_field_debug_show(m, hist_data->fields[i], 0);
5489 if (ret)
5490 return;
5491 }
5492
5493 seq_puts(m, "\n key fields:\n");
5494
5495 for (i = hist_data->n_vals; i < hist_data->n_fields; i++) {
5496 seq_printf(m, "\n hist_data->fields[%d]:\n", i);
5497 ret = hist_field_debug_show(m, hist_data->fields[i],
5498 HIST_FIELD_FL_KEY);
5499 if (ret)
5500 return;
5501 }
5502
5503 if (hist_data->n_var_refs)
5504 seq_puts(m, "\n variable reference fields:\n");
5505
5506 for (i = 0; i < hist_data->n_var_refs; i++) {
5507 seq_printf(m, "\n hist_data->var_refs[%d]:\n", i);
5508 ret = hist_field_debug_show(m, hist_data->var_refs[i],
5509 HIST_FIELD_FL_VAR_REF);
5510 if (ret)
5511 return;
5512 }
5513
5514 if (hist_data->n_field_vars)
5515 seq_puts(m, "\n field variables:\n");
5516
5517 for (i = 0; i < hist_data->n_field_vars; i++) {
5518 ret = field_var_debug_show(m, hist_data->field_vars[i], i, false);
5519 if (ret)
5520 return;
5521 }
5522
5523 ret = hist_actions_debug_show(m, hist_data);
5524 if (ret)
5525 return;
5526}
5527
5528static int hist_debug_show(struct seq_file *m, void *v)
5529{
5530 struct event_trigger_data *data;
5531 struct trace_event_file *event_file;
5532 int n = 0, ret = 0;
5533
5534 mutex_lock(&event_mutex);
5535
5536 event_file = event_file_data(m->private);
5537 if (unlikely(!event_file)) {
5538 ret = -ENODEV;
5539 goto out_unlock;
5540 }
5541
5542 list_for_each_entry(data, &event_file->triggers, list) {
5543 if (data->cmd_ops->trigger_type == ETT_EVENT_HIST)
5544 hist_trigger_debug_show(m, data, n++);
5545 }
5546
5547 out_unlock:
5548 mutex_unlock(&event_mutex);
5549
5550 return ret;
5551}
5552
5553static int event_hist_debug_open(struct inode *inode, struct file *file)
5554{
5555 int ret;
5556
5557 ret = security_locked_down(LOCKDOWN_TRACEFS);
5558 if (ret)
5559 return ret;
5560
5561 return single_open(file, hist_debug_show, file);
5562}
5563
5564const struct file_operations event_hist_debug_fops = {
5565 .open = event_hist_debug_open,
5566 .read = seq_read,
5567 .llseek = seq_lseek,
5568 .release = single_release,
5569};
5570#endif
5571
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005572static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
5573{
Tom Zanussi85013252017-09-22 14:58:22 -05005574 const char *field_name = hist_field_name(hist_field, 0);
5575
Tom Zanussi30350d62018-01-15 20:51:49 -06005576 if (hist_field->var.name)
5577 seq_printf(m, "%s=", hist_field->var.name);
5578
Tom Zanussi0ae79612018-03-28 15:10:53 -05005579 if (hist_field->flags & HIST_FIELD_FL_CPU)
Steven Rostedt (VMware)1e3bac72021-07-21 11:00:53 -04005580 seq_puts(m, "common_cpu");
Kalesh Singh52cfb372021-10-25 13:08:33 -07005581 else if (hist_field->flags & HIST_FIELD_FL_CONST)
5582 seq_printf(m, "%llu", hist_field->constant);
Tom Zanussi067fe032018-01-15 20:51:56 -06005583 else if (field_name) {
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06005584 if (hist_field->flags & HIST_FIELD_FL_VAR_REF ||
5585 hist_field->flags & HIST_FIELD_FL_ALIAS)
Tom Zanussi067fe032018-01-15 20:51:56 -06005586 seq_putc(m, '$');
Tom Zanussiad42feb2018-01-15 20:51:45 -06005587 seq_printf(m, "%s", field_name);
Tom Zanussi0ae79612018-03-28 15:10:53 -05005588 } else if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP)
5589 seq_puts(m, "common_timestamp");
Tom Zanussi608940d2018-04-26 20:04:47 -05005590
5591 if (hist_field->flags) {
5592 if (!(hist_field->flags & HIST_FIELD_FL_VAR_REF) &&
5593 !(hist_field->flags & HIST_FIELD_FL_EXPR)) {
5594 const char *flags = get_hist_field_flags(hist_field);
5595
5596 if (flags)
5597 seq_printf(m, ".%s", flags);
5598 }
5599 }
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04005600 if (hist_field->buckets)
5601 seq_printf(m, "=%ld", hist_field->buckets);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005602}
5603
5604static int event_hist_trigger_print(struct seq_file *m,
5605 struct event_trigger_ops *ops,
5606 struct event_trigger_data *data)
5607{
5608 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussi30350d62018-01-15 20:51:49 -06005609 struct hist_field *field;
5610 bool have_var = false;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005611 unsigned int i;
5612
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005613 seq_puts(m, "hist:");
5614
5615 if (data->name)
5616 seq_printf(m, "%s:", data->name);
5617
5618 seq_puts(m, "keys=");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005619
5620 for_each_hist_key_field(i, hist_data) {
Tom Zanussi30350d62018-01-15 20:51:49 -06005621 field = hist_data->fields[i];
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005622
5623 if (i > hist_data->n_vals)
5624 seq_puts(m, ",");
5625
Tom Zanussi30350d62018-01-15 20:51:49 -06005626 if (field->flags & HIST_FIELD_FL_STACKTRACE)
Tom Zanussi69a02002016-03-03 12:54:52 -06005627 seq_puts(m, "stacktrace");
5628 else
Tom Zanussi30350d62018-01-15 20:51:49 -06005629 hist_field_print(m, field);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005630 }
5631
5632 seq_puts(m, ":vals=");
Tom Zanussif2606832016-03-03 12:54:43 -06005633
5634 for_each_hist_val_field(i, hist_data) {
Tom Zanussi30350d62018-01-15 20:51:49 -06005635 field = hist_data->fields[i];
5636 if (field->flags & HIST_FIELD_FL_VAR) {
5637 have_var = true;
5638 continue;
5639 }
5640
Tom Zanussif2606832016-03-03 12:54:43 -06005641 if (i == HITCOUNT_IDX)
5642 seq_puts(m, "hitcount");
5643 else {
5644 seq_puts(m, ",");
Tom Zanussi30350d62018-01-15 20:51:49 -06005645 hist_field_print(m, field);
5646 }
5647 }
5648
5649 if (have_var) {
5650 unsigned int n = 0;
5651
5652 seq_puts(m, ":");
5653
5654 for_each_hist_val_field(i, hist_data) {
5655 field = hist_data->fields[i];
5656
5657 if (field->flags & HIST_FIELD_FL_VAR) {
5658 if (n++)
5659 seq_puts(m, ",");
5660 hist_field_print(m, field);
5661 }
Tom Zanussif2606832016-03-03 12:54:43 -06005662 }
5663 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005664
5665 seq_puts(m, ":sort=");
Tom Zanussie62347d2016-03-03 12:54:45 -06005666
5667 for (i = 0; i < hist_data->n_sort_keys; i++) {
5668 struct tracing_map_sort_key *sort_key;
Tom Zanussi30350d62018-01-15 20:51:49 -06005669 unsigned int idx, first_key_idx;
5670
5671 /* skip VAR vals */
5672 first_key_idx = hist_data->n_vals - hist_data->n_vars;
Tom Zanussie62347d2016-03-03 12:54:45 -06005673
5674 sort_key = &hist_data->sort_keys[i];
Tom Zanussiad42feb2018-01-15 20:51:45 -06005675 idx = sort_key->field_idx;
5676
Tom Zanussi1a361df2018-01-15 20:51:50 -06005677 if (WARN_ON(idx >= HIST_FIELDS_MAX))
Tom Zanussiad42feb2018-01-15 20:51:45 -06005678 return -EINVAL;
Tom Zanussie62347d2016-03-03 12:54:45 -06005679
5680 if (i > 0)
5681 seq_puts(m, ",");
5682
Tom Zanussiad42feb2018-01-15 20:51:45 -06005683 if (idx == HITCOUNT_IDX)
Tom Zanussie62347d2016-03-03 12:54:45 -06005684 seq_puts(m, "hitcount");
Tom Zanussi30350d62018-01-15 20:51:49 -06005685 else {
5686 if (idx >= first_key_idx)
5687 idx += hist_data->n_vars;
Tom Zanussie62347d2016-03-03 12:54:45 -06005688 hist_field_print(m, hist_data->fields[idx]);
Tom Zanussi30350d62018-01-15 20:51:49 -06005689 }
Tom Zanussie62347d2016-03-03 12:54:45 -06005690
5691 if (sort_key->descending)
5692 seq_puts(m, ".descending");
5693 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005694 seq_printf(m, ":size=%u", (1 << hist_data->map->map_bits));
Tom Zanussia4072fe2018-01-15 20:52:08 -06005695 if (hist_data->enable_timestamps)
5696 seq_printf(m, ":clock=%s", hist_data->attrs->clock);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005697
Tom Zanussic282a382018-01-15 20:52:00 -06005698 print_actions_spec(m, hist_data);
5699
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005700 if (data->filter_str)
5701 seq_printf(m, " if %s", data->filter_str);
5702
Tom Zanussi83e99912016-03-03 12:54:46 -06005703 if (data->paused)
5704 seq_puts(m, " [paused]");
5705 else
5706 seq_puts(m, " [active]");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005707
5708 seq_putc(m, '\n');
5709
5710 return 0;
5711}
5712
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005713static int event_hist_trigger_init(struct event_trigger_ops *ops,
5714 struct event_trigger_data *data)
5715{
5716 struct hist_trigger_data *hist_data = data->private_data;
5717
5718 if (!data->ref && hist_data->attrs->name)
5719 save_named_trigger(hist_data->attrs->name, data);
5720
5721 data->ref++;
5722
5723 return 0;
5724}
5725
Tom Zanussi02205a62018-01-15 20:51:59 -06005726static void unregister_field_var_hists(struct hist_trigger_data *hist_data)
5727{
5728 struct trace_event_file *file;
5729 unsigned int i;
5730 char *cmd;
5731 int ret;
5732
5733 for (i = 0; i < hist_data->n_field_var_hists; i++) {
5734 file = hist_data->field_var_hists[i]->hist_data->event_file;
5735 cmd = hist_data->field_var_hists[i]->cmd;
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06005736 ret = event_hist_trigger_parse(&trigger_hist_cmd, file,
5737 "!hist", "hist", cmd);
Hyeonggon Yoo6c610db2021-05-29 15:14:23 +09005738 WARN_ON_ONCE(ret < 0);
Tom Zanussi02205a62018-01-15 20:51:59 -06005739 }
5740}
5741
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005742static void event_hist_trigger_free(struct event_trigger_ops *ops,
5743 struct event_trigger_data *data)
5744{
5745 struct hist_trigger_data *hist_data = data->private_data;
5746
5747 if (WARN_ON_ONCE(data->ref <= 0))
5748 return;
5749
5750 data->ref--;
5751 if (!data->ref) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005752 if (data->name)
5753 del_named_trigger(data);
Tom Zanussi067fe032018-01-15 20:51:56 -06005754
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005755 trigger_data_free(data);
Tom Zanussi067fe032018-01-15 20:51:56 -06005756
5757 remove_hist_vars(hist_data);
5758
Tom Zanussi02205a62018-01-15 20:51:59 -06005759 unregister_field_var_hists(hist_data);
5760
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005761 destroy_hist_data(hist_data);
5762 }
5763}
5764
5765static struct event_trigger_ops event_hist_trigger_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06005766 .trigger = event_hist_trigger,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005767 .print = event_hist_trigger_print,
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005768 .init = event_hist_trigger_init,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005769 .free = event_hist_trigger_free,
5770};
5771
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005772static int event_hist_trigger_named_init(struct event_trigger_ops *ops,
5773 struct event_trigger_data *data)
5774{
5775 data->ref++;
5776
5777 save_named_trigger(data->named_data->name, data);
5778
5779 event_hist_trigger_init(ops, data->named_data);
5780
5781 return 0;
5782}
5783
5784static void event_hist_trigger_named_free(struct event_trigger_ops *ops,
5785 struct event_trigger_data *data)
5786{
5787 if (WARN_ON_ONCE(data->ref <= 0))
5788 return;
5789
5790 event_hist_trigger_free(ops, data->named_data);
5791
5792 data->ref--;
5793 if (!data->ref) {
5794 del_named_trigger(data);
5795 trigger_data_free(data);
5796 }
5797}
5798
5799static struct event_trigger_ops event_hist_trigger_named_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06005800 .trigger = event_hist_trigger,
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005801 .print = event_hist_trigger_print,
5802 .init = event_hist_trigger_named_init,
5803 .free = event_hist_trigger_named_free,
5804};
5805
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005806static struct event_trigger_ops *event_hist_get_trigger_ops(char *cmd,
5807 char *param)
5808{
5809 return &event_hist_trigger_ops;
5810}
5811
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005812static void hist_clear(struct event_trigger_data *data)
5813{
5814 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005815
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005816 if (data->name)
5817 pause_named_trigger(data);
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005818
Steven Rostedt (VMware)e0a568d2018-08-09 15:31:48 -04005819 tracepoint_synchronize_unregister();
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005820
5821 tracing_map_clear(hist_data->map);
5822
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005823 if (data->name)
5824 unpause_named_trigger(data);
5825}
5826
5827static bool compatible_field(struct ftrace_event_field *field,
5828 struct ftrace_event_field *test_field)
5829{
5830 if (field == test_field)
5831 return true;
5832 if (field == NULL || test_field == NULL)
5833 return false;
5834 if (strcmp(field->name, test_field->name) != 0)
5835 return false;
5836 if (strcmp(field->type, test_field->type) != 0)
5837 return false;
5838 if (field->size != test_field->size)
5839 return false;
5840 if (field->is_signed != test_field->is_signed)
5841 return false;
5842
5843 return true;
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005844}
5845
Tom Zanussi52a7f162016-03-03 12:54:57 -06005846static bool hist_trigger_match(struct event_trigger_data *data,
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005847 struct event_trigger_data *data_test,
5848 struct event_trigger_data *named_data,
5849 bool ignore_filter)
Tom Zanussi52a7f162016-03-03 12:54:57 -06005850{
5851 struct tracing_map_sort_key *sort_key, *sort_key_test;
5852 struct hist_trigger_data *hist_data, *hist_data_test;
5853 struct hist_field *key_field, *key_field_test;
5854 unsigned int i;
5855
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005856 if (named_data && (named_data != data_test) &&
5857 (named_data != data_test->named_data))
5858 return false;
5859
5860 if (!named_data && is_named_trigger(data_test))
5861 return false;
5862
Tom Zanussi52a7f162016-03-03 12:54:57 -06005863 hist_data = data->private_data;
5864 hist_data_test = data_test->private_data;
5865
5866 if (hist_data->n_vals != hist_data_test->n_vals ||
5867 hist_data->n_fields != hist_data_test->n_fields ||
5868 hist_data->n_sort_keys != hist_data_test->n_sort_keys)
5869 return false;
5870
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005871 if (!ignore_filter) {
5872 if ((data->filter_str && !data_test->filter_str) ||
5873 (!data->filter_str && data_test->filter_str))
5874 return false;
5875 }
Tom Zanussi52a7f162016-03-03 12:54:57 -06005876
5877 for_each_hist_field(i, hist_data) {
5878 key_field = hist_data->fields[i];
5879 key_field_test = hist_data_test->fields[i];
5880
5881 if (key_field->flags != key_field_test->flags)
5882 return false;
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005883 if (!compatible_field(key_field->field, key_field_test->field))
Tom Zanussi52a7f162016-03-03 12:54:57 -06005884 return false;
5885 if (key_field->offset != key_field_test->offset)
5886 return false;
Tom Zanussiad42feb2018-01-15 20:51:45 -06005887 if (key_field->size != key_field_test->size)
5888 return false;
5889 if (key_field->is_signed != key_field_test->is_signed)
5890 return false;
Tom Zanussi1a361df2018-01-15 20:51:50 -06005891 if (!!key_field->var.name != !!key_field_test->var.name)
5892 return false;
5893 if (key_field->var.name &&
5894 strcmp(key_field->var.name, key_field_test->var.name) != 0)
5895 return false;
Tom Zanussi52a7f162016-03-03 12:54:57 -06005896 }
5897
5898 for (i = 0; i < hist_data->n_sort_keys; i++) {
5899 sort_key = &hist_data->sort_keys[i];
5900 sort_key_test = &hist_data_test->sort_keys[i];
5901
5902 if (sort_key->field_idx != sort_key_test->field_idx ||
5903 sort_key->descending != sort_key_test->descending)
5904 return false;
5905 }
5906
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005907 if (!ignore_filter && data->filter_str &&
Tom Zanussi52a7f162016-03-03 12:54:57 -06005908 (strcmp(data->filter_str, data_test->filter_str) != 0))
5909 return false;
5910
Tom Zanussi48f79472018-03-28 15:10:55 -05005911 if (!actions_match(hist_data, hist_data_test))
5912 return false;
5913
Tom Zanussi52a7f162016-03-03 12:54:57 -06005914 return true;
5915}
5916
Tom Zanussi2378a2d2022-01-10 08:04:13 -06005917static int hist_register_trigger(char *glob,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005918 struct event_trigger_data *data,
5919 struct trace_event_file *file)
5920{
Tom Zanussi83e99912016-03-03 12:54:46 -06005921 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005922 struct event_trigger_data *test, *named_data = NULL;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04005923 struct trace_array *tr = file->tr;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005924 int ret = 0;
5925
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005926 if (hist_data->attrs->name) {
5927 named_data = find_named_trigger(hist_data->attrs->name);
5928 if (named_data) {
5929 if (!hist_trigger_match(data, named_data, named_data,
5930 true)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04005931 hist_err(tr, HIST_ERR_NAMED_MISMATCH, errpos(hist_data->attrs->name));
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005932 ret = -EINVAL;
5933 goto out;
5934 }
5935 }
5936 }
5937
5938 if (hist_data->attrs->name && !named_data)
5939 goto new;
5940
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09005941 lockdep_assert_held(&event_mutex);
5942
5943 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005944 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005945 if (!hist_trigger_match(data, test, named_data, false))
Tom Zanussi52a7f162016-03-03 12:54:57 -06005946 continue;
Tom Zanussi83e99912016-03-03 12:54:46 -06005947 if (hist_data->attrs->pause)
5948 test->paused = true;
5949 else if (hist_data->attrs->cont)
5950 test->paused = false;
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005951 else if (hist_data->attrs->clear)
5952 hist_clear(test);
Tom Zanussif404da62018-01-15 20:52:05 -06005953 else {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04005954 hist_err(tr, HIST_ERR_TRIGGER_EEXIST, 0);
Tom Zanussi83e99912016-03-03 12:54:46 -06005955 ret = -EEXIST;
Tom Zanussif404da62018-01-15 20:52:05 -06005956 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005957 goto out;
5958 }
5959 }
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005960 new:
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005961 if (hist_data->attrs->cont || hist_data->attrs->clear) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04005962 hist_err(tr, HIST_ERR_TRIGGER_ENOENT_CLEAR, 0);
Tom Zanussi83e99912016-03-03 12:54:46 -06005963 ret = -ENOENT;
5964 goto out;
5965 }
5966
Tom Zanussi7522c032016-06-29 19:56:00 -05005967 if (hist_data->attrs->pause)
5968 data->paused = true;
5969
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005970 if (named_data) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005971 data->private_data = named_data->private_data;
5972 set_named_trigger_data(data, named_data);
5973 data->ops = &event_hist_trigger_named_ops;
5974 }
5975
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005976 if (data->ops->init) {
5977 ret = data->ops->init(data->ops, data);
5978 if (ret < 0)
5979 goto out;
5980 }
5981
Tom Zanussia4072fe2018-01-15 20:52:08 -06005982 if (hist_data->enable_timestamps) {
5983 char *clock = hist_data->attrs->clock;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005984
Tom Zanussia4072fe2018-01-15 20:52:08 -06005985 ret = tracing_set_clock(file->tr, hist_data->attrs->clock);
5986 if (ret) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04005987 hist_err(tr, HIST_ERR_SET_CLOCK_FAIL, errpos(clock));
Tom Zanussia4072fe2018-01-15 20:52:08 -06005988 goto out;
5989 }
5990
Steven Rostedt (VMware)b94bc802021-03-16 12:41:05 -04005991 tracing_set_filter_buffering(file->tr, true);
Tom Zanussia4072fe2018-01-15 20:52:08 -06005992 }
5993
5994 if (named_data)
5995 destroy_hist_data(hist_data);
5996
5997 ret++;
Tom Zanussi067fe032018-01-15 20:51:56 -06005998 out:
5999 return ret;
6000}
6001
6002static int hist_trigger_enable(struct event_trigger_data *data,
6003 struct trace_event_file *file)
6004{
6005 int ret = 0;
6006
6007 list_add_tail_rcu(&data->list, &file->triggers);
6008
6009 update_cond_flag(file);
Tom Zanussiad42feb2018-01-15 20:51:45 -06006010
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006011 if (trace_event_trigger_enable_disable(file, 1) < 0) {
6012 list_del_rcu(&data->list);
6013 update_cond_flag(file);
6014 ret--;
6015 }
Tom Zanussi067fe032018-01-15 20:51:56 -06006016
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006017 return ret;
6018}
6019
Tom Zanussi4b147932018-01-15 20:51:58 -06006020static bool have_hist_trigger_match(struct event_trigger_data *data,
6021 struct trace_event_file *file)
6022{
6023 struct hist_trigger_data *hist_data = data->private_data;
6024 struct event_trigger_data *test, *named_data = NULL;
6025 bool match = false;
6026
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006027 lockdep_assert_held(&event_mutex);
6028
Tom Zanussi4b147932018-01-15 20:51:58 -06006029 if (hist_data->attrs->name)
6030 named_data = find_named_trigger(hist_data->attrs->name);
6031
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006032 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi4b147932018-01-15 20:51:58 -06006033 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
6034 if (hist_trigger_match(data, test, named_data, false)) {
6035 match = true;
6036 break;
6037 }
6038 }
6039 }
6040
6041 return match;
6042}
6043
Tom Zanussi067fe032018-01-15 20:51:56 -06006044static bool hist_trigger_check_refs(struct event_trigger_data *data,
6045 struct trace_event_file *file)
6046{
6047 struct hist_trigger_data *hist_data = data->private_data;
6048 struct event_trigger_data *test, *named_data = NULL;
6049
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006050 lockdep_assert_held(&event_mutex);
6051
Tom Zanussi067fe032018-01-15 20:51:56 -06006052 if (hist_data->attrs->name)
6053 named_data = find_named_trigger(hist_data->attrs->name);
6054
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006055 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi067fe032018-01-15 20:51:56 -06006056 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
6057 if (!hist_trigger_match(data, test, named_data, false))
6058 continue;
6059 hist_data = test->private_data;
6060 if (check_var_refs(hist_data))
6061 return true;
6062 break;
6063 }
6064 }
6065
6066 return false;
6067}
6068
Tom Zanussi2378a2d2022-01-10 08:04:13 -06006069static void hist_unregister_trigger(char *glob,
Tom Zanussi52a7f162016-03-03 12:54:57 -06006070 struct event_trigger_data *data,
6071 struct trace_event_file *file)
6072{
Tom Zanussi5463bfd2016-03-03 12:54:59 -06006073 struct hist_trigger_data *hist_data = data->private_data;
6074 struct event_trigger_data *test, *named_data = NULL;
Tom Zanussi52a7f162016-03-03 12:54:57 -06006075 bool unregistered = false;
6076
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006077 lockdep_assert_held(&event_mutex);
6078
Tom Zanussi5463bfd2016-03-03 12:54:59 -06006079 if (hist_data->attrs->name)
6080 named_data = find_named_trigger(hist_data->attrs->name);
6081
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006082 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi52a7f162016-03-03 12:54:57 -06006083 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06006084 if (!hist_trigger_match(data, test, named_data, false))
Tom Zanussi52a7f162016-03-03 12:54:57 -06006085 continue;
6086 unregistered = true;
6087 list_del_rcu(&test->list);
6088 trace_event_trigger_enable_disable(file, 0);
6089 update_cond_flag(file);
6090 break;
6091 }
6092 }
6093
6094 if (unregistered && test->ops->free)
6095 test->ops->free(test->ops, test);
Tom Zanussiad42feb2018-01-15 20:51:45 -06006096
6097 if (hist_data->enable_timestamps) {
Tom Zanussi30350d62018-01-15 20:51:49 -06006098 if (!hist_data->remove || unregistered)
Steven Rostedt (VMware)b94bc802021-03-16 12:41:05 -04006099 tracing_set_filter_buffering(file->tr, false);
Tom Zanussiad42feb2018-01-15 20:51:45 -06006100 }
Tom Zanussi52a7f162016-03-03 12:54:57 -06006101}
6102
Tom Zanussi067fe032018-01-15 20:51:56 -06006103static bool hist_file_check_refs(struct trace_event_file *file)
6104{
6105 struct hist_trigger_data *hist_data;
6106 struct event_trigger_data *test;
6107
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006108 lockdep_assert_held(&event_mutex);
6109
6110 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi067fe032018-01-15 20:51:56 -06006111 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
6112 hist_data = test->private_data;
6113 if (check_var_refs(hist_data))
6114 return true;
6115 }
6116 }
6117
6118 return false;
6119}
6120
Tom Zanussi52a7f162016-03-03 12:54:57 -06006121static void hist_unreg_all(struct trace_event_file *file)
6122{
Steven Rostedt47c18562016-06-29 19:55:59 -05006123 struct event_trigger_data *test, *n;
Tom Zanussiad42feb2018-01-15 20:51:45 -06006124 struct hist_trigger_data *hist_data;
Tom Zanussi4b147932018-01-15 20:51:58 -06006125 struct synth_event *se;
6126 const char *se_name;
Tom Zanussi52a7f162016-03-03 12:54:57 -06006127
Masami Hiramatsu0e2b81f72018-11-05 18:04:01 +09006128 lockdep_assert_held(&event_mutex);
6129
Tom Zanussi067fe032018-01-15 20:51:56 -06006130 if (hist_file_check_refs(file))
6131 return;
6132
Steven Rostedt47c18562016-06-29 19:55:59 -05006133 list_for_each_entry_safe(test, n, &file->triggers, list) {
Tom Zanussi52a7f162016-03-03 12:54:57 -06006134 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
Tom Zanussiad42feb2018-01-15 20:51:45 -06006135 hist_data = test->private_data;
Tom Zanussi52a7f162016-03-03 12:54:57 -06006136 list_del_rcu(&test->list);
6137 trace_event_trigger_enable_disable(file, 0);
Tom Zanussi4b147932018-01-15 20:51:58 -06006138
Tom Zanussi4b147932018-01-15 20:51:58 -06006139 se_name = trace_event_name(file->event_call);
6140 se = find_synth_event(se_name);
6141 if (se)
6142 se->ref--;
Tom Zanussi4b147932018-01-15 20:51:58 -06006143
Tom Zanussi52a7f162016-03-03 12:54:57 -06006144 update_cond_flag(file);
Tom Zanussiad42feb2018-01-15 20:51:45 -06006145 if (hist_data->enable_timestamps)
Steven Rostedt (VMware)b94bc802021-03-16 12:41:05 -04006146 tracing_set_filter_buffering(file->tr, false);
Tom Zanussi52a7f162016-03-03 12:54:57 -06006147 if (test->ops->free)
6148 test->ops->free(test->ops, test);
6149 }
6150 }
6151}
6152
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06006153static int event_hist_trigger_parse(struct event_command *cmd_ops,
6154 struct trace_event_file *file,
6155 char *glob, char *cmd, char *param)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006156{
6157 unsigned int hist_trigger_bits = TRACING_MAP_BITS_DEFAULT;
6158 struct event_trigger_data *trigger_data;
6159 struct hist_trigger_attrs *attrs;
6160 struct event_trigger_ops *trigger_ops;
6161 struct hist_trigger_data *hist_data;
Tom Zanussi4b147932018-01-15 20:51:58 -06006162 struct synth_event *se;
6163 const char *se_name;
Tom Zanussi30350d62018-01-15 20:51:49 -06006164 bool remove = false;
Kalesh Singhc5eac6e2021-10-25 13:08:36 -07006165 char *trigger, *p, *start;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006166 int ret = 0;
6167
Masami Hiramatsu0e2b81f72018-11-05 18:04:01 +09006168 lockdep_assert_held(&event_mutex);
6169
Tom Zanussi798a5b62022-01-27 15:44:15 -06006170 WARN_ON(!glob);
6171
6172 if (strlen(glob)) {
Tom Zanussif404da62018-01-15 20:52:05 -06006173 hist_err_clear();
Tom Zanussia1a05bb2019-03-31 18:48:16 -05006174 last_cmd_set(file, param);
Tom Zanussif404da62018-01-15 20:52:05 -06006175 }
6176
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006177 if (!param)
6178 return -EINVAL;
6179
Tom Zanussi30350d62018-01-15 20:51:49 -06006180 if (glob[0] == '!')
6181 remove = true;
6182
Tom Zanussiec5ce092018-01-15 20:52:02 -06006183 /*
6184 * separate the trigger from the filter (k:v [if filter])
6185 * allowing for whitespace in the trigger
6186 */
6187 p = trigger = param;
6188 do {
6189 p = strstr(p, "if");
6190 if (!p)
6191 break;
6192 if (p == param)
6193 return -EINVAL;
6194 if (*(p - 1) != ' ' && *(p - 1) != '\t') {
6195 p++;
6196 continue;
6197 }
Tom Zanussi2f31ed92018-12-18 14:33:21 -06006198 if (p >= param + strlen(param) - (sizeof("if") - 1) - 1)
Tom Zanussiec5ce092018-01-15 20:52:02 -06006199 return -EINVAL;
Tom Zanussi2f31ed92018-12-18 14:33:21 -06006200 if (*(p + sizeof("if") - 1) != ' ' && *(p + sizeof("if") - 1) != '\t') {
Tom Zanussiec5ce092018-01-15 20:52:02 -06006201 p++;
6202 continue;
6203 }
6204 break;
Tom Zanussib59f2f22022-01-27 15:44:16 -06006205 } while (1);
Tom Zanussiec5ce092018-01-15 20:52:02 -06006206
6207 if (!p)
6208 param = NULL;
6209 else {
6210 *(p - 1) = '\0';
6211 param = strstrip(p);
6212 trigger = strstrip(trigger);
6213 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006214
Kalesh Singhc5eac6e2021-10-25 13:08:36 -07006215 /*
6216 * To simplify arithmetic expression parsing, replace occurrences of
6217 * '.sym-offset' modifier with '.symXoffset'
6218 */
6219 start = strstr(trigger, ".sym-offset");
6220 while (start) {
6221 *(start + 4) = 'X';
6222 start = strstr(start + 11, ".sym-offset");
kernel test robotfeea69e2021-10-30 08:56:15 +08006223 }
Kalesh Singhc5eac6e2021-10-25 13:08:36 -07006224
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04006225 attrs = parse_hist_trigger_attrs(file->tr, trigger);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006226 if (IS_ERR(attrs))
6227 return PTR_ERR(attrs);
6228
6229 if (attrs->map_bits)
6230 hist_trigger_bits = attrs->map_bits;
6231
Tom Zanussi30350d62018-01-15 20:51:49 -06006232 hist_data = create_hist_data(hist_trigger_bits, attrs, file, remove);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006233 if (IS_ERR(hist_data)) {
6234 destroy_hist_trigger_attrs(attrs);
6235 return PTR_ERR(hist_data);
6236 }
6237
6238 trigger_ops = cmd_ops->get_trigger_ops(cmd, trigger);
6239
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006240 trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL);
Tom Zanussi4b147932018-01-15 20:51:58 -06006241 if (!trigger_data) {
6242 ret = -ENOMEM;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006243 goto out_free;
Tom Zanussi4b147932018-01-15 20:51:58 -06006244 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006245
6246 trigger_data->count = -1;
6247 trigger_data->ops = trigger_ops;
6248 trigger_data->cmd_ops = cmd_ops;
6249
6250 INIT_LIST_HEAD(&trigger_data->list);
6251 RCU_INIT_POINTER(trigger_data->filter, NULL);
6252
6253 trigger_data->private_data = hist_data;
6254
Tom Zanussi52a7f162016-03-03 12:54:57 -06006255 /* if param is non-empty, it's supposed to be a filter */
6256 if (param && cmd_ops->set_filter) {
6257 ret = cmd_ops->set_filter(param, trigger_data, file);
6258 if (ret < 0)
6259 goto out_free;
6260 }
6261
Tom Zanussi30350d62018-01-15 20:51:49 -06006262 if (remove) {
Tom Zanussi4b147932018-01-15 20:51:58 -06006263 if (!have_hist_trigger_match(trigger_data, file))
6264 goto out_free;
6265
Tom Zanussi067fe032018-01-15 20:51:56 -06006266 if (hist_trigger_check_refs(trigger_data, file)) {
6267 ret = -EBUSY;
6268 goto out_free;
6269 }
6270
Tom Zanussi2378a2d2022-01-10 08:04:13 -06006271 cmd_ops->unreg(glob+1, trigger_data, file);
Tom Zanussi4b147932018-01-15 20:51:58 -06006272 se_name = trace_event_name(file->event_call);
6273 se = find_synth_event(se_name);
6274 if (se)
6275 se->ref--;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006276 ret = 0;
6277 goto out_free;
6278 }
6279
Tom Zanussi2378a2d2022-01-10 08:04:13 -06006280 ret = cmd_ops->reg(glob, trigger_data, file);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006281 /*
6282 * The above returns on success the # of triggers registered,
6283 * but if it didn't register any it returns zero. Consider no
6284 * triggers registered a failure too.
6285 */
6286 if (!ret) {
Tom Zanussie86ae9b2016-03-03 12:54:47 -06006287 if (!(attrs->pause || attrs->cont || attrs->clear))
Tom Zanussi83e99912016-03-03 12:54:46 -06006288 ret = -ENOENT;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006289 goto out_free;
6290 } else if (ret < 0)
6291 goto out_free;
Tom Zanussi067fe032018-01-15 20:51:56 -06006292
6293 if (get_named_trigger_data(trigger_data))
6294 goto enable;
6295
6296 if (has_hist_vars(hist_data))
6297 save_hist_vars(hist_data);
6298
Tom Zanussi7d18a102019-02-13 17:42:41 -06006299 ret = create_actions(hist_data);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06006300 if (ret)
6301 goto out_unreg;
6302
Tom Zanussi067fe032018-01-15 20:51:56 -06006303 ret = tracing_map_init(hist_data->map);
6304 if (ret)
6305 goto out_unreg;
6306enable:
6307 ret = hist_trigger_enable(trigger_data, file);
6308 if (ret)
6309 goto out_unreg;
6310
Tom Zanussi4b147932018-01-15 20:51:58 -06006311 se_name = trace_event_name(file->event_call);
6312 se = find_synth_event(se_name);
6313 if (se)
6314 se->ref++;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006315 /* Just return zero, not the number of registered triggers */
6316 ret = 0;
6317 out:
Tom Zanussif404da62018-01-15 20:52:05 -06006318 if (ret == 0)
6319 hist_err_clear();
6320
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006321 return ret;
Tom Zanussi067fe032018-01-15 20:51:56 -06006322 out_unreg:
Tom Zanussi2378a2d2022-01-10 08:04:13 -06006323 cmd_ops->unreg(glob+1, trigger_data, file);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006324 out_free:
6325 if (cmd_ops->set_filter)
6326 cmd_ops->set_filter(NULL, trigger_data, NULL);
6327
Tom Zanussi067fe032018-01-15 20:51:56 -06006328 remove_hist_vars(hist_data);
6329
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006330 kfree(trigger_data);
6331
6332 destroy_hist_data(hist_data);
6333 goto out;
6334}
6335
6336static struct event_command trigger_hist_cmd = {
6337 .name = "hist",
6338 .trigger_type = ETT_EVENT_HIST,
6339 .flags = EVENT_CMD_FL_NEEDS_REC,
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06006340 .parse = event_hist_trigger_parse,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006341 .reg = hist_register_trigger,
Tom Zanussi52a7f162016-03-03 12:54:57 -06006342 .unreg = hist_unregister_trigger,
6343 .unreg_all = hist_unreg_all,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006344 .get_trigger_ops = event_hist_get_trigger_ops,
6345 .set_filter = set_trigger_filter,
6346};
6347
6348__init int register_trigger_hist_cmd(void)
6349{
6350 int ret;
6351
6352 ret = register_event_command(&trigger_hist_cmd);
6353 WARN_ON(ret < 0);
6354
6355 return ret;
6356}
Tom Zanussid0bad492016-03-03 12:54:55 -06006357
6358static void
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04006359hist_enable_trigger(struct event_trigger_data *data,
6360 struct trace_buffer *buffer, void *rec,
Tom Zanussi1ac4f512018-01-15 20:51:42 -06006361 struct ring_buffer_event *event)
Tom Zanussid0bad492016-03-03 12:54:55 -06006362{
6363 struct enable_trigger_data *enable_data = data->private_data;
6364 struct event_trigger_data *test;
6365
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006366 list_for_each_entry_rcu(test, &enable_data->file->triggers, list,
6367 lockdep_is_held(&event_mutex)) {
Tom Zanussid0bad492016-03-03 12:54:55 -06006368 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
6369 if (enable_data->enable)
6370 test->paused = false;
6371 else
6372 test->paused = true;
Tom Zanussid0bad492016-03-03 12:54:55 -06006373 }
6374 }
6375}
6376
6377static void
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04006378hist_enable_count_trigger(struct event_trigger_data *data,
6379 struct trace_buffer *buffer, void *rec,
Tom Zanussi1ac4f512018-01-15 20:51:42 -06006380 struct ring_buffer_event *event)
Tom Zanussid0bad492016-03-03 12:54:55 -06006381{
6382 if (!data->count)
6383 return;
6384
6385 if (data->count != -1)
6386 (data->count)--;
6387
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04006388 hist_enable_trigger(data, buffer, rec, event);
Tom Zanussid0bad492016-03-03 12:54:55 -06006389}
6390
6391static struct event_trigger_ops hist_enable_trigger_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06006392 .trigger = hist_enable_trigger,
Tom Zanussid0bad492016-03-03 12:54:55 -06006393 .print = event_enable_trigger_print,
6394 .init = event_trigger_init,
6395 .free = event_enable_trigger_free,
6396};
6397
6398static struct event_trigger_ops hist_enable_count_trigger_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06006399 .trigger = hist_enable_count_trigger,
Tom Zanussid0bad492016-03-03 12:54:55 -06006400 .print = event_enable_trigger_print,
6401 .init = event_trigger_init,
6402 .free = event_enable_trigger_free,
6403};
6404
6405static struct event_trigger_ops hist_disable_trigger_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06006406 .trigger = hist_enable_trigger,
Tom Zanussid0bad492016-03-03 12:54:55 -06006407 .print = event_enable_trigger_print,
6408 .init = event_trigger_init,
6409 .free = event_enable_trigger_free,
6410};
6411
6412static struct event_trigger_ops hist_disable_count_trigger_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06006413 .trigger = hist_enable_count_trigger,
Tom Zanussid0bad492016-03-03 12:54:55 -06006414 .print = event_enable_trigger_print,
6415 .init = event_trigger_init,
6416 .free = event_enable_trigger_free,
6417};
6418
6419static struct event_trigger_ops *
6420hist_enable_get_trigger_ops(char *cmd, char *param)
6421{
6422 struct event_trigger_ops *ops;
6423 bool enable;
6424
6425 enable = (strcmp(cmd, ENABLE_HIST_STR) == 0);
6426
6427 if (enable)
6428 ops = param ? &hist_enable_count_trigger_ops :
6429 &hist_enable_trigger_ops;
6430 else
6431 ops = param ? &hist_disable_count_trigger_ops :
6432 &hist_disable_trigger_ops;
6433
6434 return ops;
6435}
6436
Tom Zanussi52a7f162016-03-03 12:54:57 -06006437static void hist_enable_unreg_all(struct trace_event_file *file)
6438{
Steven Rostedt47c18562016-06-29 19:55:59 -05006439 struct event_trigger_data *test, *n;
Tom Zanussi52a7f162016-03-03 12:54:57 -06006440
Steven Rostedt47c18562016-06-29 19:55:59 -05006441 list_for_each_entry_safe(test, n, &file->triggers, list) {
Tom Zanussi52a7f162016-03-03 12:54:57 -06006442 if (test->cmd_ops->trigger_type == ETT_HIST_ENABLE) {
6443 list_del_rcu(&test->list);
6444 update_cond_flag(file);
6445 trace_event_trigger_enable_disable(file, 0);
6446 if (test->ops->free)
6447 test->ops->free(test->ops, test);
6448 }
6449 }
6450}
6451
Tom Zanussid0bad492016-03-03 12:54:55 -06006452static struct event_command trigger_hist_enable_cmd = {
6453 .name = ENABLE_HIST_STR,
6454 .trigger_type = ETT_HIST_ENABLE,
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06006455 .parse = event_enable_trigger_parse,
Tom Zanussid0bad492016-03-03 12:54:55 -06006456 .reg = event_enable_register_trigger,
6457 .unreg = event_enable_unregister_trigger,
Tom Zanussi52a7f162016-03-03 12:54:57 -06006458 .unreg_all = hist_enable_unreg_all,
Tom Zanussid0bad492016-03-03 12:54:55 -06006459 .get_trigger_ops = hist_enable_get_trigger_ops,
6460 .set_filter = set_trigger_filter,
6461};
6462
6463static struct event_command trigger_hist_disable_cmd = {
6464 .name = DISABLE_HIST_STR,
6465 .trigger_type = ETT_HIST_ENABLE,
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06006466 .parse = event_enable_trigger_parse,
Tom Zanussid0bad492016-03-03 12:54:55 -06006467 .reg = event_enable_register_trigger,
6468 .unreg = event_enable_unregister_trigger,
Tom Zanussi52a7f162016-03-03 12:54:57 -06006469 .unreg_all = hist_enable_unreg_all,
Tom Zanussid0bad492016-03-03 12:54:55 -06006470 .get_trigger_ops = hist_enable_get_trigger_ops,
6471 .set_filter = set_trigger_filter,
6472};
6473
6474static __init void unregister_trigger_hist_enable_disable_cmds(void)
6475{
6476 unregister_event_command(&trigger_hist_enable_cmd);
6477 unregister_event_command(&trigger_hist_disable_cmd);
6478}
6479
6480__init int register_trigger_hist_enable_disable_cmds(void)
6481{
6482 int ret;
6483
6484 ret = register_event_command(&trigger_hist_enable_cmd);
6485 if (WARN_ON(ret < 0))
6486 return ret;
6487 ret = register_event_command(&trigger_hist_disable_cmd);
6488 if (WARN_ON(ret < 0))
6489 unregister_trigger_hist_enable_disable_cmds();
6490
6491 return ret;
6492}