ftrace: Pass retval through return in ftrace_dyn_arch_init()
[cascardo/linux.git] / kernel / trace / ftrace.c
index cd7f76d..083c6d5 100644 (file)
@@ -244,7 +244,11 @@ static void control_ops_free(struct ftrace_ops *ops)
 
 static void update_global_ops(void)
 {
-       ftrace_func_t func;
+       ftrace_func_t func = ftrace_global_list_func;
+       void *private = NULL;
+
+       /* The list has its own recursion protection. */
+       global_ops.flags |= FTRACE_OPS_FL_RECURSION_SAFE;
 
        /*
         * If there's only one function registered, then call that
@@ -254,23 +258,17 @@ static void update_global_ops(void)
        if (ftrace_global_list == &ftrace_list_end ||
            ftrace_global_list->next == &ftrace_list_end) {
                func = ftrace_global_list->func;
+               private = ftrace_global_list->private;
                /*
                 * As we are calling the function directly.
                 * If it does not have recursion protection,
                 * the function_trace_op needs to be updated
                 * accordingly.
                 */
-               if (ftrace_global_list->flags & FTRACE_OPS_FL_RECURSION_SAFE)
-                       global_ops.flags |= FTRACE_OPS_FL_RECURSION_SAFE;
-               else
+               if (!(ftrace_global_list->flags & FTRACE_OPS_FL_RECURSION_SAFE))
                        global_ops.flags &= ~FTRACE_OPS_FL_RECURSION_SAFE;
-       } else {
-               func = ftrace_global_list_func;
-               /* The list has its own recursion protection. */
-               global_ops.flags |= FTRACE_OPS_FL_RECURSION_SAFE;
        }
 
-
        /* If we filter on pids, update to use the pid function */
        if (!list_empty(&ftrace_pids)) {
                set_ftrace_pid_function(func);
@@ -278,6 +276,7 @@ static void update_global_ops(void)
        }
 
        global_ops.func = func;
+       global_ops.private = private;
 }
 
 static void ftrace_sync(struct work_struct *work)
@@ -437,6 +436,9 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list,
 
 static int __register_ftrace_function(struct ftrace_ops *ops)
 {
+       if (ops->flags & FTRACE_OPS_FL_DELETED)
+               return -EINVAL;
+
        if (FTRACE_WARN_ON(ops == &global_ops))
                return -EINVAL;
 
@@ -1172,8 +1174,6 @@ struct ftrace_page {
        int                     size;
 };
 
-static struct ftrace_page *ftrace_new_pgs;
-
 #define ENTRY_SIZE sizeof(struct dyn_ftrace)
 #define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE)
 
@@ -2244,7 +2244,6 @@ static void ftrace_shutdown_sysctl(void)
 }
 
 static cycle_t         ftrace_update_time;
-static unsigned long   ftrace_update_cnt;
 unsigned long          ftrace_update_tot_cnt;
 
 static inline int ops_traces_mod(struct ftrace_ops *ops)
@@ -2300,11 +2299,12 @@ static int referenced_filters(struct dyn_ftrace *rec)
        return cnt;
 }
 
-static int ftrace_update_code(struct module *mod)
+static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs)
 {
        struct ftrace_page *pg;
        struct dyn_ftrace *p;
        cycle_t start, stop;
+       unsigned long update_cnt = 0;
        unsigned long ref = 0;
        bool test = false;
        int i;
@@ -2330,9 +2330,8 @@ static int ftrace_update_code(struct module *mod)
        }
 
        start = ftrace_now(raw_smp_processor_id());
-       ftrace_update_cnt = 0;
 
-       for (pg = ftrace_new_pgs; pg; pg = pg->next) {
+       for (pg = new_pgs; pg; pg = pg->next) {
 
                for (i = 0; i < pg->index; i++) {
                        int cnt = ref;
@@ -2353,7 +2352,7 @@ static int ftrace_update_code(struct module *mod)
                        if (!ftrace_code_disable(mod, p))
                                break;
 
-                       ftrace_update_cnt++;
+                       update_cnt++;
 
                        /*
                         * If the tracing is enabled, go ahead and enable the record.
@@ -2372,11 +2371,9 @@ static int ftrace_update_code(struct module *mod)
                }
        }
 
-       ftrace_new_pgs = NULL;
-
        stop = ftrace_now(raw_smp_processor_id());
        ftrace_update_time = stop - start;
-       ftrace_update_tot_cnt += ftrace_update_cnt;
+       ftrace_update_tot_cnt += update_cnt;
 
        return 0;
 }
@@ -2468,22 +2465,6 @@ ftrace_allocate_pages(unsigned long num_to_init)
        return NULL;
 }
 
-static int __init ftrace_dyn_table_alloc(unsigned long num_to_init)
-{
-       int cnt;
-
-       if (!num_to_init) {
-               pr_info("ftrace: No functions to be traced?\n");
-               return -1;
-       }
-
-       cnt = num_to_init / ENTRIES_PER_PAGE;
-       pr_info("ftrace: allocating %ld entries in %d pages\n",
-               num_to_init, cnt + 1);
-
-       return 0;
-}
-
 #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */
 
 struct ftrace_iterator {
@@ -2871,7 +2852,9 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
 static int
 ftrace_filter_open(struct inode *inode, struct file *file)
 {
-       return ftrace_regex_open(&global_ops,
+       struct ftrace_ops *ops = inode->i_private;
+
+       return ftrace_regex_open(ops,
                        FTRACE_ITER_FILTER | FTRACE_ITER_DO_HASH,
                        inode, file);
 }
@@ -2879,7 +2862,9 @@ ftrace_filter_open(struct inode *inode, struct file *file)
 static int
 ftrace_notrace_open(struct inode *inode, struct file *file)
 {
-       return ftrace_regex_open(&global_ops, FTRACE_ITER_NOTRACE,
+       struct ftrace_ops *ops = inode->i_private;
+
+       return ftrace_regex_open(ops, FTRACE_ITER_NOTRACE,
                                 inode, file);
 }
 
@@ -4109,6 +4094,36 @@ static const struct file_operations ftrace_graph_notrace_fops = {
 };
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 
+void ftrace_create_filter_files(struct ftrace_ops *ops,
+                               struct dentry *parent)
+{
+
+       trace_create_file("set_ftrace_filter", 0644, parent,
+                         ops, &ftrace_filter_fops);
+
+       trace_create_file("set_ftrace_notrace", 0644, parent,
+                         ops, &ftrace_notrace_fops);
+}
+
+/*
+ * The name "destroy_filter_files" is really a misnomer. Although
+ * in the future, it may actualy delete the files, but this is
+ * really intended to make sure the ops passed in are disabled
+ * and that when this function returns, the caller is free to
+ * free the ops.
+ *
+ * The "destroy" name is only to match the "create" name that this
+ * should be paired with.
+ */
+void ftrace_destroy_filter_files(struct ftrace_ops *ops)
+{
+       mutex_lock(&ftrace_lock);
+       if (ops->flags & FTRACE_OPS_FL_ENABLED)
+               ftrace_shutdown(ops, 0);
+       ops->flags |= FTRACE_OPS_FL_DELETED;
+       mutex_unlock(&ftrace_lock);
+}
+
 static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
 {
 
@@ -4118,11 +4133,7 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
        trace_create_file("enabled_functions", 0444,
                        d_tracer, NULL, &ftrace_enabled_fops);
 
-       trace_create_file("set_ftrace_filter", 0644, d_tracer,
-                       NULL, &ftrace_filter_fops);
-
-       trace_create_file("set_ftrace_notrace", 0644, d_tracer,
-                                   NULL, &ftrace_notrace_fops);
+       ftrace_create_filter_files(&global_ops, d_tracer);
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        trace_create_file("set_graph_function", 0444, d_tracer,
@@ -4238,9 +4249,6 @@ static int ftrace_process_locs(struct module *mod,
        /* Assign the last page to ftrace_pages */
        ftrace_pages = pg;
 
-       /* These new locations need to be initialized */
-       ftrace_new_pgs = start_pg;
-
        /*
         * We only need to disable interrupts on start up
         * because we are modifying code that an interrupt
@@ -4251,7 +4259,7 @@ static int ftrace_process_locs(struct module *mod,
         */
        if (!mod)
                local_irq_save(flags);
-       ftrace_update_code(mod);
+       ftrace_update_code(mod, start_pg);
        if (!mod)
                local_irq_restore(flags);
        ret = 0;
@@ -4360,11 +4368,10 @@ struct notifier_block ftrace_module_exit_nb = {
        .priority = INT_MIN,    /* Run after anything that can remove kprobes */
 };
 
-extern unsigned long __start_mcount_loc[];
-extern unsigned long __stop_mcount_loc[];
-
 void __init ftrace_init(void)
 {
+       extern unsigned long __start_mcount_loc[];
+       extern unsigned long __stop_mcount_loc[];
        unsigned long count, addr, flags;
        int ret;
 
@@ -4372,18 +4379,19 @@ void __init ftrace_init(void)
        addr = (unsigned long)ftrace_stub;
 
        local_irq_save(flags);
-       ftrace_dyn_arch_init(&addr);
+       ret = ftrace_dyn_arch_init(&addr);
        local_irq_restore(flags);
-
-       /* ftrace_dyn_arch_init places the return code in addr */
-       if (addr)
+       if (ret)
                goto failed;
 
        count = __stop_mcount_loc - __start_mcount_loc;
-
-       ret = ftrace_dyn_table_alloc(count);
-       if (ret)
+       if (!count) {
+               pr_info("ftrace: No functions to be traced?\n");
                goto failed;
+       }
+
+       pr_info("ftrace: allocating %ld entries in %ld pages\n",
+               count, count / ENTRIES_PER_PAGE + 1);
 
        last_ftrace_enabled = ftrace_enabled = 1;
 
@@ -4431,7 +4439,13 @@ static inline void ftrace_startup_enable(int command) { }
                        (ops)->flags |= FTRACE_OPS_FL_ENABLED;          \
                ___ret;                                                 \
        })
-# define ftrace_shutdown(ops, command) __unregister_ftrace_function(ops)
+# define ftrace_shutdown(ops, command)                                 \
+       ({                                                              \
+               int ___ret = __unregister_ftrace_function(ops);         \
+               if (!___ret)                                            \
+                       (ops)->flags &= ~FTRACE_OPS_FL_ENABLED;         \
+               ___ret;                                                 \
+       })
 
 # define ftrace_startup_sysctl()       do { } while (0)
 # define ftrace_shutdown_sysctl()      do { } while (0)