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