@@ -1373,6 +1373,21 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
13731373 return 0 ;
13741374}
13751375
1376+ static bool hash_contains_ip (unsigned long ip ,
1377+ struct ftrace_ops_hash * hash )
1378+ {
1379+ /*
1380+ * The function record is a match if it exists in the filter
1381+ * hash and not in the notrace hash. Note, an emty hash is
1382+ * considered a match for the filter hash, but an empty
1383+ * notrace hash is considered not in the notrace hash.
1384+ */
1385+ return (ftrace_hash_empty (hash -> filter_hash ) ||
1386+ ftrace_lookup_ip (hash -> filter_hash , ip )) &&
1387+ (ftrace_hash_empty (hash -> notrace_hash ) ||
1388+ !ftrace_lookup_ip (hash -> notrace_hash , ip ));
1389+ }
1390+
13761391/*
13771392 * Test the hashes for this ops to see if we want to call
13781393 * the ops->func or not.
@@ -1388,8 +1403,7 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
13881403static int
13891404ftrace_ops_test (struct ftrace_ops * ops , unsigned long ip , void * regs )
13901405{
1391- struct ftrace_hash * filter_hash ;
1392- struct ftrace_hash * notrace_hash ;
1406+ struct ftrace_ops_hash hash ;
13931407 int ret ;
13941408
13951409#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
@@ -1402,13 +1416,10 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
14021416 return 0 ;
14031417#endif
14041418
1405- filter_hash = rcu_dereference_raw_notrace (ops -> func_hash -> filter_hash );
1406- notrace_hash = rcu_dereference_raw_notrace (ops -> func_hash -> notrace_hash );
1419+ hash . filter_hash = rcu_dereference_raw_notrace (ops -> func_hash -> filter_hash );
1420+ hash . notrace_hash = rcu_dereference_raw_notrace (ops -> func_hash -> notrace_hash );
14071421
1408- if ((ftrace_hash_empty (filter_hash ) ||
1409- ftrace_lookup_ip (filter_hash , ip )) &&
1410- (ftrace_hash_empty (notrace_hash ) ||
1411- !ftrace_lookup_ip (notrace_hash , ip )))
1422+ if (hash_contains_ip (ip , & hash ))
14121423 ret = 1 ;
14131424 else
14141425 ret = 0 ;
@@ -1520,46 +1531,6 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)
15201531 return keep_regs ;
15211532}
15221533
1523- static void ftrace_remove_tramp (struct ftrace_ops * ops ,
1524- struct dyn_ftrace * rec )
1525- {
1526- /* If TRAMP is not set, no ops should have a trampoline for this */
1527- if (!(rec -> flags & FTRACE_FL_TRAMP ))
1528- return ;
1529-
1530- rec -> flags &= ~FTRACE_FL_TRAMP ;
1531-
1532- if ((!ftrace_hash_empty (ops -> func_hash -> filter_hash ) &&
1533- !ftrace_lookup_ip (ops -> func_hash -> filter_hash , rec -> ip )) ||
1534- ftrace_lookup_ip (ops -> func_hash -> notrace_hash , rec -> ip ))
1535- return ;
1536- /*
1537- * The tramp_hash entry will be removed at time
1538- * of update.
1539- */
1540- ops -> nr_trampolines -- ;
1541- }
1542-
1543- static void ftrace_clear_tramps (struct dyn_ftrace * rec , struct ftrace_ops * ops )
1544- {
1545- struct ftrace_ops * op ;
1546-
1547- /* If TRAMP is not set, no ops should have a trampoline for this */
1548- if (!(rec -> flags & FTRACE_FL_TRAMP ))
1549- return ;
1550-
1551- do_for_each_ftrace_op (op , ftrace_ops_list ) {
1552- /*
1553- * This function is called to clear other tramps
1554- * not the one that is being updated.
1555- */
1556- if (op == ops )
1557- continue ;
1558- if (op -> nr_trampolines )
1559- ftrace_remove_tramp (op , rec );
1560- } while_for_each_ftrace_op (op );
1561- }
1562-
15631534static void __ftrace_hash_rec_update (struct ftrace_ops * ops ,
15641535 int filter_hash ,
15651536 bool inc )
@@ -1648,18 +1619,16 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
16481619 * function, and the ops has a trampoline registered
16491620 * for it, then we can call it directly.
16501621 */
1651- if (ftrace_rec_count (rec ) == 1 && ops -> trampoline ) {
1622+ if (ftrace_rec_count (rec ) == 1 && ops -> trampoline )
16521623 rec -> flags |= FTRACE_FL_TRAMP ;
1653- ops -> nr_trampolines ++ ;
1654- } else {
1624+ else
16551625 /*
16561626 * If we are adding another function callback
16571627 * to this function, and the previous had a
16581628 * custom trampoline in use, then we need to go
16591629 * back to the default trampoline.
16601630 */
1661- ftrace_clear_tramps (rec , ops );
1662- }
1631+ rec -> flags &= ~FTRACE_FL_TRAMP ;
16631632
16641633 /*
16651634 * If any ops wants regs saved for this function
@@ -1672,9 +1641,6 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
16721641 return ;
16731642 rec -> flags -- ;
16741643
1675- if (ops -> trampoline && !ftrace_rec_count (rec ))
1676- ftrace_remove_tramp (ops , rec );
1677-
16781644 /*
16791645 * If the rec had REGS enabled and the ops that is
16801646 * being removed had REGS set, then see if there is
@@ -1688,6 +1654,17 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
16881654 rec -> flags &= ~FTRACE_FL_REGS ;
16891655 }
16901656
1657+ /*
1658+ * If the rec had TRAMP enabled, then it needs to
1659+ * be cleared. As TRAMP can only be enabled iff
1660+ * there is only a single ops attached to it.
1661+ * In otherwords, always disable it on decrementing.
1662+ * In the future, we may set it if rec count is
1663+ * decremented to one, and the ops that is left
1664+ * has a trampoline.
1665+ */
1666+ rec -> flags &= ~FTRACE_FL_TRAMP ;
1667+
16911668 /*
16921669 * flags will be cleared in ftrace_check_record()
16931670 * if rec count is zero.
@@ -1910,15 +1887,14 @@ static struct ftrace_ops *
19101887ftrace_find_tramp_ops_any (struct dyn_ftrace * rec )
19111888{
19121889 struct ftrace_ops * op ;
1890+ unsigned long ip = rec -> ip ;
19131891
19141892 do_for_each_ftrace_op (op , ftrace_ops_list ) {
19151893
19161894 if (!op -> trampoline )
19171895 continue ;
19181896
1919- if (ftrace_lookup_ip (op -> func_hash -> filter_hash , rec -> ip ) &&
1920- (ftrace_hash_empty (op -> func_hash -> notrace_hash ) ||
1921- !ftrace_lookup_ip (op -> func_hash -> notrace_hash , rec -> ip )))
1897+ if (hash_contains_ip (ip , op -> func_hash ))
19221898 return op ;
19231899 } while_for_each_ftrace_op (op );
19241900
@@ -1929,18 +1905,51 @@ static struct ftrace_ops *
19291905ftrace_find_tramp_ops_curr (struct dyn_ftrace * rec )
19301906{
19311907 struct ftrace_ops * op ;
1908+ unsigned long ip = rec -> ip ;
19321909
1933- /* Removed ops need to be tested first */
1934- if (removed_ops && removed_ops -> tramp_hash ) {
1935- if (ftrace_lookup_ip (removed_ops -> tramp_hash , rec -> ip ))
1910+ /*
1911+ * Need to check removed ops first.
1912+ * If they are being removed, and this rec has a tramp,
1913+ * and this rec is in the ops list, then it would be the
1914+ * one with the tramp.
1915+ */
1916+ if (removed_ops ) {
1917+ if (hash_contains_ip (ip , & removed_ops -> old_hash ))
19361918 return removed_ops ;
19371919 }
19381920
1921+ /*
1922+ * Need to find the current trampoline for a rec.
1923+ * Now, a trampoline is only attached to a rec if there
1924+ * was a single 'ops' attached to it. But this can be called
1925+ * when we are adding another op to the rec or removing the
1926+ * current one. Thus, if the op is being added, we can
1927+ * ignore it because it hasn't attached itself to the rec
1928+ * yet. That means we just need to find the op that has a
1929+ * trampoline and is not beeing added.
1930+ */
19391931 do_for_each_ftrace_op (op , ftrace_ops_list ) {
1940- if (!op -> tramp_hash )
1932+
1933+ if (!op -> trampoline )
1934+ continue ;
1935+
1936+ /*
1937+ * If the ops is being added, it hasn't gotten to
1938+ * the point to be removed from this tree yet.
1939+ */
1940+ if (op -> flags & FTRACE_OPS_FL_ADDING )
19411941 continue ;
19421942
1943- if (ftrace_lookup_ip (op -> tramp_hash , rec -> ip ))
1943+ /*
1944+ * If the ops is not being added and has a trampoline,
1945+ * then it must be the one that we want!
1946+ */
1947+ if (hash_contains_ip (ip , op -> func_hash ))
1948+ return op ;
1949+
1950+ /* If the ops is being modified, it may be in the old hash. */
1951+ if ((op -> flags & FTRACE_OPS_FL_MODIFYING ) &&
1952+ hash_contains_ip (ip , & op -> old_hash ))
19441953 return op ;
19451954
19461955 } while_for_each_ftrace_op (op );
@@ -1952,10 +1961,11 @@ static struct ftrace_ops *
19521961ftrace_find_tramp_ops_new (struct dyn_ftrace * rec )
19531962{
19541963 struct ftrace_ops * op ;
1964+ unsigned long ip = rec -> ip ;
19551965
19561966 do_for_each_ftrace_op (op , ftrace_ops_list ) {
19571967 /* pass rec in as regs to have non-NULL val */
1958- if (ftrace_ops_test ( op , rec -> ip , rec ))
1968+ if (hash_contains_ip ( ip , op -> func_hash ))
19591969 return op ;
19601970 } while_for_each_ftrace_op (op );
19611971
@@ -2262,92 +2272,6 @@ void __weak arch_ftrace_update_code(int command)
22622272 ftrace_run_stop_machine (command );
22632273}
22642274
2265- static int ftrace_save_ops_tramp_hash (struct ftrace_ops * ops )
2266- {
2267- struct ftrace_page * pg ;
2268- struct dyn_ftrace * rec ;
2269- int size , bits ;
2270- int ret ;
2271-
2272- size = ops -> nr_trampolines ;
2273- bits = 0 ;
2274- /*
2275- * Make the hash size about 1/2 the # found
2276- */
2277- for (size /= 2 ; size ; size >>= 1 )
2278- bits ++ ;
2279-
2280- ops -> tramp_hash = alloc_ftrace_hash (bits );
2281- /*
2282- * TODO: a failed allocation is going to screw up
2283- * the accounting of what needs to be modified
2284- * and not. For now, we kill ftrace if we fail
2285- * to allocate here. But there are ways around this,
2286- * but that will take a little more work.
2287- */
2288- if (!ops -> tramp_hash )
2289- return - ENOMEM ;
2290-
2291- do_for_each_ftrace_rec (pg , rec ) {
2292- if (ftrace_rec_count (rec ) == 1 &&
2293- ftrace_ops_test (ops , rec -> ip , rec )) {
2294-
2295- /*
2296- * If another ops adds to a rec, the rec will
2297- * lose its trampoline and never get it back
2298- * until all ops are off of it.
2299- */
2300- if (!(rec -> flags & FTRACE_FL_TRAMP ))
2301- continue ;
2302-
2303- /* This record had better have a trampoline */
2304- if (FTRACE_WARN_ON (!(rec -> flags & FTRACE_FL_TRAMP_EN )))
2305- return -1 ;
2306-
2307- ret = add_hash_entry (ops -> tramp_hash , rec -> ip );
2308- if (ret < 0 )
2309- return ret ;
2310- }
2311- } while_for_each_ftrace_rec ();
2312-
2313- /* The number of recs in the hash must match nr_trampolines */
2314- if (FTRACE_WARN_ON (ops -> tramp_hash -> count != ops -> nr_trampolines ))
2315- pr_warn ("count=%ld trampolines=%d\n" ,
2316- ops -> tramp_hash -> count ,
2317- ops -> nr_trampolines );
2318-
2319- return 0 ;
2320- }
2321-
2322- static int ftrace_save_tramp_hashes (void )
2323- {
2324- struct ftrace_ops * op ;
2325- int ret ;
2326-
2327- /*
2328- * Now that any trampoline is being used, we need to save the
2329- * hashes for the ops that have them. This allows the mapping
2330- * back from the record to the ops that has the trampoline to
2331- * know what code is being replaced. Modifying code must always
2332- * verify what it is changing.
2333- */
2334- do_for_each_ftrace_op (op , ftrace_ops_list ) {
2335-
2336- /* The tramp_hash is recreated each time. */
2337- free_ftrace_hash (op -> tramp_hash );
2338- op -> tramp_hash = NULL ;
2339-
2340- if (op -> nr_trampolines ) {
2341- ret = ftrace_save_ops_tramp_hash (op );
2342- if (ret )
2343- return ret ;
2344- }
2345-
2346- } while_for_each_ftrace_op (op );
2347-
2348- return 0 ;
2349- }
2350-
23512275static void ftrace_run_update_code (int command )
23522276{
23532277 int ret ;
@@ -2367,9 +2291,6 @@ static void ftrace_run_update_code(int command)
23672291
23682292 ret = ftrace_arch_code_modify_post_process ();
23692293 FTRACE_WARN_ON (ret );
2370-
2371- ret = ftrace_save_tramp_hashes ();
2372- FTRACE_WARN_ON (ret );
23732294}
23742295
23752296static void ftrace_run_modify_code (struct ftrace_ops * ops , int command )
@@ -2489,8 +2410,16 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
24892410 ops -> flags |= FTRACE_OPS_FL_REMOVING ;
24902411 removed_ops = ops ;
24912412
2413+ /* The trampoline logic checks the old hashes */
2414+ ops -> old_hash .filter_hash = ops -> func_hash -> filter_hash ;
2415+ ops -> old_hash .notrace_hash = ops -> func_hash -> notrace_hash ;
2416+
24922417 ftrace_run_update_code (command );
24932418
2419+ ops -> old_hash .filter_hash = NULL ;
2420+ ops -> old_hash .notrace_hash = NULL ;
2421+
2422+ removed_ops = NULL ;
24942423 ops -> flags &= ~FTRACE_OPS_FL_REMOVING ;
24952424
24962425 /*
@@ -3017,7 +2946,7 @@ static int t_show(struct seq_file *m, void *v)
30172946 struct ftrace_ops * ops ;
30182947
30192948 ops = ftrace_find_tramp_ops_any (rec );
3020- if (ops && ops -> trampoline )
2949+ if (ops )
30212950 seq_printf (m , "\ttramp: %pS" ,
30222951 (void * )ops -> trampoline );
30232952 else
0 commit comments