@@ -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,126 @@ 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+
186+ static void direct_ops_free (struct bpf_trampoline * tr ) { }
187+
188+ static struct ftrace_hash * hash_from (unsigned long ip , void * addr )
189+ {
190+ struct ftrace_hash * hash ;
191+
192+ ip = ftrace_location (ip );
193+ if (!ip )
194+ return NULL ;
195+ hash = alloc_ftrace_hash (FTRACE_HASH_DEFAULT_BITS );
196+ if (!hash )
197+ return NULL ;
198+ if (!add_hash_entry_direct (hash , ip , (unsigned long ) addr )) {
199+ free_ftrace_hash (hash );
200+ return NULL ;
201+ }
202+ return hash ;
203+ }
204+
205+ static int direct_ops_add (struct ftrace_ops * ops , unsigned long ip , void * addr )
206+ {
207+ struct ftrace_hash * hash = hash_from (ip , addr );
208+ int err = - ENOMEM ;
209+
210+ if (hash )
211+ err = update_ftrace_direct_add (ops , hash );
212+ free_ftrace_hash (hash );
213+ return err ;
214+ }
215+
216+ static int direct_ops_del (struct ftrace_ops * ops , unsigned long ip , void * addr )
217+ {
218+ struct ftrace_hash * hash = hash_from (ip , addr );
219+ int err = - ENOMEM ;
220+
221+ if (hash )
222+ err = update_ftrace_direct_del (ops , hash );
223+ free_ftrace_hash (hash );
224+ return err ;
225+ }
226+
227+ static int direct_ops_mod (struct ftrace_ops * ops , unsigned long ip , void * addr , bool lock_direct_mutex )
228+ {
229+ struct ftrace_hash * hash = hash_from (ip , addr );
230+ int err = - ENOMEM ;
231+
232+ if (hash )
233+ err = update_ftrace_direct_mod (ops , hash , lock_direct_mutex );
234+ free_ftrace_hash (hash );
235+ return err ;
236+ }
237+ #else
238+ /*
239+ * We allocate ftrace_ops object for each trampoline and it contains
240+ * call site specific for that trampoline.
241+ *
242+ * We use *_ftrace_direct api for attachment.
243+ */
244+ static int direct_ops_alloc (struct bpf_trampoline * tr )
245+ {
246+ tr -> fops = kzalloc (sizeof (struct ftrace_ops ), GFP_KERNEL );
247+ if (!tr -> fops )
248+ return - ENOMEM ;
249+ tr -> fops -> private = tr ;
250+ tr -> fops -> ops_func = bpf_tramp_ftrace_ops_func ;
251+ return 0 ;
252+ }
253+
254+ static void direct_ops_free (struct bpf_trampoline * tr )
255+ {
256+ if (tr -> fops ) {
257+ ftrace_free_filter (tr -> fops );
258+ kfree (tr -> fops );
259+ }
260+ }
261+
262+ static int direct_ops_add (struct ftrace_ops * ops , unsigned long ip , void * addr )
263+ {
264+ int ret ;
265+
266+ ret = ftrace_set_filter_ip (ops , (unsigned long )ip , 0 , 1 );
267+ if (ret )
268+ return ret ;
269+ return register_ftrace_direct (ops , (long )addr );
270+ }
271+
272+ static int direct_ops_del (struct ftrace_ops * ops , unsigned long ip , void * addr )
273+ {
274+ return unregister_ftrace_direct (ops , (long )addr , false);
275+ }
276+
277+ static int direct_ops_mod (struct ftrace_ops * ops , unsigned long ip , void * addr , bool lock_direct_mutex )
278+ {
279+ if (lock_direct_mutex )
280+ return modify_ftrace_direct (ops , (long )addr );
281+ return modify_ftrace_direct_nolock (ops , (long )addr );
282+ }
283+ #endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
284+ #else
285+ static void direct_ops_free (struct bpf_trampoline * tr ) { }
286+ #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
287+
140288static struct bpf_trampoline * bpf_trampoline_lookup (u64 key , unsigned long ip )
141289{
142290 struct bpf_trampoline * tr ;
@@ -155,14 +303,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
155303 if (!tr )
156304 goto out ;
157305#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
158- tr -> fops = kzalloc (sizeof (struct ftrace_ops ), GFP_KERNEL );
159- if (!tr -> fops ) {
306+ if (direct_ops_alloc (tr )) {
160307 kfree (tr );
161308 tr = NULL ;
162309 goto out ;
163310 }
164- tr -> fops -> private = tr ;
165- tr -> fops -> ops_func = bpf_tramp_ftrace_ops_func ;
166311#endif
167312
168313 tr -> key = key ;
@@ -187,7 +332,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
187332 int ret ;
188333
189334 if (tr -> func .ftrace_managed )
190- ret = unregister_ftrace_direct (tr -> fops , ( long ) old_addr , false );
335+ ret = direct_ops_del (tr -> fops , tr -> ip , old_addr );
191336 else
192337 ret = bpf_arch_text_poke (ip , BPF_MOD_CALL , old_addr , NULL );
193338
@@ -201,10 +346,7 @@ static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_ad
201346 int ret ;
202347
203348 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 );
349+ ret = direct_ops_mod (tr -> fops , tr -> ip , new_addr , lock_direct_mutex );
208350 } else {
209351 ret = bpf_arch_text_poke (ip , BPF_MOD_CALL , old_addr , new_addr );
210352 }
@@ -226,10 +368,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
226368 }
227369
228370 if (tr -> func .ftrace_managed ) {
229- ret = ftrace_set_filter_ip (tr -> fops , (unsigned long )ip , 0 , 1 );
230- if (ret )
231- return ret ;
232- ret = register_ftrace_direct (tr -> fops , (long )new_addr );
371+ ret = direct_ops_add (tr -> fops , tr -> ip , new_addr );
233372 } else {
234373 ret = bpf_arch_text_poke (ip , BPF_MOD_CALL , NULL , new_addr );
235374 }
@@ -865,10 +1004,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
8651004 */
8661005 hlist_del (& tr -> hlist_key );
8671006 hlist_del (& tr -> hlist_ip );
868- if (tr -> fops ) {
869- ftrace_free_filter (tr -> fops );
870- kfree (tr -> fops );
871- }
1007+ direct_ops_free (tr );
8721008 kfree (tr );
8731009out :
8741010 mutex_unlock (& trampoline_mutex );
0 commit comments