1142976Sambrisko/*-
2142976Sambrisko * Copyright (C) 2005 IronPort Systems, Inc. All rights reserved.
3142976Sambrisko *
4142976Sambrisko * Redistribution and use in source and binary forms, with or without
5142976Sambrisko * modification, are permitted provided that the following conditions
6142976Sambrisko * are met:
7142976Sambrisko * 1. Redistributions of source code must retain the above copyright
8142976Sambrisko *    notice, this list of conditions and the following disclaimer.
9142976Sambrisko * 2. Redistributions in binary form must reproduce the above copyright
10142976Sambrisko *    notice, this list of conditions and the following disclaimer in the
11142976Sambrisko *    documentation and/or other materials provided with the distribution.
12142976Sambrisko *
13142976Sambrisko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14142976Sambrisko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15142976Sambrisko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16142976Sambrisko * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17142976Sambrisko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18142976Sambrisko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19142976Sambrisko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20142976Sambrisko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21142976Sambrisko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22142976Sambrisko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23142976Sambrisko * SUCH DAMAGE.
24142976Sambrisko *
25142976Sambrisko * $FreeBSD: stable/10/tests/sys/aio/lio_kqueue_test.c 319344 2017-05-31 17:20:55Z asomers $
26142976Sambrisko */
27142976Sambrisko
28142976Sambrisko/*
29142976Sambrisko * Note: it is a good idea to run this against a physical drive to
30142976Sambrisko * exercise the physio fast path (ie. lio_kqueue /dev/<something safe>)
31142976Sambrisko * This will ensure op's counting is correct.  It is currently broken.
32142976Sambrisko *
33142976Sambrisko * Also note that LIO & kqueue is not implemented in FreeBSD yet, LIO
34142976Sambrisko * is also broken with respect to op's and some paths.
35142976Sambrisko *
36142976Sambrisko * A patch to make this work is at:
37142976Sambrisko * 	http://www.ambrisko.com/doug/listio_kqueue/listio_kqueue.patch
38142976Sambrisko */
39142976Sambrisko
40280894Sngie#include <sys/types.h>
41280894Sngie#include <sys/event.h>
42280894Sngie#include <sys/time.h>
43142976Sambrisko#include <aio.h>
44142976Sambrisko#include <fcntl.h>
45293140Sngie#include <err.h>
46280894Sngie#include <errno.h>
47142976Sambrisko#include <stdio.h>
48280894Sngie#include <stdlib.h>
49280894Sngie#include <string.h>
50142976Sambrisko#include <unistd.h>
51142976Sambrisko
52282858Sngie#include "freebsd_test_suite/macros.h"
53142976Sambrisko
54282858Sngie#define PATH_TEMPLATE   "aio.XXXXXXXXXX"
55282858Sngie
56142976Sambrisko#define LIO_MAX 5
57319344Sasomers#define IOCBS_PER_LIO	16
58319344Sasomers#define MAX_IOCBS (LIO_MAX * IOCBS_PER_LIO)
59142976Sambrisko#define MAX_RUNS 300
60142976Sambrisko
61280894Sngieint
62293140Sngiemain(int argc, char *argv[])
63293140Sngie{
64142976Sambrisko	int fd;
65282858Sngie	struct aiocb *iocb[MAX_IOCBS];
66293140Sngie	struct aiocb **lio[LIO_MAX], **kq_lio;
67142976Sambrisko	int i, result, run, error, j, k;
68142976Sambrisko	char buffer[32768];
69293140Sngie	int kq;
70142976Sambrisko	struct kevent ke, kq_returned;
71142976Sambrisko	struct timespec ts;
72142976Sambrisko	struct sigevent sig;
73142976Sambrisko	time_t time1, time2;
74293140Sngie	char *file, pathname[sizeof(PATH_TEMPLATE)];
75142976Sambrisko	int tmp_file = 0, failed = 0;
76280894Sngie
77282858Sngie	PLAIN_REQUIRE_KERNEL_MODULE("aio", 0);
78282858Sngie
79293140Sngie	kq = kqueue();
80293140Sngie	if (kq < 0)
81293140Sngie		err(1, "kqeueue(2) failed");
82142976Sambrisko
83142976Sambrisko	if (argc == 1) {
84142976Sambrisko		strcpy(pathname, PATH_TEMPLATE);
85142976Sambrisko		fd = mkstemp(pathname);
86142976Sambrisko		file = pathname;
87142976Sambrisko		tmp_file = 1;
88142976Sambrisko	} else {
89142976Sambrisko		file = argv[1];
90142976Sambrisko		fd = open(file, O_RDWR|O_CREAT, 0666);
91142976Sambrisko        }
92293140Sngie	if (fd < 0)
93293140Sngie		err(1, "can't open %s", argv[1]);
94142976Sambrisko
95142976Sambrisko#ifdef DEBUG
96142976Sambrisko	printf("Hello kq %d fd %d\n", kq, fd);
97142976Sambrisko#endif
98280894Sngie
99293140Sngie	for (run = 0; run < MAX_RUNS; run++) {
100142976Sambrisko#ifdef DEBUG
101142976Sambrisko		printf("Run %d\n", run);
102142976Sambrisko#endif
103142976Sambrisko		for (j = 0; j < LIO_MAX; j++) {
104293140Sngie			lio[j] =
105319344Sasomers			    malloc(sizeof(struct aiocb *) * IOCBS_PER_LIO);
106319344Sasomers			for (i = 0; i < IOCBS_PER_LIO; i++) {
107319344Sasomers				k = (IOCBS_PER_LIO * j) + i;
108293140Sngie				lio[j][i] = iocb[k] =
109293140Sngie				    calloc(1, sizeof(struct aiocb));
110142976Sambrisko				iocb[k]->aio_nbytes = sizeof(buffer);
111142976Sambrisko				iocb[k]->aio_buf = buffer;
112142976Sambrisko				iocb[k]->aio_fildes = fd;
113293140Sngie				iocb[k]->aio_offset
114293140Sngie				    = iocb[k]->aio_nbytes * k * (run + 1);
115142976Sambrisko
116142976Sambrisko#ifdef DEBUG
117319344Sasomers				printf("hello iocb[k] %ld\n",
118142976Sambrisko				       iocb[k]->aio_offset);
119142976Sambrisko#endif
120142976Sambrisko				iocb[k]->aio_lio_opcode = LIO_WRITE;
121142976Sambrisko			}
122142976Sambrisko			sig.sigev_notify_kqueue = kq;
123154668Sdavidxu			sig.sigev_value.sival_ptr = lio[j];
124142976Sambrisko			sig.sigev_notify = SIGEV_KEVENT;
125142976Sambrisko			time(&time1);
126142976Sambrisko			result = lio_listio(LIO_NOWAIT, lio[j],
127319344Sasomers					    IOCBS_PER_LIO, &sig);
128142976Sambrisko			error = errno;
129142976Sambrisko			time(&time2);
130142976Sambrisko#ifdef DEBUG
131319344Sasomers			printf("Time %ld %ld %ld result -> %d\n",
132142976Sambrisko			    time1, time2, time2-time1, result);
133142976Sambrisko#endif
134142976Sambrisko			if (result != 0) {
135142976Sambrisko			        errno = error;
136293140Sngie				err(1, "FAIL: Result %d iteration %d\n",
137293140Sngie				    result, j);
138142976Sambrisko			}
139142976Sambrisko#ifdef DEBUG
140142976Sambrisko			printf("write %d is at %p\n", j, lio[j]);
141142976Sambrisko#endif
142142976Sambrisko		}
143280894Sngie
144293140Sngie		for (i = 0; i < LIO_MAX; i++) {
145293140Sngie			for (j = LIO_MAX - 1; j >=0; j--) {
146142976Sambrisko				if (lio[j])
147142976Sambrisko					break;
148142976Sambrisko			}
149280894Sngie
150293140Sngie			for (;;) {
151142976Sambrisko				bzero(&ke, sizeof(ke));
152142976Sambrisko				bzero(&kq_returned, sizeof(ke));
153142976Sambrisko				ts.tv_sec = 0;
154142976Sambrisko				ts.tv_nsec = 1;
155142976Sambrisko#ifdef DEBUG
156142976Sambrisko				printf("FOO lio %d -> %p\n", j, lio[j]);
157142976Sambrisko#endif
158293140Sngie				EV_SET(&ke, (uintptr_t)lio[j],
159142976Sambrisko				       EVFILT_LIO, EV_ONESHOT, 0, 0, iocb[j]);
160293140Sngie				result = kevent(kq, NULL, 0,
161142976Sambrisko						&kq_returned, 1, &ts);
162142976Sambrisko				error = errno;
163142976Sambrisko				if (result < 0) {
164142976Sambrisko					perror("kevent error: ");
165142976Sambrisko				}
166142976Sambrisko				kq_lio = kq_returned.udata;
167142976Sambrisko#ifdef DEBUG
168142976Sambrisko				printf("kevent %d %d errno %d return.ident %p "
169293140Sngie				       "return.data %p return.udata %p %p\n",
170293140Sngie				       i, result, error,
171319344Sasomers				       (void*)kq_returned.ident,
172319344Sasomers				       (void*)kq_returned.data,
173293140Sngie				       kq_returned.udata,
174142976Sambrisko				       lio[j]);
175142976Sambrisko#endif
176280894Sngie
177293140Sngie				if (kq_lio)
178142976Sambrisko					break;
179142976Sambrisko#ifdef DEBUG
180142976Sambrisko				printf("Try again\n");
181142976Sambrisko#endif
182280894Sngie			}
183280894Sngie
184142976Sambrisko#ifdef DEBUG
185142976Sambrisko			printf("lio %p\n", lio);
186142976Sambrisko#endif
187280894Sngie
188142976Sambrisko			for (j = 0; j < LIO_MAX; j++) {
189293140Sngie				if (lio[j] == kq_lio)
190142976Sambrisko					break;
191142976Sambrisko			}
192293140Sngie			if (j == LIO_MAX)
193293140Sngie				errx(1, "FAIL: ");
194142976Sambrisko
195142976Sambrisko#ifdef DEBUG
196142976Sambrisko			printf("Error Result for %d is %d\n", j, result);
197142976Sambrisko#endif
198142976Sambrisko			if (result < 0) {
199142976Sambrisko				printf("FAIL: run %d, operation %d result %d \n", run, LIO_MAX - i -1, result);
200293140Sngie				failed++;
201293140Sngie			} else
202142976Sambrisko				printf("PASS: run %d, operation %d result %d \n", run, LIO_MAX - i -1, result);
203293140Sngie			for (k = 0; k < MAX_IOCBS / LIO_MAX; k++) {
204280894Sngie				result = aio_return(kq_lio[k]);
205142976Sambrisko#ifdef DEBUG
206142976Sambrisko				printf("Return Resulto for %d %d is %d\n", j, k, result);
207142976Sambrisko#endif
208142976Sambrisko				if (result != sizeof(buffer)) {
209280894Sngie					printf("FAIL: run %d, operation %d sub-opt %d  result %d (errno=%d) should be %zu\n",
210142976Sambrisko					   run, LIO_MAX - i -1, k, result, errno, sizeof(buffer));
211142976Sambrisko				} else {
212142976Sambrisko					printf("PASS: run %d, operation %d sub-opt %d  result %d\n",
213142976Sambrisko					   run, LIO_MAX - i -1, k, result);
214142976Sambrisko				}
215142976Sambrisko			}
216142976Sambrisko#ifdef DEBUG
217142976Sambrisko			printf("\n");
218142976Sambrisko#endif
219280894Sngie
220293140Sngie			for (k = 0; k < MAX_IOCBS / LIO_MAX; k++)
221142976Sambrisko				free(lio[j][k]);
222142976Sambrisko			free(lio[j]);
223142976Sambrisko			lio[j] = NULL;
224280894Sngie		}
225142976Sambrisko	}
226142976Sambrisko#ifdef DEBUG
227142976Sambrisko	printf("Done\n");
228142976Sambrisko#endif
229142976Sambrisko
230293140Sngie	if (tmp_file)
231142976Sambrisko		unlink(pathname);
232142976Sambrisko
233293140Sngie	if (failed)
234293140Sngie		errx(1, "FAIL: %d testcases failed", failed);
235293140Sngie	else
236293140Sngie		errx(0, "PASS: All\n");
237293140Sngie
238142976Sambrisko}
239