1 /*
2 * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org>
3 * Copyright (c) Linux Test Project, 2008-2022
4 *
5 * Based on testcases/kernel/syscalls/waitpid/waitpid01.c
6 * Original copyright message:
7 *
8 * Copyright (c) International Business Machines Corp., 2001
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18 * the GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 /*
26 * NAME
27 * eventfd01.c
28 *
29 * DESCRIPTION
30 * Test cases for eventfd syscall.
31 *
32 * USAGE: <for command-line>
33 * eventfd01 [-c n] [-i n] [-I x] [-P x] [-t]
34 * where, -c n : Run n copies concurrently.
35 * -i n : Execute test n times.
36 * -I x : Execute test for x seconds.
37 * -P x : Pause for x seconds between iterations.
38 *
39 * History
40 * 07/2008 Vijay Kumar
41 * Initial Version.
42 *
43 * Restrictions
44 * None
45 */
46
47 #include "config.h"
48
49 #include <sys/types.h>
50 #include <sys/select.h>
51 #include <sys/wait.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <inttypes.h>
55 #include <poll.h>
56 #include <signal.h>
57 #include <stdint.h>
58 #include <string.h>
59 #include <unistd.h>
60
61 #include "test.h"
62 #define CLEANUP cleanup
63 #include "lapi/syscalls.h"
64
65 TCID_DEFINE(eventfd01);
66 int TST_TOTAL = 15;
67
68 #ifdef HAVE_LIBAIO
69 #include <libaio.h>
70
71 static void setup(void);
72
myeventfd(unsigned int initval,int flags)73 static int myeventfd(unsigned int initval, int flags)
74 {
75 /* eventfd2 uses FLAGS but eventfd doesn't take FLAGS. */
76 return tst_syscall(__NR_eventfd, initval);
77 }
78
79 /*
80 * clear_counter() - clears the counter by performing a dummy read
81 * @fd: the eventfd
82 *
83 * RETURNS:
84 * 0 on success, and -1 on failure
85 */
clear_counter(int fd)86 static int clear_counter(int fd)
87 {
88 uint64_t dummy;
89 int ret;
90
91 ret = read(fd, &dummy, sizeof(dummy));
92 if (ret == -1) {
93 if (errno != EAGAIN) {
94 tst_resm(TINFO | TERRNO, "error clearing counter");
95 return -1;
96 }
97 }
98
99 return 0;
100 }
101
102 /*
103 * set_counter() - sets the count to specified value
104 * @fd: the eventfd
105 * @val: the value to be set
106 *
107 * Clears the counter and sets the counter to @val.
108 *
109 * RETURNS:
110 * 0 on success, -1 on failure
111 */
set_counter(int fd,uint64_t val)112 static int set_counter(int fd, uint64_t val)
113 {
114 int ret;
115
116 ret = clear_counter(fd);
117 if (ret == -1)
118 return -1;
119
120 ret = write(fd, &val, sizeof(val));
121 if (ret == -1) {
122 tst_resm(TINFO | TERRNO, "error setting counter value");
123 return -1;
124 }
125
126 return 0;
127 }
128
129 /*
130 * Test whether the current value of the counter matches @required.
131 */
read_test(int fd,uint64_t required)132 static void read_test(int fd, uint64_t required)
133 {
134 int ret;
135 uint64_t val;
136
137 ret = read(fd, &val, sizeof(val));
138 if (ret == -1) {
139 tst_resm(TBROK | TERRNO, "error reading eventfd");
140 return;
141 }
142
143 if (val == required)
144 tst_resm(TPASS, "counter value matches required");
145 else
146 tst_resm(TFAIL, "counter value mismatch: "
147 "required: %" PRIu64 ", got: %" PRIu64, required, val);
148 }
149
150 /*
151 * Test whether read returns with error EAGAIN when counter is at 0.
152 */
read_eagain_test(int fd)153 static void read_eagain_test(int fd)
154 {
155 int ret;
156 uint64_t val;
157
158 ret = clear_counter(fd);
159 if (ret == -1) {
160 tst_resm(TBROK, "error clearing counter");
161 return;
162 }
163
164 ret = read(fd, &val, sizeof(val));
165 if (ret == -1) {
166 if (errno == EAGAIN)
167 tst_resm(TPASS, "read failed with EAGAIN as expected");
168 else
169 tst_resm(TFAIL | TERRNO, "read failed (wanted EAGAIN)");
170 } else
171 tst_resm(TFAIL, "read returned with %d", ret);
172 }
173
174 /*
175 * Test whether writing to counter works.
176 */
write_test(int fd)177 static void write_test(int fd)
178 {
179 int ret;
180 uint64_t val;
181
182 val = 12;
183
184 ret = set_counter(fd, val);
185 if (ret == -1) {
186 tst_resm(TBROK, "error setting counter value to %" PRIu64, val);
187 return;
188 }
189
190 read_test(fd, val);
191 }
192
193 /*
194 * Test whether write returns with error EAGAIN when counter is at
195 * (UINT64_MAX - 1).
196 */
write_eagain_test(int fd)197 static void write_eagain_test(int fd)
198 {
199 int ret;
200 uint64_t val;
201
202 ret = set_counter(fd, UINT64_MAX - 1);
203 if (ret == -1) {
204 tst_resm(TBROK, "error setting counter value to UINT64_MAX-1");
205 return;
206 }
207
208 val = 1;
209 ret = write(fd, &val, sizeof(val));
210 if (ret == -1) {
211 if (errno == EAGAIN)
212 tst_resm(TPASS, "write failed with EAGAIN as expected");
213 else
214 tst_resm(TFAIL, "write failed (wanted EAGAIN)");
215 } else
216 tst_resm(TFAIL, "write returned with %d", ret);
217 }
218
219 /*
220 * Test whether read returns with error EINVAL, if buffer size is less
221 * than 8 bytes.
222 */
read_einval_test(int fd)223 static void read_einval_test(int fd)
224 {
225 uint32_t invalid;
226 int ret;
227
228 ret = read(fd, &invalid, sizeof(invalid));
229 if (ret == -1) {
230 if (errno == EINVAL)
231 tst_resm(TPASS, "read failed with EINVAL as expected");
232 else
233 tst_resm(TFAIL | TERRNO, "read failed (wanted EINVAL)");
234 } else
235 tst_resm(TFAIL, "read returned with %d", ret);
236 }
237
238 /*
239 * Test whether write returns with error EINVAL, if buffer size is
240 * less than 8 bytes.
241 */
write_einval_test(int fd)242 static void write_einval_test(int fd)
243 {
244 uint32_t invalid;
245 int ret;
246
247 ret = write(fd, &invalid, sizeof(invalid));
248 if (ret == -1) {
249 if (errno == EINVAL)
250 tst_resm(TPASS, "write failed with EINVAL as expected");
251 else
252 tst_resm(TFAIL | TERRNO,
253 "write failed (wanted EINVAL)");
254 } else
255 tst_resm(TFAIL, "write returned with %d", ret);
256 }
257
258 /*
259 * Test wheter write returns with error EINVAL, when the written value
260 * is 0xFFFFFFFFFFFFFFFF.
261 */
write_einval2_test(int fd)262 static void write_einval2_test(int fd)
263 {
264 int ret;
265 uint64_t val;
266
267 ret = clear_counter(fd);
268 if (ret == -1) {
269 tst_resm(TBROK, "error clearing counter");
270 return;
271 }
272
273 val = 0xffffffffffffffffLL;
274 ret = write(fd, &val, sizeof(val));
275 if (ret == -1) {
276 if (errno == EINVAL)
277 tst_resm(TPASS, "write failed with EINVAL as expected");
278 else
279 tst_resm(TFAIL | TERRNO,
280 "write failed (wanted EINVAL)");
281 } else {
282 tst_resm(TFAIL, "write returned with %d", ret);
283 }
284 }
285
286 /*
287 * Test whether readfd is set by select when counter value is
288 * non-zero.
289 */
readfd_set_test(int fd)290 static void readfd_set_test(int fd)
291 {
292 int ret;
293 fd_set readfds;
294 struct timeval timeout = { 0, 0 };
295 uint64_t non_zero = 10;
296
297 FD_ZERO(&readfds);
298 FD_SET(fd, &readfds);
299
300 ret = set_counter(fd, non_zero);
301 if (ret == -1) {
302 tst_resm(TBROK, "error setting counter value to %" PRIu64,
303 non_zero);
304 return;
305 }
306
307 ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
308 if (ret == -1) {
309 /* EINTR cannot occur, since we don't block. */
310 tst_resm(TBROK | TERRNO, "select() failed");
311 return;
312 }
313
314 if (FD_ISSET(fd, &readfds))
315 tst_resm(TPASS, "fd is set in readfds");
316 else
317 tst_resm(TFAIL, "fd is not set in readfds");
318 }
319
320 /*
321 * Test whether readfd is not set by select when counter value is
322 * zero.
323 */
readfd_not_set_test(int fd)324 static void readfd_not_set_test(int fd)
325 {
326 int ret;
327 fd_set readfds;
328 struct timeval timeout = { 0, 0 };
329
330 FD_ZERO(&readfds);
331 FD_SET(fd, &readfds);
332
333 ret = clear_counter(fd);
334 if (ret == -1) {
335 tst_resm(TBROK, "error clearing counter");
336 return;
337 }
338
339 ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
340 if (ret == -1) {
341 /* EINTR cannot occur, since we don't block. */
342 tst_resm(TBROK | TERRNO, "select() failed");
343 return;
344 }
345
346 if (!FD_ISSET(fd, &readfds))
347 tst_resm(TPASS, "fd is not set in readfds");
348 else
349 tst_resm(TFAIL, "fd is set in readfds");
350 }
351
352 /*
353 * Test whether writefd is set by select when counter value is not the
354 * maximum counter value.
355 */
writefd_set_test(int fd)356 static void writefd_set_test(int fd)
357 {
358 int ret;
359 fd_set writefds;
360 struct timeval timeout = { 0, 0 };
361 uint64_t non_max = 10;
362
363 FD_ZERO(&writefds);
364 FD_SET(fd, &writefds);
365
366 ret = set_counter(fd, non_max);
367 if (ret == -1) {
368 tst_resm(TBROK, "error setting counter value to %" PRIu64,
369 non_max);
370 return;
371 }
372
373 ret = select(fd + 1, NULL, &writefds, NULL, &timeout);
374 if (ret == -1) {
375 /* EINTR cannot occur, since we don't block. */
376 tst_resm(TBROK | TERRNO, "select: error getting fd status");
377 return;
378 }
379
380 if (FD_ISSET(fd, &writefds))
381 tst_resm(TPASS, "fd is set in writefds");
382 else
383 tst_resm(TFAIL, "fd is not set in writefds");
384 }
385
386 /*
387 * Test whether writefd is not set by select when counter value is at
388 * (UINT64_MAX - 1).
389 */
writefd_not_set_test(int fd)390 static void writefd_not_set_test(int fd)
391 {
392 int ret;
393 fd_set writefds;
394 struct timeval timeout = { 0, 0 };
395
396 FD_ZERO(&writefds);
397 FD_SET(fd, &writefds);
398
399 ret = set_counter(fd, UINT64_MAX - 1);
400 if (ret == -1) {
401 tst_resm(TBROK, "error setting counter value to UINT64_MAX-1");
402 return;
403 }
404
405 ret = select(fd + 1, NULL, &writefds, NULL, &timeout);
406 if (ret == -1) {
407 /* EINTR cannot occur, since we don't block. */
408 tst_resm(TBROK | TERRNO, "select: error getting fd status");
409 return;
410 }
411
412 if (!FD_ISSET(fd, &writefds))
413 tst_resm(TPASS, "fd is not set in writefds");
414 else
415 tst_resm(TFAIL, "fd is set in writefds");
416 }
417
418 /*
419 * Test whether counter update in child is reflected in the parent.
420 */
child_inherit_test(int fd)421 static void child_inherit_test(int fd)
422 {
423 uint64_t val;
424 pid_t cpid;
425 int ret;
426 int status;
427 uint64_t to_parent = 0xdeadbeef;
428 uint64_t dummy;
429
430 cpid = fork();
431 if (cpid == -1)
432 tst_resm(TBROK | TERRNO, "fork failed");
433 else if (cpid != 0) {
434 ret = wait(&status);
435 if (ret == -1) {
436 tst_resm(TBROK, "error getting child exit status");
437 return;
438 }
439
440 if (WEXITSTATUS(status) == 1) {
441 tst_resm(TBROK, "counter value write not "
442 "successful in child");
443 return;
444 }
445
446 ret = read(fd, &val, sizeof(val));
447 if (ret == -1) {
448 tst_resm(TBROK | TERRNO, "error reading eventfd");
449 return;
450 }
451
452 if (val == to_parent)
453 tst_resm(TPASS, "counter value write from "
454 "child successful");
455 else
456 tst_resm(TFAIL, "counter value write in child "
457 "failed");
458 } else {
459 /* Child */
460 ret = read(fd, &dummy, sizeof(dummy));
461 if (ret == -1 && errno != EAGAIN) {
462 tst_resm(TWARN | TERRNO, "error clearing counter");
463 exit(1);
464 }
465
466 ret = write(fd, &to_parent, sizeof(to_parent));
467 if (ret == -1) {
468 tst_resm(TWARN | TERRNO, "error writing eventfd");
469 exit(1);
470 }
471
472 exit(0);
473 }
474 }
475
476 #ifdef HAVE_IO_SET_EVENTFD
477 /*
478 * Test whether counter overflow is detected and handled correctly.
479 *
480 * It is not possible to directly overflow the counter using the
481 * write() syscall. Overflows occur when the counter is incremented
482 * from kernel space, in an irq context, when it is not possible to
483 * block the calling thread of execution.
484 *
485 * The AIO subsystem internally uses eventfd mechanism for
486 * notification of completion of read or write requests. In this test
487 * we trigger a counter overflow, by setting the counter value to the
488 * max possible value initially. When the AIO subsystem notifies
489 * through the eventfd counter, the counter overflows.
490 *
491 * NOTE: If the the counter starts from an initial value of 0, it will
492 * take decades for an overflow to occur. But since we set the initial
493 * value to the max possible counter value, we are able to cause it to
494 * overflow with a single increment.
495 *
496 * When the counter overflows, the following are tested
497 * 1. Check whether POLLERR event occurs in poll() for the eventfd.
498 * 2. Check whether readfd_set/writefd_set is set in select() for the
499 eventfd.
500 * 3. The counter value is UINT64_MAX.
501 */
trigger_eventfd_overflow(int evfd,int * fd,io_context_t * ctx)502 static int trigger_eventfd_overflow(int evfd, int *fd, io_context_t * ctx)
503 {
504 int ret;
505 struct iocb iocb;
506 struct iocb *iocbap[1];
507 struct io_event ioev;
508 static char buf[4 * 1024];
509
510 *ctx = 0;
511 ret = io_setup(16, ctx);
512 if (ret < 0) {
513 errno = -ret;
514 if (errno == ENOSYS) {
515 tst_brkm(TCONF | TERRNO, cleanup,
516 "io_setup(): AIO not supported by kernel");
517 }
518
519 tst_resm(TINFO | TERRNO, "io_setup error");
520 return -1;
521 }
522
523 *fd = open("testfile", O_RDWR | O_CREAT, 0644);
524 if (*fd == -1) {
525 tst_resm(TINFO | TERRNO, "open(testfile) failed");
526 goto err_io_destroy;
527 }
528
529 ret = set_counter(evfd, UINT64_MAX - 1);
530 if (ret == -1) {
531 tst_resm(TINFO, "error setting counter to UINT64_MAX-1");
532 goto err_close_file;
533 }
534
535 io_prep_pwrite(&iocb, *fd, buf, sizeof(buf), 0);
536 io_set_eventfd(&iocb, evfd);
537
538 iocbap[0] = &iocb;
539 ret = io_submit(*ctx, 1, iocbap);
540 if (ret < 0) {
541 errno = -ret;
542 tst_resm(TINFO | TERRNO, "error submitting iocb");
543 goto err_close_file;
544 }
545
546 ret = io_getevents(*ctx, 1, 1, &ioev, NULL);
547 if (ret < 0) {
548 errno = -ret;
549 tst_resm(TINFO | TERRNO, "error waiting for event");
550 goto err_close_file;
551 }
552
553 return 0;
554
555 err_close_file:
556 close(*fd);
557
558 err_io_destroy:
559 io_destroy(*ctx);
560
561 return -1;
562 }
563
cleanup_overflow(int fd,io_context_t ctx)564 static void cleanup_overflow(int fd, io_context_t ctx)
565 {
566 close(fd);
567 io_destroy(ctx);
568 }
569
overflow_select_test(int evfd)570 static void overflow_select_test(int evfd)
571 {
572 struct timeval timeout = { 10, 0 };
573 fd_set readfds;
574 int fd;
575 io_context_t ctx;
576 int ret;
577
578 ret = trigger_eventfd_overflow(evfd, &fd, &ctx);
579 if (ret == -1) {
580 tst_resm(TBROK, "error triggering eventfd overflow");
581 return;
582 }
583
584 FD_ZERO(&readfds);
585 FD_SET(evfd, &readfds);
586 ret = select(evfd + 1, &readfds, NULL, NULL, &timeout);
587 if (ret == -1)
588 tst_resm(TBROK | TERRNO,
589 "error getting evfd status with select");
590 else {
591 if (FD_ISSET(evfd, &readfds))
592 tst_resm(TPASS, "read fd set as expected");
593 else
594 tst_resm(TFAIL, "read fd not set");
595 }
596 cleanup_overflow(fd, ctx);
597 }
598
overflow_poll_test(int evfd)599 static void overflow_poll_test(int evfd)
600 {
601 struct pollfd pollfd;
602 int fd;
603 io_context_t ctx;
604 int ret;
605
606 ret = trigger_eventfd_overflow(evfd, &fd, &ctx);
607 if (ret == -1) {
608 tst_resm(TBROK, "error triggering eventfd overflow");
609 return;
610 }
611
612 pollfd.fd = evfd;
613 pollfd.events = POLLIN;
614 pollfd.revents = 0;
615 ret = poll(&pollfd, 1, 10000);
616 if (ret == -1)
617 tst_resm(TBROK | TERRNO, "error getting evfd status with poll");
618 else {
619 if (pollfd.revents & POLLERR)
620 tst_resm(TPASS, "POLLERR occurred as expected");
621 else
622 tst_resm(TFAIL, "POLLERR did not occur");
623 }
624 cleanup_overflow(fd, ctx);
625 }
626
overflow_read_test(int evfd)627 static void overflow_read_test(int evfd)
628 {
629 uint64_t count;
630 io_context_t ctx;
631 int fd;
632 int ret;
633
634 ret = trigger_eventfd_overflow(evfd, &fd, &ctx);
635 if (ret == -1) {
636 tst_resm(TBROK, "error triggering eventfd overflow");
637 return;
638 }
639
640 ret = read(evfd, &count, sizeof(count));
641 if (ret == -1)
642 tst_resm(TBROK | TERRNO, "error reading eventfd");
643 else {
644
645 if (count == UINT64_MAX)
646 tst_resm(TPASS, "overflow occurred as expected");
647 else
648 tst_resm(TFAIL, "overflow did not occur");
649 }
650 cleanup_overflow(fd, ctx);
651 }
652 #else
overflow_select_test(int evfd)653 static void overflow_select_test(int evfd)
654 {
655 tst_resm(TCONF, "eventfd support is not available in AIO subsystem");
656 }
657
overflow_poll_test(int evfd)658 static void overflow_poll_test(int evfd)
659 {
660 tst_resm(TCONF, "eventfd support is not available in AIO subsystem");
661 }
662
overflow_read_test(int evfd)663 static void overflow_read_test(int evfd)
664 {
665 tst_resm(TCONF, "eventfd support is not available in AIO subsystem");
666 }
667 #endif
668
main(int argc,char ** argv)669 int main(int argc, char **argv)
670 {
671 int lc;
672 int fd;
673
674 tst_parse_opts(argc, argv, NULL, NULL);
675
676 setup();
677
678 for (lc = 0; TEST_LOOPING(lc); lc++) {
679 int ret;
680 uint64_t einit = 10;
681
682 tst_count = 0;
683
684 fd = myeventfd(einit, 0);
685 if (fd == -1)
686 tst_brkm(TBROK | TERRNO, CLEANUP,
687 "error creating eventfd");
688
689 ret = fcntl(fd, F_SETFL, O_NONBLOCK);
690 if (ret == -1)
691 tst_brkm(TBROK | TERRNO, CLEANUP,
692 "error setting non-block mode");
693
694 read_test(fd, einit);
695 read_eagain_test(fd);
696 write_test(fd);
697 write_eagain_test(fd);
698 read_einval_test(fd);
699 write_einval_test(fd);
700 write_einval2_test(fd);
701 readfd_set_test(fd);
702 readfd_not_set_test(fd);
703 writefd_set_test(fd);
704 writefd_not_set_test(fd);
705 child_inherit_test(fd);
706 overflow_select_test(fd);
707 overflow_poll_test(fd);
708 overflow_read_test(fd);
709
710 close(fd);
711 }
712
713 cleanup();
714
715 tst_exit();
716 }
717
setup(void)718 static void setup(void)
719 {
720
721 tst_sig(FORK, DEF_HANDLER, cleanup);
722
723 tst_tmpdir();
724
725 TEST_PAUSE;
726 }
727
cleanup(void)728 static void cleanup(void)
729 {
730 tst_rmdir();
731 }
732
733 #else
main(void)734 int main(void)
735 {
736 tst_brkm(TCONF, NULL, "test requires libaio and it's development packages");
737 }
738 #endif
739