@@ -33,12 +33,40 @@ static DEFINE_MUTEX(trampoline_mutex);
3333#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
3434static int bpf_trampoline_update (struct bpf_trampoline * tr , bool lock_direct_mutex );
3535
36+ #ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
37+ static struct bpf_trampoline * direct_ops_ip_lookup (struct ftrace_ops * ops , unsigned long ip )
38+ {
39+ struct hlist_head * head_ip ;
40+ struct bpf_trampoline * tr ;
41+
42+ mutex_lock (& trampoline_mutex );
43+ head_ip = & trampoline_ip_table [hash_64 (ip , TRAMPOLINE_HASH_BITS )];
44+ hlist_for_each_entry (tr , head_ip , hlist_ip ) {
45+ if (tr -> ip == ip )
46+ goto out ;
47+ }
48+ tr = NULL ;
49+ out :
50+ mutex_unlock (& trampoline_mutex );
51+ return tr ;
52+ }
53+ #else
54+ static struct bpf_trampoline * direct_ops_ip_lookup (struct ftrace_ops * ops , unsigned long ip )
55+ {
56+ return ops -> private ;
57+ }
58+ #endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
59+
3660static int bpf_tramp_ftrace_ops_func (struct ftrace_ops * ops , unsigned long ip ,
3761 enum ftrace_ops_cmd cmd )
3862{
39- struct bpf_trampoline * tr = ops -> private ;
63+ struct bpf_trampoline * tr ;
4064 int ret = 0 ;
4165
66+ tr = direct_ops_ip_lookup (ops , ip );
67+ if (!tr )
68+ return - EINVAL ;
69+
4270 if (cmd == FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF ) {
4371 /* This is called inside register_ftrace_direct_multi(), so
4472 * tr->mutex is already locked.
@@ -137,6 +165,121 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
137165 PAGE_SIZE , true, ksym -> name );
138166}
139167
168+ #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
169+ #ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
170+ /*
171+ * We have only single direct_ops which contains all the direct call
172+ * sites and is the only global ftrace_ops for all trampolines.
173+ *
174+ * We use 'update_ftrace_direct_*' api for attachment.
175+ */
176+ struct ftrace_ops direct_ops = {
177+ .ops_func = bpf_tramp_ftrace_ops_func ,
178+ };
179+
180+ static int direct_ops_alloc (struct bpf_trampoline * tr )
181+ {
182+ tr -> fops = & direct_ops ;
183+ return 0 ;
184+ }
185+ static void direct_ops_free (struct bpf_trampoline * tr ) { }
186+
187+ static struct ftrace_hash * hash_from (unsigned long ip , void * addr )
188+ {
189+ struct ftrace_hash * hash ;
190+
191+ ip = ftrace_location (ip );
192+ if (!ip )
193+ return NULL ;
194+ hash = alloc_ftrace_hash (FTRACE_HASH_DEFAULT_BITS );
195+ if (!hash )
196+ return NULL ;
197+ if (!add_hash_entry_direct (hash , ip , (unsigned long ) addr )) {
198+ free_ftrace_hash (hash );
199+ return NULL ;
200+ }
201+ return hash ;
202+ }
203+
204+ static int direct_ops_add (struct ftrace_ops * ops , unsigned long ip , void * addr )
205+ {
206+ struct ftrace_hash * hash = hash_from (ip , addr );
207+ int err = - ENOMEM ;
208+
209+ if (hash )
210+ err = update_ftrace_direct_add (ops , hash );
211+ free_ftrace_hash (hash );
212+ return err ;
213+ }
214+
215+ static int direct_ops_del (struct ftrace_ops * ops , unsigned long ip , void * addr )
216+ {
217+ struct ftrace_hash * hash = hash_from (ip , addr );
218+ int err = - ENOMEM ;
219+
220+ if (hash )
221+ err = update_ftrace_direct_del (ops , hash );
222+ free_ftrace_hash (hash );
223+ return err ;
224+ }
225+
226+ static int direct_ops_mod (struct ftrace_ops * ops , unsigned long ip , void * addr , bool lock_direct_mutex )
227+ {
228+ struct ftrace_hash * hash = hash_from (ip , addr );
229+ int err = - ENOMEM ;
230+
231+ if (hash )
232+ err = update_ftrace_direct_mod (ops , hash , lock_direct_mutex );
233+ free_ftrace_hash (hash );
234+ return err ;
235+ }
236+ #else
237+ /*
238+ * We allocate ftrace_ops object for each trampoline and it contains
239+ * call site specific for that trampoline.
240+ *
241+ * We use *_ftrace_direct api for attachment.
242+ */
243+ static int direct_ops_alloc (struct bpf_trampoline * tr )
244+ {
245+ tr -> fops = kzalloc (sizeof (struct ftrace_ops ), GFP_KERNEL );
246+ if (!tr -> fops )
247+ return -1 ;
248+ tr -> fops -> private = tr ;
249+ tr -> fops -> ops_func = bpf_tramp_ftrace_ops_func ;
250+ return 0 ;
251+ }
252+
253+ static void direct_ops_free (struct bpf_trampoline * tr )
254+ {
255+ if (tr -> fops ) {
256+ ftrace_free_filter (tr -> fops );
257+ kfree (tr -> fops );
258+ }
259+ }
260+
261+ static int direct_ops_add (struct ftrace_ops * ops , unsigned long ip , void * addr )
262+ {
263+ ftrace_set_filter_ip (ops , (unsigned long )ip , 0 , 1 );
264+ return register_ftrace_direct (ops , (long )addr );
265+ }
266+
267+ static int direct_ops_del (struct ftrace_ops * ops , unsigned long ip , void * addr )
268+ {
269+ return unregister_ftrace_direct (ops , (long )addr , false);
270+ }
271+
272+ static int direct_ops_mod (struct ftrace_ops * ops , unsigned long ip , void * addr , bool lock_direct_mutex )
273+ {
274+ if (lock_direct_mutex )
275+ return modify_ftrace_direct (ops , (long )addr );
276+ return modify_ftrace_direct_nolock (ops , (long )addr );
277+ }
278+ #endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
279+ #else
280+ static void direct_ops_free (struct bpf_trampoline * tr ) { }
281+ #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
282+
140283static struct bpf_trampoline * bpf_trampoline_lookup (u64 key , unsigned long ip )
141284{
142285 struct bpf_trampoline * tr ;
@@ -155,14 +298,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
155298 if (!tr )
156299 goto out ;
157300#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
158- tr -> fops = kzalloc (sizeof (struct ftrace_ops ), GFP_KERNEL );
159- if (!tr -> fops ) {
301+ if (direct_ops_alloc (tr )) {
160302 kfree (tr );
161303 tr = NULL ;
162304 goto out ;
163305 }
164- tr -> fops -> private = tr ;
165- tr -> fops -> ops_func = bpf_tramp_ftrace_ops_func ;
166306#endif
167307
168308 tr -> key = key ;
@@ -187,7 +327,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
187327 int ret ;
188328
189329 if (tr -> func .ftrace_managed )
190- ret = unregister_ftrace_direct (tr -> fops , ( long ) old_addr , false );
330+ ret = direct_ops_del (tr -> fops , tr -> ip , old_addr );
191331 else
192332 ret = bpf_arch_text_poke (ip , BPF_MOD_CALL , old_addr , NULL );
193333
@@ -201,10 +341,7 @@ static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_ad
201341 int ret ;
202342
203343 if (tr -> func .ftrace_managed ) {
204- if (lock_direct_mutex )
205- ret = modify_ftrace_direct (tr -> fops , (long )new_addr );
206- else
207- ret = modify_ftrace_direct_nolock (tr -> fops , (long )new_addr );
344+ ret = direct_ops_mod (tr -> fops , tr -> ip , new_addr , lock_direct_mutex );
208345 } else {
209346 ret = bpf_arch_text_poke (ip , BPF_MOD_CALL , old_addr , new_addr );
210347 }
@@ -226,8 +363,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
226363 }
227364
228365 if (tr -> func .ftrace_managed ) {
229- ftrace_set_filter_ip (tr -> fops , (unsigned long )ip , 0 , 1 );
230- ret = register_ftrace_direct (tr -> fops , (long )new_addr );
366+ ret = direct_ops_add (tr -> fops , tr -> ip , new_addr );
231367 } else {
232368 ret = bpf_arch_text_poke (ip , BPF_MOD_CALL , NULL , new_addr );
233369 }
@@ -863,10 +999,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
863999 */
8641000 hlist_del (& tr -> hlist_key );
8651001 hlist_del (& tr -> hlist_ip );
866- if (tr -> fops ) {
867- ftrace_free_filter (tr -> fops );
868- kfree (tr -> fops );
869- }
1002+ direct_ops_free (tr );
8701003 kfree (tr );
8711004out :
8721005 mutex_unlock (& trampoline_mutex );
0 commit comments