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 "linux_syscall_numbers.h"
63
64#ifdef HAVE_LIBAIO_H
65#include <libaio.h>
66#endif
67
68static void setup(void);
69
70TCID_DEFINE(eventfd01);
71int TST_TOTAL = 15;
72
73static int myeventfd(unsigned int initval, int flags)
74{
75	/* eventfd2 uses FLAGS but eventfd doesn't take FLAGS. */
76	return ltp_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 */
86static 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 */
112static 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 */
132static 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 */
153static 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 */
177static 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 */
197static 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 */
223static 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 */
242static 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 */
262static 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 */
290static 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 */
324static 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 */
356static 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 */
390static 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 */
421static 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 */
502static 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	static char buf[4 * 1024];
508
509	*ctx = 0;
510	ret = io_setup(16, ctx);
511	if (ret < 0) {
512		errno = -ret;
513		tst_resm(TINFO | TERRNO, "io_setup error");
514		return -1;
515	}
516
517	*fd = open("testfile", O_RDWR | O_CREAT, 0644);
518	if (*fd == -1) {
519		tst_resm(TINFO | TERRNO, "open(testfile) failed");
520		goto err_io_destroy;
521	}
522
523	ret = set_counter(evfd, UINT64_MAX - 1);
524	if (ret == -1) {
525		tst_resm(TINFO, "error setting counter to UINT64_MAX-1");
526		goto err_close_file;
527	}
528
529	io_prep_pwrite(&iocb, *fd, buf, sizeof(buf), 0);
530	io_set_eventfd(&iocb, evfd);
531
532	iocbap[0] = &iocb;
533	ret = io_submit(*ctx, 1, iocbap);
534	if (ret < 0) {
535		errno = -ret;
536		tst_resm(TINFO | TERRNO, "error submitting iocb");
537		goto err_close_file;
538	}
539
540	return 0;
541
542err_close_file:
543	close(*fd);
544
545err_io_destroy:
546	io_destroy(*ctx);
547
548	return -1;
549}
550
551static void cleanup_overflow(int fd, io_context_t ctx)
552{
553	close(fd);
554	io_destroy(ctx);
555}
556
557static void overflow_select_test(int evfd)
558{
559	struct timeval timeout = { 10, 0 };
560	fd_set readfds;
561	int fd;
562	io_context_t ctx;
563	int ret;
564
565	ret = trigger_eventfd_overflow(evfd, &fd, &ctx);
566	if (ret == -1) {
567		tst_resm(TBROK, "error triggering eventfd overflow");
568		return;
569	}
570
571	FD_ZERO(&readfds);
572	FD_SET(evfd, &readfds);
573	ret = select(evfd + 1, &readfds, NULL, NULL, &timeout);
574	if (ret == -1)
575		tst_resm(TBROK | TERRNO,
576			 "error getting evfd status with select");
577	else {
578		if (FD_ISSET(evfd, &readfds))
579			tst_resm(TPASS, "read fd set as expected");
580		else
581			tst_resm(TFAIL, "read fd not set");
582	}
583	cleanup_overflow(fd, ctx);
584}
585
586static void overflow_poll_test(int evfd)
587{
588	struct pollfd pollfd;
589	int fd;
590	io_context_t ctx;
591	int ret;
592
593	ret = trigger_eventfd_overflow(evfd, &fd, &ctx);
594	if (ret == -1) {
595		tst_resm(TBROK, "error triggering eventfd overflow");
596		return;
597	}
598
599	pollfd.fd = evfd;
600	pollfd.events = POLLIN;
601	pollfd.revents = 0;
602	ret = poll(&pollfd, 1, 10000);
603	if (ret == -1)
604		tst_resm(TBROK | TERRNO, "error getting evfd status with poll");
605	else {
606		if (pollfd.revents & POLLERR)
607			tst_resm(TPASS, "POLLERR occurred as expected");
608		else
609			tst_resm(TFAIL, "POLLERR did not occur");
610	}
611	cleanup_overflow(fd, ctx);
612}
613
614static void overflow_read_test(int evfd)
615{
616	uint64_t count;
617	io_context_t ctx;
618	int fd;
619	int ret;
620
621	ret = trigger_eventfd_overflow(evfd, &fd, &ctx);
622	if (ret == -1) {
623		tst_resm(TBROK, "error triggering eventfd overflow");
624		return;
625	}
626
627	ret = read(evfd, &count, sizeof(count));
628	if (ret == -1)
629		tst_resm(TBROK | TERRNO, "error reading eventfd");
630	else {
631
632		if (count == UINT64_MAX)
633			tst_resm(TPASS, "overflow occurred as expected");
634		else
635			tst_resm(TFAIL, "overflow did not occur");
636	}
637	cleanup_overflow(fd, ctx);
638}
639#else
640static void overflow_select_test(int evfd)
641{
642	tst_resm(TCONF, "eventfd support is not available in AIO subsystem");
643}
644
645static void overflow_poll_test(int evfd)
646{
647	tst_resm(TCONF, "eventfd support is not available in AIO subsystem");
648}
649
650static void overflow_read_test(int evfd)
651{
652	tst_resm(TCONF, "eventfd support is not available in AIO subsystem");
653}
654#endif
655
656int main(int argc, char **argv)
657{
658	int lc;
659	int fd;
660
661	tst_parse_opts(argc, argv, NULL, NULL);
662
663	setup();
664
665	for (lc = 0; TEST_LOOPING(lc); lc++) {
666		int ret;
667		uint64_t einit = 10;
668
669		tst_count = 0;
670
671		fd = myeventfd(einit, 0);
672		if (fd == -1)
673			tst_brkm(TBROK | TERRNO, CLEANUP,
674				 "error creating eventfd");
675
676		ret = fcntl(fd, F_SETFL, O_NONBLOCK);
677		if (ret == -1)
678			tst_brkm(TBROK | TERRNO, CLEANUP,
679				 "error setting non-block mode");
680
681		read_test(fd, einit);
682		read_eagain_test(fd);
683		write_test(fd);
684		write_eagain_test(fd);
685		read_einval_test(fd);
686		write_einval_test(fd);
687		write_einval2_test(fd);
688		readfd_set_test(fd);
689		readfd_not_set_test(fd);
690		writefd_set_test(fd);
691		writefd_not_set_test(fd);
692		child_inherit_test(fd);
693		overflow_select_test(fd);
694		overflow_poll_test(fd);
695		overflow_read_test(fd);
696
697		close(fd);
698	}
699
700	cleanup();
701
702	tst_exit();
703}
704
705static void setup(void)
706{
707
708	tst_sig(FORK, DEF_HANDLER, cleanup);
709
710	if (tst_kvercmp(2, 6, 22) < 0)
711		tst_brkm(TCONF, NULL, "2.6.22 or greater kernel required");
712
713	tst_tmpdir();
714
715	TEST_PAUSE;
716}
717
718static void cleanup(void)
719{
720	tst_rmdir();
721}
722