OSDN Git Service

tracing: Use temp buffer when filtering events
[android-x86/kernel.git] / kernel / trace / trace.h
index f186867..5167c36 100644 (file)
@@ -125,6 +125,7 @@ enum trace_flag_type {
        TRACE_FLAG_HARDIRQ              = 0x08,
        TRACE_FLAG_SOFTIRQ              = 0x10,
        TRACE_FLAG_PREEMPT_RESCHED      = 0x20,
+       TRACE_FLAG_NMI                  = 0x40,
 };
 
 #define TRACE_BUF_SIZE         1024
@@ -176,9 +177,8 @@ struct trace_options {
 };
 
 struct trace_pid_list {
-       unsigned int                    nr_pids;
-       int                             order;
-       pid_t                           *pids;
+       int                             pid_max;
+       unsigned long                   *pids;
 };
 
 /*
@@ -655,6 +655,7 @@ static inline void __trace_stack(struct trace_array *tr, unsigned long flags,
 extern cycle_t ftrace_now(int cpu);
 
 extern void trace_find_cmdline(int pid, char comm[]);
+extern void trace_event_follow_fork(struct trace_array *tr, bool enable);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 extern unsigned long ftrace_update_tot_cnt;
@@ -966,6 +967,7 @@ extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
                C(STOP_ON_FREE,         "disable_on_free"),     \
                C(IRQ_INFO,             "irq-info"),            \
                C(MARKERS,              "markers"),             \
+               C(EVENT_FORK,           "event-fork"),          \
                FUNCTION_FLAGS                                  \
                FGRAPH_FLAGS                                    \
                STACK_FLAGS                                     \
@@ -1063,6 +1065,137 @@ struct trace_subsystem_dir {
        int                             nr_events;
 };
 
+extern int call_filter_check_discard(struct trace_event_call *call, void *rec,
+                                    struct ring_buffer *buffer,
+                                    struct ring_buffer_event *event);
+
+void trace_buffer_unlock_commit_regs(struct trace_array *tr,
+                                    struct ring_buffer *buffer,
+                                    struct ring_buffer_event *event,
+                                    unsigned long flags, int pc,
+                                    struct pt_regs *regs);
+
+static inline void trace_buffer_unlock_commit(struct trace_array *tr,
+                                             struct ring_buffer *buffer,
+                                             struct ring_buffer_event *event,
+                                             unsigned long flags, int pc)
+{
+       trace_buffer_unlock_commit_regs(tr, buffer, event, flags, pc, NULL);
+}
+
+DECLARE_PER_CPU(struct ring_buffer_event *, trace_buffered_event);
+DECLARE_PER_CPU(int, trace_buffered_event_cnt);
+void trace_buffered_event_disable(void);
+void trace_buffered_event_enable(void);
+
+static inline void
+__trace_event_discard_commit(struct ring_buffer *buffer,
+                            struct ring_buffer_event *event)
+{
+       if (this_cpu_read(trace_buffered_event) == event) {
+               /* Simply release the temp buffer */
+               this_cpu_dec(trace_buffered_event_cnt);
+               return;
+       }
+       ring_buffer_discard_commit(buffer, event);
+}
+
+/*
+ * Helper function for event_trigger_unlock_commit{_regs}().
+ * If there are event triggers attached to this event that requires
+ * filtering against its fields, then they wil be called as the
+ * entry already holds the field information of the current event.
+ *
+ * It also checks if the event should be discarded or not.
+ * It is to be discarded if the event is soft disabled and the
+ * event was only recorded to process triggers, or if the event
+ * filter is active and this event did not match the filters.
+ *
+ * Returns true if the event is discarded, false otherwise.
+ */
+static inline bool
+__event_trigger_test_discard(struct trace_event_file *file,
+                            struct ring_buffer *buffer,
+                            struct ring_buffer_event *event,
+                            void *entry,
+                            enum event_trigger_type *tt)
+{
+       unsigned long eflags = file->flags;
+
+       if (eflags & EVENT_FILE_FL_TRIGGER_COND)
+               *tt = event_triggers_call(file, entry);
+
+       if (test_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &file->flags) ||
+           (unlikely(file->flags & EVENT_FILE_FL_FILTERED) &&
+            !filter_match_preds(file->filter, entry))) {
+               __trace_event_discard_commit(buffer, event);
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * event_trigger_unlock_commit - handle triggers and finish event commit
+ * @file: The file pointer assoctiated to the event
+ * @buffer: The ring buffer that the event is being written to
+ * @event: The event meta data in the ring buffer
+ * @entry: The event itself
+ * @irq_flags: The state of the interrupts at the start of the event
+ * @pc: The state of the preempt count at the start of the event.
+ *
+ * This is a helper function to handle triggers that require data
+ * from the event itself. It also tests the event against filters and
+ * if the event is soft disabled and should be discarded.
+ */
+static inline void
+event_trigger_unlock_commit(struct trace_event_file *file,
+                           struct ring_buffer *buffer,
+                           struct ring_buffer_event *event,
+                           void *entry, unsigned long irq_flags, int pc)
+{
+       enum event_trigger_type tt = ETT_NONE;
+
+       if (!__event_trigger_test_discard(file, buffer, event, entry, &tt))
+               trace_buffer_unlock_commit(file->tr, buffer, event, irq_flags, pc);
+
+       if (tt)
+               event_triggers_post_call(file, tt, entry);
+}
+
+/**
+ * event_trigger_unlock_commit_regs - handle triggers and finish event commit
+ * @file: The file pointer assoctiated to the event
+ * @buffer: The ring buffer that the event is being written to
+ * @event: The event meta data in the ring buffer
+ * @entry: The event itself
+ * @irq_flags: The state of the interrupts at the start of the event
+ * @pc: The state of the preempt count at the start of the event.
+ *
+ * This is a helper function to handle triggers that require data
+ * from the event itself. It also tests the event against filters and
+ * if the event is soft disabled and should be discarded.
+ *
+ * Same as event_trigger_unlock_commit() but calls
+ * trace_buffer_unlock_commit_regs() instead of trace_buffer_unlock_commit().
+ */
+static inline void
+event_trigger_unlock_commit_regs(struct trace_event_file *file,
+                                struct ring_buffer *buffer,
+                                struct ring_buffer_event *event,
+                                void *entry, unsigned long irq_flags, int pc,
+                                struct pt_regs *regs)
+{
+       enum event_trigger_type tt = ETT_NONE;
+
+       if (!__event_trigger_test_discard(file, buffer, event, entry, &tt))
+               trace_buffer_unlock_commit_regs(file->tr, buffer, event,
+                                               irq_flags, pc, regs);
+
+       if (tt)
+               event_triggers_post_call(file, tt, entry);
+}
+
 #define FILTER_PRED_INVALID    ((unsigned short)-1)
 #define FILTER_PRED_IS_RIGHT   (1 << 15)
 #define FILTER_PRED_FOLD       (1 << 15)
@@ -1160,6 +1293,15 @@ extern struct mutex event_mutex;
 extern struct list_head ftrace_events;
 
 extern const struct file_operations event_trigger_fops;
+extern const struct file_operations event_hist_fops;
+
+#ifdef CONFIG_HIST_TRIGGERS
+extern int register_trigger_hist_cmd(void);
+extern int register_trigger_hist_enable_disable_cmds(void);
+#else
+static inline int register_trigger_hist_cmd(void) { return 0; }
+static inline int register_trigger_hist_enable_disable_cmds(void) { return 0; }
+#endif
 
 extern int register_trigger_cmds(void);
 extern void clear_event_triggers(struct trace_array *tr);
@@ -1173,9 +1315,41 @@ struct event_trigger_data {
        char                            *filter_str;
        void                            *private_data;
        bool                            paused;
+       bool                            paused_tmp;
        struct list_head                list;
+       char                            *name;
+       struct list_head                named_list;
+       struct event_trigger_data       *named_data;
+};
+
+/* Avoid typos */
+#define ENABLE_EVENT_STR       "enable_event"
+#define DISABLE_EVENT_STR      "disable_event"
+#define ENABLE_HIST_STR                "enable_hist"
+#define DISABLE_HIST_STR       "disable_hist"
+
+struct enable_trigger_data {
+       struct trace_event_file         *file;
+       bool                            enable;
+       bool                            hist;
 };
 
+extern int event_enable_trigger_print(struct seq_file *m,
+                                     struct event_trigger_ops *ops,
+                                     struct event_trigger_data *data);
+extern void event_enable_trigger_free(struct event_trigger_ops *ops,
+                                     struct event_trigger_data *data);
+extern int event_enable_trigger_func(struct event_command *cmd_ops,
+                                    struct trace_event_file *file,
+                                    char *glob, char *cmd, char *param);
+extern int event_enable_register_trigger(char *glob,
+                                        struct event_trigger_ops *ops,
+                                        struct event_trigger_data *data,
+                                        struct trace_event_file *file);
+extern void event_enable_unregister_trigger(char *glob,
+                                           struct event_trigger_ops *ops,
+                                           struct event_trigger_data *test,
+                                           struct trace_event_file *file);
 extern void trigger_data_free(struct event_trigger_data *data);
 extern int event_trigger_init(struct event_trigger_ops *ops,
                              struct event_trigger_data *data);
@@ -1188,7 +1362,18 @@ extern void unregister_trigger(char *glob, struct event_trigger_ops *ops,
 extern int set_trigger_filter(char *filter_str,
                              struct event_trigger_data *trigger_data,
                              struct trace_event_file *file);
+extern struct event_trigger_data *find_named_trigger(const char *name);
+extern bool is_named_trigger(struct event_trigger_data *test);
+extern int save_named_trigger(const char *name,
+                             struct event_trigger_data *data);
+extern void del_named_trigger(struct event_trigger_data *data);
+extern void pause_named_trigger(struct event_trigger_data *data);
+extern void unpause_named_trigger(struct event_trigger_data *data);
+extern void set_named_trigger_data(struct event_trigger_data *data,
+                                  struct event_trigger_data *named_data);
 extern int register_event_command(struct event_command *cmd);
+extern int unregister_event_command(struct event_command *cmd);
+extern int register_trigger_hist_enable_disable_cmds(void);
 
 /**
  * struct event_trigger_ops - callbacks for trace event triggers
@@ -1273,27 +1458,10 @@ struct event_trigger_ops {
  *     values are defined by adding new values to the trigger_type
  *     enum in include/linux/trace_events.h.
  *
- * @post_trigger: A flag that says whether or not this command needs
- *     to have its action delayed until after the current event has
- *     been closed.  Some triggers need to avoid being invoked while
- *     an event is currently in the process of being logged, since
- *     the trigger may itself log data into the trace buffer.  Thus
- *     we make sure the current event is committed before invoking
- *     those triggers.  To do that, the trigger invocation is split
- *     in two - the first part checks the filter using the current
- *     trace record; if a command has the @post_trigger flag set, it
- *     sets a bit for itself in the return value, otherwise it
- *     directly invokes the trigger.  Once all commands have been
- *     either invoked or set their return flag, the current record is
- *     either committed or discarded.  At that point, if any commands
- *     have deferred their triggers, those commands are finally
- *     invoked following the close of the current event.  In other
- *     words, if the event_trigger_ops @func() probe implementation
- *     itself logs to the trace buffer, this flag should be set,
- *     otherwise it can be left unspecified.
+ * @flags: See the enum event_command_flags below.
  *
- * All the methods below, except for @set_filter(), must be
- * implemented.
+ * All the methods below, except for @set_filter() and @unreg_all(),
+ * must be implemented.
  *
  * @func: The callback function responsible for parsing and
  *     registering the trigger written to the 'trigger' file by the
@@ -1318,6 +1486,10 @@ struct event_trigger_ops {
  *     This is usually implemented by the generic utility function
  *     @unregister_trigger() (see trace_event_triggers.c).
  *
+ * @unreg_all: An optional function called to remove all the triggers
+ *     from the list of triggers associated with the event.  Called
+ *     when a trigger file is opened in truncate mode.
+ *
  * @set_filter: An optional function called to parse and set a filter
  *     for the trigger.  If no @set_filter() method is set for the
  *     event command, filters set by the user for the command will be
@@ -1331,7 +1503,7 @@ struct event_command {
        struct list_head        list;
        char                    *name;
        enum event_trigger_type trigger_type;
-       bool                    post_trigger;
+       int                     flags;
        int                     (*func)(struct event_command *cmd_ops,
                                        struct trace_event_file *file,
                                        char *glob, char *cmd, char *params);
@@ -1343,12 +1515,56 @@ struct event_command {
                                         struct event_trigger_ops *ops,
                                         struct event_trigger_data *data,
                                         struct trace_event_file *file);
+       void                    (*unreg_all)(struct trace_event_file *file);
        int                     (*set_filter)(char *filter_str,
                                              struct event_trigger_data *data,
                                              struct trace_event_file *file);
        struct event_trigger_ops *(*get_trigger_ops)(char *cmd, char *param);
 };
 
+/**
+ * enum event_command_flags - flags for struct event_command
+ *
+ * @POST_TRIGGER: A flag that says whether or not this command needs
+ *     to have its action delayed until after the current event has
+ *     been closed.  Some triggers need to avoid being invoked while
+ *     an event is currently in the process of being logged, since
+ *     the trigger may itself log data into the trace buffer.  Thus
+ *     we make sure the current event is committed before invoking
+ *     those triggers.  To do that, the trigger invocation is split
+ *     in two - the first part checks the filter using the current
+ *     trace record; if a command has the @post_trigger flag set, it
+ *     sets a bit for itself in the return value, otherwise it
+ *     directly invokes the trigger.  Once all commands have been
+ *     either invoked or set their return flag, the current record is
+ *     either committed or discarded.  At that point, if any commands
+ *     have deferred their triggers, those commands are finally
+ *     invoked following the close of the current event.  In other
+ *     words, if the event_trigger_ops @func() probe implementation
+ *     itself logs to the trace buffer, this flag should be set,
+ *     otherwise it can be left unspecified.
+ *
+ * @NEEDS_REC: A flag that says whether or not this command needs
+ *     access to the trace record in order to perform its function,
+ *     regardless of whether or not it has a filter associated with
+ *     it (filters make a trigger require access to the trace record
+ *     but are not always present).
+ */
+enum event_command_flags {
+       EVENT_CMD_FL_POST_TRIGGER       = 1,
+       EVENT_CMD_FL_NEEDS_REC          = 2,
+};
+
+static inline bool event_command_post_trigger(struct event_command *cmd_ops)
+{
+       return cmd_ops->flags & EVENT_CMD_FL_POST_TRIGGER;
+}
+
+static inline bool event_command_needs_rec(struct event_command *cmd_ops)
+{
+       return cmd_ops->flags & EVENT_CMD_FL_NEEDS_REC;
+}
+
 extern int trace_event_enable_disable(struct trace_event_file *file,
                                      int enable, int soft_disable);
 extern int tracing_alloc_snapshot(void);