xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/eventfd/eventfd06.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) International Business Machines  Corp., 2001
4  * Copyright (c) 2008 Vijay Kumar B. <[email protected]>
5  * Copyright (c) Linux Test Project, 2008-2022
6  * Copyright (C) 2023 SUSE LLC Andrea Cervesato <[email protected]>
7  */
8 
9 /*\
10  * [Description]
11  *
12  * Test whether counter overflow is detected and handled correctly.
13  *
14  * It is not possible to directly overflow the counter using the
15  * write() syscall. Overflows occur when the counter is incremented
16  * from kernel space, in an IRQ context, when it is not possible to
17  * block the calling thread of execution.
18  *
19  * The AIO subsystem internally uses eventfd mechanism for
20  * notification of completion of read or write requests. In this test
21  * we trigger a counter overflow, by setting the counter value to the
22  * max possible value initially. When the AIO subsystem notifies
23  * through the eventfd counter, the counter overflows.
24  *
25  * If the counter starts from an initial value of 0, it will
26  * take decades for an overflow to occur. But since we set the initial
27  * value to the max possible counter value, we are able to cause it to
28  * overflow with a single increment.
29  *
30  * When the counter overflows, the following is tested:
31  *
32  * - POLLERR event occurs in poll() for the eventfd
33  * - readfd_set/writefd_set is set in select() for the eventfd
34  * - the counter value is UINT64_MAX
35  */
36 
37 #include "tst_test.h"
38 
39 #ifdef HAVE_LIBAIO
40 #ifdef HAVE_IO_SET_EVENTFD
41 
42 #include <poll.h>
43 #include <libaio.h>
44 #include <stdlib.h>
45 #include <sys/eventfd.h>
46 
47 #define MAXEVENTS 16
48 #define BUFSIZE 1024
49 
50 static int fd;
51 static int evfd;
52 static io_context_t ctx;
53 
async_write(void)54 static void async_write(void)
55 {
56 	struct iocb iocb;
57 	struct iocb *iocbap[1];
58 	struct io_event ioev;
59 	static char buf[BUFSIZE];
60 
61 	memset(buf, 1, BUFSIZE);
62 
63 	io_prep_pwrite(&iocb, fd, buf, sizeof(buf), 0);
64 	io_set_eventfd(&iocb, evfd);
65 
66 	iocbap[0] = &iocb;
67 	TEST(io_submit(ctx, 1, iocbap));
68 	if (TST_RET < 0)
69 		tst_brk(TBROK, "io_submit() failed: %s", tst_strerrno(-TST_RET));
70 
71 	TEST(io_getevents(ctx, 1, 1, &ioev, NULL));
72 	if (TST_RET < 0)
73 		tst_brk(TBROK, "io_getevents() failed: %s", tst_strerrno(-TST_RET));
74 }
75 
clear_counter(void)76 static void clear_counter(void)
77 {
78 	uint64_t val;
79 	uint64_t max =  UINT64_MAX - 1;
80 
81 	TEST(read(evfd, &val, sizeof(val)));
82 	if (TST_RET == -1 && TST_ERR != EAGAIN)
83 		tst_brk(TBROK | TERRNO, "read");
84 
85 	SAFE_WRITE(0, evfd, &max, sizeof(max));
86 }
87 
test_select(void)88 static void test_select(void)
89 {
90 	fd_set readfds;
91 	uint64_t count;
92 	struct timeval timeout = { 10, 0 };
93 
94 	clear_counter();
95 	async_write();
96 
97 	FD_ZERO(&readfds);
98 	FD_SET(fd, &readfds);
99 
100 	tst_res(TINFO, "Checking if select() detects counter overflow");
101 
102 	TEST(select(fd + 1, NULL, &readfds, NULL, &timeout));
103 	if (TST_RET == -1)
104 		tst_brk(TBROK | TERRNO, "select");
105 
106 	TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 1);
107 
108 	SAFE_READ(0, evfd, &count, sizeof(count));
109 	TST_EXP_EQ_LI(count, UINT64_MAX);
110 }
111 
test_poll(void)112 static void test_poll(void)
113 {
114 	uint64_t count;
115 	struct pollfd pollfd;
116 
117 	clear_counter();
118 	async_write();
119 
120 	pollfd.fd = evfd;
121 	pollfd.events = POLLIN;
122 	pollfd.revents = 0;
123 
124 	tst_res(TINFO, "Checking if poll() detects counter overflow");
125 
126 	TEST(poll(&pollfd, 1, 10000));
127 	if (TST_RET == -1)
128 		tst_brk(TBROK | TERRNO, "poll");
129 
130 	TST_EXP_EQ_LI(pollfd.revents & POLLERR, POLLERR);
131 
132 	SAFE_READ(0, evfd, &count, sizeof(count));
133 	TST_EXP_EQ_LI(count, UINT64_MAX);
134 }
135 
setup(void)136 static void setup(void)
137 {
138 	TEST(io_setup(MAXEVENTS, &ctx));
139 	if (TST_RET < 0)
140 		tst_brk(TBROK, "io_setup() failed: %s", tst_strerrno(-TST_RET));
141 
142 	fd = SAFE_OPEN("testfile", O_RDWR | O_CREAT, 0644);
143 	evfd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK));
144 }
145 
cleanup(void)146 static void cleanup(void)
147 {
148 	SAFE_CLOSE(evfd);
149 	io_destroy(ctx);
150 }
151 
run(void)152 static void run(void)
153 {
154 	test_select();
155 	test_poll();
156 }
157 
158 static struct tst_test test = {
159 	.test_all = run,
160 	.setup = setup,
161 	.cleanup = cleanup,
162 	.needs_tmpdir = 1,
163 	.needs_kconfigs = (const char *[]) {
164 		"CONFIG_EVENTFD",
165 		NULL
166 	},
167 };
168 
169 #else /* HAVE_IO_SET_EVENTFD */
170 TST_TEST_TCONF("eventfd support is not available in AIO subsystem");
171 #endif
172 #else /* HAVE_LIBAIO */
173 TST_TEST_TCONF("libaio is not available");
174 #endif
175