15448d44cSMasami Hiramatsu /* SPDX-License-Identifier: GPL-2.0 */
25448d44cSMasami Hiramatsu /*
35448d44cSMasami Hiramatsu * Common header file for generic dynamic events.
45448d44cSMasami Hiramatsu */
55448d44cSMasami Hiramatsu
65448d44cSMasami Hiramatsu #ifndef _TRACE_DYNEVENT_H
75448d44cSMasami Hiramatsu #define _TRACE_DYNEVENT_H
85448d44cSMasami Hiramatsu
95448d44cSMasami Hiramatsu #include <linux/kernel.h>
105448d44cSMasami Hiramatsu #include <linux/list.h>
115448d44cSMasami Hiramatsu #include <linux/mutex.h>
125448d44cSMasami Hiramatsu #include <linux/seq_file.h>
135448d44cSMasami Hiramatsu
145448d44cSMasami Hiramatsu #include "trace.h"
155448d44cSMasami Hiramatsu
165448d44cSMasami Hiramatsu struct dyn_event;
175448d44cSMasami Hiramatsu
185448d44cSMasami Hiramatsu /**
195448d44cSMasami Hiramatsu * struct dyn_event_operations - Methods for each type of dynamic events
205448d44cSMasami Hiramatsu *
215448d44cSMasami Hiramatsu * These methods must be set for each type, since there is no default method.
225448d44cSMasami Hiramatsu * Before using this for dyn_event_init(), it must be registered by
235448d44cSMasami Hiramatsu * dyn_event_register().
245448d44cSMasami Hiramatsu *
255448d44cSMasami Hiramatsu * @create: Parse and create event method. This is invoked when user passes
265448d44cSMasami Hiramatsu * a event definition to dynamic_events interface. This must not destruct
275448d44cSMasami Hiramatsu * the arguments and return -ECANCELED if given arguments doesn't match its
285448d44cSMasami Hiramatsu * command prefix.
295448d44cSMasami Hiramatsu * @show: Showing method. This is invoked when user reads the event definitions
305448d44cSMasami Hiramatsu * via dynamic_events interface.
315448d44cSMasami Hiramatsu * @is_busy: Check whether given event is busy so that it can not be deleted.
322b5894ccSQiujun Huang * Return true if it is busy, otherwise false.
332b5894ccSQiujun Huang * @free: Delete the given event. Return 0 if success, otherwise error.
3430199137SMasami Hiramatsu * @match: Check whether given event and system name match this event. The argc
352b5894ccSQiujun Huang * and argv is used for exact match. Return true if it matches, otherwise
3630199137SMasami Hiramatsu * false.
375448d44cSMasami Hiramatsu *
385448d44cSMasami Hiramatsu * Except for @create, these methods are called under holding event_mutex.
395448d44cSMasami Hiramatsu */
405448d44cSMasami Hiramatsu struct dyn_event_operations {
415448d44cSMasami Hiramatsu struct list_head list;
42d262271dSMasami Hiramatsu int (*create)(const char *raw_command);
435448d44cSMasami Hiramatsu int (*show)(struct seq_file *m, struct dyn_event *ev);
445448d44cSMasami Hiramatsu bool (*is_busy)(struct dyn_event *ev);
455448d44cSMasami Hiramatsu int (*free)(struct dyn_event *ev);
465448d44cSMasami Hiramatsu bool (*match)(const char *system, const char *event,
4730199137SMasami Hiramatsu int argc, const char **argv, struct dyn_event *ev);
485448d44cSMasami Hiramatsu };
495448d44cSMasami Hiramatsu
505448d44cSMasami Hiramatsu /* Register new dyn_event type -- must be called at first */
515448d44cSMasami Hiramatsu int dyn_event_register(struct dyn_event_operations *ops);
525448d44cSMasami Hiramatsu
535448d44cSMasami Hiramatsu /**
545448d44cSMasami Hiramatsu * struct dyn_event - Dynamic event list header
555448d44cSMasami Hiramatsu *
565448d44cSMasami Hiramatsu * The dyn_event structure encapsulates a list and a pointer to the operators
575448d44cSMasami Hiramatsu * for making a global list of dynamic events.
585448d44cSMasami Hiramatsu * User must includes this in each event structure, so that those events can
595448d44cSMasami Hiramatsu * be added/removed via dynamic_events interface.
605448d44cSMasami Hiramatsu */
615448d44cSMasami Hiramatsu struct dyn_event {
625448d44cSMasami Hiramatsu struct list_head list;
635448d44cSMasami Hiramatsu struct dyn_event_operations *ops;
645448d44cSMasami Hiramatsu };
655448d44cSMasami Hiramatsu
665448d44cSMasami Hiramatsu extern struct list_head dyn_event_list;
675448d44cSMasami Hiramatsu
685448d44cSMasami Hiramatsu static inline
dyn_event_init(struct dyn_event * ev,struct dyn_event_operations * ops)695448d44cSMasami Hiramatsu int dyn_event_init(struct dyn_event *ev, struct dyn_event_operations *ops)
705448d44cSMasami Hiramatsu {
715448d44cSMasami Hiramatsu if (!ev || !ops)
725448d44cSMasami Hiramatsu return -EINVAL;
735448d44cSMasami Hiramatsu
745448d44cSMasami Hiramatsu INIT_LIST_HEAD(&ev->list);
755448d44cSMasami Hiramatsu ev->ops = ops;
765448d44cSMasami Hiramatsu return 0;
775448d44cSMasami Hiramatsu }
785448d44cSMasami Hiramatsu
dyn_event_add(struct dyn_event * ev,struct trace_event_call * call)79*8b0e6c74SSteven Rostedt (VMware) static inline int dyn_event_add(struct dyn_event *ev,
80*8b0e6c74SSteven Rostedt (VMware) struct trace_event_call *call)
815448d44cSMasami Hiramatsu {
825448d44cSMasami Hiramatsu lockdep_assert_held(&event_mutex);
835448d44cSMasami Hiramatsu
845448d44cSMasami Hiramatsu if (!ev || !ev->ops)
855448d44cSMasami Hiramatsu return -EINVAL;
865448d44cSMasami Hiramatsu
87*8b0e6c74SSteven Rostedt (VMware) call->flags |= TRACE_EVENT_FL_DYNAMIC;
885448d44cSMasami Hiramatsu list_add_tail(&ev->list, &dyn_event_list);
895448d44cSMasami Hiramatsu return 0;
905448d44cSMasami Hiramatsu }
915448d44cSMasami Hiramatsu
dyn_event_remove(struct dyn_event * ev)925448d44cSMasami Hiramatsu static inline void dyn_event_remove(struct dyn_event *ev)
935448d44cSMasami Hiramatsu {
945448d44cSMasami Hiramatsu lockdep_assert_held(&event_mutex);
955448d44cSMasami Hiramatsu list_del_init(&ev->list);
965448d44cSMasami Hiramatsu }
975448d44cSMasami Hiramatsu
985448d44cSMasami Hiramatsu void *dyn_event_seq_start(struct seq_file *m, loff_t *pos);
995448d44cSMasami Hiramatsu void *dyn_event_seq_next(struct seq_file *m, void *v, loff_t *pos);
1005448d44cSMasami Hiramatsu void dyn_event_seq_stop(struct seq_file *m, void *v);
1015448d44cSMasami Hiramatsu int dyn_events_release_all(struct dyn_event_operations *type);
102d262271dSMasami Hiramatsu int dyn_event_release(const char *raw_command, struct dyn_event_operations *type);
1035448d44cSMasami Hiramatsu
1045448d44cSMasami Hiramatsu /*
1055448d44cSMasami Hiramatsu * for_each_dyn_event - iterate over the dyn_event list
1065448d44cSMasami Hiramatsu * @pos: the struct dyn_event * to use as a loop cursor
1075448d44cSMasami Hiramatsu *
1085448d44cSMasami Hiramatsu * This is just a basement of for_each macro. Wrap this for
1095448d44cSMasami Hiramatsu * each actual event structure with ops filtering.
1105448d44cSMasami Hiramatsu */
1115448d44cSMasami Hiramatsu #define for_each_dyn_event(pos) \
1125448d44cSMasami Hiramatsu list_for_each_entry(pos, &dyn_event_list, list)
1135448d44cSMasami Hiramatsu
1145448d44cSMasami Hiramatsu /*
1155448d44cSMasami Hiramatsu * for_each_dyn_event - iterate over the dyn_event list safely
1165448d44cSMasami Hiramatsu * @pos: the struct dyn_event * to use as a loop cursor
1175448d44cSMasami Hiramatsu * @n: the struct dyn_event * to use as temporary storage
1185448d44cSMasami Hiramatsu */
1195448d44cSMasami Hiramatsu #define for_each_dyn_event_safe(pos, n) \
1205448d44cSMasami Hiramatsu list_for_each_entry_safe(pos, n, &dyn_event_list, list)
1215448d44cSMasami Hiramatsu
12286c5426bSTom Zanussi extern void dynevent_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen,
12386c5426bSTom Zanussi enum dynevent_type type,
12486c5426bSTom Zanussi dynevent_create_fn_t run_command);
12586c5426bSTom Zanussi
12686c5426bSTom Zanussi typedef int (*dynevent_check_arg_fn_t)(void *data);
12786c5426bSTom Zanussi
12886c5426bSTom Zanussi struct dynevent_arg {
12986c5426bSTom Zanussi const char *str;
13086c5426bSTom Zanussi char separator; /* e.g. ';', ',', or nothing */
13186c5426bSTom Zanussi };
13286c5426bSTom Zanussi
13386c5426bSTom Zanussi extern void dynevent_arg_init(struct dynevent_arg *arg,
13486c5426bSTom Zanussi char separator);
13586c5426bSTom Zanussi extern int dynevent_arg_add(struct dynevent_cmd *cmd,
13674403b6cSTom Zanussi struct dynevent_arg *arg,
13774403b6cSTom Zanussi dynevent_check_arg_fn_t check_arg);
13886c5426bSTom Zanussi
13986c5426bSTom Zanussi struct dynevent_arg_pair {
14086c5426bSTom Zanussi const char *lhs;
14186c5426bSTom Zanussi const char *rhs;
14286c5426bSTom Zanussi char operator; /* e.g. '=' or nothing */
14386c5426bSTom Zanussi char separator; /* e.g. ';', ',', or nothing */
14486c5426bSTom Zanussi };
14586c5426bSTom Zanussi
14686c5426bSTom Zanussi extern void dynevent_arg_pair_init(struct dynevent_arg_pair *arg_pair,
14786c5426bSTom Zanussi char operator, char separator);
14874403b6cSTom Zanussi
14986c5426bSTom Zanussi extern int dynevent_arg_pair_add(struct dynevent_cmd *cmd,
15074403b6cSTom Zanussi struct dynevent_arg_pair *arg_pair,
15174403b6cSTom Zanussi dynevent_check_arg_fn_t check_arg);
15286c5426bSTom Zanussi extern int dynevent_str_add(struct dynevent_cmd *cmd, const char *str);
15386c5426bSTom Zanussi
1545448d44cSMasami Hiramatsu #endif
155