Loading...
Note: File does not exist in v3.15.
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 "../bpf_testmod/bpf_testmod_kfunc.h"
9
10char _license[] SEC("license") = "GPL";
11
12struct 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
19struct {
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
26struct {
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
34struct elem {
35 int ok_offset;
36 struct bpf_wq w;
37};
38
39struct {
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
46struct {
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
56static 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
89static 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 */
120static 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 */
128static 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
141SEC("tc")
142/* test that workqueues can be used from an array */
143__retval(0)
144long test_call_array_sleepable(void *ctx)
145{
146 int key = 0;
147
148 return test_elem_callback(&array, &key, wq_cb_sleepable);
149}
150
151SEC("syscall")
152/* Same test than above but from a sleepable context. */
153__retval(0)
154long test_syscall_array_sleepable(void *ctx)
155{
156 int key = 1;
157
158 return test_elem_callback(&array, &key, wq_cb_sleepable);
159}
160
161SEC("tc")
162/* test that workqueues can be used from a hashmap */
163__retval(0)
164long test_call_hash_sleepable(void *ctx)
165{
166 int key = 2;
167
168 return test_hmap_elem_callback(&hmap, &key, wq_callback);
169}
170
171SEC("tc")
172/* test that workqueues can be used from a hashmap with NO_PREALLOC. */
173__retval(0)
174long 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
181SEC("tc")
182/* test that workqueues can be used from a LRU map */
183__retval(0)
184long test_call_lru_sleepable(void *ctx)
185{
186 int key = 4;
187
188 return test_elem_callback(&lru, &key, wq_callback);
189}