xref: /linux/tools/testing/selftests/bpf/progs/task_work.c (revision 4f38da1f027ea2c9f01bb71daa7a299c191b6940)
1*39fd74dfSMykyta Yatsenko // SPDX-License-Identifier: GPL-2.0
2*39fd74dfSMykyta Yatsenko /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3*39fd74dfSMykyta Yatsenko 
4*39fd74dfSMykyta Yatsenko #include <vmlinux.h>
5*39fd74dfSMykyta Yatsenko #include <string.h>
6*39fd74dfSMykyta Yatsenko #include <stdbool.h>
7*39fd74dfSMykyta Yatsenko #include <bpf/bpf_helpers.h>
8*39fd74dfSMykyta Yatsenko #include <bpf/bpf_tracing.h>
9*39fd74dfSMykyta Yatsenko #include "bpf_misc.h"
10*39fd74dfSMykyta Yatsenko #include "errno.h"
11*39fd74dfSMykyta Yatsenko 
12*39fd74dfSMykyta Yatsenko char _license[] SEC("license") = "GPL";
13*39fd74dfSMykyta Yatsenko 
14*39fd74dfSMykyta Yatsenko const void *user_ptr = NULL;
15*39fd74dfSMykyta Yatsenko 
16*39fd74dfSMykyta Yatsenko struct elem {
17*39fd74dfSMykyta Yatsenko 	char data[128];
18*39fd74dfSMykyta Yatsenko 	struct bpf_task_work tw;
19*39fd74dfSMykyta Yatsenko };
20*39fd74dfSMykyta Yatsenko 
21*39fd74dfSMykyta Yatsenko struct {
22*39fd74dfSMykyta Yatsenko 	__uint(type, BPF_MAP_TYPE_HASH);
23*39fd74dfSMykyta Yatsenko 	__uint(map_flags, BPF_F_NO_PREALLOC);
24*39fd74dfSMykyta Yatsenko 	__uint(max_entries, 1);
25*39fd74dfSMykyta Yatsenko 	__type(key, int);
26*39fd74dfSMykyta Yatsenko 	__type(value, struct elem);
27*39fd74dfSMykyta Yatsenko } hmap SEC(".maps");
28*39fd74dfSMykyta Yatsenko 
29*39fd74dfSMykyta Yatsenko struct {
30*39fd74dfSMykyta Yatsenko 	__uint(type, BPF_MAP_TYPE_ARRAY);
31*39fd74dfSMykyta Yatsenko 	__uint(max_entries, 1);
32*39fd74dfSMykyta Yatsenko 	__type(key, int);
33*39fd74dfSMykyta Yatsenko 	__type(value, struct elem);
34*39fd74dfSMykyta Yatsenko } arrmap SEC(".maps");
35*39fd74dfSMykyta Yatsenko 
36*39fd74dfSMykyta Yatsenko struct {
37*39fd74dfSMykyta Yatsenko 	__uint(type, BPF_MAP_TYPE_LRU_HASH);
38*39fd74dfSMykyta Yatsenko 	__uint(max_entries, 1);
39*39fd74dfSMykyta Yatsenko 	__type(key, int);
40*39fd74dfSMykyta Yatsenko 	__type(value, struct elem);
41*39fd74dfSMykyta Yatsenko } lrumap SEC(".maps");
42*39fd74dfSMykyta Yatsenko 
43*39fd74dfSMykyta Yatsenko static int process_work(struct bpf_map *map, void *key, void *value)
44*39fd74dfSMykyta Yatsenko {
45*39fd74dfSMykyta Yatsenko 	struct elem *work = value;
46*39fd74dfSMykyta Yatsenko 
47*39fd74dfSMykyta Yatsenko 	bpf_copy_from_user_str(work->data, sizeof(work->data), (const void *)user_ptr, 0);
48*39fd74dfSMykyta Yatsenko 	return 0;
49*39fd74dfSMykyta Yatsenko }
50*39fd74dfSMykyta Yatsenko 
51*39fd74dfSMykyta Yatsenko int key = 0;
52*39fd74dfSMykyta Yatsenko 
53*39fd74dfSMykyta Yatsenko SEC("perf_event")
54*39fd74dfSMykyta Yatsenko int oncpu_hash_map(struct pt_regs *args)
55*39fd74dfSMykyta Yatsenko {
56*39fd74dfSMykyta Yatsenko 	struct elem empty_work = { .data = { 0 } };
57*39fd74dfSMykyta Yatsenko 	struct elem *work;
58*39fd74dfSMykyta Yatsenko 	struct task_struct *task;
59*39fd74dfSMykyta Yatsenko 	int err;
60*39fd74dfSMykyta Yatsenko 
61*39fd74dfSMykyta Yatsenko 	task = bpf_get_current_task_btf();
62*39fd74dfSMykyta Yatsenko 	err = bpf_map_update_elem(&hmap, &key, &empty_work, BPF_NOEXIST);
63*39fd74dfSMykyta Yatsenko 	if (err)
64*39fd74dfSMykyta Yatsenko 		return 0;
65*39fd74dfSMykyta Yatsenko 	work = bpf_map_lookup_elem(&hmap, &key);
66*39fd74dfSMykyta Yatsenko 	if (!work)
67*39fd74dfSMykyta Yatsenko 		return 0;
68*39fd74dfSMykyta Yatsenko 
69*39fd74dfSMykyta Yatsenko 	bpf_task_work_schedule_resume(task, &work->tw, &hmap, process_work, NULL);
70*39fd74dfSMykyta Yatsenko 	return 0;
71*39fd74dfSMykyta Yatsenko }
72*39fd74dfSMykyta Yatsenko 
73*39fd74dfSMykyta Yatsenko SEC("perf_event")
74*39fd74dfSMykyta Yatsenko int oncpu_array_map(struct pt_regs *args)
75*39fd74dfSMykyta Yatsenko {
76*39fd74dfSMykyta Yatsenko 	struct elem *work;
77*39fd74dfSMykyta Yatsenko 	struct task_struct *task;
78*39fd74dfSMykyta Yatsenko 
79*39fd74dfSMykyta Yatsenko 	task = bpf_get_current_task_btf();
80*39fd74dfSMykyta Yatsenko 	work = bpf_map_lookup_elem(&arrmap, &key);
81*39fd74dfSMykyta Yatsenko 	if (!work)
82*39fd74dfSMykyta Yatsenko 		return 0;
83*39fd74dfSMykyta Yatsenko 	bpf_task_work_schedule_signal(task, &work->tw, &arrmap, process_work, NULL);
84*39fd74dfSMykyta Yatsenko 	return 0;
85*39fd74dfSMykyta Yatsenko }
86*39fd74dfSMykyta Yatsenko 
87*39fd74dfSMykyta Yatsenko SEC("perf_event")
88*39fd74dfSMykyta Yatsenko int oncpu_lru_map(struct pt_regs *args)
89*39fd74dfSMykyta Yatsenko {
90*39fd74dfSMykyta Yatsenko 	struct elem empty_work = { .data = { 0 } };
91*39fd74dfSMykyta Yatsenko 	struct elem *work;
92*39fd74dfSMykyta Yatsenko 	struct task_struct *task;
93*39fd74dfSMykyta Yatsenko 	int err;
94*39fd74dfSMykyta Yatsenko 
95*39fd74dfSMykyta Yatsenko 	task = bpf_get_current_task_btf();
96*39fd74dfSMykyta Yatsenko 	work = bpf_map_lookup_elem(&lrumap, &key);
97*39fd74dfSMykyta Yatsenko 	if (work)
98*39fd74dfSMykyta Yatsenko 		return 0;
99*39fd74dfSMykyta Yatsenko 	err = bpf_map_update_elem(&lrumap, &key, &empty_work, BPF_NOEXIST);
100*39fd74dfSMykyta Yatsenko 	if (err)
101*39fd74dfSMykyta Yatsenko 		return 0;
102*39fd74dfSMykyta Yatsenko 	work = bpf_map_lookup_elem(&lrumap, &key);
103*39fd74dfSMykyta Yatsenko 	if (!work || work->data[0])
104*39fd74dfSMykyta Yatsenko 		return 0;
105*39fd74dfSMykyta Yatsenko 	bpf_task_work_schedule_resume(task, &work->tw, &lrumap, process_work, NULL);
106*39fd74dfSMykyta Yatsenko 	return 0;
107*39fd74dfSMykyta Yatsenko }
108