blob: 5e6a988a8a517e44ad86cfefd14d8bf436e49a26 [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;
2506 expr->operator = FIELD_OP_UNARY_MINUS;
2507 expr->name = expr_str(expr, 0);
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04002508 expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
Tom Zanussi19a9fac2018-01-15 20:51:55 -06002509 if (!expr->type) {
2510 ret = -ENOMEM;
2511 goto free;
2512 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002513
2514 return expr;
2515 free:
2516 destroy_hist_field(expr, 0);
2517 return ERR_PTR(ret);
2518}
2519
Kalesh Singhf47716b2021-10-25 13:08:37 -07002520/*
2521 * If the operands are var refs, return pointers the
2522 * variable(s) referenced in var1 and var2, else NULL.
2523 */
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002524static int check_expr_operands(struct trace_array *tr,
2525 struct hist_field *operand1,
Kalesh Singhf47716b2021-10-25 13:08:37 -07002526 struct hist_field *operand2,
2527 struct hist_field **var1,
2528 struct hist_field **var2)
Tom Zanussi100719d2018-01-15 20:51:52 -06002529{
2530 unsigned long operand1_flags = operand1->flags;
2531 unsigned long operand2_flags = operand2->flags;
2532
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06002533 if ((operand1_flags & HIST_FIELD_FL_VAR_REF) ||
2534 (operand1_flags & HIST_FIELD_FL_ALIAS)) {
2535 struct hist_field *var;
2536
2537 var = find_var_field(operand1->var.hist_data, operand1->name);
2538 if (!var)
2539 return -EINVAL;
2540 operand1_flags = var->flags;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002541 *var1 = var;
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06002542 }
2543
2544 if ((operand2_flags & HIST_FIELD_FL_VAR_REF) ||
2545 (operand2_flags & HIST_FIELD_FL_ALIAS)) {
2546 struct hist_field *var;
2547
2548 var = find_var_field(operand2->var.hist_data, operand2->name);
2549 if (!var)
2550 return -EINVAL;
2551 operand2_flags = var->flags;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002552 *var2 = var;
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06002553 }
2554
Tom Zanussi100719d2018-01-15 20:51:52 -06002555 if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS) !=
Tom Zanussif404da62018-01-15 20:52:05 -06002556 (operand2_flags & HIST_FIELD_FL_TIMESTAMP_USECS)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002557 hist_err(tr, HIST_ERR_TIMESTAMP_MISMATCH, 0);
Tom Zanussi100719d2018-01-15 20:51:52 -06002558 return -EINVAL;
Tom Zanussif404da62018-01-15 20:52:05 -06002559 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002560
2561 return 0;
2562}
2563
2564static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
2565 struct trace_event_file *file,
2566 char *str, unsigned long flags,
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002567 char *var_name, unsigned int *n_subexprs)
Tom Zanussi100719d2018-01-15 20:51:52 -06002568{
2569 struct hist_field *operand1 = NULL, *operand2 = NULL, *expr = NULL;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002570 struct hist_field *var1 = NULL, *var2 = NULL;
2571 unsigned long operand_flags, operand2_flags;
Tom Zanussi100719d2018-01-15 20:51:52 -06002572 int field_op, ret = -EINVAL;
2573 char *sep, *operand1_str;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002574 hist_field_fn_t op_fn;
2575 bool combine_consts;
Tom Zanussi100719d2018-01-15 20:51:52 -06002576
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002577 if (*n_subexprs > 3) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002578 hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str));
Tom Zanussi100719d2018-01-15 20:51:52 -06002579 return ERR_PTR(-EINVAL);
Tom Zanussif404da62018-01-15 20:52:05 -06002580 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002581
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002582 field_op = contains_operator(str, &sep);
Tom Zanussi100719d2018-01-15 20:51:52 -06002583
2584 if (field_op == FIELD_OP_NONE)
2585 return parse_atom(hist_data, file, str, &flags, var_name);
2586
2587 if (field_op == FIELD_OP_UNARY_MINUS)
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002588 return parse_unary(hist_data, file, str, flags, var_name, n_subexprs);
Tom Zanussi100719d2018-01-15 20:51:52 -06002589
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002590 /* Binary operator found, increment n_subexprs */
2591 ++*n_subexprs;
2592
2593 /* Split the expression string at the root operator */
2594 if (!sep)
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002595 return ERR_PTR(-EINVAL);
2596
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002597 *sep = '\0';
2598 operand1_str = str;
2599 str = sep+1;
Tom Zanussi100719d2018-01-15 20:51:52 -06002600
Kalesh Singh1cab6bc2021-11-12 11:13:24 -08002601 /* Binary operator requires both operands */
2602 if (*operand1_str == '\0' || *str == '\0')
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002603 return ERR_PTR(-EINVAL);
Tom Zanussi100719d2018-01-15 20:51:52 -06002604
2605 operand_flags = 0;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002606
2607 /* LHS of string is an expression e.g. a+b in a+b+c */
2608 operand1 = parse_expr(hist_data, file, operand1_str, operand_flags, NULL, n_subexprs);
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002609 if (IS_ERR(operand1))
2610 return ERR_CAST(operand1);
2611
Masami Hiramatsua9d10ca2021-07-28 07:55:43 +09002612 if (operand1->flags & HIST_FIELD_FL_STRING) {
2613 hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(operand1_str));
2614 ret = -EINVAL;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002615 goto free_op1;
Masami Hiramatsua9d10ca2021-07-28 07:55:43 +09002616 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002617
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002618 /* RHS of string is another expression e.g. c in a+b+c */
Tom Zanussi100719d2018-01-15 20:51:52 -06002619 operand_flags = 0;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07002620 operand2 = parse_expr(hist_data, file, str, operand_flags, NULL, n_subexprs);
Tom Zanussi100719d2018-01-15 20:51:52 -06002621 if (IS_ERR(operand2)) {
2622 ret = PTR_ERR(operand2);
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002623 goto free_op1;
Tom Zanussi100719d2018-01-15 20:51:52 -06002624 }
Masami Hiramatsua9d10ca2021-07-28 07:55:43 +09002625 if (operand2->flags & HIST_FIELD_FL_STRING) {
2626 hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(str));
2627 ret = -EINVAL;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002628 goto free_operands;
Masami Hiramatsua9d10ca2021-07-28 07:55:43 +09002629 }
Tom Zanussi100719d2018-01-15 20:51:52 -06002630
Kalesh Singhf47716b2021-10-25 13:08:37 -07002631 switch (field_op) {
2632 case FIELD_OP_MINUS:
2633 op_fn = hist_field_minus;
2634 break;
2635 case FIELD_OP_PLUS:
2636 op_fn = hist_field_plus;
2637 break;
2638 case FIELD_OP_DIV:
2639 op_fn = hist_field_div;
2640 break;
2641 case FIELD_OP_MULT:
2642 op_fn = hist_field_mult;
2643 break;
2644 default:
2645 ret = -EINVAL;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002646 goto free_operands;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002647 }
2648
2649 ret = check_expr_operands(file->tr, operand1, operand2, &var1, &var2);
Tom Zanussi100719d2018-01-15 20:51:52 -06002650 if (ret)
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002651 goto free_operands;
Tom Zanussi100719d2018-01-15 20:51:52 -06002652
Kalesh Singhf47716b2021-10-25 13:08:37 -07002653 operand_flags = var1 ? var1->flags : operand1->flags;
2654 operand2_flags = var2 ? var2->flags : operand2->flags;
2655
2656 /*
2657 * If both operands are constant, the expression can be
2658 * collapsed to a single constant.
2659 */
2660 combine_consts = operand_flags & operand2_flags & HIST_FIELD_FL_CONST;
2661
2662 flags |= combine_consts ? HIST_FIELD_FL_CONST : HIST_FIELD_FL_EXPR;
Tom Zanussi100719d2018-01-15 20:51:52 -06002663
2664 flags |= operand1->flags &
2665 (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
2666
2667 expr = create_hist_field(hist_data, NULL, flags, var_name);
2668 if (!expr) {
2669 ret = -ENOMEM;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002670 goto free_operands;
Tom Zanussi100719d2018-01-15 20:51:52 -06002671 }
2672
Tom Zanussi067fe032018-01-15 20:51:56 -06002673 operand1->read_once = true;
2674 operand2->read_once = true;
2675
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002676 /* The operands are now owned and free'd by 'expr' */
Tom Zanussi100719d2018-01-15 20:51:52 -06002677 expr->operands[0] = operand1;
2678 expr->operands[1] = operand2;
Steven Rostedt (VMware)2c05caa2021-07-30 17:19:51 -04002679
Kalesh Singh8b5d46f2021-10-29 16:24:10 -07002680 if (field_op == FIELD_OP_DIV &&
2681 operand2_flags & HIST_FIELD_FL_CONST) {
2682 u64 divisor = var2 ? var2->constant : operand2->constant;
2683
2684 if (!divisor) {
2685 hist_err(file->tr, HIST_ERR_DIVISION_BY_ZERO, errpos(str));
2686 ret = -EDOM;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002687 goto free_expr;
Kalesh Singh8b5d46f2021-10-29 16:24:10 -07002688 }
2689
2690 /*
2691 * Copy the divisor here so we don't have to look it up
2692 * later if this is a var ref
2693 */
2694 operand2->constant = divisor;
2695 op_fn = hist_field_get_div_fn(operand2);
2696 }
2697
Kalesh Singhf47716b2021-10-25 13:08:37 -07002698 if (combine_consts) {
2699 if (var1)
2700 expr->operands[0] = var1;
2701 if (var2)
2702 expr->operands[1] = var2;
Steven Rostedt (VMware)2c05caa2021-07-30 17:19:51 -04002703
Kalesh Singhf47716b2021-10-25 13:08:37 -07002704 expr->constant = op_fn(expr, NULL, NULL, NULL, NULL);
Tom Zanussi100719d2018-01-15 20:51:52 -06002705
Kalesh Singhf47716b2021-10-25 13:08:37 -07002706 expr->operands[0] = NULL;
2707 expr->operands[1] = NULL;
2708
2709 /*
2710 * var refs won't be destroyed immediately
2711 * See: destroy_hist_field()
2712 */
2713 destroy_hist_field(operand2, 0);
2714 destroy_hist_field(operand1, 0);
2715
2716 expr->name = expr_str(expr, 0);
2717 } else {
2718 expr->fn = op_fn;
2719
2720 /* The operand sizes should be the same, so just pick one */
2721 expr->size = operand1->size;
2722
2723 expr->operator = field_op;
2724 expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
2725 if (!expr->type) {
2726 ret = -ENOMEM;
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002727 goto free_expr;
Kalesh Singhf47716b2021-10-25 13:08:37 -07002728 }
2729
2730 expr->name = expr_str(expr, 0);
Tom Zanussi100719d2018-01-15 20:51:52 -06002731 }
2732
2733 return expr;
Tom Zanussi100719d2018-01-15 20:51:52 -06002734
Kalesh Singhf86b0aa2021-11-17 17:15:42 -08002735free_operands:
2736 destroy_hist_field(operand2, 0);
2737free_op1:
2738 destroy_hist_field(operand1, 0);
2739 return ERR_PTR(ret);
2740
2741free_expr:
2742 destroy_hist_field(expr, 0);
Tom Zanussi100719d2018-01-15 20:51:52 -06002743 return ERR_PTR(ret);
2744}
2745
Tom Zanussi02205a62018-01-15 20:51:59 -06002746static char *find_trigger_filter(struct hist_trigger_data *hist_data,
2747 struct trace_event_file *file)
2748{
2749 struct event_trigger_data *test;
2750
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09002751 lockdep_assert_held(&event_mutex);
2752
2753 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi02205a62018-01-15 20:51:59 -06002754 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
2755 if (test->private_data == hist_data)
2756 return test->filter_str;
2757 }
2758 }
2759
2760 return NULL;
2761}
2762
2763static struct event_command trigger_hist_cmd;
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06002764static int event_hist_trigger_parse(struct event_command *cmd_ops,
2765 struct trace_event_file *file,
2766 char *glob, char *cmd, char *param);
Tom Zanussi02205a62018-01-15 20:51:59 -06002767
2768static bool compatible_keys(struct hist_trigger_data *target_hist_data,
2769 struct hist_trigger_data *hist_data,
2770 unsigned int n_keys)
2771{
2772 struct hist_field *target_hist_field, *hist_field;
2773 unsigned int n, i, j;
2774
2775 if (hist_data->n_fields - hist_data->n_vals != n_keys)
2776 return false;
2777
2778 i = hist_data->n_vals;
2779 j = target_hist_data->n_vals;
2780
2781 for (n = 0; n < n_keys; n++) {
2782 hist_field = hist_data->fields[i + n];
2783 target_hist_field = target_hist_data->fields[j + n];
2784
2785 if (strcmp(hist_field->type, target_hist_field->type) != 0)
2786 return false;
2787 if (hist_field->size != target_hist_field->size)
2788 return false;
2789 if (hist_field->is_signed != target_hist_field->is_signed)
2790 return false;
2791 }
2792
2793 return true;
2794}
2795
2796static struct hist_trigger_data *
2797find_compatible_hist(struct hist_trigger_data *target_hist_data,
2798 struct trace_event_file *file)
2799{
2800 struct hist_trigger_data *hist_data;
2801 struct event_trigger_data *test;
2802 unsigned int n_keys;
2803
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09002804 lockdep_assert_held(&event_mutex);
2805
Tom Zanussi02205a62018-01-15 20:51:59 -06002806 n_keys = target_hist_data->n_fields - target_hist_data->n_vals;
2807
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09002808 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi02205a62018-01-15 20:51:59 -06002809 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
2810 hist_data = test->private_data;
2811
2812 if (compatible_keys(target_hist_data, hist_data, n_keys))
2813 return hist_data;
2814 }
2815 }
2816
2817 return NULL;
2818}
2819
2820static struct trace_event_file *event_file(struct trace_array *tr,
2821 char *system, char *event_name)
2822{
2823 struct trace_event_file *file;
2824
Steven Rostedt (VMware)3be4c1e2018-05-10 12:42:10 -04002825 file = __find_event_file(tr, system, event_name);
Tom Zanussi02205a62018-01-15 20:51:59 -06002826 if (!file)
2827 return ERR_PTR(-EINVAL);
2828
2829 return file;
2830}
2831
2832static struct hist_field *
2833find_synthetic_field_var(struct hist_trigger_data *target_hist_data,
2834 char *system, char *event_name, char *field_name)
2835{
2836 struct hist_field *event_var;
2837 char *synthetic_name;
2838
2839 synthetic_name = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
2840 if (!synthetic_name)
2841 return ERR_PTR(-ENOMEM);
2842
2843 strcpy(synthetic_name, "synthetic_");
2844 strcat(synthetic_name, field_name);
2845
2846 event_var = find_event_var(target_hist_data, system, event_name, synthetic_name);
2847
2848 kfree(synthetic_name);
2849
2850 return event_var;
2851}
2852
2853/**
2854 * create_field_var_hist - Automatically create a histogram and var for a field
2855 * @target_hist_data: The target hist trigger
2856 * @subsys_name: Optional subsystem name
2857 * @event_name: Optional event name
2858 * @field_name: The name of the field (and the resulting variable)
2859 *
2860 * Hist trigger actions fetch data from variables, not directly from
2861 * events. However, for convenience, users are allowed to directly
2862 * specify an event field in an action, which will be automatically
2863 * converted into a variable on their behalf.
Colin Ian Kingb26503b2021-10-06 18:28:30 +01002864 *
Tom Zanussi02205a62018-01-15 20:51:59 -06002865 * If a user specifies a field on an event that isn't the event the
2866 * histogram currently being defined (the target event histogram), the
2867 * only way that can be accomplished is if a new hist trigger is
2868 * created and the field variable defined on that.
2869 *
2870 * This function creates a new histogram compatible with the target
2871 * event (meaning a histogram with the same key as the target
2872 * histogram), and creates a variable for the specified field, but
2873 * with 'synthetic_' prepended to the variable name in order to avoid
2874 * collision with normal field variables.
2875 *
2876 * Return: The variable created for the field.
2877 */
Tom Zanussic282a382018-01-15 20:52:00 -06002878static struct hist_field *
Tom Zanussi02205a62018-01-15 20:51:59 -06002879create_field_var_hist(struct hist_trigger_data *target_hist_data,
2880 char *subsys_name, char *event_name, char *field_name)
2881{
2882 struct trace_array *tr = target_hist_data->event_file->tr;
Tom Zanussi02205a62018-01-15 20:51:59 -06002883 struct hist_trigger_data *hist_data;
2884 unsigned int i, n, first = true;
2885 struct field_var_hist *var_hist;
2886 struct trace_event_file *file;
2887 struct hist_field *key_field;
Jiapeng Chong614db492021-05-08 18:37:16 +08002888 struct hist_field *event_var;
Tom Zanussi02205a62018-01-15 20:51:59 -06002889 char *saved_filter;
2890 char *cmd;
2891 int ret;
2892
Tom Zanussif404da62018-01-15 20:52:05 -06002893 if (target_hist_data->n_field_var_hists >= SYNTH_FIELDS_MAX) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002894 hist_err(tr, HIST_ERR_TOO_MANY_FIELD_VARS, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06002895 return ERR_PTR(-EINVAL);
Tom Zanussif404da62018-01-15 20:52:05 -06002896 }
Tom Zanussi02205a62018-01-15 20:51:59 -06002897
2898 file = event_file(tr, subsys_name, event_name);
2899
2900 if (IS_ERR(file)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002901 hist_err(tr, HIST_ERR_EVENT_FILE_NOT_FOUND, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06002902 ret = PTR_ERR(file);
2903 return ERR_PTR(ret);
2904 }
2905
2906 /*
2907 * Look for a histogram compatible with target. We'll use the
2908 * found histogram specification to create a new matching
2909 * histogram with our variable on it. target_hist_data is not
2910 * yet a registered histogram so we can't use that.
2911 */
2912 hist_data = find_compatible_hist(target_hist_data, file);
Tom Zanussif404da62018-01-15 20:52:05 -06002913 if (!hist_data) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002914 hist_err(tr, HIST_ERR_HIST_NOT_FOUND, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06002915 return ERR_PTR(-EINVAL);
Tom Zanussif404da62018-01-15 20:52:05 -06002916 }
Tom Zanussi02205a62018-01-15 20:51:59 -06002917
2918 /* See if a synthetic field variable has already been created */
2919 event_var = find_synthetic_field_var(target_hist_data, subsys_name,
2920 event_name, field_name);
2921 if (!IS_ERR_OR_NULL(event_var))
2922 return event_var;
2923
2924 var_hist = kzalloc(sizeof(*var_hist), GFP_KERNEL);
2925 if (!var_hist)
2926 return ERR_PTR(-ENOMEM);
2927
2928 cmd = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
2929 if (!cmd) {
2930 kfree(var_hist);
2931 return ERR_PTR(-ENOMEM);
2932 }
2933
2934 /* Use the same keys as the compatible histogram */
2935 strcat(cmd, "keys=");
2936
2937 for_each_hist_key_field(i, hist_data) {
2938 key_field = hist_data->fields[i];
2939 if (!first)
2940 strcat(cmd, ",");
2941 strcat(cmd, key_field->field->name);
2942 first = false;
2943 }
2944
2945 /* Create the synthetic field variable specification */
2946 strcat(cmd, ":synthetic_");
2947 strcat(cmd, field_name);
2948 strcat(cmd, "=");
2949 strcat(cmd, field_name);
2950
2951 /* Use the same filter as the compatible histogram */
2952 saved_filter = find_trigger_filter(hist_data, file);
2953 if (saved_filter) {
2954 strcat(cmd, " if ");
2955 strcat(cmd, saved_filter);
2956 }
2957
2958 var_hist->cmd = kstrdup(cmd, GFP_KERNEL);
2959 if (!var_hist->cmd) {
2960 kfree(cmd);
2961 kfree(var_hist);
2962 return ERR_PTR(-ENOMEM);
2963 }
2964
2965 /* Save the compatible histogram information */
2966 var_hist->hist_data = hist_data;
2967
2968 /* Create the new histogram with our variable */
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06002969 ret = event_hist_trigger_parse(&trigger_hist_cmd, file,
2970 "", "hist", cmd);
Tom Zanussi02205a62018-01-15 20:51:59 -06002971 if (ret) {
2972 kfree(cmd);
2973 kfree(var_hist->cmd);
2974 kfree(var_hist);
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002975 hist_err(tr, HIST_ERR_HIST_CREATE_FAIL, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06002976 return ERR_PTR(ret);
2977 }
2978
2979 kfree(cmd);
2980
2981 /* If we can't find the variable, something went wrong */
2982 event_var = find_synthetic_field_var(target_hist_data, subsys_name,
2983 event_name, field_name);
2984 if (IS_ERR_OR_NULL(event_var)) {
2985 kfree(var_hist->cmd);
2986 kfree(var_hist);
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04002987 hist_err(tr, HIST_ERR_SYNTH_VAR_NOT_FOUND, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06002988 return ERR_PTR(-EINVAL);
2989 }
2990
2991 n = target_hist_data->n_field_var_hists;
2992 target_hist_data->field_var_hists[n] = var_hist;
2993 target_hist_data->n_field_var_hists++;
2994
2995 return event_var;
2996}
2997
Tom Zanussic282a382018-01-15 20:52:00 -06002998static struct hist_field *
Tom Zanussi02205a62018-01-15 20:51:59 -06002999find_target_event_var(struct hist_trigger_data *hist_data,
3000 char *subsys_name, char *event_name, char *var_name)
3001{
3002 struct trace_event_file *file = hist_data->event_file;
3003 struct hist_field *hist_field = NULL;
3004
3005 if (subsys_name) {
3006 struct trace_event_call *call;
3007
3008 if (!event_name)
3009 return NULL;
3010
3011 call = file->event_call;
3012
3013 if (strcmp(subsys_name, call->class->system) != 0)
3014 return NULL;
3015
3016 if (strcmp(event_name, trace_event_name(call)) != 0)
3017 return NULL;
3018 }
3019
3020 hist_field = find_var_field(hist_data, var_name);
3021
3022 return hist_field;
3023}
3024
3025static inline void __update_field_vars(struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003026 struct trace_buffer *buffer,
Tom Zanussi02205a62018-01-15 20:51:59 -06003027 struct ring_buffer_event *rbe,
3028 void *rec,
3029 struct field_var **field_vars,
3030 unsigned int n_field_vars,
3031 unsigned int field_var_str_start)
3032{
3033 struct hist_elt_data *elt_data = elt->private_data;
3034 unsigned int i, j, var_idx;
3035 u64 var_val;
3036
3037 for (i = 0, j = field_var_str_start; i < n_field_vars; i++) {
3038 struct field_var *field_var = field_vars[i];
3039 struct hist_field *var = field_var->var;
3040 struct hist_field *val = field_var->val;
3041
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003042 var_val = val->fn(val, elt, buffer, rbe, rec);
Tom Zanussi02205a62018-01-15 20:51:59 -06003043 var_idx = var->var.idx;
3044
3045 if (val->flags & HIST_FIELD_FL_STRING) {
3046 char *str = elt_data->field_var_str[j++];
3047 char *val_str = (char *)(uintptr_t)var_val;
Steven Rostedt (VMware)938aa332021-11-14 13:28:34 -05003048 unsigned int size;
Tom Zanussi02205a62018-01-15 20:51:59 -06003049
Steven Rostedt (VMware)938aa332021-11-14 13:28:34 -05003050 size = min(val->size, STR_VAR_LEN_MAX);
3051 strscpy(str, val_str, size);
Tom Zanussi02205a62018-01-15 20:51:59 -06003052 var_val = (u64)(uintptr_t)str;
3053 }
3054 tracing_map_set_var(elt, var_idx, var_val);
3055 }
3056}
3057
3058static void update_field_vars(struct hist_trigger_data *hist_data,
3059 struct tracing_map_elt *elt,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003060 struct trace_buffer *buffer,
Tom Zanussi02205a62018-01-15 20:51:59 -06003061 struct ring_buffer_event *rbe,
3062 void *rec)
3063{
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003064 __update_field_vars(elt, buffer, rbe, rec, hist_data->field_vars,
Tom Zanussi02205a62018-01-15 20:51:59 -06003065 hist_data->n_field_vars, 0);
3066}
3067
Tom Zanussi466f4522019-02-13 17:42:44 -06003068static void save_track_data_vars(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003069 struct tracing_map_elt *elt,
3070 struct trace_buffer *buffer, void *rec,
Tom Zanussi466f4522019-02-13 17:42:44 -06003071 struct ring_buffer_event *rbe, void *key,
3072 struct action_data *data, u64 *var_ref_vals)
Tom Zanussi50450602018-01-15 20:52:01 -06003073{
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003074 __update_field_vars(elt, buffer, rbe, rec, hist_data->save_vars,
Tom Zanussi7d18a102019-02-13 17:42:41 -06003075 hist_data->n_save_vars, hist_data->n_field_var_str);
Tom Zanussi50450602018-01-15 20:52:01 -06003076}
3077
Tom Zanussi02205a62018-01-15 20:51:59 -06003078static struct hist_field *create_var(struct hist_trigger_data *hist_data,
3079 struct trace_event_file *file,
3080 char *name, int size, const char *type)
3081{
3082 struct hist_field *var;
3083 int idx;
3084
3085 if (find_var(hist_data, file, name) && !hist_data->remove) {
3086 var = ERR_PTR(-EINVAL);
3087 goto out;
3088 }
3089
3090 var = kzalloc(sizeof(struct hist_field), GFP_KERNEL);
3091 if (!var) {
3092 var = ERR_PTR(-ENOMEM);
3093 goto out;
3094 }
3095
3096 idx = tracing_map_add_var(hist_data->map);
3097 if (idx < 0) {
3098 kfree(var);
3099 var = ERR_PTR(-EINVAL);
3100 goto out;
3101 }
3102
Vamshi K Sthambamkadi9da73972020-04-22 11:45:06 +05303103 var->ref = 1;
Tom Zanussi02205a62018-01-15 20:51:59 -06003104 var->flags = HIST_FIELD_FL_VAR;
3105 var->var.idx = idx;
3106 var->var.hist_data = var->hist_data = hist_data;
3107 var->size = size;
3108 var->var.name = kstrdup(name, GFP_KERNEL);
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04003109 var->type = kstrdup_const(type, GFP_KERNEL);
Tom Zanussi02205a62018-01-15 20:51:59 -06003110 if (!var->var.name || !var->type) {
Steven Rostedt (VMware)3347d802021-07-22 10:27:06 -04003111 kfree_const(var->type);
Tom Zanussi02205a62018-01-15 20:51:59 -06003112 kfree(var->var.name);
Tom Zanussi02205a62018-01-15 20:51:59 -06003113 kfree(var);
3114 var = ERR_PTR(-ENOMEM);
3115 }
3116 out:
3117 return var;
3118}
3119
3120static struct field_var *create_field_var(struct hist_trigger_data *hist_data,
3121 struct trace_event_file *file,
3122 char *field_name)
3123{
3124 struct hist_field *val = NULL, *var = NULL;
3125 unsigned long flags = HIST_FIELD_FL_VAR;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003126 struct trace_array *tr = file->tr;
Tom Zanussi02205a62018-01-15 20:51:59 -06003127 struct field_var *field_var;
3128 int ret = 0;
3129
3130 if (hist_data->n_field_vars >= SYNTH_FIELDS_MAX) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003131 hist_err(tr, HIST_ERR_TOO_MANY_FIELD_VARS, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06003132 ret = -EINVAL;
3133 goto err;
3134 }
3135
3136 val = parse_atom(hist_data, file, field_name, &flags, NULL);
3137 if (IS_ERR(val)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003138 hist_err(tr, HIST_ERR_FIELD_VAR_PARSE_FAIL, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06003139 ret = PTR_ERR(val);
3140 goto err;
3141 }
3142
3143 var = create_var(hist_data, file, field_name, val->size, val->type);
3144 if (IS_ERR(var)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003145 hist_err(tr, HIST_ERR_VAR_CREATE_FIND_FAIL, errpos(field_name));
Tom Zanussi02205a62018-01-15 20:51:59 -06003146 kfree(val);
3147 ret = PTR_ERR(var);
3148 goto err;
3149 }
3150
3151 field_var = kzalloc(sizeof(struct field_var), GFP_KERNEL);
3152 if (!field_var) {
3153 kfree(val);
3154 kfree(var);
3155 ret = -ENOMEM;
3156 goto err;
3157 }
3158
3159 field_var->var = var;
3160 field_var->val = val;
3161 out:
3162 return field_var;
3163 err:
3164 field_var = ERR_PTR(ret);
3165 goto out;
3166}
3167
3168/**
3169 * create_target_field_var - Automatically create a variable for a field
3170 * @target_hist_data: The target hist trigger
3171 * @subsys_name: Optional subsystem name
3172 * @event_name: Optional event name
3173 * @var_name: The name of the field (and the resulting variable)
3174 *
3175 * Hist trigger actions fetch data from variables, not directly from
3176 * events. However, for convenience, users are allowed to directly
3177 * specify an event field in an action, which will be automatically
3178 * converted into a variable on their behalf.
3179
3180 * This function creates a field variable with the name var_name on
3181 * the hist trigger currently being defined on the target event. If
3182 * subsys_name and event_name are specified, this function simply
3183 * verifies that they do in fact match the target event subsystem and
3184 * event name.
3185 *
3186 * Return: The variable created for the field.
3187 */
Tom Zanussic282a382018-01-15 20:52:00 -06003188static struct field_var *
Tom Zanussi02205a62018-01-15 20:51:59 -06003189create_target_field_var(struct hist_trigger_data *target_hist_data,
3190 char *subsys_name, char *event_name, char *var_name)
3191{
3192 struct trace_event_file *file = target_hist_data->event_file;
3193
3194 if (subsys_name) {
3195 struct trace_event_call *call;
3196
3197 if (!event_name)
3198 return NULL;
3199
3200 call = file->event_call;
3201
3202 if (strcmp(subsys_name, call->class->system) != 0)
3203 return NULL;
3204
3205 if (strcmp(event_name, trace_event_name(call)) != 0)
3206 return NULL;
3207 }
3208
3209 return create_field_var(target_hist_data, file, var_name);
3210}
3211
Tom Zanussi466f4522019-02-13 17:42:44 -06003212static bool check_track_val_max(u64 track_val, u64 var_val)
Tom Zanussi50450602018-01-15 20:52:01 -06003213{
Tom Zanussi466f4522019-02-13 17:42:44 -06003214 if (var_val <= track_val)
3215 return false;
Tom Zanussi50450602018-01-15 20:52:01 -06003216
Tom Zanussi466f4522019-02-13 17:42:44 -06003217 return true;
3218}
3219
Tom Zanussidff81f52019-02-13 17:42:48 -06003220static bool check_track_val_changed(u64 track_val, u64 var_val)
3221{
3222 if (var_val == track_val)
3223 return false;
3224
3225 return true;
3226}
3227
Tom Zanussi466f4522019-02-13 17:42:44 -06003228static u64 get_track_val(struct hist_trigger_data *hist_data,
3229 struct tracing_map_elt *elt,
3230 struct action_data *data)
3231{
3232 unsigned int track_var_idx = data->track_data.track_var->var.idx;
3233 u64 track_val;
3234
3235 track_val = tracing_map_read_var(elt, track_var_idx);
3236
3237 return track_val;
3238}
3239
3240static void save_track_val(struct hist_trigger_data *hist_data,
3241 struct tracing_map_elt *elt,
3242 struct action_data *data, u64 var_val)
3243{
3244 unsigned int track_var_idx = data->track_data.track_var->var.idx;
3245
3246 tracing_map_set_var(elt, track_var_idx, var_val);
3247}
3248
3249static void save_track_data(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003250 struct tracing_map_elt *elt,
3251 struct trace_buffer *buffer, void *rec,
Tom Zanussi466f4522019-02-13 17:42:44 -06003252 struct ring_buffer_event *rbe, void *key,
3253 struct action_data *data, u64 *var_ref_vals)
3254{
3255 if (data->track_data.save_data)
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003256 data->track_data.save_data(hist_data, elt, buffer, rec, rbe,
3257 key, data, var_ref_vals);
Tom Zanussi466f4522019-02-13 17:42:44 -06003258}
3259
3260static bool check_track_val(struct tracing_map_elt *elt,
3261 struct action_data *data,
3262 u64 var_val)
3263{
3264 struct hist_trigger_data *hist_data;
3265 u64 track_val;
3266
3267 hist_data = data->track_data.track_var->hist_data;
3268 track_val = get_track_val(hist_data, elt, data);
3269
3270 return data->track_data.check_val(track_val, var_val);
3271}
3272
Tom Zanussia3785b72019-02-13 17:42:46 -06003273#ifdef CONFIG_TRACER_SNAPSHOT
3274static bool cond_snapshot_update(struct trace_array *tr, void *cond_data)
3275{
3276 /* called with tr->max_lock held */
3277 struct track_data *track_data = tr->cond_snapshot->cond_data;
3278 struct hist_elt_data *elt_data, *track_elt_data;
3279 struct snapshot_context *context = cond_data;
Tom Zanussi9b2ca372019-04-18 10:18:52 -05003280 struct action_data *action;
Tom Zanussia3785b72019-02-13 17:42:46 -06003281 u64 track_val;
3282
3283 if (!track_data)
3284 return false;
3285
Tom Zanussi9b2ca372019-04-18 10:18:52 -05003286 action = track_data->action_data;
3287
Tom Zanussia3785b72019-02-13 17:42:46 -06003288 track_val = get_track_val(track_data->hist_data, context->elt,
3289 track_data->action_data);
3290
Tom Zanussi9b2ca372019-04-18 10:18:52 -05003291 if (!action->track_data.check_val(track_data->track_val, track_val))
3292 return false;
3293
Tom Zanussia3785b72019-02-13 17:42:46 -06003294 track_data->track_val = track_val;
3295 memcpy(track_data->key, context->key, track_data->key_len);
3296
3297 elt_data = context->elt->private_data;
3298 track_elt_data = track_data->elt.private_data;
3299 if (elt_data->comm)
Tom Zanussi27242c62019-03-05 10:11:59 -06003300 strncpy(track_elt_data->comm, elt_data->comm, TASK_COMM_LEN);
Tom Zanussia3785b72019-02-13 17:42:46 -06003301
3302 track_data->updated = true;
3303
3304 return true;
3305}
3306
3307static void save_track_data_snapshot(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003308 struct tracing_map_elt *elt,
3309 struct trace_buffer *buffer, void *rec,
Tom Zanussia3785b72019-02-13 17:42:46 -06003310 struct ring_buffer_event *rbe, void *key,
3311 struct action_data *data,
3312 u64 *var_ref_vals)
3313{
3314 struct trace_event_file *file = hist_data->event_file;
3315 struct snapshot_context context;
3316
3317 context.elt = elt;
3318 context.key = key;
3319
3320 tracing_snapshot_cond(file->tr, &context);
3321}
3322
3323static void hist_trigger_print_key(struct seq_file *m,
3324 struct hist_trigger_data *hist_data,
3325 void *key,
3326 struct tracing_map_elt *elt);
3327
3328static struct action_data *snapshot_action(struct hist_trigger_data *hist_data)
3329{
3330 unsigned int i;
3331
3332 if (!hist_data->n_actions)
3333 return NULL;
3334
3335 for (i = 0; i < hist_data->n_actions; i++) {
3336 struct action_data *data = hist_data->actions[i];
3337
3338 if (data->action == ACTION_SNAPSHOT)
3339 return data;
3340 }
3341
3342 return NULL;
3343}
3344
3345static void track_data_snapshot_print(struct seq_file *m,
3346 struct hist_trigger_data *hist_data)
3347{
3348 struct trace_event_file *file = hist_data->event_file;
3349 struct track_data *track_data;
3350 struct action_data *action;
3351
3352 track_data = tracing_cond_snapshot_data(file->tr);
3353 if (!track_data)
3354 return;
3355
3356 if (!track_data->updated)
3357 return;
3358
3359 action = snapshot_action(hist_data);
3360 if (!action)
3361 return;
3362
3363 seq_puts(m, "\nSnapshot taken (see tracing/snapshot). Details:\n");
3364 seq_printf(m, "\ttriggering value { %s(%s) }: %10llu",
3365 action->handler == HANDLER_ONMAX ? "onmax" : "onchange",
3366 action->track_data.var_str, track_data->track_val);
3367
3368 seq_puts(m, "\ttriggered by event with key: ");
3369 hist_trigger_print_key(m, hist_data, track_data->key, &track_data->elt);
3370 seq_putc(m, '\n');
3371}
3372#else
3373static bool cond_snapshot_update(struct trace_array *tr, void *cond_data)
3374{
3375 return false;
3376}
3377static void save_track_data_snapshot(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003378 struct tracing_map_elt *elt,
3379 struct trace_buffer *buffer, void *rec,
Tom Zanussia3785b72019-02-13 17:42:46 -06003380 struct ring_buffer_event *rbe, void *key,
3381 struct action_data *data,
3382 u64 *var_ref_vals) {}
3383static void track_data_snapshot_print(struct seq_file *m,
3384 struct hist_trigger_data *hist_data) {}
3385#endif /* CONFIG_TRACER_SNAPSHOT */
3386
Tom Zanussi466f4522019-02-13 17:42:44 -06003387static void track_data_print(struct seq_file *m,
3388 struct hist_trigger_data *hist_data,
3389 struct tracing_map_elt *elt,
3390 struct action_data *data)
3391{
3392 u64 track_val = get_track_val(hist_data, elt, data);
3393 unsigned int i, save_var_idx;
3394
3395 if (data->handler == HANDLER_ONMAX)
3396 seq_printf(m, "\n\tmax: %10llu", track_val);
Tom Zanussidff81f52019-02-13 17:42:48 -06003397 else if (data->handler == HANDLER_ONCHANGE)
3398 seq_printf(m, "\n\tchanged: %10llu", track_val);
Tom Zanussi50450602018-01-15 20:52:01 -06003399
Tom Zanussia3785b72019-02-13 17:42:46 -06003400 if (data->action == ACTION_SNAPSHOT)
3401 return;
3402
Tom Zanussi7d18a102019-02-13 17:42:41 -06003403 for (i = 0; i < hist_data->n_save_vars; i++) {
3404 struct hist_field *save_val = hist_data->save_vars[i]->val;
3405 struct hist_field *save_var = hist_data->save_vars[i]->var;
Tom Zanussi50450602018-01-15 20:52:01 -06003406 u64 val;
3407
3408 save_var_idx = save_var->var.idx;
3409
3410 val = tracing_map_read_var(elt, save_var_idx);
3411
3412 if (save_val->flags & HIST_FIELD_FL_STRING) {
3413 seq_printf(m, " %s: %-32s", save_var->var.name,
3414 (char *)(uintptr_t)(val));
3415 } else
3416 seq_printf(m, " %s: %10llu", save_var->var.name, val);
3417 }
3418}
3419
Tom Zanussi466f4522019-02-13 17:42:44 -06003420static void ontrack_action(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003421 struct tracing_map_elt *elt,
3422 struct trace_buffer *buffer, void *rec,
Tom Zanussi466f4522019-02-13 17:42:44 -06003423 struct ring_buffer_event *rbe, void *key,
3424 struct action_data *data, u64 *var_ref_vals)
Tom Zanussi50450602018-01-15 20:52:01 -06003425{
Tom Zanussi466f4522019-02-13 17:42:44 -06003426 u64 var_val = var_ref_vals[data->track_data.var_ref->var_ref_idx];
Tom Zanussi50450602018-01-15 20:52:01 -06003427
Tom Zanussi466f4522019-02-13 17:42:44 -06003428 if (check_track_val(elt, data, var_val)) {
3429 save_track_val(hist_data, elt, data, var_val);
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04003430 save_track_data(hist_data, elt, buffer, rec, rbe,
3431 key, data, var_ref_vals);
Tom Zanussi466f4522019-02-13 17:42:44 -06003432 }
Tom Zanussi50450602018-01-15 20:52:01 -06003433}
3434
Tom Zanussic3e49502019-02-13 17:42:43 -06003435static void action_data_destroy(struct action_data *data)
Tom Zanussi50450602018-01-15 20:52:01 -06003436{
3437 unsigned int i;
3438
Tom Zanussic3e49502019-02-13 17:42:43 -06003439 lockdep_assert_held(&event_mutex);
Tom Zanussi50450602018-01-15 20:52:01 -06003440
Tom Zanussi7d18a102019-02-13 17:42:41 -06003441 kfree(data->action_name);
Tom Zanussi50450602018-01-15 20:52:01 -06003442
3443 for (i = 0; i < data->n_params; i++)
3444 kfree(data->params[i]);
3445
Tom Zanussic3e49502019-02-13 17:42:43 -06003446 if (data->synth_event)
3447 data->synth_event->ref--;
3448
Tom Zanussie91eefd72019-02-13 17:42:50 -06003449 kfree(data->synth_event_name);
3450
Tom Zanussi50450602018-01-15 20:52:01 -06003451 kfree(data);
3452}
3453
Tom Zanussi466f4522019-02-13 17:42:44 -06003454static void track_data_destroy(struct hist_trigger_data *hist_data,
3455 struct action_data *data)
Tom Zanussic3e49502019-02-13 17:42:43 -06003456{
Tom Zanussia3785b72019-02-13 17:42:46 -06003457 struct trace_event_file *file = hist_data->event_file;
3458
Tom Zanussi466f4522019-02-13 17:42:44 -06003459 destroy_hist_field(data->track_data.track_var, 0);
Tom Zanussic3e49502019-02-13 17:42:43 -06003460
Tom Zanussia3785b72019-02-13 17:42:46 -06003461 if (data->action == ACTION_SNAPSHOT) {
3462 struct track_data *track_data;
3463
3464 track_data = tracing_cond_snapshot_data(file->tr);
3465 if (track_data && track_data->hist_data == hist_data) {
3466 tracing_snapshot_cond_disable(file->tr);
3467 track_data_free(track_data);
3468 }
3469 }
3470
Tom Zanussi466f4522019-02-13 17:42:44 -06003471 kfree(data->track_data.var_str);
Tom Zanussic3e49502019-02-13 17:42:43 -06003472
3473 action_data_destroy(data);
3474}
3475
Tom Zanussi7d18a102019-02-13 17:42:41 -06003476static int action_create(struct hist_trigger_data *hist_data,
3477 struct action_data *data);
3478
Tom Zanussi466f4522019-02-13 17:42:44 -06003479static int track_data_create(struct hist_trigger_data *hist_data,
3480 struct action_data *data)
Tom Zanussi50450602018-01-15 20:52:01 -06003481{
Tom Zanussi466f4522019-02-13 17:42:44 -06003482 struct hist_field *var_field, *ref_field, *track_var = NULL;
Tom Zanussi50450602018-01-15 20:52:01 -06003483 struct trace_event_file *file = hist_data->event_file;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003484 struct trace_array *tr = file->tr;
Tom Zanussi466f4522019-02-13 17:42:44 -06003485 char *track_data_var_str;
Tom Zanussi50450602018-01-15 20:52:01 -06003486 int ret = 0;
3487
Tom Zanussi466f4522019-02-13 17:42:44 -06003488 track_data_var_str = data->track_data.var_str;
3489 if (track_data_var_str[0] != '$') {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003490 hist_err(tr, HIST_ERR_ONX_NOT_VAR, errpos(track_data_var_str));
Tom Zanussi50450602018-01-15 20:52:01 -06003491 return -EINVAL;
Tom Zanussif404da62018-01-15 20:52:05 -06003492 }
Tom Zanussi466f4522019-02-13 17:42:44 -06003493 track_data_var_str++;
Tom Zanussi50450602018-01-15 20:52:01 -06003494
Tom Zanussi466f4522019-02-13 17:42:44 -06003495 var_field = find_target_event_var(hist_data, NULL, NULL, track_data_var_str);
Tom Zanussif404da62018-01-15 20:52:05 -06003496 if (!var_field) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003497 hist_err(tr, HIST_ERR_ONX_VAR_NOT_FOUND, errpos(track_data_var_str));
Tom Zanussi50450602018-01-15 20:52:01 -06003498 return -EINVAL;
Tom Zanussif404da62018-01-15 20:52:05 -06003499 }
Tom Zanussi50450602018-01-15 20:52:01 -06003500
Tom Zanusside40f032018-12-18 14:33:23 -06003501 ref_field = create_var_ref(hist_data, var_field, NULL, NULL);
Tom Zanussi50450602018-01-15 20:52:01 -06003502 if (!ref_field)
3503 return -ENOMEM;
3504
Tom Zanussi466f4522019-02-13 17:42:44 -06003505 data->track_data.var_ref = ref_field;
Tom Zanussi50450602018-01-15 20:52:01 -06003506
Tom Zanussi466f4522019-02-13 17:42:44 -06003507 if (data->handler == HANDLER_ONMAX)
3508 track_var = create_var(hist_data, file, "__max", sizeof(u64), "u64");
3509 if (IS_ERR(track_var)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003510 hist_err(tr, HIST_ERR_ONX_VAR_CREATE_FAIL, 0);
Tom Zanussi466f4522019-02-13 17:42:44 -06003511 ret = PTR_ERR(track_var);
Tom Zanussi50450602018-01-15 20:52:01 -06003512 goto out;
3513 }
Tom Zanussidff81f52019-02-13 17:42:48 -06003514
3515 if (data->handler == HANDLER_ONCHANGE)
3516 track_var = create_var(hist_data, file, "__change", sizeof(u64), "u64");
3517 if (IS_ERR(track_var)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003518 hist_err(tr, HIST_ERR_ONX_VAR_CREATE_FAIL, 0);
Tom Zanussidff81f52019-02-13 17:42:48 -06003519 ret = PTR_ERR(track_var);
3520 goto out;
3521 }
Tom Zanussi466f4522019-02-13 17:42:44 -06003522 data->track_data.track_var = track_var;
Tom Zanussi50450602018-01-15 20:52:01 -06003523
Tom Zanussi7d18a102019-02-13 17:42:41 -06003524 ret = action_create(hist_data, data);
Tom Zanussi50450602018-01-15 20:52:01 -06003525 out:
3526 return ret;
3527}
3528
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003529static int parse_action_params(struct trace_array *tr, char *params,
3530 struct action_data *data)
Tom Zanussi50450602018-01-15 20:52:01 -06003531{
3532 char *param, *saved_param;
Tom Zanussie91eefd72019-02-13 17:42:50 -06003533 bool first_param = true;
Tom Zanussi50450602018-01-15 20:52:01 -06003534 int ret = 0;
3535
3536 while (params) {
Tom Zanussi7d18a102019-02-13 17:42:41 -06003537 if (data->n_params >= SYNTH_FIELDS_MAX) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003538 hist_err(tr, HIST_ERR_TOO_MANY_PARAMS, 0);
Tom Zanussi50450602018-01-15 20:52:01 -06003539 goto out;
Tom Zanussi7d18a102019-02-13 17:42:41 -06003540 }
Tom Zanussi50450602018-01-15 20:52:01 -06003541
3542 param = strsep(&params, ",");
3543 if (!param) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003544 hist_err(tr, HIST_ERR_PARAM_NOT_FOUND, 0);
Tom Zanussi50450602018-01-15 20:52:01 -06003545 ret = -EINVAL;
3546 goto out;
3547 }
3548
3549 param = strstrip(param);
3550 if (strlen(param) < 2) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003551 hist_err(tr, HIST_ERR_INVALID_PARAM, errpos(param));
Tom Zanussi50450602018-01-15 20:52:01 -06003552 ret = -EINVAL;
3553 goto out;
3554 }
3555
3556 saved_param = kstrdup(param, GFP_KERNEL);
3557 if (!saved_param) {
3558 ret = -ENOMEM;
3559 goto out;
3560 }
3561
Tom Zanussie91eefd72019-02-13 17:42:50 -06003562 if (first_param && data->use_trace_keyword) {
3563 data->synth_event_name = saved_param;
3564 first_param = false;
3565 continue;
3566 }
3567 first_param = false;
3568
Tom Zanussi50450602018-01-15 20:52:01 -06003569 data->params[data->n_params++] = saved_param;
3570 }
3571 out:
3572 return ret;
3573}
3574
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003575static int action_parse(struct trace_array *tr, char *str, struct action_data *data,
Tom Zanussi7d18a102019-02-13 17:42:41 -06003576 enum handler_id handler)
Tom Zanussi50450602018-01-15 20:52:01 -06003577{
Tom Zanussi7d18a102019-02-13 17:42:41 -06003578 char *action_name;
3579 int ret = 0;
3580
3581 strsep(&str, ".");
3582 if (!str) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003583 hist_err(tr, HIST_ERR_ACTION_NOT_FOUND, 0);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003584 ret = -EINVAL;
3585 goto out;
3586 }
3587
3588 action_name = strsep(&str, "(");
3589 if (!action_name || !str) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003590 hist_err(tr, HIST_ERR_ACTION_NOT_FOUND, 0);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003591 ret = -EINVAL;
3592 goto out;
3593 }
3594
3595 if (str_has_prefix(action_name, "save")) {
3596 char *params = strsep(&str, ")");
3597
3598 if (!params) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003599 hist_err(tr, HIST_ERR_NO_SAVE_PARAMS, 0);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003600 ret = -EINVAL;
3601 goto out;
3602 }
3603
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003604 ret = parse_action_params(tr, params, data);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003605 if (ret)
3606 goto out;
3607
3608 if (handler == HANDLER_ONMAX)
Tom Zanussi466f4522019-02-13 17:42:44 -06003609 data->track_data.check_val = check_track_val_max;
Tom Zanussidff81f52019-02-13 17:42:48 -06003610 else if (handler == HANDLER_ONCHANGE)
3611 data->track_data.check_val = check_track_val_changed;
Tom Zanussi466f4522019-02-13 17:42:44 -06003612 else {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003613 hist_err(tr, HIST_ERR_ACTION_MISMATCH, errpos(action_name));
Tom Zanussi466f4522019-02-13 17:42:44 -06003614 ret = -EINVAL;
3615 goto out;
3616 }
Tom Zanussi7d18a102019-02-13 17:42:41 -06003617
Tom Zanussi466f4522019-02-13 17:42:44 -06003618 data->track_data.save_data = save_track_data_vars;
3619 data->fn = ontrack_action;
Tom Zanussi7d18a102019-02-13 17:42:41 -06003620 data->action = ACTION_SAVE;
Tom Zanussia3785b72019-02-13 17:42:46 -06003621 } else if (str_has_prefix(action_name, "snapshot")) {
3622 char *params = strsep(&str, ")");
3623
3624 if (!str) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003625 hist_err(tr, HIST_ERR_NO_CLOSING_PAREN, errpos(params));
Tom Zanussia3785b72019-02-13 17:42:46 -06003626 ret = -EINVAL;
3627 goto out;
3628 }
3629
3630 if (handler == HANDLER_ONMAX)
3631 data->track_data.check_val = check_track_val_max;
Tom Zanussidff81f52019-02-13 17:42:48 -06003632 else if (handler == HANDLER_ONCHANGE)
3633 data->track_data.check_val = check_track_val_changed;
Tom Zanussia3785b72019-02-13 17:42:46 -06003634 else {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003635 hist_err(tr, HIST_ERR_ACTION_MISMATCH, errpos(action_name));
Tom Zanussia3785b72019-02-13 17:42:46 -06003636 ret = -EINVAL;
3637 goto out;
3638 }
3639
3640 data->track_data.save_data = save_track_data_snapshot;
3641 data->fn = ontrack_action;
3642 data->action = ACTION_SNAPSHOT;
Tom Zanussi7d18a102019-02-13 17:42:41 -06003643 } else {
3644 char *params = strsep(&str, ")");
3645
Tom Zanussie91eefd72019-02-13 17:42:50 -06003646 if (str_has_prefix(action_name, "trace"))
3647 data->use_trace_keyword = true;
3648
Tom Zanussi7d18a102019-02-13 17:42:41 -06003649 if (params) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003650 ret = parse_action_params(tr, params, data);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003651 if (ret)
3652 goto out;
3653 }
3654
Tom Zanussi466f4522019-02-13 17:42:44 -06003655 if (handler == HANDLER_ONMAX)
3656 data->track_data.check_val = check_track_val_max;
Tom Zanussidff81f52019-02-13 17:42:48 -06003657 else if (handler == HANDLER_ONCHANGE)
3658 data->track_data.check_val = check_track_val_changed;
Tom Zanussi466f4522019-02-13 17:42:44 -06003659
3660 if (handler != HANDLER_ONMATCH) {
3661 data->track_data.save_data = action_trace;
3662 data->fn = ontrack_action;
3663 } else
3664 data->fn = action_trace;
3665
Tom Zanussi7d18a102019-02-13 17:42:41 -06003666 data->action = ACTION_TRACE;
3667 }
3668
3669 data->action_name = kstrdup(action_name, GFP_KERNEL);
3670 if (!data->action_name) {
3671 ret = -ENOMEM;
3672 goto out;
3673 }
3674
3675 data->handler = handler;
3676 out:
3677 return ret;
3678}
3679
Tom Zanussi466f4522019-02-13 17:42:44 -06003680static struct action_data *track_data_parse(struct hist_trigger_data *hist_data,
3681 char *str, enum handler_id handler)
Tom Zanussi7d18a102019-02-13 17:42:41 -06003682{
Tom Zanussi50450602018-01-15 20:52:01 -06003683 struct action_data *data;
3684 int ret = -EINVAL;
Tom Zanussi466f4522019-02-13 17:42:44 -06003685 char *var_str;
Tom Zanussi50450602018-01-15 20:52:01 -06003686
3687 data = kzalloc(sizeof(*data), GFP_KERNEL);
3688 if (!data)
3689 return ERR_PTR(-ENOMEM);
3690
Tom Zanussi466f4522019-02-13 17:42:44 -06003691 var_str = strsep(&str, ")");
3692 if (!var_str || !str) {
Tom Zanussi50450602018-01-15 20:52:01 -06003693 ret = -EINVAL;
3694 goto free;
3695 }
3696
Tom Zanussi466f4522019-02-13 17:42:44 -06003697 data->track_data.var_str = kstrdup(var_str, GFP_KERNEL);
3698 if (!data->track_data.var_str) {
Tom Zanussi50450602018-01-15 20:52:01 -06003699 ret = -ENOMEM;
3700 goto free;
3701 }
3702
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003703 ret = action_parse(hist_data->event_file->tr, str, data, handler);
Tom Zanussi7d18a102019-02-13 17:42:41 -06003704 if (ret)
Tom Zanussi50450602018-01-15 20:52:01 -06003705 goto free;
Tom Zanussi50450602018-01-15 20:52:01 -06003706 out:
3707 return data;
3708 free:
Tom Zanussi466f4522019-02-13 17:42:44 -06003709 track_data_destroy(hist_data, data);
Tom Zanussi50450602018-01-15 20:52:01 -06003710 data = ERR_PTR(ret);
3711 goto out;
3712}
3713
Tom Zanussic282a382018-01-15 20:52:00 -06003714static void onmatch_destroy(struct action_data *data)
3715{
Tom Zanussic3e49502019-02-13 17:42:43 -06003716 kfree(data->match_data.event);
3717 kfree(data->match_data.event_system);
Tom Zanussic282a382018-01-15 20:52:00 -06003718
Tom Zanussic3e49502019-02-13 17:42:43 -06003719 action_data_destroy(data);
Tom Zanussic282a382018-01-15 20:52:00 -06003720}
3721
Tom Zanussi02205a62018-01-15 20:51:59 -06003722static void destroy_field_var(struct field_var *field_var)
3723{
3724 if (!field_var)
3725 return;
3726
3727 destroy_hist_field(field_var->var, 0);
3728 destroy_hist_field(field_var->val, 0);
3729
3730 kfree(field_var);
3731}
3732
3733static void destroy_field_vars(struct hist_trigger_data *hist_data)
3734{
3735 unsigned int i;
3736
3737 for (i = 0; i < hist_data->n_field_vars; i++)
3738 destroy_field_var(hist_data->field_vars[i]);
Vamshi K Sthambamkadi9da73972020-04-22 11:45:06 +05303739
3740 for (i = 0; i < hist_data->n_save_vars; i++)
3741 destroy_field_var(hist_data->save_vars[i]);
Tom Zanussi02205a62018-01-15 20:51:59 -06003742}
3743
Tom Zanussic282a382018-01-15 20:52:00 -06003744static void save_field_var(struct hist_trigger_data *hist_data,
3745 struct field_var *field_var)
Tom Zanussi02205a62018-01-15 20:51:59 -06003746{
3747 hist_data->field_vars[hist_data->n_field_vars++] = field_var;
3748
3749 if (field_var->val->flags & HIST_FIELD_FL_STRING)
3750 hist_data->n_field_var_str++;
3751}
3752
Tom Zanussic282a382018-01-15 20:52:00 -06003753
Tom Zanussic282a382018-01-15 20:52:00 -06003754static int check_synth_field(struct synth_event *event,
3755 struct hist_field *hist_field,
3756 unsigned int field_pos)
3757{
3758 struct synth_field *field;
3759
3760 if (field_pos >= event->n_fields)
3761 return -EINVAL;
3762
3763 field = event->fields[field_pos];
3764
Tom Zanussibd826312020-10-04 17:14:06 -05003765 /*
3766 * A dynamic string synth field can accept static or
3767 * dynamic. A static string synth field can only accept a
3768 * same-sized static string, which is checked for later.
3769 */
3770 if (strstr(hist_field->type, "char[") && field->is_string
3771 && field->is_dynamic)
3772 return 0;
3773
Masami Hiramatsub05e89a2020-01-11 01:05:53 +09003774 if (strcmp(field->type, hist_field->type) != 0) {
3775 if (field->size != hist_field->size ||
Steven Rostedt (VMware)450fec12021-11-30 12:31:23 -05003776 (!field->is_string && field->is_signed != hist_field->is_signed))
Masami Hiramatsub05e89a2020-01-11 01:05:53 +09003777 return -EINVAL;
3778 }
Tom Zanussic282a382018-01-15 20:52:00 -06003779
3780 return 0;
3781}
3782
Tom Zanussic282a382018-01-15 20:52:00 -06003783static struct hist_field *
Tom Zanussi7d18a102019-02-13 17:42:41 -06003784trace_action_find_var(struct hist_trigger_data *hist_data,
3785 struct action_data *data,
3786 char *system, char *event, char *var)
Tom Zanussic282a382018-01-15 20:52:00 -06003787{
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003788 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussic282a382018-01-15 20:52:00 -06003789 struct hist_field *hist_field;
3790
3791 var++; /* skip '$' */
3792
3793 hist_field = find_target_event_var(hist_data, system, event, var);
3794 if (!hist_field) {
Tom Zanussi7d18a102019-02-13 17:42:41 -06003795 if (!system && data->handler == HANDLER_ONMATCH) {
Tom Zanussic3e49502019-02-13 17:42:43 -06003796 system = data->match_data.event_system;
3797 event = data->match_data.event;
Tom Zanussic282a382018-01-15 20:52:00 -06003798 }
3799
3800 hist_field = find_event_var(hist_data, system, event, var);
3801 }
3802
Tom Zanussif404da62018-01-15 20:52:05 -06003803 if (!hist_field)
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003804 hist_err(tr, HIST_ERR_PARAM_NOT_FOUND, errpos(var));
Tom Zanussif404da62018-01-15 20:52:05 -06003805
Tom Zanussic282a382018-01-15 20:52:00 -06003806 return hist_field;
3807}
3808
3809static struct hist_field *
Tom Zanussi7d18a102019-02-13 17:42:41 -06003810trace_action_create_field_var(struct hist_trigger_data *hist_data,
3811 struct action_data *data, char *system,
3812 char *event, char *var)
Tom Zanussic282a382018-01-15 20:52:00 -06003813{
3814 struct hist_field *hist_field = NULL;
3815 struct field_var *field_var;
3816
3817 /*
3818 * First try to create a field var on the target event (the
3819 * currently being defined). This will create a variable for
3820 * unqualified fields on the target event, or if qualified,
3821 * target fields that have qualified names matching the target.
3822 */
3823 field_var = create_target_field_var(hist_data, system, event, var);
3824
3825 if (field_var && !IS_ERR(field_var)) {
3826 save_field_var(hist_data, field_var);
3827 hist_field = field_var->var;
3828 } else {
3829 field_var = NULL;
3830 /*
Qiujun Huang2b5894c2020-10-29 23:05:54 +08003831 * If no explicit system.event is specified, default to
Tom Zanussic282a382018-01-15 20:52:00 -06003832 * looking for fields on the onmatch(system.event.xxx)
3833 * event.
3834 */
Tom Zanussi7d18a102019-02-13 17:42:41 -06003835 if (!system && data->handler == HANDLER_ONMATCH) {
Tom Zanussic3e49502019-02-13 17:42:43 -06003836 system = data->match_data.event_system;
3837 event = data->match_data.event;
Tom Zanussic282a382018-01-15 20:52:00 -06003838 }
3839
Steven Rostedt (VMware)5acce0b2021-08-08 00:30:11 -04003840 if (!event)
3841 goto free;
Tom Zanussic282a382018-01-15 20:52:00 -06003842 /*
3843 * At this point, we're looking at a field on another
3844 * event. Because we can't modify a hist trigger on
3845 * another event to add a variable for a field, we need
3846 * to create a new trigger on that event and create the
3847 * variable at the same time.
3848 */
3849 hist_field = create_field_var_hist(hist_data, system, event, var);
3850 if (IS_ERR(hist_field))
3851 goto free;
3852 }
3853 out:
3854 return hist_field;
3855 free:
3856 destroy_field_var(field_var);
3857 hist_field = NULL;
3858 goto out;
3859}
3860
Tom Zanussi7d18a102019-02-13 17:42:41 -06003861static int trace_action_create(struct hist_trigger_data *hist_data,
3862 struct action_data *data)
Tom Zanussic282a382018-01-15 20:52:00 -06003863{
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003864 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussic282a382018-01-15 20:52:00 -06003865 char *event_name, *param, *system = NULL;
3866 struct hist_field *hist_field, *var_ref;
Tom Zanussid380dcd2020-01-29 21:18:18 -05003867 unsigned int i;
Tom Zanussic282a382018-01-15 20:52:00 -06003868 unsigned int field_pos = 0;
3869 struct synth_event *event;
Tom Zanussie91eefd72019-02-13 17:42:50 -06003870 char *synth_event_name;
Tom Zanussid380dcd2020-01-29 21:18:18 -05003871 int var_ref_idx, ret = 0;
Tom Zanussic282a382018-01-15 20:52:00 -06003872
Masami Hiramatsu0e2b81f72018-11-05 18:04:01 +09003873 lockdep_assert_held(&event_mutex);
3874
Tom Zanussie91eefd72019-02-13 17:42:50 -06003875 if (data->use_trace_keyword)
3876 synth_event_name = data->synth_event_name;
3877 else
3878 synth_event_name = data->action_name;
3879
3880 event = find_synth_event(synth_event_name);
Tom Zanussic282a382018-01-15 20:52:00 -06003881 if (!event) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003882 hist_err(tr, HIST_ERR_SYNTH_EVENT_NOT_FOUND, errpos(synth_event_name));
Tom Zanussic282a382018-01-15 20:52:00 -06003883 return -EINVAL;
3884 }
Tom Zanussi7d18a102019-02-13 17:42:41 -06003885
Tom Zanussic282a382018-01-15 20:52:00 -06003886 event->ref++;
Tom Zanussic282a382018-01-15 20:52:00 -06003887
Tom Zanussic282a382018-01-15 20:52:00 -06003888 for (i = 0; i < data->n_params; i++) {
3889 char *p;
3890
3891 p = param = kstrdup(data->params[i], GFP_KERNEL);
3892 if (!param) {
3893 ret = -ENOMEM;
3894 goto err;
3895 }
3896
3897 system = strsep(&param, ".");
3898 if (!param) {
3899 param = (char *)system;
3900 system = event_name = NULL;
3901 } else {
3902 event_name = strsep(&param, ".");
3903 if (!param) {
3904 kfree(p);
3905 ret = -EINVAL;
3906 goto err;
3907 }
3908 }
3909
3910 if (param[0] == '$')
Tom Zanussi7d18a102019-02-13 17:42:41 -06003911 hist_field = trace_action_find_var(hist_data, data,
3912 system, event_name,
3913 param);
Tom Zanussic282a382018-01-15 20:52:00 -06003914 else
Tom Zanussi7d18a102019-02-13 17:42:41 -06003915 hist_field = trace_action_create_field_var(hist_data,
3916 data,
3917 system,
3918 event_name,
3919 param);
Tom Zanussic282a382018-01-15 20:52:00 -06003920
3921 if (!hist_field) {
3922 kfree(p);
3923 ret = -EINVAL;
3924 goto err;
3925 }
3926
3927 if (check_synth_field(event, hist_field, field_pos) == 0) {
Tom Zanusside40f032018-12-18 14:33:23 -06003928 var_ref = create_var_ref(hist_data, hist_field,
3929 system, event_name);
Tom Zanussic282a382018-01-15 20:52:00 -06003930 if (!var_ref) {
3931 kfree(p);
3932 ret = -ENOMEM;
3933 goto err;
3934 }
3935
Tom Zanussid380dcd2020-01-29 21:18:18 -05003936 var_ref_idx = find_var_ref_idx(hist_data, var_ref);
3937 if (WARN_ON(var_ref_idx < 0)) {
3938 ret = var_ref_idx;
3939 goto err;
3940 }
3941
3942 data->var_ref_idx[i] = var_ref_idx;
3943
Tom Zanussic282a382018-01-15 20:52:00 -06003944 field_pos++;
3945 kfree(p);
3946 continue;
3947 }
3948
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003949 hist_err(tr, HIST_ERR_SYNTH_TYPE_MISMATCH, errpos(param));
Tom Zanussic282a382018-01-15 20:52:00 -06003950 kfree(p);
3951 ret = -EINVAL;
3952 goto err;
3953 }
3954
3955 if (field_pos != event->n_fields) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003956 hist_err(tr, HIST_ERR_SYNTH_COUNT_MISMATCH, errpos(event->name));
Tom Zanussic282a382018-01-15 20:52:00 -06003957 ret = -EINVAL;
3958 goto err;
3959 }
3960
Tom Zanussic3e49502019-02-13 17:42:43 -06003961 data->synth_event = event;
Tom Zanussic282a382018-01-15 20:52:00 -06003962 out:
3963 return ret;
3964 err:
Tom Zanussic282a382018-01-15 20:52:00 -06003965 event->ref--;
Tom Zanussic282a382018-01-15 20:52:00 -06003966
3967 goto out;
3968}
3969
Tom Zanussi7d18a102019-02-13 17:42:41 -06003970static int action_create(struct hist_trigger_data *hist_data,
3971 struct action_data *data)
3972{
Tom Zanussia3785b72019-02-13 17:42:46 -06003973 struct trace_event_file *file = hist_data->event_file;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04003974 struct trace_array *tr = file->tr;
Tom Zanussia3785b72019-02-13 17:42:46 -06003975 struct track_data *track_data;
Tom Zanussi7d18a102019-02-13 17:42:41 -06003976 struct field_var *field_var;
3977 unsigned int i;
3978 char *param;
3979 int ret = 0;
3980
3981 if (data->action == ACTION_TRACE)
3982 return trace_action_create(hist_data, data);
3983
Tom Zanussia3785b72019-02-13 17:42:46 -06003984 if (data->action == ACTION_SNAPSHOT) {
3985 track_data = track_data_alloc(hist_data->key_size, data, hist_data);
3986 if (IS_ERR(track_data)) {
3987 ret = PTR_ERR(track_data);
3988 goto out;
3989 }
3990
3991 ret = tracing_snapshot_cond_enable(file->tr, track_data,
3992 cond_snapshot_update);
3993 if (ret)
3994 track_data_free(track_data);
3995
3996 goto out;
3997 }
3998
Tom Zanussi7d18a102019-02-13 17:42:41 -06003999 if (data->action == ACTION_SAVE) {
4000 if (hist_data->n_save_vars) {
4001 ret = -EEXIST;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004002 hist_err(tr, HIST_ERR_TOO_MANY_SAVE_ACTIONS, 0);
Tom Zanussi7d18a102019-02-13 17:42:41 -06004003 goto out;
4004 }
4005
4006 for (i = 0; i < data->n_params; i++) {
4007 param = kstrdup(data->params[i], GFP_KERNEL);
4008 if (!param) {
4009 ret = -ENOMEM;
4010 goto out;
4011 }
4012
4013 field_var = create_target_field_var(hist_data, NULL, NULL, param);
4014 if (IS_ERR(field_var)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004015 hist_err(tr, HIST_ERR_FIELD_VAR_CREATE_FAIL,
4016 errpos(param));
Tom Zanussi7d18a102019-02-13 17:42:41 -06004017 ret = PTR_ERR(field_var);
4018 kfree(param);
4019 goto out;
4020 }
4021
4022 hist_data->save_vars[hist_data->n_save_vars++] = field_var;
4023 if (field_var->val->flags & HIST_FIELD_FL_STRING)
4024 hist_data->n_save_var_str++;
4025 kfree(param);
4026 }
4027 }
4028 out:
4029 return ret;
4030}
4031
4032static int onmatch_create(struct hist_trigger_data *hist_data,
4033 struct action_data *data)
4034{
4035 return action_create(hist_data, data);
4036}
4037
Tom Zanussic282a382018-01-15 20:52:00 -06004038static struct action_data *onmatch_parse(struct trace_array *tr, char *str)
4039{
4040 char *match_event, *match_event_system;
Tom Zanussic282a382018-01-15 20:52:00 -06004041 struct action_data *data;
4042 int ret = -EINVAL;
4043
4044 data = kzalloc(sizeof(*data), GFP_KERNEL);
4045 if (!data)
4046 return ERR_PTR(-ENOMEM);
4047
4048 match_event = strsep(&str, ")");
Tom Zanussif404da62018-01-15 20:52:05 -06004049 if (!match_event || !str) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004050 hist_err(tr, HIST_ERR_NO_CLOSING_PAREN, errpos(match_event));
Tom Zanussic282a382018-01-15 20:52:00 -06004051 goto free;
Tom Zanussif404da62018-01-15 20:52:05 -06004052 }
Tom Zanussic282a382018-01-15 20:52:00 -06004053
4054 match_event_system = strsep(&match_event, ".");
Tom Zanussif404da62018-01-15 20:52:05 -06004055 if (!match_event) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004056 hist_err(tr, HIST_ERR_SUBSYS_NOT_FOUND, errpos(match_event_system));
Tom Zanussic282a382018-01-15 20:52:00 -06004057 goto free;
Tom Zanussif404da62018-01-15 20:52:05 -06004058 }
Tom Zanussic282a382018-01-15 20:52:00 -06004059
Tom Zanussif404da62018-01-15 20:52:05 -06004060 if (IS_ERR(event_file(tr, match_event_system, match_event))) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004061 hist_err(tr, HIST_ERR_INVALID_SUBSYS_EVENT, errpos(match_event));
Tom Zanussic282a382018-01-15 20:52:00 -06004062 goto free;
Tom Zanussif404da62018-01-15 20:52:05 -06004063 }
Tom Zanussic282a382018-01-15 20:52:00 -06004064
Tom Zanussic3e49502019-02-13 17:42:43 -06004065 data->match_data.event = kstrdup(match_event, GFP_KERNEL);
4066 if (!data->match_data.event) {
Tom Zanussic282a382018-01-15 20:52:00 -06004067 ret = -ENOMEM;
4068 goto free;
4069 }
4070
Tom Zanussic3e49502019-02-13 17:42:43 -06004071 data->match_data.event_system = kstrdup(match_event_system, GFP_KERNEL);
4072 if (!data->match_data.event_system) {
Tom Zanussic282a382018-01-15 20:52:00 -06004073 ret = -ENOMEM;
4074 goto free;
4075 }
4076
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004077 ret = action_parse(tr, str, data, HANDLER_ONMATCH);
Tom Zanussic282a382018-01-15 20:52:00 -06004078 if (ret)
4079 goto free;
4080 out:
4081 return data;
4082 free:
4083 onmatch_destroy(data);
4084 data = ERR_PTR(ret);
4085 goto out;
4086}
4087
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004088static int create_hitcount_val(struct hist_trigger_data *hist_data)
4089{
4090 hist_data->fields[HITCOUNT_IDX] =
Tom Zanussi30350d62018-01-15 20:51:49 -06004091 create_hist_field(hist_data, NULL, HIST_FIELD_FL_HITCOUNT, NULL);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004092 if (!hist_data->fields[HITCOUNT_IDX])
4093 return -ENOMEM;
4094
4095 hist_data->n_vals++;
Tom Zanussi30350d62018-01-15 20:51:49 -06004096 hist_data->n_fields++;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004097
4098 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
4099 return -EINVAL;
4100
4101 return 0;
4102}
4103
Tom Zanussi30350d62018-01-15 20:51:49 -06004104static int __create_val_field(struct hist_trigger_data *hist_data,
4105 unsigned int val_idx,
4106 struct trace_event_file *file,
4107 char *var_name, char *field_str,
4108 unsigned long flags)
Tom Zanussif2606832016-03-03 12:54:43 -06004109{
Tom Zanussi100719d2018-01-15 20:51:52 -06004110 struct hist_field *hist_field;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07004111 int ret = 0, n_subexprs = 0;
Tom Zanussif2606832016-03-03 12:54:43 -06004112
Kalesh Singh9710b2f2021-10-25 13:08:35 -07004113 hist_field = parse_expr(hist_data, file, field_str, flags, var_name, &n_subexprs);
Tom Zanussi100719d2018-01-15 20:51:52 -06004114 if (IS_ERR(hist_field)) {
4115 ret = PTR_ERR(hist_field);
Tom Zanussif2606832016-03-03 12:54:43 -06004116 goto out;
4117 }
4118
Tom Zanussi100719d2018-01-15 20:51:52 -06004119 hist_data->fields[val_idx] = hist_field;
4120
Tom Zanussif2606832016-03-03 12:54:43 -06004121 ++hist_data->n_vals;
Tom Zanussi30350d62018-01-15 20:51:49 -06004122 ++hist_data->n_fields;
Tom Zanussif2606832016-03-03 12:54:43 -06004123
Tom Zanussi30350d62018-01-15 20:51:49 -06004124 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX + TRACING_MAP_VARS_MAX))
Tom Zanussif2606832016-03-03 12:54:43 -06004125 ret = -EINVAL;
4126 out:
4127 return ret;
4128}
4129
Tom Zanussi30350d62018-01-15 20:51:49 -06004130static int create_val_field(struct hist_trigger_data *hist_data,
4131 unsigned int val_idx,
4132 struct trace_event_file *file,
4133 char *field_str)
4134{
4135 if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX))
4136 return -EINVAL;
4137
4138 return __create_val_field(hist_data, val_idx, file, NULL, field_str, 0);
4139}
4140
Steven Rostedt (VMware)ed2cf902021-07-22 10:27:07 -04004141static const char *no_comm = "(no comm)";
4142
4143static u64 hist_field_execname(struct hist_field *hist_field,
4144 struct tracing_map_elt *elt,
4145 struct trace_buffer *buffer,
4146 struct ring_buffer_event *rbe,
4147 void *event)
4148{
4149 struct hist_elt_data *elt_data;
4150
4151 if (WARN_ON_ONCE(!elt))
4152 return (u64)(unsigned long)no_comm;
4153
4154 elt_data = elt->private_data;
4155
4156 if (WARN_ON_ONCE(!elt_data->comm))
4157 return (u64)(unsigned long)no_comm;
4158
4159 return (u64)(unsigned long)(elt_data->comm);
4160}
4161
4162/* Convert a var that points to common_pid.execname to a string */
4163static void update_var_execname(struct hist_field *hist_field)
4164{
4165 hist_field->flags = HIST_FIELD_FL_STRING | HIST_FIELD_FL_VAR |
4166 HIST_FIELD_FL_EXECNAME;
4167 hist_field->size = MAX_FILTER_STR_VAL;
4168 hist_field->is_signed = 0;
4169
4170 kfree_const(hist_field->type);
4171 hist_field->type = "char[]";
4172
4173 hist_field->fn = hist_field_execname;
4174}
4175
Tom Zanussi30350d62018-01-15 20:51:49 -06004176static int create_var_field(struct hist_trigger_data *hist_data,
4177 unsigned int val_idx,
4178 struct trace_event_file *file,
4179 char *var_name, char *expr_str)
4180{
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004181 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussi30350d62018-01-15 20:51:49 -06004182 unsigned long flags = 0;
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004183 int ret;
Tom Zanussi30350d62018-01-15 20:51:49 -06004184
4185 if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX + TRACING_MAP_VARS_MAX))
4186 return -EINVAL;
Tom Zanussif404da62018-01-15 20:52:05 -06004187
Tom Zanussi30350d62018-01-15 20:51:49 -06004188 if (find_var(hist_data, file, var_name) && !hist_data->remove) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004189 hist_err(tr, HIST_ERR_DUPLICATE_VAR, errpos(var_name));
Tom Zanussi30350d62018-01-15 20:51:49 -06004190 return -EINVAL;
4191 }
4192
4193 flags |= HIST_FIELD_FL_VAR;
4194 hist_data->n_vars++;
4195 if (WARN_ON(hist_data->n_vars > TRACING_MAP_VARS_MAX))
4196 return -EINVAL;
4197
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004198 ret = __create_val_field(hist_data, val_idx, file, var_name, expr_str, flags);
4199
Steven Rostedt (VMware)ed2cf902021-07-22 10:27:07 -04004200 if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_EXECNAME)
4201 update_var_execname(hist_data->fields[val_idx]);
4202
Steven Rostedt (VMware)6d9bd132020-10-13 15:48:52 -04004203 if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_STRING)
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004204 hist_data->fields[val_idx]->var_str_idx = hist_data->n_var_str++;
4205
4206 return ret;
Tom Zanussi30350d62018-01-15 20:51:49 -06004207}
4208
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004209static int create_val_fields(struct hist_trigger_data *hist_data,
4210 struct trace_event_file *file)
4211{
Tom Zanussif2606832016-03-03 12:54:43 -06004212 char *fields_str, *field_str;
Tom Zanussi30350d62018-01-15 20:51:49 -06004213 unsigned int i, j = 1;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004214 int ret;
4215
4216 ret = create_hitcount_val(hist_data);
Tom Zanussif2606832016-03-03 12:54:43 -06004217 if (ret)
4218 goto out;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004219
Tom Zanussif2606832016-03-03 12:54:43 -06004220 fields_str = hist_data->attrs->vals_str;
4221 if (!fields_str)
4222 goto out;
4223
Tom Zanussif2606832016-03-03 12:54:43 -06004224 for (i = 0, j = 1; i < TRACING_MAP_VALS_MAX &&
4225 j < TRACING_MAP_VALS_MAX; i++) {
4226 field_str = strsep(&fields_str, ",");
4227 if (!field_str)
4228 break;
Tom Zanussi30350d62018-01-15 20:51:49 -06004229
Tom Zanussif2606832016-03-03 12:54:43 -06004230 if (strcmp(field_str, "hitcount") == 0)
4231 continue;
Tom Zanussi30350d62018-01-15 20:51:49 -06004232
Tom Zanussif2606832016-03-03 12:54:43 -06004233 ret = create_val_field(hist_data, j++, file, field_str);
4234 if (ret)
4235 goto out;
4236 }
Tom Zanussi30350d62018-01-15 20:51:49 -06004237
Tom Zanussif2606832016-03-03 12:54:43 -06004238 if (fields_str && (strcmp(fields_str, "hitcount") != 0))
4239 ret = -EINVAL;
4240 out:
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004241 return ret;
4242}
4243
4244static int create_key_field(struct hist_trigger_data *hist_data,
4245 unsigned int key_idx,
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004246 unsigned int key_offset,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004247 struct trace_event_file *file,
4248 char *field_str)
4249{
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004250 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussi30350d62018-01-15 20:51:49 -06004251 struct hist_field *hist_field = NULL;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004252 unsigned long flags = 0;
4253 unsigned int key_size;
Kalesh Singh9710b2f2021-10-25 13:08:35 -07004254 int ret = 0, n_subexprs = 0;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004255
Tom Zanussi30350d62018-01-15 20:51:49 -06004256 if (WARN_ON(key_idx >= HIST_FIELDS_MAX))
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004257 return -EINVAL;
4258
4259 flags |= HIST_FIELD_FL_KEY;
4260
Tom Zanussi69a02002016-03-03 12:54:52 -06004261 if (strcmp(field_str, "stacktrace") == 0) {
4262 flags |= HIST_FIELD_FL_STACKTRACE;
4263 key_size = sizeof(unsigned long) * HIST_STACKTRACE_DEPTH;
Tom Zanussi30350d62018-01-15 20:51:49 -06004264 hist_field = create_hist_field(hist_data, NULL, flags, NULL);
Tom Zanussi69a02002016-03-03 12:54:52 -06004265 } else {
Tom Zanussi100719d2018-01-15 20:51:52 -06004266 hist_field = parse_expr(hist_data, file, field_str, flags,
Kalesh Singh9710b2f2021-10-25 13:08:35 -07004267 NULL, &n_subexprs);
Tom Zanussi100719d2018-01-15 20:51:52 -06004268 if (IS_ERR(hist_field)) {
4269 ret = PTR_ERR(hist_field);
4270 goto out;
Tom Zanussi69a02002016-03-03 12:54:52 -06004271 }
4272
Tom Zanussic8d94a12019-04-18 10:18:51 -05004273 if (field_has_hist_vars(hist_field, 0)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004274 hist_err(tr, HIST_ERR_INVALID_REF_KEY, errpos(field_str));
Tom Zanussi067fe032018-01-15 20:51:56 -06004275 destroy_hist_field(hist_field, 0);
4276 ret = -EINVAL;
4277 goto out;
4278 }
4279
Tom Zanussi100719d2018-01-15 20:51:52 -06004280 key_size = hist_field->size;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004281 }
4282
Tom Zanussi100719d2018-01-15 20:51:52 -06004283 hist_data->fields[key_idx] = hist_field;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004284
4285 key_size = ALIGN(key_size, sizeof(u64));
4286 hist_data->fields[key_idx]->size = key_size;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004287 hist_data->fields[key_idx]->offset = key_offset;
Tom Zanussi100719d2018-01-15 20:51:52 -06004288
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004289 hist_data->key_size += key_size;
Tom Zanussi100719d2018-01-15 20:51:52 -06004290
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004291 if (hist_data->key_size > HIST_KEY_SIZE_MAX) {
4292 ret = -EINVAL;
4293 goto out;
4294 }
4295
4296 hist_data->n_keys++;
Tom Zanussi30350d62018-01-15 20:51:49 -06004297 hist_data->n_fields++;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004298
4299 if (WARN_ON(hist_data->n_keys > TRACING_MAP_KEYS_MAX))
4300 return -EINVAL;
4301
4302 ret = key_size;
4303 out:
4304 return ret;
4305}
4306
4307static int create_key_fields(struct hist_trigger_data *hist_data,
4308 struct trace_event_file *file)
4309{
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004310 unsigned int i, key_offset = 0, n_vals = hist_data->n_vals;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004311 char *fields_str, *field_str;
4312 int ret = -EINVAL;
4313
4314 fields_str = hist_data->attrs->keys_str;
4315 if (!fields_str)
4316 goto out;
4317
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004318 for (i = n_vals; i < n_vals + TRACING_MAP_KEYS_MAX; i++) {
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004319 field_str = strsep(&fields_str, ",");
4320 if (!field_str)
4321 break;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004322 ret = create_key_field(hist_data, i, key_offset,
4323 file, field_str);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004324 if (ret < 0)
4325 goto out;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004326 key_offset += ret;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004327 }
4328 if (fields_str) {
4329 ret = -EINVAL;
4330 goto out;
4331 }
4332 ret = 0;
4333 out:
4334 return ret;
4335}
4336
Tom Zanussi30350d62018-01-15 20:51:49 -06004337static int create_var_fields(struct hist_trigger_data *hist_data,
4338 struct trace_event_file *file)
4339{
4340 unsigned int i, j = hist_data->n_vals;
4341 int ret = 0;
4342
4343 unsigned int n_vars = hist_data->attrs->var_defs.n_vars;
4344
4345 for (i = 0; i < n_vars; i++) {
4346 char *var_name = hist_data->attrs->var_defs.name[i];
4347 char *expr = hist_data->attrs->var_defs.expr[i];
4348
4349 ret = create_var_field(hist_data, j++, file, var_name, expr);
4350 if (ret)
4351 goto out;
4352 }
4353 out:
4354 return ret;
4355}
4356
4357static void free_var_defs(struct hist_trigger_data *hist_data)
4358{
4359 unsigned int i;
4360
4361 for (i = 0; i < hist_data->attrs->var_defs.n_vars; i++) {
4362 kfree(hist_data->attrs->var_defs.name[i]);
4363 kfree(hist_data->attrs->var_defs.expr[i]);
4364 }
4365
4366 hist_data->attrs->var_defs.n_vars = 0;
4367}
4368
4369static int parse_var_defs(struct hist_trigger_data *hist_data)
4370{
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004371 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussi30350d62018-01-15 20:51:49 -06004372 char *s, *str, *var_name, *field_str;
4373 unsigned int i, j, n_vars = 0;
4374 int ret = 0;
4375
4376 for (i = 0; i < hist_data->attrs->n_assignments; i++) {
4377 str = hist_data->attrs->assignment_str[i];
4378 for (j = 0; j < TRACING_MAP_VARS_MAX; j++) {
4379 field_str = strsep(&str, ",");
4380 if (!field_str)
4381 break;
4382
4383 var_name = strsep(&field_str, "=");
4384 if (!var_name || !field_str) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004385 hist_err(tr, HIST_ERR_MALFORMED_ASSIGNMENT,
4386 errpos(var_name));
Tom Zanussi30350d62018-01-15 20:51:49 -06004387 ret = -EINVAL;
4388 goto free;
4389 }
4390
4391 if (n_vars == TRACING_MAP_VARS_MAX) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04004392 hist_err(tr, HIST_ERR_TOO_MANY_VARS, errpos(var_name));
Tom Zanussi30350d62018-01-15 20:51:49 -06004393 ret = -EINVAL;
4394 goto free;
4395 }
4396
4397 s = kstrdup(var_name, GFP_KERNEL);
4398 if (!s) {
4399 ret = -ENOMEM;
4400 goto free;
4401 }
4402 hist_data->attrs->var_defs.name[n_vars] = s;
4403
4404 s = kstrdup(field_str, GFP_KERNEL);
4405 if (!s) {
Tom Zanussi30350d62018-01-15 20:51:49 -06004406 ret = -ENOMEM;
4407 goto free;
4408 }
4409 hist_data->attrs->var_defs.expr[n_vars++] = s;
4410
4411 hist_data->attrs->var_defs.n_vars = n_vars;
4412 }
4413 }
4414
4415 return ret;
4416 free:
4417 free_var_defs(hist_data);
4418
4419 return ret;
4420}
4421
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004422static int create_hist_fields(struct hist_trigger_data *hist_data,
4423 struct trace_event_file *file)
4424{
4425 int ret;
4426
Tom Zanussi30350d62018-01-15 20:51:49 -06004427 ret = parse_var_defs(hist_data);
4428 if (ret)
4429 goto out;
4430
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004431 ret = create_val_fields(hist_data, file);
4432 if (ret)
4433 goto out;
4434
Tom Zanussi30350d62018-01-15 20:51:49 -06004435 ret = create_var_fields(hist_data, file);
4436 if (ret)
4437 goto out;
4438
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004439 ret = create_key_fields(hist_data, file);
4440 if (ret)
4441 goto out;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004442 out:
Tom Zanussi30350d62018-01-15 20:51:49 -06004443 free_var_defs(hist_data);
4444
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004445 return ret;
4446}
4447
Tom Zanussi4de26c82019-06-28 12:40:21 -05004448static int is_descending(struct trace_array *tr, const char *str)
Tom Zanussie62347d2016-03-03 12:54:45 -06004449{
4450 if (!str)
4451 return 0;
4452
4453 if (strcmp(str, "descending") == 0)
4454 return 1;
4455
4456 if (strcmp(str, "ascending") == 0)
4457 return 0;
4458
Tom Zanussi4de26c82019-06-28 12:40:21 -05004459 hist_err(tr, HIST_ERR_INVALID_SORT_MODIFIER, errpos((char *)str));
4460
Tom Zanussie62347d2016-03-03 12:54:45 -06004461 return -EINVAL;
4462}
4463
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004464static int create_sort_keys(struct hist_trigger_data *hist_data)
4465{
Tom Zanussi4de26c82019-06-28 12:40:21 -05004466 struct trace_array *tr = hist_data->event_file->tr;
Tom Zanussie62347d2016-03-03 12:54:45 -06004467 char *fields_str = hist_data->attrs->sort_key_str;
Tom Zanussie62347d2016-03-03 12:54:45 -06004468 struct tracing_map_sort_key *sort_key;
4469 int descending, ret = 0;
Tom Zanussi30350d62018-01-15 20:51:49 -06004470 unsigned int i, j, k;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004471
Tom Zanussie62347d2016-03-03 12:54:45 -06004472 hist_data->n_sort_keys = 1; /* we always have at least one, hitcount */
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004473
Tom Zanussie62347d2016-03-03 12:54:45 -06004474 if (!fields_str)
4475 goto out;
4476
Tom Zanussie62347d2016-03-03 12:54:45 -06004477 for (i = 0; i < TRACING_MAP_SORT_KEYS_MAX; i++) {
Tom Zanussi85013252017-09-22 14:58:22 -05004478 struct hist_field *hist_field;
Tom Zanussie62347d2016-03-03 12:54:45 -06004479 char *field_str, *field_name;
Tom Zanussi85013252017-09-22 14:58:22 -05004480 const char *test_name;
Tom Zanussie62347d2016-03-03 12:54:45 -06004481
4482 sort_key = &hist_data->sort_keys[i];
4483
4484 field_str = strsep(&fields_str, ",");
Tom Zanussib527b632019-06-28 12:40:20 -05004485 if (!field_str)
4486 break;
4487
4488 if (!*field_str) {
4489 ret = -EINVAL;
Tom Zanussi4de26c82019-06-28 12:40:21 -05004490 hist_err(tr, HIST_ERR_EMPTY_SORT_FIELD, errpos("sort="));
Tom Zanussie62347d2016-03-03 12:54:45 -06004491 break;
4492 }
4493
4494 if ((i == TRACING_MAP_SORT_KEYS_MAX - 1) && fields_str) {
Tom Zanussi4de26c82019-06-28 12:40:21 -05004495 hist_err(tr, HIST_ERR_TOO_MANY_SORT_FIELDS, errpos("sort="));
Tom Zanussie62347d2016-03-03 12:54:45 -06004496 ret = -EINVAL;
4497 break;
4498 }
4499
4500 field_name = strsep(&field_str, ".");
Tom Zanussib527b632019-06-28 12:40:20 -05004501 if (!field_name || !*field_name) {
Tom Zanussie62347d2016-03-03 12:54:45 -06004502 ret = -EINVAL;
Tom Zanussi4de26c82019-06-28 12:40:21 -05004503 hist_err(tr, HIST_ERR_EMPTY_SORT_FIELD, errpos("sort="));
Tom Zanussie62347d2016-03-03 12:54:45 -06004504 break;
4505 }
4506
4507 if (strcmp(field_name, "hitcount") == 0) {
Tom Zanussi4de26c82019-06-28 12:40:21 -05004508 descending = is_descending(tr, field_str);
Tom Zanussie62347d2016-03-03 12:54:45 -06004509 if (descending < 0) {
4510 ret = descending;
4511 break;
4512 }
4513 sort_key->descending = descending;
4514 continue;
4515 }
4516
Tom Zanussi30350d62018-01-15 20:51:49 -06004517 for (j = 1, k = 1; j < hist_data->n_fields; j++) {
4518 unsigned int idx;
4519
Tom Zanussi85013252017-09-22 14:58:22 -05004520 hist_field = hist_data->fields[j];
Tom Zanussi30350d62018-01-15 20:51:49 -06004521 if (hist_field->flags & HIST_FIELD_FL_VAR)
4522 continue;
4523
4524 idx = k++;
4525
Tom Zanussi85013252017-09-22 14:58:22 -05004526 test_name = hist_field_name(hist_field, 0);
4527
4528 if (strcmp(field_name, test_name) == 0) {
Tom Zanussi30350d62018-01-15 20:51:49 -06004529 sort_key->field_idx = idx;
Tom Zanussi4de26c82019-06-28 12:40:21 -05004530 descending = is_descending(tr, field_str);
Tom Zanussie62347d2016-03-03 12:54:45 -06004531 if (descending < 0) {
4532 ret = descending;
4533 goto out;
4534 }
4535 sort_key->descending = descending;
4536 break;
4537 }
4538 }
4539 if (j == hist_data->n_fields) {
4540 ret = -EINVAL;
Tom Zanussi4de26c82019-06-28 12:40:21 -05004541 hist_err(tr, HIST_ERR_INVALID_SORT_FIELD, errpos(field_name));
Tom Zanussie62347d2016-03-03 12:54:45 -06004542 break;
4543 }
4544 }
Tom Zanussi30350d62018-01-15 20:51:49 -06004545
Tom Zanussie62347d2016-03-03 12:54:45 -06004546 hist_data->n_sort_keys = i;
4547 out:
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004548 return ret;
4549}
4550
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004551static void destroy_actions(struct hist_trigger_data *hist_data)
4552{
4553 unsigned int i;
4554
4555 for (i = 0; i < hist_data->n_actions; i++) {
4556 struct action_data *data = hist_data->actions[i];
4557
Tom Zanussi7d18a102019-02-13 17:42:41 -06004558 if (data->handler == HANDLER_ONMATCH)
Tom Zanussic282a382018-01-15 20:52:00 -06004559 onmatch_destroy(data);
Tom Zanussidff81f52019-02-13 17:42:48 -06004560 else if (data->handler == HANDLER_ONMAX ||
4561 data->handler == HANDLER_ONCHANGE)
Tom Zanussi466f4522019-02-13 17:42:44 -06004562 track_data_destroy(hist_data, data);
Tom Zanussic282a382018-01-15 20:52:00 -06004563 else
4564 kfree(data);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004565 }
4566}
4567
4568static int parse_actions(struct hist_trigger_data *hist_data)
4569{
Tom Zanussic282a382018-01-15 20:52:00 -06004570 struct trace_array *tr = hist_data->event_file->tr;
4571 struct action_data *data;
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004572 unsigned int i;
4573 int ret = 0;
4574 char *str;
Steven Rostedt (VMware)036876f2018-12-21 18:40:46 -05004575 int len;
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004576
4577 for (i = 0; i < hist_data->attrs->n_actions; i++) {
4578 str = hist_data->attrs->action_str[i];
Tom Zanussic282a382018-01-15 20:52:00 -06004579
Steven Rostedt (VMware)036876f2018-12-21 18:40:46 -05004580 if ((len = str_has_prefix(str, "onmatch("))) {
4581 char *action_str = str + len;
Tom Zanussic282a382018-01-15 20:52:00 -06004582
4583 data = onmatch_parse(tr, action_str);
4584 if (IS_ERR(data)) {
4585 ret = PTR_ERR(data);
4586 break;
4587 }
Steven Rostedt (VMware)036876f2018-12-21 18:40:46 -05004588 } else if ((len = str_has_prefix(str, "onmax("))) {
4589 char *action_str = str + len;
Tom Zanussi50450602018-01-15 20:52:01 -06004590
Tom Zanussi466f4522019-02-13 17:42:44 -06004591 data = track_data_parse(hist_data, action_str,
4592 HANDLER_ONMAX);
Tom Zanussi50450602018-01-15 20:52:01 -06004593 if (IS_ERR(data)) {
4594 ret = PTR_ERR(data);
4595 break;
4596 }
Tom Zanussidff81f52019-02-13 17:42:48 -06004597 } else if ((len = str_has_prefix(str, "onchange("))) {
4598 char *action_str = str + len;
4599
4600 data = track_data_parse(hist_data, action_str,
4601 HANDLER_ONCHANGE);
4602 if (IS_ERR(data)) {
4603 ret = PTR_ERR(data);
4604 break;
4605 }
Tom Zanussic282a382018-01-15 20:52:00 -06004606 } else {
4607 ret = -EINVAL;
4608 break;
4609 }
4610
4611 hist_data->actions[hist_data->n_actions++] = data;
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004612 }
4613
4614 return ret;
4615}
4616
Tom Zanussi7d18a102019-02-13 17:42:41 -06004617static int create_actions(struct hist_trigger_data *hist_data)
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004618{
4619 struct action_data *data;
4620 unsigned int i;
4621 int ret = 0;
4622
4623 for (i = 0; i < hist_data->attrs->n_actions; i++) {
4624 data = hist_data->actions[i];
Tom Zanussic282a382018-01-15 20:52:00 -06004625
Tom Zanussi7d18a102019-02-13 17:42:41 -06004626 if (data->handler == HANDLER_ONMATCH) {
4627 ret = onmatch_create(hist_data, data);
Tom Zanussic282a382018-01-15 20:52:00 -06004628 if (ret)
Tom Zanussi7d18a102019-02-13 17:42:41 -06004629 break;
Tom Zanussidff81f52019-02-13 17:42:48 -06004630 } else if (data->handler == HANDLER_ONMAX ||
4631 data->handler == HANDLER_ONCHANGE) {
Tom Zanussi466f4522019-02-13 17:42:44 -06004632 ret = track_data_create(hist_data, data);
Tom Zanussi50450602018-01-15 20:52:01 -06004633 if (ret)
Tom Zanussi7d18a102019-02-13 17:42:41 -06004634 break;
4635 } else {
4636 ret = -EINVAL;
4637 break;
Tom Zanussic282a382018-01-15 20:52:00 -06004638 }
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004639 }
4640
4641 return ret;
4642}
4643
Tom Zanussi50450602018-01-15 20:52:01 -06004644static void print_actions(struct seq_file *m,
4645 struct hist_trigger_data *hist_data,
4646 struct tracing_map_elt *elt)
4647{
4648 unsigned int i;
4649
4650 for (i = 0; i < hist_data->n_actions; i++) {
4651 struct action_data *data = hist_data->actions[i];
4652
Tom Zanussia3785b72019-02-13 17:42:46 -06004653 if (data->action == ACTION_SNAPSHOT)
4654 continue;
4655
Tom Zanussidff81f52019-02-13 17:42:48 -06004656 if (data->handler == HANDLER_ONMAX ||
4657 data->handler == HANDLER_ONCHANGE)
Tom Zanussi466f4522019-02-13 17:42:44 -06004658 track_data_print(m, hist_data, elt, data);
Tom Zanussi50450602018-01-15 20:52:01 -06004659 }
4660}
4661
Tom Zanussi7d18a102019-02-13 17:42:41 -06004662static void print_action_spec(struct seq_file *m,
4663 struct hist_trigger_data *hist_data,
4664 struct action_data *data)
4665{
4666 unsigned int i;
4667
4668 if (data->action == ACTION_SAVE) {
4669 for (i = 0; i < hist_data->n_save_vars; i++) {
4670 seq_printf(m, "%s", hist_data->save_vars[i]->var->var.name);
4671 if (i < hist_data->n_save_vars - 1)
4672 seq_puts(m, ",");
4673 }
4674 } else if (data->action == ACTION_TRACE) {
Tom Zanussie91eefd72019-02-13 17:42:50 -06004675 if (data->use_trace_keyword)
4676 seq_printf(m, "%s", data->synth_event_name);
Tom Zanussi7d18a102019-02-13 17:42:41 -06004677 for (i = 0; i < data->n_params; i++) {
Tom Zanussie91eefd72019-02-13 17:42:50 -06004678 if (i || data->use_trace_keyword)
Tom Zanussi7d18a102019-02-13 17:42:41 -06004679 seq_puts(m, ",");
4680 seq_printf(m, "%s", data->params[i]);
4681 }
4682 }
4683}
4684
Tom Zanussi466f4522019-02-13 17:42:44 -06004685static void print_track_data_spec(struct seq_file *m,
4686 struct hist_trigger_data *hist_data,
4687 struct action_data *data)
Tom Zanussi50450602018-01-15 20:52:01 -06004688{
Tom Zanussi466f4522019-02-13 17:42:44 -06004689 if (data->handler == HANDLER_ONMAX)
4690 seq_puts(m, ":onmax(");
Tom Zanussidff81f52019-02-13 17:42:48 -06004691 else if (data->handler == HANDLER_ONCHANGE)
4692 seq_puts(m, ":onchange(");
Tom Zanussi466f4522019-02-13 17:42:44 -06004693 seq_printf(m, "%s", data->track_data.var_str);
Tom Zanussi7d18a102019-02-13 17:42:41 -06004694 seq_printf(m, ").%s(", data->action_name);
Tom Zanussi50450602018-01-15 20:52:01 -06004695
Tom Zanussi7d18a102019-02-13 17:42:41 -06004696 print_action_spec(m, hist_data, data);
4697
Tom Zanussi50450602018-01-15 20:52:01 -06004698 seq_puts(m, ")");
4699}
4700
Tom Zanussic282a382018-01-15 20:52:00 -06004701static void print_onmatch_spec(struct seq_file *m,
4702 struct hist_trigger_data *hist_data,
4703 struct action_data *data)
4704{
Tom Zanussic3e49502019-02-13 17:42:43 -06004705 seq_printf(m, ":onmatch(%s.%s).", data->match_data.event_system,
4706 data->match_data.event);
Tom Zanussic282a382018-01-15 20:52:00 -06004707
Tom Zanussi7d18a102019-02-13 17:42:41 -06004708 seq_printf(m, "%s(", data->action_name);
Tom Zanussic282a382018-01-15 20:52:00 -06004709
Tom Zanussi7d18a102019-02-13 17:42:41 -06004710 print_action_spec(m, hist_data, data);
Tom Zanussic282a382018-01-15 20:52:00 -06004711
4712 seq_puts(m, ")");
4713}
4714
Tom Zanussi48f79472018-03-28 15:10:55 -05004715static bool actions_match(struct hist_trigger_data *hist_data,
4716 struct hist_trigger_data *hist_data_test)
4717{
4718 unsigned int i, j;
4719
4720 if (hist_data->n_actions != hist_data_test->n_actions)
4721 return false;
4722
4723 for (i = 0; i < hist_data->n_actions; i++) {
4724 struct action_data *data = hist_data->actions[i];
4725 struct action_data *data_test = hist_data_test->actions[i];
Tom Zanussie91eefd72019-02-13 17:42:50 -06004726 char *action_name, *action_name_test;
Tom Zanussi48f79472018-03-28 15:10:55 -05004727
Tom Zanussi7d18a102019-02-13 17:42:41 -06004728 if (data->handler != data_test->handler)
4729 return false;
4730 if (data->action != data_test->action)
Tom Zanussi48f79472018-03-28 15:10:55 -05004731 return false;
4732
4733 if (data->n_params != data_test->n_params)
4734 return false;
4735
4736 for (j = 0; j < data->n_params; j++) {
4737 if (strcmp(data->params[j], data_test->params[j]) != 0)
4738 return false;
4739 }
4740
Tom Zanussie91eefd72019-02-13 17:42:50 -06004741 if (data->use_trace_keyword)
4742 action_name = data->synth_event_name;
4743 else
4744 action_name = data->action_name;
4745
4746 if (data_test->use_trace_keyword)
4747 action_name_test = data_test->synth_event_name;
4748 else
4749 action_name_test = data_test->action_name;
4750
4751 if (strcmp(action_name, action_name_test) != 0)
Tom Zanussi7d18a102019-02-13 17:42:41 -06004752 return false;
4753
4754 if (data->handler == HANDLER_ONMATCH) {
Tom Zanussic3e49502019-02-13 17:42:43 -06004755 if (strcmp(data->match_data.event_system,
4756 data_test->match_data.event_system) != 0)
Tom Zanussi48f79472018-03-28 15:10:55 -05004757 return false;
Tom Zanussic3e49502019-02-13 17:42:43 -06004758 if (strcmp(data->match_data.event,
4759 data_test->match_data.event) != 0)
Tom Zanussi48f79472018-03-28 15:10:55 -05004760 return false;
Tom Zanussidff81f52019-02-13 17:42:48 -06004761 } else if (data->handler == HANDLER_ONMAX ||
4762 data->handler == HANDLER_ONCHANGE) {
Tom Zanussi466f4522019-02-13 17:42:44 -06004763 if (strcmp(data->track_data.var_str,
4764 data_test->track_data.var_str) != 0)
Tom Zanussi48f79472018-03-28 15:10:55 -05004765 return false;
Tom Zanussi48f79472018-03-28 15:10:55 -05004766 }
4767 }
4768
4769 return true;
4770}
4771
4772
Tom Zanussic282a382018-01-15 20:52:00 -06004773static void print_actions_spec(struct seq_file *m,
4774 struct hist_trigger_data *hist_data)
4775{
4776 unsigned int i;
4777
4778 for (i = 0; i < hist_data->n_actions; i++) {
4779 struct action_data *data = hist_data->actions[i];
4780
Tom Zanussi7d18a102019-02-13 17:42:41 -06004781 if (data->handler == HANDLER_ONMATCH)
Tom Zanussic282a382018-01-15 20:52:00 -06004782 print_onmatch_spec(m, hist_data, data);
Tom Zanussidff81f52019-02-13 17:42:48 -06004783 else if (data->handler == HANDLER_ONMAX ||
4784 data->handler == HANDLER_ONCHANGE)
Tom Zanussi466f4522019-02-13 17:42:44 -06004785 print_track_data_spec(m, hist_data, data);
Tom Zanussic282a382018-01-15 20:52:00 -06004786 }
4787}
4788
Tom Zanussi02205a62018-01-15 20:51:59 -06004789static void destroy_field_var_hists(struct hist_trigger_data *hist_data)
4790{
4791 unsigned int i;
4792
4793 for (i = 0; i < hist_data->n_field_var_hists; i++) {
4794 kfree(hist_data->field_var_hists[i]->cmd);
4795 kfree(hist_data->field_var_hists[i]);
4796 }
4797}
4798
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004799static void destroy_hist_data(struct hist_trigger_data *hist_data)
4800{
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004801 if (!hist_data)
4802 return;
4803
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004804 destroy_hist_trigger_attrs(hist_data->attrs);
4805 destroy_hist_fields(hist_data);
4806 tracing_map_destroy(hist_data->map);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004807
4808 destroy_actions(hist_data);
Tom Zanussi02205a62018-01-15 20:51:59 -06004809 destroy_field_vars(hist_data);
4810 destroy_field_var_hists(hist_data);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004811
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004812 kfree(hist_data);
4813}
4814
4815static int create_tracing_map_fields(struct hist_trigger_data *hist_data)
4816{
4817 struct tracing_map *map = hist_data->map;
4818 struct ftrace_event_field *field;
4819 struct hist_field *hist_field;
Dan Carpenterb28d7b22018-03-28 14:48:15 +03004820 int i, idx = 0;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004821
4822 for_each_hist_field(i, hist_data) {
4823 hist_field = hist_data->fields[i];
4824 if (hist_field->flags & HIST_FIELD_FL_KEY) {
4825 tracing_map_cmp_fn_t cmp_fn;
4826
4827 field = hist_field->field;
4828
Tom Zanussi69a02002016-03-03 12:54:52 -06004829 if (hist_field->flags & HIST_FIELD_FL_STACKTRACE)
4830 cmp_fn = tracing_map_cmp_none;
Tom Zanussiad42feb2018-01-15 20:51:45 -06004831 else if (!field)
4832 cmp_fn = tracing_map_cmp_num(hist_field->size,
4833 hist_field->is_signed);
Tom Zanussi69a02002016-03-03 12:54:52 -06004834 else if (is_string_field(field))
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004835 cmp_fn = tracing_map_cmp_string;
4836 else
4837 cmp_fn = tracing_map_cmp_num(field->size,
4838 field->is_signed);
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06004839 idx = tracing_map_add_key_field(map,
4840 hist_field->offset,
4841 cmp_fn);
Tom Zanussi30350d62018-01-15 20:51:49 -06004842 } else if (!(hist_field->flags & HIST_FIELD_FL_VAR))
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004843 idx = tracing_map_add_sum_field(map);
4844
4845 if (idx < 0)
4846 return idx;
Tom Zanussi30350d62018-01-15 20:51:49 -06004847
4848 if (hist_field->flags & HIST_FIELD_FL_VAR) {
4849 idx = tracing_map_add_var(map);
4850 if (idx < 0)
4851 return idx;
4852 hist_field->var.idx = idx;
4853 hist_field->var.hist_data = hist_data;
4854 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004855 }
4856
4857 return 0;
4858}
4859
4860static struct hist_trigger_data *
4861create_hist_data(unsigned int map_bits,
4862 struct hist_trigger_attrs *attrs,
Tom Zanussi30350d62018-01-15 20:51:49 -06004863 struct trace_event_file *file,
4864 bool remove)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004865{
Tom Zanussi6b4827a2016-03-03 12:54:50 -06004866 const struct tracing_map_ops *map_ops = NULL;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004867 struct hist_trigger_data *hist_data;
4868 int ret = 0;
4869
4870 hist_data = kzalloc(sizeof(*hist_data), GFP_KERNEL);
4871 if (!hist_data)
4872 return ERR_PTR(-ENOMEM);
4873
4874 hist_data->attrs = attrs;
Tom Zanussi30350d62018-01-15 20:51:49 -06004875 hist_data->remove = remove;
Tom Zanussi067fe032018-01-15 20:51:56 -06004876 hist_data->event_file = file;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004877
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004878 ret = parse_actions(hist_data);
4879 if (ret)
4880 goto free;
4881
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004882 ret = create_hist_fields(hist_data, file);
4883 if (ret)
4884 goto free;
4885
4886 ret = create_sort_keys(hist_data);
4887 if (ret)
4888 goto free;
4889
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06004890 map_ops = &hist_trigger_elt_data_ops;
Tom Zanussi6b4827a2016-03-03 12:54:50 -06004891
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004892 hist_data->map = tracing_map_create(map_bits, hist_data->key_size,
Tom Zanussi6b4827a2016-03-03 12:54:50 -06004893 map_ops, hist_data);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004894 if (IS_ERR(hist_data->map)) {
4895 ret = PTR_ERR(hist_data->map);
4896 hist_data->map = NULL;
4897 goto free;
4898 }
4899
4900 ret = create_tracing_map_fields(hist_data);
4901 if (ret)
4902 goto free;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004903 out:
4904 return hist_data;
4905 free:
4906 hist_data->attrs = NULL;
4907
4908 destroy_hist_data(hist_data);
4909
4910 hist_data = ERR_PTR(ret);
4911
4912 goto out;
4913}
4914
4915static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04004916 struct tracing_map_elt *elt,
4917 struct trace_buffer *buffer, void *rec,
Tom Zanussi067fe032018-01-15 20:51:56 -06004918 struct ring_buffer_event *rbe,
4919 u64 *var_ref_vals)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004920{
Tom Zanussi067fe032018-01-15 20:51:56 -06004921 struct hist_elt_data *elt_data;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004922 struct hist_field *hist_field;
Tom Zanussi30350d62018-01-15 20:51:49 -06004923 unsigned int i, var_idx;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004924 u64 hist_val;
4925
Tom Zanussi067fe032018-01-15 20:51:56 -06004926 elt_data = elt->private_data;
4927 elt_data->var_ref_vals = var_ref_vals;
4928
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004929 for_each_hist_val_field(i, hist_data) {
4930 hist_field = hist_data->fields[i];
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04004931 hist_val = hist_field->fn(hist_field, elt, buffer, rbe, rec);
Tom Zanussi30350d62018-01-15 20:51:49 -06004932 if (hist_field->flags & HIST_FIELD_FL_VAR) {
4933 var_idx = hist_field->var.idx;
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004934
4935 if (hist_field->flags & HIST_FIELD_FL_STRING) {
4936 unsigned int str_start, var_str_idx, idx;
4937 char *str, *val_str;
Steven Rostedt (VMware)938aa332021-11-14 13:28:34 -05004938 unsigned int size;
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004939
4940 str_start = hist_data->n_field_var_str +
4941 hist_data->n_save_var_str;
4942 var_str_idx = hist_field->var_str_idx;
4943 idx = str_start + var_str_idx;
4944
4945 str = elt_data->field_var_str[idx];
4946 val_str = (char *)(uintptr_t)hist_val;
Steven Rostedt (VMware)938aa332021-11-14 13:28:34 -05004947
4948 size = min(hist_field->size, STR_VAR_LEN_MAX);
4949 strscpy(str, val_str, size);
Tom Zanussi63a1e5d2020-10-04 17:14:05 -05004950
4951 hist_val = (u64)(uintptr_t)str;
4952 }
Tom Zanussi30350d62018-01-15 20:51:49 -06004953 tracing_map_set_var(elt, var_idx, hist_val);
4954 continue;
4955 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004956 tracing_map_update_sum(elt, i, hist_val);
4957 }
Tom Zanussi30350d62018-01-15 20:51:49 -06004958
4959 for_each_hist_key_field(i, hist_data) {
4960 hist_field = hist_data->fields[i];
4961 if (hist_field->flags & HIST_FIELD_FL_VAR) {
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04004962 hist_val = hist_field->fn(hist_field, elt, buffer, rbe, rec);
Tom Zanussi30350d62018-01-15 20:51:49 -06004963 var_idx = hist_field->var.idx;
4964 tracing_map_set_var(elt, var_idx, hist_val);
4965 }
4966 }
Tom Zanussi02205a62018-01-15 20:51:59 -06004967
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04004968 update_field_vars(hist_data, elt, buffer, rbe, rec);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06004969}
4970
Tom Zanussi6a475cb2016-03-03 12:54:54 -06004971static inline void add_to_key(char *compound_key, void *key,
4972 struct hist_field *key_field, void *rec)
4973{
4974 size_t size = key_field->size;
4975
4976 if (key_field->flags & HIST_FIELD_FL_STRING) {
4977 struct ftrace_event_field *field;
4978
4979 field = key_field->field;
Masami Hiramatsu05770dd2021-11-22 18:30:12 +09004980 if (field->filter_type == FILTER_DYN_STRING ||
4981 field->filter_type == FILTER_RDYN_STRING)
Tom Zanussi6a475cb2016-03-03 12:54:54 -06004982 size = *(u32 *)(rec + field->offset) >> 16;
Tom Zanussi6a475cb2016-03-03 12:54:54 -06004983 else if (field->filter_type == FILTER_STATIC_STRING)
4984 size = field->size;
4985
4986 /* ensure NULL-termination */
4987 if (size > key_field->size - 1)
4988 size = key_field->size - 1;
Tom Zanussi6a475cb2016-03-03 12:54:54 -06004989
Tom Zanussi9f0bbf32019-02-04 15:07:24 -06004990 strncpy(compound_key + key_field->offset, (char *)key, size);
4991 } else
4992 memcpy(compound_key + key_field->offset, key, size);
Tom Zanussi6a475cb2016-03-03 12:54:54 -06004993}
4994
Tom Zanussi0212e2a2018-01-15 20:51:57 -06004995static void
4996hist_trigger_actions(struct hist_trigger_data *hist_data,
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04004997 struct tracing_map_elt *elt,
4998 struct trace_buffer *buffer, void *rec,
Tom Zanussi7d18a102019-02-13 17:42:41 -06004999 struct ring_buffer_event *rbe, void *key,
5000 u64 *var_ref_vals)
Tom Zanussi0212e2a2018-01-15 20:51:57 -06005001{
5002 struct action_data *data;
5003 unsigned int i;
5004
5005 for (i = 0; i < hist_data->n_actions; i++) {
5006 data = hist_data->actions[i];
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005007 data->fn(hist_data, elt, buffer, rec, rbe, key, data, var_ref_vals);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06005008 }
5009}
5010
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005011static void event_hist_trigger(struct event_trigger_data *data,
5012 struct trace_buffer *buffer, void *rec,
Tom Zanussifbd302c2018-01-15 20:51:43 -06005013 struct ring_buffer_event *rbe)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005014{
5015 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005016 bool use_compound_key = (hist_data->n_keys > 1);
Tom Zanussi69a02002016-03-03 12:54:52 -06005017 unsigned long entries[HIST_STACKTRACE_DEPTH];
Tom Zanussi067fe032018-01-15 20:51:56 -06005018 u64 var_ref_vals[TRACING_MAP_VARS_MAX];
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005019 char compound_key[HIST_KEY_SIZE_MAX];
Tom Zanussidf35d932018-01-15 20:51:54 -06005020 struct tracing_map_elt *elt = NULL;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005021 struct hist_field *key_field;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005022 u64 field_contents;
5023 void *key = NULL;
5024 unsigned int i;
5025
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005026 memset(compound_key, 0, hist_data->key_size);
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005027
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005028 for_each_hist_key_field(i, hist_data) {
5029 key_field = hist_data->fields[i];
5030
Tom Zanussi69a02002016-03-03 12:54:52 -06005031 if (key_field->flags & HIST_FIELD_FL_STACKTRACE) {
Thomas Gleixnere7d91662019-04-25 11:45:13 +02005032 memset(entries, 0, HIST_STACKTRACE_SIZE);
5033 stack_trace_save(entries, HIST_STACKTRACE_DEPTH,
5034 HIST_STACKTRACE_SKIP);
Tom Zanussi69a02002016-03-03 12:54:52 -06005035 key = entries;
5036 } else {
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005037 field_contents = key_field->fn(key_field, elt, buffer, rbe, rec);
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005038 if (key_field->flags & HIST_FIELD_FL_STRING) {
Tom Zanussi69a02002016-03-03 12:54:52 -06005039 key = (void *)(unsigned long)field_contents;
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005040 use_compound_key = true;
5041 } else
Tom Zanussi69a02002016-03-03 12:54:52 -06005042 key = (void *)&field_contents;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005043 }
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005044
5045 if (use_compound_key)
5046 add_to_key(compound_key, key, key_field, rec);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005047 }
5048
Tom Zanussi6a475cb2016-03-03 12:54:54 -06005049 if (use_compound_key)
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005050 key = compound_key;
5051
Tom Zanussi067fe032018-01-15 20:51:56 -06005052 if (hist_data->n_var_refs &&
5053 !resolve_var_refs(hist_data, key, var_ref_vals, false))
5054 return;
5055
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005056 elt = tracing_map_insert(hist_data->map, key);
Tom Zanussi067fe032018-01-15 20:51:56 -06005057 if (!elt)
5058 return;
5059
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005060 hist_trigger_elt_update(hist_data, elt, buffer, rec, rbe, var_ref_vals);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06005061
5062 if (resolve_var_refs(hist_data, key, var_ref_vals, true))
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04005063 hist_trigger_actions(hist_data, elt, buffer, rec, rbe, key, var_ref_vals);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005064}
5065
Tom Zanussi69a02002016-03-03 12:54:52 -06005066static void hist_trigger_stacktrace_print(struct seq_file *m,
5067 unsigned long *stacktrace_entries,
5068 unsigned int max_entries)
5069{
Tom Zanussi69a02002016-03-03 12:54:52 -06005070 unsigned int spaces = 8;
5071 unsigned int i;
5072
5073 for (i = 0; i < max_entries; i++) {
Thomas Gleixner4285f2f2019-04-10 12:28:10 +02005074 if (!stacktrace_entries[i])
Tom Zanussi69a02002016-03-03 12:54:52 -06005075 return;
5076
5077 seq_printf(m, "%*c", 1 + spaces, ' ');
Arnd Bergmann8720aee2021-10-19 17:33:13 +02005078 seq_printf(m, "%pS\n", (void*)stacktrace_entries[i]);
Tom Zanussi69a02002016-03-03 12:54:52 -06005079 }
5080}
5081
Tom Zanussia3785b72019-02-13 17:42:46 -06005082static void hist_trigger_print_key(struct seq_file *m,
5083 struct hist_trigger_data *hist_data,
5084 void *key,
5085 struct tracing_map_elt *elt)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005086{
5087 struct hist_field *key_field;
Tom Zanussi69a02002016-03-03 12:54:52 -06005088 bool multiline = false;
Tom Zanussi85013252017-09-22 14:58:22 -05005089 const char *field_name;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005090 unsigned int i;
5091 u64 uval;
5092
5093 seq_puts(m, "{ ");
5094
5095 for_each_hist_key_field(i, hist_data) {
5096 key_field = hist_data->fields[i];
5097
5098 if (i > hist_data->n_vals)
5099 seq_puts(m, ", ");
5100
Tom Zanussi85013252017-09-22 14:58:22 -05005101 field_name = hist_field_name(key_field, 0);
5102
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06005103 if (key_field->flags & HIST_FIELD_FL_HEX) {
5104 uval = *(u64 *)(key + key_field->offset);
Tom Zanussi85013252017-09-22 14:58:22 -05005105 seq_printf(m, "%s: %llx", field_name, uval);
Tom Zanussic6afad42016-03-03 12:54:49 -06005106 } else if (key_field->flags & HIST_FIELD_FL_SYM) {
5107 uval = *(u64 *)(key + key_field->offset);
Arnd Bergmann8720aee2021-10-19 17:33:13 +02005108 seq_printf(m, "%s: [%llx] %-45ps", field_name,
5109 uval, (void *)(uintptr_t)uval);
Tom Zanussic6afad42016-03-03 12:54:49 -06005110 } else if (key_field->flags & HIST_FIELD_FL_SYM_OFFSET) {
5111 uval = *(u64 *)(key + key_field->offset);
Arnd Bergmann8720aee2021-10-19 17:33:13 +02005112 seq_printf(m, "%s: [%llx] %-55pS", field_name,
5113 uval, (void *)(uintptr_t)uval);
Tom Zanussi6b4827a2016-03-03 12:54:50 -06005114 } else if (key_field->flags & HIST_FIELD_FL_EXECNAME) {
Tom Zanussiaf6a29b2018-01-15 20:51:53 -06005115 struct hist_elt_data *elt_data = elt->private_data;
5116 char *comm;
5117
5118 if (WARN_ON_ONCE(!elt_data))
5119 return;
5120
5121 comm = elt_data->comm;
Tom Zanussi6b4827a2016-03-03 12:54:50 -06005122
5123 uval = *(u64 *)(key + key_field->offset);
Tom Zanussi85013252017-09-22 14:58:22 -05005124 seq_printf(m, "%s: %-16s[%10llu]", field_name,
5125 comm, uval);
Tom Zanussi31696192016-03-03 12:54:51 -06005126 } else if (key_field->flags & HIST_FIELD_FL_SYSCALL) {
5127 const char *syscall_name;
5128
5129 uval = *(u64 *)(key + key_field->offset);
5130 syscall_name = get_syscall_name(uval);
5131 if (!syscall_name)
5132 syscall_name = "unknown_syscall";
5133
Tom Zanussi85013252017-09-22 14:58:22 -05005134 seq_printf(m, "%s: %-30s[%3llu]", field_name,
5135 syscall_name, uval);
Tom Zanussi69a02002016-03-03 12:54:52 -06005136 } else if (key_field->flags & HIST_FIELD_FL_STACKTRACE) {
5137 seq_puts(m, "stacktrace:\n");
5138 hist_trigger_stacktrace_print(m,
5139 key + key_field->offset,
5140 HIST_STACKTRACE_DEPTH);
5141 multiline = true;
Namhyung Kim4b94f5b2016-03-03 12:55:02 -06005142 } else if (key_field->flags & HIST_FIELD_FL_LOG2) {
Tom Zanussi85013252017-09-22 14:58:22 -05005143 seq_printf(m, "%s: ~ 2^%-2llu", field_name,
Namhyung Kim4b94f5b2016-03-03 12:55:02 -06005144 *(u64 *)(key + key_field->offset));
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04005145 } else if (key_field->flags & HIST_FIELD_FL_BUCKET) {
5146 unsigned long buckets = key_field->buckets;
5147 uval = *(u64 *)(key + key_field->offset);
5148 seq_printf(m, "%s: ~ %llu-%llu", field_name,
5149 uval, uval + buckets -1);
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06005150 } else if (key_field->flags & HIST_FIELD_FL_STRING) {
Tom Zanussi85013252017-09-22 14:58:22 -05005151 seq_printf(m, "%s: %-50s", field_name,
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005152 (char *)(key + key_field->offset));
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005153 } else {
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06005154 uval = *(u64 *)(key + key_field->offset);
Tom Zanussi85013252017-09-22 14:58:22 -05005155 seq_printf(m, "%s: %10llu", field_name, uval);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005156 }
5157 }
5158
Tom Zanussi69a02002016-03-03 12:54:52 -06005159 if (!multiline)
5160 seq_puts(m, " ");
5161
5162 seq_puts(m, "}");
Tom Zanussia3785b72019-02-13 17:42:46 -06005163}
5164
5165static void hist_trigger_entry_print(struct seq_file *m,
5166 struct hist_trigger_data *hist_data,
5167 void *key,
5168 struct tracing_map_elt *elt)
5169{
5170 const char *field_name;
5171 unsigned int i;
5172
5173 hist_trigger_print_key(m, hist_data, key, elt);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005174
5175 seq_printf(m, " hitcount: %10llu",
5176 tracing_map_read_sum(elt, HITCOUNT_IDX));
5177
Tom Zanussif2606832016-03-03 12:54:43 -06005178 for (i = 1; i < hist_data->n_vals; i++) {
Tom Zanussi85013252017-09-22 14:58:22 -05005179 field_name = hist_field_name(hist_data->fields[i], 0);
5180
Tom Zanussi100719d2018-01-15 20:51:52 -06005181 if (hist_data->fields[i]->flags & HIST_FIELD_FL_VAR ||
5182 hist_data->fields[i]->flags & HIST_FIELD_FL_EXPR)
Tom Zanussi30350d62018-01-15 20:51:49 -06005183 continue;
5184
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06005185 if (hist_data->fields[i]->flags & HIST_FIELD_FL_HEX) {
Tom Zanussi85013252017-09-22 14:58:22 -05005186 seq_printf(m, " %s: %10llx", field_name,
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06005187 tracing_map_read_sum(elt, i));
5188 } else {
Tom Zanussi85013252017-09-22 14:58:22 -05005189 seq_printf(m, " %s: %10llu", field_name,
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06005190 tracing_map_read_sum(elt, i));
5191 }
Tom Zanussif2606832016-03-03 12:54:43 -06005192 }
5193
Tom Zanussi50450602018-01-15 20:52:01 -06005194 print_actions(m, hist_data, elt);
5195
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005196 seq_puts(m, "\n");
5197}
5198
5199static int print_entries(struct seq_file *m,
5200 struct hist_trigger_data *hist_data)
5201{
5202 struct tracing_map_sort_entry **sort_entries = NULL;
5203 struct tracing_map *map = hist_data->map;
Steven Rostedt (Red Hat)d50c7442016-03-08 17:17:15 -05005204 int i, n_entries;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005205
5206 n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
5207 hist_data->n_sort_keys,
5208 &sort_entries);
5209 if (n_entries < 0)
5210 return n_entries;
5211
5212 for (i = 0; i < n_entries; i++)
5213 hist_trigger_entry_print(m, hist_data,
5214 sort_entries[i]->key,
5215 sort_entries[i]->elt);
5216
5217 tracing_map_destroy_sort_entries(sort_entries, n_entries);
5218
5219 return n_entries;
5220}
5221
Tom Zanussi52a7f162016-03-03 12:54:57 -06005222static void hist_trigger_show(struct seq_file *m,
5223 struct event_trigger_data *data, int n)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005224{
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005225 struct hist_trigger_data *hist_data;
Colin Ian King6e7a2392017-08-23 12:23:09 +01005226 int n_entries;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005227
Tom Zanussi52a7f162016-03-03 12:54:57 -06005228 if (n > 0)
5229 seq_puts(m, "\n\n");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005230
5231 seq_puts(m, "# event histogram\n#\n# trigger info: ");
5232 data->ops->print(m, data->ops, data);
Tom Zanussi52a7f162016-03-03 12:54:57 -06005233 seq_puts(m, "#\n\n");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005234
5235 hist_data = data->private_data;
5236 n_entries = print_entries(m, hist_data);
Colin Ian King6e7a2392017-08-23 12:23:09 +01005237 if (n_entries < 0)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005238 n_entries = 0;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005239
Tom Zanussia3785b72019-02-13 17:42:46 -06005240 track_data_snapshot_print(m, hist_data);
5241
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005242 seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n",
5243 (u64)atomic64_read(&hist_data->map->hits),
5244 n_entries, (u64)atomic64_read(&hist_data->map->drops));
Tom Zanussi52a7f162016-03-03 12:54:57 -06005245}
5246
5247static int hist_show(struct seq_file *m, void *v)
5248{
5249 struct event_trigger_data *data;
5250 struct trace_event_file *event_file;
5251 int n = 0, ret = 0;
5252
5253 mutex_lock(&event_mutex);
5254
5255 event_file = event_file_data(m->private);
5256 if (unlikely(!event_file)) {
5257 ret = -ENODEV;
5258 goto out_unlock;
5259 }
5260
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09005261 list_for_each_entry(data, &event_file->triggers, list) {
Tom Zanussi52a7f162016-03-03 12:54:57 -06005262 if (data->cmd_ops->trigger_type == ETT_EVENT_HIST)
5263 hist_trigger_show(m, data, n++);
5264 }
5265
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005266 out_unlock:
5267 mutex_unlock(&event_mutex);
5268
5269 return ret;
5270}
5271
5272static int event_hist_open(struct inode *inode, struct file *file)
5273{
Steven Rostedt (VMware)17911ff2019-10-11 17:22:50 -04005274 int ret;
5275
5276 ret = security_locked_down(LOCKDOWN_TRACEFS);
5277 if (ret)
5278 return ret;
5279
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005280 return single_open(file, hist_show, file);
5281}
5282
5283const struct file_operations event_hist_fops = {
5284 .open = event_hist_open,
5285 .read = seq_read,
5286 .llseek = seq_lseek,
5287 .release = single_release,
5288};
5289
Tom Zanussi2d19bd72020-04-03 14:31:21 -05005290#ifdef CONFIG_HIST_TRIGGERS_DEBUG
5291static void hist_field_debug_show_flags(struct seq_file *m,
5292 unsigned long flags)
5293{
5294 seq_puts(m, " flags:\n");
5295
5296 if (flags & HIST_FIELD_FL_KEY)
5297 seq_puts(m, " HIST_FIELD_FL_KEY\n");
5298 else if (flags & HIST_FIELD_FL_HITCOUNT)
5299 seq_puts(m, " VAL: HIST_FIELD_FL_HITCOUNT\n");
5300 else if (flags & HIST_FIELD_FL_VAR)
5301 seq_puts(m, " HIST_FIELD_FL_VAR\n");
5302 else if (flags & HIST_FIELD_FL_VAR_REF)
5303 seq_puts(m, " HIST_FIELD_FL_VAR_REF\n");
5304 else
5305 seq_puts(m, " VAL: normal u64 value\n");
5306
5307 if (flags & HIST_FIELD_FL_ALIAS)
5308 seq_puts(m, " HIST_FIELD_FL_ALIAS\n");
Kalesh Singh52cfb372021-10-25 13:08:33 -07005309 else if (flags & HIST_FIELD_FL_CONST)
5310 seq_puts(m, " HIST_FIELD_FL_CONST\n");
Tom Zanussi2d19bd72020-04-03 14:31:21 -05005311}
5312
5313static int hist_field_debug_show(struct seq_file *m,
5314 struct hist_field *field, unsigned long flags)
5315{
5316 if ((field->flags & flags) != flags) {
5317 seq_printf(m, "ERROR: bad flags - %lx\n", flags);
5318 return -EINVAL;
5319 }
5320
5321 hist_field_debug_show_flags(m, field->flags);
5322 if (field->field)
5323 seq_printf(m, " ftrace_event_field name: %s\n",
5324 field->field->name);
5325
5326 if (field->flags & HIST_FIELD_FL_VAR) {
5327 seq_printf(m, " var.name: %s\n", field->var.name);
5328 seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n",
5329 field->var.idx);
5330 }
5331
Kalesh Singh52cfb372021-10-25 13:08:33 -07005332 if (field->flags & HIST_FIELD_FL_CONST)
5333 seq_printf(m, " constant: %llu\n", field->constant);
5334
Tom Zanussi2d19bd72020-04-03 14:31:21 -05005335 if (field->flags & HIST_FIELD_FL_ALIAS)
5336 seq_printf(m, " var_ref_idx (into hist_data->var_refs[]): %u\n",
5337 field->var_ref_idx);
5338
5339 if (field->flags & HIST_FIELD_FL_VAR_REF) {
5340 seq_printf(m, " name: %s\n", field->name);
5341 seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n",
5342 field->var.idx);
5343 seq_printf(m, " var.hist_data: %p\n", field->var.hist_data);
5344 seq_printf(m, " var_ref_idx (into hist_data->var_refs[]): %u\n",
5345 field->var_ref_idx);
5346 if (field->system)
5347 seq_printf(m, " system: %s\n", field->system);
5348 if (field->event_name)
5349 seq_printf(m, " event_name: %s\n", field->event_name);
5350 }
5351
5352 seq_printf(m, " type: %s\n", field->type);
5353 seq_printf(m, " size: %u\n", field->size);
5354 seq_printf(m, " is_signed: %u\n", field->is_signed);
5355
5356 return 0;
5357}
5358
5359static int field_var_debug_show(struct seq_file *m,
5360 struct field_var *field_var, unsigned int i,
5361 bool save_vars)
5362{
5363 const char *vars_name = save_vars ? "save_vars" : "field_vars";
5364 struct hist_field *field;
5365 int ret = 0;
5366
5367 seq_printf(m, "\n hist_data->%s[%d]:\n", vars_name, i);
5368
5369 field = field_var->var;
5370
5371 seq_printf(m, "\n %s[%d].var:\n", vars_name, i);
5372
5373 hist_field_debug_show_flags(m, field->flags);
5374 seq_printf(m, " var.name: %s\n", field->var.name);
5375 seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n",
5376 field->var.idx);
5377
5378 field = field_var->val;
5379
5380 seq_printf(m, "\n %s[%d].val:\n", vars_name, i);
5381 if (field->field)
5382 seq_printf(m, " ftrace_event_field name: %s\n",
5383 field->field->name);
5384 else {
5385 ret = -EINVAL;
5386 goto out;
5387 }
5388
5389 seq_printf(m, " type: %s\n", field->type);
5390 seq_printf(m, " size: %u\n", field->size);
5391 seq_printf(m, " is_signed: %u\n", field->is_signed);
5392out:
5393 return ret;
5394}
5395
5396static int hist_action_debug_show(struct seq_file *m,
5397 struct action_data *data, int i)
5398{
5399 int ret = 0;
5400
5401 if (data->handler == HANDLER_ONMAX ||
5402 data->handler == HANDLER_ONCHANGE) {
5403 seq_printf(m, "\n hist_data->actions[%d].track_data.var_ref:\n", i);
5404 ret = hist_field_debug_show(m, data->track_data.var_ref,
5405 HIST_FIELD_FL_VAR_REF);
5406 if (ret)
5407 goto out;
5408
5409 seq_printf(m, "\n hist_data->actions[%d].track_data.track_var:\n", i);
5410 ret = hist_field_debug_show(m, data->track_data.track_var,
5411 HIST_FIELD_FL_VAR);
5412 if (ret)
5413 goto out;
5414 }
5415
5416 if (data->handler == HANDLER_ONMATCH) {
5417 seq_printf(m, "\n hist_data->actions[%d].match_data.event_system: %s\n",
5418 i, data->match_data.event_system);
5419 seq_printf(m, " hist_data->actions[%d].match_data.event: %s\n",
5420 i, data->match_data.event);
5421 }
5422out:
5423 return ret;
5424}
5425
5426static int hist_actions_debug_show(struct seq_file *m,
5427 struct hist_trigger_data *hist_data)
5428{
5429 int i, ret = 0;
5430
5431 if (hist_data->n_actions)
5432 seq_puts(m, "\n action tracking variables (for onmax()/onchange()/onmatch()):\n");
5433
5434 for (i = 0; i < hist_data->n_actions; i++) {
5435 struct action_data *action = hist_data->actions[i];
5436
5437 ret = hist_action_debug_show(m, action, i);
5438 if (ret)
5439 goto out;
5440 }
5441
5442 if (hist_data->n_save_vars)
5443 seq_puts(m, "\n save action variables (save() params):\n");
5444
5445 for (i = 0; i < hist_data->n_save_vars; i++) {
5446 ret = field_var_debug_show(m, hist_data->save_vars[i], i, true);
5447 if (ret)
5448 goto out;
5449 }
5450out:
5451 return ret;
5452}
5453
5454static void hist_trigger_debug_show(struct seq_file *m,
5455 struct event_trigger_data *data, int n)
5456{
5457 struct hist_trigger_data *hist_data;
5458 int i, ret;
5459
5460 if (n > 0)
5461 seq_puts(m, "\n\n");
5462
5463 seq_puts(m, "# event histogram\n#\n# trigger info: ");
5464 data->ops->print(m, data->ops, data);
5465 seq_puts(m, "#\n\n");
5466
5467 hist_data = data->private_data;
5468
5469 seq_printf(m, "hist_data: %p\n\n", hist_data);
5470 seq_printf(m, " n_vals: %u\n", hist_data->n_vals);
5471 seq_printf(m, " n_keys: %u\n", hist_data->n_keys);
5472 seq_printf(m, " n_fields: %u\n", hist_data->n_fields);
5473
5474 seq_puts(m, "\n val fields:\n\n");
5475
5476 seq_puts(m, " hist_data->fields[0]:\n");
5477 ret = hist_field_debug_show(m, hist_data->fields[0],
5478 HIST_FIELD_FL_HITCOUNT);
5479 if (ret)
5480 return;
5481
5482 for (i = 1; i < hist_data->n_vals; i++) {
5483 seq_printf(m, "\n hist_data->fields[%d]:\n", i);
5484 ret = hist_field_debug_show(m, hist_data->fields[i], 0);
5485 if (ret)
5486 return;
5487 }
5488
5489 seq_puts(m, "\n key fields:\n");
5490
5491 for (i = hist_data->n_vals; i < hist_data->n_fields; i++) {
5492 seq_printf(m, "\n hist_data->fields[%d]:\n", i);
5493 ret = hist_field_debug_show(m, hist_data->fields[i],
5494 HIST_FIELD_FL_KEY);
5495 if (ret)
5496 return;
5497 }
5498
5499 if (hist_data->n_var_refs)
5500 seq_puts(m, "\n variable reference fields:\n");
5501
5502 for (i = 0; i < hist_data->n_var_refs; i++) {
5503 seq_printf(m, "\n hist_data->var_refs[%d]:\n", i);
5504 ret = hist_field_debug_show(m, hist_data->var_refs[i],
5505 HIST_FIELD_FL_VAR_REF);
5506 if (ret)
5507 return;
5508 }
5509
5510 if (hist_data->n_field_vars)
5511 seq_puts(m, "\n field variables:\n");
5512
5513 for (i = 0; i < hist_data->n_field_vars; i++) {
5514 ret = field_var_debug_show(m, hist_data->field_vars[i], i, false);
5515 if (ret)
5516 return;
5517 }
5518
5519 ret = hist_actions_debug_show(m, hist_data);
5520 if (ret)
5521 return;
5522}
5523
5524static int hist_debug_show(struct seq_file *m, void *v)
5525{
5526 struct event_trigger_data *data;
5527 struct trace_event_file *event_file;
5528 int n = 0, ret = 0;
5529
5530 mutex_lock(&event_mutex);
5531
5532 event_file = event_file_data(m->private);
5533 if (unlikely(!event_file)) {
5534 ret = -ENODEV;
5535 goto out_unlock;
5536 }
5537
5538 list_for_each_entry(data, &event_file->triggers, list) {
5539 if (data->cmd_ops->trigger_type == ETT_EVENT_HIST)
5540 hist_trigger_debug_show(m, data, n++);
5541 }
5542
5543 out_unlock:
5544 mutex_unlock(&event_mutex);
5545
5546 return ret;
5547}
5548
5549static int event_hist_debug_open(struct inode *inode, struct file *file)
5550{
5551 int ret;
5552
5553 ret = security_locked_down(LOCKDOWN_TRACEFS);
5554 if (ret)
5555 return ret;
5556
5557 return single_open(file, hist_debug_show, file);
5558}
5559
5560const struct file_operations event_hist_debug_fops = {
5561 .open = event_hist_debug_open,
5562 .read = seq_read,
5563 .llseek = seq_lseek,
5564 .release = single_release,
5565};
5566#endif
5567
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005568static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
5569{
Tom Zanussi85013252017-09-22 14:58:22 -05005570 const char *field_name = hist_field_name(hist_field, 0);
5571
Tom Zanussi30350d62018-01-15 20:51:49 -06005572 if (hist_field->var.name)
5573 seq_printf(m, "%s=", hist_field->var.name);
5574
Tom Zanussi0ae79612018-03-28 15:10:53 -05005575 if (hist_field->flags & HIST_FIELD_FL_CPU)
Steven Rostedt (VMware)1e3bac72021-07-21 11:00:53 -04005576 seq_puts(m, "common_cpu");
Kalesh Singh52cfb372021-10-25 13:08:33 -07005577 else if (hist_field->flags & HIST_FIELD_FL_CONST)
5578 seq_printf(m, "%llu", hist_field->constant);
Tom Zanussi067fe032018-01-15 20:51:56 -06005579 else if (field_name) {
Tom Zanussi7e8b88a2018-01-15 20:52:04 -06005580 if (hist_field->flags & HIST_FIELD_FL_VAR_REF ||
5581 hist_field->flags & HIST_FIELD_FL_ALIAS)
Tom Zanussi067fe032018-01-15 20:51:56 -06005582 seq_putc(m, '$');
Tom Zanussiad42feb2018-01-15 20:51:45 -06005583 seq_printf(m, "%s", field_name);
Tom Zanussi0ae79612018-03-28 15:10:53 -05005584 } else if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP)
5585 seq_puts(m, "common_timestamp");
Tom Zanussi608940d2018-04-26 20:04:47 -05005586
5587 if (hist_field->flags) {
5588 if (!(hist_field->flags & HIST_FIELD_FL_VAR_REF) &&
5589 !(hist_field->flags & HIST_FIELD_FL_EXPR)) {
5590 const char *flags = get_hist_field_flags(hist_field);
5591
5592 if (flags)
5593 seq_printf(m, ".%s", flags);
5594 }
5595 }
Steven Rostedt (VMware)de9a48a2021-07-07 17:36:24 -04005596 if (hist_field->buckets)
5597 seq_printf(m, "=%ld", hist_field->buckets);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005598}
5599
5600static int event_hist_trigger_print(struct seq_file *m,
5601 struct event_trigger_ops *ops,
5602 struct event_trigger_data *data)
5603{
5604 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussi30350d62018-01-15 20:51:49 -06005605 struct hist_field *field;
5606 bool have_var = false;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005607 unsigned int i;
5608
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005609 seq_puts(m, "hist:");
5610
5611 if (data->name)
5612 seq_printf(m, "%s:", data->name);
5613
5614 seq_puts(m, "keys=");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005615
5616 for_each_hist_key_field(i, hist_data) {
Tom Zanussi30350d62018-01-15 20:51:49 -06005617 field = hist_data->fields[i];
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005618
5619 if (i > hist_data->n_vals)
5620 seq_puts(m, ",");
5621
Tom Zanussi30350d62018-01-15 20:51:49 -06005622 if (field->flags & HIST_FIELD_FL_STACKTRACE)
Tom Zanussi69a02002016-03-03 12:54:52 -06005623 seq_puts(m, "stacktrace");
5624 else
Tom Zanussi30350d62018-01-15 20:51:49 -06005625 hist_field_print(m, field);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005626 }
5627
5628 seq_puts(m, ":vals=");
Tom Zanussif2606832016-03-03 12:54:43 -06005629
5630 for_each_hist_val_field(i, hist_data) {
Tom Zanussi30350d62018-01-15 20:51:49 -06005631 field = hist_data->fields[i];
5632 if (field->flags & HIST_FIELD_FL_VAR) {
5633 have_var = true;
5634 continue;
5635 }
5636
Tom Zanussif2606832016-03-03 12:54:43 -06005637 if (i == HITCOUNT_IDX)
5638 seq_puts(m, "hitcount");
5639 else {
5640 seq_puts(m, ",");
Tom Zanussi30350d62018-01-15 20:51:49 -06005641 hist_field_print(m, field);
5642 }
5643 }
5644
5645 if (have_var) {
5646 unsigned int n = 0;
5647
5648 seq_puts(m, ":");
5649
5650 for_each_hist_val_field(i, hist_data) {
5651 field = hist_data->fields[i];
5652
5653 if (field->flags & HIST_FIELD_FL_VAR) {
5654 if (n++)
5655 seq_puts(m, ",");
5656 hist_field_print(m, field);
5657 }
Tom Zanussif2606832016-03-03 12:54:43 -06005658 }
5659 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005660
5661 seq_puts(m, ":sort=");
Tom Zanussie62347d2016-03-03 12:54:45 -06005662
5663 for (i = 0; i < hist_data->n_sort_keys; i++) {
5664 struct tracing_map_sort_key *sort_key;
Tom Zanussi30350d62018-01-15 20:51:49 -06005665 unsigned int idx, first_key_idx;
5666
5667 /* skip VAR vals */
5668 first_key_idx = hist_data->n_vals - hist_data->n_vars;
Tom Zanussie62347d2016-03-03 12:54:45 -06005669
5670 sort_key = &hist_data->sort_keys[i];
Tom Zanussiad42feb2018-01-15 20:51:45 -06005671 idx = sort_key->field_idx;
5672
Tom Zanussi1a361df2018-01-15 20:51:50 -06005673 if (WARN_ON(idx >= HIST_FIELDS_MAX))
Tom Zanussiad42feb2018-01-15 20:51:45 -06005674 return -EINVAL;
Tom Zanussie62347d2016-03-03 12:54:45 -06005675
5676 if (i > 0)
5677 seq_puts(m, ",");
5678
Tom Zanussiad42feb2018-01-15 20:51:45 -06005679 if (idx == HITCOUNT_IDX)
Tom Zanussie62347d2016-03-03 12:54:45 -06005680 seq_puts(m, "hitcount");
Tom Zanussi30350d62018-01-15 20:51:49 -06005681 else {
5682 if (idx >= first_key_idx)
5683 idx += hist_data->n_vars;
Tom Zanussie62347d2016-03-03 12:54:45 -06005684 hist_field_print(m, hist_data->fields[idx]);
Tom Zanussi30350d62018-01-15 20:51:49 -06005685 }
Tom Zanussie62347d2016-03-03 12:54:45 -06005686
5687 if (sort_key->descending)
5688 seq_puts(m, ".descending");
5689 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005690 seq_printf(m, ":size=%u", (1 << hist_data->map->map_bits));
Tom Zanussia4072fe2018-01-15 20:52:08 -06005691 if (hist_data->enable_timestamps)
5692 seq_printf(m, ":clock=%s", hist_data->attrs->clock);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005693
Tom Zanussic282a382018-01-15 20:52:00 -06005694 print_actions_spec(m, hist_data);
5695
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005696 if (data->filter_str)
5697 seq_printf(m, " if %s", data->filter_str);
5698
Tom Zanussi83e99912016-03-03 12:54:46 -06005699 if (data->paused)
5700 seq_puts(m, " [paused]");
5701 else
5702 seq_puts(m, " [active]");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005703
5704 seq_putc(m, '\n');
5705
5706 return 0;
5707}
5708
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005709static int event_hist_trigger_init(struct event_trigger_ops *ops,
5710 struct event_trigger_data *data)
5711{
5712 struct hist_trigger_data *hist_data = data->private_data;
5713
5714 if (!data->ref && hist_data->attrs->name)
5715 save_named_trigger(hist_data->attrs->name, data);
5716
5717 data->ref++;
5718
5719 return 0;
5720}
5721
Tom Zanussi02205a62018-01-15 20:51:59 -06005722static void unregister_field_var_hists(struct hist_trigger_data *hist_data)
5723{
5724 struct trace_event_file *file;
5725 unsigned int i;
5726 char *cmd;
5727 int ret;
5728
5729 for (i = 0; i < hist_data->n_field_var_hists; i++) {
5730 file = hist_data->field_var_hists[i]->hist_data->event_file;
5731 cmd = hist_data->field_var_hists[i]->cmd;
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06005732 ret = event_hist_trigger_parse(&trigger_hist_cmd, file,
5733 "!hist", "hist", cmd);
Hyeonggon Yoo6c610db2021-05-29 15:14:23 +09005734 WARN_ON_ONCE(ret < 0);
Tom Zanussi02205a62018-01-15 20:51:59 -06005735 }
5736}
5737
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005738static void event_hist_trigger_free(struct event_trigger_ops *ops,
5739 struct event_trigger_data *data)
5740{
5741 struct hist_trigger_data *hist_data = data->private_data;
5742
5743 if (WARN_ON_ONCE(data->ref <= 0))
5744 return;
5745
5746 data->ref--;
5747 if (!data->ref) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005748 if (data->name)
5749 del_named_trigger(data);
Tom Zanussi067fe032018-01-15 20:51:56 -06005750
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005751 trigger_data_free(data);
Tom Zanussi067fe032018-01-15 20:51:56 -06005752
5753 remove_hist_vars(hist_data);
5754
Tom Zanussi02205a62018-01-15 20:51:59 -06005755 unregister_field_var_hists(hist_data);
5756
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005757 destroy_hist_data(hist_data);
5758 }
5759}
5760
5761static struct event_trigger_ops event_hist_trigger_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06005762 .trigger = event_hist_trigger,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005763 .print = event_hist_trigger_print,
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005764 .init = event_hist_trigger_init,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005765 .free = event_hist_trigger_free,
5766};
5767
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005768static int event_hist_trigger_named_init(struct event_trigger_ops *ops,
5769 struct event_trigger_data *data)
5770{
5771 data->ref++;
5772
5773 save_named_trigger(data->named_data->name, data);
5774
5775 event_hist_trigger_init(ops, data->named_data);
5776
5777 return 0;
5778}
5779
5780static void event_hist_trigger_named_free(struct event_trigger_ops *ops,
5781 struct event_trigger_data *data)
5782{
5783 if (WARN_ON_ONCE(data->ref <= 0))
5784 return;
5785
5786 event_hist_trigger_free(ops, data->named_data);
5787
5788 data->ref--;
5789 if (!data->ref) {
5790 del_named_trigger(data);
5791 trigger_data_free(data);
5792 }
5793}
5794
5795static struct event_trigger_ops event_hist_trigger_named_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06005796 .trigger = event_hist_trigger,
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005797 .print = event_hist_trigger_print,
5798 .init = event_hist_trigger_named_init,
5799 .free = event_hist_trigger_named_free,
5800};
5801
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005802static struct event_trigger_ops *event_hist_get_trigger_ops(char *cmd,
5803 char *param)
5804{
5805 return &event_hist_trigger_ops;
5806}
5807
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005808static void hist_clear(struct event_trigger_data *data)
5809{
5810 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005811
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005812 if (data->name)
5813 pause_named_trigger(data);
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005814
Steven Rostedt (VMware)e0a568d2018-08-09 15:31:48 -04005815 tracepoint_synchronize_unregister();
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005816
5817 tracing_map_clear(hist_data->map);
5818
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005819 if (data->name)
5820 unpause_named_trigger(data);
5821}
5822
5823static bool compatible_field(struct ftrace_event_field *field,
5824 struct ftrace_event_field *test_field)
5825{
5826 if (field == test_field)
5827 return true;
5828 if (field == NULL || test_field == NULL)
5829 return false;
5830 if (strcmp(field->name, test_field->name) != 0)
5831 return false;
5832 if (strcmp(field->type, test_field->type) != 0)
5833 return false;
5834 if (field->size != test_field->size)
5835 return false;
5836 if (field->is_signed != test_field->is_signed)
5837 return false;
5838
5839 return true;
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005840}
5841
Tom Zanussi52a7f162016-03-03 12:54:57 -06005842static bool hist_trigger_match(struct event_trigger_data *data,
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005843 struct event_trigger_data *data_test,
5844 struct event_trigger_data *named_data,
5845 bool ignore_filter)
Tom Zanussi52a7f162016-03-03 12:54:57 -06005846{
5847 struct tracing_map_sort_key *sort_key, *sort_key_test;
5848 struct hist_trigger_data *hist_data, *hist_data_test;
5849 struct hist_field *key_field, *key_field_test;
5850 unsigned int i;
5851
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005852 if (named_data && (named_data != data_test) &&
5853 (named_data != data_test->named_data))
5854 return false;
5855
5856 if (!named_data && is_named_trigger(data_test))
5857 return false;
5858
Tom Zanussi52a7f162016-03-03 12:54:57 -06005859 hist_data = data->private_data;
5860 hist_data_test = data_test->private_data;
5861
5862 if (hist_data->n_vals != hist_data_test->n_vals ||
5863 hist_data->n_fields != hist_data_test->n_fields ||
5864 hist_data->n_sort_keys != hist_data_test->n_sort_keys)
5865 return false;
5866
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005867 if (!ignore_filter) {
5868 if ((data->filter_str && !data_test->filter_str) ||
5869 (!data->filter_str && data_test->filter_str))
5870 return false;
5871 }
Tom Zanussi52a7f162016-03-03 12:54:57 -06005872
5873 for_each_hist_field(i, hist_data) {
5874 key_field = hist_data->fields[i];
5875 key_field_test = hist_data_test->fields[i];
5876
5877 if (key_field->flags != key_field_test->flags)
5878 return false;
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005879 if (!compatible_field(key_field->field, key_field_test->field))
Tom Zanussi52a7f162016-03-03 12:54:57 -06005880 return false;
5881 if (key_field->offset != key_field_test->offset)
5882 return false;
Tom Zanussiad42feb2018-01-15 20:51:45 -06005883 if (key_field->size != key_field_test->size)
5884 return false;
5885 if (key_field->is_signed != key_field_test->is_signed)
5886 return false;
Tom Zanussi1a361df2018-01-15 20:51:50 -06005887 if (!!key_field->var.name != !!key_field_test->var.name)
5888 return false;
5889 if (key_field->var.name &&
5890 strcmp(key_field->var.name, key_field_test->var.name) != 0)
5891 return false;
Tom Zanussi52a7f162016-03-03 12:54:57 -06005892 }
5893
5894 for (i = 0; i < hist_data->n_sort_keys; i++) {
5895 sort_key = &hist_data->sort_keys[i];
5896 sort_key_test = &hist_data_test->sort_keys[i];
5897
5898 if (sort_key->field_idx != sort_key_test->field_idx ||
5899 sort_key->descending != sort_key_test->descending)
5900 return false;
5901 }
5902
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005903 if (!ignore_filter && data->filter_str &&
Tom Zanussi52a7f162016-03-03 12:54:57 -06005904 (strcmp(data->filter_str, data_test->filter_str) != 0))
5905 return false;
5906
Tom Zanussi48f79472018-03-28 15:10:55 -05005907 if (!actions_match(hist_data, hist_data_test))
5908 return false;
5909
Tom Zanussi52a7f162016-03-03 12:54:57 -06005910 return true;
5911}
5912
Tom Zanussi2378a2d2022-01-10 08:04:13 -06005913static int hist_register_trigger(char *glob,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005914 struct event_trigger_data *data,
5915 struct trace_event_file *file)
5916{
Tom Zanussi83e99912016-03-03 12:54:46 -06005917 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005918 struct event_trigger_data *test, *named_data = NULL;
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04005919 struct trace_array *tr = file->tr;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005920 int ret = 0;
5921
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005922 if (hist_data->attrs->name) {
5923 named_data = find_named_trigger(hist_data->attrs->name);
5924 if (named_data) {
5925 if (!hist_trigger_match(data, named_data, named_data,
5926 true)) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04005927 hist_err(tr, HIST_ERR_NAMED_MISMATCH, errpos(hist_data->attrs->name));
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005928 ret = -EINVAL;
5929 goto out;
5930 }
5931 }
5932 }
5933
5934 if (hist_data->attrs->name && !named_data)
5935 goto new;
5936
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09005937 lockdep_assert_held(&event_mutex);
5938
5939 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005940 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005941 if (!hist_trigger_match(data, test, named_data, false))
Tom Zanussi52a7f162016-03-03 12:54:57 -06005942 continue;
Tom Zanussi83e99912016-03-03 12:54:46 -06005943 if (hist_data->attrs->pause)
5944 test->paused = true;
5945 else if (hist_data->attrs->cont)
5946 test->paused = false;
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005947 else if (hist_data->attrs->clear)
5948 hist_clear(test);
Tom Zanussif404da62018-01-15 20:52:05 -06005949 else {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04005950 hist_err(tr, HIST_ERR_TRIGGER_EEXIST, 0);
Tom Zanussi83e99912016-03-03 12:54:46 -06005951 ret = -EEXIST;
Tom Zanussif404da62018-01-15 20:52:05 -06005952 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005953 goto out;
5954 }
5955 }
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005956 new:
Tom Zanussie86ae9b2016-03-03 12:54:47 -06005957 if (hist_data->attrs->cont || hist_data->attrs->clear) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04005958 hist_err(tr, HIST_ERR_TRIGGER_ENOENT_CLEAR, 0);
Tom Zanussi83e99912016-03-03 12:54:46 -06005959 ret = -ENOENT;
5960 goto out;
5961 }
5962
Tom Zanussi7522c032016-06-29 19:56:00 -05005963 if (hist_data->attrs->pause)
5964 data->paused = true;
5965
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005966 if (named_data) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06005967 data->private_data = named_data->private_data;
5968 set_named_trigger_data(data, named_data);
5969 data->ops = &event_hist_trigger_named_ops;
5970 }
5971
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005972 if (data->ops->init) {
5973 ret = data->ops->init(data->ops, data);
5974 if (ret < 0)
5975 goto out;
5976 }
5977
Tom Zanussia4072fe2018-01-15 20:52:08 -06005978 if (hist_data->enable_timestamps) {
5979 char *clock = hist_data->attrs->clock;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06005980
Tom Zanussia4072fe2018-01-15 20:52:08 -06005981 ret = tracing_set_clock(file->tr, hist_data->attrs->clock);
5982 if (ret) {
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04005983 hist_err(tr, HIST_ERR_SET_CLOCK_FAIL, errpos(clock));
Tom Zanussia4072fe2018-01-15 20:52:08 -06005984 goto out;
5985 }
5986
Steven Rostedt (VMware)b94bc802021-03-16 12:41:05 -04005987 tracing_set_filter_buffering(file->tr, true);
Tom Zanussia4072fe2018-01-15 20:52:08 -06005988 }
5989
5990 if (named_data)
5991 destroy_hist_data(hist_data);
5992
5993 ret++;
Tom Zanussi067fe032018-01-15 20:51:56 -06005994 out:
5995 return ret;
5996}
5997
5998static int hist_trigger_enable(struct event_trigger_data *data,
5999 struct trace_event_file *file)
6000{
6001 int ret = 0;
6002
6003 list_add_tail_rcu(&data->list, &file->triggers);
6004
6005 update_cond_flag(file);
Tom Zanussiad42feb2018-01-15 20:51:45 -06006006
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006007 if (trace_event_trigger_enable_disable(file, 1) < 0) {
6008 list_del_rcu(&data->list);
6009 update_cond_flag(file);
6010 ret--;
6011 }
Tom Zanussi067fe032018-01-15 20:51:56 -06006012
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006013 return ret;
6014}
6015
Tom Zanussi4b147932018-01-15 20:51:58 -06006016static bool have_hist_trigger_match(struct event_trigger_data *data,
6017 struct trace_event_file *file)
6018{
6019 struct hist_trigger_data *hist_data = data->private_data;
6020 struct event_trigger_data *test, *named_data = NULL;
6021 bool match = false;
6022
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006023 lockdep_assert_held(&event_mutex);
6024
Tom Zanussi4b147932018-01-15 20:51:58 -06006025 if (hist_data->attrs->name)
6026 named_data = find_named_trigger(hist_data->attrs->name);
6027
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006028 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi4b147932018-01-15 20:51:58 -06006029 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
6030 if (hist_trigger_match(data, test, named_data, false)) {
6031 match = true;
6032 break;
6033 }
6034 }
6035 }
6036
6037 return match;
6038}
6039
Tom Zanussi067fe032018-01-15 20:51:56 -06006040static bool hist_trigger_check_refs(struct event_trigger_data *data,
6041 struct trace_event_file *file)
6042{
6043 struct hist_trigger_data *hist_data = data->private_data;
6044 struct event_trigger_data *test, *named_data = NULL;
6045
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006046 lockdep_assert_held(&event_mutex);
6047
Tom Zanussi067fe032018-01-15 20:51:56 -06006048 if (hist_data->attrs->name)
6049 named_data = find_named_trigger(hist_data->attrs->name);
6050
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006051 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi067fe032018-01-15 20:51:56 -06006052 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
6053 if (!hist_trigger_match(data, test, named_data, false))
6054 continue;
6055 hist_data = test->private_data;
6056 if (check_var_refs(hist_data))
6057 return true;
6058 break;
6059 }
6060 }
6061
6062 return false;
6063}
6064
Tom Zanussi2378a2d2022-01-10 08:04:13 -06006065static void hist_unregister_trigger(char *glob,
Tom Zanussi52a7f162016-03-03 12:54:57 -06006066 struct event_trigger_data *data,
6067 struct trace_event_file *file)
6068{
Tom Zanussi5463bfd2016-03-03 12:54:59 -06006069 struct hist_trigger_data *hist_data = data->private_data;
6070 struct event_trigger_data *test, *named_data = NULL;
Tom Zanussi52a7f162016-03-03 12:54:57 -06006071 bool unregistered = false;
6072
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006073 lockdep_assert_held(&event_mutex);
6074
Tom Zanussi5463bfd2016-03-03 12:54:59 -06006075 if (hist_data->attrs->name)
6076 named_data = find_named_trigger(hist_data->attrs->name);
6077
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006078 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi52a7f162016-03-03 12:54:57 -06006079 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06006080 if (!hist_trigger_match(data, test, named_data, false))
Tom Zanussi52a7f162016-03-03 12:54:57 -06006081 continue;
6082 unregistered = true;
6083 list_del_rcu(&test->list);
6084 trace_event_trigger_enable_disable(file, 0);
6085 update_cond_flag(file);
6086 break;
6087 }
6088 }
6089
6090 if (unregistered && test->ops->free)
6091 test->ops->free(test->ops, test);
Tom Zanussiad42feb2018-01-15 20:51:45 -06006092
6093 if (hist_data->enable_timestamps) {
Tom Zanussi30350d62018-01-15 20:51:49 -06006094 if (!hist_data->remove || unregistered)
Steven Rostedt (VMware)b94bc802021-03-16 12:41:05 -04006095 tracing_set_filter_buffering(file->tr, false);
Tom Zanussiad42feb2018-01-15 20:51:45 -06006096 }
Tom Zanussi52a7f162016-03-03 12:54:57 -06006097}
6098
Tom Zanussi067fe032018-01-15 20:51:56 -06006099static bool hist_file_check_refs(struct trace_event_file *file)
6100{
6101 struct hist_trigger_data *hist_data;
6102 struct event_trigger_data *test;
6103
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006104 lockdep_assert_held(&event_mutex);
6105
6106 list_for_each_entry(test, &file->triggers, list) {
Tom Zanussi067fe032018-01-15 20:51:56 -06006107 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
6108 hist_data = test->private_data;
6109 if (check_var_refs(hist_data))
6110 return true;
6111 }
6112 }
6113
6114 return false;
6115}
6116
Tom Zanussi52a7f162016-03-03 12:54:57 -06006117static void hist_unreg_all(struct trace_event_file *file)
6118{
Steven Rostedt47c18562016-06-29 19:55:59 -05006119 struct event_trigger_data *test, *n;
Tom Zanussiad42feb2018-01-15 20:51:45 -06006120 struct hist_trigger_data *hist_data;
Tom Zanussi4b147932018-01-15 20:51:58 -06006121 struct synth_event *se;
6122 const char *se_name;
Tom Zanussi52a7f162016-03-03 12:54:57 -06006123
Masami Hiramatsu0e2b81f72018-11-05 18:04:01 +09006124 lockdep_assert_held(&event_mutex);
6125
Tom Zanussi067fe032018-01-15 20:51:56 -06006126 if (hist_file_check_refs(file))
6127 return;
6128
Steven Rostedt47c18562016-06-29 19:55:59 -05006129 list_for_each_entry_safe(test, n, &file->triggers, list) {
Tom Zanussi52a7f162016-03-03 12:54:57 -06006130 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
Tom Zanussiad42feb2018-01-15 20:51:45 -06006131 hist_data = test->private_data;
Tom Zanussi52a7f162016-03-03 12:54:57 -06006132 list_del_rcu(&test->list);
6133 trace_event_trigger_enable_disable(file, 0);
Tom Zanussi4b147932018-01-15 20:51:58 -06006134
Tom Zanussi4b147932018-01-15 20:51:58 -06006135 se_name = trace_event_name(file->event_call);
6136 se = find_synth_event(se_name);
6137 if (se)
6138 se->ref--;
Tom Zanussi4b147932018-01-15 20:51:58 -06006139
Tom Zanussi52a7f162016-03-03 12:54:57 -06006140 update_cond_flag(file);
Tom Zanussiad42feb2018-01-15 20:51:45 -06006141 if (hist_data->enable_timestamps)
Steven Rostedt (VMware)b94bc802021-03-16 12:41:05 -04006142 tracing_set_filter_buffering(file->tr, false);
Tom Zanussi52a7f162016-03-03 12:54:57 -06006143 if (test->ops->free)
6144 test->ops->free(test->ops, test);
6145 }
6146 }
6147}
6148
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06006149static int event_hist_trigger_parse(struct event_command *cmd_ops,
6150 struct trace_event_file *file,
6151 char *glob, char *cmd, char *param)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006152{
6153 unsigned int hist_trigger_bits = TRACING_MAP_BITS_DEFAULT;
6154 struct event_trigger_data *trigger_data;
6155 struct hist_trigger_attrs *attrs;
6156 struct event_trigger_ops *trigger_ops;
6157 struct hist_trigger_data *hist_data;
Tom Zanussi4b147932018-01-15 20:51:58 -06006158 struct synth_event *se;
6159 const char *se_name;
Tom Zanussi30350d62018-01-15 20:51:49 -06006160 bool remove = false;
Kalesh Singhc5eac6e2021-10-25 13:08:36 -07006161 char *trigger, *p, *start;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006162 int ret = 0;
6163
Masami Hiramatsu0e2b81f72018-11-05 18:04:01 +09006164 lockdep_assert_held(&event_mutex);
6165
Tom Zanussif404da62018-01-15 20:52:05 -06006166 if (glob && strlen(glob)) {
Tom Zanussif404da62018-01-15 20:52:05 -06006167 hist_err_clear();
Tom Zanussia1a05bb2019-03-31 18:48:16 -05006168 last_cmd_set(file, param);
Tom Zanussif404da62018-01-15 20:52:05 -06006169 }
6170
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006171 if (!param)
6172 return -EINVAL;
6173
Tom Zanussi30350d62018-01-15 20:51:49 -06006174 if (glob[0] == '!')
6175 remove = true;
6176
Tom Zanussiec5ce092018-01-15 20:52:02 -06006177 /*
6178 * separate the trigger from the filter (k:v [if filter])
6179 * allowing for whitespace in the trigger
6180 */
6181 p = trigger = param;
6182 do {
6183 p = strstr(p, "if");
6184 if (!p)
6185 break;
6186 if (p == param)
6187 return -EINVAL;
6188 if (*(p - 1) != ' ' && *(p - 1) != '\t') {
6189 p++;
6190 continue;
6191 }
Tom Zanussi2f31ed92018-12-18 14:33:21 -06006192 if (p >= param + strlen(param) - (sizeof("if") - 1) - 1)
Tom Zanussiec5ce092018-01-15 20:52:02 -06006193 return -EINVAL;
Tom Zanussi2f31ed92018-12-18 14:33:21 -06006194 if (*(p + sizeof("if") - 1) != ' ' && *(p + sizeof("if") - 1) != '\t') {
Tom Zanussiec5ce092018-01-15 20:52:02 -06006195 p++;
6196 continue;
6197 }
6198 break;
6199 } while (p);
6200
6201 if (!p)
6202 param = NULL;
6203 else {
6204 *(p - 1) = '\0';
6205 param = strstrip(p);
6206 trigger = strstrip(trigger);
6207 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006208
Kalesh Singhc5eac6e2021-10-25 13:08:36 -07006209 /*
6210 * To simplify arithmetic expression parsing, replace occurrences of
6211 * '.sym-offset' modifier with '.symXoffset'
6212 */
6213 start = strstr(trigger, ".sym-offset");
6214 while (start) {
6215 *(start + 4) = 'X';
6216 start = strstr(start + 11, ".sym-offset");
kernel test robotfeea69e2021-10-30 08:56:15 +08006217 }
Kalesh Singhc5eac6e2021-10-25 13:08:36 -07006218
Steven Rostedt (VMware)d0cd8712019-04-01 22:30:22 -04006219 attrs = parse_hist_trigger_attrs(file->tr, trigger);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006220 if (IS_ERR(attrs))
6221 return PTR_ERR(attrs);
6222
6223 if (attrs->map_bits)
6224 hist_trigger_bits = attrs->map_bits;
6225
Tom Zanussi30350d62018-01-15 20:51:49 -06006226 hist_data = create_hist_data(hist_trigger_bits, attrs, file, remove);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006227 if (IS_ERR(hist_data)) {
6228 destroy_hist_trigger_attrs(attrs);
6229 return PTR_ERR(hist_data);
6230 }
6231
6232 trigger_ops = cmd_ops->get_trigger_ops(cmd, trigger);
6233
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006234 trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL);
Tom Zanussi4b147932018-01-15 20:51:58 -06006235 if (!trigger_data) {
6236 ret = -ENOMEM;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006237 goto out_free;
Tom Zanussi4b147932018-01-15 20:51:58 -06006238 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006239
6240 trigger_data->count = -1;
6241 trigger_data->ops = trigger_ops;
6242 trigger_data->cmd_ops = cmd_ops;
6243
6244 INIT_LIST_HEAD(&trigger_data->list);
6245 RCU_INIT_POINTER(trigger_data->filter, NULL);
6246
6247 trigger_data->private_data = hist_data;
6248
Tom Zanussi52a7f162016-03-03 12:54:57 -06006249 /* if param is non-empty, it's supposed to be a filter */
6250 if (param && cmd_ops->set_filter) {
6251 ret = cmd_ops->set_filter(param, trigger_data, file);
6252 if (ret < 0)
6253 goto out_free;
6254 }
6255
Tom Zanussi30350d62018-01-15 20:51:49 -06006256 if (remove) {
Tom Zanussi4b147932018-01-15 20:51:58 -06006257 if (!have_hist_trigger_match(trigger_data, file))
6258 goto out_free;
6259
Tom Zanussi067fe032018-01-15 20:51:56 -06006260 if (hist_trigger_check_refs(trigger_data, file)) {
6261 ret = -EBUSY;
6262 goto out_free;
6263 }
6264
Tom Zanussi2378a2d2022-01-10 08:04:13 -06006265 cmd_ops->unreg(glob+1, trigger_data, file);
Tom Zanussi4b147932018-01-15 20:51:58 -06006266 se_name = trace_event_name(file->event_call);
6267 se = find_synth_event(se_name);
6268 if (se)
6269 se->ref--;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006270 ret = 0;
6271 goto out_free;
6272 }
6273
Tom Zanussi2378a2d2022-01-10 08:04:13 -06006274 ret = cmd_ops->reg(glob, trigger_data, file);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006275 /*
6276 * The above returns on success the # of triggers registered,
6277 * but if it didn't register any it returns zero. Consider no
6278 * triggers registered a failure too.
6279 */
6280 if (!ret) {
Tom Zanussie86ae9b2016-03-03 12:54:47 -06006281 if (!(attrs->pause || attrs->cont || attrs->clear))
Tom Zanussi83e99912016-03-03 12:54:46 -06006282 ret = -ENOENT;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006283 goto out_free;
6284 } else if (ret < 0)
6285 goto out_free;
Tom Zanussi067fe032018-01-15 20:51:56 -06006286
6287 if (get_named_trigger_data(trigger_data))
6288 goto enable;
6289
6290 if (has_hist_vars(hist_data))
6291 save_hist_vars(hist_data);
6292
Tom Zanussi7d18a102019-02-13 17:42:41 -06006293 ret = create_actions(hist_data);
Tom Zanussi0212e2a2018-01-15 20:51:57 -06006294 if (ret)
6295 goto out_unreg;
6296
Tom Zanussi067fe032018-01-15 20:51:56 -06006297 ret = tracing_map_init(hist_data->map);
6298 if (ret)
6299 goto out_unreg;
6300enable:
6301 ret = hist_trigger_enable(trigger_data, file);
6302 if (ret)
6303 goto out_unreg;
6304
Tom Zanussi4b147932018-01-15 20:51:58 -06006305 se_name = trace_event_name(file->event_call);
6306 se = find_synth_event(se_name);
6307 if (se)
6308 se->ref++;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006309 /* Just return zero, not the number of registered triggers */
6310 ret = 0;
6311 out:
Tom Zanussif404da62018-01-15 20:52:05 -06006312 if (ret == 0)
6313 hist_err_clear();
6314
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006315 return ret;
Tom Zanussi067fe032018-01-15 20:51:56 -06006316 out_unreg:
Tom Zanussi2378a2d2022-01-10 08:04:13 -06006317 cmd_ops->unreg(glob+1, trigger_data, file);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006318 out_free:
6319 if (cmd_ops->set_filter)
6320 cmd_ops->set_filter(NULL, trigger_data, NULL);
6321
Tom Zanussi067fe032018-01-15 20:51:56 -06006322 remove_hist_vars(hist_data);
6323
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006324 kfree(trigger_data);
6325
6326 destroy_hist_data(hist_data);
6327 goto out;
6328}
6329
6330static struct event_command trigger_hist_cmd = {
6331 .name = "hist",
6332 .trigger_type = ETT_EVENT_HIST,
6333 .flags = EVENT_CMD_FL_NEEDS_REC,
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06006334 .parse = event_hist_trigger_parse,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006335 .reg = hist_register_trigger,
Tom Zanussi52a7f162016-03-03 12:54:57 -06006336 .unreg = hist_unregister_trigger,
6337 .unreg_all = hist_unreg_all,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06006338 .get_trigger_ops = event_hist_get_trigger_ops,
6339 .set_filter = set_trigger_filter,
6340};
6341
6342__init int register_trigger_hist_cmd(void)
6343{
6344 int ret;
6345
6346 ret = register_event_command(&trigger_hist_cmd);
6347 WARN_ON(ret < 0);
6348
6349 return ret;
6350}
Tom Zanussid0bad492016-03-03 12:54:55 -06006351
6352static void
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04006353hist_enable_trigger(struct event_trigger_data *data,
6354 struct trace_buffer *buffer, void *rec,
Tom Zanussi1ac4f512018-01-15 20:51:42 -06006355 struct ring_buffer_event *event)
Tom Zanussid0bad492016-03-03 12:54:55 -06006356{
6357 struct enable_trigger_data *enable_data = data->private_data;
6358 struct event_trigger_data *test;
6359
Masami Hiramatsuaeed8aa2019-12-20 11:31:43 +09006360 list_for_each_entry_rcu(test, &enable_data->file->triggers, list,
6361 lockdep_is_held(&event_mutex)) {
Tom Zanussid0bad492016-03-03 12:54:55 -06006362 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
6363 if (enable_data->enable)
6364 test->paused = false;
6365 else
6366 test->paused = true;
Tom Zanussid0bad492016-03-03 12:54:55 -06006367 }
6368 }
6369}
6370
6371static void
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04006372hist_enable_count_trigger(struct event_trigger_data *data,
6373 struct trace_buffer *buffer, void *rec,
Tom Zanussi1ac4f512018-01-15 20:51:42 -06006374 struct ring_buffer_event *event)
Tom Zanussid0bad492016-03-03 12:54:55 -06006375{
6376 if (!data->count)
6377 return;
6378
6379 if (data->count != -1)
6380 (data->count)--;
6381
Steven Rostedt (VMware)b47e3302021-03-16 12:41:03 -04006382 hist_enable_trigger(data, buffer, rec, event);
Tom Zanussid0bad492016-03-03 12:54:55 -06006383}
6384
6385static struct event_trigger_ops hist_enable_trigger_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06006386 .trigger = hist_enable_trigger,
Tom Zanussid0bad492016-03-03 12:54:55 -06006387 .print = event_enable_trigger_print,
6388 .init = event_trigger_init,
6389 .free = event_enable_trigger_free,
6390};
6391
6392static struct event_trigger_ops hist_enable_count_trigger_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06006393 .trigger = hist_enable_count_trigger,
Tom Zanussid0bad492016-03-03 12:54:55 -06006394 .print = event_enable_trigger_print,
6395 .init = event_trigger_init,
6396 .free = event_enable_trigger_free,
6397};
6398
6399static struct event_trigger_ops hist_disable_trigger_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06006400 .trigger = hist_enable_trigger,
Tom Zanussid0bad492016-03-03 12:54:55 -06006401 .print = event_enable_trigger_print,
6402 .init = event_trigger_init,
6403 .free = event_enable_trigger_free,
6404};
6405
6406static struct event_trigger_ops hist_disable_count_trigger_ops = {
Tom Zanussifb339e52022-01-10 08:04:12 -06006407 .trigger = hist_enable_count_trigger,
Tom Zanussid0bad492016-03-03 12:54:55 -06006408 .print = event_enable_trigger_print,
6409 .init = event_trigger_init,
6410 .free = event_enable_trigger_free,
6411};
6412
6413static struct event_trigger_ops *
6414hist_enable_get_trigger_ops(char *cmd, char *param)
6415{
6416 struct event_trigger_ops *ops;
6417 bool enable;
6418
6419 enable = (strcmp(cmd, ENABLE_HIST_STR) == 0);
6420
6421 if (enable)
6422 ops = param ? &hist_enable_count_trigger_ops :
6423 &hist_enable_trigger_ops;
6424 else
6425 ops = param ? &hist_disable_count_trigger_ops :
6426 &hist_disable_trigger_ops;
6427
6428 return ops;
6429}
6430
Tom Zanussi52a7f162016-03-03 12:54:57 -06006431static void hist_enable_unreg_all(struct trace_event_file *file)
6432{
Steven Rostedt47c18562016-06-29 19:55:59 -05006433 struct event_trigger_data *test, *n;
Tom Zanussi52a7f162016-03-03 12:54:57 -06006434
Steven Rostedt47c18562016-06-29 19:55:59 -05006435 list_for_each_entry_safe(test, n, &file->triggers, list) {
Tom Zanussi52a7f162016-03-03 12:54:57 -06006436 if (test->cmd_ops->trigger_type == ETT_HIST_ENABLE) {
6437 list_del_rcu(&test->list);
6438 update_cond_flag(file);
6439 trace_event_trigger_enable_disable(file, 0);
6440 if (test->ops->free)
6441 test->ops->free(test->ops, test);
6442 }
6443 }
6444}
6445
Tom Zanussid0bad492016-03-03 12:54:55 -06006446static struct event_command trigger_hist_enable_cmd = {
6447 .name = ENABLE_HIST_STR,
6448 .trigger_type = ETT_HIST_ENABLE,
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06006449 .parse = event_enable_trigger_parse,
Tom Zanussid0bad492016-03-03 12:54:55 -06006450 .reg = event_enable_register_trigger,
6451 .unreg = event_enable_unregister_trigger,
Tom Zanussi52a7f162016-03-03 12:54:57 -06006452 .unreg_all = hist_enable_unreg_all,
Tom Zanussid0bad492016-03-03 12:54:55 -06006453 .get_trigger_ops = hist_enable_get_trigger_ops,
6454 .set_filter = set_trigger_filter,
6455};
6456
6457static struct event_command trigger_hist_disable_cmd = {
6458 .name = DISABLE_HIST_STR,
6459 .trigger_type = ETT_HIST_ENABLE,
Tom Zanussi9ec5a7d2022-01-10 08:04:11 -06006460 .parse = event_enable_trigger_parse,
Tom Zanussid0bad492016-03-03 12:54:55 -06006461 .reg = event_enable_register_trigger,
6462 .unreg = event_enable_unregister_trigger,
Tom Zanussi52a7f162016-03-03 12:54:57 -06006463 .unreg_all = hist_enable_unreg_all,
Tom Zanussid0bad492016-03-03 12:54:55 -06006464 .get_trigger_ops = hist_enable_get_trigger_ops,
6465 .set_filter = set_trigger_filter,
6466};
6467
6468static __init void unregister_trigger_hist_enable_disable_cmds(void)
6469{
6470 unregister_event_command(&trigger_hist_enable_cmd);
6471 unregister_event_command(&trigger_hist_disable_cmd);
6472}
6473
6474__init int register_trigger_hist_enable_disable_cmds(void)
6475{
6476 int ret;
6477
6478 ret = register_event_command(&trigger_hist_enable_cmd);
6479 if (WARN_ON(ret < 0))
6480 return ret;
6481 ret = register_event_command(&trigger_hist_disable_cmd);
6482 if (WARN_ON(ret < 0))
6483 unregister_trigger_hist_enable_disable_cmds();
6484
6485 return ret;
6486}