@@ -175,24 +175,42 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
175175 return tr ;
176176}
177177
178- static int unregister_fentry (struct bpf_trampoline * tr , void * old_addr )
178+ static int bpf_trampoline_update_fentry (struct bpf_trampoline * tr , u32 orig_flags ,
179+ void * old_addr , void * new_addr )
179180{
181+ enum bpf_text_poke_type new_t = BPF_MOD_CALL , old_t = BPF_MOD_CALL ;
180182 void * ip = tr -> func .addr ;
183+
184+ if (!new_addr )
185+ new_t = BPF_MOD_NOP ;
186+ else if (bpf_trampoline_use_jmp (tr -> flags ))
187+ new_t = BPF_MOD_JUMP ;
188+
189+ if (!old_addr )
190+ old_t = BPF_MOD_NOP ;
191+ else if (bpf_trampoline_use_jmp (orig_flags ))
192+ old_t = BPF_MOD_JUMP ;
193+
194+ return bpf_arch_text_poke (ip , old_t , new_t , old_addr , new_addr );
195+ }
196+
197+ static int unregister_fentry (struct bpf_trampoline * tr , u32 orig_flags ,
198+ void * old_addr )
199+ {
181200 int ret ;
182201
183202 if (tr -> func .ftrace_managed )
184203 ret = unregister_ftrace_direct (tr -> fops , (long )old_addr , false);
185204 else
186- ret = bpf_arch_text_poke (ip , BPF_MOD_CALL , BPF_MOD_NOP ,
187- old_addr , NULL );
205+ ret = bpf_trampoline_update_fentry (tr , orig_flags , old_addr , NULL );
188206
189207 return ret ;
190208}
191209
192- static int modify_fentry (struct bpf_trampoline * tr , void * old_addr , void * new_addr ,
210+ static int modify_fentry (struct bpf_trampoline * tr , u32 orig_flags ,
211+ void * old_addr , void * new_addr ,
193212 bool lock_direct_mutex )
194213{
195- void * ip = tr -> func .addr ;
196214 int ret ;
197215
198216 if (tr -> func .ftrace_managed ) {
@@ -201,10 +219,8 @@ static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_ad
201219 else
202220 ret = modify_ftrace_direct_nolock (tr -> fops , (long )new_addr );
203221 } else {
204- ret = bpf_arch_text_poke (ip ,
205- old_addr ? BPF_MOD_CALL : BPF_MOD_NOP ,
206- new_addr ? BPF_MOD_CALL : BPF_MOD_NOP ,
207- old_addr , new_addr );
222+ ret = bpf_trampoline_update_fentry (tr , orig_flags , old_addr ,
223+ new_addr );
208224 }
209225 return ret ;
210226}
@@ -229,8 +245,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
229245 return ret ;
230246 ret = register_ftrace_direct (tr -> fops , (long )new_addr );
231247 } else {
232- ret = bpf_arch_text_poke (ip , BPF_MOD_NOP , BPF_MOD_CALL ,
233- NULL , new_addr );
248+ ret = bpf_trampoline_update_fentry (tr , 0 , NULL , new_addr );
234249 }
235250
236251 return ret ;
@@ -416,7 +431,7 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
416431 return PTR_ERR (tlinks );
417432
418433 if (total == 0 ) {
419- err = unregister_fentry (tr , tr -> cur_image -> image );
434+ err = unregister_fentry (tr , orig_flags , tr -> cur_image -> image );
420435 bpf_tramp_image_put (tr -> cur_image );
421436 tr -> cur_image = NULL ;
422437 goto out ;
@@ -440,9 +455,20 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
440455
441456#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
442457again :
443- if ((tr -> flags & BPF_TRAMP_F_SHARE_IPMODIFY ) &&
444- (tr -> flags & BPF_TRAMP_F_CALL_ORIG ))
445- tr -> flags |= BPF_TRAMP_F_ORIG_STACK ;
458+ if (tr -> flags & BPF_TRAMP_F_CALL_ORIG ) {
459+ if (tr -> flags & BPF_TRAMP_F_SHARE_IPMODIFY ) {
460+ /* The BPF_TRAMP_F_SKIP_FRAME can be cleared in the
461+ * first try, reset it in the second try.
462+ */
463+ tr -> flags |= BPF_TRAMP_F_ORIG_STACK | BPF_TRAMP_F_SKIP_FRAME ;
464+ } else if (IS_ENABLED (CONFIG_DYNAMIC_FTRACE_WITH_JMP )) {
465+ /* Use "jmp" instead of "call" for the trampoline
466+ * in the origin call case, and we don't need to
467+ * skip the frame.
468+ */
469+ tr -> flags &= ~BPF_TRAMP_F_SKIP_FRAME ;
470+ }
471+ }
446472#endif
447473
448474 size = arch_bpf_trampoline_size (& tr -> func .model , tr -> flags ,
@@ -473,10 +499,18 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
473499 if (err )
474500 goto out_free ;
475501
502+ #ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP
503+ if (bpf_trampoline_use_jmp (tr -> flags ))
504+ tr -> fops -> flags |= FTRACE_OPS_FL_JMP ;
505+ else
506+ tr -> fops -> flags &= ~FTRACE_OPS_FL_JMP ;
507+ #endif
508+
476509 WARN_ON (tr -> cur_image && total == 0 );
477510 if (tr -> cur_image )
478511 /* progs already running at this address */
479- err = modify_fentry (tr , tr -> cur_image -> image , im -> image , lock_direct_mutex );
512+ err = modify_fentry (tr , orig_flags , tr -> cur_image -> image ,
513+ im -> image , lock_direct_mutex );
480514 else
481515 /* first time registering */
482516 err = register_fentry (tr , im -> image );
@@ -499,8 +533,15 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
499533 tr -> cur_image = im ;
500534out :
501535 /* If any error happens, restore previous flags */
502- if (err )
536+ if (err ) {
503537 tr -> flags = orig_flags ;
538+ #ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP
539+ if (bpf_trampoline_use_jmp (tr -> flags ))
540+ tr -> fops -> flags |= FTRACE_OPS_FL_JMP ;
541+ else
542+ tr -> fops -> flags &= ~FTRACE_OPS_FL_JMP ;
543+ #endif
544+ }
504545 kfree (tlinks );
505546 return err ;
506547
0 commit comments