1580fa343SKaitao Cheng // SPDX-License-Identifier: GPL-2.0 2580fa343SKaitao Cheng /* Copyright (c) 2026 KylinSoft Corporation. */ 3580fa343SKaitao Cheng 4580fa343SKaitao Cheng #include <vmlinux.h> 5580fa343SKaitao Cheng #include <bpf/bpf_helpers.h> 6580fa343SKaitao Cheng #include "bpf_misc.h" 7580fa343SKaitao Cheng #include "bpf_experimental.h" 8580fa343SKaitao Cheng 9580fa343SKaitao Cheng #define NR_NODES 16 10580fa343SKaitao Cheng 11580fa343SKaitao Cheng struct node_data { 12580fa343SKaitao Cheng int data; 13580fa343SKaitao Cheng }; 14580fa343SKaitao Cheng 15580fa343SKaitao Cheng struct tree_node { 16580fa343SKaitao Cheng struct bpf_rb_node node; 17580fa343SKaitao Cheng u64 key; 18580fa343SKaitao Cheng struct node_data __kptr * node_data; 19580fa343SKaitao Cheng }; 20580fa343SKaitao Cheng 21*ed8fa4b8SKaitao Cheng struct tree_node_ref { 22*ed8fa4b8SKaitao Cheng struct bpf_refcount ref; 23*ed8fa4b8SKaitao Cheng struct bpf_rb_node node; 24*ed8fa4b8SKaitao Cheng u64 key; 25*ed8fa4b8SKaitao Cheng struct node_data __kptr * node_data; 26*ed8fa4b8SKaitao Cheng }; 27*ed8fa4b8SKaitao Cheng 28580fa343SKaitao Cheng #define private(name) SEC(".data." #name) __hidden __aligned(8) 29580fa343SKaitao Cheng 30580fa343SKaitao Cheng private(A) struct bpf_rb_root root __contains(tree_node, node); 31580fa343SKaitao Cheng private(A) struct bpf_spin_lock lock; 32580fa343SKaitao Cheng 33*ed8fa4b8SKaitao Cheng private(B) struct bpf_rb_root root_r __contains(tree_node_ref, node); 34*ed8fa4b8SKaitao Cheng private(B) struct bpf_spin_lock lock_r; 35*ed8fa4b8SKaitao Cheng 36580fa343SKaitao Cheng static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b) 37580fa343SKaitao Cheng { 38580fa343SKaitao Cheng struct tree_node *node_a, *node_b; 39580fa343SKaitao Cheng 40580fa343SKaitao Cheng node_a = container_of(a, struct tree_node, node); 41580fa343SKaitao Cheng node_b = container_of(b, struct tree_node, node); 42580fa343SKaitao Cheng 43580fa343SKaitao Cheng return node_a->key < node_b->key; 44580fa343SKaitao Cheng } 45580fa343SKaitao Cheng 46580fa343SKaitao Cheng SEC("syscall") 47580fa343SKaitao Cheng __retval(0) 48580fa343SKaitao Cheng long rbtree_search_kptr(void *ctx) 49580fa343SKaitao Cheng { 50580fa343SKaitao Cheng struct tree_node *tnode; 51580fa343SKaitao Cheng struct bpf_rb_node *rb_n; 52580fa343SKaitao Cheng struct node_data __kptr * node_data; 53580fa343SKaitao Cheng int lookup_key = NR_NODES / 2; 54580fa343SKaitao Cheng int lookup_data = NR_NODES / 2; 55580fa343SKaitao Cheng int i, data, ret = 0; 56580fa343SKaitao Cheng 57580fa343SKaitao Cheng for (i = 0; i < NR_NODES && can_loop; i++) { 58580fa343SKaitao Cheng tnode = bpf_obj_new(typeof(*tnode)); 59580fa343SKaitao Cheng if (!tnode) 60580fa343SKaitao Cheng return __LINE__; 61580fa343SKaitao Cheng 62580fa343SKaitao Cheng node_data = bpf_obj_new(typeof(*node_data)); 63580fa343SKaitao Cheng if (!node_data) { 64580fa343SKaitao Cheng bpf_obj_drop(tnode); 65580fa343SKaitao Cheng return __LINE__; 66580fa343SKaitao Cheng } 67580fa343SKaitao Cheng 68580fa343SKaitao Cheng tnode->key = i; 69580fa343SKaitao Cheng node_data->data = i; 70580fa343SKaitao Cheng 71580fa343SKaitao Cheng node_data = bpf_kptr_xchg(&tnode->node_data, node_data); 72580fa343SKaitao Cheng if (node_data) 73580fa343SKaitao Cheng bpf_obj_drop(node_data); 74580fa343SKaitao Cheng 75580fa343SKaitao Cheng bpf_spin_lock(&lock); 76580fa343SKaitao Cheng bpf_rbtree_add(&root, &tnode->node, less); 77580fa343SKaitao Cheng bpf_spin_unlock(&lock); 78580fa343SKaitao Cheng } 79580fa343SKaitao Cheng 80580fa343SKaitao Cheng bpf_spin_lock(&lock); 81580fa343SKaitao Cheng rb_n = bpf_rbtree_root(&root); 82580fa343SKaitao Cheng while (rb_n && can_loop) { 83580fa343SKaitao Cheng tnode = container_of(rb_n, struct tree_node, node); 84580fa343SKaitao Cheng node_data = bpf_kptr_xchg(&tnode->node_data, NULL); 85580fa343SKaitao Cheng if (!node_data) { 86580fa343SKaitao Cheng ret = __LINE__; 87580fa343SKaitao Cheng goto fail; 88580fa343SKaitao Cheng } 89580fa343SKaitao Cheng 90580fa343SKaitao Cheng data = node_data->data; 91580fa343SKaitao Cheng node_data = bpf_kptr_xchg(&tnode->node_data, node_data); 92580fa343SKaitao Cheng if (node_data) { 93580fa343SKaitao Cheng bpf_spin_unlock(&lock); 94580fa343SKaitao Cheng bpf_obj_drop(node_data); 95580fa343SKaitao Cheng return __LINE__; 96580fa343SKaitao Cheng } 97580fa343SKaitao Cheng 98580fa343SKaitao Cheng if (lookup_key == tnode->key) { 99580fa343SKaitao Cheng if (data == lookup_data) 100580fa343SKaitao Cheng break; 101580fa343SKaitao Cheng 102580fa343SKaitao Cheng ret = __LINE__; 103580fa343SKaitao Cheng goto fail; 104580fa343SKaitao Cheng } 105580fa343SKaitao Cheng 106580fa343SKaitao Cheng if (lookup_key < tnode->key) 107580fa343SKaitao Cheng rb_n = bpf_rbtree_left(&root, rb_n); 108580fa343SKaitao Cheng else 109580fa343SKaitao Cheng rb_n = bpf_rbtree_right(&root, rb_n); 110580fa343SKaitao Cheng } 111580fa343SKaitao Cheng bpf_spin_unlock(&lock); 112580fa343SKaitao Cheng 113580fa343SKaitao Cheng while (can_loop) { 114580fa343SKaitao Cheng bpf_spin_lock(&lock); 115580fa343SKaitao Cheng rb_n = bpf_rbtree_first(&root); 116580fa343SKaitao Cheng if (!rb_n) { 117580fa343SKaitao Cheng bpf_spin_unlock(&lock); 118580fa343SKaitao Cheng return 0; 119580fa343SKaitao Cheng } 120580fa343SKaitao Cheng 121580fa343SKaitao Cheng rb_n = bpf_rbtree_remove(&root, rb_n); 122580fa343SKaitao Cheng if (!rb_n) { 123580fa343SKaitao Cheng ret = __LINE__; 124580fa343SKaitao Cheng goto fail; 125580fa343SKaitao Cheng } 126580fa343SKaitao Cheng bpf_spin_unlock(&lock); 127580fa343SKaitao Cheng 128580fa343SKaitao Cheng tnode = container_of(rb_n, struct tree_node, node); 129580fa343SKaitao Cheng 130580fa343SKaitao Cheng node_data = bpf_kptr_xchg(&tnode->node_data, NULL); 131580fa343SKaitao Cheng if (node_data) 132580fa343SKaitao Cheng bpf_obj_drop(node_data); 133580fa343SKaitao Cheng 134580fa343SKaitao Cheng bpf_obj_drop(tnode); 135580fa343SKaitao Cheng } 136580fa343SKaitao Cheng 137580fa343SKaitao Cheng return 0; 138580fa343SKaitao Cheng fail: 139580fa343SKaitao Cheng bpf_spin_unlock(&lock); 140580fa343SKaitao Cheng return ret; 141580fa343SKaitao Cheng } 142580fa343SKaitao Cheng 143*ed8fa4b8SKaitao Cheng static bool less_r(struct bpf_rb_node *a, const struct bpf_rb_node *b) 144*ed8fa4b8SKaitao Cheng { 145*ed8fa4b8SKaitao Cheng struct tree_node_ref *node_a, *node_b; 146*ed8fa4b8SKaitao Cheng 147*ed8fa4b8SKaitao Cheng node_a = container_of(a, struct tree_node_ref, node); 148*ed8fa4b8SKaitao Cheng node_b = container_of(b, struct tree_node_ref, node); 149*ed8fa4b8SKaitao Cheng 150*ed8fa4b8SKaitao Cheng return node_a->key < node_b->key; 151*ed8fa4b8SKaitao Cheng } 152*ed8fa4b8SKaitao Cheng 153*ed8fa4b8SKaitao Cheng SEC("syscall") 154*ed8fa4b8SKaitao Cheng __retval(0) 155*ed8fa4b8SKaitao Cheng long rbtree_search_kptr_ref(void *ctx) 156*ed8fa4b8SKaitao Cheng { 157*ed8fa4b8SKaitao Cheng struct tree_node_ref *tnode_r, *tnode_m; 158*ed8fa4b8SKaitao Cheng struct bpf_rb_node *rb_n; 159*ed8fa4b8SKaitao Cheng struct node_data __kptr * node_data; 160*ed8fa4b8SKaitao Cheng int lookup_key = NR_NODES / 2; 161*ed8fa4b8SKaitao Cheng int lookup_data = NR_NODES / 2; 162*ed8fa4b8SKaitao Cheng int i, data, ret = 0; 163*ed8fa4b8SKaitao Cheng 164*ed8fa4b8SKaitao Cheng for (i = 0; i < NR_NODES && can_loop; i++) { 165*ed8fa4b8SKaitao Cheng tnode_r = bpf_obj_new(typeof(*tnode_r)); 166*ed8fa4b8SKaitao Cheng if (!tnode_r) 167*ed8fa4b8SKaitao Cheng return __LINE__; 168*ed8fa4b8SKaitao Cheng 169*ed8fa4b8SKaitao Cheng node_data = bpf_obj_new(typeof(*node_data)); 170*ed8fa4b8SKaitao Cheng if (!node_data) { 171*ed8fa4b8SKaitao Cheng bpf_obj_drop(tnode_r); 172*ed8fa4b8SKaitao Cheng return __LINE__; 173*ed8fa4b8SKaitao Cheng } 174*ed8fa4b8SKaitao Cheng 175*ed8fa4b8SKaitao Cheng tnode_r->key = i; 176*ed8fa4b8SKaitao Cheng node_data->data = i; 177*ed8fa4b8SKaitao Cheng 178*ed8fa4b8SKaitao Cheng node_data = bpf_kptr_xchg(&tnode_r->node_data, node_data); 179*ed8fa4b8SKaitao Cheng if (node_data) 180*ed8fa4b8SKaitao Cheng bpf_obj_drop(node_data); 181*ed8fa4b8SKaitao Cheng 182*ed8fa4b8SKaitao Cheng /* Unused reference */ 183*ed8fa4b8SKaitao Cheng tnode_m = bpf_refcount_acquire(tnode_r); 184*ed8fa4b8SKaitao Cheng if (!tnode_m) 185*ed8fa4b8SKaitao Cheng return __LINE__; 186*ed8fa4b8SKaitao Cheng 187*ed8fa4b8SKaitao Cheng bpf_spin_lock(&lock_r); 188*ed8fa4b8SKaitao Cheng bpf_rbtree_add(&root_r, &tnode_r->node, less_r); 189*ed8fa4b8SKaitao Cheng bpf_spin_unlock(&lock_r); 190*ed8fa4b8SKaitao Cheng 191*ed8fa4b8SKaitao Cheng bpf_obj_drop(tnode_m); 192*ed8fa4b8SKaitao Cheng } 193*ed8fa4b8SKaitao Cheng 194*ed8fa4b8SKaitao Cheng bpf_spin_lock(&lock_r); 195*ed8fa4b8SKaitao Cheng rb_n = bpf_rbtree_root(&root_r); 196*ed8fa4b8SKaitao Cheng while (rb_n && can_loop) { 197*ed8fa4b8SKaitao Cheng tnode_r = container_of(rb_n, struct tree_node_ref, node); 198*ed8fa4b8SKaitao Cheng node_data = bpf_kptr_xchg(&tnode_r->node_data, NULL); 199*ed8fa4b8SKaitao Cheng if (!node_data) { 200*ed8fa4b8SKaitao Cheng ret = __LINE__; 201*ed8fa4b8SKaitao Cheng goto fail; 202*ed8fa4b8SKaitao Cheng } 203*ed8fa4b8SKaitao Cheng 204*ed8fa4b8SKaitao Cheng data = node_data->data; 205*ed8fa4b8SKaitao Cheng node_data = bpf_kptr_xchg(&tnode_r->node_data, node_data); 206*ed8fa4b8SKaitao Cheng if (node_data) { 207*ed8fa4b8SKaitao Cheng bpf_spin_unlock(&lock_r); 208*ed8fa4b8SKaitao Cheng bpf_obj_drop(node_data); 209*ed8fa4b8SKaitao Cheng return __LINE__; 210*ed8fa4b8SKaitao Cheng } 211*ed8fa4b8SKaitao Cheng 212*ed8fa4b8SKaitao Cheng if (lookup_key == tnode_r->key) { 213*ed8fa4b8SKaitao Cheng if (data == lookup_data) 214*ed8fa4b8SKaitao Cheng break; 215*ed8fa4b8SKaitao Cheng 216*ed8fa4b8SKaitao Cheng ret = __LINE__; 217*ed8fa4b8SKaitao Cheng goto fail; 218*ed8fa4b8SKaitao Cheng } 219*ed8fa4b8SKaitao Cheng 220*ed8fa4b8SKaitao Cheng if (lookup_key < tnode_r->key) 221*ed8fa4b8SKaitao Cheng rb_n = bpf_rbtree_left(&root_r, rb_n); 222*ed8fa4b8SKaitao Cheng else 223*ed8fa4b8SKaitao Cheng rb_n = bpf_rbtree_right(&root_r, rb_n); 224*ed8fa4b8SKaitao Cheng } 225*ed8fa4b8SKaitao Cheng bpf_spin_unlock(&lock_r); 226*ed8fa4b8SKaitao Cheng 227*ed8fa4b8SKaitao Cheng while (can_loop) { 228*ed8fa4b8SKaitao Cheng bpf_spin_lock(&lock_r); 229*ed8fa4b8SKaitao Cheng rb_n = bpf_rbtree_first(&root_r); 230*ed8fa4b8SKaitao Cheng if (!rb_n) { 231*ed8fa4b8SKaitao Cheng bpf_spin_unlock(&lock_r); 232*ed8fa4b8SKaitao Cheng return 0; 233*ed8fa4b8SKaitao Cheng } 234*ed8fa4b8SKaitao Cheng 235*ed8fa4b8SKaitao Cheng rb_n = bpf_rbtree_remove(&root_r, rb_n); 236*ed8fa4b8SKaitao Cheng if (!rb_n) { 237*ed8fa4b8SKaitao Cheng ret = __LINE__; 238*ed8fa4b8SKaitao Cheng goto fail; 239*ed8fa4b8SKaitao Cheng } 240*ed8fa4b8SKaitao Cheng bpf_spin_unlock(&lock_r); 241*ed8fa4b8SKaitao Cheng 242*ed8fa4b8SKaitao Cheng tnode_r = container_of(rb_n, struct tree_node_ref, node); 243*ed8fa4b8SKaitao Cheng 244*ed8fa4b8SKaitao Cheng node_data = bpf_kptr_xchg(&tnode_r->node_data, NULL); 245*ed8fa4b8SKaitao Cheng if (node_data) 246*ed8fa4b8SKaitao Cheng bpf_obj_drop(node_data); 247*ed8fa4b8SKaitao Cheng 248*ed8fa4b8SKaitao Cheng bpf_obj_drop(tnode_r); 249*ed8fa4b8SKaitao Cheng } 250*ed8fa4b8SKaitao Cheng 251*ed8fa4b8SKaitao Cheng return 0; 252*ed8fa4b8SKaitao Cheng fail: 253*ed8fa4b8SKaitao Cheng bpf_spin_unlock(&lock_r); 254*ed8fa4b8SKaitao Cheng return ret; 255*ed8fa4b8SKaitao Cheng } 256580fa343SKaitao Cheng 257580fa343SKaitao Cheng SEC("syscall") 258580fa343SKaitao Cheng __failure __msg("R1 type=scalar expected=map_value, ptr_, ptr_") 259580fa343SKaitao Cheng long non_own_ref_kptr_xchg_no_lock(void *ctx) 260580fa343SKaitao Cheng { 261580fa343SKaitao Cheng struct tree_node *tnode; 262580fa343SKaitao Cheng struct bpf_rb_node *rb_n; 263580fa343SKaitao Cheng struct node_data __kptr * node_data; 264580fa343SKaitao Cheng int data; 265580fa343SKaitao Cheng 266580fa343SKaitao Cheng bpf_spin_lock(&lock); 267580fa343SKaitao Cheng rb_n = bpf_rbtree_first(&root); 268580fa343SKaitao Cheng if (!rb_n) { 269580fa343SKaitao Cheng bpf_spin_unlock(&lock); 270580fa343SKaitao Cheng return __LINE__; 271580fa343SKaitao Cheng } 272580fa343SKaitao Cheng bpf_spin_unlock(&lock); 273580fa343SKaitao Cheng 274580fa343SKaitao Cheng tnode = container_of(rb_n, struct tree_node, node); 275580fa343SKaitao Cheng node_data = bpf_kptr_xchg(&tnode->node_data, NULL); 276580fa343SKaitao Cheng if (!node_data) 277580fa343SKaitao Cheng return __LINE__; 278580fa343SKaitao Cheng 279580fa343SKaitao Cheng data = node_data->data; 280580fa343SKaitao Cheng if (data < 0) 281580fa343SKaitao Cheng return __LINE__; 282580fa343SKaitao Cheng 283580fa343SKaitao Cheng node_data = bpf_kptr_xchg(&tnode->node_data, node_data); 284580fa343SKaitao Cheng if (node_data) 285580fa343SKaitao Cheng return __LINE__; 286580fa343SKaitao Cheng 287580fa343SKaitao Cheng return 0; 288580fa343SKaitao Cheng } 289580fa343SKaitao Cheng 290580fa343SKaitao Cheng char _license[] SEC("license") = "GPL"; 291