1*c6ae18e0SMykyta Yatsenko // SPDX-License-Identifier: GPL-2.0 2*c6ae18e0SMykyta Yatsenko /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3*c6ae18e0SMykyta Yatsenko 4*c6ae18e0SMykyta Yatsenko #include <vmlinux.h> 5*c6ae18e0SMykyta Yatsenko #include <string.h> 6*c6ae18e0SMykyta Yatsenko #include <stdbool.h> 7*c6ae18e0SMykyta Yatsenko #include <bpf/bpf_helpers.h> 8*c6ae18e0SMykyta Yatsenko #include <bpf/bpf_tracing.h> 9*c6ae18e0SMykyta Yatsenko #include "bpf_misc.h" 10*c6ae18e0SMykyta Yatsenko 11*c6ae18e0SMykyta Yatsenko #define ENTRIES 128 12*c6ae18e0SMykyta Yatsenko 13*c6ae18e0SMykyta Yatsenko char _license[] SEC("license") = "GPL"; 14*c6ae18e0SMykyta Yatsenko 15*c6ae18e0SMykyta Yatsenko __u64 callback_scheduled = 0; 16*c6ae18e0SMykyta Yatsenko __u64 callback_success = 0; 17*c6ae18e0SMykyta Yatsenko __u64 schedule_error = 0; 18*c6ae18e0SMykyta Yatsenko __u64 delete_success = 0; 19*c6ae18e0SMykyta Yatsenko 20*c6ae18e0SMykyta Yatsenko struct elem { 21*c6ae18e0SMykyta Yatsenko __u32 count; 22*c6ae18e0SMykyta Yatsenko struct bpf_task_work tw; 23*c6ae18e0SMykyta Yatsenko }; 24*c6ae18e0SMykyta Yatsenko 25*c6ae18e0SMykyta Yatsenko struct { 26*c6ae18e0SMykyta Yatsenko __uint(type, BPF_MAP_TYPE_HASH); 27*c6ae18e0SMykyta Yatsenko __uint(map_flags, BPF_F_NO_PREALLOC); 28*c6ae18e0SMykyta Yatsenko __uint(max_entries, ENTRIES); 29*c6ae18e0SMykyta Yatsenko __type(key, int); 30*c6ae18e0SMykyta Yatsenko __type(value, struct elem); 31*c6ae18e0SMykyta Yatsenko } hmap SEC(".maps"); 32*c6ae18e0SMykyta Yatsenko 33*c6ae18e0SMykyta Yatsenko static int process_work(struct bpf_map *map, void *key, void *value) 34*c6ae18e0SMykyta Yatsenko { 35*c6ae18e0SMykyta Yatsenko __sync_fetch_and_add(&callback_success, 1); 36*c6ae18e0SMykyta Yatsenko return 0; 37*c6ae18e0SMykyta Yatsenko } 38*c6ae18e0SMykyta Yatsenko 39*c6ae18e0SMykyta Yatsenko SEC("syscall") 40*c6ae18e0SMykyta Yatsenko int schedule_task_work(void *ctx) 41*c6ae18e0SMykyta Yatsenko { 42*c6ae18e0SMykyta Yatsenko struct elem empty_work = {.count = 0}; 43*c6ae18e0SMykyta Yatsenko struct elem *work; 44*c6ae18e0SMykyta Yatsenko int key = 0, err; 45*c6ae18e0SMykyta Yatsenko 46*c6ae18e0SMykyta Yatsenko key = bpf_ktime_get_ns() % ENTRIES; 47*c6ae18e0SMykyta Yatsenko work = bpf_map_lookup_elem(&hmap, &key); 48*c6ae18e0SMykyta Yatsenko if (!work) { 49*c6ae18e0SMykyta Yatsenko bpf_map_update_elem(&hmap, &key, &empty_work, BPF_NOEXIST); 50*c6ae18e0SMykyta Yatsenko work = bpf_map_lookup_elem(&hmap, &key); 51*c6ae18e0SMykyta Yatsenko if (!work) 52*c6ae18e0SMykyta Yatsenko return 0; 53*c6ae18e0SMykyta Yatsenko } 54*c6ae18e0SMykyta Yatsenko err = bpf_task_work_schedule_signal(bpf_get_current_task_btf(), &work->tw, &hmap, 55*c6ae18e0SMykyta Yatsenko process_work, NULL); 56*c6ae18e0SMykyta Yatsenko if (err) 57*c6ae18e0SMykyta Yatsenko __sync_fetch_and_add(&schedule_error, 1); 58*c6ae18e0SMykyta Yatsenko else 59*c6ae18e0SMykyta Yatsenko __sync_fetch_and_add(&callback_scheduled, 1); 60*c6ae18e0SMykyta Yatsenko return 0; 61*c6ae18e0SMykyta Yatsenko } 62*c6ae18e0SMykyta Yatsenko 63*c6ae18e0SMykyta Yatsenko SEC("syscall") 64*c6ae18e0SMykyta Yatsenko int delete_task_work(void *ctx) 65*c6ae18e0SMykyta Yatsenko { 66*c6ae18e0SMykyta Yatsenko int key = 0, err; 67*c6ae18e0SMykyta Yatsenko 68*c6ae18e0SMykyta Yatsenko key = bpf_get_prandom_u32() % ENTRIES; 69*c6ae18e0SMykyta Yatsenko err = bpf_map_delete_elem(&hmap, &key); 70*c6ae18e0SMykyta Yatsenko if (!err) 71*c6ae18e0SMykyta Yatsenko __sync_fetch_and_add(&delete_success, 1); 72*c6ae18e0SMykyta Yatsenko return 0; 73*c6ae18e0SMykyta Yatsenko } 74