tracing: Add hist trigger support for compound keys
[linux-2.6-block.git] / kernel / trace / trace_events_hist.c
CommitLineData
7ef224d1
TZ
1/*
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>
22
23#include "tracing_map.h"
24#include "trace.h"
25
26struct hist_field;
27
28typedef u64 (*hist_field_fn_t) (struct hist_field *field, void *event);
29
30struct hist_field {
31 struct ftrace_event_field *field;
32 unsigned long flags;
33 hist_field_fn_t fn;
34 unsigned int size;
76a3b0c8 35 unsigned int offset;
7ef224d1
TZ
36};
37
38static u64 hist_field_counter(struct hist_field *field, void *event)
39{
40 return 1;
41}
42
43static u64 hist_field_string(struct hist_field *hist_field, void *event)
44{
45 char *addr = (char *)(event + hist_field->field->offset);
46
47 return (u64)(unsigned long)addr;
48}
49
50#define DEFINE_HIST_FIELD_FN(type) \
51static u64 hist_field_##type(struct hist_field *hist_field, void *event)\
52{ \
53 type *addr = (type *)(event + hist_field->field->offset); \
54 \
55 return (u64)*addr; \
56}
57
58DEFINE_HIST_FIELD_FN(s64);
59DEFINE_HIST_FIELD_FN(u64);
60DEFINE_HIST_FIELD_FN(s32);
61DEFINE_HIST_FIELD_FN(u32);
62DEFINE_HIST_FIELD_FN(s16);
63DEFINE_HIST_FIELD_FN(u16);
64DEFINE_HIST_FIELD_FN(s8);
65DEFINE_HIST_FIELD_FN(u8);
66
67#define for_each_hist_field(i, hist_data) \
68 for ((i) = 0; (i) < (hist_data)->n_fields; (i)++)
69
70#define for_each_hist_val_field(i, hist_data) \
71 for ((i) = 0; (i) < (hist_data)->n_vals; (i)++)
72
73#define for_each_hist_key_field(i, hist_data) \
74 for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++)
75
76#define HITCOUNT_IDX 0
76a3b0c8 77#define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + sizeof(u64))
7ef224d1
TZ
78
79enum hist_field_flags {
80 HIST_FIELD_FL_HITCOUNT = 1,
81 HIST_FIELD_FL_KEY = 2,
82 HIST_FIELD_FL_STRING = 4,
83};
84
85struct hist_trigger_attrs {
86 char *keys_str;
f2606835 87 char *vals_str;
7ef224d1
TZ
88 unsigned int map_bits;
89};
90
91struct hist_trigger_data {
92 struct hist_field *fields[TRACING_MAP_FIELDS_MAX];
93 unsigned int n_vals;
94 unsigned int n_keys;
95 unsigned int n_fields;
96 unsigned int key_size;
97 struct tracing_map_sort_key sort_keys[TRACING_MAP_SORT_KEYS_MAX];
98 unsigned int n_sort_keys;
99 struct trace_event_file *event_file;
100 struct hist_trigger_attrs *attrs;
101 struct tracing_map *map;
102};
103
104static hist_field_fn_t select_value_fn(int field_size, int field_is_signed)
105{
106 hist_field_fn_t fn = NULL;
107
108 switch (field_size) {
109 case 8:
110 if (field_is_signed)
111 fn = hist_field_s64;
112 else
113 fn = hist_field_u64;
114 break;
115 case 4:
116 if (field_is_signed)
117 fn = hist_field_s32;
118 else
119 fn = hist_field_u32;
120 break;
121 case 2:
122 if (field_is_signed)
123 fn = hist_field_s16;
124 else
125 fn = hist_field_u16;
126 break;
127 case 1:
128 if (field_is_signed)
129 fn = hist_field_s8;
130 else
131 fn = hist_field_u8;
132 break;
133 }
134
135 return fn;
136}
137
138static int parse_map_size(char *str)
139{
140 unsigned long size, map_bits;
141 int ret;
142
143 strsep(&str, "=");
144 if (!str) {
145 ret = -EINVAL;
146 goto out;
147 }
148
149 ret = kstrtoul(str, 0, &size);
150 if (ret)
151 goto out;
152
153 map_bits = ilog2(roundup_pow_of_two(size));
154 if (map_bits < TRACING_MAP_BITS_MIN ||
155 map_bits > TRACING_MAP_BITS_MAX)
156 ret = -EINVAL;
157 else
158 ret = map_bits;
159 out:
160 return ret;
161}
162
163static void destroy_hist_trigger_attrs(struct hist_trigger_attrs *attrs)
164{
165 if (!attrs)
166 return;
167
168 kfree(attrs->keys_str);
f2606835 169 kfree(attrs->vals_str);
7ef224d1
TZ
170 kfree(attrs);
171}
172
173static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str)
174{
175 struct hist_trigger_attrs *attrs;
176 int ret = 0;
177
178 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
179 if (!attrs)
180 return ERR_PTR(-ENOMEM);
181
182 while (trigger_str) {
183 char *str = strsep(&trigger_str, ":");
184
185 if ((strncmp(str, "key=", strlen("key=")) == 0) ||
186 (strncmp(str, "keys=", strlen("keys=")) == 0))
187 attrs->keys_str = kstrdup(str, GFP_KERNEL);
f2606835
TZ
188 else if ((strncmp(str, "val=", strlen("val=")) == 0) ||
189 (strncmp(str, "vals=", strlen("vals=")) == 0) ||
190 (strncmp(str, "values=", strlen("values=")) == 0))
191 attrs->vals_str = kstrdup(str, GFP_KERNEL);
7ef224d1
TZ
192 else if (strncmp(str, "size=", strlen("size=")) == 0) {
193 int map_bits = parse_map_size(str);
194
195 if (map_bits < 0) {
196 ret = map_bits;
197 goto free;
198 }
199 attrs->map_bits = map_bits;
200 } else {
201 ret = -EINVAL;
202 goto free;
203 }
204 }
205
206 if (!attrs->keys_str) {
207 ret = -EINVAL;
208 goto free;
209 }
210
211 return attrs;
212 free:
213 destroy_hist_trigger_attrs(attrs);
214
215 return ERR_PTR(ret);
216}
217
218static void destroy_hist_field(struct hist_field *hist_field)
219{
220 kfree(hist_field);
221}
222
223static struct hist_field *create_hist_field(struct ftrace_event_field *field,
224 unsigned long flags)
225{
226 struct hist_field *hist_field;
227
228 if (field && is_function_field(field))
229 return NULL;
230
231 hist_field = kzalloc(sizeof(struct hist_field), GFP_KERNEL);
232 if (!hist_field)
233 return NULL;
234
235 if (flags & HIST_FIELD_FL_HITCOUNT) {
236 hist_field->fn = hist_field_counter;
237 goto out;
238 }
239
240 if (is_string_field(field)) {
241 flags |= HIST_FIELD_FL_STRING;
242 hist_field->fn = hist_field_string;
243 } else {
244 hist_field->fn = select_value_fn(field->size,
245 field->is_signed);
246 if (!hist_field->fn) {
247 destroy_hist_field(hist_field);
248 return NULL;
249 }
250 }
251 out:
252 hist_field->field = field;
253 hist_field->flags = flags;
254
255 return hist_field;
256}
257
258static void destroy_hist_fields(struct hist_trigger_data *hist_data)
259{
260 unsigned int i;
261
262 for (i = 0; i < TRACING_MAP_FIELDS_MAX; i++) {
263 if (hist_data->fields[i]) {
264 destroy_hist_field(hist_data->fields[i]);
265 hist_data->fields[i] = NULL;
266 }
267 }
268}
269
270static int create_hitcount_val(struct hist_trigger_data *hist_data)
271{
272 hist_data->fields[HITCOUNT_IDX] =
273 create_hist_field(NULL, HIST_FIELD_FL_HITCOUNT);
274 if (!hist_data->fields[HITCOUNT_IDX])
275 return -ENOMEM;
276
277 hist_data->n_vals++;
278
279 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
280 return -EINVAL;
281
282 return 0;
283}
284
f2606835
TZ
285static int create_val_field(struct hist_trigger_data *hist_data,
286 unsigned int val_idx,
287 struct trace_event_file *file,
288 char *field_str)
289{
290 struct ftrace_event_field *field = NULL;
291 unsigned long flags = 0;
292 int ret = 0;
293
294 if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX))
295 return -EINVAL;
296 field = trace_find_event_field(file->event_call, field_str);
297 if (!field) {
298 ret = -EINVAL;
299 goto out;
300 }
301
302 hist_data->fields[val_idx] = create_hist_field(field, flags);
303 if (!hist_data->fields[val_idx]) {
304 ret = -ENOMEM;
305 goto out;
306 }
307
308 ++hist_data->n_vals;
309
310 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
311 ret = -EINVAL;
312 out:
313 return ret;
314}
315
7ef224d1
TZ
316static int create_val_fields(struct hist_trigger_data *hist_data,
317 struct trace_event_file *file)
318{
f2606835
TZ
319 char *fields_str, *field_str;
320 unsigned int i, j;
7ef224d1
TZ
321 int ret;
322
323 ret = create_hitcount_val(hist_data);
f2606835
TZ
324 if (ret)
325 goto out;
7ef224d1 326
f2606835
TZ
327 fields_str = hist_data->attrs->vals_str;
328 if (!fields_str)
329 goto out;
330
331 strsep(&fields_str, "=");
332 if (!fields_str)
333 goto out;
334
335 for (i = 0, j = 1; i < TRACING_MAP_VALS_MAX &&
336 j < TRACING_MAP_VALS_MAX; i++) {
337 field_str = strsep(&fields_str, ",");
338 if (!field_str)
339 break;
340 if (strcmp(field_str, "hitcount") == 0)
341 continue;
342 ret = create_val_field(hist_data, j++, file, field_str);
343 if (ret)
344 goto out;
345 }
346 if (fields_str && (strcmp(fields_str, "hitcount") != 0))
347 ret = -EINVAL;
348 out:
7ef224d1
TZ
349 return ret;
350}
351
352static int create_key_field(struct hist_trigger_data *hist_data,
353 unsigned int key_idx,
76a3b0c8 354 unsigned int key_offset,
7ef224d1
TZ
355 struct trace_event_file *file,
356 char *field_str)
357{
358 struct ftrace_event_field *field = NULL;
359 unsigned long flags = 0;
360 unsigned int key_size;
361 int ret = 0;
362
363 if (WARN_ON(key_idx >= TRACING_MAP_FIELDS_MAX))
364 return -EINVAL;
365
366 flags |= HIST_FIELD_FL_KEY;
367
368 field = trace_find_event_field(file->event_call, field_str);
369 if (!field) {
370 ret = -EINVAL;
371 goto out;
372 }
373
374 key_size = field->size;
375
376 hist_data->fields[key_idx] = create_hist_field(field, flags);
377 if (!hist_data->fields[key_idx]) {
378 ret = -ENOMEM;
379 goto out;
380 }
381
382 key_size = ALIGN(key_size, sizeof(u64));
383 hist_data->fields[key_idx]->size = key_size;
76a3b0c8
TZ
384 hist_data->fields[key_idx]->offset = key_offset;
385 hist_data->key_size += key_size;
7ef224d1
TZ
386 if (hist_data->key_size > HIST_KEY_SIZE_MAX) {
387 ret = -EINVAL;
388 goto out;
389 }
390
391 hist_data->n_keys++;
392
393 if (WARN_ON(hist_data->n_keys > TRACING_MAP_KEYS_MAX))
394 return -EINVAL;
395
396 ret = key_size;
397 out:
398 return ret;
399}
400
401static int create_key_fields(struct hist_trigger_data *hist_data,
402 struct trace_event_file *file)
403{
76a3b0c8 404 unsigned int i, key_offset = 0, n_vals = hist_data->n_vals;
7ef224d1
TZ
405 char *fields_str, *field_str;
406 int ret = -EINVAL;
407
408 fields_str = hist_data->attrs->keys_str;
409 if (!fields_str)
410 goto out;
411
412 strsep(&fields_str, "=");
413 if (!fields_str)
414 goto out;
415
76a3b0c8 416 for (i = n_vals; i < n_vals + TRACING_MAP_KEYS_MAX; i++) {
7ef224d1
TZ
417 field_str = strsep(&fields_str, ",");
418 if (!field_str)
419 break;
76a3b0c8
TZ
420 ret = create_key_field(hist_data, i, key_offset,
421 file, field_str);
7ef224d1
TZ
422 if (ret < 0)
423 goto out;
76a3b0c8 424 key_offset += ret;
7ef224d1
TZ
425 }
426 if (fields_str) {
427 ret = -EINVAL;
428 goto out;
429 }
430 ret = 0;
431 out:
432 return ret;
433}
434
435static int create_hist_fields(struct hist_trigger_data *hist_data,
436 struct trace_event_file *file)
437{
438 int ret;
439
440 ret = create_val_fields(hist_data, file);
441 if (ret)
442 goto out;
443
444 ret = create_key_fields(hist_data, file);
445 if (ret)
446 goto out;
447
448 hist_data->n_fields = hist_data->n_vals + hist_data->n_keys;
449 out:
450 return ret;
451}
452
453static int create_sort_keys(struct hist_trigger_data *hist_data)
454{
455 int ret = 0;
456
457 hist_data->n_sort_keys = 1; /* sort_keys[0] is always hitcount */
458
459 return ret;
460}
461
462static void destroy_hist_data(struct hist_trigger_data *hist_data)
463{
464 destroy_hist_trigger_attrs(hist_data->attrs);
465 destroy_hist_fields(hist_data);
466 tracing_map_destroy(hist_data->map);
467 kfree(hist_data);
468}
469
470static int create_tracing_map_fields(struct hist_trigger_data *hist_data)
471{
472 struct tracing_map *map = hist_data->map;
473 struct ftrace_event_field *field;
474 struct hist_field *hist_field;
475 unsigned int i, idx;
476
477 for_each_hist_field(i, hist_data) {
478 hist_field = hist_data->fields[i];
479 if (hist_field->flags & HIST_FIELD_FL_KEY) {
480 tracing_map_cmp_fn_t cmp_fn;
481
482 field = hist_field->field;
483
484 if (is_string_field(field))
485 cmp_fn = tracing_map_cmp_string;
486 else
487 cmp_fn = tracing_map_cmp_num(field->size,
488 field->is_signed);
76a3b0c8
TZ
489 idx = tracing_map_add_key_field(map,
490 hist_field->offset,
491 cmp_fn);
492
7ef224d1
TZ
493 } else
494 idx = tracing_map_add_sum_field(map);
495
496 if (idx < 0)
497 return idx;
498 }
499
500 return 0;
501}
502
503static struct hist_trigger_data *
504create_hist_data(unsigned int map_bits,
505 struct hist_trigger_attrs *attrs,
506 struct trace_event_file *file)
507{
508 struct hist_trigger_data *hist_data;
509 int ret = 0;
510
511 hist_data = kzalloc(sizeof(*hist_data), GFP_KERNEL);
512 if (!hist_data)
513 return ERR_PTR(-ENOMEM);
514
515 hist_data->attrs = attrs;
516
517 ret = create_hist_fields(hist_data, file);
518 if (ret)
519 goto free;
520
521 ret = create_sort_keys(hist_data);
522 if (ret)
523 goto free;
524
525 hist_data->map = tracing_map_create(map_bits, hist_data->key_size,
526 NULL, hist_data);
527 if (IS_ERR(hist_data->map)) {
528 ret = PTR_ERR(hist_data->map);
529 hist_data->map = NULL;
530 goto free;
531 }
532
533 ret = create_tracing_map_fields(hist_data);
534 if (ret)
535 goto free;
536
537 ret = tracing_map_init(hist_data->map);
538 if (ret)
539 goto free;
540
541 hist_data->event_file = file;
542 out:
543 return hist_data;
544 free:
545 hist_data->attrs = NULL;
546
547 destroy_hist_data(hist_data);
548
549 hist_data = ERR_PTR(ret);
550
551 goto out;
552}
553
554static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
555 struct tracing_map_elt *elt,
556 void *rec)
557{
558 struct hist_field *hist_field;
559 unsigned int i;
560 u64 hist_val;
561
562 for_each_hist_val_field(i, hist_data) {
563 hist_field = hist_data->fields[i];
564 hist_val = hist_field->fn(hist_field, rec);
565 tracing_map_update_sum(elt, i, hist_val);
566 }
567}
568
569static void event_hist_trigger(struct event_trigger_data *data, void *rec)
570{
571 struct hist_trigger_data *hist_data = data->private_data;
76a3b0c8 572 char compound_key[HIST_KEY_SIZE_MAX];
7ef224d1
TZ
573 struct hist_field *key_field;
574 struct tracing_map_elt *elt;
575 u64 field_contents;
576 void *key = NULL;
577 unsigned int i;
578
76a3b0c8
TZ
579 if (hist_data->n_keys > 1)
580 memset(compound_key, 0, hist_data->key_size);
581
7ef224d1
TZ
582 for_each_hist_key_field(i, hist_data) {
583 key_field = hist_data->fields[i];
584
585 field_contents = key_field->fn(key_field, rec);
586 if (key_field->flags & HIST_FIELD_FL_STRING)
587 key = (void *)(unsigned long)field_contents;
588 else
589 key = (void *)&field_contents;
76a3b0c8
TZ
590
591 if (hist_data->n_keys > 1) {
592 memcpy(compound_key + key_field->offset, key,
593 key_field->size);
594 }
7ef224d1
TZ
595 }
596
76a3b0c8
TZ
597 if (hist_data->n_keys > 1)
598 key = compound_key;
599
7ef224d1
TZ
600 elt = tracing_map_insert(hist_data->map, key);
601 if (elt)
602 hist_trigger_elt_update(hist_data, elt, rec);
603}
604
605static void
606hist_trigger_entry_print(struct seq_file *m,
607 struct hist_trigger_data *hist_data, void *key,
608 struct tracing_map_elt *elt)
609{
610 struct hist_field *key_field;
611 unsigned int i;
612 u64 uval;
613
614 seq_puts(m, "{ ");
615
616 for_each_hist_key_field(i, hist_data) {
617 key_field = hist_data->fields[i];
618
619 if (i > hist_data->n_vals)
620 seq_puts(m, ", ");
621
622 if (key_field->flags & HIST_FIELD_FL_STRING) {
623 seq_printf(m, "%s: %-50s", key_field->field->name,
76a3b0c8 624 (char *)(key + key_field->offset));
7ef224d1 625 } else {
76a3b0c8
TZ
626 uval = *(u64 *)(key + key_field->offset);
627 seq_printf(m, "%s: %10llu", key_field->field->name,
628 uval);
7ef224d1
TZ
629 }
630 }
631
632 seq_puts(m, " }");
633
634 seq_printf(m, " hitcount: %10llu",
635 tracing_map_read_sum(elt, HITCOUNT_IDX));
636
f2606835
TZ
637 for (i = 1; i < hist_data->n_vals; i++) {
638 seq_printf(m, " %s: %10llu",
639 hist_data->fields[i]->field->name,
640 tracing_map_read_sum(elt, i));
641 }
642
7ef224d1
TZ
643 seq_puts(m, "\n");
644}
645
646static int print_entries(struct seq_file *m,
647 struct hist_trigger_data *hist_data)
648{
649 struct tracing_map_sort_entry **sort_entries = NULL;
650 struct tracing_map *map = hist_data->map;
651 unsigned int i, n_entries;
652
653 n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
654 hist_data->n_sort_keys,
655 &sort_entries);
656 if (n_entries < 0)
657 return n_entries;
658
659 for (i = 0; i < n_entries; i++)
660 hist_trigger_entry_print(m, hist_data,
661 sort_entries[i]->key,
662 sort_entries[i]->elt);
663
664 tracing_map_destroy_sort_entries(sort_entries, n_entries);
665
666 return n_entries;
667}
668
669static int hist_show(struct seq_file *m, void *v)
670{
671 struct event_trigger_data *test, *data = NULL;
672 struct trace_event_file *event_file;
673 struct hist_trigger_data *hist_data;
674 int n_entries, ret = 0;
675
676 mutex_lock(&event_mutex);
677
678 event_file = event_file_data(m->private);
679 if (unlikely(!event_file)) {
680 ret = -ENODEV;
681 goto out_unlock;
682 }
683
684 list_for_each_entry_rcu(test, &event_file->triggers, list) {
685 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
686 data = test;
687 break;
688 }
689 }
690 if (!data)
691 goto out_unlock;
692
693 seq_puts(m, "# event histogram\n#\n# trigger info: ");
694 data->ops->print(m, data->ops, data);
695 seq_puts(m, "\n");
696
697 hist_data = data->private_data;
698 n_entries = print_entries(m, hist_data);
699 if (n_entries < 0) {
700 ret = n_entries;
701 n_entries = 0;
702 }
703
704 seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n",
705 (u64)atomic64_read(&hist_data->map->hits),
706 n_entries, (u64)atomic64_read(&hist_data->map->drops));
707 out_unlock:
708 mutex_unlock(&event_mutex);
709
710 return ret;
711}
712
713static int event_hist_open(struct inode *inode, struct file *file)
714{
715 return single_open(file, hist_show, file);
716}
717
718const struct file_operations event_hist_fops = {
719 .open = event_hist_open,
720 .read = seq_read,
721 .llseek = seq_lseek,
722 .release = single_release,
723};
724
725static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
726{
727 seq_printf(m, "%s", hist_field->field->name);
728}
729
730static int event_hist_trigger_print(struct seq_file *m,
731 struct event_trigger_ops *ops,
732 struct event_trigger_data *data)
733{
734 struct hist_trigger_data *hist_data = data->private_data;
735 struct hist_field *key_field;
736 unsigned int i;
737
738 seq_puts(m, "hist:keys=");
739
740 for_each_hist_key_field(i, hist_data) {
741 key_field = hist_data->fields[i];
742
743 if (i > hist_data->n_vals)
744 seq_puts(m, ",");
745
746 hist_field_print(m, key_field);
747 }
748
749 seq_puts(m, ":vals=");
f2606835
TZ
750
751 for_each_hist_val_field(i, hist_data) {
752 if (i == HITCOUNT_IDX)
753 seq_puts(m, "hitcount");
754 else {
755 seq_puts(m, ",");
756 hist_field_print(m, hist_data->fields[i]);
757 }
758 }
7ef224d1
TZ
759
760 seq_puts(m, ":sort=");
761 seq_puts(m, "hitcount");
762
763 seq_printf(m, ":size=%u", (1 << hist_data->map->map_bits));
764
765 if (data->filter_str)
766 seq_printf(m, " if %s", data->filter_str);
767
768 seq_puts(m, " [active]");
769
770 seq_putc(m, '\n');
771
772 return 0;
773}
774
775static void event_hist_trigger_free(struct event_trigger_ops *ops,
776 struct event_trigger_data *data)
777{
778 struct hist_trigger_data *hist_data = data->private_data;
779
780 if (WARN_ON_ONCE(data->ref <= 0))
781 return;
782
783 data->ref--;
784 if (!data->ref) {
785 trigger_data_free(data);
786 destroy_hist_data(hist_data);
787 }
788}
789
790static struct event_trigger_ops event_hist_trigger_ops = {
791 .func = event_hist_trigger,
792 .print = event_hist_trigger_print,
793 .init = event_trigger_init,
794 .free = event_hist_trigger_free,
795};
796
797static struct event_trigger_ops *event_hist_get_trigger_ops(char *cmd,
798 char *param)
799{
800 return &event_hist_trigger_ops;
801}
802
803static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
804 struct event_trigger_data *data,
805 struct trace_event_file *file)
806{
807 struct event_trigger_data *test;
808 int ret = 0;
809
810 list_for_each_entry_rcu(test, &file->triggers, list) {
811 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
812 ret = -EEXIST;
813 goto out;
814 }
815 }
816
817 if (data->ops->init) {
818 ret = data->ops->init(data->ops, data);
819 if (ret < 0)
820 goto out;
821 }
822
823 list_add_rcu(&data->list, &file->triggers);
824 ret++;
825
826 update_cond_flag(file);
827 if (trace_event_trigger_enable_disable(file, 1) < 0) {
828 list_del_rcu(&data->list);
829 update_cond_flag(file);
830 ret--;
831 }
832 out:
833 return ret;
834}
835
836static int event_hist_trigger_func(struct event_command *cmd_ops,
837 struct trace_event_file *file,
838 char *glob, char *cmd, char *param)
839{
840 unsigned int hist_trigger_bits = TRACING_MAP_BITS_DEFAULT;
841 struct event_trigger_data *trigger_data;
842 struct hist_trigger_attrs *attrs;
843 struct event_trigger_ops *trigger_ops;
844 struct hist_trigger_data *hist_data;
845 char *trigger;
846 int ret = 0;
847
848 if (!param)
849 return -EINVAL;
850
851 /* separate the trigger from the filter (k:v [if filter]) */
852 trigger = strsep(&param, " \t");
853 if (!trigger)
854 return -EINVAL;
855
856 attrs = parse_hist_trigger_attrs(trigger);
857 if (IS_ERR(attrs))
858 return PTR_ERR(attrs);
859
860 if (attrs->map_bits)
861 hist_trigger_bits = attrs->map_bits;
862
863 hist_data = create_hist_data(hist_trigger_bits, attrs, file);
864 if (IS_ERR(hist_data)) {
865 destroy_hist_trigger_attrs(attrs);
866 return PTR_ERR(hist_data);
867 }
868
869 trigger_ops = cmd_ops->get_trigger_ops(cmd, trigger);
870
871 ret = -ENOMEM;
872 trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL);
873 if (!trigger_data)
874 goto out_free;
875
876 trigger_data->count = -1;
877 trigger_data->ops = trigger_ops;
878 trigger_data->cmd_ops = cmd_ops;
879
880 INIT_LIST_HEAD(&trigger_data->list);
881 RCU_INIT_POINTER(trigger_data->filter, NULL);
882
883 trigger_data->private_data = hist_data;
884
885 if (glob[0] == '!') {
886 cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
887 ret = 0;
888 goto out_free;
889 }
890
891 if (!param) /* if param is non-empty, it's supposed to be a filter */
892 goto out_reg;
893
894 if (!cmd_ops->set_filter)
895 goto out_reg;
896
897 ret = cmd_ops->set_filter(param, trigger_data, file);
898 if (ret < 0)
899 goto out_free;
900 out_reg:
901 ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file);
902 /*
903 * The above returns on success the # of triggers registered,
904 * but if it didn't register any it returns zero. Consider no
905 * triggers registered a failure too.
906 */
907 if (!ret) {
908 ret = -ENOENT;
909 goto out_free;
910 } else if (ret < 0)
911 goto out_free;
912 /* Just return zero, not the number of registered triggers */
913 ret = 0;
914 out:
915 return ret;
916 out_free:
917 if (cmd_ops->set_filter)
918 cmd_ops->set_filter(NULL, trigger_data, NULL);
919
920 kfree(trigger_data);
921
922 destroy_hist_data(hist_data);
923 goto out;
924}
925
926static struct event_command trigger_hist_cmd = {
927 .name = "hist",
928 .trigger_type = ETT_EVENT_HIST,
929 .flags = EVENT_CMD_FL_NEEDS_REC,
930 .func = event_hist_trigger_func,
931 .reg = hist_register_trigger,
932 .unreg = unregister_trigger,
933 .get_trigger_ops = event_hist_get_trigger_ops,
934 .set_filter = set_trigger_filter,
935};
936
937__init int register_trigger_hist_cmd(void)
938{
939 int ret;
940
941 ret = register_event_command(&trigger_hist_cmd);
942 WARN_ON(ret < 0);
943
944 return ret;
945}