]> Pileus Git - ~andy/linux/blobdiff - include/linux/ftrace_event.h
Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[~andy/linux] / include / linux / ftrace_event.h
index 8c9b7a1c4138b87a79833bc400370a13e94cf270..4cdb3a17bcb5932113020955cf8aa46b7b592f14 100644 (file)
@@ -1,3 +1,4 @@
+
 #ifndef _LINUX_FTRACE_EVENT_H
 #define _LINUX_FTRACE_EVENT_H
 
@@ -264,6 +265,8 @@ enum {
        FTRACE_EVENT_FL_NO_SET_FILTER_BIT,
        FTRACE_EVENT_FL_SOFT_MODE_BIT,
        FTRACE_EVENT_FL_SOFT_DISABLED_BIT,
+       FTRACE_EVENT_FL_TRIGGER_MODE_BIT,
+       FTRACE_EVENT_FL_TRIGGER_COND_BIT,
 };
 
 /*
@@ -275,6 +278,8 @@ enum {
  *  SOFT_MODE     - The event is enabled/disabled by SOFT_DISABLED
  *  SOFT_DISABLED - When set, do not trace the event (even though its
  *                   tracepoint may be enabled)
+ *  TRIGGER_MODE  - When set, invoke the triggers associated with the event
+ *  TRIGGER_COND  - When set, one or more triggers has an associated filter
  */
 enum {
        FTRACE_EVENT_FL_ENABLED         = (1 << FTRACE_EVENT_FL_ENABLED_BIT),
@@ -283,6 +288,8 @@ enum {
        FTRACE_EVENT_FL_NO_SET_FILTER   = (1 << FTRACE_EVENT_FL_NO_SET_FILTER_BIT),
        FTRACE_EVENT_FL_SOFT_MODE       = (1 << FTRACE_EVENT_FL_SOFT_MODE_BIT),
        FTRACE_EVENT_FL_SOFT_DISABLED   = (1 << FTRACE_EVENT_FL_SOFT_DISABLED_BIT),
+       FTRACE_EVENT_FL_TRIGGER_MODE    = (1 << FTRACE_EVENT_FL_TRIGGER_MODE_BIT),
+       FTRACE_EVENT_FL_TRIGGER_COND    = (1 << FTRACE_EVENT_FL_TRIGGER_COND_BIT),
 };
 
 struct ftrace_event_file {
@@ -292,6 +299,7 @@ struct ftrace_event_file {
        struct dentry                   *dir;
        struct trace_array              *tr;
        struct ftrace_subsystem_dir     *system;
+       struct list_head                triggers;
 
        /*
         * 32 bit flags:
@@ -299,6 +307,7 @@ struct ftrace_event_file {
         *   bit 1:             enabled cmd record
         *   bit 2:             enable/disable with the soft disable bit
         *   bit 3:             soft disabled
+        *   bit 4:             trigger enabled
         *
         * Note: The bits must be set atomically to prevent races
         * from other writers. Reads of flags do not need to be in
@@ -310,6 +319,7 @@ struct ftrace_event_file {
         */
        unsigned long           flags;
        atomic_t                sm_ref; /* soft-mode reference counter */
+       atomic_t                tm_ref; /* trigger-mode reference counter */
 };
 
 #define __TRACE_EVENT_FLAGS(name, value)                               \
@@ -337,6 +347,14 @@ struct ftrace_event_file {
 
 #define MAX_FILTER_STR_VAL     256     /* Should handle KSYM_SYMBOL_LEN */
 
+enum event_trigger_type {
+       ETT_NONE                = (0),
+       ETT_TRACE_ONOFF         = (1 << 0),
+       ETT_SNAPSHOT            = (1 << 1),
+       ETT_STACKTRACE          = (1 << 2),
+       ETT_EVENT_ENABLE        = (1 << 3),
+};
+
 extern void destroy_preds(struct ftrace_event_file *file);
 extern void destroy_call_preds(struct ftrace_event_call *call);
 extern int filter_match_preds(struct event_filter *filter, void *rec);
@@ -347,6 +365,127 @@ extern int filter_check_discard(struct ftrace_event_file *file, void *rec,
 extern int call_filter_check_discard(struct ftrace_event_call *call, void *rec,
                                     struct ring_buffer *buffer,
                                     struct ring_buffer_event *event);
+extern enum event_trigger_type event_triggers_call(struct ftrace_event_file *file,
+                                                  void *rec);
+extern void event_triggers_post_call(struct ftrace_event_file *file,
+                                    enum event_trigger_type tt);
+
+/**
+ * ftrace_trigger_soft_disabled - do triggers and test if soft disabled
+ * @file: The file pointer of the event to test
+ *
+ * If any triggers without filters are attached to this event, they
+ * will be called here. If the event is soft disabled and has no
+ * triggers that require testing the fields, it will return true,
+ * otherwise false.
+ */
+static inline bool
+ftrace_trigger_soft_disabled(struct ftrace_event_file *file)
+{
+       unsigned long eflags = file->flags;
+
+       if (!(eflags & FTRACE_EVENT_FL_TRIGGER_COND)) {
+               if (eflags & FTRACE_EVENT_FL_TRIGGER_MODE)
+                       event_triggers_call(file, NULL);
+               if (eflags & FTRACE_EVENT_FL_SOFT_DISABLED)
+                       return true;
+       }
+       return false;
+}
+
+/*
+ * 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 ftrace_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 & FTRACE_EVENT_FL_TRIGGER_COND)
+               *tt = event_triggers_call(file, entry);
+
+       if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags))
+               ring_buffer_discard_commit(buffer, event);
+       else if (!filter_check_discard(file, entry, buffer, event))
+               return false;
+
+       return true;
+}
+
+/**
+ * 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 ftrace_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(buffer, event, irq_flags, pc);
+
+       if (tt)
+               event_triggers_post_call(file, tt);
+}
+
+/**
+ * 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 ftrace_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(buffer, event,
+                                               irq_flags, pc, regs);
+
+       if (tt)
+               event_triggers_post_call(file, tt);
+}
 
 enum {
        FILTER_OTHER = 0,
@@ -356,10 +495,6 @@ enum {
        FILTER_TRACE_FN,
 };
 
-#define EVENT_STORAGE_SIZE 128
-extern struct mutex event_storage_mutex;
-extern char event_storage[EVENT_STORAGE_SIZE];
-
 extern int trace_event_raw_init(struct ftrace_event_call *call);
 extern int trace_define_field(struct ftrace_event_call *call, const char *type,
                              const char *name, int offset, int size,