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