1 // SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause 2 /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ 3 #include <limits.h> 4 5 #include <libarena/common.h> 6 #include <libarena/asan.h> 7 #include <libarena/buddy.h> 8 9 struct buddy __arena buddy; 10 volatile u32 zero = 0; 11 12 /* 13 * Storage for the queue nodes declared by bpf_arena_spin_lock.h. Each program 14 * linking the arena spinlock provides exactly one definition, so that the array 15 * is emitted once rather than once per translation unit. 16 */ 17 struct arena_qnode __arena __hidden qnodes[_Q_MAX_CPUS][_Q_MAX_NODES]; 18 19 int arena_fls(__u64 word) 20 { 21 if (!word) 22 return 0; 23 24 return 64 - __builtin_clzll(word); 25 } 26 27 SEC("syscall") 28 __weak int arena_get_info(struct arena_get_info_args *args) 29 { 30 args->arena_base = arena_base(&arena); 31 32 return 0; 33 } 34 35 SEC("syscall") 36 __weak int arena_alloc_reserve(struct arena_alloc_reserve_args *args) 37 { 38 return bpf_arena_reserve_pages(&arena, NULL, args->nr_pages); 39 } 40 41 SEC("syscall") 42 __weak int arena_buddy_reset(void) 43 { 44 buddy_destroy(&buddy); 45 46 return buddy_init(&buddy); 47 } 48 49 SEC("syscall") 50 __weak int arena_buddy_destroy(void) 51 { 52 return buddy_destroy(&buddy); 53 } 54 55 __weak void __arena *arena_malloc(size_t size) 56 { 57 return buddy_alloc(&buddy, size); 58 } 59 60 __weak void __arena *arena_calloc(size_t ncount, size_t size) 61 { 62 void __arena *mem; 63 size_t total; 64 65 /* 66 * Ideally we'd be using __builtin_mul_overflow here, 67 * but the BPF compiler backend doesn't implement __multi3. 68 * There are ways to optimize the division away from the 69 * overflow check, but any costs are dwarfed by the 70 * buddy_alloc() call. Keep it simple for now. 71 */ 72 if (unlikely(ncount && size >= ULLONG_MAX / ncount)) 73 return NULL; 74 75 total = ncount * size; 76 77 mem = buddy_alloc(&buddy, total); 78 if (likely(mem)) 79 arena_memset(mem, 0, total); 80 81 return mem; 82 } 83 84 __weak void arena_free(void __arena *ptr) 85 { 86 buddy_free(&buddy, ptr); 87 } 88 89 char _license[] SEC("license") = "GPL"; 90