@@ -5935,28 +5935,24 @@ static int check_direct_multi(struct ftrace_ops *ops)
59355935 return 0 ;
59365936}
59375937
5938- static void remove_direct_functions_hash (struct ftrace_hash * hash , unsigned long addr )
5938+ static void register_ftrace_direct_cb (struct rcu_head * rhp )
59395939{
5940- struct ftrace_func_entry * entry , * del ;
5941- int size , i ;
5940+ struct ftrace_hash * fhp = container_of (rhp , struct ftrace_hash , rcu );
59425941
5943- size = 1 << hash -> size_bits ;
5944- for (i = 0 ; i < size ; i ++ ) {
5945- hlist_for_each_entry (entry , & hash -> buckets [i ], hlist ) {
5946- del = __ftrace_lookup_ip (direct_functions , entry -> ip );
5947- if (del && del -> direct == addr ) {
5948- remove_hash_entry (direct_functions , del );
5949- kfree (del );
5950- }
5951- }
5952- }
5942+ free_ftrace_hash (fhp );
59535943}
59545944
5955- static void register_ftrace_direct_cb ( struct rcu_head * rhp )
5945+ static struct ftrace_hash * hash_from_ip ( unsigned long ip , unsigned long addr )
59565946{
5957- struct ftrace_hash * fhp = container_of ( rhp , struct ftrace_hash , rcu ) ;
5947+ struct ftrace_hash * hash ;
59585948
5959- free_ftrace_hash (fhp );
5949+ ip = ftrace_location (ip );
5950+ if (!ip )
5951+ return NULL ;
5952+ hash = alloc_ftrace_hash (FTRACE_HASH_DEFAULT_BITS );
5953+ if (!hash || !add_hash_entry_direct (hash , ip , addr ))
5954+ return NULL ;
5955+ return hash ;
59605956}
59615957
59625958/**
@@ -5981,89 +5977,17 @@ static void register_ftrace_direct_cb(struct rcu_head *rhp)
59815977 * -ENODEV - @ip does not point to a ftrace nop location (or not supported)
59825978 * -ENOMEM - There was an allocation failure.
59835979 */
5984- int register_ftrace_direct (struct ftrace_ops * ops , unsigned long addr )
5980+ int register_ftrace_direct (struct ftrace_ops * ops , unsigned long ip , unsigned long addr )
59855981{
5986- struct ftrace_hash * hash , * new_hash = NULL , * free_hash = NULL ;
5987- struct ftrace_func_entry * entry , * new ;
5988- int err = - EBUSY , size , i ;
5989-
5990- if (ops -> func || ops -> trampoline )
5991- return - EINVAL ;
5992- if (!(ops -> flags & FTRACE_OPS_FL_INITIALIZED ))
5993- return - EINVAL ;
5994- if (ops -> flags & FTRACE_OPS_FL_ENABLED )
5995- return - EINVAL ;
5996-
5997- hash = ops -> func_hash -> filter_hash ;
5998- if (ftrace_hash_empty (hash ))
5999- return - EINVAL ;
6000-
6001- mutex_lock (& direct_mutex );
6002-
6003- /* Make sure requested entries are not already registered.. */
6004- size = 1 << hash -> size_bits ;
6005- for (i = 0 ; i < size ; i ++ ) {
6006- hlist_for_each_entry (entry , & hash -> buckets [i ], hlist ) {
6007- if (ftrace_find_rec_direct (entry -> ip ))
6008- goto out_unlock ;
6009- }
6010- }
6011-
6012- err = - ENOMEM ;
6013-
6014- /* Make a copy hash to place the new and the old entries in */
6015- size = hash -> count + direct_functions -> count ;
6016- size = fls (size );
6017- if (size > FTRACE_HASH_MAX_BITS )
6018- size = FTRACE_HASH_MAX_BITS ;
6019- new_hash = alloc_ftrace_hash (size );
6020- if (!new_hash )
6021- goto out_unlock ;
6022-
6023- /* Now copy over the existing direct entries */
6024- size = 1 << direct_functions -> size_bits ;
6025- for (i = 0 ; i < size ; i ++ ) {
6026- hlist_for_each_entry (entry , & direct_functions -> buckets [i ], hlist ) {
6027- new = add_hash_entry (new_hash , entry -> ip );
6028- if (!new )
6029- goto out_unlock ;
6030- new -> direct = entry -> direct ;
6031- }
6032- }
6033-
6034- /* ... and add the new entries */
6035- size = 1 << hash -> size_bits ;
6036- for (i = 0 ; i < size ; i ++ ) {
6037- hlist_for_each_entry (entry , & hash -> buckets [i ], hlist ) {
6038- new = add_hash_entry (new_hash , entry -> ip );
6039- if (!new )
6040- goto out_unlock ;
6041- /* Update both the copy and the hash entry */
6042- new -> direct = addr ;
6043- entry -> direct = addr ;
6044- }
6045- }
6046-
6047- free_hash = direct_functions ;
6048- rcu_assign_pointer (direct_functions , new_hash );
6049- new_hash = NULL ;
6050-
6051- ops -> func = call_direct_funcs ;
6052- ops -> flags = MULTI_FLAGS ;
6053- ops -> trampoline = FTRACE_REGS_ADDR ;
6054- ops -> direct_call = addr ;
6055-
6056- err = register_ftrace_function_nolock (ops );
6057-
6058- out_unlock :
6059- mutex_unlock (& direct_mutex );
6060-
6061- if (free_hash && free_hash != EMPTY_HASH )
6062- call_rcu_tasks (& free_hash -> rcu , register_ftrace_direct_cb );
5982+ struct ftrace_hash * hash ;
5983+ int err ;
60635984
6064- if (new_hash )
6065- free_ftrace_hash (new_hash );
5985+ hash = hash_from_ip (ip , addr );
5986+ if (!hash )
5987+ return - ENOMEM ;
60665988
5989+ err = register_ftrace_direct_hash (ops , hash );
5990+ free_ftrace_hash (hash );
60675991 return err ;
60685992}
60695993EXPORT_SYMBOL_GPL (register_ftrace_direct );
@@ -6083,111 +6007,24 @@ EXPORT_SYMBOL_GPL(register_ftrace_direct);
60836007 * 0 on success
60846008 * -EINVAL - The @ops object was not properly registered.
60856009 */
6086- int unregister_ftrace_direct (struct ftrace_ops * ops , unsigned long addr ,
6010+ int unregister_ftrace_direct (struct ftrace_ops * ops , unsigned long ip , unsigned long addr ,
60876011 bool free_filters )
60886012{
6089- struct ftrace_hash * hash = ops -> func_hash -> filter_hash ;
6013+ struct ftrace_hash * hash ;
60906014 int err ;
60916015
6092- if (check_direct_multi (ops ))
6093- return - EINVAL ;
6094- if (!(ops -> flags & FTRACE_OPS_FL_ENABLED ))
6095- return - EINVAL ;
6096-
6097- mutex_lock (& direct_mutex );
6098- err = unregister_ftrace_function (ops );
6099- remove_direct_functions_hash (hash , addr );
6100- mutex_unlock (& direct_mutex );
6101-
6102- /* cleanup for possible another register call */
6103- ops -> func = NULL ;
6104- ops -> trampoline = 0 ;
6016+ hash = hash_from_ip (ip , addr );
6017+ if (!hash )
6018+ return - ENOMEM ;
61056019
6020+ err = unregister_ftrace_direct_hash (ops , hash );
6021+ free_ftrace_hash (hash );
61066022 if (free_filters )
61076023 ftrace_free_filter (ops );
61086024 return err ;
61096025}
61106026EXPORT_SYMBOL_GPL (unregister_ftrace_direct );
61116027
6112- static int
6113- __modify_ftrace_direct (struct ftrace_ops * ops , unsigned long addr )
6114- {
6115- struct ftrace_hash * hash ;
6116- struct ftrace_func_entry * entry , * iter ;
6117- static struct ftrace_ops tmp_ops = {
6118- .func = ftrace_stub ,
6119- .flags = FTRACE_OPS_FL_STUB ,
6120- };
6121- int i , size ;
6122- int err ;
6123-
6124- lockdep_assert_held_once (& direct_mutex );
6125-
6126- /* Enable the tmp_ops to have the same functions as the direct ops */
6127- ftrace_ops_init (& tmp_ops );
6128- tmp_ops .func_hash = ops -> func_hash ;
6129- tmp_ops .direct_call = addr ;
6130-
6131- err = register_ftrace_function_nolock (& tmp_ops );
6132- if (err )
6133- return err ;
6134-
6135- /*
6136- * Now the ftrace_ops_list_func() is called to do the direct callers.
6137- * We can safely change the direct functions attached to each entry.
6138- */
6139- mutex_lock (& ftrace_lock );
6140-
6141- hash = ops -> func_hash -> filter_hash ;
6142- size = 1 << hash -> size_bits ;
6143- for (i = 0 ; i < size ; i ++ ) {
6144- hlist_for_each_entry (iter , & hash -> buckets [i ], hlist ) {
6145- entry = __ftrace_lookup_ip (direct_functions , iter -> ip );
6146- if (!entry )
6147- continue ;
6148- entry -> direct = addr ;
6149- }
6150- }
6151- /* Prevent store tearing if a trampoline concurrently accesses the value */
6152- WRITE_ONCE (ops -> direct_call , addr );
6153-
6154- mutex_unlock (& ftrace_lock );
6155-
6156- /* Removing the tmp_ops will add the updated direct callers to the functions */
6157- unregister_ftrace_function (& tmp_ops );
6158-
6159- return err ;
6160- }
6161-
6162- /**
6163- * modify_ftrace_direct_nolock - Modify an existing direct 'multi' call
6164- * to call something else
6165- * @ops: The address of the struct ftrace_ops object
6166- * @addr: The address of the new trampoline to call at @ops functions
6167- *
6168- * This is used to unregister currently registered direct caller and
6169- * register new one @addr on functions registered in @ops object.
6170- *
6171- * Note there's window between ftrace_shutdown and ftrace_startup calls
6172- * where there will be no callbacks called.
6173- *
6174- * Caller should already have direct_mutex locked, so we don't lock
6175- * direct_mutex here.
6176- *
6177- * Returns: zero on success. Non zero on error, which includes:
6178- * -EINVAL - The @ops object was not properly registered.
6179- */
6180- int modify_ftrace_direct_nolock (struct ftrace_ops * ops , unsigned long addr )
6181- {
6182- if (check_direct_multi (ops ))
6183- return - EINVAL ;
6184- if (!(ops -> flags & FTRACE_OPS_FL_ENABLED ))
6185- return - EINVAL ;
6186-
6187- return __modify_ftrace_direct (ops , addr );
6188- }
6189- EXPORT_SYMBOL_GPL (modify_ftrace_direct_nolock );
6190-
61916028/**
61926029 * modify_ftrace_direct - Modify an existing direct 'multi' call
61936030 * to call something else
@@ -6203,18 +6040,17 @@ EXPORT_SYMBOL_GPL(modify_ftrace_direct_nolock);
62036040 * Returns: zero on success. Non zero on error, which includes:
62046041 * -EINVAL - The @ops object was not properly registered.
62056042 */
6206- int modify_ftrace_direct (struct ftrace_ops * ops , unsigned long addr )
6043+ int modify_ftrace_direct (struct ftrace_ops * ops , unsigned long ip , unsigned long addr , bool lock_direct_mutex )
62076044{
6045+ struct ftrace_hash * hash ;
62086046 int err ;
62096047
6210- if (check_direct_multi (ops ))
6211- return - EINVAL ;
6212- if (!(ops -> flags & FTRACE_OPS_FL_ENABLED ))
6213- return - EINVAL ;
6048+ hash = hash_from_ip (ip , addr );
6049+ if (!hash )
6050+ return - ENOMEM ;
62146051
6215- mutex_lock (& direct_mutex );
6216- err = __modify_ftrace_direct (ops , addr );
6217- mutex_unlock (& direct_mutex );
6052+ err = modify_ftrace_direct_hash (ops , hash , lock_direct_mutex );
6053+ free_ftrace_hash (hash );
62186054 return err ;
62196055}
62206056EXPORT_SYMBOL_GPL (modify_ftrace_direct );
0 commit comments