13540f7c6SAlexei Starovoitov // SPDX-License-Identifier: GPL-2.0 23540f7c6SAlexei Starovoitov /* Copyright (c) 2021 Facebook */ 33540f7c6SAlexei Starovoitov #include <linux/bpf.h> 43540f7c6SAlexei Starovoitov #include <time.h> 53540f7c6SAlexei Starovoitov #include <errno.h> 63540f7c6SAlexei Starovoitov #include <bpf/bpf_helpers.h> 73540f7c6SAlexei Starovoitov #include "bpf_tcp_helpers.h" 83540f7c6SAlexei Starovoitov 93540f7c6SAlexei Starovoitov char _license[] SEC("license") = "GPL"; 103540f7c6SAlexei Starovoitov struct hmap_elem { 113540f7c6SAlexei Starovoitov int counter; 123540f7c6SAlexei Starovoitov struct bpf_timer timer; 133540f7c6SAlexei Starovoitov struct bpf_spin_lock lock; /* unused */ 143540f7c6SAlexei Starovoitov }; 153540f7c6SAlexei Starovoitov 163540f7c6SAlexei Starovoitov struct { 173540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_HASH); 183540f7c6SAlexei Starovoitov __uint(max_entries, 1000); 193540f7c6SAlexei Starovoitov __type(key, int); 203540f7c6SAlexei Starovoitov __type(value, struct hmap_elem); 213540f7c6SAlexei Starovoitov } hmap SEC(".maps"); 223540f7c6SAlexei Starovoitov 233540f7c6SAlexei Starovoitov struct { 243540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_HASH); 253540f7c6SAlexei Starovoitov __uint(map_flags, BPF_F_NO_PREALLOC); 263540f7c6SAlexei Starovoitov __uint(max_entries, 1000); 273540f7c6SAlexei Starovoitov __type(key, int); 283540f7c6SAlexei Starovoitov __type(value, struct hmap_elem); 293540f7c6SAlexei Starovoitov } hmap_malloc SEC(".maps"); 303540f7c6SAlexei Starovoitov 313540f7c6SAlexei Starovoitov struct elem { 323540f7c6SAlexei Starovoitov struct bpf_timer t; 333540f7c6SAlexei Starovoitov }; 343540f7c6SAlexei Starovoitov 353540f7c6SAlexei Starovoitov struct { 363540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_ARRAY); 373540f7c6SAlexei Starovoitov __uint(max_entries, 2); 383540f7c6SAlexei Starovoitov __type(key, int); 393540f7c6SAlexei Starovoitov __type(value, struct elem); 403540f7c6SAlexei Starovoitov } array SEC(".maps"); 413540f7c6SAlexei Starovoitov 423540f7c6SAlexei Starovoitov struct { 433540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_LRU_HASH); 443540f7c6SAlexei Starovoitov __uint(max_entries, 4); 453540f7c6SAlexei Starovoitov __type(key, int); 463540f7c6SAlexei Starovoitov __type(value, struct elem); 473540f7c6SAlexei Starovoitov } lru SEC(".maps"); 483540f7c6SAlexei Starovoitov 49944459e8STero Kristo struct { 50944459e8STero Kristo __uint(type, BPF_MAP_TYPE_ARRAY); 51944459e8STero Kristo __uint(max_entries, 1); 52944459e8STero Kristo __type(key, int); 53944459e8STero Kristo __type(value, struct elem); 54*3f00e4a9SMartin KaFai Lau } abs_timer SEC(".maps"), soft_timer_pinned SEC(".maps"), abs_timer_pinned SEC(".maps"), 55*3f00e4a9SMartin KaFai Lau race_array SEC(".maps"); 56944459e8STero Kristo 573540f7c6SAlexei Starovoitov __u64 bss_data; 58944459e8STero Kristo __u64 abs_data; 593540f7c6SAlexei Starovoitov __u64 err; 603540f7c6SAlexei Starovoitov __u64 ok; 613540f7c6SAlexei Starovoitov __u64 callback_check = 52; 623540f7c6SAlexei Starovoitov __u64 callback2_check = 52; 630d7ae068SDavid Vernet __u64 pinned_callback_check; 640d7ae068SDavid Vernet __s32 pinned_cpu; 653540f7c6SAlexei Starovoitov 663540f7c6SAlexei Starovoitov #define ARRAY 1 673540f7c6SAlexei Starovoitov #define HTAB 2 683540f7c6SAlexei Starovoitov #define HTAB_MALLOC 3 693540f7c6SAlexei Starovoitov #define LRU 4 703540f7c6SAlexei Starovoitov 713540f7c6SAlexei Starovoitov /* callback for array and lru timers */ 723540f7c6SAlexei Starovoitov static int timer_cb1(void *map, int *key, struct bpf_timer *timer) 733540f7c6SAlexei Starovoitov { 743540f7c6SAlexei Starovoitov /* increment bss variable twice. 753540f7c6SAlexei Starovoitov * Once via array timer callback and once via lru timer callback 763540f7c6SAlexei Starovoitov */ 773540f7c6SAlexei Starovoitov bss_data += 5; 783540f7c6SAlexei Starovoitov 793540f7c6SAlexei Starovoitov /* *key == 0 - the callback was called for array timer. 803540f7c6SAlexei Starovoitov * *key == 4 - the callback was called from lru timer. 813540f7c6SAlexei Starovoitov */ 823540f7c6SAlexei Starovoitov if (*key == ARRAY) { 833540f7c6SAlexei Starovoitov struct bpf_timer *lru_timer; 843540f7c6SAlexei Starovoitov int lru_key = LRU; 853540f7c6SAlexei Starovoitov 863540f7c6SAlexei Starovoitov /* rearm array timer to be called again in ~35 seconds */ 873540f7c6SAlexei Starovoitov if (bpf_timer_start(timer, 1ull << 35, 0) != 0) 883540f7c6SAlexei Starovoitov err |= 1; 893540f7c6SAlexei Starovoitov 903540f7c6SAlexei Starovoitov lru_timer = bpf_map_lookup_elem(&lru, &lru_key); 913540f7c6SAlexei Starovoitov if (!lru_timer) 923540f7c6SAlexei Starovoitov return 0; 933540f7c6SAlexei Starovoitov bpf_timer_set_callback(lru_timer, timer_cb1); 943540f7c6SAlexei Starovoitov if (bpf_timer_start(lru_timer, 0, 0) != 0) 953540f7c6SAlexei Starovoitov err |= 2; 963540f7c6SAlexei Starovoitov } else if (*key == LRU) { 973540f7c6SAlexei Starovoitov int lru_key, i; 983540f7c6SAlexei Starovoitov 993540f7c6SAlexei Starovoitov for (i = LRU + 1; 1003540f7c6SAlexei Starovoitov i <= 100 /* for current LRU eviction algorithm this number 1013540f7c6SAlexei Starovoitov * should be larger than ~ lru->max_entries * 2 1023540f7c6SAlexei Starovoitov */; 1033540f7c6SAlexei Starovoitov i++) { 1043540f7c6SAlexei Starovoitov struct elem init = {}; 1053540f7c6SAlexei Starovoitov 1063540f7c6SAlexei Starovoitov /* lru_key cannot be used as loop induction variable 1073540f7c6SAlexei Starovoitov * otherwise the loop will be unbounded. 1083540f7c6SAlexei Starovoitov */ 1093540f7c6SAlexei Starovoitov lru_key = i; 1103540f7c6SAlexei Starovoitov 1113540f7c6SAlexei Starovoitov /* add more elements into lru map to push out current 1123540f7c6SAlexei Starovoitov * element and force deletion of this timer 1133540f7c6SAlexei Starovoitov */ 1143540f7c6SAlexei Starovoitov bpf_map_update_elem(map, &lru_key, &init, 0); 1153540f7c6SAlexei Starovoitov /* look it up to bump it into active list */ 1163540f7c6SAlexei Starovoitov bpf_map_lookup_elem(map, &lru_key); 1173540f7c6SAlexei Starovoitov 1183540f7c6SAlexei Starovoitov /* keep adding until *key changes underneath, 1193540f7c6SAlexei Starovoitov * which means that key/timer memory was reused 1203540f7c6SAlexei Starovoitov */ 1213540f7c6SAlexei Starovoitov if (*key != LRU) 1223540f7c6SAlexei Starovoitov break; 1233540f7c6SAlexei Starovoitov } 1243540f7c6SAlexei Starovoitov 1253540f7c6SAlexei Starovoitov /* check that the timer was removed */ 1263540f7c6SAlexei Starovoitov if (bpf_timer_cancel(timer) != -EINVAL) 1273540f7c6SAlexei Starovoitov err |= 4; 1283540f7c6SAlexei Starovoitov ok |= 1; 1293540f7c6SAlexei Starovoitov } 1303540f7c6SAlexei Starovoitov return 0; 1313540f7c6SAlexei Starovoitov } 1323540f7c6SAlexei Starovoitov 1333540f7c6SAlexei Starovoitov SEC("fentry/bpf_fentry_test1") 134a7c2ca3aSYonghong Song int BPF_PROG2(test1, int, a) 1353540f7c6SAlexei Starovoitov { 1363540f7c6SAlexei Starovoitov struct bpf_timer *arr_timer, *lru_timer; 1373540f7c6SAlexei Starovoitov struct elem init = {}; 1383540f7c6SAlexei Starovoitov int lru_key = LRU; 1393540f7c6SAlexei Starovoitov int array_key = ARRAY; 1403540f7c6SAlexei Starovoitov 1413540f7c6SAlexei Starovoitov arr_timer = bpf_map_lookup_elem(&array, &array_key); 1423540f7c6SAlexei Starovoitov if (!arr_timer) 1433540f7c6SAlexei Starovoitov return 0; 1443540f7c6SAlexei Starovoitov bpf_timer_init(arr_timer, &array, CLOCK_MONOTONIC); 1453540f7c6SAlexei Starovoitov 1463540f7c6SAlexei Starovoitov bpf_map_update_elem(&lru, &lru_key, &init, 0); 1473540f7c6SAlexei Starovoitov lru_timer = bpf_map_lookup_elem(&lru, &lru_key); 1483540f7c6SAlexei Starovoitov if (!lru_timer) 1493540f7c6SAlexei Starovoitov return 0; 1503540f7c6SAlexei Starovoitov bpf_timer_init(lru_timer, &lru, CLOCK_MONOTONIC); 1513540f7c6SAlexei Starovoitov 1523540f7c6SAlexei Starovoitov bpf_timer_set_callback(arr_timer, timer_cb1); 1533540f7c6SAlexei Starovoitov bpf_timer_start(arr_timer, 0 /* call timer_cb1 asap */, 0); 1543540f7c6SAlexei Starovoitov 1553540f7c6SAlexei Starovoitov /* init more timers to check that array destruction 1563540f7c6SAlexei Starovoitov * doesn't leak timer memory. 1573540f7c6SAlexei Starovoitov */ 1583540f7c6SAlexei Starovoitov array_key = 0; 1593540f7c6SAlexei Starovoitov arr_timer = bpf_map_lookup_elem(&array, &array_key); 1603540f7c6SAlexei Starovoitov if (!arr_timer) 1613540f7c6SAlexei Starovoitov return 0; 1623540f7c6SAlexei Starovoitov bpf_timer_init(arr_timer, &array, CLOCK_MONOTONIC); 1633540f7c6SAlexei Starovoitov return 0; 1643540f7c6SAlexei Starovoitov } 1653540f7c6SAlexei Starovoitov 1663540f7c6SAlexei Starovoitov /* callback for prealloc and non-prealloca hashtab timers */ 1673540f7c6SAlexei Starovoitov static int timer_cb2(void *map, int *key, struct hmap_elem *val) 1683540f7c6SAlexei Starovoitov { 1693540f7c6SAlexei Starovoitov if (*key == HTAB) 1703540f7c6SAlexei Starovoitov callback_check--; 1713540f7c6SAlexei Starovoitov else 1723540f7c6SAlexei Starovoitov callback2_check--; 1733540f7c6SAlexei Starovoitov if (val->counter > 0 && --val->counter) { 1743540f7c6SAlexei Starovoitov /* re-arm the timer again to execute after 1 usec */ 1753540f7c6SAlexei Starovoitov bpf_timer_start(&val->timer, 1000, 0); 1763540f7c6SAlexei Starovoitov } else if (*key == HTAB) { 1773540f7c6SAlexei Starovoitov struct bpf_timer *arr_timer; 1783540f7c6SAlexei Starovoitov int array_key = ARRAY; 1793540f7c6SAlexei Starovoitov 1803540f7c6SAlexei Starovoitov /* cancel arr_timer otherwise bpf_fentry_test1 prog 1813540f7c6SAlexei Starovoitov * will stay alive forever. 1823540f7c6SAlexei Starovoitov */ 1833540f7c6SAlexei Starovoitov arr_timer = bpf_map_lookup_elem(&array, &array_key); 1843540f7c6SAlexei Starovoitov if (!arr_timer) 1853540f7c6SAlexei Starovoitov return 0; 1863540f7c6SAlexei Starovoitov if (bpf_timer_cancel(arr_timer) != 1) 1873540f7c6SAlexei Starovoitov /* bpf_timer_cancel should return 1 to indicate 1883540f7c6SAlexei Starovoitov * that arr_timer was active at this time 1893540f7c6SAlexei Starovoitov */ 1903540f7c6SAlexei Starovoitov err |= 8; 1913540f7c6SAlexei Starovoitov 1923540f7c6SAlexei Starovoitov /* try to cancel ourself. It shouldn't deadlock. */ 1933540f7c6SAlexei Starovoitov if (bpf_timer_cancel(&val->timer) != -EDEADLK) 1943540f7c6SAlexei Starovoitov err |= 16; 1953540f7c6SAlexei Starovoitov 1963540f7c6SAlexei Starovoitov /* delete this key and this timer anyway. 1973540f7c6SAlexei Starovoitov * It shouldn't deadlock either. 1983540f7c6SAlexei Starovoitov */ 1993540f7c6SAlexei Starovoitov bpf_map_delete_elem(map, key); 2003540f7c6SAlexei Starovoitov 2013540f7c6SAlexei Starovoitov /* in preallocated hashmap both 'key' and 'val' could have been 2023540f7c6SAlexei Starovoitov * reused to store another map element (like in LRU above), 2033540f7c6SAlexei Starovoitov * but in controlled test environment the below test works. 2043540f7c6SAlexei Starovoitov * It's not a use-after-free. The memory is owned by the map. 2053540f7c6SAlexei Starovoitov */ 2063540f7c6SAlexei Starovoitov if (bpf_timer_start(&val->timer, 1000, 0) != -EINVAL) 2073540f7c6SAlexei Starovoitov err |= 32; 2083540f7c6SAlexei Starovoitov ok |= 2; 2093540f7c6SAlexei Starovoitov } else { 2103540f7c6SAlexei Starovoitov if (*key != HTAB_MALLOC) 2113540f7c6SAlexei Starovoitov err |= 64; 2123540f7c6SAlexei Starovoitov 2133540f7c6SAlexei Starovoitov /* try to cancel ourself. It shouldn't deadlock. */ 2143540f7c6SAlexei Starovoitov if (bpf_timer_cancel(&val->timer) != -EDEADLK) 2153540f7c6SAlexei Starovoitov err |= 128; 2163540f7c6SAlexei Starovoitov 2173540f7c6SAlexei Starovoitov /* delete this key and this timer anyway. 2183540f7c6SAlexei Starovoitov * It shouldn't deadlock either. 2193540f7c6SAlexei Starovoitov */ 2203540f7c6SAlexei Starovoitov bpf_map_delete_elem(map, key); 2213540f7c6SAlexei Starovoitov 2223540f7c6SAlexei Starovoitov ok |= 4; 2233540f7c6SAlexei Starovoitov } 2243540f7c6SAlexei Starovoitov return 0; 2253540f7c6SAlexei Starovoitov } 2263540f7c6SAlexei Starovoitov 2273540f7c6SAlexei Starovoitov int bpf_timer_test(void) 2283540f7c6SAlexei Starovoitov { 2293540f7c6SAlexei Starovoitov struct hmap_elem *val; 2303540f7c6SAlexei Starovoitov int key = HTAB, key_malloc = HTAB_MALLOC; 2313540f7c6SAlexei Starovoitov 2323540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key); 2333540f7c6SAlexei Starovoitov if (val) { 2343540f7c6SAlexei Starovoitov if (bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME) != 0) 2353540f7c6SAlexei Starovoitov err |= 512; 2363540f7c6SAlexei Starovoitov bpf_timer_set_callback(&val->timer, timer_cb2); 2373540f7c6SAlexei Starovoitov bpf_timer_start(&val->timer, 1000, 0); 2383540f7c6SAlexei Starovoitov } 2393540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); 2403540f7c6SAlexei Starovoitov if (val) { 2413540f7c6SAlexei Starovoitov if (bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME) != 0) 2423540f7c6SAlexei Starovoitov err |= 1024; 2433540f7c6SAlexei Starovoitov bpf_timer_set_callback(&val->timer, timer_cb2); 2443540f7c6SAlexei Starovoitov bpf_timer_start(&val->timer, 1000, 0); 2453540f7c6SAlexei Starovoitov } 2463540f7c6SAlexei Starovoitov return 0; 2473540f7c6SAlexei Starovoitov } 2483540f7c6SAlexei Starovoitov 2493540f7c6SAlexei Starovoitov SEC("fentry/bpf_fentry_test2") 250a7c2ca3aSYonghong Song int BPF_PROG2(test2, int, a, int, b) 2513540f7c6SAlexei Starovoitov { 2523540f7c6SAlexei Starovoitov struct hmap_elem init = {}, *val; 2533540f7c6SAlexei Starovoitov int key = HTAB, key_malloc = HTAB_MALLOC; 2543540f7c6SAlexei Starovoitov 2553540f7c6SAlexei Starovoitov init.counter = 10; /* number of times to trigger timer_cb2 */ 2563540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0); 2573540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key); 2583540f7c6SAlexei Starovoitov if (val) 2593540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME); 2603540f7c6SAlexei Starovoitov /* update the same key to free the timer */ 2613540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0); 2623540f7c6SAlexei Starovoitov 2633540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0); 2643540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); 2653540f7c6SAlexei Starovoitov if (val) 2663540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME); 2673540f7c6SAlexei Starovoitov /* update the same key to free the timer */ 2683540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0); 2693540f7c6SAlexei Starovoitov 2703540f7c6SAlexei Starovoitov /* init more timers to check that htab operations 2713540f7c6SAlexei Starovoitov * don't leak timer memory. 2723540f7c6SAlexei Starovoitov */ 2733540f7c6SAlexei Starovoitov key = 0; 2743540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0); 2753540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key); 2763540f7c6SAlexei Starovoitov if (val) 2773540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME); 2783540f7c6SAlexei Starovoitov bpf_map_delete_elem(&hmap, &key); 2793540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0); 2803540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key); 2813540f7c6SAlexei Starovoitov if (val) 2823540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME); 2833540f7c6SAlexei Starovoitov 2843540f7c6SAlexei Starovoitov /* and with non-prealloc htab */ 2853540f7c6SAlexei Starovoitov key_malloc = 0; 2863540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0); 2873540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); 2883540f7c6SAlexei Starovoitov if (val) 2893540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME); 2903540f7c6SAlexei Starovoitov bpf_map_delete_elem(&hmap_malloc, &key_malloc); 2913540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0); 2923540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); 2933540f7c6SAlexei Starovoitov if (val) 2943540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME); 2953540f7c6SAlexei Starovoitov 2963540f7c6SAlexei Starovoitov return bpf_timer_test(); 2973540f7c6SAlexei Starovoitov } 298944459e8STero Kristo 299944459e8STero Kristo /* callback for absolute timer */ 300944459e8STero Kristo static int timer_cb3(void *map, int *key, struct bpf_timer *timer) 301944459e8STero Kristo { 302944459e8STero Kristo abs_data += 6; 303944459e8STero Kristo 304944459e8STero Kristo if (abs_data < 12) { 305944459e8STero Kristo bpf_timer_start(timer, bpf_ktime_get_boot_ns() + 1000, 306944459e8STero Kristo BPF_F_TIMER_ABS); 307944459e8STero Kristo } else { 308944459e8STero Kristo /* Re-arm timer ~35 seconds in future */ 309944459e8STero Kristo bpf_timer_start(timer, bpf_ktime_get_boot_ns() + (1ull << 35), 310944459e8STero Kristo BPF_F_TIMER_ABS); 311944459e8STero Kristo } 312944459e8STero Kristo 313944459e8STero Kristo return 0; 314944459e8STero Kristo } 315944459e8STero Kristo 316944459e8STero Kristo SEC("fentry/bpf_fentry_test3") 317944459e8STero Kristo int BPF_PROG2(test3, int, a) 318944459e8STero Kristo { 319944459e8STero Kristo int key = 0; 320944459e8STero Kristo struct bpf_timer *timer; 321944459e8STero Kristo 322944459e8STero Kristo bpf_printk("test3"); 323944459e8STero Kristo 324944459e8STero Kristo timer = bpf_map_lookup_elem(&abs_timer, &key); 325944459e8STero Kristo if (timer) { 326944459e8STero Kristo if (bpf_timer_init(timer, &abs_timer, CLOCK_BOOTTIME) != 0) 327944459e8STero Kristo err |= 2048; 328944459e8STero Kristo bpf_timer_set_callback(timer, timer_cb3); 329944459e8STero Kristo bpf_timer_start(timer, bpf_ktime_get_boot_ns() + 1000, 330944459e8STero Kristo BPF_F_TIMER_ABS); 331944459e8STero Kristo } 332944459e8STero Kristo 333944459e8STero Kristo return 0; 334944459e8STero Kristo } 3350d7ae068SDavid Vernet 3360d7ae068SDavid Vernet /* callback for pinned timer */ 3370d7ae068SDavid Vernet static int timer_cb_pinned(void *map, int *key, struct bpf_timer *timer) 3380d7ae068SDavid Vernet { 3390d7ae068SDavid Vernet __s32 cpu = bpf_get_smp_processor_id(); 3400d7ae068SDavid Vernet 3410d7ae068SDavid Vernet if (cpu != pinned_cpu) 3420d7ae068SDavid Vernet err |= 16384; 3430d7ae068SDavid Vernet 3440d7ae068SDavid Vernet pinned_callback_check++; 3450d7ae068SDavid Vernet return 0; 3460d7ae068SDavid Vernet } 3470d7ae068SDavid Vernet 3480d7ae068SDavid Vernet static void test_pinned_timer(bool soft) 3490d7ae068SDavid Vernet { 3500d7ae068SDavid Vernet int key = 0; 3510d7ae068SDavid Vernet void *map; 3520d7ae068SDavid Vernet struct bpf_timer *timer; 3530d7ae068SDavid Vernet __u64 flags = BPF_F_TIMER_CPU_PIN; 3540d7ae068SDavid Vernet __u64 start_time; 3550d7ae068SDavid Vernet 3560d7ae068SDavid Vernet if (soft) { 3570d7ae068SDavid Vernet map = &soft_timer_pinned; 3580d7ae068SDavid Vernet start_time = 0; 3590d7ae068SDavid Vernet } else { 3600d7ae068SDavid Vernet map = &abs_timer_pinned; 3610d7ae068SDavid Vernet start_time = bpf_ktime_get_boot_ns(); 3620d7ae068SDavid Vernet flags |= BPF_F_TIMER_ABS; 3630d7ae068SDavid Vernet } 3640d7ae068SDavid Vernet 3650d7ae068SDavid Vernet timer = bpf_map_lookup_elem(map, &key); 3660d7ae068SDavid Vernet if (timer) { 3670d7ae068SDavid Vernet if (bpf_timer_init(timer, map, CLOCK_BOOTTIME) != 0) 3680d7ae068SDavid Vernet err |= 4096; 3690d7ae068SDavid Vernet bpf_timer_set_callback(timer, timer_cb_pinned); 3700d7ae068SDavid Vernet pinned_cpu = bpf_get_smp_processor_id(); 3710d7ae068SDavid Vernet bpf_timer_start(timer, start_time + 1000, flags); 3720d7ae068SDavid Vernet } else { 3730d7ae068SDavid Vernet err |= 8192; 3740d7ae068SDavid Vernet } 3750d7ae068SDavid Vernet } 3760d7ae068SDavid Vernet 3770d7ae068SDavid Vernet SEC("fentry/bpf_fentry_test4") 3780d7ae068SDavid Vernet int BPF_PROG2(test4, int, a) 3790d7ae068SDavid Vernet { 3800d7ae068SDavid Vernet bpf_printk("test4"); 3810d7ae068SDavid Vernet test_pinned_timer(true); 3820d7ae068SDavid Vernet 3830d7ae068SDavid Vernet return 0; 3840d7ae068SDavid Vernet } 3850d7ae068SDavid Vernet 3860d7ae068SDavid Vernet SEC("fentry/bpf_fentry_test5") 3870d7ae068SDavid Vernet int BPF_PROG2(test5, int, a) 3880d7ae068SDavid Vernet { 3890d7ae068SDavid Vernet bpf_printk("test5"); 3900d7ae068SDavid Vernet test_pinned_timer(false); 3910d7ae068SDavid Vernet 3920d7ae068SDavid Vernet return 0; 3930d7ae068SDavid Vernet } 394*3f00e4a9SMartin KaFai Lau 395*3f00e4a9SMartin KaFai Lau static int race_timer_callback(void *race_array, int *race_key, struct bpf_timer *timer) 396*3f00e4a9SMartin KaFai Lau { 397*3f00e4a9SMartin KaFai Lau bpf_timer_start(timer, 1000000, 0); 398*3f00e4a9SMartin KaFai Lau return 0; 399*3f00e4a9SMartin KaFai Lau } 400*3f00e4a9SMartin KaFai Lau 401*3f00e4a9SMartin KaFai Lau SEC("syscall") 402*3f00e4a9SMartin KaFai Lau int race(void *ctx) 403*3f00e4a9SMartin KaFai Lau { 404*3f00e4a9SMartin KaFai Lau struct bpf_timer *timer; 405*3f00e4a9SMartin KaFai Lau int err, race_key = 0; 406*3f00e4a9SMartin KaFai Lau struct elem init; 407*3f00e4a9SMartin KaFai Lau 408*3f00e4a9SMartin KaFai Lau __builtin_memset(&init, 0, sizeof(struct elem)); 409*3f00e4a9SMartin KaFai Lau bpf_map_update_elem(&race_array, &race_key, &init, BPF_ANY); 410*3f00e4a9SMartin KaFai Lau 411*3f00e4a9SMartin KaFai Lau timer = bpf_map_lookup_elem(&race_array, &race_key); 412*3f00e4a9SMartin KaFai Lau if (!timer) 413*3f00e4a9SMartin KaFai Lau return 1; 414*3f00e4a9SMartin KaFai Lau 415*3f00e4a9SMartin KaFai Lau err = bpf_timer_init(timer, &race_array, CLOCK_MONOTONIC); 416*3f00e4a9SMartin KaFai Lau if (err && err != -EBUSY) 417*3f00e4a9SMartin KaFai Lau return 1; 418*3f00e4a9SMartin KaFai Lau 419*3f00e4a9SMartin KaFai Lau bpf_timer_set_callback(timer, race_timer_callback); 420*3f00e4a9SMartin KaFai Lau bpf_timer_start(timer, 0, 0); 421*3f00e4a9SMartin KaFai Lau bpf_timer_cancel(timer); 422*3f00e4a9SMartin KaFai Lau 423*3f00e4a9SMartin KaFai Lau return 0; 424*3f00e4a9SMartin KaFai Lau } 425