@@ -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.
@@ -144,6 +172,162 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
144172 PAGE_SIZE , true, ksym -> name );
145173}
146174
175+ #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
176+ #ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
177+ /*
178+ * We have only single direct_ops which contains all the direct call
179+ * sites and is the only global ftrace_ops for all trampolines.
180+ *
181+ * We use 'update_ftrace_direct_*' api for attachment.
182+ */
183+ struct ftrace_ops direct_ops = {
184+ .ops_func = bpf_tramp_ftrace_ops_func ,
185+ };
186+
187+ static int direct_ops_alloc (struct bpf_trampoline * tr )
188+ {
189+ tr -> fops = & direct_ops ;
190+ return 0 ;
191+ }
192+
193+ static void direct_ops_free (struct bpf_trampoline * tr ) { }
194+
195+ static struct ftrace_hash * hash_from_ip (struct bpf_trampoline * tr , void * ptr )
196+ {
197+ unsigned long ip , addr = (unsigned long ) ptr ;
198+ struct ftrace_hash * hash ;
199+
200+ ip = ftrace_location (tr -> ip );
201+ if (!ip )
202+ return NULL ;
203+ hash = alloc_ftrace_hash (FTRACE_HASH_DEFAULT_BITS );
204+ if (!hash )
205+ return NULL ;
206+ if (bpf_trampoline_use_jmp (tr -> flags ))
207+ addr = ftrace_jmp_set (addr );
208+ if (!add_ftrace_hash_entry_direct (hash , ip , addr )) {
209+ free_ftrace_hash (hash );
210+ return NULL ;
211+ }
212+ return hash ;
213+ }
214+
215+ static int direct_ops_add (struct bpf_trampoline * tr , void * addr )
216+ {
217+ struct ftrace_hash * hash = hash_from_ip (tr , addr );
218+ int err ;
219+
220+ if (!hash )
221+ return - ENOMEM ;
222+ err = update_ftrace_direct_add (tr -> fops , hash );
223+ free_ftrace_hash (hash );
224+ return err ;
225+ }
226+
227+ static int direct_ops_del (struct bpf_trampoline * tr , void * addr )
228+ {
229+ struct ftrace_hash * hash = hash_from_ip (tr , addr );
230+ int err ;
231+
232+ if (!hash )
233+ return - ENOMEM ;
234+ err = update_ftrace_direct_del (tr -> fops , hash );
235+ free_ftrace_hash (hash );
236+ return err ;
237+ }
238+
239+ static int direct_ops_mod (struct bpf_trampoline * tr , void * addr , bool lock_direct_mutex )
240+ {
241+ struct ftrace_hash * hash = hash_from_ip (tr , addr );
242+ int err ;
243+
244+ if (!hash )
245+ return - ENOMEM ;
246+ err = update_ftrace_direct_mod (tr -> fops , hash , lock_direct_mutex );
247+ free_ftrace_hash (hash );
248+ return err ;
249+ }
250+ #else
251+ /*
252+ * We allocate ftrace_ops object for each trampoline and it contains
253+ * call site specific for that trampoline.
254+ *
255+ * We use *_ftrace_direct api for attachment.
256+ */
257+ static int direct_ops_alloc (struct bpf_trampoline * tr )
258+ {
259+ tr -> fops = kzalloc (sizeof (struct ftrace_ops ), GFP_KERNEL );
260+ if (!tr -> fops )
261+ return - ENOMEM ;
262+ tr -> fops -> private = tr ;
263+ tr -> fops -> ops_func = bpf_tramp_ftrace_ops_func ;
264+ return 0 ;
265+ }
266+
267+ static void direct_ops_free (struct bpf_trampoline * tr )
268+ {
269+ if (!tr -> fops )
270+ return ;
271+ ftrace_free_filter (tr -> fops );
272+ kfree (tr -> fops );
273+ }
274+
275+ static int direct_ops_add (struct bpf_trampoline * tr , void * ptr )
276+ {
277+ unsigned long addr = (unsigned long ) ptr ;
278+ struct ftrace_ops * ops = tr -> fops ;
279+ int ret ;
280+
281+ if (bpf_trampoline_use_jmp (tr -> flags ))
282+ addr = ftrace_jmp_set (addr );
283+
284+ ret = ftrace_set_filter_ip (ops , tr -> ip , 0 , 1 );
285+ if (ret )
286+ return ret ;
287+ return register_ftrace_direct (ops , addr );
288+ }
289+
290+ static int direct_ops_del (struct bpf_trampoline * tr , void * addr )
291+ {
292+ return unregister_ftrace_direct (tr -> fops , (long )addr , false);
293+ }
294+
295+ static int direct_ops_mod (struct bpf_trampoline * tr , void * ptr , bool lock_direct_mutex )
296+ {
297+ unsigned long addr = (unsigned long ) ptr ;
298+ struct ftrace_ops * ops = tr -> fops ;
299+
300+ if (bpf_trampoline_use_jmp (tr -> flags ))
301+ addr = ftrace_jmp_set (addr );
302+ if (lock_direct_mutex )
303+ return modify_ftrace_direct (ops , addr );
304+ return modify_ftrace_direct_nolock (ops , addr );
305+ }
306+ #endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
307+ #else
308+ static void direct_ops_free (struct bpf_trampoline * tr ) { }
309+
310+ static int direct_ops_alloc (struct bpf_trampoline * tr )
311+ {
312+ return 0 ;
313+ }
314+
315+ static int direct_ops_add (struct bpf_trampoline * tr , void * addr )
316+ {
317+ return - ENODEV ;
318+ }
319+
320+ static int direct_ops_del (struct bpf_trampoline * tr , void * addr )
321+ {
322+ return - ENODEV ;
323+ }
324+
325+ static int direct_ops_mod (struct bpf_trampoline * tr , void * ptr , bool lock_direct_mutex )
326+ {
327+ return - ENODEV ;
328+ }
329+ #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
330+
147331static struct bpf_trampoline * bpf_trampoline_lookup (u64 key , unsigned long ip )
148332{
149333 struct bpf_trampoline * tr ;
@@ -161,16 +345,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
161345 tr = kzalloc (sizeof (* tr ), GFP_KERNEL );
162346 if (!tr )
163347 goto out ;
164- #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
165- tr -> fops = kzalloc (sizeof (struct ftrace_ops ), GFP_KERNEL );
166- if (!tr -> fops ) {
348+ if (direct_ops_alloc (tr )) {
167349 kfree (tr );
168350 tr = NULL ;
169351 goto out ;
170352 }
171- tr -> fops -> private = tr ;
172- tr -> fops -> ops_func = bpf_tramp_ftrace_ops_func ;
173- #endif
174353
175354 tr -> key = key ;
176355 tr -> ip = ftrace_location (ip );
@@ -213,7 +392,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
213392 int ret ;
214393
215394 if (tr -> func .ftrace_managed )
216- ret = unregister_ftrace_direct (tr -> fops , ( long ) old_addr , false );
395+ ret = direct_ops_del (tr , old_addr );
217396 else
218397 ret = bpf_trampoline_update_fentry (tr , orig_flags , old_addr , NULL );
219398
@@ -227,15 +406,7 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
227406 int ret ;
228407
229408 if (tr -> func .ftrace_managed ) {
230- unsigned long addr = (unsigned long ) new_addr ;
231-
232- if (bpf_trampoline_use_jmp (tr -> flags ))
233- addr = ftrace_jmp_set (addr );
234-
235- if (lock_direct_mutex )
236- ret = modify_ftrace_direct (tr -> fops , addr );
237- else
238- ret = modify_ftrace_direct_nolock (tr -> fops , addr );
409+ ret = direct_ops_mod (tr , new_addr , lock_direct_mutex );
239410 } else {
240411 ret = bpf_trampoline_update_fentry (tr , orig_flags , old_addr ,
241412 new_addr );
@@ -258,15 +429,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
258429 }
259430
260431 if (tr -> func .ftrace_managed ) {
261- unsigned long addr = (unsigned long ) new_addr ;
262-
263- if (bpf_trampoline_use_jmp (tr -> flags ))
264- addr = ftrace_jmp_set (addr );
265-
266- ret = ftrace_set_filter_ip (tr -> fops , (unsigned long )ip , 0 , 1 );
267- if (ret )
268- return ret ;
269- ret = register_ftrace_direct (tr -> fops , addr );
432+ ret = direct_ops_add (tr , new_addr );
270433 } else {
271434 ret = bpf_trampoline_update_fentry (tr , 0 , NULL , new_addr );
272435 }
@@ -947,10 +1110,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
9471110 */
9481111 hlist_del (& tr -> hlist_key );
9491112 hlist_del (& tr -> hlist_ip );
950- if (tr -> fops ) {
951- ftrace_free_filter (tr -> fops );
952- kfree (tr -> fops );
953- }
1113+ direct_ops_free (tr );
9541114 kfree (tr );
9551115out :
9561116 mutex_unlock (& trampoline_mutex );
0 commit comments