1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2024 Benjamin Tissoires 3 */ 4 5 #include "bpf_experimental.h" 6 #include <bpf/bpf_helpers.h> 7 #include "bpf_misc.h" 8 #include "../bpf_testmod/bpf_testmod_kfunc.h" 9 10 char _license[] SEC("license") = "GPL"; 11 12 struct hmap_elem { 13 int counter; 14 struct bpf_timer timer; /* unused */ 15 struct bpf_spin_lock lock; /* unused */ 16 struct bpf_wq work; 17 }; 18 19 struct { 20 __uint(type, BPF_MAP_TYPE_HASH); 21 __uint(max_entries, 1000); 22 __type(key, int); 23 __type(value, struct hmap_elem); 24 } hmap SEC(".maps"); 25 26 struct { 27 __uint(type, BPF_MAP_TYPE_HASH); 28 __uint(map_flags, BPF_F_NO_PREALLOC); 29 __uint(max_entries, 1000); 30 __type(key, int); 31 __type(value, struct hmap_elem); 32 } hmap_malloc SEC(".maps"); 33 34 struct elem { 35 int ok_offset; 36 struct bpf_wq w; 37 }; 38 39 struct { 40 __uint(type, BPF_MAP_TYPE_ARRAY); 41 __uint(max_entries, 2); 42 __type(key, int); 43 __type(value, struct elem); 44 } array SEC(".maps"); 45 46 struct { 47 __uint(type, BPF_MAP_TYPE_LRU_HASH); 48 __uint(max_entries, 4); 49 __type(key, int); 50 __type(value, struct elem); 51 } lru SEC(".maps"); 52 53 __u32 ok; 54 __u32 ok_sleepable; 55 56 static int test_elem_callback(void *map, int *key, 57 int (callback_fn)(void *map, int *key, void *value)) 58 { 59 struct elem init = {}, *val; 60 struct bpf_wq *wq; 61 62 if ((ok & (1 << *key) || 63 (ok_sleepable & (1 << *key)))) 64 return -22; 65 66 if (map == &lru && 67 bpf_map_update_elem(map, key, &init, 0)) 68 return -1; 69 70 val = bpf_map_lookup_elem(map, key); 71 if (!val) 72 return -2; 73 74 val->ok_offset = *key; 75 76 wq = &val->w; 77 if (bpf_wq_init(wq, map, 0) != 0) 78 return -3; 79 80 if (bpf_wq_set_callback(wq, callback_fn, 0)) 81 return -4; 82 83 if (bpf_wq_start(wq, 0)) 84 return -5; 85 86 return 0; 87 } 88 89 static int test_hmap_elem_callback(void *map, int *key, 90 int (callback_fn)(void *map, int *key, void *value)) 91 { 92 struct hmap_elem init = {}, *val; 93 struct bpf_wq *wq; 94 95 if ((ok & (1 << *key) || 96 (ok_sleepable & (1 << *key)))) 97 return -22; 98 99 if (bpf_map_update_elem(map, key, &init, 0)) 100 return -1; 101 102 val = bpf_map_lookup_elem(map, key); 103 if (!val) 104 return -2; 105 106 wq = &val->work; 107 if (bpf_wq_init(wq, map, 0) != 0) 108 return -3; 109 110 if (bpf_wq_set_callback(wq, callback_fn, 0)) 111 return -4; 112 113 if (bpf_wq_start(wq, 0)) 114 return -5; 115 116 return 0; 117 } 118 119 /* callback for non sleepable workqueue */ 120 static int wq_callback(void *map, int *key, void *value) 121 { 122 bpf_kfunc_common_test(); 123 ok |= (1 << *key); 124 return 0; 125 } 126 127 /* callback for sleepable workqueue */ 128 static int wq_cb_sleepable(void *map, int *key, void *value) 129 { 130 struct elem *data = (struct elem *)value; 131 int offset = data->ok_offset; 132 133 if (*key != offset) 134 return 0; 135 136 bpf_kfunc_call_test_sleepable(); 137 ok_sleepable |= (1 << offset); 138 return 0; 139 } 140 141 SEC("tc") 142 /* test that workqueues can be used from an array */ 143 __retval(0) 144 long test_call_array_sleepable(void *ctx) 145 { 146 int key = 0; 147 148 return test_elem_callback(&array, &key, wq_cb_sleepable); 149 } 150 151 SEC("syscall") 152 /* Same test than above but from a sleepable context. */ 153 __retval(0) 154 long test_syscall_array_sleepable(void *ctx) 155 { 156 int key = 1; 157 158 return test_elem_callback(&array, &key, wq_cb_sleepable); 159 } 160 161 SEC("tc") 162 /* test that workqueues can be used from a hashmap */ 163 __retval(0) 164 long test_call_hash_sleepable(void *ctx) 165 { 166 int key = 2; 167 168 return test_hmap_elem_callback(&hmap, &key, wq_callback); 169 } 170 171 SEC("tc") 172 /* test that workqueues can be used from a hashmap with NO_PREALLOC. */ 173 __retval(0) 174 long test_call_hash_malloc_sleepable(void *ctx) 175 { 176 int key = 3; 177 178 return test_hmap_elem_callback(&hmap_malloc, &key, wq_callback); 179 } 180 181 SEC("tc") 182 /* test that workqueues can be used from a LRU map */ 183 __retval(0) 184 long test_call_lru_sleepable(void *ctx) 185 { 186 int key = 4; 187 188 return test_elem_callback(&lru, &key, wq_callback); 189 } 190
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.