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/11/tests/sys/aio/lio_kqueue_test.c 326677 2017-12-08 05:20:54Z asomers $
26142976Sambrisko */
27142976Sambrisko
28142976Sambrisko/*
29142976Sambrisko * Note: it is a good idea to run this against a physical drive to
30326677Sasomers * exercise the physio fast path (ie. lio_kqueue_test /dev/<something safe>)
31142976Sambrisko */
32142976Sambrisko
33280894Sngie#include <sys/types.h>
34280894Sngie#include <sys/event.h>
35280894Sngie#include <sys/time.h>
36142976Sambrisko#include <aio.h>
37142976Sambrisko#include <fcntl.h>
38292818Sngie#include <err.h>
39280894Sngie#include <errno.h>
40142976Sambrisko#include <stdio.h>
41280894Sngie#include <stdlib.h>
42280894Sngie#include <string.h>
43142976Sambrisko#include <unistd.h>
44142976Sambrisko
45282136Sngie#include "freebsd_test_suite/macros.h"
46296277Sjhb#include "local.h"
47142976Sambrisko
48282136Sngie#define PATH_TEMPLATE   "aio.XXXXXXXXXX"
49282136Sngie
50142976Sambrisko#define LIO_MAX 5
51326677Sasomers#define MAX_IOCBS_PER_LIO	64
52326677Sasomers#define MAX_IOCBS (LIO_MAX * MAX_IOCBS_PER_LIO)
53142976Sambrisko#define MAX_RUNS 300
54142976Sambrisko
55280894Sngieint
56292818Sngiemain(int argc, char *argv[])
57292818Sngie{
58142976Sambrisko	int fd;
59282136Sngie	struct aiocb *iocb[MAX_IOCBS];
60292819Sngie	struct aiocb **lio[LIO_MAX], **kq_lio;
61326677Sasomers	int i, result, run, error, j, k, max_queue_per_proc;
62326677Sasomers	int max_iocbs, iocbs_per_lio;
63326677Sasomers	size_t max_queue_per_proc_size;
64142976Sambrisko	char buffer[32768];
65292818Sngie	int kq;
66142976Sambrisko	struct kevent ke, kq_returned;
67142976Sambrisko	struct timespec ts;
68142976Sambrisko	struct sigevent sig;
69142976Sambrisko	time_t time1, time2;
70292819Sngie	char *file, pathname[sizeof(PATH_TEMPLATE)];
71142976Sambrisko	int tmp_file = 0, failed = 0;
72280894Sngie
73282136Sngie	PLAIN_REQUIRE_KERNEL_MODULE("aio", 0);
74296277Sjhb	PLAIN_REQUIRE_UNSAFE_AIO(0);
75282136Sngie
76326677Sasomers	max_queue_per_proc_size = sizeof(max_queue_per_proc);
77326677Sasomers	if (sysctlbyname("vfs.aio.max_aio_queue_per_proc",
78326677Sasomers	    &max_queue_per_proc, &max_queue_per_proc_size, NULL, 0) != 0)
79326677Sasomers		err(1, "sysctlbyname");
80326677Sasomers	iocbs_per_lio = max_queue_per_proc / LIO_MAX;
81326677Sasomers	max_iocbs = LIO_MAX * iocbs_per_lio;
82326677Sasomers
83292818Sngie	kq = kqueue();
84292818Sngie	if (kq < 0)
85292818Sngie		err(1, "kqeueue(2) failed");
86142976Sambrisko
87142976Sambrisko	if (argc == 1) {
88142976Sambrisko		strcpy(pathname, PATH_TEMPLATE);
89142976Sambrisko		fd = mkstemp(pathname);
90142976Sambrisko		file = pathname;
91142976Sambrisko		tmp_file = 1;
92142976Sambrisko	} else {
93142976Sambrisko		file = argv[1];
94142976Sambrisko		fd = open(file, O_RDWR|O_CREAT, 0666);
95142976Sambrisko        }
96292818Sngie	if (fd < 0)
97292818Sngie		err(1, "can't open %s", argv[1]);
98142976Sambrisko
99142976Sambrisko#ifdef DEBUG
100142976Sambrisko	printf("Hello kq %d fd %d\n", kq, fd);
101142976Sambrisko#endif
102280894Sngie
103292818Sngie	for (run = 0; run < MAX_RUNS; run++) {
104142976Sambrisko#ifdef DEBUG
105142976Sambrisko		printf("Run %d\n", run);
106142976Sambrisko#endif
107142976Sambrisko		for (j = 0; j < LIO_MAX; j++) {
108292818Sngie			lio[j] =
109326677Sasomers			    malloc(sizeof(struct aiocb *) * iocbs_per_lio);
110326677Sasomers			for (i = 0; i < iocbs_per_lio; i++) {
111326677Sasomers				k = (iocbs_per_lio * j) + i;
112292818Sngie				lio[j][i] = iocb[k] =
113292818Sngie				    calloc(1, sizeof(struct aiocb));
114142976Sambrisko				iocb[k]->aio_nbytes = sizeof(buffer);
115142976Sambrisko				iocb[k]->aio_buf = buffer;
116142976Sambrisko				iocb[k]->aio_fildes = fd;
117292818Sngie				iocb[k]->aio_offset
118292818Sngie				    = iocb[k]->aio_nbytes * k * (run + 1);
119142976Sambrisko
120142976Sambrisko#ifdef DEBUG
121326677Sasomers				printf("hello iocb[k] %jd\n",
122326677Sasomers				       (intmax_t)iocb[k]->aio_offset);
123142976Sambrisko#endif
124142976Sambrisko				iocb[k]->aio_lio_opcode = LIO_WRITE;
125142976Sambrisko			}
126142976Sambrisko			sig.sigev_notify_kqueue = kq;
127154668Sdavidxu			sig.sigev_value.sival_ptr = lio[j];
128142976Sambrisko			sig.sigev_notify = SIGEV_KEVENT;
129142976Sambrisko			time(&time1);
130142976Sambrisko			result = lio_listio(LIO_NOWAIT, lio[j],
131326677Sasomers					    iocbs_per_lio, &sig);
132142976Sambrisko			error = errno;
133142976Sambrisko			time(&time2);
134142976Sambrisko#ifdef DEBUG
135326677Sasomers			printf("Time %jd %jd %jd result -> %d\n",
136326677Sasomers			    (intmax_t)time1, (intmax_t)time2,
137326677Sasomers			    (intmax_t)time2-time1, result);
138142976Sambrisko#endif
139142976Sambrisko			if (result != 0) {
140142976Sambrisko			        errno = error;
141292818Sngie				err(1, "FAIL: Result %d iteration %d\n",
142292818Sngie				    result, j);
143142976Sambrisko			}
144142976Sambrisko#ifdef DEBUG
145142976Sambrisko			printf("write %d is at %p\n", j, lio[j]);
146142976Sambrisko#endif
147142976Sambrisko		}
148280894Sngie
149292818Sngie		for (i = 0; i < LIO_MAX; i++) {
150292818Sngie			for (j = LIO_MAX - 1; j >=0; j--) {
151142976Sambrisko				if (lio[j])
152142976Sambrisko					break;
153142976Sambrisko			}
154280894Sngie
155292818Sngie			for (;;) {
156142976Sambrisko				bzero(&ke, sizeof(ke));
157142976Sambrisko				bzero(&kq_returned, sizeof(ke));
158142976Sambrisko				ts.tv_sec = 0;
159142976Sambrisko				ts.tv_nsec = 1;
160142976Sambrisko#ifdef DEBUG
161142976Sambrisko				printf("FOO lio %d -> %p\n", j, lio[j]);
162142976Sambrisko#endif
163292818Sngie				EV_SET(&ke, (uintptr_t)lio[j],
164142976Sambrisko				       EVFILT_LIO, EV_ONESHOT, 0, 0, iocb[j]);
165292818Sngie				result = kevent(kq, NULL, 0,
166142976Sambrisko						&kq_returned, 1, &ts);
167142976Sambrisko				error = errno;
168142976Sambrisko				if (result < 0) {
169142976Sambrisko					perror("kevent error: ");
170142976Sambrisko				}
171142976Sambrisko				kq_lio = kq_returned.udata;
172142976Sambrisko#ifdef DEBUG
173142976Sambrisko				printf("kevent %d %d errno %d return.ident %p "
174292818Sngie				       "return.data %p return.udata %p %p\n",
175292818Sngie				       i, result, error,
176319218Sasomers				       (void*)kq_returned.ident,
177319218Sasomers				       (void*)kq_returned.data,
178292818Sngie				       kq_returned.udata,
179142976Sambrisko				       lio[j]);
180142976Sambrisko#endif
181280894Sngie
182292818Sngie				if (kq_lio)
183142976Sambrisko					break;
184142976Sambrisko#ifdef DEBUG
185142976Sambrisko				printf("Try again\n");
186142976Sambrisko#endif
187280894Sngie			}
188280894Sngie
189142976Sambrisko#ifdef DEBUG
190142976Sambrisko			printf("lio %p\n", lio);
191142976Sambrisko#endif
192280894Sngie
193142976Sambrisko			for (j = 0; j < LIO_MAX; j++) {
194292818Sngie				if (lio[j] == kq_lio)
195142976Sambrisko					break;
196142976Sambrisko			}
197292818Sngie			if (j == LIO_MAX)
198292818Sngie				errx(1, "FAIL: ");
199142976Sambrisko
200142976Sambrisko#ifdef DEBUG
201142976Sambrisko			printf("Error Result for %d is %d\n", j, result);
202142976Sambrisko#endif
203142976Sambrisko			if (result < 0) {
204142976Sambrisko				printf("FAIL: run %d, operation %d result %d \n", run, LIO_MAX - i -1, result);
205292818Sngie				failed++;
206292818Sngie			} else
207142976Sambrisko				printf("PASS: run %d, operation %d result %d \n", run, LIO_MAX - i -1, result);
208326677Sasomers			for (k = 0; k < max_iocbs / LIO_MAX; k++) {
209280894Sngie				result = aio_return(kq_lio[k]);
210142976Sambrisko#ifdef DEBUG
211326677Sasomers				printf("Return Result for %d %d is %d\n", j, k, result);
212142976Sambrisko#endif
213142976Sambrisko				if (result != sizeof(buffer)) {
214280894Sngie					printf("FAIL: run %d, operation %d sub-opt %d  result %d (errno=%d) should be %zu\n",
215142976Sambrisko					   run, LIO_MAX - i -1, k, result, errno, sizeof(buffer));
216142976Sambrisko				} else {
217142976Sambrisko					printf("PASS: run %d, operation %d sub-opt %d  result %d\n",
218142976Sambrisko					   run, LIO_MAX - i -1, k, result);
219142976Sambrisko				}
220142976Sambrisko			}
221142976Sambrisko#ifdef DEBUG
222142976Sambrisko			printf("\n");
223142976Sambrisko#endif
224280894Sngie
225326677Sasomers			for (k = 0; k < max_iocbs / LIO_MAX; k++)
226142976Sambrisko				free(lio[j][k]);
227142976Sambrisko			free(lio[j]);
228142976Sambrisko			lio[j] = NULL;
229280894Sngie		}
230142976Sambrisko	}
231142976Sambrisko#ifdef DEBUG
232142976Sambrisko	printf("Done\n");
233142976Sambrisko#endif
234142976Sambrisko
235292818Sngie	if (tmp_file)
236142976Sambrisko		unlink(pathname);
237142976Sambrisko
238292818Sngie	if (failed)
239292818Sngie		errx(1, "FAIL: %d testcases failed", failed);
240292818Sngie	else
241292818Sngie		errx(0, "PASS: All\n");
242292818Sngie
243142976Sambrisko}
244