@@ -1373,6 +1373,21 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
1373
1373
return 0 ;
1374
1374
}
1375
1375
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
+
1376
1391
/*
1377
1392
* Test the hashes for this ops to see if we want to call
1378
1393
* the ops->func or not.
@@ -1388,8 +1403,7 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
1388
1403
static int
1389
1404
ftrace_ops_test (struct ftrace_ops * ops , unsigned long ip , void * regs )
1390
1405
{
1391
- struct ftrace_hash * filter_hash ;
1392
- struct ftrace_hash * notrace_hash ;
1406
+ struct ftrace_ops_hash hash ;
1393
1407
int ret ;
1394
1408
1395
1409
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
@@ -1402,13 +1416,10 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
1402
1416
return 0 ;
1403
1417
#endif
1404
1418
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 );
1407
1421
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 ))
1412
1423
ret = 1 ;
1413
1424
else
1414
1425
ret = 0 ;
@@ -1520,46 +1531,6 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)
1520
1531
return keep_regs ;
1521
1532
}
1522
1533
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
-
1563
1534
static void __ftrace_hash_rec_update (struct ftrace_ops * ops ,
1564
1535
int filter_hash ,
1565
1536
bool inc )
@@ -1648,18 +1619,16 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
1648
1619
* function, and the ops has a trampoline registered
1649
1620
* for it, then we can call it directly.
1650
1621
*/
1651
- if (ftrace_rec_count (rec ) == 1 && ops -> trampoline ) {
1622
+ if (ftrace_rec_count (rec ) == 1 && ops -> trampoline )
1652
1623
rec -> flags |= FTRACE_FL_TRAMP ;
1653
- ops -> nr_trampolines ++ ;
1654
- } else {
1624
+ else
1655
1625
/*
1656
1626
* If we are adding another function callback
1657
1627
* to this function, and the previous had a
1658
1628
* custom trampoline in use, then we need to go
1659
1629
* back to the default trampoline.
1660
1630
*/
1661
- ftrace_clear_tramps (rec , ops );
1662
- }
1631
+ rec -> flags &= ~FTRACE_FL_TRAMP ;
1663
1632
1664
1633
/*
1665
1634
* If any ops wants regs saved for this function
@@ -1672,9 +1641,6 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
1672
1641
return ;
1673
1642
rec -> flags -- ;
1674
1643
1675
- if (ops -> trampoline && !ftrace_rec_count (rec ))
1676
- ftrace_remove_tramp (ops , rec );
1677
-
1678
1644
/*
1679
1645
* If the rec had REGS enabled and the ops that is
1680
1646
* being removed had REGS set, then see if there is
@@ -1688,6 +1654,17 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
1688
1654
rec -> flags &= ~FTRACE_FL_REGS ;
1689
1655
}
1690
1656
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
+
1691
1668
/*
1692
1669
* flags will be cleared in ftrace_check_record()
1693
1670
* if rec count is zero.
@@ -1910,15 +1887,14 @@ static struct ftrace_ops *
1910
1887
ftrace_find_tramp_ops_any (struct dyn_ftrace * rec )
1911
1888
{
1912
1889
struct ftrace_ops * op ;
1890
+ unsigned long ip = rec -> ip ;
1913
1891
1914
1892
do_for_each_ftrace_op (op , ftrace_ops_list ) {
1915
1893
1916
1894
if (!op -> trampoline )
1917
1895
continue ;
1918
1896
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 ))
1922
1898
return op ;
1923
1899
} while_for_each_ftrace_op (op );
1924
1900
@@ -1929,18 +1905,51 @@ static struct ftrace_ops *
1929
1905
ftrace_find_tramp_ops_curr (struct dyn_ftrace * rec )
1930
1906
{
1931
1907
struct ftrace_ops * op ;
1908
+ unsigned long ip = rec -> ip ;
1932
1909
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 ))
1936
1918
return removed_ops ;
1937
1919
}
1938
1920
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
+ */
1939
1931
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 )
1941
1941
continue ;
1942
1942
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 ))
1944
1953
return op ;
1945
1954
1946
1955
} while_for_each_ftrace_op (op );
@@ -1952,10 +1961,11 @@ static struct ftrace_ops *
1952
1961
ftrace_find_tramp_ops_new (struct dyn_ftrace * rec )
1953
1962
{
1954
1963
struct ftrace_ops * op ;
1964
+ unsigned long ip = rec -> ip ;
1955
1965
1956
1966
do_for_each_ftrace_op (op , ftrace_ops_list ) {
1957
1967
/* 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 ))
1959
1969
return op ;
1960
1970
} while_for_each_ftrace_op (op );
1961
1971
@@ -2262,92 +2272,6 @@ void __weak arch_ftrace_update_code(int command)
2262
2272
ftrace_run_stop_machine (command );
2263
2273
}
2264
2274
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
-
2351
2275
static void ftrace_run_update_code (int command )
2352
2276
{
2353
2277
int ret ;
@@ -2367,9 +2291,6 @@ static void ftrace_run_update_code(int command)
2367
2291
2368
2292
ret = ftrace_arch_code_modify_post_process ();
2369
2293
FTRACE_WARN_ON (ret );
2370
-
2371
- ret = ftrace_save_tramp_hashes ();
2372
- FTRACE_WARN_ON (ret );
2373
2294
}
2374
2295
2375
2296
static 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)
2489
2410
ops -> flags |= FTRACE_OPS_FL_REMOVING ;
2490
2411
removed_ops = ops ;
2491
2412
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
+
2492
2417
ftrace_run_update_code (command );
2493
2418
2419
+ ops -> old_hash .filter_hash = NULL ;
2420
+ ops -> old_hash .notrace_hash = NULL ;
2421
+
2422
+ removed_ops = NULL ;
2494
2423
ops -> flags &= ~FTRACE_OPS_FL_REMOVING ;
2495
2424
2496
2425
/*
@@ -3017,7 +2946,7 @@ static int t_show(struct seq_file *m, void *v)
3017
2946
struct ftrace_ops * ops ;
3018
2947
3019
2948
ops = ftrace_find_tramp_ops_any (rec );
3020
- if (ops && ops -> trampoline )
2949
+ if (ops )
3021
2950
seq_printf (m , "\ttramp: %pS" ,
3022
2951
(void * )ops -> trampoline );
3023
2952
else
0 commit comments