ftrace: Annotate the ops operation on update
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>
Tue, 5 Aug 2014 21:19:38 +0000 (17:19 -0400)
committerSteven Rostedt <rostedt@goodmis.org>
Wed, 10 Sep 2014 14:48:44 +0000 (10:48 -0400)
Add three new flags for ftrace_ops:

  FTRACE_OPS_FL_ADDING
  FTRACE_OPS_FL_REMOVING
  FTRACE_OPS_FL_MODIFYING

These will be set for the ftrace_ops when they are first added
to the function tracing, being removed from function tracing
or just having their functions changed from function tracing,
respectively.

This will be needed to remove the tramp_hash, which can grow quite
big. The tramp_hash is used to note what functions a ftrace_ops
is using a trampoline for. Denoting which ftrace_ops is being
modified, will allow us to use the ftrace_ops hashes themselves,
which are much smaller as they have a global flag to denote if
a ftrace_ops is tracing all functions, as well as a notrace hash
if the ftrace_ops is tracing all but a few. The tramp_hash just
creates a hash item for every function, which can go into the 10s
of thousands if all functions are using the ftrace_ops trampoline.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
include/linux/ftrace.h
kernel/trace/ftrace.c

index ef37286547fc5b6cf62affe86d11c16ff08c8c95..d9216f6385d9cae001407e8ffbb0dcd988362e03 100644 (file)
@@ -91,6 +91,9 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops);
  * INITIALIZED - The ftrace_ops has already been initialized (first use time
  *            register_ftrace_function() is called, it will initialized the ops)
  * DELETED - The ops are being deleted, do not let them be registered again.
+ * ADDING  - The ops is in the process of being added.
+ * REMOVING - The ops is in the process of being removed.
+ * MODIFYING - The ops is in the process of changing its filter functions.
  */
 enum {
        FTRACE_OPS_FL_ENABLED                   = 1 << 0,
@@ -102,6 +105,9 @@ enum {
        FTRACE_OPS_FL_STUB                      = 1 << 6,
        FTRACE_OPS_FL_INITIALIZED               = 1 << 7,
        FTRACE_OPS_FL_DELETED                   = 1 << 8,
+       FTRACE_OPS_FL_ADDING                    = 1 << 9,
+       FTRACE_OPS_FL_REMOVING                  = 1 << 10,
+       FTRACE_OPS_FL_MODIFYING                 = 1 << 11,
 };
 
 #ifdef CONFIG_DYNAMIC_FTRACE
index 858ac16f84920ab6238db2ddcd383cfa1972baa5..e43c793093e568c087b93a30a342e8d33f20102f 100644 (file)
@@ -1057,6 +1057,12 @@ static struct pid * const ftrace_swapper_pid = &init_struct_pid;
 
 static struct ftrace_ops *removed_ops;
 
+/*
+ * Set when doing a global update, like enabling all recs or disabling them.
+ * It is not set when just updating a single ftrace_ops.
+ */
+static bool update_all_ops;
+
 #ifndef CONFIG_FTRACE_MCOUNT_RECORD
 # error Dynamic ftrace depends on MCOUNT_RECORD
 #endif
@@ -2366,6 +2372,13 @@ static void ftrace_run_update_code(int command)
        FTRACE_WARN_ON(ret);
 }
 
+static void ftrace_run_modify_code(struct ftrace_ops *ops, int command)
+{
+       ops->flags |= FTRACE_OPS_FL_MODIFYING;
+       ftrace_run_update_code(command);
+       ops->flags &= ~FTRACE_OPS_FL_MODIFYING;
+}
+
 static ftrace_func_t saved_ftrace_func;
 static int ftrace_start_up;
 
@@ -2387,6 +2400,13 @@ static void ftrace_startup_enable(int command)
        ftrace_run_update_code(command);
 }
 
+static void ftrace_startup_all(int command)
+{
+       update_all_ops = true;
+       ftrace_startup_enable(command);
+       update_all_ops = false;
+}
+
 static int ftrace_startup(struct ftrace_ops *ops, int command)
 {
        int ret;
@@ -2401,12 +2421,22 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)
        ftrace_start_up++;
        command |= FTRACE_UPDATE_CALLS;
 
-       ops->flags |= FTRACE_OPS_FL_ENABLED;
+       /*
+        * Note that ftrace probes uses this to start up
+        * and modify functions it will probe. But we still
+        * set the ADDING flag for modification, as probes
+        * do not have trampolines. If they add them in the
+        * future, then the probes will need to distinguish
+        * between adding and updating probes.
+        */
+       ops->flags |= FTRACE_OPS_FL_ENABLED | FTRACE_OPS_FL_ADDING;
 
        ftrace_hash_rec_enable(ops, 1);
 
        ftrace_startup_enable(command);
 
+       ops->flags &= ~FTRACE_OPS_FL_ADDING;
+
        return 0;
 }
 
@@ -2456,11 +2486,12 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
         * If the ops uses a trampoline, then it needs to be
         * tested first on update.
         */
+       ops->flags |= FTRACE_OPS_FL_REMOVING;
        removed_ops = ops;
 
        ftrace_run_update_code(command);
 
-       removed_ops = NULL;
+       ops->flags &= ~FTRACE_OPS_FL_REMOVING;
 
        /*
         * Dynamic ops may be freed, we must make sure that all
@@ -3373,7 +3404,7 @@ static void __enable_ftrace_function_probe(void)
        if (ftrace_probe_registered) {
                /* still need to update the function call sites */
                if (ftrace_enabled)
-                       ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+                       ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS);
                return;
        }
 
@@ -3792,7 +3823,7 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
 static void ftrace_ops_update_code(struct ftrace_ops *ops)
 {
        if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled)
-               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+               ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS);
 }
 
 static int
@@ -4717,6 +4748,7 @@ core_initcall(ftrace_nodyn_init);
 
 static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; }
 static inline void ftrace_startup_enable(int command) { }
+static inline void ftrace_startup_all(int command) { }
 /* Keep as macros so we do not need to define the commands */
 # define ftrace_startup(ops, command)                                  \
        ({                                                              \
@@ -5016,7 +5048,8 @@ static int ftrace_pid_add(int p)
        set_ftrace_pid_task(pid);
 
        ftrace_update_pid_func();
-       ftrace_startup_enable(0);
+
+       ftrace_startup_all(0);
 
        mutex_unlock(&ftrace_lock);
        return 0;
@@ -5045,7 +5078,7 @@ static void ftrace_pid_reset(void)
        }
 
        ftrace_update_pid_func();
-       ftrace_startup_enable(0);
+       ftrace_startup_all(0);
 
        mutex_unlock(&ftrace_lock);
 }