| /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ |
| /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ |
| #pragma once |
| #include "bpf_arena_common.h" |
| |
| #ifndef __round_mask |
| #define __round_mask(x, y) ((__typeof__(x))((y)-1)) |
| #endif |
| #ifndef round_up |
| #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) |
| #endif |
| |
| #ifdef __BPF__ |
| #define NR_CPUS (sizeof(struct cpumask) * 8) |
| |
| static void __arena * __arena page_frag_cur_page[NR_CPUS]; |
| static int __arena page_frag_cur_offset[NR_CPUS]; |
| |
| /* Simple page_frag allocator */ |
| static inline void __arena* bpf_alloc(unsigned int size) |
| { |
| __u64 __arena *obj_cnt; |
| __u32 cpu = bpf_get_smp_processor_id(); |
| void __arena *page = page_frag_cur_page[cpu]; |
| int __arena *cur_offset = &page_frag_cur_offset[cpu]; |
| int offset; |
| |
| size = round_up(size, 8); |
| if (size >= PAGE_SIZE - 8) |
| return NULL; |
| if (!page) { |
| refill: |
| page = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0); |
| if (!page) |
| return NULL; |
| cast_kern(page); |
| page_frag_cur_page[cpu] = page; |
| *cur_offset = PAGE_SIZE - 8; |
| obj_cnt = page + PAGE_SIZE - 8; |
| *obj_cnt = 0; |
| } else { |
| cast_kern(page); |
| obj_cnt = page + PAGE_SIZE - 8; |
| } |
| |
| offset = *cur_offset - size; |
| if (offset < 0) |
| goto refill; |
| |
| (*obj_cnt)++; |
| *cur_offset = offset; |
| return page + offset; |
| } |
| |
| static inline void bpf_free(void __arena *addr) |
| { |
| __u64 __arena *obj_cnt; |
| |
| addr = (void __arena *)(((long)addr) & ~(PAGE_SIZE - 1)); |
| obj_cnt = addr + PAGE_SIZE - 8; |
| if (--(*obj_cnt) == 0) |
| bpf_arena_free_pages(&arena, addr, 1); |
| } |
| #else |
| static inline void __arena* bpf_alloc(unsigned int size) { return NULL; } |
| static inline void bpf_free(void __arena *addr) {} |
| #endif |