• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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