1 // SPDX-License-Identifier: GPL-2.0
3 * User Events ABI Test Program
5 * Copyright (c) 2022 Beau Belgrave <beaub@linux.microsoft.com>
12 #include <linux/user_events.h>
16 #include <sys/ioctl.h>
21 #include <asm/unistd.h>
23 #include "../kselftest_harness.h"
24 #include "user_events_selftests.h"
26 const char *data_file
= "/sys/kernel/tracing/user_events_data";
27 const char *enable_file
= "/sys/kernel/tracing/events/user_events/__abi_event/enable";
28 const char *multi_dir_glob
= "/sys/kernel/tracing/events/user_events_multi/__abi_event.*";
30 static int wait_for_delete(char *dir
)
35 for (i
= 0; i
< 10000; ++i
) {
36 if (stat(dir
, &buf
) == -1 && errno
== ENOENT
)
45 static int find_multi_event_dir(char *unique_field
, char *out_dir
, int dir_len
)
51 ret
= glob(multi_dir_glob
, GLOB_ONLYDIR
, NULL
, &buf
);
58 for (i
= 0; i
< buf
.gl_pathc
; ++i
) {
61 snprintf(path
, sizeof(path
), "%s/format", buf
.gl_pathv
[i
]);
62 fp
= fopen(path
, "r");
67 while (fgets(path
, sizeof(path
), fp
) != NULL
) {
68 if (strstr(path
, unique_field
)) {
70 /* strscpy is not available, use snprintf */
71 snprintf(out_dir
, dir_len
, "%s", buf
.gl_pathv
[i
]);
85 static bool event_exists(void)
87 int fd
= open(enable_file
, O_RDWR
);
97 static int change_event(bool enable
)
99 int fd
= open(enable_file
, O_RDWR
);
106 ret
= write(fd
, "1", 1);
108 ret
= write(fd
, "0", 1);
120 static int event_delete(void)
122 int fd
= open(data_file
, O_RDWR
);
128 ret
= ioctl(fd
, DIAG_IOCSDEL
, "__abi_event");
135 static int reg_enable_multi(void *enable
, int size
, int bit
, int flags
,
138 struct user_reg reg
= {0};
139 char full_args
[512] = {0};
140 int fd
= open(data_file
, O_RDWR
);
147 len
= snprintf(full_args
, sizeof(full_args
), "__abi_event %s", args
);
149 if (len
> sizeof(full_args
)) {
154 reg
.size
= sizeof(reg
);
155 reg
.name_args
= (__u64
)full_args
;
156 reg
.flags
= USER_EVENT_REG_MULTI_FORMAT
| flags
;
157 reg
.enable_bit
= bit
;
158 reg
.enable_addr
= (__u64
)enable
;
159 reg
.enable_size
= size
;
161 ret
= ioctl(fd
, DIAG_IOCSREG
, ®
);
168 static int reg_enable_flags(void *enable
, int size
, int bit
, int flags
)
170 struct user_reg reg
= {0};
171 int fd
= open(data_file
, O_RDWR
);
177 reg
.size
= sizeof(reg
);
178 reg
.name_args
= (__u64
)"__abi_event";
180 reg
.enable_bit
= bit
;
181 reg
.enable_addr
= (__u64
)enable
;
182 reg
.enable_size
= size
;
184 ret
= ioctl(fd
, DIAG_IOCSREG
, ®
);
191 static int reg_enable(void *enable
, int size
, int bit
)
193 return reg_enable_flags(enable
, size
, bit
, 0);
196 static int reg_disable(void *enable
, int bit
)
198 struct user_unreg reg
= {0};
199 int fd
= open(data_file
, O_RDWR
);
205 reg
.size
= sizeof(reg
);
206 reg
.disable_bit
= bit
;
207 reg
.disable_addr
= (__u64
)enable
;
209 ret
= ioctl(fd
, DIAG_IOCSUNREG
, ®
);
222 FIXTURE_SETUP(user
) {
223 USER_EVENT_FIXTURE_SETUP(return, self
->umount
);
227 self
->check_long
= 0;
230 FIXTURE_TEARDOWN(user
) {
231 USER_EVENT_FIXTURE_TEARDOWN(self
->umount
);
234 TEST_F(user
, enablement
) {
235 /* Changes should be reflected immediately */
236 ASSERT_EQ(0, self
->check
);
237 ASSERT_EQ(0, reg_enable(&self
->check
, sizeof(int), 0));
238 ASSERT_EQ(0, change_event(true));
239 ASSERT_EQ(1, self
->check
);
240 ASSERT_EQ(0, change_event(false));
241 ASSERT_EQ(0, self
->check
);
243 /* Ensure kernel clears bit after disable */
244 ASSERT_EQ(0, change_event(true));
245 ASSERT_EQ(1, self
->check
);
246 ASSERT_EQ(0, reg_disable(&self
->check
, 0));
247 ASSERT_EQ(0, self
->check
);
249 /* Ensure doesn't change after unreg */
250 ASSERT_EQ(0, change_event(true));
251 ASSERT_EQ(0, self
->check
);
252 ASSERT_EQ(0, change_event(false));
255 TEST_F(user
, flags
) {
256 /* USER_EVENT_REG_PERSIST is allowed */
257 ASSERT_EQ(0, reg_enable_flags(&self
->check
, sizeof(int), 0,
258 USER_EVENT_REG_PERSIST
));
259 ASSERT_EQ(0, reg_disable(&self
->check
, 0));
261 /* Ensure it exists after close and disable */
262 ASSERT_TRUE(event_exists());
264 /* Ensure we can delete it */
265 ASSERT_EQ(0, event_delete());
267 /* USER_EVENT_REG_MAX or above is not allowed */
268 ASSERT_EQ(-1, reg_enable_flags(&self
->check
, sizeof(int), 0,
269 USER_EVENT_REG_MAX
));
271 /* Ensure it does not exist after invalid flags */
272 ASSERT_FALSE(event_exists());
275 TEST_F(user
, bit_sizes
) {
276 /* Allow 0-31 bits for 32-bit */
277 ASSERT_EQ(0, reg_enable(&self
->check
, sizeof(int), 0));
278 ASSERT_EQ(0, reg_enable(&self
->check
, sizeof(int), 31));
279 ASSERT_NE(0, reg_enable(&self
->check
, sizeof(int), 32));
280 ASSERT_EQ(0, reg_disable(&self
->check
, 0));
281 ASSERT_EQ(0, reg_disable(&self
->check
, 31));
283 #if BITS_PER_LONG == 8
284 /* Allow 0-64 bits for 64-bit */
285 ASSERT_EQ(0, reg_enable(&self
->check_long
, sizeof(long), 63));
286 ASSERT_NE(0, reg_enable(&self
->check_long
, sizeof(long), 64));
287 ASSERT_EQ(0, reg_disable(&self
->check_long
, 63));
290 /* Disallowed sizes (everything beside 4 and 8) */
291 ASSERT_NE(0, reg_enable(&self
->check
, 1, 0));
292 ASSERT_NE(0, reg_enable(&self
->check
, 2, 0));
293 ASSERT_NE(0, reg_enable(&self
->check
, 3, 0));
294 ASSERT_NE(0, reg_enable(&self
->check
, 5, 0));
295 ASSERT_NE(0, reg_enable(&self
->check
, 6, 0));
296 ASSERT_NE(0, reg_enable(&self
->check
, 7, 0));
297 ASSERT_NE(0, reg_enable(&self
->check
, 9, 0));
298 ASSERT_NE(0, reg_enable(&self
->check
, 128, 0));
301 TEST_F(user
, multi_format
) {
303 char second_dir
[256];
306 /* Multiple formats for the same name should work */
307 ASSERT_EQ(0, reg_enable_multi(&self
->check
, sizeof(int), 0,
308 0, "u32 multi_first"));
310 ASSERT_EQ(0, reg_enable_multi(&self
->check
, sizeof(int), 1,
311 0, "u64 multi_second"));
313 /* Same name with same format should also work */
314 ASSERT_EQ(0, reg_enable_multi(&self
->check
, sizeof(int), 2,
315 0, "u64 multi_second"));
317 ASSERT_EQ(0, find_multi_event_dir("multi_first",
318 first_dir
, sizeof(first_dir
)));
320 ASSERT_EQ(0, find_multi_event_dir("multi_second",
321 second_dir
, sizeof(second_dir
)));
323 /* Should not be found in the same dir */
324 ASSERT_NE(0, strcmp(first_dir
, second_dir
));
326 /* First dir should still exist */
327 ASSERT_EQ(0, stat(first_dir
, &buf
));
329 /* Disabling first register should remove first dir */
330 ASSERT_EQ(0, reg_disable(&self
->check
, 0));
331 ASSERT_EQ(0, wait_for_delete(first_dir
));
333 /* Second dir should still exist */
334 ASSERT_EQ(0, stat(second_dir
, &buf
));
336 /* Disabling second register should remove second dir */
337 ASSERT_EQ(0, reg_disable(&self
->check
, 1));
338 /* Ensure bit 1 and 2 are tied together, should not delete yet */
339 ASSERT_EQ(0, stat(second_dir
, &buf
));
340 ASSERT_EQ(0, reg_disable(&self
->check
, 2));
341 ASSERT_EQ(0, wait_for_delete(second_dir
));
344 TEST_F(user
, forks
) {
347 /* Ensure COW pages get updated after fork */
348 ASSERT_EQ(0, reg_enable(&self
->check
, sizeof(int), 0));
349 ASSERT_EQ(0, self
->check
);
355 /* Up to 1 sec for enablement */
356 for (i
= 0; i
< 10; ++i
) {
366 /* Allow generous time for COW, then enable */
368 ASSERT_EQ(0, change_event(true));
370 ASSERT_NE(-1, wait(&i
));
371 ASSERT_EQ(0, WEXITSTATUS(i
));
373 /* Ensure child doesn't disable parent */
375 exit(reg_disable(&self
->check
, 0));
377 ASSERT_NE(-1, wait(&i
));
378 ASSERT_EQ(0, WEXITSTATUS(i
));
379 ASSERT_EQ(1, self
->check
);
380 ASSERT_EQ(0, change_event(false));
381 ASSERT_EQ(0, self
->check
);
384 /* Waits up to 1 sec for enablement */
385 static int clone_check(void *check
)
389 for (i
= 0; i
< 10; ++i
) {
399 TEST_F(user
, clones
) {
400 int i
, stack_size
= 4096;
401 void *stack
= mmap(NULL
, stack_size
, PROT_READ
| PROT_WRITE
,
402 MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_STACK
,
405 ASSERT_NE(MAP_FAILED
, stack
);
406 ASSERT_EQ(0, reg_enable(&self
->check
, sizeof(int), 0));
407 ASSERT_EQ(0, self
->check
);
409 /* Shared VM should see enablements */
410 ASSERT_NE(-1, clone(&clone_check
, stack
+ stack_size
,
411 CLONE_VM
| SIGCHLD
, &self
->check
));
413 ASSERT_EQ(0, change_event(true));
414 ASSERT_NE(-1, wait(&i
));
415 ASSERT_EQ(0, WEXITSTATUS(i
));
416 munmap(stack
, stack_size
);
417 ASSERT_EQ(0, change_event(false));
420 int main(int argc
, char **argv
)
422 return test_harness_run(argc
, argv
);