blob: a793f8c04830ddddaeab1217a77518049a93bea2 [file] [log] [blame]
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001/*
2 * trace_events_hist - trace event hist triggers
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * Copyright (C) 2015 Tom Zanussi <tom.zanussi@linux.intel.com>
15 */
16
17#include <linux/module.h>
18#include <linux/kallsyms.h>
19#include <linux/mutex.h>
20#include <linux/slab.h>
21#include <linux/stacktrace.h>
Ingo Molnarb2d09102017-02-04 01:27:20 +010022#include <linux/rculist.h>
Tom Zanussi7ef224d2016-03-03 12:54:42 -060023
24#include "tracing_map.h"
25#include "trace.h"
26
27struct hist_field;
28
Tom Zanussifbd302c2018-01-15 20:51:43 -060029typedef u64 (*hist_field_fn_t) (struct hist_field *field, void *event,
30 struct ring_buffer_event *rbe);
Tom Zanussi7ef224d2016-03-03 12:54:42 -060031
Tom Zanussi5819ead2017-09-22 14:58:23 -050032#define HIST_FIELD_OPERANDS_MAX 2
33
Tom Zanussi7ef224d2016-03-03 12:54:42 -060034struct hist_field {
35 struct ftrace_event_field *field;
36 unsigned long flags;
37 hist_field_fn_t fn;
38 unsigned int size;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -060039 unsigned int offset;
Tom Zanussi5819ead2017-09-22 14:58:23 -050040 unsigned int is_signed;
41 struct hist_field *operands[HIST_FIELD_OPERANDS_MAX];
Tom Zanussi7ef224d2016-03-03 12:54:42 -060042};
43
Tom Zanussifbd302c2018-01-15 20:51:43 -060044static u64 hist_field_none(struct hist_field *field, void *event,
45 struct ring_buffer_event *rbe)
Tom Zanussi69a02002016-03-03 12:54:52 -060046{
47 return 0;
48}
49
Tom Zanussifbd302c2018-01-15 20:51:43 -060050static u64 hist_field_counter(struct hist_field *field, void *event,
51 struct ring_buffer_event *rbe)
Tom Zanussi7ef224d2016-03-03 12:54:42 -060052{
53 return 1;
54}
55
Tom Zanussifbd302c2018-01-15 20:51:43 -060056static u64 hist_field_string(struct hist_field *hist_field, void *event,
57 struct ring_buffer_event *rbe)
Tom Zanussi7ef224d2016-03-03 12:54:42 -060058{
59 char *addr = (char *)(event + hist_field->field->offset);
60
61 return (u64)(unsigned long)addr;
62}
63
Tom Zanussifbd302c2018-01-15 20:51:43 -060064static u64 hist_field_dynstring(struct hist_field *hist_field, void *event,
65 struct ring_buffer_event *rbe)
Namhyung Kim79e577c2016-03-03 12:54:53 -060066{
67 u32 str_item = *(u32 *)(event + hist_field->field->offset);
68 int str_loc = str_item & 0xffff;
69 char *addr = (char *)(event + str_loc);
70
71 return (u64)(unsigned long)addr;
72}
73
Tom Zanussifbd302c2018-01-15 20:51:43 -060074static u64 hist_field_pstring(struct hist_field *hist_field, void *event,
75 struct ring_buffer_event *rbe)
Namhyung Kim79e577c2016-03-03 12:54:53 -060076{
77 char **addr = (char **)(event + hist_field->field->offset);
78
79 return (u64)(unsigned long)*addr;
80}
81
Tom Zanussifbd302c2018-01-15 20:51:43 -060082static u64 hist_field_log2(struct hist_field *hist_field, void *event,
83 struct ring_buffer_event *rbe)
Namhyung Kim4b94f5b2016-03-03 12:55:02 -060084{
Tom Zanussi5819ead2017-09-22 14:58:23 -050085 struct hist_field *operand = hist_field->operands[0];
86
Tom Zanussifbd302c2018-01-15 20:51:43 -060087 u64 val = operand->fn(operand, event, rbe);
Namhyung Kim4b94f5b2016-03-03 12:55:02 -060088
89 return (u64) ilog2(roundup_pow_of_two(val));
90}
91
Tom Zanussiad42feb2018-01-15 20:51:45 -060092static u64 hist_field_timestamp(struct hist_field *hist_field, void *event,
93 struct ring_buffer_event *rbe)
94{
95 return ring_buffer_event_time_stamp(rbe);
96}
97
Tom Zanussi7ef224d2016-03-03 12:54:42 -060098#define DEFINE_HIST_FIELD_FN(type) \
Tom Zanussifbd302c2018-01-15 20:51:43 -060099 static u64 hist_field_##type(struct hist_field *hist_field, \
100 void *event, \
101 struct ring_buffer_event *rbe) \
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600102{ \
103 type *addr = (type *)(event + hist_field->field->offset); \
104 \
Namhyung Kim79e577c2016-03-03 12:54:53 -0600105 return (u64)(unsigned long)*addr; \
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600106}
107
108DEFINE_HIST_FIELD_FN(s64);
109DEFINE_HIST_FIELD_FN(u64);
110DEFINE_HIST_FIELD_FN(s32);
111DEFINE_HIST_FIELD_FN(u32);
112DEFINE_HIST_FIELD_FN(s16);
113DEFINE_HIST_FIELD_FN(u16);
114DEFINE_HIST_FIELD_FN(s8);
115DEFINE_HIST_FIELD_FN(u8);
116
117#define for_each_hist_field(i, hist_data) \
118 for ((i) = 0; (i) < (hist_data)->n_fields; (i)++)
119
120#define for_each_hist_val_field(i, hist_data) \
121 for ((i) = 0; (i) < (hist_data)->n_vals; (i)++)
122
123#define for_each_hist_key_field(i, hist_data) \
124 for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++)
125
Tom Zanussi69a02002016-03-03 12:54:52 -0600126#define HIST_STACKTRACE_DEPTH 16
127#define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
128#define HIST_STACKTRACE_SKIP 5
129
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600130#define HITCOUNT_IDX 0
Tom Zanussi69a02002016-03-03 12:54:52 -0600131#define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE)
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600132
133enum hist_field_flags {
Tom Zanussi0d7a8322017-09-22 14:58:21 -0500134 HIST_FIELD_FL_HITCOUNT = 1 << 0,
135 HIST_FIELD_FL_KEY = 1 << 1,
136 HIST_FIELD_FL_STRING = 1 << 2,
137 HIST_FIELD_FL_HEX = 1 << 3,
138 HIST_FIELD_FL_SYM = 1 << 4,
139 HIST_FIELD_FL_SYM_OFFSET = 1 << 5,
140 HIST_FIELD_FL_EXECNAME = 1 << 6,
141 HIST_FIELD_FL_SYSCALL = 1 << 7,
142 HIST_FIELD_FL_STACKTRACE = 1 << 8,
143 HIST_FIELD_FL_LOG2 = 1 << 9,
Tom Zanussiad42feb2018-01-15 20:51:45 -0600144 HIST_FIELD_FL_TIMESTAMP = 1 << 10,
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600145};
146
147struct hist_trigger_attrs {
148 char *keys_str;
Tom Zanussif2606832016-03-03 12:54:43 -0600149 char *vals_str;
Tom Zanussie62347d2016-03-03 12:54:45 -0600150 char *sort_key_str;
Tom Zanussi5463bfd2016-03-03 12:54:59 -0600151 char *name;
Tom Zanussi83e99912016-03-03 12:54:46 -0600152 bool pause;
153 bool cont;
Tom Zanussie86ae9b2016-03-03 12:54:47 -0600154 bool clear;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600155 unsigned int map_bits;
156};
157
158struct hist_trigger_data {
159 struct hist_field *fields[TRACING_MAP_FIELDS_MAX];
160 unsigned int n_vals;
161 unsigned int n_keys;
162 unsigned int n_fields;
163 unsigned int key_size;
164 struct tracing_map_sort_key sort_keys[TRACING_MAP_SORT_KEYS_MAX];
165 unsigned int n_sort_keys;
166 struct trace_event_file *event_file;
167 struct hist_trigger_attrs *attrs;
168 struct tracing_map *map;
Tom Zanussiad42feb2018-01-15 20:51:45 -0600169 bool enable_timestamps;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600170};
171
Tom Zanussi85013252017-09-22 14:58:22 -0500172static const char *hist_field_name(struct hist_field *field,
173 unsigned int level)
174{
175 const char *field_name = "";
176
177 if (level > 1)
178 return field_name;
179
180 if (field->field)
181 field_name = field->field->name;
Tom Zanussi5819ead2017-09-22 14:58:23 -0500182 else if (field->flags & HIST_FIELD_FL_LOG2)
183 field_name = hist_field_name(field->operands[0], ++level);
Tom Zanussiad42feb2018-01-15 20:51:45 -0600184 else if (field->flags & HIST_FIELD_FL_TIMESTAMP)
185 field_name = "common_timestamp";
Tom Zanussi85013252017-09-22 14:58:22 -0500186
187 if (field_name == NULL)
188 field_name = "";
189
190 return field_name;
191}
192
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600193static hist_field_fn_t select_value_fn(int field_size, int field_is_signed)
194{
195 hist_field_fn_t fn = NULL;
196
197 switch (field_size) {
198 case 8:
199 if (field_is_signed)
200 fn = hist_field_s64;
201 else
202 fn = hist_field_u64;
203 break;
204 case 4:
205 if (field_is_signed)
206 fn = hist_field_s32;
207 else
208 fn = hist_field_u32;
209 break;
210 case 2:
211 if (field_is_signed)
212 fn = hist_field_s16;
213 else
214 fn = hist_field_u16;
215 break;
216 case 1:
217 if (field_is_signed)
218 fn = hist_field_s8;
219 else
220 fn = hist_field_u8;
221 break;
222 }
223
224 return fn;
225}
226
227static int parse_map_size(char *str)
228{
229 unsigned long size, map_bits;
230 int ret;
231
232 strsep(&str, "=");
233 if (!str) {
234 ret = -EINVAL;
235 goto out;
236 }
237
238 ret = kstrtoul(str, 0, &size);
239 if (ret)
240 goto out;
241
242 map_bits = ilog2(roundup_pow_of_two(size));
243 if (map_bits < TRACING_MAP_BITS_MIN ||
244 map_bits > TRACING_MAP_BITS_MAX)
245 ret = -EINVAL;
246 else
247 ret = map_bits;
248 out:
249 return ret;
250}
251
252static void destroy_hist_trigger_attrs(struct hist_trigger_attrs *attrs)
253{
254 if (!attrs)
255 return;
256
Tom Zanussi5463bfd2016-03-03 12:54:59 -0600257 kfree(attrs->name);
Tom Zanussie62347d2016-03-03 12:54:45 -0600258 kfree(attrs->sort_key_str);
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600259 kfree(attrs->keys_str);
Tom Zanussif2606832016-03-03 12:54:43 -0600260 kfree(attrs->vals_str);
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600261 kfree(attrs);
262}
263
Tom Zanussi9b1ae032018-01-15 20:51:44 -0600264static int parse_assignment(char *str, struct hist_trigger_attrs *attrs)
265{
266 int ret = 0;
267
268 if ((strncmp(str, "key=", strlen("key=")) == 0) ||
269 (strncmp(str, "keys=", strlen("keys=")) == 0)) {
270 attrs->keys_str = kstrdup(str, GFP_KERNEL);
271 if (!attrs->keys_str) {
272 ret = -ENOMEM;
273 goto out;
274 }
275 } else if ((strncmp(str, "val=", strlen("val=")) == 0) ||
276 (strncmp(str, "vals=", strlen("vals=")) == 0) ||
277 (strncmp(str, "values=", strlen("values=")) == 0)) {
278 attrs->vals_str = kstrdup(str, GFP_KERNEL);
279 if (!attrs->vals_str) {
280 ret = -ENOMEM;
281 goto out;
282 }
283 } else if (strncmp(str, "sort=", strlen("sort=")) == 0) {
284 attrs->sort_key_str = kstrdup(str, GFP_KERNEL);
285 if (!attrs->sort_key_str) {
286 ret = -ENOMEM;
287 goto out;
288 }
289 } else if (strncmp(str, "name=", strlen("name=")) == 0) {
290 attrs->name = kstrdup(str, GFP_KERNEL);
291 if (!attrs->name) {
292 ret = -ENOMEM;
293 goto out;
294 }
295 } else if (strncmp(str, "size=", strlen("size=")) == 0) {
296 int map_bits = parse_map_size(str);
297
298 if (map_bits < 0) {
299 ret = map_bits;
300 goto out;
301 }
302 attrs->map_bits = map_bits;
303 } else
304 ret = -EINVAL;
305 out:
306 return ret;
307}
308
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600309static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str)
310{
311 struct hist_trigger_attrs *attrs;
312 int ret = 0;
313
314 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
315 if (!attrs)
316 return ERR_PTR(-ENOMEM);
317
318 while (trigger_str) {
319 char *str = strsep(&trigger_str, ":");
320
Tom Zanussi9b1ae032018-01-15 20:51:44 -0600321 if (strchr(str, '=')) {
322 ret = parse_assignment(str, attrs);
323 if (ret)
324 goto free;
325 } else if (strcmp(str, "pause") == 0)
Tom Zanussi83e99912016-03-03 12:54:46 -0600326 attrs->pause = true;
327 else if ((strcmp(str, "cont") == 0) ||
328 (strcmp(str, "continue") == 0))
329 attrs->cont = true;
Tom Zanussie86ae9b2016-03-03 12:54:47 -0600330 else if (strcmp(str, "clear") == 0)
331 attrs->clear = true;
Tom Zanussi9b1ae032018-01-15 20:51:44 -0600332 else {
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600333 ret = -EINVAL;
334 goto free;
335 }
336 }
337
338 if (!attrs->keys_str) {
339 ret = -EINVAL;
340 goto free;
341 }
342
343 return attrs;
344 free:
345 destroy_hist_trigger_attrs(attrs);
346
347 return ERR_PTR(ret);
348}
349
Tom Zanussi6b4827a2016-03-03 12:54:50 -0600350static inline void save_comm(char *comm, struct task_struct *task)
351{
352 if (!task->pid) {
353 strcpy(comm, "<idle>");
354 return;
355 }
356
357 if (WARN_ON_ONCE(task->pid < 0)) {
358 strcpy(comm, "<XXX>");
359 return;
360 }
361
362 memcpy(comm, task->comm, TASK_COMM_LEN);
363}
364
365static void hist_trigger_elt_comm_free(struct tracing_map_elt *elt)
366{
367 kfree((char *)elt->private_data);
368}
369
370static int hist_trigger_elt_comm_alloc(struct tracing_map_elt *elt)
371{
372 struct hist_trigger_data *hist_data = elt->map->private_data;
373 struct hist_field *key_field;
374 unsigned int i;
375
376 for_each_hist_key_field(i, hist_data) {
377 key_field = hist_data->fields[i];
378
379 if (key_field->flags & HIST_FIELD_FL_EXECNAME) {
380 unsigned int size = TASK_COMM_LEN + 1;
381
382 elt->private_data = kzalloc(size, GFP_KERNEL);
383 if (!elt->private_data)
384 return -ENOMEM;
385 break;
386 }
387 }
388
389 return 0;
390}
391
Tom Zanussi6b4827a2016-03-03 12:54:50 -0600392static void hist_trigger_elt_comm_init(struct tracing_map_elt *elt)
393{
394 char *comm = elt->private_data;
395
396 if (comm)
397 save_comm(comm, current);
398}
399
400static const struct tracing_map_ops hist_trigger_elt_comm_ops = {
401 .elt_alloc = hist_trigger_elt_comm_alloc,
Tom Zanussi6b4827a2016-03-03 12:54:50 -0600402 .elt_free = hist_trigger_elt_comm_free,
403 .elt_init = hist_trigger_elt_comm_init,
404};
405
Tom Zanussi5819ead2017-09-22 14:58:23 -0500406static void destroy_hist_field(struct hist_field *hist_field,
407 unsigned int level)
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600408{
Tom Zanussi5819ead2017-09-22 14:58:23 -0500409 unsigned int i;
410
411 if (level > 2)
412 return;
413
414 if (!hist_field)
415 return;
416
417 for (i = 0; i < HIST_FIELD_OPERANDS_MAX; i++)
418 destroy_hist_field(hist_field->operands[i], level + 1);
419
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600420 kfree(hist_field);
421}
422
423static struct hist_field *create_hist_field(struct ftrace_event_field *field,
424 unsigned long flags)
425{
426 struct hist_field *hist_field;
427
428 if (field && is_function_field(field))
429 return NULL;
430
431 hist_field = kzalloc(sizeof(struct hist_field), GFP_KERNEL);
432 if (!hist_field)
433 return NULL;
434
435 if (flags & HIST_FIELD_FL_HITCOUNT) {
436 hist_field->fn = hist_field_counter;
437 goto out;
438 }
439
Tom Zanussi69a02002016-03-03 12:54:52 -0600440 if (flags & HIST_FIELD_FL_STACKTRACE) {
441 hist_field->fn = hist_field_none;
442 goto out;
443 }
444
Namhyung Kim4b94f5b2016-03-03 12:55:02 -0600445 if (flags & HIST_FIELD_FL_LOG2) {
Tom Zanussi5819ead2017-09-22 14:58:23 -0500446 unsigned long fl = flags & ~HIST_FIELD_FL_LOG2;
Namhyung Kim4b94f5b2016-03-03 12:55:02 -0600447 hist_field->fn = hist_field_log2;
Tom Zanussi5819ead2017-09-22 14:58:23 -0500448 hist_field->operands[0] = create_hist_field(field, fl);
449 hist_field->size = hist_field->operands[0]->size;
Namhyung Kim4b94f5b2016-03-03 12:55:02 -0600450 goto out;
451 }
452
Tom Zanussiad42feb2018-01-15 20:51:45 -0600453 if (flags & HIST_FIELD_FL_TIMESTAMP) {
454 hist_field->fn = hist_field_timestamp;
455 hist_field->size = sizeof(u64);
456 goto out;
457 }
458
Tom Zanussi432480c2016-04-25 14:01:27 -0500459 if (WARN_ON_ONCE(!field))
460 goto out;
461
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600462 if (is_string_field(field)) {
463 flags |= HIST_FIELD_FL_STRING;
Namhyung Kim79e577c2016-03-03 12:54:53 -0600464
465 if (field->filter_type == FILTER_STATIC_STRING)
466 hist_field->fn = hist_field_string;
467 else if (field->filter_type == FILTER_DYN_STRING)
468 hist_field->fn = hist_field_dynstring;
469 else
470 hist_field->fn = hist_field_pstring;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600471 } else {
472 hist_field->fn = select_value_fn(field->size,
473 field->is_signed);
474 if (!hist_field->fn) {
Tom Zanussi5819ead2017-09-22 14:58:23 -0500475 destroy_hist_field(hist_field, 0);
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600476 return NULL;
477 }
478 }
479 out:
480 hist_field->field = field;
481 hist_field->flags = flags;
482
483 return hist_field;
484}
485
486static void destroy_hist_fields(struct hist_trigger_data *hist_data)
487{
488 unsigned int i;
489
490 for (i = 0; i < TRACING_MAP_FIELDS_MAX; i++) {
491 if (hist_data->fields[i]) {
Tom Zanussi5819ead2017-09-22 14:58:23 -0500492 destroy_hist_field(hist_data->fields[i], 0);
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600493 hist_data->fields[i] = NULL;
494 }
495 }
496}
497
498static int create_hitcount_val(struct hist_trigger_data *hist_data)
499{
500 hist_data->fields[HITCOUNT_IDX] =
501 create_hist_field(NULL, HIST_FIELD_FL_HITCOUNT);
502 if (!hist_data->fields[HITCOUNT_IDX])
503 return -ENOMEM;
504
505 hist_data->n_vals++;
506
507 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
508 return -EINVAL;
509
510 return 0;
511}
512
Tom Zanussif2606832016-03-03 12:54:43 -0600513static int create_val_field(struct hist_trigger_data *hist_data,
514 unsigned int val_idx,
515 struct trace_event_file *file,
516 char *field_str)
517{
518 struct ftrace_event_field *field = NULL;
519 unsigned long flags = 0;
Tom Zanussi0c4a6b42016-03-03 12:54:48 -0600520 char *field_name;
Tom Zanussif2606832016-03-03 12:54:43 -0600521 int ret = 0;
522
523 if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX))
524 return -EINVAL;
Tom Zanussi0c4a6b42016-03-03 12:54:48 -0600525
526 field_name = strsep(&field_str, ".");
527 if (field_str) {
528 if (strcmp(field_str, "hex") == 0)
529 flags |= HIST_FIELD_FL_HEX;
530 else {
531 ret = -EINVAL;
532 goto out;
533 }
534 }
535
Tom Zanussiad42feb2018-01-15 20:51:45 -0600536 if (strcmp(field_name, "common_timestamp") == 0) {
537 flags |= HIST_FIELD_FL_TIMESTAMP;
538 hist_data->enable_timestamps = true;
539 } else {
540 field = trace_find_event_field(file->event_call, field_name);
541 if (!field || !field->size) {
542 ret = -EINVAL;
543 goto out;
544 }
Tom Zanussif2606832016-03-03 12:54:43 -0600545 }
546
547 hist_data->fields[val_idx] = create_hist_field(field, flags);
548 if (!hist_data->fields[val_idx]) {
549 ret = -ENOMEM;
550 goto out;
551 }
552
553 ++hist_data->n_vals;
554
555 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
556 ret = -EINVAL;
557 out:
558 return ret;
559}
560
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600561static int create_val_fields(struct hist_trigger_data *hist_data,
562 struct trace_event_file *file)
563{
Tom Zanussif2606832016-03-03 12:54:43 -0600564 char *fields_str, *field_str;
565 unsigned int i, j;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600566 int ret;
567
568 ret = create_hitcount_val(hist_data);
Tom Zanussif2606832016-03-03 12:54:43 -0600569 if (ret)
570 goto out;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600571
Tom Zanussif2606832016-03-03 12:54:43 -0600572 fields_str = hist_data->attrs->vals_str;
573 if (!fields_str)
574 goto out;
575
576 strsep(&fields_str, "=");
577 if (!fields_str)
578 goto out;
579
580 for (i = 0, j = 1; i < TRACING_MAP_VALS_MAX &&
581 j < TRACING_MAP_VALS_MAX; i++) {
582 field_str = strsep(&fields_str, ",");
583 if (!field_str)
584 break;
585 if (strcmp(field_str, "hitcount") == 0)
586 continue;
587 ret = create_val_field(hist_data, j++, file, field_str);
588 if (ret)
589 goto out;
590 }
591 if (fields_str && (strcmp(fields_str, "hitcount") != 0))
592 ret = -EINVAL;
593 out:
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600594 return ret;
595}
596
597static int create_key_field(struct hist_trigger_data *hist_data,
598 unsigned int key_idx,
Tom Zanussi76a3b0c2016-03-03 12:54:44 -0600599 unsigned int key_offset,
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600600 struct trace_event_file *file,
601 char *field_str)
602{
603 struct ftrace_event_field *field = NULL;
604 unsigned long flags = 0;
605 unsigned int key_size;
606 int ret = 0;
607
608 if (WARN_ON(key_idx >= TRACING_MAP_FIELDS_MAX))
609 return -EINVAL;
610
611 flags |= HIST_FIELD_FL_KEY;
612
Tom Zanussi69a02002016-03-03 12:54:52 -0600613 if (strcmp(field_str, "stacktrace") == 0) {
614 flags |= HIST_FIELD_FL_STACKTRACE;
615 key_size = sizeof(unsigned long) * HIST_STACKTRACE_DEPTH;
616 } else {
617 char *field_name = strsep(&field_str, ".");
618
619 if (field_str) {
620 if (strcmp(field_str, "hex") == 0)
621 flags |= HIST_FIELD_FL_HEX;
622 else if (strcmp(field_str, "sym") == 0)
623 flags |= HIST_FIELD_FL_SYM;
624 else if (strcmp(field_str, "sym-offset") == 0)
625 flags |= HIST_FIELD_FL_SYM_OFFSET;
626 else if ((strcmp(field_str, "execname") == 0) &&
627 (strcmp(field_name, "common_pid") == 0))
628 flags |= HIST_FIELD_FL_EXECNAME;
629 else if (strcmp(field_str, "syscall") == 0)
630 flags |= HIST_FIELD_FL_SYSCALL;
Namhyung Kim4b94f5b2016-03-03 12:55:02 -0600631 else if (strcmp(field_str, "log2") == 0)
632 flags |= HIST_FIELD_FL_LOG2;
Tom Zanussi69a02002016-03-03 12:54:52 -0600633 else {
634 ret = -EINVAL;
635 goto out;
636 }
637 }
638
Tom Zanussiad42feb2018-01-15 20:51:45 -0600639 if (strcmp(field_name, "common_timestamp") == 0) {
640 flags |= HIST_FIELD_FL_TIMESTAMP;
641 hist_data->enable_timestamps = true;
642 key_size = sizeof(u64);
643 } else {
644 field = trace_find_event_field(file->event_call, field_name);
645 if (!field || !field->size) {
646 ret = -EINVAL;
647 goto out;
648 }
Tom Zanussi0c4a6b42016-03-03 12:54:48 -0600649
Tom Zanussiad42feb2018-01-15 20:51:45 -0600650 if (is_string_field(field))
651 key_size = MAX_FILTER_STR_VAL;
652 else
653 key_size = field->size;
654 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600655 }
656
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600657 hist_data->fields[key_idx] = create_hist_field(field, flags);
658 if (!hist_data->fields[key_idx]) {
659 ret = -ENOMEM;
660 goto out;
661 }
662
663 key_size = ALIGN(key_size, sizeof(u64));
664 hist_data->fields[key_idx]->size = key_size;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -0600665 hist_data->fields[key_idx]->offset = key_offset;
666 hist_data->key_size += key_size;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600667 if (hist_data->key_size > HIST_KEY_SIZE_MAX) {
668 ret = -EINVAL;
669 goto out;
670 }
671
672 hist_data->n_keys++;
673
674 if (WARN_ON(hist_data->n_keys > TRACING_MAP_KEYS_MAX))
675 return -EINVAL;
676
677 ret = key_size;
678 out:
679 return ret;
680}
681
682static int create_key_fields(struct hist_trigger_data *hist_data,
683 struct trace_event_file *file)
684{
Tom Zanussi76a3b0c2016-03-03 12:54:44 -0600685 unsigned int i, key_offset = 0, n_vals = hist_data->n_vals;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600686 char *fields_str, *field_str;
687 int ret = -EINVAL;
688
689 fields_str = hist_data->attrs->keys_str;
690 if (!fields_str)
691 goto out;
692
693 strsep(&fields_str, "=");
694 if (!fields_str)
695 goto out;
696
Tom Zanussi76a3b0c2016-03-03 12:54:44 -0600697 for (i = n_vals; i < n_vals + TRACING_MAP_KEYS_MAX; i++) {
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600698 field_str = strsep(&fields_str, ",");
699 if (!field_str)
700 break;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -0600701 ret = create_key_field(hist_data, i, key_offset,
702 file, field_str);
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600703 if (ret < 0)
704 goto out;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -0600705 key_offset += ret;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600706 }
707 if (fields_str) {
708 ret = -EINVAL;
709 goto out;
710 }
711 ret = 0;
712 out:
713 return ret;
714}
715
716static int create_hist_fields(struct hist_trigger_data *hist_data,
717 struct trace_event_file *file)
718{
719 int ret;
720
721 ret = create_val_fields(hist_data, file);
722 if (ret)
723 goto out;
724
725 ret = create_key_fields(hist_data, file);
726 if (ret)
727 goto out;
728
729 hist_data->n_fields = hist_data->n_vals + hist_data->n_keys;
730 out:
731 return ret;
732}
733
Tom Zanussie62347d2016-03-03 12:54:45 -0600734static int is_descending(const char *str)
735{
736 if (!str)
737 return 0;
738
739 if (strcmp(str, "descending") == 0)
740 return 1;
741
742 if (strcmp(str, "ascending") == 0)
743 return 0;
744
745 return -EINVAL;
746}
747
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600748static int create_sort_keys(struct hist_trigger_data *hist_data)
749{
Tom Zanussie62347d2016-03-03 12:54:45 -0600750 char *fields_str = hist_data->attrs->sort_key_str;
Tom Zanussie62347d2016-03-03 12:54:45 -0600751 struct tracing_map_sort_key *sort_key;
752 int descending, ret = 0;
753 unsigned int i, j;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600754
Tom Zanussie62347d2016-03-03 12:54:45 -0600755 hist_data->n_sort_keys = 1; /* we always have at least one, hitcount */
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600756
Tom Zanussie62347d2016-03-03 12:54:45 -0600757 if (!fields_str)
758 goto out;
759
760 strsep(&fields_str, "=");
761 if (!fields_str) {
762 ret = -EINVAL;
763 goto out;
764 }
765
766 for (i = 0; i < TRACING_MAP_SORT_KEYS_MAX; i++) {
Tom Zanussi85013252017-09-22 14:58:22 -0500767 struct hist_field *hist_field;
Tom Zanussie62347d2016-03-03 12:54:45 -0600768 char *field_str, *field_name;
Tom Zanussi85013252017-09-22 14:58:22 -0500769 const char *test_name;
Tom Zanussie62347d2016-03-03 12:54:45 -0600770
771 sort_key = &hist_data->sort_keys[i];
772
773 field_str = strsep(&fields_str, ",");
774 if (!field_str) {
775 if (i == 0)
776 ret = -EINVAL;
777 break;
778 }
779
780 if ((i == TRACING_MAP_SORT_KEYS_MAX - 1) && fields_str) {
781 ret = -EINVAL;
782 break;
783 }
784
785 field_name = strsep(&field_str, ".");
786 if (!field_name) {
787 ret = -EINVAL;
788 break;
789 }
790
791 if (strcmp(field_name, "hitcount") == 0) {
792 descending = is_descending(field_str);
793 if (descending < 0) {
794 ret = descending;
795 break;
796 }
797 sort_key->descending = descending;
798 continue;
799 }
800
801 for (j = 1; j < hist_data->n_fields; j++) {
Tom Zanussi85013252017-09-22 14:58:22 -0500802 hist_field = hist_data->fields[j];
803 test_name = hist_field_name(hist_field, 0);
804
805 if (strcmp(field_name, test_name) == 0) {
Tom Zanussie62347d2016-03-03 12:54:45 -0600806 sort_key->field_idx = j;
807 descending = is_descending(field_str);
808 if (descending < 0) {
809 ret = descending;
810 goto out;
811 }
812 sort_key->descending = descending;
813 break;
814 }
815 }
816 if (j == hist_data->n_fields) {
817 ret = -EINVAL;
818 break;
819 }
820 }
821 hist_data->n_sort_keys = i;
822 out:
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600823 return ret;
824}
825
826static void destroy_hist_data(struct hist_trigger_data *hist_data)
827{
828 destroy_hist_trigger_attrs(hist_data->attrs);
829 destroy_hist_fields(hist_data);
830 tracing_map_destroy(hist_data->map);
831 kfree(hist_data);
832}
833
834static int create_tracing_map_fields(struct hist_trigger_data *hist_data)
835{
836 struct tracing_map *map = hist_data->map;
837 struct ftrace_event_field *field;
838 struct hist_field *hist_field;
Steven Rostedt (Red Hat)d50c7442016-03-08 17:17:15 -0500839 int i, idx;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600840
841 for_each_hist_field(i, hist_data) {
842 hist_field = hist_data->fields[i];
843 if (hist_field->flags & HIST_FIELD_FL_KEY) {
844 tracing_map_cmp_fn_t cmp_fn;
845
846 field = hist_field->field;
847
Tom Zanussi69a02002016-03-03 12:54:52 -0600848 if (hist_field->flags & HIST_FIELD_FL_STACKTRACE)
849 cmp_fn = tracing_map_cmp_none;
Tom Zanussiad42feb2018-01-15 20:51:45 -0600850 else if (!field)
851 cmp_fn = tracing_map_cmp_num(hist_field->size,
852 hist_field->is_signed);
Tom Zanussi69a02002016-03-03 12:54:52 -0600853 else if (is_string_field(field))
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600854 cmp_fn = tracing_map_cmp_string;
855 else
856 cmp_fn = tracing_map_cmp_num(field->size,
857 field->is_signed);
Tom Zanussi76a3b0c2016-03-03 12:54:44 -0600858 idx = tracing_map_add_key_field(map,
859 hist_field->offset,
860 cmp_fn);
861
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600862 } else
863 idx = tracing_map_add_sum_field(map);
864
865 if (idx < 0)
866 return idx;
867 }
868
869 return 0;
870}
871
Tom Zanussi6b4827a2016-03-03 12:54:50 -0600872static bool need_tracing_map_ops(struct hist_trigger_data *hist_data)
873{
874 struct hist_field *key_field;
875 unsigned int i;
876
877 for_each_hist_key_field(i, hist_data) {
878 key_field = hist_data->fields[i];
879
880 if (key_field->flags & HIST_FIELD_FL_EXECNAME)
881 return true;
882 }
883
884 return false;
885}
886
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600887static struct hist_trigger_data *
888create_hist_data(unsigned int map_bits,
889 struct hist_trigger_attrs *attrs,
890 struct trace_event_file *file)
891{
Tom Zanussi6b4827a2016-03-03 12:54:50 -0600892 const struct tracing_map_ops *map_ops = NULL;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600893 struct hist_trigger_data *hist_data;
894 int ret = 0;
895
896 hist_data = kzalloc(sizeof(*hist_data), GFP_KERNEL);
897 if (!hist_data)
898 return ERR_PTR(-ENOMEM);
899
900 hist_data->attrs = attrs;
901
902 ret = create_hist_fields(hist_data, file);
903 if (ret)
904 goto free;
905
906 ret = create_sort_keys(hist_data);
907 if (ret)
908 goto free;
909
Tom Zanussi6b4827a2016-03-03 12:54:50 -0600910 if (need_tracing_map_ops(hist_data))
911 map_ops = &hist_trigger_elt_comm_ops;
912
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600913 hist_data->map = tracing_map_create(map_bits, hist_data->key_size,
Tom Zanussi6b4827a2016-03-03 12:54:50 -0600914 map_ops, hist_data);
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600915 if (IS_ERR(hist_data->map)) {
916 ret = PTR_ERR(hist_data->map);
917 hist_data->map = NULL;
918 goto free;
919 }
920
921 ret = create_tracing_map_fields(hist_data);
922 if (ret)
923 goto free;
924
925 ret = tracing_map_init(hist_data->map);
926 if (ret)
927 goto free;
928
929 hist_data->event_file = file;
930 out:
931 return hist_data;
932 free:
933 hist_data->attrs = NULL;
934
935 destroy_hist_data(hist_data);
936
937 hist_data = ERR_PTR(ret);
938
939 goto out;
940}
941
942static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
Tom Zanussifbd302c2018-01-15 20:51:43 -0600943 struct tracing_map_elt *elt, void *rec,
944 struct ring_buffer_event *rbe)
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600945{
946 struct hist_field *hist_field;
947 unsigned int i;
948 u64 hist_val;
949
950 for_each_hist_val_field(i, hist_data) {
951 hist_field = hist_data->fields[i];
Tom Zanussifbd302c2018-01-15 20:51:43 -0600952 hist_val = hist_field->fn(hist_field, rec, rbe);
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600953 tracing_map_update_sum(elt, i, hist_val);
954 }
955}
956
Tom Zanussi6a475cb2016-03-03 12:54:54 -0600957static inline void add_to_key(char *compound_key, void *key,
958 struct hist_field *key_field, void *rec)
959{
960 size_t size = key_field->size;
961
962 if (key_field->flags & HIST_FIELD_FL_STRING) {
963 struct ftrace_event_field *field;
964
965 field = key_field->field;
966 if (field->filter_type == FILTER_DYN_STRING)
967 size = *(u32 *)(rec + field->offset) >> 16;
968 else if (field->filter_type == FILTER_PTR_STRING)
969 size = strlen(key);
970 else if (field->filter_type == FILTER_STATIC_STRING)
971 size = field->size;
972
973 /* ensure NULL-termination */
974 if (size > key_field->size - 1)
975 size = key_field->size - 1;
976 }
977
978 memcpy(compound_key + key_field->offset, key, size);
979}
980
Tom Zanussi1ac4f512018-01-15 20:51:42 -0600981static void event_hist_trigger(struct event_trigger_data *data, void *rec,
Tom Zanussifbd302c2018-01-15 20:51:43 -0600982 struct ring_buffer_event *rbe)
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600983{
984 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussi6a475cb2016-03-03 12:54:54 -0600985 bool use_compound_key = (hist_data->n_keys > 1);
Tom Zanussi69a02002016-03-03 12:54:52 -0600986 unsigned long entries[HIST_STACKTRACE_DEPTH];
Tom Zanussi76a3b0c2016-03-03 12:54:44 -0600987 char compound_key[HIST_KEY_SIZE_MAX];
Tom Zanussi69a02002016-03-03 12:54:52 -0600988 struct stack_trace stacktrace;
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600989 struct hist_field *key_field;
990 struct tracing_map_elt *elt;
991 u64 field_contents;
992 void *key = NULL;
993 unsigned int i;
994
Tom Zanussi6a475cb2016-03-03 12:54:54 -0600995 memset(compound_key, 0, hist_data->key_size);
Tom Zanussi76a3b0c2016-03-03 12:54:44 -0600996
Tom Zanussi7ef224d2016-03-03 12:54:42 -0600997 for_each_hist_key_field(i, hist_data) {
998 key_field = hist_data->fields[i];
999
Tom Zanussi69a02002016-03-03 12:54:52 -06001000 if (key_field->flags & HIST_FIELD_FL_STACKTRACE) {
1001 stacktrace.max_entries = HIST_STACKTRACE_DEPTH;
1002 stacktrace.entries = entries;
1003 stacktrace.nr_entries = 0;
1004 stacktrace.skip = HIST_STACKTRACE_SKIP;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06001005
Tom Zanussi69a02002016-03-03 12:54:52 -06001006 memset(stacktrace.entries, 0, HIST_STACKTRACE_SIZE);
1007 save_stack_trace(&stacktrace);
1008
1009 key = entries;
1010 } else {
Tom Zanussifbd302c2018-01-15 20:51:43 -06001011 field_contents = key_field->fn(key_field, rec, rbe);
Tom Zanussi6a475cb2016-03-03 12:54:54 -06001012 if (key_field->flags & HIST_FIELD_FL_STRING) {
Tom Zanussi69a02002016-03-03 12:54:52 -06001013 key = (void *)(unsigned long)field_contents;
Tom Zanussi6a475cb2016-03-03 12:54:54 -06001014 use_compound_key = true;
1015 } else
Tom Zanussi69a02002016-03-03 12:54:52 -06001016 key = (void *)&field_contents;
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06001017 }
Tom Zanussi6a475cb2016-03-03 12:54:54 -06001018
1019 if (use_compound_key)
1020 add_to_key(compound_key, key, key_field, rec);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001021 }
1022
Tom Zanussi6a475cb2016-03-03 12:54:54 -06001023 if (use_compound_key)
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06001024 key = compound_key;
1025
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001026 elt = tracing_map_insert(hist_data->map, key);
1027 if (elt)
Tom Zanussifbd302c2018-01-15 20:51:43 -06001028 hist_trigger_elt_update(hist_data, elt, rec, rbe);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001029}
1030
Tom Zanussi69a02002016-03-03 12:54:52 -06001031static void hist_trigger_stacktrace_print(struct seq_file *m,
1032 unsigned long *stacktrace_entries,
1033 unsigned int max_entries)
1034{
1035 char str[KSYM_SYMBOL_LEN];
1036 unsigned int spaces = 8;
1037 unsigned int i;
1038
1039 for (i = 0; i < max_entries; i++) {
1040 if (stacktrace_entries[i] == ULONG_MAX)
1041 return;
1042
1043 seq_printf(m, "%*c", 1 + spaces, ' ');
1044 sprint_symbol(str, stacktrace_entries[i]);
1045 seq_printf(m, "%s\n", str);
1046 }
1047}
1048
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001049static void
1050hist_trigger_entry_print(struct seq_file *m,
1051 struct hist_trigger_data *hist_data, void *key,
1052 struct tracing_map_elt *elt)
1053{
1054 struct hist_field *key_field;
Tom Zanussic6afad42016-03-03 12:54:49 -06001055 char str[KSYM_SYMBOL_LEN];
Tom Zanussi69a02002016-03-03 12:54:52 -06001056 bool multiline = false;
Tom Zanussi85013252017-09-22 14:58:22 -05001057 const char *field_name;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001058 unsigned int i;
1059 u64 uval;
1060
1061 seq_puts(m, "{ ");
1062
1063 for_each_hist_key_field(i, hist_data) {
1064 key_field = hist_data->fields[i];
1065
1066 if (i > hist_data->n_vals)
1067 seq_puts(m, ", ");
1068
Tom Zanussi85013252017-09-22 14:58:22 -05001069 field_name = hist_field_name(key_field, 0);
1070
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06001071 if (key_field->flags & HIST_FIELD_FL_HEX) {
1072 uval = *(u64 *)(key + key_field->offset);
Tom Zanussi85013252017-09-22 14:58:22 -05001073 seq_printf(m, "%s: %llx", field_name, uval);
Tom Zanussic6afad42016-03-03 12:54:49 -06001074 } else if (key_field->flags & HIST_FIELD_FL_SYM) {
1075 uval = *(u64 *)(key + key_field->offset);
1076 sprint_symbol_no_offset(str, uval);
Tom Zanussi85013252017-09-22 14:58:22 -05001077 seq_printf(m, "%s: [%llx] %-45s", field_name,
1078 uval, str);
Tom Zanussic6afad42016-03-03 12:54:49 -06001079 } else if (key_field->flags & HIST_FIELD_FL_SYM_OFFSET) {
1080 uval = *(u64 *)(key + key_field->offset);
1081 sprint_symbol(str, uval);
Tom Zanussi85013252017-09-22 14:58:22 -05001082 seq_printf(m, "%s: [%llx] %-55s", field_name,
1083 uval, str);
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001084 } else if (key_field->flags & HIST_FIELD_FL_EXECNAME) {
1085 char *comm = elt->private_data;
1086
1087 uval = *(u64 *)(key + key_field->offset);
Tom Zanussi85013252017-09-22 14:58:22 -05001088 seq_printf(m, "%s: %-16s[%10llu]", field_name,
1089 comm, uval);
Tom Zanussi31696192016-03-03 12:54:51 -06001090 } else if (key_field->flags & HIST_FIELD_FL_SYSCALL) {
1091 const char *syscall_name;
1092
1093 uval = *(u64 *)(key + key_field->offset);
1094 syscall_name = get_syscall_name(uval);
1095 if (!syscall_name)
1096 syscall_name = "unknown_syscall";
1097
Tom Zanussi85013252017-09-22 14:58:22 -05001098 seq_printf(m, "%s: %-30s[%3llu]", field_name,
1099 syscall_name, uval);
Tom Zanussi69a02002016-03-03 12:54:52 -06001100 } else if (key_field->flags & HIST_FIELD_FL_STACKTRACE) {
1101 seq_puts(m, "stacktrace:\n");
1102 hist_trigger_stacktrace_print(m,
1103 key + key_field->offset,
1104 HIST_STACKTRACE_DEPTH);
1105 multiline = true;
Namhyung Kim4b94f5b2016-03-03 12:55:02 -06001106 } else if (key_field->flags & HIST_FIELD_FL_LOG2) {
Tom Zanussi85013252017-09-22 14:58:22 -05001107 seq_printf(m, "%s: ~ 2^%-2llu", field_name,
Namhyung Kim4b94f5b2016-03-03 12:55:02 -06001108 *(u64 *)(key + key_field->offset));
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06001109 } else if (key_field->flags & HIST_FIELD_FL_STRING) {
Tom Zanussi85013252017-09-22 14:58:22 -05001110 seq_printf(m, "%s: %-50s", field_name,
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06001111 (char *)(key + key_field->offset));
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001112 } else {
Tom Zanussi76a3b0c2016-03-03 12:54:44 -06001113 uval = *(u64 *)(key + key_field->offset);
Tom Zanussi85013252017-09-22 14:58:22 -05001114 seq_printf(m, "%s: %10llu", field_name, uval);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001115 }
1116 }
1117
Tom Zanussi69a02002016-03-03 12:54:52 -06001118 if (!multiline)
1119 seq_puts(m, " ");
1120
1121 seq_puts(m, "}");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001122
1123 seq_printf(m, " hitcount: %10llu",
1124 tracing_map_read_sum(elt, HITCOUNT_IDX));
1125
Tom Zanussif2606832016-03-03 12:54:43 -06001126 for (i = 1; i < hist_data->n_vals; i++) {
Tom Zanussi85013252017-09-22 14:58:22 -05001127 field_name = hist_field_name(hist_data->fields[i], 0);
1128
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06001129 if (hist_data->fields[i]->flags & HIST_FIELD_FL_HEX) {
Tom Zanussi85013252017-09-22 14:58:22 -05001130 seq_printf(m, " %s: %10llx", field_name,
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06001131 tracing_map_read_sum(elt, i));
1132 } else {
Tom Zanussi85013252017-09-22 14:58:22 -05001133 seq_printf(m, " %s: %10llu", field_name,
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06001134 tracing_map_read_sum(elt, i));
1135 }
Tom Zanussif2606832016-03-03 12:54:43 -06001136 }
1137
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001138 seq_puts(m, "\n");
1139}
1140
1141static int print_entries(struct seq_file *m,
1142 struct hist_trigger_data *hist_data)
1143{
1144 struct tracing_map_sort_entry **sort_entries = NULL;
1145 struct tracing_map *map = hist_data->map;
Steven Rostedt (Red Hat)d50c7442016-03-08 17:17:15 -05001146 int i, n_entries;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001147
1148 n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
1149 hist_data->n_sort_keys,
1150 &sort_entries);
1151 if (n_entries < 0)
1152 return n_entries;
1153
1154 for (i = 0; i < n_entries; i++)
1155 hist_trigger_entry_print(m, hist_data,
1156 sort_entries[i]->key,
1157 sort_entries[i]->elt);
1158
1159 tracing_map_destroy_sort_entries(sort_entries, n_entries);
1160
1161 return n_entries;
1162}
1163
Tom Zanussi52a7f162016-03-03 12:54:57 -06001164static void hist_trigger_show(struct seq_file *m,
1165 struct event_trigger_data *data, int n)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001166{
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001167 struct hist_trigger_data *hist_data;
Colin Ian King6e7a2392017-08-23 12:23:09 +01001168 int n_entries;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001169
Tom Zanussi52a7f162016-03-03 12:54:57 -06001170 if (n > 0)
1171 seq_puts(m, "\n\n");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001172
1173 seq_puts(m, "# event histogram\n#\n# trigger info: ");
1174 data->ops->print(m, data->ops, data);
Tom Zanussi52a7f162016-03-03 12:54:57 -06001175 seq_puts(m, "#\n\n");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001176
1177 hist_data = data->private_data;
1178 n_entries = print_entries(m, hist_data);
Colin Ian King6e7a2392017-08-23 12:23:09 +01001179 if (n_entries < 0)
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001180 n_entries = 0;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001181
1182 seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n",
1183 (u64)atomic64_read(&hist_data->map->hits),
1184 n_entries, (u64)atomic64_read(&hist_data->map->drops));
Tom Zanussi52a7f162016-03-03 12:54:57 -06001185}
1186
1187static int hist_show(struct seq_file *m, void *v)
1188{
1189 struct event_trigger_data *data;
1190 struct trace_event_file *event_file;
1191 int n = 0, ret = 0;
1192
1193 mutex_lock(&event_mutex);
1194
1195 event_file = event_file_data(m->private);
1196 if (unlikely(!event_file)) {
1197 ret = -ENODEV;
1198 goto out_unlock;
1199 }
1200
1201 list_for_each_entry_rcu(data, &event_file->triggers, list) {
1202 if (data->cmd_ops->trigger_type == ETT_EVENT_HIST)
1203 hist_trigger_show(m, data, n++);
1204 }
1205
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001206 out_unlock:
1207 mutex_unlock(&event_mutex);
1208
1209 return ret;
1210}
1211
1212static int event_hist_open(struct inode *inode, struct file *file)
1213{
1214 return single_open(file, hist_show, file);
1215}
1216
1217const struct file_operations event_hist_fops = {
1218 .open = event_hist_open,
1219 .read = seq_read,
1220 .llseek = seq_lseek,
1221 .release = single_release,
1222};
1223
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06001224static const char *get_hist_field_flags(struct hist_field *hist_field)
1225{
1226 const char *flags_str = NULL;
1227
1228 if (hist_field->flags & HIST_FIELD_FL_HEX)
1229 flags_str = "hex";
Tom Zanussic6afad42016-03-03 12:54:49 -06001230 else if (hist_field->flags & HIST_FIELD_FL_SYM)
1231 flags_str = "sym";
1232 else if (hist_field->flags & HIST_FIELD_FL_SYM_OFFSET)
1233 flags_str = "sym-offset";
Tom Zanussi6b4827a2016-03-03 12:54:50 -06001234 else if (hist_field->flags & HIST_FIELD_FL_EXECNAME)
1235 flags_str = "execname";
Tom Zanussi31696192016-03-03 12:54:51 -06001236 else if (hist_field->flags & HIST_FIELD_FL_SYSCALL)
1237 flags_str = "syscall";
Namhyung Kim4b94f5b2016-03-03 12:55:02 -06001238 else if (hist_field->flags & HIST_FIELD_FL_LOG2)
1239 flags_str = "log2";
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06001240
1241 return flags_str;
1242}
1243
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001244static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
1245{
Tom Zanussi85013252017-09-22 14:58:22 -05001246 const char *field_name = hist_field_name(hist_field, 0);
1247
Tom Zanussiad42feb2018-01-15 20:51:45 -06001248 if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP)
1249 seq_puts(m, "common_timestamp");
1250 else if (field_name)
1251 seq_printf(m, "%s", field_name);
1252
Tom Zanussi0c4a6b42016-03-03 12:54:48 -06001253 if (hist_field->flags) {
1254 const char *flags_str = get_hist_field_flags(hist_field);
1255
1256 if (flags_str)
1257 seq_printf(m, ".%s", flags_str);
1258 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001259}
1260
1261static int event_hist_trigger_print(struct seq_file *m,
1262 struct event_trigger_ops *ops,
1263 struct event_trigger_data *data)
1264{
1265 struct hist_trigger_data *hist_data = data->private_data;
1266 struct hist_field *key_field;
1267 unsigned int i;
1268
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001269 seq_puts(m, "hist:");
1270
1271 if (data->name)
1272 seq_printf(m, "%s:", data->name);
1273
1274 seq_puts(m, "keys=");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001275
1276 for_each_hist_key_field(i, hist_data) {
1277 key_field = hist_data->fields[i];
1278
1279 if (i > hist_data->n_vals)
1280 seq_puts(m, ",");
1281
Tom Zanussi69a02002016-03-03 12:54:52 -06001282 if (key_field->flags & HIST_FIELD_FL_STACKTRACE)
1283 seq_puts(m, "stacktrace");
1284 else
1285 hist_field_print(m, key_field);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001286 }
1287
1288 seq_puts(m, ":vals=");
Tom Zanussif2606832016-03-03 12:54:43 -06001289
1290 for_each_hist_val_field(i, hist_data) {
1291 if (i == HITCOUNT_IDX)
1292 seq_puts(m, "hitcount");
1293 else {
1294 seq_puts(m, ",");
1295 hist_field_print(m, hist_data->fields[i]);
1296 }
1297 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001298
1299 seq_puts(m, ":sort=");
Tom Zanussie62347d2016-03-03 12:54:45 -06001300
1301 for (i = 0; i < hist_data->n_sort_keys; i++) {
1302 struct tracing_map_sort_key *sort_key;
Tom Zanussiad42feb2018-01-15 20:51:45 -06001303 unsigned int idx;
Tom Zanussie62347d2016-03-03 12:54:45 -06001304
1305 sort_key = &hist_data->sort_keys[i];
Tom Zanussiad42feb2018-01-15 20:51:45 -06001306 idx = sort_key->field_idx;
1307
1308 if (WARN_ON(idx >= TRACING_MAP_FIELDS_MAX))
1309 return -EINVAL;
Tom Zanussie62347d2016-03-03 12:54:45 -06001310
1311 if (i > 0)
1312 seq_puts(m, ",");
1313
Tom Zanussiad42feb2018-01-15 20:51:45 -06001314 if (idx == HITCOUNT_IDX)
Tom Zanussie62347d2016-03-03 12:54:45 -06001315 seq_puts(m, "hitcount");
Tom Zanussiad42feb2018-01-15 20:51:45 -06001316 else
Tom Zanussie62347d2016-03-03 12:54:45 -06001317 hist_field_print(m, hist_data->fields[idx]);
Tom Zanussie62347d2016-03-03 12:54:45 -06001318
1319 if (sort_key->descending)
1320 seq_puts(m, ".descending");
1321 }
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001322 seq_printf(m, ":size=%u", (1 << hist_data->map->map_bits));
1323
1324 if (data->filter_str)
1325 seq_printf(m, " if %s", data->filter_str);
1326
Tom Zanussi83e99912016-03-03 12:54:46 -06001327 if (data->paused)
1328 seq_puts(m, " [paused]");
1329 else
1330 seq_puts(m, " [active]");
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001331
1332 seq_putc(m, '\n');
1333
1334 return 0;
1335}
1336
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001337static int event_hist_trigger_init(struct event_trigger_ops *ops,
1338 struct event_trigger_data *data)
1339{
1340 struct hist_trigger_data *hist_data = data->private_data;
1341
1342 if (!data->ref && hist_data->attrs->name)
1343 save_named_trigger(hist_data->attrs->name, data);
1344
1345 data->ref++;
1346
1347 return 0;
1348}
1349
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001350static void event_hist_trigger_free(struct event_trigger_ops *ops,
1351 struct event_trigger_data *data)
1352{
1353 struct hist_trigger_data *hist_data = data->private_data;
1354
1355 if (WARN_ON_ONCE(data->ref <= 0))
1356 return;
1357
1358 data->ref--;
1359 if (!data->ref) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001360 if (data->name)
1361 del_named_trigger(data);
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001362 trigger_data_free(data);
1363 destroy_hist_data(hist_data);
1364 }
1365}
1366
1367static struct event_trigger_ops event_hist_trigger_ops = {
1368 .func = event_hist_trigger,
1369 .print = event_hist_trigger_print,
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001370 .init = event_hist_trigger_init,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001371 .free = event_hist_trigger_free,
1372};
1373
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001374static int event_hist_trigger_named_init(struct event_trigger_ops *ops,
1375 struct event_trigger_data *data)
1376{
1377 data->ref++;
1378
1379 save_named_trigger(data->named_data->name, data);
1380
1381 event_hist_trigger_init(ops, data->named_data);
1382
1383 return 0;
1384}
1385
1386static void event_hist_trigger_named_free(struct event_trigger_ops *ops,
1387 struct event_trigger_data *data)
1388{
1389 if (WARN_ON_ONCE(data->ref <= 0))
1390 return;
1391
1392 event_hist_trigger_free(ops, data->named_data);
1393
1394 data->ref--;
1395 if (!data->ref) {
1396 del_named_trigger(data);
1397 trigger_data_free(data);
1398 }
1399}
1400
1401static struct event_trigger_ops event_hist_trigger_named_ops = {
1402 .func = event_hist_trigger,
1403 .print = event_hist_trigger_print,
1404 .init = event_hist_trigger_named_init,
1405 .free = event_hist_trigger_named_free,
1406};
1407
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001408static struct event_trigger_ops *event_hist_get_trigger_ops(char *cmd,
1409 char *param)
1410{
1411 return &event_hist_trigger_ops;
1412}
1413
Tom Zanussie86ae9b2016-03-03 12:54:47 -06001414static void hist_clear(struct event_trigger_data *data)
1415{
1416 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussie86ae9b2016-03-03 12:54:47 -06001417
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001418 if (data->name)
1419 pause_named_trigger(data);
Tom Zanussie86ae9b2016-03-03 12:54:47 -06001420
1421 synchronize_sched();
1422
1423 tracing_map_clear(hist_data->map);
1424
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001425 if (data->name)
1426 unpause_named_trigger(data);
1427}
1428
1429static bool compatible_field(struct ftrace_event_field *field,
1430 struct ftrace_event_field *test_field)
1431{
1432 if (field == test_field)
1433 return true;
1434 if (field == NULL || test_field == NULL)
1435 return false;
1436 if (strcmp(field->name, test_field->name) != 0)
1437 return false;
1438 if (strcmp(field->type, test_field->type) != 0)
1439 return false;
1440 if (field->size != test_field->size)
1441 return false;
1442 if (field->is_signed != test_field->is_signed)
1443 return false;
1444
1445 return true;
Tom Zanussie86ae9b2016-03-03 12:54:47 -06001446}
1447
Tom Zanussi52a7f162016-03-03 12:54:57 -06001448static bool hist_trigger_match(struct event_trigger_data *data,
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001449 struct event_trigger_data *data_test,
1450 struct event_trigger_data *named_data,
1451 bool ignore_filter)
Tom Zanussi52a7f162016-03-03 12:54:57 -06001452{
1453 struct tracing_map_sort_key *sort_key, *sort_key_test;
1454 struct hist_trigger_data *hist_data, *hist_data_test;
1455 struct hist_field *key_field, *key_field_test;
1456 unsigned int i;
1457
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001458 if (named_data && (named_data != data_test) &&
1459 (named_data != data_test->named_data))
1460 return false;
1461
1462 if (!named_data && is_named_trigger(data_test))
1463 return false;
1464
Tom Zanussi52a7f162016-03-03 12:54:57 -06001465 hist_data = data->private_data;
1466 hist_data_test = data_test->private_data;
1467
1468 if (hist_data->n_vals != hist_data_test->n_vals ||
1469 hist_data->n_fields != hist_data_test->n_fields ||
1470 hist_data->n_sort_keys != hist_data_test->n_sort_keys)
1471 return false;
1472
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001473 if (!ignore_filter) {
1474 if ((data->filter_str && !data_test->filter_str) ||
1475 (!data->filter_str && data_test->filter_str))
1476 return false;
1477 }
Tom Zanussi52a7f162016-03-03 12:54:57 -06001478
1479 for_each_hist_field(i, hist_data) {
1480 key_field = hist_data->fields[i];
1481 key_field_test = hist_data_test->fields[i];
1482
1483 if (key_field->flags != key_field_test->flags)
1484 return false;
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001485 if (!compatible_field(key_field->field, key_field_test->field))
Tom Zanussi52a7f162016-03-03 12:54:57 -06001486 return false;
1487 if (key_field->offset != key_field_test->offset)
1488 return false;
Tom Zanussiad42feb2018-01-15 20:51:45 -06001489 if (key_field->size != key_field_test->size)
1490 return false;
1491 if (key_field->is_signed != key_field_test->is_signed)
1492 return false;
Tom Zanussi52a7f162016-03-03 12:54:57 -06001493 }
1494
1495 for (i = 0; i < hist_data->n_sort_keys; i++) {
1496 sort_key = &hist_data->sort_keys[i];
1497 sort_key_test = &hist_data_test->sort_keys[i];
1498
1499 if (sort_key->field_idx != sort_key_test->field_idx ||
1500 sort_key->descending != sort_key_test->descending)
1501 return false;
1502 }
1503
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001504 if (!ignore_filter && data->filter_str &&
Tom Zanussi52a7f162016-03-03 12:54:57 -06001505 (strcmp(data->filter_str, data_test->filter_str) != 0))
1506 return false;
1507
1508 return true;
1509}
1510
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001511static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
1512 struct event_trigger_data *data,
1513 struct trace_event_file *file)
1514{
Tom Zanussi83e99912016-03-03 12:54:46 -06001515 struct hist_trigger_data *hist_data = data->private_data;
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001516 struct event_trigger_data *test, *named_data = NULL;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001517 int ret = 0;
1518
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001519 if (hist_data->attrs->name) {
1520 named_data = find_named_trigger(hist_data->attrs->name);
1521 if (named_data) {
1522 if (!hist_trigger_match(data, named_data, named_data,
1523 true)) {
1524 ret = -EINVAL;
1525 goto out;
1526 }
1527 }
1528 }
1529
1530 if (hist_data->attrs->name && !named_data)
1531 goto new;
1532
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001533 list_for_each_entry_rcu(test, &file->triggers, list) {
1534 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001535 if (!hist_trigger_match(data, test, named_data, false))
Tom Zanussi52a7f162016-03-03 12:54:57 -06001536 continue;
Tom Zanussi83e99912016-03-03 12:54:46 -06001537 if (hist_data->attrs->pause)
1538 test->paused = true;
1539 else if (hist_data->attrs->cont)
1540 test->paused = false;
Tom Zanussie86ae9b2016-03-03 12:54:47 -06001541 else if (hist_data->attrs->clear)
1542 hist_clear(test);
Tom Zanussi83e99912016-03-03 12:54:46 -06001543 else
1544 ret = -EEXIST;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001545 goto out;
1546 }
1547 }
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001548 new:
Tom Zanussie86ae9b2016-03-03 12:54:47 -06001549 if (hist_data->attrs->cont || hist_data->attrs->clear) {
Tom Zanussi83e99912016-03-03 12:54:46 -06001550 ret = -ENOENT;
1551 goto out;
1552 }
1553
Tom Zanussi7522c032016-06-29 19:56:00 -05001554 if (hist_data->attrs->pause)
1555 data->paused = true;
1556
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001557 if (named_data) {
1558 destroy_hist_data(data->private_data);
1559 data->private_data = named_data->private_data;
1560 set_named_trigger_data(data, named_data);
1561 data->ops = &event_hist_trigger_named_ops;
1562 }
1563
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001564 if (data->ops->init) {
1565 ret = data->ops->init(data->ops, data);
1566 if (ret < 0)
1567 goto out;
1568 }
1569
1570 list_add_rcu(&data->list, &file->triggers);
1571 ret++;
1572
1573 update_cond_flag(file);
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001574
Tom Zanussiad42feb2018-01-15 20:51:45 -06001575 if (hist_data->enable_timestamps)
1576 tracing_set_time_stamp_abs(file->tr, true);
1577
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001578 if (trace_event_trigger_enable_disable(file, 1) < 0) {
1579 list_del_rcu(&data->list);
1580 update_cond_flag(file);
1581 ret--;
1582 }
1583 out:
1584 return ret;
1585}
1586
Tom Zanussi52a7f162016-03-03 12:54:57 -06001587static void hist_unregister_trigger(char *glob, struct event_trigger_ops *ops,
1588 struct event_trigger_data *data,
1589 struct trace_event_file *file)
1590{
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001591 struct hist_trigger_data *hist_data = data->private_data;
1592 struct event_trigger_data *test, *named_data = NULL;
Tom Zanussi52a7f162016-03-03 12:54:57 -06001593 bool unregistered = false;
1594
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001595 if (hist_data->attrs->name)
1596 named_data = find_named_trigger(hist_data->attrs->name);
1597
Tom Zanussi52a7f162016-03-03 12:54:57 -06001598 list_for_each_entry_rcu(test, &file->triggers, list) {
1599 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
Tom Zanussi5463bfd2016-03-03 12:54:59 -06001600 if (!hist_trigger_match(data, test, named_data, false))
Tom Zanussi52a7f162016-03-03 12:54:57 -06001601 continue;
1602 unregistered = true;
1603 list_del_rcu(&test->list);
1604 trace_event_trigger_enable_disable(file, 0);
1605 update_cond_flag(file);
1606 break;
1607 }
1608 }
1609
1610 if (unregistered && test->ops->free)
1611 test->ops->free(test->ops, test);
Tom Zanussiad42feb2018-01-15 20:51:45 -06001612
1613 if (hist_data->enable_timestamps) {
1614 if (unregistered)
1615 tracing_set_time_stamp_abs(file->tr, false);
1616 }
Tom Zanussi52a7f162016-03-03 12:54:57 -06001617}
1618
1619static void hist_unreg_all(struct trace_event_file *file)
1620{
Steven Rostedt47c18562016-06-29 19:55:59 -05001621 struct event_trigger_data *test, *n;
Tom Zanussiad42feb2018-01-15 20:51:45 -06001622 struct hist_trigger_data *hist_data;
Tom Zanussi52a7f162016-03-03 12:54:57 -06001623
Steven Rostedt47c18562016-06-29 19:55:59 -05001624 list_for_each_entry_safe(test, n, &file->triggers, list) {
Tom Zanussi52a7f162016-03-03 12:54:57 -06001625 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
Tom Zanussiad42feb2018-01-15 20:51:45 -06001626 hist_data = test->private_data;
Tom Zanussi52a7f162016-03-03 12:54:57 -06001627 list_del_rcu(&test->list);
1628 trace_event_trigger_enable_disable(file, 0);
1629 update_cond_flag(file);
Tom Zanussiad42feb2018-01-15 20:51:45 -06001630 if (hist_data->enable_timestamps)
1631 tracing_set_time_stamp_abs(file->tr, false);
Tom Zanussi52a7f162016-03-03 12:54:57 -06001632 if (test->ops->free)
1633 test->ops->free(test->ops, test);
1634 }
1635 }
1636}
1637
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001638static int event_hist_trigger_func(struct event_command *cmd_ops,
1639 struct trace_event_file *file,
1640 char *glob, char *cmd, char *param)
1641{
1642 unsigned int hist_trigger_bits = TRACING_MAP_BITS_DEFAULT;
1643 struct event_trigger_data *trigger_data;
1644 struct hist_trigger_attrs *attrs;
1645 struct event_trigger_ops *trigger_ops;
1646 struct hist_trigger_data *hist_data;
1647 char *trigger;
1648 int ret = 0;
1649
1650 if (!param)
1651 return -EINVAL;
1652
1653 /* separate the trigger from the filter (k:v [if filter]) */
1654 trigger = strsep(&param, " \t");
1655 if (!trigger)
1656 return -EINVAL;
1657
1658 attrs = parse_hist_trigger_attrs(trigger);
1659 if (IS_ERR(attrs))
1660 return PTR_ERR(attrs);
1661
1662 if (attrs->map_bits)
1663 hist_trigger_bits = attrs->map_bits;
1664
1665 hist_data = create_hist_data(hist_trigger_bits, attrs, file);
1666 if (IS_ERR(hist_data)) {
1667 destroy_hist_trigger_attrs(attrs);
1668 return PTR_ERR(hist_data);
1669 }
1670
1671 trigger_ops = cmd_ops->get_trigger_ops(cmd, trigger);
1672
1673 ret = -ENOMEM;
1674 trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL);
1675 if (!trigger_data)
1676 goto out_free;
1677
1678 trigger_data->count = -1;
1679 trigger_data->ops = trigger_ops;
1680 trigger_data->cmd_ops = cmd_ops;
1681
1682 INIT_LIST_HEAD(&trigger_data->list);
1683 RCU_INIT_POINTER(trigger_data->filter, NULL);
1684
1685 trigger_data->private_data = hist_data;
1686
Tom Zanussi52a7f162016-03-03 12:54:57 -06001687 /* if param is non-empty, it's supposed to be a filter */
1688 if (param && cmd_ops->set_filter) {
1689 ret = cmd_ops->set_filter(param, trigger_data, file);
1690 if (ret < 0)
1691 goto out_free;
1692 }
1693
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001694 if (glob[0] == '!') {
1695 cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
1696 ret = 0;
1697 goto out_free;
1698 }
1699
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001700 ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file);
1701 /*
1702 * The above returns on success the # of triggers registered,
1703 * but if it didn't register any it returns zero. Consider no
1704 * triggers registered a failure too.
1705 */
1706 if (!ret) {
Tom Zanussie86ae9b2016-03-03 12:54:47 -06001707 if (!(attrs->pause || attrs->cont || attrs->clear))
Tom Zanussi83e99912016-03-03 12:54:46 -06001708 ret = -ENOENT;
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001709 goto out_free;
1710 } else if (ret < 0)
1711 goto out_free;
1712 /* Just return zero, not the number of registered triggers */
1713 ret = 0;
1714 out:
1715 return ret;
1716 out_free:
1717 if (cmd_ops->set_filter)
1718 cmd_ops->set_filter(NULL, trigger_data, NULL);
1719
1720 kfree(trigger_data);
1721
1722 destroy_hist_data(hist_data);
1723 goto out;
1724}
1725
1726static struct event_command trigger_hist_cmd = {
1727 .name = "hist",
1728 .trigger_type = ETT_EVENT_HIST,
1729 .flags = EVENT_CMD_FL_NEEDS_REC,
1730 .func = event_hist_trigger_func,
1731 .reg = hist_register_trigger,
Tom Zanussi52a7f162016-03-03 12:54:57 -06001732 .unreg = hist_unregister_trigger,
1733 .unreg_all = hist_unreg_all,
Tom Zanussi7ef224d2016-03-03 12:54:42 -06001734 .get_trigger_ops = event_hist_get_trigger_ops,
1735 .set_filter = set_trigger_filter,
1736};
1737
1738__init int register_trigger_hist_cmd(void)
1739{
1740 int ret;
1741
1742 ret = register_event_command(&trigger_hist_cmd);
1743 WARN_ON(ret < 0);
1744
1745 return ret;
1746}
Tom Zanussid0bad492016-03-03 12:54:55 -06001747
1748static void
Tom Zanussi1ac4f512018-01-15 20:51:42 -06001749hist_enable_trigger(struct event_trigger_data *data, void *rec,
1750 struct ring_buffer_event *event)
Tom Zanussid0bad492016-03-03 12:54:55 -06001751{
1752 struct enable_trigger_data *enable_data = data->private_data;
1753 struct event_trigger_data *test;
1754
1755 list_for_each_entry_rcu(test, &enable_data->file->triggers, list) {
1756 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
1757 if (enable_data->enable)
1758 test->paused = false;
1759 else
1760 test->paused = true;
Tom Zanussid0bad492016-03-03 12:54:55 -06001761 }
1762 }
1763}
1764
1765static void
Tom Zanussi1ac4f512018-01-15 20:51:42 -06001766hist_enable_count_trigger(struct event_trigger_data *data, void *rec,
1767 struct ring_buffer_event *event)
Tom Zanussid0bad492016-03-03 12:54:55 -06001768{
1769 if (!data->count)
1770 return;
1771
1772 if (data->count != -1)
1773 (data->count)--;
1774
Tom Zanussi1ac4f512018-01-15 20:51:42 -06001775 hist_enable_trigger(data, rec, event);
Tom Zanussid0bad492016-03-03 12:54:55 -06001776}
1777
1778static struct event_trigger_ops hist_enable_trigger_ops = {
1779 .func = hist_enable_trigger,
1780 .print = event_enable_trigger_print,
1781 .init = event_trigger_init,
1782 .free = event_enable_trigger_free,
1783};
1784
1785static struct event_trigger_ops hist_enable_count_trigger_ops = {
1786 .func = hist_enable_count_trigger,
1787 .print = event_enable_trigger_print,
1788 .init = event_trigger_init,
1789 .free = event_enable_trigger_free,
1790};
1791
1792static struct event_trigger_ops hist_disable_trigger_ops = {
1793 .func = hist_enable_trigger,
1794 .print = event_enable_trigger_print,
1795 .init = event_trigger_init,
1796 .free = event_enable_trigger_free,
1797};
1798
1799static struct event_trigger_ops hist_disable_count_trigger_ops = {
1800 .func = hist_enable_count_trigger,
1801 .print = event_enable_trigger_print,
1802 .init = event_trigger_init,
1803 .free = event_enable_trigger_free,
1804};
1805
1806static struct event_trigger_ops *
1807hist_enable_get_trigger_ops(char *cmd, char *param)
1808{
1809 struct event_trigger_ops *ops;
1810 bool enable;
1811
1812 enable = (strcmp(cmd, ENABLE_HIST_STR) == 0);
1813
1814 if (enable)
1815 ops = param ? &hist_enable_count_trigger_ops :
1816 &hist_enable_trigger_ops;
1817 else
1818 ops = param ? &hist_disable_count_trigger_ops :
1819 &hist_disable_trigger_ops;
1820
1821 return ops;
1822}
1823
Tom Zanussi52a7f162016-03-03 12:54:57 -06001824static void hist_enable_unreg_all(struct trace_event_file *file)
1825{
Steven Rostedt47c18562016-06-29 19:55:59 -05001826 struct event_trigger_data *test, *n;
Tom Zanussi52a7f162016-03-03 12:54:57 -06001827
Steven Rostedt47c18562016-06-29 19:55:59 -05001828 list_for_each_entry_safe(test, n, &file->triggers, list) {
Tom Zanussi52a7f162016-03-03 12:54:57 -06001829 if (test->cmd_ops->trigger_type == ETT_HIST_ENABLE) {
1830 list_del_rcu(&test->list);
1831 update_cond_flag(file);
1832 trace_event_trigger_enable_disable(file, 0);
1833 if (test->ops->free)
1834 test->ops->free(test->ops, test);
1835 }
1836 }
1837}
1838
Tom Zanussid0bad492016-03-03 12:54:55 -06001839static struct event_command trigger_hist_enable_cmd = {
1840 .name = ENABLE_HIST_STR,
1841 .trigger_type = ETT_HIST_ENABLE,
1842 .func = event_enable_trigger_func,
1843 .reg = event_enable_register_trigger,
1844 .unreg = event_enable_unregister_trigger,
Tom Zanussi52a7f162016-03-03 12:54:57 -06001845 .unreg_all = hist_enable_unreg_all,
Tom Zanussid0bad492016-03-03 12:54:55 -06001846 .get_trigger_ops = hist_enable_get_trigger_ops,
1847 .set_filter = set_trigger_filter,
1848};
1849
1850static struct event_command trigger_hist_disable_cmd = {
1851 .name = DISABLE_HIST_STR,
1852 .trigger_type = ETT_HIST_ENABLE,
1853 .func = event_enable_trigger_func,
1854 .reg = event_enable_register_trigger,
1855 .unreg = event_enable_unregister_trigger,
Tom Zanussi52a7f162016-03-03 12:54:57 -06001856 .unreg_all = hist_enable_unreg_all,
Tom Zanussid0bad492016-03-03 12:54:55 -06001857 .get_trigger_ops = hist_enable_get_trigger_ops,
1858 .set_filter = set_trigger_filter,
1859};
1860
1861static __init void unregister_trigger_hist_enable_disable_cmds(void)
1862{
1863 unregister_event_command(&trigger_hist_enable_cmd);
1864 unregister_event_command(&trigger_hist_disable_cmd);
1865}
1866
1867__init int register_trigger_hist_enable_disable_cmds(void)
1868{
1869 int ret;
1870
1871 ret = register_event_command(&trigger_hist_enable_cmd);
1872 if (WARN_ON(ret < 0))
1873 return ret;
1874 ret = register_event_command(&trigger_hist_disable_cmd);
1875 if (WARN_ON(ret < 0))
1876 unregister_trigger_hist_enable_disable_cmds();
1877
1878 return ret;
1879}