Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-or-later
2
3/* Basic per-epoll context busy poll test.
4 *
5 * Only tests the ioctls, but should be expanded to test two connected hosts in
6 * the future
7 */
8
9#define _GNU_SOURCE
10
11#include <error.h>
12#include <errno.h>
13#include <inttypes.h>
14#include <limits.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <unistd.h>
19
20#include <sys/capability.h>
21
22#include <sys/epoll.h>
23#include <sys/ioctl.h>
24#include <sys/socket.h>
25
26#include "../kselftest_harness.h"
27
28/* if the headers haven't been updated, we need to define some things */
29#if !defined(EPOLL_IOC_TYPE)
30struct epoll_params {
31 uint32_t busy_poll_usecs;
32 uint16_t busy_poll_budget;
33 uint8_t prefer_busy_poll;
34
35 /* pad the struct to a multiple of 64bits */
36 uint8_t __pad;
37};
38
39#define EPOLL_IOC_TYPE 0x8A
40#define EPIOCSPARAMS _IOW(EPOLL_IOC_TYPE, 0x01, struct epoll_params)
41#define EPIOCGPARAMS _IOR(EPOLL_IOC_TYPE, 0x02, struct epoll_params)
42#endif
43
44FIXTURE(invalid_fd)
45{
46 int invalid_fd;
47 struct epoll_params params;
48};
49
50FIXTURE_SETUP(invalid_fd)
51{
52 int ret;
53
54 ret = socket(AF_UNIX, SOCK_DGRAM, 0);
55 EXPECT_NE(-1, ret)
56 TH_LOG("error creating unix socket");
57
58 self->invalid_fd = ret;
59}
60
61FIXTURE_TEARDOWN(invalid_fd)
62{
63 int ret;
64
65 ret = close(self->invalid_fd);
66 EXPECT_EQ(0, ret);
67}
68
69TEST_F(invalid_fd, test_invalid_fd)
70{
71 int ret;
72
73 ret = ioctl(self->invalid_fd, EPIOCGPARAMS, &self->params);
74
75 EXPECT_EQ(-1, ret)
76 TH_LOG("EPIOCGPARAMS on invalid epoll FD should error");
77
78 EXPECT_EQ(ENOTTY, errno)
79 TH_LOG("EPIOCGPARAMS on invalid epoll FD should set errno to ENOTTY");
80
81 memset(&self->params, 0, sizeof(struct epoll_params));
82
83 ret = ioctl(self->invalid_fd, EPIOCSPARAMS, &self->params);
84
85 EXPECT_EQ(-1, ret)
86 TH_LOG("EPIOCSPARAMS on invalid epoll FD should error");
87
88 EXPECT_EQ(ENOTTY, errno)
89 TH_LOG("EPIOCSPARAMS on invalid epoll FD should set errno to ENOTTY");
90}
91
92FIXTURE(epoll_busy_poll)
93{
94 int fd;
95 struct epoll_params params;
96 struct epoll_params *invalid_params;
97 cap_t caps;
98};
99
100FIXTURE_SETUP(epoll_busy_poll)
101{
102 int ret;
103
104 ret = epoll_create1(0);
105 EXPECT_NE(-1, ret)
106 TH_LOG("epoll_create1 failed?");
107
108 self->fd = ret;
109
110 self->caps = cap_get_proc();
111 EXPECT_NE(NULL, self->caps);
112}
113
114FIXTURE_TEARDOWN(epoll_busy_poll)
115{
116 int ret;
117
118 ret = close(self->fd);
119 EXPECT_EQ(0, ret);
120
121 ret = cap_free(self->caps);
122 EXPECT_NE(-1, ret)
123 TH_LOG("unable to free capabilities");
124}
125
126TEST_F(epoll_busy_poll, test_get_params)
127{
128 /* begin by getting the epoll params from the kernel
129 *
130 * the default should be default and all fields should be zero'd by the
131 * kernel, so set params fields to garbage to test this.
132 */
133 int ret = 0;
134
135 self->params.busy_poll_usecs = 0xff;
136 self->params.busy_poll_budget = 0xff;
137 self->params.prefer_busy_poll = 1;
138 self->params.__pad = 0xf;
139
140 ret = ioctl(self->fd, EPIOCGPARAMS, &self->params);
141 EXPECT_EQ(0, ret)
142 TH_LOG("ioctl EPIOCGPARAMS should succeed");
143
144 EXPECT_EQ(0, self->params.busy_poll_usecs)
145 TH_LOG("EPIOCGPARAMS busy_poll_usecs should have been 0");
146
147 EXPECT_EQ(0, self->params.busy_poll_budget)
148 TH_LOG("EPIOCGPARAMS busy_poll_budget should have been 0");
149
150 EXPECT_EQ(0, self->params.prefer_busy_poll)
151 TH_LOG("EPIOCGPARAMS prefer_busy_poll should have been 0");
152
153 EXPECT_EQ(0, self->params.__pad)
154 TH_LOG("EPIOCGPARAMS __pad should have been 0");
155
156 self->invalid_params = (struct epoll_params *)0xdeadbeef;
157 ret = ioctl(self->fd, EPIOCGPARAMS, self->invalid_params);
158
159 EXPECT_EQ(-1, ret)
160 TH_LOG("EPIOCGPARAMS should error with invalid params");
161
162 EXPECT_EQ(EFAULT, errno)
163 TH_LOG("EPIOCGPARAMS with invalid params should set errno to EFAULT");
164}
165
166TEST_F(epoll_busy_poll, test_set_invalid)
167{
168 int ret;
169
170 memset(&self->params, 0, sizeof(struct epoll_params));
171
172 self->params.__pad = 1;
173
174 ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
175
176 EXPECT_EQ(-1, ret)
177 TH_LOG("EPIOCSPARAMS non-zero __pad should error");
178
179 EXPECT_EQ(EINVAL, errno)
180 TH_LOG("EPIOCSPARAMS non-zero __pad errno should be EINVAL");
181
182 self->params.__pad = 0;
183 self->params.busy_poll_usecs = (uint32_t)INT_MAX + 1;
184
185 ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
186
187 EXPECT_EQ(-1, ret)
188 TH_LOG("EPIOCSPARAMS should error busy_poll_usecs > S32_MAX");
189
190 EXPECT_EQ(EINVAL, errno)
191 TH_LOG("EPIOCSPARAMS busy_poll_usecs > S32_MAX errno should be EINVAL");
192
193 self->params.__pad = 0;
194 self->params.busy_poll_usecs = 32;
195 self->params.prefer_busy_poll = 2;
196
197 ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
198
199 EXPECT_EQ(-1, ret)
200 TH_LOG("EPIOCSPARAMS should error prefer_busy_poll > 1");
201
202 EXPECT_EQ(EINVAL, errno)
203 TH_LOG("EPIOCSPARAMS prefer_busy_poll > 1 errno should be EINVAL");
204
205 self->params.__pad = 0;
206 self->params.busy_poll_usecs = 32;
207 self->params.prefer_busy_poll = 1;
208
209 /* set budget well above kernel's NAPI_POLL_WEIGHT of 64 */
210 self->params.busy_poll_budget = UINT16_MAX;
211
212 /* test harness should run with CAP_NET_ADMIN, but let's make sure */
213 cap_flag_value_t tmp;
214
215 ret = cap_get_flag(self->caps, CAP_NET_ADMIN, CAP_EFFECTIVE, &tmp);
216 EXPECT_EQ(0, ret)
217 TH_LOG("unable to get CAP_NET_ADMIN cap flag");
218
219 EXPECT_EQ(CAP_SET, tmp)
220 TH_LOG("expecting CAP_NET_ADMIN to be set for the test harness");
221
222 /* at this point we know CAP_NET_ADMIN is available, so setting the
223 * params with a busy_poll_budget > NAPI_POLL_WEIGHT should succeed
224 */
225 ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
226
227 EXPECT_EQ(0, ret)
228 TH_LOG("EPIOCSPARAMS should allow busy_poll_budget > NAPI_POLL_WEIGHT");
229
230 /* remove CAP_NET_ADMIN from our effective set */
231 cap_value_t net_admin[] = { CAP_NET_ADMIN };
232
233 ret = cap_set_flag(self->caps, CAP_EFFECTIVE, 1, net_admin, CAP_CLEAR);
234 EXPECT_EQ(0, ret)
235 TH_LOG("couldn't clear CAP_NET_ADMIN");
236
237 ret = cap_set_proc(self->caps);
238 EXPECT_EQ(0, ret)
239 TH_LOG("cap_set_proc should drop CAP_NET_ADMIN");
240
241 /* this is now expected to fail */
242 ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
243
244 EXPECT_EQ(-1, ret)
245 TH_LOG("EPIOCSPARAMS should error busy_poll_budget > NAPI_POLL_WEIGHT");
246
247 EXPECT_EQ(EPERM, errno)
248 TH_LOG("EPIOCSPARAMS errno should be EPERM busy_poll_budget > NAPI_POLL_WEIGHT");
249
250 /* restore CAP_NET_ADMIN to our effective set */
251 ret = cap_set_flag(self->caps, CAP_EFFECTIVE, 1, net_admin, CAP_SET);
252 EXPECT_EQ(0, ret)
253 TH_LOG("couldn't restore CAP_NET_ADMIN");
254
255 ret = cap_set_proc(self->caps);
256 EXPECT_EQ(0, ret)
257 TH_LOG("cap_set_proc should set CAP_NET_ADMIN");
258
259 self->invalid_params = (struct epoll_params *)0xdeadbeef;
260 ret = ioctl(self->fd, EPIOCSPARAMS, self->invalid_params);
261
262 EXPECT_EQ(-1, ret)
263 TH_LOG("EPIOCSPARAMS should error when epoll_params is invalid");
264
265 EXPECT_EQ(EFAULT, errno)
266 TH_LOG("EPIOCSPARAMS should set errno to EFAULT when epoll_params is invalid");
267}
268
269TEST_F(epoll_busy_poll, test_set_and_get_valid)
270{
271 int ret;
272
273 memset(&self->params, 0, sizeof(struct epoll_params));
274
275 self->params.busy_poll_usecs = 25;
276 self->params.busy_poll_budget = 16;
277 self->params.prefer_busy_poll = 1;
278
279 ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
280
281 EXPECT_EQ(0, ret)
282 TH_LOG("EPIOCSPARAMS with valid params should not error");
283
284 /* check that the kernel returns the same values back */
285
286 memset(&self->params, 0, sizeof(struct epoll_params));
287
288 ret = ioctl(self->fd, EPIOCGPARAMS, &self->params);
289
290 EXPECT_EQ(0, ret)
291 TH_LOG("EPIOCGPARAMS should not error");
292
293 EXPECT_EQ(25, self->params.busy_poll_usecs)
294 TH_LOG("params.busy_poll_usecs incorrect");
295
296 EXPECT_EQ(16, self->params.busy_poll_budget)
297 TH_LOG("params.busy_poll_budget incorrect");
298
299 EXPECT_EQ(1, self->params.prefer_busy_poll)
300 TH_LOG("params.prefer_busy_poll incorrect");
301
302 EXPECT_EQ(0, self->params.__pad)
303 TH_LOG("params.__pad was not 0");
304}
305
306TEST_F(epoll_busy_poll, test_invalid_ioctl)
307{
308 int invalid_ioctl = EPIOCGPARAMS + 10;
309 int ret;
310
311 ret = ioctl(self->fd, invalid_ioctl, &self->params);
312
313 EXPECT_EQ(-1, ret)
314 TH_LOG("invalid ioctl should return error");
315
316 EXPECT_EQ(EINVAL, errno)
317 TH_LOG("invalid ioctl should set errno to EINVAL");
318}
319
320TEST_HARNESS_MAIN