]> Git Repo - linux.git/blob - tools/testing/selftests/bpf/progs/wq.c
Linux 6.14-rc3
[linux.git] / tools / testing / selftests / bpf / progs / wq.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2024 Benjamin Tissoires
3  */
4
5 #include "bpf_experimental.h"
6 #include <bpf/bpf_helpers.h>
7 #include "bpf_misc.h"
8 #include "../test_kmods/bpf_testmod_kfunc.h"
9
10 char _license[] SEC("license") = "GPL";
11
12 struct hmap_elem {
13         int counter;
14         struct bpf_timer timer; /* unused */
15         struct bpf_spin_lock lock; /* unused */
16         struct bpf_wq work;
17 };
18
19 struct {
20         __uint(type, BPF_MAP_TYPE_HASH);
21         __uint(max_entries, 1000);
22         __type(key, int);
23         __type(value, struct hmap_elem);
24 } hmap SEC(".maps");
25
26 struct {
27         __uint(type, BPF_MAP_TYPE_HASH);
28         __uint(map_flags, BPF_F_NO_PREALLOC);
29         __uint(max_entries, 1000);
30         __type(key, int);
31         __type(value, struct hmap_elem);
32 } hmap_malloc SEC(".maps");
33
34 struct elem {
35         int ok_offset;
36         struct bpf_wq w;
37 };
38
39 struct {
40         __uint(type, BPF_MAP_TYPE_ARRAY);
41         __uint(max_entries, 2);
42         __type(key, int);
43         __type(value, struct elem);
44 } array SEC(".maps");
45
46 struct {
47         __uint(type, BPF_MAP_TYPE_LRU_HASH);
48         __uint(max_entries, 4);
49         __type(key, int);
50         __type(value, struct elem);
51 } lru SEC(".maps");
52
53 __u32 ok;
54 __u32 ok_sleepable;
55
56 static int test_elem_callback(void *map, int *key,
57                 int (callback_fn)(void *map, int *key, void *value))
58 {
59         struct elem init = {}, *val;
60         struct bpf_wq *wq;
61
62         if ((ok & (1 << *key) ||
63             (ok_sleepable & (1 << *key))))
64                 return -22;
65
66         if (map == &lru &&
67             bpf_map_update_elem(map, key, &init, 0))
68                 return -1;
69
70         val = bpf_map_lookup_elem(map, key);
71         if (!val)
72                 return -2;
73
74         val->ok_offset = *key;
75
76         wq = &val->w;
77         if (bpf_wq_init(wq, map, 0) != 0)
78                 return -3;
79
80         if (bpf_wq_set_callback(wq, callback_fn, 0))
81                 return -4;
82
83         if (bpf_wq_start(wq, 0))
84                 return -5;
85
86         return 0;
87 }
88
89 static int test_hmap_elem_callback(void *map, int *key,
90                 int (callback_fn)(void *map, int *key, void *value))
91 {
92         struct hmap_elem init = {}, *val;
93         struct bpf_wq *wq;
94
95         if ((ok & (1 << *key) ||
96             (ok_sleepable & (1 << *key))))
97                 return -22;
98
99         if (bpf_map_update_elem(map, key, &init, 0))
100                 return -1;
101
102         val = bpf_map_lookup_elem(map, key);
103         if (!val)
104                 return -2;
105
106         wq = &val->work;
107         if (bpf_wq_init(wq, map, 0) != 0)
108                 return -3;
109
110         if (bpf_wq_set_callback(wq, callback_fn, 0))
111                 return -4;
112
113         if (bpf_wq_start(wq, 0))
114                 return -5;
115
116         return 0;
117 }
118
119 /* callback for non sleepable workqueue */
120 static int wq_callback(void *map, int *key, void *value)
121 {
122         bpf_kfunc_common_test();
123         ok |= (1 << *key);
124         return 0;
125 }
126
127 /* callback for sleepable workqueue */
128 static int wq_cb_sleepable(void *map, int *key, void *value)
129 {
130         struct elem *data = (struct elem *)value;
131         int offset = data->ok_offset;
132
133         if (*key != offset)
134                 return 0;
135
136         bpf_kfunc_call_test_sleepable();
137         ok_sleepable |= (1 << offset);
138         return 0;
139 }
140
141 SEC("tc")
142 /* test that workqueues can be used from an array */
143 __retval(0)
144 long test_call_array_sleepable(void *ctx)
145 {
146         int key = 0;
147
148         return test_elem_callback(&array, &key, wq_cb_sleepable);
149 }
150
151 SEC("syscall")
152 /* Same test than above but from a sleepable context. */
153 __retval(0)
154 long test_syscall_array_sleepable(void *ctx)
155 {
156         int key = 1;
157
158         return test_elem_callback(&array, &key, wq_cb_sleepable);
159 }
160
161 SEC("tc")
162 /* test that workqueues can be used from a hashmap */
163 __retval(0)
164 long test_call_hash_sleepable(void *ctx)
165 {
166         int key = 2;
167
168         return test_hmap_elem_callback(&hmap, &key, wq_callback);
169 }
170
171 SEC("tc")
172 /* test that workqueues can be used from a hashmap with NO_PREALLOC. */
173 __retval(0)
174 long test_call_hash_malloc_sleepable(void *ctx)
175 {
176         int key = 3;
177
178         return test_hmap_elem_callback(&hmap_malloc, &key, wq_callback);
179 }
180
181 SEC("tc")
182 /* test that workqueues can be used from a LRU map */
183 __retval(0)
184 long test_call_lru_sleepable(void *ctx)
185 {
186         int key = 4;
187
188         return test_elem_callback(&lru, &key, wq_callback);
189 }
This page took 0.041895 seconds and 4 git commands to generate.