aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index e6effd0c40a9..dab031fec85b 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2988,18 +2988,20 @@ static void ftrace_free_entry_rcu(struct rcu_head *rhp)
2988 kfree(entry); 2988 kfree(entry);
2989} 2989}
2990 2990
2991
2992int 2991int
2993register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, 2992register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
2994 void *data) 2993 void *data)
2995{ 2994{
2996 struct ftrace_func_probe *entry; 2995 struct ftrace_func_probe *entry;
2996 struct ftrace_hash **orig_hash = &trace_probe_ops.filter_hash;
2997 struct ftrace_hash *hash;
2997 struct ftrace_page *pg; 2998 struct ftrace_page *pg;
2998 struct dyn_ftrace *rec; 2999 struct dyn_ftrace *rec;
2999 int type, len, not; 3000 int type, len, not;
3000 unsigned long key; 3001 unsigned long key;
3001 int count = 0; 3002 int count = 0;
3002 char *search; 3003 char *search;
3004 int ret;
3003 3005
3004 type = filter_parse_regex(glob, strlen(glob), &search, &not); 3006 type = filter_parse_regex(glob, strlen(glob), &search, &not);
3005 len = strlen(search); 3007 len = strlen(search);
@@ -3010,8 +3012,16 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
3010 3012
3011 mutex_lock(&ftrace_lock); 3013 mutex_lock(&ftrace_lock);
3012 3014
3013 if (unlikely(ftrace_disabled)) 3015 hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
3016 if (!hash) {
3017 count = -ENOMEM;
3018 goto out_unlock;
3019 }
3020
3021 if (unlikely(ftrace_disabled)) {
3022 count = -ENODEV;
3014 goto out_unlock; 3023 goto out_unlock;
3024 }
3015 3025
3016 do_for_each_ftrace_rec(pg, rec) { 3026 do_for_each_ftrace_rec(pg, rec) {
3017 3027
@@ -3043,6 +3053,13 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
3043 } 3053 }
3044 } 3054 }
3045 3055
3056 ret = enter_record(hash, rec, 0);
3057 if (ret < 0) {
3058 kfree(entry);
3059 count = ret;
3060 goto out_unlock;
3061 }
3062
3046 entry->ops = ops; 3063 entry->ops = ops;
3047 entry->ip = rec->ip; 3064 entry->ip = rec->ip;
3048 3065
@@ -3050,10 +3067,16 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
3050 hlist_add_head_rcu(&entry->node, &ftrace_func_hash[key]); 3067 hlist_add_head_rcu(&entry->node, &ftrace_func_hash[key]);
3051 3068
3052 } while_for_each_ftrace_rec(); 3069 } while_for_each_ftrace_rec();
3070
3071 ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
3072 if (ret < 0)
3073 count = ret;
3074
3053 __enable_ftrace_function_probe(); 3075 __enable_ftrace_function_probe();
3054 3076
3055 out_unlock: 3077 out_unlock:
3056 mutex_unlock(&ftrace_lock); 3078 mutex_unlock(&ftrace_lock);
3079 free_ftrace_hash(hash);
3057 3080
3058 return count; 3081 return count;
3059} 3082}
@@ -3067,7 +3090,10 @@ static void
3067__unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, 3090__unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
3068 void *data, int flags) 3091 void *data, int flags)
3069{ 3092{
3093 struct ftrace_func_entry *rec_entry;
3070 struct ftrace_func_probe *entry; 3094 struct ftrace_func_probe *entry;
3095 struct ftrace_hash **orig_hash = &trace_probe_ops.filter_hash;
3096 struct ftrace_hash *hash;
3071 struct hlist_node *n, *tmp; 3097 struct hlist_node *n, *tmp;
3072 char str[KSYM_SYMBOL_LEN]; 3098 char str[KSYM_SYMBOL_LEN];
3073 int type = MATCH_FULL; 3099 int type = MATCH_FULL;
@@ -3088,6 +3114,12 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
3088 } 3114 }
3089 3115
3090 mutex_lock(&ftrace_lock); 3116 mutex_lock(&ftrace_lock);
3117
3118 hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
3119 if (!hash)
3120 /* Hmm, should report this somehow */
3121 goto out_unlock;
3122
3091 for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) { 3123 for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
3092 struct hlist_head *hhd = &ftrace_func_hash[i]; 3124 struct hlist_head *hhd = &ftrace_func_hash[i];
3093 3125
@@ -3108,12 +3140,24 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
3108 continue; 3140 continue;
3109 } 3141 }
3110 3142
3143 rec_entry = ftrace_lookup_ip(hash, entry->ip);
3144 /* It is possible more than one entry had this ip */
3145 if (rec_entry)
3146 free_hash_entry(hash, rec_entry);
3147
3111 hlist_del_rcu(&entry->node); 3148 hlist_del_rcu(&entry->node);
3112 call_rcu_sched(&entry->rcu, ftrace_free_entry_rcu); 3149 call_rcu_sched(&entry->rcu, ftrace_free_entry_rcu);
3113 } 3150 }
3114 } 3151 }
3115 __disable_ftrace_function_probe(); 3152 __disable_ftrace_function_probe();
3153 /*
3154 * Remove after the disable is called. Otherwise, if the last
3155 * probe is removed, a null hash means *all enabled*.
3156 */
3157 ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
3158 out_unlock:
3116 mutex_unlock(&ftrace_lock); 3159 mutex_unlock(&ftrace_lock);
3160 free_ftrace_hash(hash);
3117} 3161}
3118 3162
3119void 3163void