1// SPDX-License-Identifier: GPL-2.0 2#include <vmlinux.h> 3#include <bpf/bpf_tracing.h> 4#include <bpf/bpf_helpers.h> 5#include <bpf/bpf_core_read.h> 6#include "bpf_experimental.h" 7 8#ifndef ARRAY_SIZE 9#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof((x)[0])) 10#endif 11 12#include "linked_list.h" 13 14static __always_inline 15int list_push_pop(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map) 16{ 17 struct bpf_list_node *n; 18 struct foo *f; 19 20 f = bpf_obj_new(typeof(*f)); 21 if (!f) 22 return 2; 23 24 bpf_spin_lock(lock); 25 n = bpf_list_pop_front(head); 26 bpf_spin_unlock(lock); 27 if (n) { 28 bpf_obj_drop(container_of(n, struct foo, node2)); 29 bpf_obj_drop(f); 30 return 3; 31 } 32 33 bpf_spin_lock(lock); 34 n = bpf_list_pop_back(head); 35 bpf_spin_unlock(lock); 36 if (n) { 37 bpf_obj_drop(container_of(n, struct foo, node2)); 38 bpf_obj_drop(f); 39 return 4; 40 } 41 42 43 bpf_spin_lock(lock); 44 f->data = 42; 45 bpf_list_push_front(head, &f->node2); 46 bpf_spin_unlock(lock); 47 if (leave_in_map) 48 return 0; 49 bpf_spin_lock(lock); 50 n = bpf_list_pop_back(head); 51 bpf_spin_unlock(lock); 52 if (!n) 53 return 5; 54 f = container_of(n, struct foo, node2); 55 if (f->data != 42) { 56 bpf_obj_drop(f); 57 return 6; 58 } 59 60 bpf_spin_lock(lock); 61 f->data = 13; 62 bpf_list_push_front(head, &f->node2); 63 bpf_spin_unlock(lock); 64 bpf_spin_lock(lock); 65 n = bpf_list_pop_front(head); 66 bpf_spin_unlock(lock); 67 if (!n) 68 return 7; 69 f = container_of(n, struct foo, node2); 70 if (f->data != 13) { 71 bpf_obj_drop(f); 72 return 8; 73 } 74 bpf_obj_drop(f); 75 76 bpf_spin_lock(lock); 77 n = bpf_list_pop_front(head); 78 bpf_spin_unlock(lock); 79 if (n) { 80 bpf_obj_drop(container_of(n, struct foo, node2)); 81 return 9; 82 } 83 84 bpf_spin_lock(lock); 85 n = bpf_list_pop_back(head); 86 bpf_spin_unlock(lock); 87 if (n) { 88 bpf_obj_drop(container_of(n, struct foo, node2)); 89 return 10; 90 } 91 return 0; 92} 93 94 95static __always_inline 96int list_push_pop_multiple(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map) 97{ 98 struct bpf_list_node *n; 99 struct foo *f[200], *pf; 100 int i; 101 102 /* Loop following this check adds nodes 2-at-a-time in order to 103 * validate multiple release_on_unlock release logic 104 */ 105 if (ARRAY_SIZE(f) % 2) 106 return 10; 107 108 for (i = 0; i < ARRAY_SIZE(f); i += 2) { 109 f[i] = bpf_obj_new(typeof(**f)); 110 if (!f[i]) 111 return 2; 112 f[i]->data = i; 113 114 f[i + 1] = bpf_obj_new(typeof(**f)); 115 if (!f[i + 1]) { 116 bpf_obj_drop(f[i]); 117 return 9; 118 } 119 f[i + 1]->data = i + 1; 120 121 bpf_spin_lock(lock); 122 bpf_list_push_front(head, &f[i]->node2); 123 bpf_list_push_front(head, &f[i + 1]->node2); 124 bpf_spin_unlock(lock); 125 } 126 127 for (i = 0; i < ARRAY_SIZE(f); i++) { 128 bpf_spin_lock(lock); 129 n = bpf_list_pop_front(head); 130 bpf_spin_unlock(lock); 131 if (!n) 132 return 3; 133 pf = container_of(n, struct foo, node2); 134 if (pf->data != (ARRAY_SIZE(f) - i - 1)) { 135 bpf_obj_drop(pf); 136 return 4; 137 } 138 bpf_spin_lock(lock); 139 bpf_list_push_back(head, &pf->node2); 140 bpf_spin_unlock(lock); 141 } 142 143 if (leave_in_map) 144 return 0; 145 146 for (i = 0; i < ARRAY_SIZE(f); i++) { 147 bpf_spin_lock(lock); 148 n = bpf_list_pop_back(head); 149 bpf_spin_unlock(lock); 150 if (!n) 151 return 5; 152 pf = container_of(n, struct foo, node2); 153 if (pf->data != i) { 154 bpf_obj_drop(pf); 155 return 6; 156 } 157 bpf_obj_drop(pf); 158 } 159 bpf_spin_lock(lock); 160 n = bpf_list_pop_back(head); 161 bpf_spin_unlock(lock); 162 if (n) { 163 bpf_obj_drop(container_of(n, struct foo, node2)); 164 return 7; 165 } 166 167 bpf_spin_lock(lock); 168 n = bpf_list_pop_front(head); 169 bpf_spin_unlock(lock); 170 if (n) { 171 bpf_obj_drop(container_of(n, struct foo, node2)); 172 return 8; 173 } 174 return 0; 175} 176 177static __always_inline 178int list_in_list(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map) 179{ 180 struct bpf_list_node *n; 181 struct bar *ba[8], *b; 182 struct foo *f; 183 int i; 184 185 f = bpf_obj_new(typeof(*f)); 186 if (!f) 187 return 2; 188 for (i = 0; i < ARRAY_SIZE(ba); i++) { 189 b = bpf_obj_new(typeof(*b)); 190 if (!b) { 191 bpf_obj_drop(f); 192 return 3; 193 } 194 b->data = i; 195 bpf_spin_lock(&f->lock); 196 bpf_list_push_back(&f->head, &b->node); 197 bpf_spin_unlock(&f->lock); 198 } 199 200 bpf_spin_lock(lock); 201 f->data = 42; 202 bpf_list_push_front(head, &f->node2); 203 bpf_spin_unlock(lock); 204 205 if (leave_in_map) 206 return 0; 207 208 bpf_spin_lock(lock); 209 n = bpf_list_pop_front(head); 210 bpf_spin_unlock(lock); 211 if (!n) 212 return 4; 213 f = container_of(n, struct foo, node2); 214 if (f->data != 42) { 215 bpf_obj_drop(f); 216 return 5; 217 } 218 219 for (i = 0; i < ARRAY_SIZE(ba); i++) { 220 bpf_spin_lock(&f->lock); 221 n = bpf_list_pop_front(&f->head); 222 bpf_spin_unlock(&f->lock); 223 if (!n) { 224 bpf_obj_drop(f); 225 return 6; 226 } 227 b = container_of(n, struct bar, node); 228 if (b->data != i) { 229 bpf_obj_drop(f); 230 bpf_obj_drop(b); 231 return 7; 232 } 233 bpf_obj_drop(b); 234 } 235 bpf_spin_lock(&f->lock); 236 n = bpf_list_pop_front(&f->head); 237 bpf_spin_unlock(&f->lock); 238 if (n) { 239 bpf_obj_drop(f); 240 bpf_obj_drop(container_of(n, struct bar, node)); 241 return 8; 242 } 243 bpf_obj_drop(f); 244 return 0; 245} 246 247static __always_inline 248int test_list_push_pop(struct bpf_spin_lock *lock, struct bpf_list_head *head) 249{ 250 int ret; 251 252 ret = list_push_pop(lock, head, false); 253 if (ret) 254 return ret; 255 return list_push_pop(lock, head, true); 256} 257 258static __always_inline 259int test_list_push_pop_multiple(struct bpf_spin_lock *lock, struct bpf_list_head *head) 260{ 261 int ret; 262 263 ret = list_push_pop_multiple(lock, head, false); 264 if (ret) 265 return ret; 266 return list_push_pop_multiple(lock, head, true); 267} 268 269static __always_inline 270int test_list_in_list(struct bpf_spin_lock *lock, struct bpf_list_head *head) 271{ 272 int ret; 273 274 ret = list_in_list(lock, head, false); 275 if (ret) 276 return ret; 277 return list_in_list(lock, head, true); 278} 279 280SEC("tc") 281int map_list_push_pop(void *ctx) 282{ 283 struct map_value *v; 284 285 v = bpf_map_lookup_elem(&array_map, &(int){0}); 286 if (!v) 287 return 1; 288 return test_list_push_pop(&v->lock, &v->head); 289} 290 291SEC("tc") 292int inner_map_list_push_pop(void *ctx) 293{ 294 struct map_value *v; 295 void *map; 296 297 map = bpf_map_lookup_elem(&map_of_maps, &(int){0}); 298 if (!map) 299 return 1; 300 v = bpf_map_lookup_elem(map, &(int){0}); 301 if (!v) 302 return 1; 303 return test_list_push_pop(&v->lock, &v->head); 304} 305 306SEC("tc") 307int global_list_push_pop(void *ctx) 308{ 309 return test_list_push_pop(&glock, &ghead); 310} 311 312SEC("tc") 313int map_list_push_pop_multiple(void *ctx) 314{ 315 struct map_value *v; 316 317 v = bpf_map_lookup_elem(&array_map, &(int){0}); 318 if (!v) 319 return 1; 320 return test_list_push_pop_multiple(&v->lock, &v->head); 321} 322 323SEC("tc") 324int inner_map_list_push_pop_multiple(void *ctx) 325{ 326 struct map_value *v; 327 void *map; 328 329 map = bpf_map_lookup_elem(&map_of_maps, &(int){0}); 330 if (!map) 331 return 1; 332 v = bpf_map_lookup_elem(map, &(int){0}); 333 if (!v) 334 return 1; 335 return test_list_push_pop_multiple(&v->lock, &v->head); 336} 337 338SEC("tc") 339int global_list_push_pop_multiple(void *ctx) 340{ 341 int ret; 342 343 ret = list_push_pop_multiple(&glock, &ghead, false); 344 if (ret) 345 return ret; 346 return list_push_pop_multiple(&glock, &ghead, true); 347} 348 349SEC("tc") 350int map_list_in_list(void *ctx) 351{ 352 struct map_value *v; 353 354 v = bpf_map_lookup_elem(&array_map, &(int){0}); 355 if (!v) 356 return 1; 357 return test_list_in_list(&v->lock, &v->head); 358} 359 360SEC("tc") 361int inner_map_list_in_list(void *ctx) 362{ 363 struct map_value *v; 364 void *map; 365 366 map = bpf_map_lookup_elem(&map_of_maps, &(int){0}); 367 if (!map) 368 return 1; 369 v = bpf_map_lookup_elem(map, &(int){0}); 370 if (!v) 371 return 1; 372 return test_list_in_list(&v->lock, &v->head); 373} 374 375SEC("tc") 376int global_list_in_list(void *ctx) 377{ 378 return test_list_in_list(&glock, &ghead); 379} 380 381char _license[] SEC("license") = "GPL"; 382