tracing: Add hist trigger support for multiple values ('vals=' param)
[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;
35};
36
37static u64 hist_field_counter(struct hist_field *field, void *event)
38{
39 return 1;
40}
41
42static u64 hist_field_string(struct hist_field *hist_field, void *event)
43{
44 char *addr = (char *)(event + hist_field->field->offset);
45
46 return (u64)(unsigned long)addr;
47}
48
49#define DEFINE_HIST_FIELD_FN(type) \
50static u64 hist_field_##type(struct hist_field *hist_field, void *event)\
51{ \
52 type *addr = (type *)(event + hist_field->field->offset); \
53 \
54 return (u64)*addr; \
55}
56
57DEFINE_HIST_FIELD_FN(s64);
58DEFINE_HIST_FIELD_FN(u64);
59DEFINE_HIST_FIELD_FN(s32);
60DEFINE_HIST_FIELD_FN(u32);
61DEFINE_HIST_FIELD_FN(s16);
62DEFINE_HIST_FIELD_FN(u16);
63DEFINE_HIST_FIELD_FN(s8);
64DEFINE_HIST_FIELD_FN(u8);
65
66#define for_each_hist_field(i, hist_data) \
67 for ((i) = 0; (i) < (hist_data)->n_fields; (i)++)
68
69#define for_each_hist_val_field(i, hist_data) \
70 for ((i) = 0; (i) < (hist_data)->n_vals; (i)++)
71
72#define for_each_hist_key_field(i, hist_data) \
73 for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++)
74
75#define HITCOUNT_IDX 0
76#define HIST_KEY_MAX 1
77#define HIST_KEY_SIZE_MAX MAX_FILTER_STR_VAL
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,
354 struct trace_event_file *file,
355 char *field_str)
356{
357 struct ftrace_event_field *field = NULL;
358 unsigned long flags = 0;
359 unsigned int key_size;
360 int ret = 0;
361
362 if (WARN_ON(key_idx >= TRACING_MAP_FIELDS_MAX))
363 return -EINVAL;
364
365 flags |= HIST_FIELD_FL_KEY;
366
367 field = trace_find_event_field(file->event_call, field_str);
368 if (!field) {
369 ret = -EINVAL;
370 goto out;
371 }
372
373 key_size = field->size;
374
375 hist_data->fields[key_idx] = create_hist_field(field, flags);
376 if (!hist_data->fields[key_idx]) {
377 ret = -ENOMEM;
378 goto out;
379 }
380
381 key_size = ALIGN(key_size, sizeof(u64));
382 hist_data->fields[key_idx]->size = key_size;
383 hist_data->key_size = key_size;
384 if (hist_data->key_size > HIST_KEY_SIZE_MAX) {
385 ret = -EINVAL;
386 goto out;
387 }
388
389 hist_data->n_keys++;
390
391 if (WARN_ON(hist_data->n_keys > TRACING_MAP_KEYS_MAX))
392 return -EINVAL;
393
394 ret = key_size;
395 out:
396 return ret;
397}
398
399static int create_key_fields(struct hist_trigger_data *hist_data,
400 struct trace_event_file *file)
401{
402 unsigned int i, n_vals = hist_data->n_vals;
403 char *fields_str, *field_str;
404 int ret = -EINVAL;
405
406 fields_str = hist_data->attrs->keys_str;
407 if (!fields_str)
408 goto out;
409
410 strsep(&fields_str, "=");
411 if (!fields_str)
412 goto out;
413
414 for (i = n_vals; i < n_vals + HIST_KEY_MAX; i++) {
415 field_str = strsep(&fields_str, ",");
416 if (!field_str)
417 break;
418 ret = create_key_field(hist_data, i, file, field_str);
419 if (ret < 0)
420 goto out;
421 }
422 if (fields_str) {
423 ret = -EINVAL;
424 goto out;
425 }
426 ret = 0;
427 out:
428 return ret;
429}
430
431static int create_hist_fields(struct hist_trigger_data *hist_data,
432 struct trace_event_file *file)
433{
434 int ret;
435
436 ret = create_val_fields(hist_data, file);
437 if (ret)
438 goto out;
439
440 ret = create_key_fields(hist_data, file);
441 if (ret)
442 goto out;
443
444 hist_data->n_fields = hist_data->n_vals + hist_data->n_keys;
445 out:
446 return ret;
447}
448
449static int create_sort_keys(struct hist_trigger_data *hist_data)
450{
451 int ret = 0;
452
453 hist_data->n_sort_keys = 1; /* sort_keys[0] is always hitcount */
454
455 return ret;
456}
457
458static void destroy_hist_data(struct hist_trigger_data *hist_data)
459{
460 destroy_hist_trigger_attrs(hist_data->attrs);
461 destroy_hist_fields(hist_data);
462 tracing_map_destroy(hist_data->map);
463 kfree(hist_data);
464}
465
466static int create_tracing_map_fields(struct hist_trigger_data *hist_data)
467{
468 struct tracing_map *map = hist_data->map;
469 struct ftrace_event_field *field;
470 struct hist_field *hist_field;
471 unsigned int i, idx;
472
473 for_each_hist_field(i, hist_data) {
474 hist_field = hist_data->fields[i];
475 if (hist_field->flags & HIST_FIELD_FL_KEY) {
476 tracing_map_cmp_fn_t cmp_fn;
477
478 field = hist_field->field;
479
480 if (is_string_field(field))
481 cmp_fn = tracing_map_cmp_string;
482 else
483 cmp_fn = tracing_map_cmp_num(field->size,
484 field->is_signed);
485 idx = tracing_map_add_key_field(map, 0, cmp_fn);
486 } else
487 idx = tracing_map_add_sum_field(map);
488
489 if (idx < 0)
490 return idx;
491 }
492
493 return 0;
494}
495
496static struct hist_trigger_data *
497create_hist_data(unsigned int map_bits,
498 struct hist_trigger_attrs *attrs,
499 struct trace_event_file *file)
500{
501 struct hist_trigger_data *hist_data;
502 int ret = 0;
503
504 hist_data = kzalloc(sizeof(*hist_data), GFP_KERNEL);
505 if (!hist_data)
506 return ERR_PTR(-ENOMEM);
507
508 hist_data->attrs = attrs;
509
510 ret = create_hist_fields(hist_data, file);
511 if (ret)
512 goto free;
513
514 ret = create_sort_keys(hist_data);
515 if (ret)
516 goto free;
517
518 hist_data->map = tracing_map_create(map_bits, hist_data->key_size,
519 NULL, hist_data);
520 if (IS_ERR(hist_data->map)) {
521 ret = PTR_ERR(hist_data->map);
522 hist_data->map = NULL;
523 goto free;
524 }
525
526 ret = create_tracing_map_fields(hist_data);
527 if (ret)
528 goto free;
529
530 ret = tracing_map_init(hist_data->map);
531 if (ret)
532 goto free;
533
534 hist_data->event_file = file;
535 out:
536 return hist_data;
537 free:
538 hist_data->attrs = NULL;
539
540 destroy_hist_data(hist_data);
541
542 hist_data = ERR_PTR(ret);
543
544 goto out;
545}
546
547static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
548 struct tracing_map_elt *elt,
549 void *rec)
550{
551 struct hist_field *hist_field;
552 unsigned int i;
553 u64 hist_val;
554
555 for_each_hist_val_field(i, hist_data) {
556 hist_field = hist_data->fields[i];
557 hist_val = hist_field->fn(hist_field, rec);
558 tracing_map_update_sum(elt, i, hist_val);
559 }
560}
561
562static void event_hist_trigger(struct event_trigger_data *data, void *rec)
563{
564 struct hist_trigger_data *hist_data = data->private_data;
565 struct hist_field *key_field;
566 struct tracing_map_elt *elt;
567 u64 field_contents;
568 void *key = NULL;
569 unsigned int i;
570
571 for_each_hist_key_field(i, hist_data) {
572 key_field = hist_data->fields[i];
573
574 field_contents = key_field->fn(key_field, rec);
575 if (key_field->flags & HIST_FIELD_FL_STRING)
576 key = (void *)(unsigned long)field_contents;
577 else
578 key = (void *)&field_contents;
579 }
580
581 elt = tracing_map_insert(hist_data->map, key);
582 if (elt)
583 hist_trigger_elt_update(hist_data, elt, rec);
584}
585
586static void
587hist_trigger_entry_print(struct seq_file *m,
588 struct hist_trigger_data *hist_data, void *key,
589 struct tracing_map_elt *elt)
590{
591 struct hist_field *key_field;
592 unsigned int i;
593 u64 uval;
594
595 seq_puts(m, "{ ");
596
597 for_each_hist_key_field(i, hist_data) {
598 key_field = hist_data->fields[i];
599
600 if (i > hist_data->n_vals)
601 seq_puts(m, ", ");
602
603 if (key_field->flags & HIST_FIELD_FL_STRING) {
604 seq_printf(m, "%s: %-50s", key_field->field->name,
605 (char *)key);
606 } else {
607 uval = *(u64 *)key;
608 seq_printf(m, "%s: %10llu",
609 key_field->field->name, uval);
610 }
611 }
612
613 seq_puts(m, " }");
614
615 seq_printf(m, " hitcount: %10llu",
616 tracing_map_read_sum(elt, HITCOUNT_IDX));
617
f2606835
TZ
618 for (i = 1; i < hist_data->n_vals; i++) {
619 seq_printf(m, " %s: %10llu",
620 hist_data->fields[i]->field->name,
621 tracing_map_read_sum(elt, i));
622 }
623
7ef224d1
TZ
624 seq_puts(m, "\n");
625}
626
627static int print_entries(struct seq_file *m,
628 struct hist_trigger_data *hist_data)
629{
630 struct tracing_map_sort_entry **sort_entries = NULL;
631 struct tracing_map *map = hist_data->map;
632 unsigned int i, n_entries;
633
634 n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
635 hist_data->n_sort_keys,
636 &sort_entries);
637 if (n_entries < 0)
638 return n_entries;
639
640 for (i = 0; i < n_entries; i++)
641 hist_trigger_entry_print(m, hist_data,
642 sort_entries[i]->key,
643 sort_entries[i]->elt);
644
645 tracing_map_destroy_sort_entries(sort_entries, n_entries);
646
647 return n_entries;
648}
649
650static int hist_show(struct seq_file *m, void *v)
651{
652 struct event_trigger_data *test, *data = NULL;
653 struct trace_event_file *event_file;
654 struct hist_trigger_data *hist_data;
655 int n_entries, ret = 0;
656
657 mutex_lock(&event_mutex);
658
659 event_file = event_file_data(m->private);
660 if (unlikely(!event_file)) {
661 ret = -ENODEV;
662 goto out_unlock;
663 }
664
665 list_for_each_entry_rcu(test, &event_file->triggers, list) {
666 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
667 data = test;
668 break;
669 }
670 }
671 if (!data)
672 goto out_unlock;
673
674 seq_puts(m, "# event histogram\n#\n# trigger info: ");
675 data->ops->print(m, data->ops, data);
676 seq_puts(m, "\n");
677
678 hist_data = data->private_data;
679 n_entries = print_entries(m, hist_data);
680 if (n_entries < 0) {
681 ret = n_entries;
682 n_entries = 0;
683 }
684
685 seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n",
686 (u64)atomic64_read(&hist_data->map->hits),
687 n_entries, (u64)atomic64_read(&hist_data->map->drops));
688 out_unlock:
689 mutex_unlock(&event_mutex);
690
691 return ret;
692}
693
694static int event_hist_open(struct inode *inode, struct file *file)
695{
696 return single_open(file, hist_show, file);
697}
698
699const struct file_operations event_hist_fops = {
700 .open = event_hist_open,
701 .read = seq_read,
702 .llseek = seq_lseek,
703 .release = single_release,
704};
705
706static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
707{
708 seq_printf(m, "%s", hist_field->field->name);
709}
710
711static int event_hist_trigger_print(struct seq_file *m,
712 struct event_trigger_ops *ops,
713 struct event_trigger_data *data)
714{
715 struct hist_trigger_data *hist_data = data->private_data;
716 struct hist_field *key_field;
717 unsigned int i;
718
719 seq_puts(m, "hist:keys=");
720
721 for_each_hist_key_field(i, hist_data) {
722 key_field = hist_data->fields[i];
723
724 if (i > hist_data->n_vals)
725 seq_puts(m, ",");
726
727 hist_field_print(m, key_field);
728 }
729
730 seq_puts(m, ":vals=");
f2606835
TZ
731
732 for_each_hist_val_field(i, hist_data) {
733 if (i == HITCOUNT_IDX)
734 seq_puts(m, "hitcount");
735 else {
736 seq_puts(m, ",");
737 hist_field_print(m, hist_data->fields[i]);
738 }
739 }
7ef224d1
TZ
740
741 seq_puts(m, ":sort=");
742 seq_puts(m, "hitcount");
743
744 seq_printf(m, ":size=%u", (1 << hist_data->map->map_bits));
745
746 if (data->filter_str)
747 seq_printf(m, " if %s", data->filter_str);
748
749 seq_puts(m, " [active]");
750
751 seq_putc(m, '\n');
752
753 return 0;
754}
755
756static void event_hist_trigger_free(struct event_trigger_ops *ops,
757 struct event_trigger_data *data)
758{
759 struct hist_trigger_data *hist_data = data->private_data;
760
761 if (WARN_ON_ONCE(data->ref <= 0))
762 return;
763
764 data->ref--;
765 if (!data->ref) {
766 trigger_data_free(data);
767 destroy_hist_data(hist_data);
768 }
769}
770
771static struct event_trigger_ops event_hist_trigger_ops = {
772 .func = event_hist_trigger,
773 .print = event_hist_trigger_print,
774 .init = event_trigger_init,
775 .free = event_hist_trigger_free,
776};
777
778static struct event_trigger_ops *event_hist_get_trigger_ops(char *cmd,
779 char *param)
780{
781 return &event_hist_trigger_ops;
782}
783
784static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
785 struct event_trigger_data *data,
786 struct trace_event_file *file)
787{
788 struct event_trigger_data *test;
789 int ret = 0;
790
791 list_for_each_entry_rcu(test, &file->triggers, list) {
792 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
793 ret = -EEXIST;
794 goto out;
795 }
796 }
797
798 if (data->ops->init) {
799 ret = data->ops->init(data->ops, data);
800 if (ret < 0)
801 goto out;
802 }
803
804 list_add_rcu(&data->list, &file->triggers);
805 ret++;
806
807 update_cond_flag(file);
808 if (trace_event_trigger_enable_disable(file, 1) < 0) {
809 list_del_rcu(&data->list);
810 update_cond_flag(file);
811 ret--;
812 }
813 out:
814 return ret;
815}
816
817static int event_hist_trigger_func(struct event_command *cmd_ops,
818 struct trace_event_file *file,
819 char *glob, char *cmd, char *param)
820{
821 unsigned int hist_trigger_bits = TRACING_MAP_BITS_DEFAULT;
822 struct event_trigger_data *trigger_data;
823 struct hist_trigger_attrs *attrs;
824 struct event_trigger_ops *trigger_ops;
825 struct hist_trigger_data *hist_data;
826 char *trigger;
827 int ret = 0;
828
829 if (!param)
830 return -EINVAL;
831
832 /* separate the trigger from the filter (k:v [if filter]) */
833 trigger = strsep(&param, " \t");
834 if (!trigger)
835 return -EINVAL;
836
837 attrs = parse_hist_trigger_attrs(trigger);
838 if (IS_ERR(attrs))
839 return PTR_ERR(attrs);
840
841 if (attrs->map_bits)
842 hist_trigger_bits = attrs->map_bits;
843
844 hist_data = create_hist_data(hist_trigger_bits, attrs, file);
845 if (IS_ERR(hist_data)) {
846 destroy_hist_trigger_attrs(attrs);
847 return PTR_ERR(hist_data);
848 }
849
850 trigger_ops = cmd_ops->get_trigger_ops(cmd, trigger);
851
852 ret = -ENOMEM;
853 trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL);
854 if (!trigger_data)
855 goto out_free;
856
857 trigger_data->count = -1;
858 trigger_data->ops = trigger_ops;
859 trigger_data->cmd_ops = cmd_ops;
860
861 INIT_LIST_HEAD(&trigger_data->list);
862 RCU_INIT_POINTER(trigger_data->filter, NULL);
863
864 trigger_data->private_data = hist_data;
865
866 if (glob[0] == '!') {
867 cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
868 ret = 0;
869 goto out_free;
870 }
871
872 if (!param) /* if param is non-empty, it's supposed to be a filter */
873 goto out_reg;
874
875 if (!cmd_ops->set_filter)
876 goto out_reg;
877
878 ret = cmd_ops->set_filter(param, trigger_data, file);
879 if (ret < 0)
880 goto out_free;
881 out_reg:
882 ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file);
883 /*
884 * The above returns on success the # of triggers registered,
885 * but if it didn't register any it returns zero. Consider no
886 * triggers registered a failure too.
887 */
888 if (!ret) {
889 ret = -ENOENT;
890 goto out_free;
891 } else if (ret < 0)
892 goto out_free;
893 /* Just return zero, not the number of registered triggers */
894 ret = 0;
895 out:
896 return ret;
897 out_free:
898 if (cmd_ops->set_filter)
899 cmd_ops->set_filter(NULL, trigger_data, NULL);
900
901 kfree(trigger_data);
902
903 destroy_hist_data(hist_data);
904 goto out;
905}
906
907static struct event_command trigger_hist_cmd = {
908 .name = "hist",
909 .trigger_type = ETT_EVENT_HIST,
910 .flags = EVENT_CMD_FL_NEEDS_REC,
911 .func = event_hist_trigger_func,
912 .reg = hist_register_trigger,
913 .unreg = unregister_trigger,
914 .get_trigger_ops = event_hist_get_trigger_ops,
915 .set_filter = set_trigger_filter,
916};
917
918__init int register_trigger_hist_cmd(void)
919{
920 int ret;
921
922 ret = register_event_command(&trigger_hist_cmd);
923 WARN_ON(ret < 0);
924
925 return ret;
926}