@@ -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,162 @@ 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_ip (struct bpf_trampoline * tr , void * ptr )
189+ {
190+ unsigned long ip , addr = (unsigned long ) ptr ;
191+ struct ftrace_hash * hash ;
192+
193+ ip = ftrace_location (tr -> ip );
194+ if (!ip )
195+ return NULL ;
196+ hash = alloc_ftrace_hash (FTRACE_HASH_DEFAULT_BITS );
197+ if (!hash )
198+ return NULL ;
199+ if (bpf_trampoline_use_jmp (tr -> flags ))
200+ addr = ftrace_jmp_set (addr );
201+ if (!add_ftrace_hash_entry_direct (hash , ip , addr )) {
202+ free_ftrace_hash (hash );
203+ return NULL ;
204+ }
205+ return hash ;
206+ }
207+
208+ static int direct_ops_add (struct bpf_trampoline * tr , void * addr )
209+ {
210+ struct ftrace_hash * hash = hash_from_ip (tr , addr );
211+ int err ;
212+
213+ if (!hash )
214+ return - ENOMEM ;
215+ err = update_ftrace_direct_add (tr -> fops , hash );
216+ free_ftrace_hash (hash );
217+ return err ;
218+ }
219+
220+ static int direct_ops_del (struct bpf_trampoline * tr , void * addr )
221+ {
222+ struct ftrace_hash * hash = hash_from_ip (tr , addr );
223+ int err ;
224+
225+ if (!hash )
226+ return - ENOMEM ;
227+ err = update_ftrace_direct_del (tr -> fops , hash );
228+ free_ftrace_hash (hash );
229+ return err ;
230+ }
231+
232+ static int direct_ops_mod (struct bpf_trampoline * tr , void * addr , bool lock_direct_mutex )
233+ {
234+ struct ftrace_hash * hash = hash_from_ip (tr , addr );
235+ int err ;
236+
237+ if (!hash )
238+ return - ENOMEM ;
239+ err = update_ftrace_direct_mod (tr -> fops , hash , lock_direct_mutex );
240+ free_ftrace_hash (hash );
241+ return err ;
242+ }
243+ #else
244+ /*
245+ * We allocate ftrace_ops object for each trampoline and it contains
246+ * call site specific for that trampoline.
247+ *
248+ * We use *_ftrace_direct api for attachment.
249+ */
250+ static int direct_ops_alloc (struct bpf_trampoline * tr )
251+ {
252+ tr -> fops = kzalloc (sizeof (struct ftrace_ops ), GFP_KERNEL );
253+ if (!tr -> fops )
254+ return - ENOMEM ;
255+ tr -> fops -> private = tr ;
256+ tr -> fops -> ops_func = bpf_tramp_ftrace_ops_func ;
257+ return 0 ;
258+ }
259+
260+ static void direct_ops_free (struct bpf_trampoline * tr )
261+ {
262+ if (!tr -> fops )
263+ return ;
264+ ftrace_free_filter (tr -> fops );
265+ kfree (tr -> fops );
266+ }
267+
268+ static int direct_ops_add (struct bpf_trampoline * tr , void * ptr )
269+ {
270+ unsigned long addr = (unsigned long ) ptr ;
271+ struct ftrace_ops * ops = tr -> fops ;
272+ int ret ;
273+
274+ if (bpf_trampoline_use_jmp (tr -> flags ))
275+ addr = ftrace_jmp_set (addr );
276+
277+ ret = ftrace_set_filter_ip (ops , tr -> ip , 0 , 1 );
278+ if (ret )
279+ return ret ;
280+ return register_ftrace_direct (ops , addr );
281+ }
282+
283+ static int direct_ops_del (struct bpf_trampoline * tr , void * addr )
284+ {
285+ return unregister_ftrace_direct (tr -> fops , (long )addr , false);
286+ }
287+
288+ static int direct_ops_mod (struct bpf_trampoline * tr , void * ptr , bool lock_direct_mutex )
289+ {
290+ unsigned long addr = (unsigned long ) ptr ;
291+ struct ftrace_ops * ops = tr -> fops ;
292+
293+ if (bpf_trampoline_use_jmp (tr -> flags ))
294+ addr = ftrace_jmp_set (addr );
295+ if (lock_direct_mutex )
296+ return modify_ftrace_direct (ops , addr );
297+ return modify_ftrace_direct_nolock (ops , addr );
298+ }
299+ #endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
300+ #else
301+ static void direct_ops_free (struct bpf_trampoline * tr ) { }
302+
303+ static int direct_ops_alloc (struct bpf_trampoline * tr )
304+ {
305+ return 0 ;
306+ }
307+
308+ static int direct_ops_add (struct bpf_trampoline * tr , void * addr )
309+ {
310+ return - ENODEV ;
311+ }
312+
313+ static int direct_ops_del (struct bpf_trampoline * tr , void * addr )
314+ {
315+ return - ENODEV ;
316+ }
317+
318+ static int direct_ops_mod (struct bpf_trampoline * tr , void * ptr , bool lock_direct_mutex )
319+ {
320+ return - ENODEV ;
321+ }
322+ #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
323+
140324static struct bpf_trampoline * bpf_trampoline_lookup (u64 key , unsigned long ip )
141325{
142326 struct bpf_trampoline * tr ;
@@ -154,16 +338,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
154338 tr = kzalloc (sizeof (* tr ), GFP_KERNEL );
155339 if (!tr )
156340 goto out ;
157- #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
158- tr -> fops = kzalloc (sizeof (struct ftrace_ops ), GFP_KERNEL );
159- if (!tr -> fops ) {
341+ if (direct_ops_alloc (tr )) {
160342 kfree (tr );
161343 tr = NULL ;
162344 goto out ;
163345 }
164- tr -> fops -> private = tr ;
165- tr -> fops -> ops_func = bpf_tramp_ftrace_ops_func ;
166- #endif
167346
168347 tr -> key = key ;
169348 tr -> ip = ftrace_location (ip );
@@ -206,7 +385,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
206385 int ret ;
207386
208387 if (tr -> func .ftrace_managed )
209- ret = unregister_ftrace_direct (tr -> fops , ( long ) old_addr , false );
388+ ret = direct_ops_del (tr , old_addr );
210389 else
211390 ret = bpf_trampoline_update_fentry (tr , orig_flags , old_addr , NULL );
212391
@@ -220,15 +399,7 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
220399 int ret ;
221400
222401 if (tr -> func .ftrace_managed ) {
223- unsigned long addr = (unsigned long ) new_addr ;
224-
225- if (bpf_trampoline_use_jmp (tr -> flags ))
226- addr = ftrace_jmp_set (addr );
227-
228- if (lock_direct_mutex )
229- ret = modify_ftrace_direct (tr -> fops , addr );
230- else
231- ret = modify_ftrace_direct_nolock (tr -> fops , addr );
402+ ret = direct_ops_mod (tr , new_addr , lock_direct_mutex );
232403 } else {
233404 ret = bpf_trampoline_update_fentry (tr , orig_flags , old_addr ,
234405 new_addr );
@@ -251,15 +422,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
251422 }
252423
253424 if (tr -> func .ftrace_managed ) {
254- unsigned long addr = (unsigned long ) new_addr ;
255-
256- if (bpf_trampoline_use_jmp (tr -> flags ))
257- addr = ftrace_jmp_set (addr );
258-
259- ret = ftrace_set_filter_ip (tr -> fops , (unsigned long )ip , 0 , 1 );
260- if (ret )
261- return ret ;
262- ret = register_ftrace_direct (tr -> fops , addr );
425+ ret = direct_ops_add (tr , new_addr );
263426 } else {
264427 ret = bpf_trampoline_update_fentry (tr , 0 , NULL , new_addr );
265428 }
@@ -910,10 +1073,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
9101073 */
9111074 hlist_del (& tr -> hlist_key );
9121075 hlist_del (& tr -> hlist_ip );
913- if (tr -> fops ) {
914- ftrace_free_filter (tr -> fops );
915- kfree (tr -> fops );
916- }
1076+ direct_ops_free (tr );
9171077 kfree (tr );
9181078out :
9191079 mutex_unlock (& trampoline_mutex );
0 commit comments