diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/ftrace.c | 48 |
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 | |||
| 2992 | int | 2991 | int |
| 2993 | register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | 2992 | register_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, ¬); | 3006 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
| 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 | ||
| 3119 | void | 3163 | void |
