@@ -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,139 @@ 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_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 = - ENOMEM ;
212+
213+ if (hash )
214+ err = update_ftrace_direct_add (tr -> fops , hash );
215+ free_ftrace_hash (hash );
216+ return err ;
217+ }
218+
219+ static int direct_ops_del (struct bpf_trampoline * tr , void * addr )
220+ {
221+ struct ftrace_hash * hash = hash_from_ip (tr , addr );
222+ int err = - ENOMEM ;
223+
224+ if (hash )
225+ err = update_ftrace_direct_del (tr -> fops , hash );
226+ free_ftrace_hash (hash );
227+ return err ;
228+ }
229+
230+ static int direct_ops_mod (struct bpf_trampoline * tr , void * addr , bool lock_direct_mutex )
231+ {
232+ struct ftrace_hash * hash = hash_from_ip (tr , addr );
233+ int err = - ENOMEM ;
234+
235+ if (hash )
236+ err = update_ftrace_direct_mod (tr -> fops , hash , lock_direct_mutex );
237+ free_ftrace_hash (hash );
238+ return err ;
239+ }
240+ #else
241+ /*
242+ * We allocate ftrace_ops object for each trampoline and it contains
243+ * call site specific for that trampoline.
244+ *
245+ * We use *_ftrace_direct api for attachment.
246+ */
247+ static int direct_ops_alloc (struct bpf_trampoline * tr )
248+ {
249+ tr -> fops = kzalloc (sizeof (struct ftrace_ops ), GFP_KERNEL );
250+ if (!tr -> fops )
251+ return - ENOMEM ;
252+ tr -> fops -> private = tr ;
253+ tr -> fops -> ops_func = bpf_tramp_ftrace_ops_func ;
254+ return 0 ;
255+ }
256+
257+ static void direct_ops_free (struct bpf_trampoline * tr )
258+ {
259+ if (tr -> fops ) {
260+ ftrace_free_filter (tr -> fops );
261+ kfree (tr -> fops );
262+ }
263+ }
264+
265+ static int direct_ops_add (struct bpf_trampoline * tr , void * ptr )
266+ {
267+ unsigned long addr = (unsigned long ) ptr ;
268+ struct ftrace_ops * ops = tr -> fops ;
269+ int ret ;
270+
271+ if (bpf_trampoline_use_jmp (tr -> flags ))
272+ addr = ftrace_jmp_set (addr );
273+
274+ ret = ftrace_set_filter_ip (ops , tr -> ip , 0 , 1 );
275+ if (ret )
276+ return ret ;
277+ return register_ftrace_direct (ops , addr );
278+ }
279+
280+ static int direct_ops_del (struct bpf_trampoline * tr , void * addr )
281+ {
282+ return unregister_ftrace_direct (tr -> fops , (long )addr , false);
283+ }
284+
285+ static int direct_ops_mod (struct bpf_trampoline * tr , void * ptr , bool lock_direct_mutex )
286+ {
287+ unsigned long addr = (unsigned long ) ptr ;
288+ struct ftrace_ops * ops = tr -> fops ;
289+
290+ if (bpf_trampoline_use_jmp (tr -> flags ))
291+ addr = ftrace_jmp_set (addr );
292+ if (lock_direct_mutex )
293+ return modify_ftrace_direct (ops , addr );
294+ return modify_ftrace_direct_nolock (ops , addr );
295+ }
296+ #endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
297+ #else
298+ static void direct_ops_free (struct bpf_trampoline * tr ) { }
299+ #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
300+
140301static struct bpf_trampoline * bpf_trampoline_lookup (u64 key , unsigned long ip )
141302{
142303 struct bpf_trampoline * tr ;
@@ -155,14 +316,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
155316 if (!tr )
156317 goto out ;
157318#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
158- tr -> fops = kzalloc (sizeof (struct ftrace_ops ), GFP_KERNEL );
159- if (!tr -> fops ) {
319+ if (direct_ops_alloc (tr )) {
160320 kfree (tr );
161321 tr = NULL ;
162322 goto out ;
163323 }
164- tr -> fops -> private = tr ;
165- tr -> fops -> ops_func = bpf_tramp_ftrace_ops_func ;
166324#endif
167325
168326 tr -> key = key ;
@@ -206,7 +364,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
206364 int ret ;
207365
208366 if (tr -> func .ftrace_managed )
209- ret = unregister_ftrace_direct (tr -> fops , ( long ) old_addr , false );
367+ ret = direct_ops_del (tr , old_addr );
210368 else
211369 ret = bpf_trampoline_update_fentry (tr , orig_flags , old_addr , NULL );
212370
@@ -220,15 +378,7 @@ static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
220378 int ret ;
221379
222380 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 );
381+ ret = direct_ops_mod (tr , new_addr , lock_direct_mutex );
232382 } else {
233383 ret = bpf_trampoline_update_fentry (tr , orig_flags , old_addr ,
234384 new_addr );
@@ -251,15 +401,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
251401 }
252402
253403 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 );
404+ ret = direct_ops_add (tr , new_addr );
263405 } else {
264406 ret = bpf_trampoline_update_fentry (tr , 0 , NULL , new_addr );
265407 }
@@ -910,10 +1052,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
9101052 */
9111053 hlist_del (& tr -> hlist_key );
9121054 hlist_del (& tr -> hlist_ip );
913- if (tr -> fops ) {
914- ftrace_free_filter (tr -> fops );
915- kfree (tr -> fops );
916- }
1055+ direct_ops_free (tr );
9171056 kfree (tr );
9181057out :
9191058 mutex_unlock (& trampoline_mutex );
0 commit comments