xref: /freebsd-src/tests/sys/aio/aio_test.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1f44eb013SEnji Cooper /*-
2f44eb013SEnji Cooper  * Copyright (c) 2004 Robert N. M. Watson
3f44eb013SEnji Cooper  * All rights reserved.
4f44eb013SEnji Cooper  *
5f44eb013SEnji Cooper  * Redistribution and use in source and binary forms, with or without
6f44eb013SEnji Cooper  * modification, are permitted provided that the following conditions
7f44eb013SEnji Cooper  * are met:
8f44eb013SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
9f44eb013SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
10f44eb013SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
11f44eb013SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
12f44eb013SEnji Cooper  *    documentation and/or other materials provided with the distribution.
13f44eb013SEnji Cooper  *
14f44eb013SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15f44eb013SEnji Cooper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16f44eb013SEnji Cooper  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17f44eb013SEnji Cooper  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18f44eb013SEnji Cooper  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19f44eb013SEnji Cooper  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20f44eb013SEnji Cooper  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21f44eb013SEnji Cooper  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22f44eb013SEnji Cooper  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23f44eb013SEnji Cooper  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24f44eb013SEnji Cooper  * SUCH DAMAGE.
25f44eb013SEnji Cooper  */
26f44eb013SEnji Cooper 
27f44eb013SEnji Cooper /*
28f44eb013SEnji Cooper  * Regression test to do some very basic AIO exercising on several types of
29f44eb013SEnji Cooper  * file descriptors.  Currently, the tests consist of initializing a fixed
30f44eb013SEnji Cooper  * size buffer with pseudo-random data, writing it to one fd using AIO, then
31f44eb013SEnji Cooper  * reading it from a second descriptor using AIO.  For some targets, the same
32f44eb013SEnji Cooper  * fd is used for write and read (i.e., file, md device), but for others the
33d600f474SAlan Somers  * operation is performed on a peer (pty, socket, fifo, etc).  For each file
34d600f474SAlan Somers  * descriptor type, several completion methods are tested.  This test program
35d600f474SAlan Somers  * does not attempt to exercise error cases or more subtle asynchronous
36d600f474SAlan Somers  * behavior, just make sure that the basic operations work on some basic object
37d600f474SAlan Somers  * types.
38f44eb013SEnji Cooper  */
39f44eb013SEnji Cooper 
40f44eb013SEnji Cooper #include <sys/param.h>
4157082ce8SAlan Somers #include <sys/event.h>
42141fe2dcSMark Johnston #include <sys/mdioctl.h>
43f44eb013SEnji Cooper #include <sys/module.h>
44b1012d80SJohn Baldwin #include <sys/resource.h>
45f44eb013SEnji Cooper #include <sys/socket.h>
46f44eb013SEnji Cooper #include <sys/stat.h>
47141fe2dcSMark Johnston #include <sys/un.h>
48f44eb013SEnji Cooper 
49f44eb013SEnji Cooper #include <aio.h>
50f44eb013SEnji Cooper #include <err.h>
51f44eb013SEnji Cooper #include <errno.h>
52f44eb013SEnji Cooper #include <fcntl.h>
53f44eb013SEnji Cooper #include <libutil.h>
54f44eb013SEnji Cooper #include <limits.h>
55314b447fSAlan Somers #include <semaphore.h>
56c13f6dd7SMark Johnston #include <signal.h>
57f44eb013SEnji Cooper #include <stdint.h>
58f44eb013SEnji Cooper #include <stdio.h>
59f44eb013SEnji Cooper #include <stdlib.h>
60f44eb013SEnji Cooper #include <string.h>
61f44eb013SEnji Cooper #include <termios.h>
62f44eb013SEnji Cooper #include <unistd.h>
63f44eb013SEnji Cooper 
64f44eb013SEnji Cooper #include <atf-c.h>
65f44eb013SEnji Cooper 
66c5dfa43aSEnji Cooper #include "freebsd_test_suite/macros.h"
67f3215338SJohn Baldwin #include "local.h"
68c5dfa43aSEnji Cooper 
69f44eb013SEnji Cooper /*
70f44eb013SEnji Cooper  * GLOBAL_MAX sets the largest usable buffer size to be read and written, as
71f44eb013SEnji Cooper  * it sizes ac_buffer in the aio_context structure.  It is also the default
72f44eb013SEnji Cooper  * size for file I/O.  For other types, we use smaller blocks or we risk
73f44eb013SEnji Cooper  * blocking (and we run in a single process/thread so that would be bad).
74f44eb013SEnji Cooper  */
75f44eb013SEnji Cooper #define	GLOBAL_MAX	16384
76f44eb013SEnji Cooper 
77f44eb013SEnji Cooper #define	BUFFER_MAX	GLOBAL_MAX
78740a9bfaSAlan Somers 
79740a9bfaSAlan Somers /*
80740a9bfaSAlan Somers  * A completion function will block until the aio has completed, then return
81740a9bfaSAlan Somers  * the result of the aio.  errno will be set appropriately.
82740a9bfaSAlan Somers  */
83740a9bfaSAlan Somers typedef ssize_t (*completion)(struct aiocb*);
84740a9bfaSAlan Somers 
85f44eb013SEnji Cooper struct aio_context {
86f44eb013SEnji Cooper 	int		 ac_read_fd, ac_write_fd;
87f44eb013SEnji Cooper 	long		 ac_seed;
88f44eb013SEnji Cooper 	char		 ac_buffer[GLOBAL_MAX];
89f44eb013SEnji Cooper 	int		 ac_buflen;
90f44eb013SEnji Cooper 	int		 ac_seconds;
91f44eb013SEnji Cooper };
92f44eb013SEnji Cooper 
93314b447fSAlan Somers static sem_t		completions;
94314b447fSAlan Somers 
95f44eb013SEnji Cooper /*
96f44eb013SEnji Cooper  * Fill a buffer given a seed that can be fed into srandom() to initialize
97f44eb013SEnji Cooper  * the PRNG in a repeatable manner.
98f44eb013SEnji Cooper  */
99f44eb013SEnji Cooper static void
aio_fill_buffer(char * buffer,int len,long seed)100f44eb013SEnji Cooper aio_fill_buffer(char *buffer, int len, long seed)
101f44eb013SEnji Cooper {
102f44eb013SEnji Cooper 	char ch;
103f44eb013SEnji Cooper 	int i;
104f44eb013SEnji Cooper 
105f44eb013SEnji Cooper 	srandom(seed);
106f44eb013SEnji Cooper 	for (i = 0; i < len; i++) {
107f44eb013SEnji Cooper 		ch = random() & 0xff;
108f44eb013SEnji Cooper 		buffer[i] = ch;
109f44eb013SEnji Cooper 	}
110f44eb013SEnji Cooper }
111f44eb013SEnji Cooper 
112f44eb013SEnji Cooper /*
113f44eb013SEnji Cooper  * Test that a buffer matches a given seed.  See aio_fill_buffer().  Return
114f44eb013SEnji Cooper  * (1) on a match, (0) on a mismatch.
115f44eb013SEnji Cooper  */
116f44eb013SEnji Cooper static int
aio_test_buffer(char * buffer,int len,long seed)117f44eb013SEnji Cooper aio_test_buffer(char *buffer, int len, long seed)
118f44eb013SEnji Cooper {
119f44eb013SEnji Cooper 	char ch;
120f44eb013SEnji Cooper 	int i;
121f44eb013SEnji Cooper 
122f44eb013SEnji Cooper 	srandom(seed);
123f44eb013SEnji Cooper 	for (i = 0; i < len; i++) {
124f44eb013SEnji Cooper 		ch = random() & 0xff;
125f44eb013SEnji Cooper 		if (buffer[i] != ch)
126f44eb013SEnji Cooper 			return (0);
127f44eb013SEnji Cooper 	}
128f44eb013SEnji Cooper 	return (1);
129f44eb013SEnji Cooper }
130f44eb013SEnji Cooper 
131f44eb013SEnji Cooper /*
132f44eb013SEnji Cooper  * Initialize a testing context given the file descriptors provided by the
133f44eb013SEnji Cooper  * test setup.
134f44eb013SEnji Cooper  */
135f44eb013SEnji Cooper static void
aio_context_init(struct aio_context * ac,int read_fd,int write_fd,int buflen)136f44eb013SEnji Cooper aio_context_init(struct aio_context *ac, int read_fd,
137d600f474SAlan Somers     int write_fd, int buflen)
138f44eb013SEnji Cooper {
139f44eb013SEnji Cooper 
140f44eb013SEnji Cooper 	ATF_REQUIRE_MSG(buflen <= BUFFER_MAX,
141f44eb013SEnji Cooper 	    "aio_context_init: buffer too large (%d > %d)",
142f44eb013SEnji Cooper 	    buflen, BUFFER_MAX);
143f44eb013SEnji Cooper 	bzero(ac, sizeof(*ac));
144f44eb013SEnji Cooper 	ac->ac_read_fd = read_fd;
145f44eb013SEnji Cooper 	ac->ac_write_fd = write_fd;
146f44eb013SEnji Cooper 	ac->ac_buflen = buflen;
147f44eb013SEnji Cooper 	srandomdev();
148f44eb013SEnji Cooper 	ac->ac_seed = random();
149f44eb013SEnji Cooper 	aio_fill_buffer(ac->ac_buffer, buflen, ac->ac_seed);
150f44eb013SEnji Cooper 	ATF_REQUIRE_MSG(aio_test_buffer(ac->ac_buffer, buflen,
151f44eb013SEnji Cooper 	    ac->ac_seed) != 0, "aio_test_buffer: internal error");
152f44eb013SEnji Cooper }
153f44eb013SEnji Cooper 
154740a9bfaSAlan Somers static ssize_t
poll(struct aiocb * aio)155e9b7132bSEnji Cooper poll(struct aiocb *aio)
156e9b7132bSEnji Cooper {
15755e0d88aSRobert Watson 	int error;
158740a9bfaSAlan Somers 
159d600f474SAlan Somers 	while ((error = aio_error(aio)) == EINPROGRESS)
160740a9bfaSAlan Somers 		usleep(25000);
1610eafa707SAlan Somers 	if (error)
16255e0d88aSRobert Watson 		return (error);
1630eafa707SAlan Somers 	else
1640eafa707SAlan Somers 		return (aio_return(aio));
165740a9bfaSAlan Somers }
166740a9bfaSAlan Somers 
167314b447fSAlan Somers static void
sigusr1_handler(int sig __unused)168314b447fSAlan Somers sigusr1_handler(int sig __unused)
169314b447fSAlan Somers {
170314b447fSAlan Somers 	ATF_REQUIRE_EQ(0, sem_post(&completions));
171314b447fSAlan Somers }
172314b447fSAlan Somers 
173314b447fSAlan Somers static void
thr_handler(union sigval sv __unused)174314b447fSAlan Somers thr_handler(union sigval sv __unused)
175314b447fSAlan Somers {
176314b447fSAlan Somers 	ATF_REQUIRE_EQ(0, sem_post(&completions));
177314b447fSAlan Somers }
178314b447fSAlan Somers 
179314b447fSAlan Somers static ssize_t
poll_signaled(struct aiocb * aio)180314b447fSAlan Somers poll_signaled(struct aiocb *aio)
181314b447fSAlan Somers {
182314b447fSAlan Somers 	int error;
183314b447fSAlan Somers 
184314b447fSAlan Somers 	ATF_REQUIRE_EQ(0, sem_wait(&completions));
185314b447fSAlan Somers 	error = aio_error(aio);
186314b447fSAlan Somers 	switch (error) {
187314b447fSAlan Somers 		case EINPROGRESS:
188314b447fSAlan Somers 			errno = EINTR;
189314b447fSAlan Somers 			return (-1);
190314b447fSAlan Somers 		case 0:
191314b447fSAlan Somers 			return (aio_return(aio));
192314b447fSAlan Somers 		default:
193314b447fSAlan Somers 			return (error);
194314b447fSAlan Somers 	}
195314b447fSAlan Somers }
196314b447fSAlan Somers 
197314b447fSAlan Somers /*
198314b447fSAlan Somers  * Setup a signal handler for signal delivery tests
199314b447fSAlan Somers  * This isn't thread safe, but it's ok since ATF runs each testcase in a
200314b447fSAlan Somers  * separate process
201314b447fSAlan Somers  */
202314b447fSAlan Somers static struct sigevent*
setup_signal(void)203314b447fSAlan Somers setup_signal(void)
204314b447fSAlan Somers {
205314b447fSAlan Somers 	static struct sigevent sev;
206314b447fSAlan Somers 
207314b447fSAlan Somers 	ATF_REQUIRE_EQ(0, sem_init(&completions, false, 0));
208314b447fSAlan Somers 	sev.sigev_notify = SIGEV_SIGNAL;
209314b447fSAlan Somers 	sev.sigev_signo = SIGUSR1;
210314b447fSAlan Somers 	ATF_REQUIRE(SIG_ERR != signal(SIGUSR1, sigusr1_handler));
211314b447fSAlan Somers 	return (&sev);
212314b447fSAlan Somers }
213314b447fSAlan Somers 
214314b447fSAlan Somers /*
215314b447fSAlan Somers  * Setup a thread for thread delivery tests
216314b447fSAlan Somers  * This isn't thread safe, but it's ok since ATF runs each testcase in a
217314b447fSAlan Somers  * separate process
218314b447fSAlan Somers  */
219314b447fSAlan Somers static struct sigevent*
setup_thread(void)220a4ea52aaSAlan Somers setup_thread(void)
221314b447fSAlan Somers {
222314b447fSAlan Somers 	static struct sigevent sev;
223314b447fSAlan Somers 
224314b447fSAlan Somers 	ATF_REQUIRE_EQ(0, sem_init(&completions, false, 0));
225314b447fSAlan Somers 	sev.sigev_notify = SIGEV_THREAD;
226314b447fSAlan Somers 	sev.sigev_notify_function = thr_handler;
227314b447fSAlan Somers 	sev.sigev_notify_attributes = NULL;
228314b447fSAlan Somers 	return (&sev);
229314b447fSAlan Somers }
230314b447fSAlan Somers 
231740a9bfaSAlan Somers static ssize_t
suspend(struct aiocb * aio)232e9b7132bSEnji Cooper suspend(struct aiocb *aio)
233e9b7132bSEnji Cooper {
234740a9bfaSAlan Somers 	const struct aiocb *const iocbs[] = {aio};
23555e0d88aSRobert Watson 	int error;
236740a9bfaSAlan Somers 
23755e0d88aSRobert Watson 	error = aio_suspend(iocbs, 1, NULL);
23855e0d88aSRobert Watson 	if (error == 0)
239740a9bfaSAlan Somers 		return (aio_return(aio));
240740a9bfaSAlan Somers 	else
24155e0d88aSRobert Watson 		return (error);
242740a9bfaSAlan Somers }
243740a9bfaSAlan Somers 
244740a9bfaSAlan Somers static ssize_t
waitcomplete(struct aiocb * aio)245e9b7132bSEnji Cooper waitcomplete(struct aiocb *aio)
246e9b7132bSEnji Cooper {
247740a9bfaSAlan Somers 	struct aiocb *aiop;
248740a9bfaSAlan Somers 	ssize_t ret;
249740a9bfaSAlan Somers 
250740a9bfaSAlan Somers 	ret = aio_waitcomplete(&aiop, NULL);
251740a9bfaSAlan Somers 	ATF_REQUIRE_EQ(aio, aiop);
252740a9bfaSAlan Somers 	return (ret);
253740a9bfaSAlan Somers }
254740a9bfaSAlan Somers 
255f44eb013SEnji Cooper /*
25657082ce8SAlan Somers  * Setup an iocb for kqueue notification.  This isn't thread
25757082ce8SAlan Somers  * safe, but it's ok because ATF runs every test case in a separate process.
25857082ce8SAlan Somers  */
25957082ce8SAlan Somers static struct sigevent*
setup_kqueue(void)26057082ce8SAlan Somers setup_kqueue(void)
26157082ce8SAlan Somers {
26257082ce8SAlan Somers 	static struct sigevent sev;
26357082ce8SAlan Somers 	static int kq;
26457082ce8SAlan Somers 
26557082ce8SAlan Somers 	kq = kqueue();
26657082ce8SAlan Somers 	ATF_REQUIRE(kq >= 0);
26757082ce8SAlan Somers 
26857082ce8SAlan Somers 	memset(&sev, 0, sizeof(sev));
26957082ce8SAlan Somers 	sev.sigev_notify_kqueue = kq;
27057082ce8SAlan Somers 	sev.sigev_value.sival_ptr = (void*)0xdeadbeef;
27157082ce8SAlan Somers 	sev.sigev_notify = SIGEV_KEVENT;
27257082ce8SAlan Somers 
27357082ce8SAlan Somers 	return (&sev);
27457082ce8SAlan Somers }
27557082ce8SAlan Somers 
27657082ce8SAlan Somers static ssize_t
poll_kqueue(struct aiocb * aio)27757082ce8SAlan Somers poll_kqueue(struct aiocb *aio)
27857082ce8SAlan Somers {
27957082ce8SAlan Somers 	int kq, nevents;
28057082ce8SAlan Somers 	struct kevent events[1];
28157082ce8SAlan Somers 
28257082ce8SAlan Somers 	kq = aio->aio_sigevent.sigev_notify_kqueue;
28357082ce8SAlan Somers 
28457082ce8SAlan Somers 	nevents = kevent(kq, NULL, 0, events, 1, NULL);
28557082ce8SAlan Somers 	ATF_CHECK_EQ(1, nevents);
28657082ce8SAlan Somers 	ATF_CHECK_EQ(events[0].ident, (uintptr_t) aio);
28757082ce8SAlan Somers 	ATF_CHECK_EQ(events[0].filter, EVFILT_AIO);
28857082ce8SAlan Somers 	ATF_CHECK_EQ(events[0].flags, EV_EOF);
28957082ce8SAlan Somers 	ATF_CHECK_EQ(events[0].fflags, 0);
29057082ce8SAlan Somers 	ATF_CHECK_EQ(events[0].data, 0);
29157082ce8SAlan Somers 	ATF_CHECK_EQ((uintptr_t)events[0].udata, 0xdeadbeef);
29257082ce8SAlan Somers 
29357082ce8SAlan Somers 	return (aio_return(aio));
29457082ce8SAlan Somers }
29557082ce8SAlan Somers 
29657082ce8SAlan Somers /*
297f44eb013SEnji Cooper  * Perform a simple write test of our initialized data buffer to the provided
298f44eb013SEnji Cooper  * file descriptor.
299f44eb013SEnji Cooper  */
300f44eb013SEnji Cooper static void
aio_write_test(struct aio_context * ac,completion comp,struct sigevent * sev)301314b447fSAlan Somers aio_write_test(struct aio_context *ac, completion comp, struct sigevent *sev)
302f44eb013SEnji Cooper {
303740a9bfaSAlan Somers 	struct aiocb aio;
304f44eb013SEnji Cooper 	ssize_t len;
305f44eb013SEnji Cooper 
306f44eb013SEnji Cooper 	bzero(&aio, sizeof(aio));
307f44eb013SEnji Cooper 	aio.aio_buf = ac->ac_buffer;
308f44eb013SEnji Cooper 	aio.aio_nbytes = ac->ac_buflen;
309f44eb013SEnji Cooper 	aio.aio_fildes = ac->ac_write_fd;
310f44eb013SEnji Cooper 	aio.aio_offset = 0;
311314b447fSAlan Somers 	if (sev)
312314b447fSAlan Somers 		aio.aio_sigevent = *sev;
313f44eb013SEnji Cooper 
314d600f474SAlan Somers 	if (aio_write(&aio) < 0)
315f44eb013SEnji Cooper 		atf_tc_fail("aio_write failed: %s", strerror(errno));
316f44eb013SEnji Cooper 
317740a9bfaSAlan Somers 	len = comp(&aio);
318d600f474SAlan Somers 	if (len < 0)
319740a9bfaSAlan Somers 		atf_tc_fail("aio failed: %s", strerror(errno));
320f44eb013SEnji Cooper 
321d600f474SAlan Somers 	if (len != ac->ac_buflen)
322740a9bfaSAlan Somers 		atf_tc_fail("aio short write (%jd)", (intmax_t)len);
323f44eb013SEnji Cooper }
324f44eb013SEnji Cooper 
325f44eb013SEnji Cooper /*
326022ca2fcSAlan Somers  * Perform a vectored I/O test of our initialized data buffer to the provided
327022ca2fcSAlan Somers  * file descriptor.
328022ca2fcSAlan Somers  *
329022ca2fcSAlan Somers  * To vectorize the linear buffer, chop it up into two pieces of dissimilar
330022ca2fcSAlan Somers  * size, and swap their offsets.
331022ca2fcSAlan Somers  */
332022ca2fcSAlan Somers static void
aio_writev_test(struct aio_context * ac,completion comp,struct sigevent * sev)333022ca2fcSAlan Somers aio_writev_test(struct aio_context *ac, completion comp, struct sigevent *sev)
334022ca2fcSAlan Somers {
335022ca2fcSAlan Somers 	struct aiocb aio;
336022ca2fcSAlan Somers 	struct iovec iov[2];
337022ca2fcSAlan Somers 	size_t len0, len1;
338022ca2fcSAlan Somers 	ssize_t len;
339022ca2fcSAlan Somers 
340022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
341022ca2fcSAlan Somers 
342022ca2fcSAlan Somers 	aio.aio_fildes = ac->ac_write_fd;
343022ca2fcSAlan Somers 	aio.aio_offset = 0;
344022ca2fcSAlan Somers 	len0 = ac->ac_buflen * 3 / 4;
345022ca2fcSAlan Somers 	len1 = ac->ac_buflen / 4;
346022ca2fcSAlan Somers 	iov[0].iov_base = ac->ac_buffer + len1;
347022ca2fcSAlan Somers 	iov[0].iov_len = len0;
348022ca2fcSAlan Somers 	iov[1].iov_base = ac->ac_buffer;
349022ca2fcSAlan Somers 	iov[1].iov_len = len1;
350022ca2fcSAlan Somers 	aio.aio_iov = iov;
351022ca2fcSAlan Somers 	aio.aio_iovcnt = 2;
352022ca2fcSAlan Somers 	if (sev)
353022ca2fcSAlan Somers 		aio.aio_sigevent = *sev;
354022ca2fcSAlan Somers 
355022ca2fcSAlan Somers 	if (aio_writev(&aio) < 0)
356022ca2fcSAlan Somers 		atf_tc_fail("aio_writev failed: %s", strerror(errno));
357022ca2fcSAlan Somers 
358022ca2fcSAlan Somers 	len = comp(&aio);
359022ca2fcSAlan Somers 	if (len < 0)
360022ca2fcSAlan Somers 		atf_tc_fail("aio failed: %s", strerror(errno));
361022ca2fcSAlan Somers 
362022ca2fcSAlan Somers 	if (len != ac->ac_buflen)
363022ca2fcSAlan Somers 		atf_tc_fail("aio short write (%jd)", (intmax_t)len);
364022ca2fcSAlan Somers }
365022ca2fcSAlan Somers 
366022ca2fcSAlan Somers /*
367f44eb013SEnji Cooper  * Perform a simple read test of our initialized data buffer from the
368f44eb013SEnji Cooper  * provided file descriptor.
369f44eb013SEnji Cooper  */
370f44eb013SEnji Cooper static void
aio_read_test(struct aio_context * ac,completion comp,struct sigevent * sev)371314b447fSAlan Somers aio_read_test(struct aio_context *ac, completion comp, struct sigevent *sev)
372f44eb013SEnji Cooper {
373740a9bfaSAlan Somers 	struct aiocb aio;
374f44eb013SEnji Cooper 	ssize_t len;
375f44eb013SEnji Cooper 
376f44eb013SEnji Cooper 	bzero(ac->ac_buffer, ac->ac_buflen);
377f44eb013SEnji Cooper 	bzero(&aio, sizeof(aio));
378f44eb013SEnji Cooper 	aio.aio_buf = ac->ac_buffer;
379f44eb013SEnji Cooper 	aio.aio_nbytes = ac->ac_buflen;
380f44eb013SEnji Cooper 	aio.aio_fildes = ac->ac_read_fd;
381f44eb013SEnji Cooper 	aio.aio_offset = 0;
382314b447fSAlan Somers 	if (sev)
383314b447fSAlan Somers 		aio.aio_sigevent = *sev;
384f44eb013SEnji Cooper 
385d600f474SAlan Somers 	if (aio_read(&aio) < 0)
386f44eb013SEnji Cooper 		atf_tc_fail("aio_read failed: %s", strerror(errno));
387f44eb013SEnji Cooper 
388740a9bfaSAlan Somers 	len = comp(&aio);
389d600f474SAlan Somers 	if (len < 0)
390740a9bfaSAlan Somers 		atf_tc_fail("aio failed: %s", strerror(errno));
391f44eb013SEnji Cooper 
392d600f474SAlan Somers 	ATF_REQUIRE_EQ_MSG(len, ac->ac_buflen,
393d600f474SAlan Somers 	    "aio short read (%jd)", (intmax_t)len);
394f44eb013SEnji Cooper 
395d600f474SAlan Somers 	if (aio_test_buffer(ac->ac_buffer, ac->ac_buflen, ac->ac_seed) == 0)
396f44eb013SEnji Cooper 		atf_tc_fail("buffer mismatched");
397f44eb013SEnji Cooper }
398f44eb013SEnji Cooper 
399022ca2fcSAlan Somers static void
aio_readv_test(struct aio_context * ac,completion comp,struct sigevent * sev)400022ca2fcSAlan Somers aio_readv_test(struct aio_context *ac, completion comp, struct sigevent *sev)
401022ca2fcSAlan Somers {
402022ca2fcSAlan Somers 	struct aiocb aio;
403022ca2fcSAlan Somers 	struct iovec iov[2];
404022ca2fcSAlan Somers 	size_t len0, len1;
405022ca2fcSAlan Somers 	ssize_t len;
406022ca2fcSAlan Somers 
407022ca2fcSAlan Somers 	bzero(ac->ac_buffer, ac->ac_buflen);
408022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
409022ca2fcSAlan Somers 	aio.aio_fildes = ac->ac_read_fd;
410022ca2fcSAlan Somers 	aio.aio_offset = 0;
411022ca2fcSAlan Somers 	len0 = ac->ac_buflen * 3 / 4;
412022ca2fcSAlan Somers 	len1 = ac->ac_buflen / 4;
413022ca2fcSAlan Somers 	iov[0].iov_base = ac->ac_buffer + len1;
414022ca2fcSAlan Somers 	iov[0].iov_len = len0;
415022ca2fcSAlan Somers 	iov[1].iov_base = ac->ac_buffer;
416022ca2fcSAlan Somers 	iov[1].iov_len = len1;
417022ca2fcSAlan Somers 	aio.aio_iov = iov;
418022ca2fcSAlan Somers 	aio.aio_iovcnt = 2;
419022ca2fcSAlan Somers 	if (sev)
420022ca2fcSAlan Somers 		aio.aio_sigevent = *sev;
421022ca2fcSAlan Somers 
422022ca2fcSAlan Somers 	if (aio_readv(&aio) < 0)
423022ca2fcSAlan Somers 		atf_tc_fail("aio_read failed: %s", strerror(errno));
424022ca2fcSAlan Somers 
425022ca2fcSAlan Somers 	len = comp(&aio);
426022ca2fcSAlan Somers 	if (len < 0)
427022ca2fcSAlan Somers 		atf_tc_fail("aio failed: %s", strerror(errno));
428022ca2fcSAlan Somers 
429022ca2fcSAlan Somers 	ATF_REQUIRE_EQ_MSG(len, ac->ac_buflen,
430022ca2fcSAlan Somers 	    "aio short read (%jd)", (intmax_t)len);
431022ca2fcSAlan Somers 
432022ca2fcSAlan Somers 	if (aio_test_buffer(ac->ac_buffer, ac->ac_buflen, ac->ac_seed) == 0)
433022ca2fcSAlan Somers 		atf_tc_fail("buffer mismatched");
434022ca2fcSAlan Somers }
435022ca2fcSAlan Somers 
436f44eb013SEnji Cooper /*
437f44eb013SEnji Cooper  * Series of type-specific tests for AIO.  For now, we just make sure we can
438f44eb013SEnji Cooper  * issue a write and then a read to each type.  We assume that once a write
439f44eb013SEnji Cooper  * is issued, a read can follow.
440f44eb013SEnji Cooper  */
441f44eb013SEnji Cooper 
442f44eb013SEnji Cooper /*
443f44eb013SEnji Cooper  * Test with a classic file.  Assumes we can create a moderate size temporary
444f44eb013SEnji Cooper  * file.
445f44eb013SEnji Cooper  */
446740a9bfaSAlan Somers #define	FILE_LEN	GLOBAL_MAX
447740a9bfaSAlan Somers #define	FILE_PATHNAME	"testfile"
448f44eb013SEnji Cooper 
449740a9bfaSAlan Somers static void
aio_file_test(completion comp,struct sigevent * sev,bool vectored)450022ca2fcSAlan Somers aio_file_test(completion comp, struct sigevent *sev, bool vectored)
451f44eb013SEnji Cooper {
452f44eb013SEnji Cooper 	struct aio_context ac;
453f44eb013SEnji Cooper 	int fd;
454f44eb013SEnji Cooper 
455c5dfa43aSEnji Cooper 	ATF_REQUIRE_KERNEL_MODULE("aio");
456f3215338SJohn Baldwin 	ATF_REQUIRE_UNSAFE_AIO();
457f44eb013SEnji Cooper 
4589086b30bSJilles Tjoelker 	fd = open(FILE_PATHNAME, O_RDWR | O_CREAT, 0600);
459740a9bfaSAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
460f44eb013SEnji Cooper 
461d600f474SAlan Somers 	aio_context_init(&ac, fd, fd, FILE_LEN);
462022ca2fcSAlan Somers 	if (vectored) {
463022ca2fcSAlan Somers 		aio_writev_test(&ac, comp, sev);
464022ca2fcSAlan Somers 		aio_readv_test(&ac, comp, sev);
465022ca2fcSAlan Somers 	} else {
466314b447fSAlan Somers 		aio_write_test(&ac, comp, sev);
467314b447fSAlan Somers 		aio_read_test(&ac, comp, sev);
468022ca2fcSAlan Somers 	}
469d600f474SAlan Somers 	close(fd);
470f44eb013SEnji Cooper }
471f44eb013SEnji Cooper 
47257082ce8SAlan Somers ATF_TC_WITHOUT_HEAD(file_kq);
ATF_TC_BODY(file_kq,tc)47357082ce8SAlan Somers ATF_TC_BODY(file_kq, tc)
47457082ce8SAlan Somers {
47557082ce8SAlan Somers 	aio_file_test(poll_kqueue, setup_kqueue(), false);
47657082ce8SAlan Somers }
47757082ce8SAlan Somers 
478740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(file_poll);
ATF_TC_BODY(file_poll,tc)479740a9bfaSAlan Somers ATF_TC_BODY(file_poll, tc)
480740a9bfaSAlan Somers {
481022ca2fcSAlan Somers 	aio_file_test(poll, NULL, false);
482314b447fSAlan Somers }
483314b447fSAlan Somers 
484314b447fSAlan Somers ATF_TC_WITHOUT_HEAD(file_signal);
ATF_TC_BODY(file_signal,tc)485314b447fSAlan Somers ATF_TC_BODY(file_signal, tc)
486314b447fSAlan Somers {
487022ca2fcSAlan Somers 	aio_file_test(poll_signaled, setup_signal(), false);
488740a9bfaSAlan Somers }
489740a9bfaSAlan Somers 
490740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(file_suspend);
ATF_TC_BODY(file_suspend,tc)491740a9bfaSAlan Somers ATF_TC_BODY(file_suspend, tc)
492740a9bfaSAlan Somers {
493022ca2fcSAlan Somers 	aio_file_test(suspend, NULL, false);
494314b447fSAlan Somers }
495314b447fSAlan Somers 
496314b447fSAlan Somers ATF_TC_WITHOUT_HEAD(file_thread);
ATF_TC_BODY(file_thread,tc)497314b447fSAlan Somers ATF_TC_BODY(file_thread, tc)
498314b447fSAlan Somers {
499022ca2fcSAlan Somers 	aio_file_test(poll_signaled, setup_thread(), false);
500740a9bfaSAlan Somers }
501740a9bfaSAlan Somers 
502740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(file_waitcomplete);
ATF_TC_BODY(file_waitcomplete,tc)503740a9bfaSAlan Somers ATF_TC_BODY(file_waitcomplete, tc)
504740a9bfaSAlan Somers {
505022ca2fcSAlan Somers 	aio_file_test(waitcomplete, NULL, false);
506740a9bfaSAlan Somers }
507740a9bfaSAlan Somers 
508740a9bfaSAlan Somers #define	FIFO_LEN	256
509740a9bfaSAlan Somers #define	FIFO_PATHNAME	"testfifo"
510f44eb013SEnji Cooper 
511740a9bfaSAlan Somers static void
aio_fifo_test(completion comp,struct sigevent * sev)512314b447fSAlan Somers aio_fifo_test(completion comp, struct sigevent *sev)
513f44eb013SEnji Cooper {
514f44eb013SEnji Cooper 	int error, read_fd = -1, write_fd = -1;
515f44eb013SEnji Cooper 	struct aio_context ac;
516f44eb013SEnji Cooper 
517c5dfa43aSEnji Cooper 	ATF_REQUIRE_KERNEL_MODULE("aio");
518f3215338SJohn Baldwin 	ATF_REQUIRE_UNSAFE_AIO();
519f44eb013SEnji Cooper 
520740a9bfaSAlan Somers 	ATF_REQUIRE_MSG(mkfifo(FIFO_PATHNAME, 0600) != -1,
521f44eb013SEnji Cooper 	    "mkfifo failed: %s", strerror(errno));
522f44eb013SEnji Cooper 
523740a9bfaSAlan Somers 	read_fd = open(FIFO_PATHNAME, O_RDONLY | O_NONBLOCK);
524f44eb013SEnji Cooper 	if (read_fd == -1) {
525f44eb013SEnji Cooper 		error = errno;
526f44eb013SEnji Cooper 		errno = error;
527f44eb013SEnji Cooper 		atf_tc_fail("read_fd open failed: %s",
528f44eb013SEnji Cooper 		    strerror(errno));
529f44eb013SEnji Cooper 	}
530f44eb013SEnji Cooper 
531740a9bfaSAlan Somers 	write_fd = open(FIFO_PATHNAME, O_WRONLY);
532f44eb013SEnji Cooper 	if (write_fd == -1) {
533f44eb013SEnji Cooper 		error = errno;
534f44eb013SEnji Cooper 		errno = error;
535f44eb013SEnji Cooper 		atf_tc_fail("write_fd open failed: %s",
536f44eb013SEnji Cooper 		    strerror(errno));
537f44eb013SEnji Cooper 	}
538f44eb013SEnji Cooper 
539d600f474SAlan Somers 	aio_context_init(&ac, read_fd, write_fd, FIFO_LEN);
540314b447fSAlan Somers 	aio_write_test(&ac, comp, sev);
541314b447fSAlan Somers 	aio_read_test(&ac, comp, sev);
542f44eb013SEnji Cooper 
543d600f474SAlan Somers 	close(read_fd);
544d600f474SAlan Somers 	close(write_fd);
545f44eb013SEnji Cooper }
546f44eb013SEnji Cooper 
54757082ce8SAlan Somers ATF_TC_WITHOUT_HEAD(fifo_kq);
ATF_TC_BODY(fifo_kq,tc)54857082ce8SAlan Somers ATF_TC_BODY(fifo_kq, tc)
54957082ce8SAlan Somers {
55057082ce8SAlan Somers 	aio_fifo_test(poll_kqueue, setup_kqueue());
55157082ce8SAlan Somers }
55257082ce8SAlan Somers 
553740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(fifo_poll);
ATF_TC_BODY(fifo_poll,tc)554740a9bfaSAlan Somers ATF_TC_BODY(fifo_poll, tc)
555740a9bfaSAlan Somers {
556314b447fSAlan Somers 	aio_fifo_test(poll, NULL);
557314b447fSAlan Somers }
558314b447fSAlan Somers 
559314b447fSAlan Somers ATF_TC_WITHOUT_HEAD(fifo_signal);
ATF_TC_BODY(fifo_signal,tc)560314b447fSAlan Somers ATF_TC_BODY(fifo_signal, tc)
561314b447fSAlan Somers {
562314b447fSAlan Somers 	aio_fifo_test(poll_signaled, setup_signal());
563740a9bfaSAlan Somers }
564740a9bfaSAlan Somers 
565740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(fifo_suspend);
ATF_TC_BODY(fifo_suspend,tc)566740a9bfaSAlan Somers ATF_TC_BODY(fifo_suspend, tc)
567740a9bfaSAlan Somers {
568314b447fSAlan Somers 	aio_fifo_test(suspend, NULL);
569314b447fSAlan Somers }
570314b447fSAlan Somers 
571314b447fSAlan Somers ATF_TC_WITHOUT_HEAD(fifo_thread);
ATF_TC_BODY(fifo_thread,tc)572314b447fSAlan Somers ATF_TC_BODY(fifo_thread, tc)
573314b447fSAlan Somers {
574314b447fSAlan Somers 	aio_fifo_test(poll_signaled, setup_thread());
575740a9bfaSAlan Somers }
576740a9bfaSAlan Somers 
577740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(fifo_waitcomplete);
ATF_TC_BODY(fifo_waitcomplete,tc)578740a9bfaSAlan Somers ATF_TC_BODY(fifo_waitcomplete, tc)
579740a9bfaSAlan Somers {
580314b447fSAlan Somers 	aio_fifo_test(waitcomplete, NULL);
581740a9bfaSAlan Somers }
582740a9bfaSAlan Somers 
583f44eb013SEnji Cooper #define	UNIX_SOCKETPAIR_LEN	256
584740a9bfaSAlan Somers static void
aio_unix_socketpair_test(completion comp,struct sigevent * sev,bool vectored)585022ca2fcSAlan Somers aio_unix_socketpair_test(completion comp, struct sigevent *sev, bool vectored)
586f44eb013SEnji Cooper {
587f44eb013SEnji Cooper 	struct aio_context ac;
588b1012d80SJohn Baldwin 	struct rusage ru_before, ru_after;
589f44eb013SEnji Cooper 	int sockets[2];
590f44eb013SEnji Cooper 
591c5dfa43aSEnji Cooper 	ATF_REQUIRE_KERNEL_MODULE("aio");
592f44eb013SEnji Cooper 
593f44eb013SEnji Cooper 	ATF_REQUIRE_MSG(socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) != -1,
594f44eb013SEnji Cooper 	    "socketpair failed: %s", strerror(errno));
595f44eb013SEnji Cooper 
596d600f474SAlan Somers 	aio_context_init(&ac, sockets[0], sockets[1], UNIX_SOCKETPAIR_LEN);
597b1012d80SJohn Baldwin 	ATF_REQUIRE_MSG(getrusage(RUSAGE_SELF, &ru_before) != -1,
598b1012d80SJohn Baldwin 	    "getrusage failed: %s", strerror(errno));
599022ca2fcSAlan Somers 	if (vectored) {
600022ca2fcSAlan Somers 		aio_writev_test(&ac, comp, sev);
601022ca2fcSAlan Somers 		aio_readv_test(&ac, comp, sev);
602022ca2fcSAlan Somers 	} else {
603314b447fSAlan Somers 		aio_write_test(&ac, comp, sev);
604022ca2fcSAlan Somers 		aio_read_test(&ac, comp, sev);
605022ca2fcSAlan Somers 	}
606b1012d80SJohn Baldwin 	ATF_REQUIRE_MSG(getrusage(RUSAGE_SELF, &ru_after) != -1,
607b1012d80SJohn Baldwin 	    "getrusage failed: %s", strerror(errno));
608b1012d80SJohn Baldwin 	ATF_REQUIRE(ru_after.ru_msgsnd == ru_before.ru_msgsnd + 1);
609b1012d80SJohn Baldwin 	ATF_REQUIRE(ru_after.ru_msgrcv == ru_before.ru_msgrcv + 1);
610f44eb013SEnji Cooper 
611d600f474SAlan Somers 	close(sockets[0]);
612d600f474SAlan Somers 	close(sockets[1]);
613f44eb013SEnji Cooper }
614f44eb013SEnji Cooper 
61557082ce8SAlan Somers ATF_TC_WITHOUT_HEAD(socket_kq);
ATF_TC_BODY(socket_kq,tc)61657082ce8SAlan Somers ATF_TC_BODY(socket_kq, tc)
61757082ce8SAlan Somers {
61857082ce8SAlan Somers 	aio_unix_socketpair_test(poll_kqueue, setup_kqueue(), false);
61957082ce8SAlan Somers }
62057082ce8SAlan Somers 
621740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(socket_poll);
ATF_TC_BODY(socket_poll,tc)622740a9bfaSAlan Somers ATF_TC_BODY(socket_poll, tc)
623740a9bfaSAlan Somers {
624022ca2fcSAlan Somers 	aio_unix_socketpair_test(poll, NULL, false);
625314b447fSAlan Somers }
626314b447fSAlan Somers 
627314b447fSAlan Somers ATF_TC_WITHOUT_HEAD(socket_signal);
ATF_TC_BODY(socket_signal,tc)628314b447fSAlan Somers ATF_TC_BODY(socket_signal, tc)
629314b447fSAlan Somers {
630022ca2fcSAlan Somers 	aio_unix_socketpair_test(poll_signaled, setup_signal(), false);
631740a9bfaSAlan Somers }
632740a9bfaSAlan Somers 
633740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(socket_suspend);
ATF_TC_BODY(socket_suspend,tc)634740a9bfaSAlan Somers ATF_TC_BODY(socket_suspend, tc)
635740a9bfaSAlan Somers {
636022ca2fcSAlan Somers 	aio_unix_socketpair_test(suspend, NULL, false);
637314b447fSAlan Somers }
638314b447fSAlan Somers 
639314b447fSAlan Somers ATF_TC_WITHOUT_HEAD(socket_thread);
ATF_TC_BODY(socket_thread,tc)640314b447fSAlan Somers ATF_TC_BODY(socket_thread, tc)
641314b447fSAlan Somers {
642022ca2fcSAlan Somers 	aio_unix_socketpair_test(poll_signaled, setup_thread(), false);
643740a9bfaSAlan Somers }
644740a9bfaSAlan Somers 
645740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(socket_waitcomplete);
ATF_TC_BODY(socket_waitcomplete,tc)646740a9bfaSAlan Somers ATF_TC_BODY(socket_waitcomplete, tc)
647740a9bfaSAlan Somers {
648022ca2fcSAlan Somers 	aio_unix_socketpair_test(waitcomplete, NULL, false);
649740a9bfaSAlan Somers }
650740a9bfaSAlan Somers 
651f44eb013SEnji Cooper struct aio_pty_arg {
652f44eb013SEnji Cooper 	int	apa_read_fd;
653f44eb013SEnji Cooper 	int	apa_write_fd;
654f44eb013SEnji Cooper };
655f44eb013SEnji Cooper 
656f44eb013SEnji Cooper #define	PTY_LEN		256
657740a9bfaSAlan Somers static void
aio_pty_test(completion comp,struct sigevent * sev)658314b447fSAlan Somers aio_pty_test(completion comp, struct sigevent *sev)
659f44eb013SEnji Cooper {
660f44eb013SEnji Cooper 	struct aio_context ac;
661f44eb013SEnji Cooper 	int read_fd, write_fd;
662f44eb013SEnji Cooper 	struct termios ts;
663f44eb013SEnji Cooper 	int error;
664f44eb013SEnji Cooper 
665c5dfa43aSEnji Cooper 	ATF_REQUIRE_KERNEL_MODULE("aio");
666f3215338SJohn Baldwin 	ATF_REQUIRE_UNSAFE_AIO();
667f44eb013SEnji Cooper 
668f44eb013SEnji Cooper 	ATF_REQUIRE_MSG(openpty(&read_fd, &write_fd, NULL, NULL, NULL) == 0,
669f44eb013SEnji Cooper 	    "openpty failed: %s", strerror(errno));
670f44eb013SEnji Cooper 
671f44eb013SEnji Cooper 
672f44eb013SEnji Cooper 	if (tcgetattr(write_fd, &ts) < 0) {
673f44eb013SEnji Cooper 		error = errno;
674f44eb013SEnji Cooper 		errno = error;
675f44eb013SEnji Cooper 		atf_tc_fail("tcgetattr failed: %s", strerror(errno));
676f44eb013SEnji Cooper 	}
677f44eb013SEnji Cooper 	cfmakeraw(&ts);
678f44eb013SEnji Cooper 	if (tcsetattr(write_fd, TCSANOW, &ts) < 0) {
679f44eb013SEnji Cooper 		error = errno;
680f44eb013SEnji Cooper 		errno = error;
681f44eb013SEnji Cooper 		atf_tc_fail("tcsetattr failed: %s", strerror(errno));
682f44eb013SEnji Cooper 	}
683d600f474SAlan Somers 	aio_context_init(&ac, read_fd, write_fd, PTY_LEN);
684f44eb013SEnji Cooper 
685314b447fSAlan Somers 	aio_write_test(&ac, comp, sev);
686314b447fSAlan Somers 	aio_read_test(&ac, comp, sev);
687f44eb013SEnji Cooper 
688d600f474SAlan Somers 	close(read_fd);
689d600f474SAlan Somers 	close(write_fd);
690f44eb013SEnji Cooper }
691f44eb013SEnji Cooper 
69257082ce8SAlan Somers ATF_TC_WITHOUT_HEAD(pty_kq);
ATF_TC_BODY(pty_kq,tc)69357082ce8SAlan Somers ATF_TC_BODY(pty_kq, tc)
69457082ce8SAlan Somers {
69557082ce8SAlan Somers 	aio_pty_test(poll_kqueue, setup_kqueue());
69657082ce8SAlan Somers }
69757082ce8SAlan Somers 
698740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(pty_poll);
ATF_TC_BODY(pty_poll,tc)699740a9bfaSAlan Somers ATF_TC_BODY(pty_poll, tc)
700740a9bfaSAlan Somers {
701314b447fSAlan Somers 	aio_pty_test(poll, NULL);
702314b447fSAlan Somers }
703314b447fSAlan Somers 
704314b447fSAlan Somers ATF_TC_WITHOUT_HEAD(pty_signal);
ATF_TC_BODY(pty_signal,tc)705314b447fSAlan Somers ATF_TC_BODY(pty_signal, tc)
706314b447fSAlan Somers {
707314b447fSAlan Somers 	aio_pty_test(poll_signaled, setup_signal());
708740a9bfaSAlan Somers }
709740a9bfaSAlan Somers 
710740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(pty_suspend);
ATF_TC_BODY(pty_suspend,tc)711740a9bfaSAlan Somers ATF_TC_BODY(pty_suspend, tc)
712740a9bfaSAlan Somers {
713314b447fSAlan Somers 	aio_pty_test(suspend, NULL);
714314b447fSAlan Somers }
715314b447fSAlan Somers 
716314b447fSAlan Somers ATF_TC_WITHOUT_HEAD(pty_thread);
ATF_TC_BODY(pty_thread,tc)717314b447fSAlan Somers ATF_TC_BODY(pty_thread, tc)
718314b447fSAlan Somers {
719314b447fSAlan Somers 	aio_pty_test(poll_signaled, setup_thread());
720740a9bfaSAlan Somers }
721740a9bfaSAlan Somers 
722740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(pty_waitcomplete);
ATF_TC_BODY(pty_waitcomplete,tc)723740a9bfaSAlan Somers ATF_TC_BODY(pty_waitcomplete, tc)
724740a9bfaSAlan Somers {
725314b447fSAlan Somers 	aio_pty_test(waitcomplete, NULL);
726740a9bfaSAlan Somers }
727740a9bfaSAlan Somers 
728f44eb013SEnji Cooper #define	PIPE_LEN	256
729740a9bfaSAlan Somers static void
aio_pipe_test(completion comp,struct sigevent * sev)730314b447fSAlan Somers aio_pipe_test(completion comp, struct sigevent *sev)
731f44eb013SEnji Cooper {
732f44eb013SEnji Cooper 	struct aio_context ac;
733f44eb013SEnji Cooper 	int pipes[2];
734f44eb013SEnji Cooper 
735c5dfa43aSEnji Cooper 	ATF_REQUIRE_KERNEL_MODULE("aio");
736f3215338SJohn Baldwin 	ATF_REQUIRE_UNSAFE_AIO();
737f44eb013SEnji Cooper 
738f44eb013SEnji Cooper 	ATF_REQUIRE_MSG(pipe(pipes) != -1,
739f44eb013SEnji Cooper 	    "pipe failed: %s", strerror(errno));
740f44eb013SEnji Cooper 
741d600f474SAlan Somers 	aio_context_init(&ac, pipes[0], pipes[1], PIPE_LEN);
742314b447fSAlan Somers 	aio_write_test(&ac, comp, sev);
743314b447fSAlan Somers 	aio_read_test(&ac, comp, sev);
744f44eb013SEnji Cooper 
745d600f474SAlan Somers 	close(pipes[0]);
746d600f474SAlan Somers 	close(pipes[1]);
747f44eb013SEnji Cooper }
748f44eb013SEnji Cooper 
74957082ce8SAlan Somers ATF_TC_WITHOUT_HEAD(pipe_kq);
ATF_TC_BODY(pipe_kq,tc)75057082ce8SAlan Somers ATF_TC_BODY(pipe_kq, tc)
75157082ce8SAlan Somers {
75257082ce8SAlan Somers 	aio_pipe_test(poll_kqueue, setup_kqueue());
75357082ce8SAlan Somers }
75457082ce8SAlan Somers 
755740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(pipe_poll);
ATF_TC_BODY(pipe_poll,tc)756740a9bfaSAlan Somers ATF_TC_BODY(pipe_poll, tc)
757740a9bfaSAlan Somers {
758314b447fSAlan Somers 	aio_pipe_test(poll, NULL);
759314b447fSAlan Somers }
760314b447fSAlan Somers 
761314b447fSAlan Somers ATF_TC_WITHOUT_HEAD(pipe_signal);
ATF_TC_BODY(pipe_signal,tc)762314b447fSAlan Somers ATF_TC_BODY(pipe_signal, tc)
763314b447fSAlan Somers {
764314b447fSAlan Somers 	aio_pipe_test(poll_signaled, setup_signal());
765740a9bfaSAlan Somers }
766740a9bfaSAlan Somers 
767740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(pipe_suspend);
ATF_TC_BODY(pipe_suspend,tc)768740a9bfaSAlan Somers ATF_TC_BODY(pipe_suspend, tc)
769740a9bfaSAlan Somers {
770314b447fSAlan Somers 	aio_pipe_test(suspend, NULL);
771314b447fSAlan Somers }
772314b447fSAlan Somers 
773314b447fSAlan Somers ATF_TC_WITHOUT_HEAD(pipe_thread);
ATF_TC_BODY(pipe_thread,tc)774314b447fSAlan Somers ATF_TC_BODY(pipe_thread, tc)
775314b447fSAlan Somers {
776314b447fSAlan Somers 	aio_pipe_test(poll_signaled, setup_thread());
777740a9bfaSAlan Somers }
778740a9bfaSAlan Somers 
779740a9bfaSAlan Somers ATF_TC_WITHOUT_HEAD(pipe_waitcomplete);
ATF_TC_BODY(pipe_waitcomplete,tc)780740a9bfaSAlan Somers ATF_TC_BODY(pipe_waitcomplete, tc)
781740a9bfaSAlan Somers {
782314b447fSAlan Somers 	aio_pipe_test(waitcomplete, NULL);
783740a9bfaSAlan Somers }
784740a9bfaSAlan Somers 
785d600f474SAlan Somers #define	MD_LEN		GLOBAL_MAX
786d600f474SAlan Somers #define	MDUNIT_LINK	"mdunit_link"
787f44eb013SEnji Cooper 
788022ca2fcSAlan Somers static int
aio_md_setup(void)789022ca2fcSAlan Somers aio_md_setup(void)
790f44eb013SEnji Cooper {
791f44eb013SEnji Cooper 	int error, fd, mdctl_fd, unit;
792f44eb013SEnji Cooper 	char pathname[PATH_MAX];
793f44eb013SEnji Cooper 	struct md_ioctl mdio;
794d600f474SAlan Somers 	char buf[80];
795f44eb013SEnji Cooper 
796c5dfa43aSEnji Cooper 	ATF_REQUIRE_KERNEL_MODULE("aio");
797f44eb013SEnji Cooper 
798f44eb013SEnji Cooper 	mdctl_fd = open("/dev/" MDCTL_NAME, O_RDWR, 0);
799f44eb013SEnji Cooper 	ATF_REQUIRE_MSG(mdctl_fd != -1,
800f44eb013SEnji Cooper 	    "opening /dev/%s failed: %s", MDCTL_NAME, strerror(errno));
801f44eb013SEnji Cooper 
802f44eb013SEnji Cooper 	bzero(&mdio, sizeof(mdio));
803f44eb013SEnji Cooper 	mdio.md_version = MDIOVERSION;
804f44eb013SEnji Cooper 	mdio.md_type = MD_MALLOC;
805f44eb013SEnji Cooper 	mdio.md_options = MD_AUTOUNIT | MD_COMPRESS;
806f44eb013SEnji Cooper 	mdio.md_mediasize = GLOBAL_MAX;
807f44eb013SEnji Cooper 	mdio.md_sectorsize = 512;
8089666cda9SEric van Gyzen 	strlcpy(buf, __func__, sizeof(buf));
8099666cda9SEric van Gyzen 	mdio.md_label = buf;
810f44eb013SEnji Cooper 
811f44eb013SEnji Cooper 	if (ioctl(mdctl_fd, MDIOCATTACH, &mdio) < 0) {
812f44eb013SEnji Cooper 		error = errno;
813f44eb013SEnji Cooper 		errno = error;
814f44eb013SEnji Cooper 		atf_tc_fail("ioctl MDIOCATTACH failed: %s", strerror(errno));
815f44eb013SEnji Cooper 	}
816d600f474SAlan Somers 	close(mdctl_fd);
817f44eb013SEnji Cooper 
818d600f474SAlan Somers 	/* Store the md unit number in a symlink for future cleanup */
819d600f474SAlan Somers 	unit = mdio.md_unit;
820d600f474SAlan Somers 	snprintf(buf, sizeof(buf), "%d", unit);
821d600f474SAlan Somers 	ATF_REQUIRE_EQ(0, symlink(buf, MDUNIT_LINK));
822f44eb013SEnji Cooper 	snprintf(pathname, PATH_MAX, "/dev/md%d", unit);
823f44eb013SEnji Cooper 	fd = open(pathname, O_RDWR);
824f44eb013SEnji Cooper 	ATF_REQUIRE_MSG(fd != -1,
825f44eb013SEnji Cooper 	    "opening %s failed: %s", pathname, strerror(errno));
826f44eb013SEnji Cooper 
827022ca2fcSAlan Somers 	return (fd);
828022ca2fcSAlan Somers }
829022ca2fcSAlan Somers 
830022ca2fcSAlan Somers static void
aio_md_cleanup(void)831022ca2fcSAlan Somers aio_md_cleanup(void)
832022ca2fcSAlan Somers {
833022ca2fcSAlan Somers 	struct md_ioctl mdio;
834c6f92e64SEric van Gyzen 	int mdctl_fd, n, unit;
835022ca2fcSAlan Somers 	char buf[80];
836022ca2fcSAlan Somers 
837022ca2fcSAlan Somers 	mdctl_fd = open("/dev/" MDCTL_NAME, O_RDWR, 0);
838c6f92e64SEric van Gyzen 	if (mdctl_fd < 0) {
839c6f92e64SEric van Gyzen 		fprintf(stderr, "opening /dev/%s failed: %s\n", MDCTL_NAME,
840c6f92e64SEric van Gyzen 		    strerror(errno));
841c6f92e64SEric van Gyzen 		return;
842c6f92e64SEric van Gyzen 	}
843ea0e1b19SEric van Gyzen 	n = readlink(MDUNIT_LINK, buf, sizeof(buf) - 1);
844022ca2fcSAlan Somers 	if (n > 0) {
845ea0e1b19SEric van Gyzen 		buf[n] = '\0';
846022ca2fcSAlan Somers 		if (sscanf(buf, "%d", &unit) == 1 && unit >= 0) {
847022ca2fcSAlan Somers 			bzero(&mdio, sizeof(mdio));
848022ca2fcSAlan Somers 			mdio.md_version = MDIOVERSION;
849022ca2fcSAlan Somers 			mdio.md_unit = unit;
850022ca2fcSAlan Somers 			if (ioctl(mdctl_fd, MDIOCDETACH, &mdio) == -1) {
851c6f92e64SEric van Gyzen 				fprintf(stderr,
852c6f92e64SEric van Gyzen 				    "ioctl MDIOCDETACH unit %d failed: %s\n",
853c6f92e64SEric van Gyzen 				    unit, strerror(errno));
854022ca2fcSAlan Somers 			}
855022ca2fcSAlan Somers 		}
856022ca2fcSAlan Somers 	}
857022ca2fcSAlan Somers 
858022ca2fcSAlan Somers 	close(mdctl_fd);
859022ca2fcSAlan Somers }
860022ca2fcSAlan Somers 
861022ca2fcSAlan Somers static void
aio_md_test(completion comp,struct sigevent * sev,bool vectored)862022ca2fcSAlan Somers aio_md_test(completion comp, struct sigevent *sev, bool vectored)
863022ca2fcSAlan Somers {
864022ca2fcSAlan Somers 	struct aio_context ac;
865022ca2fcSAlan Somers 	int fd;
866022ca2fcSAlan Somers 
867022ca2fcSAlan Somers 	fd = aio_md_setup();
868d600f474SAlan Somers 	aio_context_init(&ac, fd, fd, MD_LEN);
869022ca2fcSAlan Somers 	if (vectored) {
870022ca2fcSAlan Somers 		aio_writev_test(&ac, comp, sev);
871022ca2fcSAlan Somers 		aio_readv_test(&ac, comp, sev);
872022ca2fcSAlan Somers 	} else {
873314b447fSAlan Somers 		aio_write_test(&ac, comp, sev);
874314b447fSAlan Somers 		aio_read_test(&ac, comp, sev);
875022ca2fcSAlan Somers 	}
876f44eb013SEnji Cooper 
877d600f474SAlan Somers 	close(fd);
878f44eb013SEnji Cooper }
879f44eb013SEnji Cooper 
88057082ce8SAlan Somers ATF_TC_WITH_CLEANUP(md_kq);
ATF_TC_HEAD(md_kq,tc)88157082ce8SAlan Somers ATF_TC_HEAD(md_kq, tc)
88257082ce8SAlan Somers {
88357082ce8SAlan Somers 
88457082ce8SAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
88557082ce8SAlan Somers }
ATF_TC_BODY(md_kq,tc)88657082ce8SAlan Somers ATF_TC_BODY(md_kq, tc)
88757082ce8SAlan Somers {
88857082ce8SAlan Somers 	aio_md_test(poll_kqueue, setup_kqueue(), false);
88957082ce8SAlan Somers }
ATF_TC_CLEANUP(md_kq,tc)89057082ce8SAlan Somers ATF_TC_CLEANUP(md_kq, tc)
89157082ce8SAlan Somers {
89257082ce8SAlan Somers 	aio_md_cleanup();
89357082ce8SAlan Somers }
89457082ce8SAlan Somers 
895d600f474SAlan Somers ATF_TC_WITH_CLEANUP(md_poll);
ATF_TC_HEAD(md_poll,tc)896740a9bfaSAlan Somers ATF_TC_HEAD(md_poll, tc)
897740a9bfaSAlan Somers {
898740a9bfaSAlan Somers 
899740a9bfaSAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
900740a9bfaSAlan Somers }
ATF_TC_BODY(md_poll,tc)901740a9bfaSAlan Somers ATF_TC_BODY(md_poll, tc)
902740a9bfaSAlan Somers {
903022ca2fcSAlan Somers 	aio_md_test(poll, NULL, false);
904740a9bfaSAlan Somers }
ATF_TC_CLEANUP(md_poll,tc)905d600f474SAlan Somers ATF_TC_CLEANUP(md_poll, tc)
906d600f474SAlan Somers {
907d600f474SAlan Somers 	aio_md_cleanup();
908d600f474SAlan Somers }
909740a9bfaSAlan Somers 
910314b447fSAlan Somers ATF_TC_WITH_CLEANUP(md_signal);
ATF_TC_HEAD(md_signal,tc)911314b447fSAlan Somers ATF_TC_HEAD(md_signal, tc)
912314b447fSAlan Somers {
913314b447fSAlan Somers 
914314b447fSAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
915314b447fSAlan Somers }
ATF_TC_BODY(md_signal,tc)916314b447fSAlan Somers ATF_TC_BODY(md_signal, tc)
917314b447fSAlan Somers {
918022ca2fcSAlan Somers 	aio_md_test(poll_signaled, setup_signal(), false);
919314b447fSAlan Somers }
ATF_TC_CLEANUP(md_signal,tc)920314b447fSAlan Somers ATF_TC_CLEANUP(md_signal, tc)
921314b447fSAlan Somers {
922314b447fSAlan Somers 	aio_md_cleanup();
923314b447fSAlan Somers }
924314b447fSAlan Somers 
925d600f474SAlan Somers ATF_TC_WITH_CLEANUP(md_suspend);
ATF_TC_HEAD(md_suspend,tc)926740a9bfaSAlan Somers ATF_TC_HEAD(md_suspend, tc)
927740a9bfaSAlan Somers {
928740a9bfaSAlan Somers 
929740a9bfaSAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
930740a9bfaSAlan Somers }
ATF_TC_BODY(md_suspend,tc)931740a9bfaSAlan Somers ATF_TC_BODY(md_suspend, tc)
932740a9bfaSAlan Somers {
933022ca2fcSAlan Somers 	aio_md_test(suspend, NULL, false);
934740a9bfaSAlan Somers }
ATF_TC_CLEANUP(md_suspend,tc)935d600f474SAlan Somers ATF_TC_CLEANUP(md_suspend, tc)
936d600f474SAlan Somers {
937d600f474SAlan Somers 	aio_md_cleanup();
938d600f474SAlan Somers }
939740a9bfaSAlan Somers 
940314b447fSAlan Somers ATF_TC_WITH_CLEANUP(md_thread);
ATF_TC_HEAD(md_thread,tc)941314b447fSAlan Somers ATF_TC_HEAD(md_thread, tc)
942314b447fSAlan Somers {
943314b447fSAlan Somers 
944314b447fSAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
945314b447fSAlan Somers }
ATF_TC_BODY(md_thread,tc)946314b447fSAlan Somers ATF_TC_BODY(md_thread, tc)
947314b447fSAlan Somers {
948022ca2fcSAlan Somers 	aio_md_test(poll_signaled, setup_thread(), false);
949314b447fSAlan Somers }
ATF_TC_CLEANUP(md_thread,tc)950314b447fSAlan Somers ATF_TC_CLEANUP(md_thread, tc)
951314b447fSAlan Somers {
952314b447fSAlan Somers 	aio_md_cleanup();
953314b447fSAlan Somers }
954314b447fSAlan Somers 
955d600f474SAlan Somers ATF_TC_WITH_CLEANUP(md_waitcomplete);
ATF_TC_HEAD(md_waitcomplete,tc)956740a9bfaSAlan Somers ATF_TC_HEAD(md_waitcomplete, tc)
957740a9bfaSAlan Somers {
958740a9bfaSAlan Somers 
959740a9bfaSAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
960740a9bfaSAlan Somers }
ATF_TC_BODY(md_waitcomplete,tc)961740a9bfaSAlan Somers ATF_TC_BODY(md_waitcomplete, tc)
962740a9bfaSAlan Somers {
963022ca2fcSAlan Somers 	aio_md_test(waitcomplete, NULL, false);
964740a9bfaSAlan Somers }
ATF_TC_CLEANUP(md_waitcomplete,tc)965d600f474SAlan Somers ATF_TC_CLEANUP(md_waitcomplete, tc)
966d600f474SAlan Somers {
967d600f474SAlan Somers 	aio_md_cleanup();
968d600f474SAlan Somers }
969740a9bfaSAlan Somers 
970022ca2fcSAlan Somers #define	ZVOL_VDEV_PATHNAME	"test_vdev"
971022ca2fcSAlan Somers #define POOL_SIZE		(1 << 28)	/* 256 MB */
972022ca2fcSAlan Somers #define ZVOL_SIZE		"64m"
973022ca2fcSAlan Somers #define POOL_NAME		"aio_testpool"
974022ca2fcSAlan Somers #define ZVOL_NAME		"aio_testvol"
975022ca2fcSAlan Somers 
976022ca2fcSAlan Somers static int
aio_zvol_setup(const char * unique)977*9cefc0fbSMark Johnston aio_zvol_setup(const char *unique)
978022ca2fcSAlan Somers {
979022ca2fcSAlan Somers 	FILE *pidfile;
980022ca2fcSAlan Somers 	int fd;
981022ca2fcSAlan Somers 	pid_t pid;
982*9cefc0fbSMark Johnston 	char vdev_name[160];
983022ca2fcSAlan Somers 	char pool_name[80];
984022ca2fcSAlan Somers 	char cmd[160];
985022ca2fcSAlan Somers 	char zvol_name[160];
986022ca2fcSAlan Somers 	char devname[160];
987022ca2fcSAlan Somers 
988022ca2fcSAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("aio");
989022ca2fcSAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("zfs");
990022ca2fcSAlan Somers 
991*9cefc0fbSMark Johnston 	pid = getpid();
992*9cefc0fbSMark Johnston 	snprintf(vdev_name, sizeof(vdev_name), "%s", ZVOL_VDEV_PATHNAME);
993*9cefc0fbSMark Johnston 	snprintf(pool_name, sizeof(pool_name), "%s_%s.%d", POOL_NAME, unique,
994*9cefc0fbSMark Johnston 	    pid);
995*9cefc0fbSMark Johnston 	snprintf(zvol_name, sizeof(zvol_name), "%s/%s_%s", pool_name, ZVOL_NAME,
996*9cefc0fbSMark Johnston 	    unique);
997*9cefc0fbSMark Johnston 
998*9cefc0fbSMark Johnston 	fd = open(vdev_name, O_RDWR | O_CREAT, 0600);
999022ca2fcSAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1000022ca2fcSAlan Somers 	ATF_REQUIRE_EQ_MSG(0,
1001022ca2fcSAlan Somers 	    ftruncate(fd, POOL_SIZE), "ftruncate failed: %s", strerror(errno));
1002022ca2fcSAlan Somers 	close(fd);
1003022ca2fcSAlan Somers 
1004022ca2fcSAlan Somers 	pidfile = fopen("pidfile", "w");
1005022ca2fcSAlan Somers 	ATF_REQUIRE_MSG(NULL != pidfile, "fopen: %s", strerror(errno));
1006022ca2fcSAlan Somers 	fprintf(pidfile, "%d", pid);
1007022ca2fcSAlan Somers 	fclose(pidfile);
1008022ca2fcSAlan Somers 
1009*9cefc0fbSMark Johnston 	snprintf(cmd, sizeof(cmd), "zpool create %s $PWD/%s", pool_name,
1010*9cefc0fbSMark Johnston 	    vdev_name);
1011022ca2fcSAlan Somers 	ATF_REQUIRE_EQ_MSG(0, system(cmd),
1012022ca2fcSAlan Somers 	    "zpool create failed: %s", strerror(errno));
1013022ca2fcSAlan Somers 	snprintf(cmd, sizeof(cmd),
1014*9cefc0fbSMark Johnston 	    "zfs create -o volblocksize=8192 -o volmode=dev -V %s %s",
1015*9cefc0fbSMark Johnston 	    ZVOL_SIZE, zvol_name);
1016022ca2fcSAlan Somers 	ATF_REQUIRE_EQ_MSG(0, system(cmd),
1017022ca2fcSAlan Somers 	    "zfs create failed: %s", strerror(errno));
1018022ca2fcSAlan Somers 
1019022ca2fcSAlan Somers 	snprintf(devname, sizeof(devname), "/dev/zvol/%s", zvol_name);
1020022ca2fcSAlan Somers 	do {
1021022ca2fcSAlan Somers 		fd = open(devname, O_RDWR);
1022022ca2fcSAlan Somers 	} while (fd == -1 && errno == EINTR);
1023022ca2fcSAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1024022ca2fcSAlan Somers 	return (fd);
1025022ca2fcSAlan Somers }
1026022ca2fcSAlan Somers 
1027022ca2fcSAlan Somers static void
aio_zvol_cleanup(const char * unique)1028*9cefc0fbSMark Johnston aio_zvol_cleanup(const char *unique)
1029022ca2fcSAlan Somers {
1030022ca2fcSAlan Somers 	FILE *pidfile;
1031022ca2fcSAlan Somers 	pid_t testpid;
1032022ca2fcSAlan Somers 	char cmd[160];
1033022ca2fcSAlan Somers 
1034022ca2fcSAlan Somers 	pidfile = fopen("pidfile", "r");
103519cca0b9SAlan Somers 	if (pidfile == NULL && errno == ENOENT) {
103619cca0b9SAlan Somers 		/* Setup probably failed */
103719cca0b9SAlan Somers 		return;
103819cca0b9SAlan Somers 	}
1039022ca2fcSAlan Somers 	ATF_REQUIRE_MSG(NULL != pidfile, "fopen: %s", strerror(errno));
1040022ca2fcSAlan Somers 	ATF_REQUIRE_EQ(1, fscanf(pidfile, "%d", &testpid));
1041022ca2fcSAlan Somers 	fclose(pidfile);
1042022ca2fcSAlan Somers 
1043*9cefc0fbSMark Johnston 	snprintf(cmd, sizeof(cmd), "zpool destroy %s_%s.%d", POOL_NAME, unique,
1044*9cefc0fbSMark Johnston 	    testpid);
1045022ca2fcSAlan Somers 	system(cmd);
1046022ca2fcSAlan Somers }
1047022ca2fcSAlan Somers 
1048022ca2fcSAlan Somers 
1049bb430bc7SJohn Baldwin ATF_TC_WITHOUT_HEAD(aio_large_read_test);
ATF_TC_BODY(aio_large_read_test,tc)1050bb430bc7SJohn Baldwin ATF_TC_BODY(aio_large_read_test, tc)
1051bb430bc7SJohn Baldwin {
1052bb430bc7SJohn Baldwin 	struct aiocb cb, *cbp;
1053bb430bc7SJohn Baldwin 	ssize_t nread;
1054bb430bc7SJohn Baldwin 	size_t len;
1055bb430bc7SJohn Baldwin 	int fd;
1056bb430bc7SJohn Baldwin #ifdef __LP64__
1057bb430bc7SJohn Baldwin 	int clamped;
1058bb430bc7SJohn Baldwin #endif
1059bb430bc7SJohn Baldwin 
1060bb430bc7SJohn Baldwin 	ATF_REQUIRE_KERNEL_MODULE("aio");
1061bb430bc7SJohn Baldwin 	ATF_REQUIRE_UNSAFE_AIO();
1062bb430bc7SJohn Baldwin 
1063bb430bc7SJohn Baldwin #ifdef __LP64__
1064bb430bc7SJohn Baldwin 	len = sizeof(clamped);
1065bb430bc7SJohn Baldwin 	if (sysctlbyname("debug.iosize_max_clamp", &clamped, &len, NULL, 0) ==
1066bb430bc7SJohn Baldwin 	    -1)
1067bb430bc7SJohn Baldwin 		atf_libc_error(errno, "Failed to read debug.iosize_max_clamp");
1068bb430bc7SJohn Baldwin #endif
1069bb430bc7SJohn Baldwin 
1070bb430bc7SJohn Baldwin 	/* Determine the maximum supported read(2) size. */
1071bb430bc7SJohn Baldwin 	len = SSIZE_MAX;
1072bb430bc7SJohn Baldwin #ifdef __LP64__
1073bb430bc7SJohn Baldwin 	if (clamped)
1074bb430bc7SJohn Baldwin 		len = INT_MAX;
1075bb430bc7SJohn Baldwin #endif
1076bb430bc7SJohn Baldwin 
10779086b30bSJilles Tjoelker 	fd = open(FILE_PATHNAME, O_RDWR | O_CREAT, 0600);
1078740a9bfaSAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1079bb430bc7SJohn Baldwin 
1080740a9bfaSAlan Somers 	unlink(FILE_PATHNAME);
1081bb430bc7SJohn Baldwin 
1082bb430bc7SJohn Baldwin 	memset(&cb, 0, sizeof(cb));
1083bb430bc7SJohn Baldwin 	cb.aio_nbytes = len;
1084bb430bc7SJohn Baldwin 	cb.aio_fildes = fd;
1085bb430bc7SJohn Baldwin 	cb.aio_buf = NULL;
1086bb430bc7SJohn Baldwin 	if (aio_read(&cb) == -1)
1087bb430bc7SJohn Baldwin 		atf_tc_fail("aio_read() of maximum read size failed: %s",
1088bb430bc7SJohn Baldwin 		    strerror(errno));
1089bb430bc7SJohn Baldwin 
1090bb430bc7SJohn Baldwin 	nread = aio_waitcomplete(&cbp, NULL);
1091bb430bc7SJohn Baldwin 	if (nread == -1)
1092bb430bc7SJohn Baldwin 		atf_tc_fail("aio_waitcomplete() failed: %s", strerror(errno));
1093bb430bc7SJohn Baldwin 	if (nread != 0)
1094c03094a4SJohn Baldwin 		atf_tc_fail("aio_read() from empty file returned data: %zd",
1095bb430bc7SJohn Baldwin 		    nread);
1096bb430bc7SJohn Baldwin 
1097bb430bc7SJohn Baldwin 	memset(&cb, 0, sizeof(cb));
1098bb430bc7SJohn Baldwin 	cb.aio_nbytes = len + 1;
1099bb430bc7SJohn Baldwin 	cb.aio_fildes = fd;
1100bb430bc7SJohn Baldwin 	cb.aio_buf = NULL;
1101bb430bc7SJohn Baldwin 	if (aio_read(&cb) == -1) {
1102bb430bc7SJohn Baldwin 		if (errno == EINVAL)
1103bb430bc7SJohn Baldwin 			goto finished;
1104bb430bc7SJohn Baldwin 		atf_tc_fail("aio_read() of too large read size failed: %s",
1105bb430bc7SJohn Baldwin 		    strerror(errno));
1106bb430bc7SJohn Baldwin 	}
1107bb430bc7SJohn Baldwin 
1108bb430bc7SJohn Baldwin 	nread = aio_waitcomplete(&cbp, NULL);
1109bb430bc7SJohn Baldwin 	if (nread == -1) {
1110bb430bc7SJohn Baldwin 		if (errno == EINVAL)
1111bb430bc7SJohn Baldwin 			goto finished;
1112bb430bc7SJohn Baldwin 		atf_tc_fail("aio_waitcomplete() failed: %s", strerror(errno));
1113bb430bc7SJohn Baldwin 	}
1114c03094a4SJohn Baldwin 	atf_tc_fail("aio_read() of too large read size returned: %zd", nread);
1115bb430bc7SJohn Baldwin 
1116bb430bc7SJohn Baldwin finished:
1117bb430bc7SJohn Baldwin 	close(fd);
1118bb430bc7SJohn Baldwin }
1119bb430bc7SJohn Baldwin 
1120d1ad1a73SJohn Baldwin /*
1121d1ad1a73SJohn Baldwin  * This tests for a bug where arriving socket data can wakeup multiple
1122d1ad1a73SJohn Baldwin  * AIO read requests resulting in an uncancellable request.
1123d1ad1a73SJohn Baldwin  */
1124d1ad1a73SJohn Baldwin ATF_TC_WITHOUT_HEAD(aio_socket_two_reads);
ATF_TC_BODY(aio_socket_two_reads,tc)1125d1ad1a73SJohn Baldwin ATF_TC_BODY(aio_socket_two_reads, tc)
1126d1ad1a73SJohn Baldwin {
1127d1ad1a73SJohn Baldwin 	struct ioreq {
1128d1ad1a73SJohn Baldwin 		struct aiocb iocb;
1129d1ad1a73SJohn Baldwin 		char buffer[1024];
1130d1ad1a73SJohn Baldwin 	} ioreq[2];
1131d1ad1a73SJohn Baldwin 	struct aiocb *iocb;
1132d1ad1a73SJohn Baldwin 	unsigned i;
1133d1ad1a73SJohn Baldwin 	int s[2];
1134d1ad1a73SJohn Baldwin 	char c;
1135d1ad1a73SJohn Baldwin 
1136d1ad1a73SJohn Baldwin 	ATF_REQUIRE_KERNEL_MODULE("aio");
1137d1ad1a73SJohn Baldwin #if __FreeBSD_version < 1100101
1138d1ad1a73SJohn Baldwin 	aft_tc_skip("kernel version %d is too old (%d required)",
1139d1ad1a73SJohn Baldwin 	    __FreeBSD_version, 1100101);
1140d1ad1a73SJohn Baldwin #endif
1141d1ad1a73SJohn Baldwin 
1142d1ad1a73SJohn Baldwin 	ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, s) != -1);
1143d1ad1a73SJohn Baldwin 
1144d1ad1a73SJohn Baldwin 	/* Queue two read requests. */
1145d1ad1a73SJohn Baldwin 	memset(&ioreq, 0, sizeof(ioreq));
1146d1ad1a73SJohn Baldwin 	for (i = 0; i < nitems(ioreq); i++) {
1147d1ad1a73SJohn Baldwin 		ioreq[i].iocb.aio_nbytes = sizeof(ioreq[i].buffer);
1148d1ad1a73SJohn Baldwin 		ioreq[i].iocb.aio_fildes = s[0];
1149d1ad1a73SJohn Baldwin 		ioreq[i].iocb.aio_buf = ioreq[i].buffer;
1150d1ad1a73SJohn Baldwin 		ATF_REQUIRE(aio_read(&ioreq[i].iocb) == 0);
1151d1ad1a73SJohn Baldwin 	}
1152d1ad1a73SJohn Baldwin 
1153d1ad1a73SJohn Baldwin 	/* Send a single byte.  This should complete one request. */
1154d1ad1a73SJohn Baldwin 	c = 0xc3;
1155d1ad1a73SJohn Baldwin 	ATF_REQUIRE(write(s[1], &c, sizeof(c)) == 1);
1156d1ad1a73SJohn Baldwin 
1157d1ad1a73SJohn Baldwin 	ATF_REQUIRE(aio_waitcomplete(&iocb, NULL) == 1);
1158d1ad1a73SJohn Baldwin 
1159d1ad1a73SJohn Baldwin 	/* Determine which request completed and verify the data was read. */
1160d1ad1a73SJohn Baldwin 	if (iocb == &ioreq[0].iocb)
1161d1ad1a73SJohn Baldwin 		i = 0;
1162d1ad1a73SJohn Baldwin 	else
1163d1ad1a73SJohn Baldwin 		i = 1;
1164d1ad1a73SJohn Baldwin 	ATF_REQUIRE(ioreq[i].buffer[0] == c);
1165d1ad1a73SJohn Baldwin 
1166d1ad1a73SJohn Baldwin 	i ^= 1;
1167d1ad1a73SJohn Baldwin 
1168d1ad1a73SJohn Baldwin 	/*
1169d1ad1a73SJohn Baldwin 	 * Try to cancel the other request.  On broken systems this
1170d1ad1a73SJohn Baldwin 	 * will fail and the process will hang on exit.
1171d1ad1a73SJohn Baldwin 	 */
1172d1ad1a73SJohn Baldwin 	ATF_REQUIRE(aio_error(&ioreq[i].iocb) == EINPROGRESS);
1173d1ad1a73SJohn Baldwin 	ATF_REQUIRE(aio_cancel(s[0], &ioreq[i].iocb) == AIO_CANCELED);
1174d1ad1a73SJohn Baldwin 
1175d1ad1a73SJohn Baldwin 	close(s[1]);
1176d1ad1a73SJohn Baldwin 	close(s[0]);
1177d1ad1a73SJohn Baldwin }
1178d1ad1a73SJohn Baldwin 
1179022ca2fcSAlan Somers static void
aio_socket_blocking_short_write_test(bool vectored)1180022ca2fcSAlan Somers aio_socket_blocking_short_write_test(bool vectored)
11811717b68aSJohn Baldwin {
11821717b68aSJohn Baldwin 	struct aiocb iocb, *iocbp;
1183022ca2fcSAlan Somers 	struct iovec iov[2];
11841717b68aSJohn Baldwin 	char *buffer[2];
1185022ca2fcSAlan Somers 	ssize_t done, r;
11861717b68aSJohn Baldwin 	int buffer_size, sb_size;
11871717b68aSJohn Baldwin 	socklen_t len;
11881717b68aSJohn Baldwin 	int s[2];
11891717b68aSJohn Baldwin 
11901717b68aSJohn Baldwin 	ATF_REQUIRE_KERNEL_MODULE("aio");
11911717b68aSJohn Baldwin 
11921717b68aSJohn Baldwin 	ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, s) != -1);
11931717b68aSJohn Baldwin 
11941717b68aSJohn Baldwin 	len = sizeof(sb_size);
11951717b68aSJohn Baldwin 	ATF_REQUIRE(getsockopt(s[0], SOL_SOCKET, SO_RCVBUF, &sb_size, &len) !=
11961717b68aSJohn Baldwin 	    -1);
11971717b68aSJohn Baldwin 	ATF_REQUIRE(len == sizeof(sb_size));
11981717b68aSJohn Baldwin 	buffer_size = sb_size;
11991717b68aSJohn Baldwin 
12001717b68aSJohn Baldwin 	ATF_REQUIRE(getsockopt(s[1], SOL_SOCKET, SO_SNDBUF, &sb_size, &len) !=
12011717b68aSJohn Baldwin 	    -1);
12021717b68aSJohn Baldwin 	ATF_REQUIRE(len == sizeof(sb_size));
12031717b68aSJohn Baldwin 	if (sb_size > buffer_size)
12041717b68aSJohn Baldwin 		buffer_size = sb_size;
12051717b68aSJohn Baldwin 
12061717b68aSJohn Baldwin 	/*
12071717b68aSJohn Baldwin 	 * Use twice the size of the MAX(receive buffer, send buffer)
12081717b68aSJohn Baldwin 	 * to ensure that the write is split up into multiple writes
12091717b68aSJohn Baldwin 	 * internally.
12101717b68aSJohn Baldwin 	 */
12111717b68aSJohn Baldwin 	buffer_size *= 2;
12121717b68aSJohn Baldwin 
12131717b68aSJohn Baldwin 	buffer[0] = malloc(buffer_size);
12141717b68aSJohn Baldwin 	ATF_REQUIRE(buffer[0] != NULL);
12151717b68aSJohn Baldwin 	buffer[1] = malloc(buffer_size);
12161717b68aSJohn Baldwin 	ATF_REQUIRE(buffer[1] != NULL);
12171717b68aSJohn Baldwin 
12181717b68aSJohn Baldwin 	srandomdev();
12191717b68aSJohn Baldwin 	aio_fill_buffer(buffer[1], buffer_size, random());
12201717b68aSJohn Baldwin 
12211717b68aSJohn Baldwin 	memset(&iocb, 0, sizeof(iocb));
12221717b68aSJohn Baldwin 	iocb.aio_fildes = s[1];
1223022ca2fcSAlan Somers 	if (vectored) {
1224022ca2fcSAlan Somers 		iov[0].iov_base = buffer[1];
1225022ca2fcSAlan Somers 		iov[0].iov_len = buffer_size / 2 + 1;
1226022ca2fcSAlan Somers 		iov[1].iov_base = buffer[1] + buffer_size / 2 + 1;
1227022ca2fcSAlan Somers 		iov[1].iov_len = buffer_size / 2 - 1;
1228022ca2fcSAlan Somers 		iocb.aio_iov = iov;
1229022ca2fcSAlan Somers 		iocb.aio_iovcnt = 2;
1230022ca2fcSAlan Somers 		r = aio_writev(&iocb);
1231022ca2fcSAlan Somers 		ATF_CHECK_EQ_MSG(0, r, "aio_writev returned %zd", r);
1232022ca2fcSAlan Somers 	} else {
12331717b68aSJohn Baldwin 		iocb.aio_buf = buffer[1];
12341717b68aSJohn Baldwin 		iocb.aio_nbytes = buffer_size;
1235022ca2fcSAlan Somers 		r = aio_write(&iocb);
1236022ca2fcSAlan Somers 		ATF_CHECK_EQ_MSG(0, r, "aio_writev returned %zd", r);
1237022ca2fcSAlan Somers 	}
12381717b68aSJohn Baldwin 
12391717b68aSJohn Baldwin 	done = recv(s[0], buffer[0], buffer_size, MSG_WAITALL);
12401717b68aSJohn Baldwin 	ATF_REQUIRE(done == buffer_size);
12411717b68aSJohn Baldwin 
12421717b68aSJohn Baldwin 	done = aio_waitcomplete(&iocbp, NULL);
12431717b68aSJohn Baldwin 	ATF_REQUIRE(iocbp == &iocb);
12441717b68aSJohn Baldwin 	ATF_REQUIRE(done == buffer_size);
12451717b68aSJohn Baldwin 
12461717b68aSJohn Baldwin 	ATF_REQUIRE(memcmp(buffer[0], buffer[1], buffer_size) == 0);
12471717b68aSJohn Baldwin 
12481717b68aSJohn Baldwin 	close(s[1]);
12491717b68aSJohn Baldwin 	close(s[0]);
12501717b68aSJohn Baldwin }
12511717b68aSJohn Baldwin 
1252778ce4f2SJohn Baldwin /*
1253022ca2fcSAlan Somers  * This test ensures that aio_write() on a blocking socket of a "large"
1254022ca2fcSAlan Somers  * buffer does not return a short completion.
1255022ca2fcSAlan Somers  */
1256022ca2fcSAlan Somers ATF_TC_WITHOUT_HEAD(aio_socket_blocking_short_write);
ATF_TC_BODY(aio_socket_blocking_short_write,tc)1257022ca2fcSAlan Somers ATF_TC_BODY(aio_socket_blocking_short_write, tc)
1258022ca2fcSAlan Somers {
1259022ca2fcSAlan Somers 	aio_socket_blocking_short_write_test(false);
1260022ca2fcSAlan Somers }
1261022ca2fcSAlan Somers 
1262022ca2fcSAlan Somers /*
1263022ca2fcSAlan Somers  * Like aio_socket_blocking_short_write, but also tests that partially
1264022ca2fcSAlan Somers  * completed vectored sends can be retried correctly.
1265022ca2fcSAlan Somers  */
1266022ca2fcSAlan Somers ATF_TC_WITHOUT_HEAD(aio_socket_blocking_short_write_vectored);
ATF_TC_BODY(aio_socket_blocking_short_write_vectored,tc)1267022ca2fcSAlan Somers ATF_TC_BODY(aio_socket_blocking_short_write_vectored, tc)
1268022ca2fcSAlan Somers {
1269022ca2fcSAlan Somers 	aio_socket_blocking_short_write_test(true);
1270022ca2fcSAlan Somers }
1271022ca2fcSAlan Somers 
1272022ca2fcSAlan Somers /*
1273141fe2dcSMark Johnston  * Verify that AIO requests fail when applied to a listening socket.
1274141fe2dcSMark Johnston  */
1275141fe2dcSMark Johnston ATF_TC_WITHOUT_HEAD(aio_socket_listen_fail);
ATF_TC_BODY(aio_socket_listen_fail,tc)1276141fe2dcSMark Johnston ATF_TC_BODY(aio_socket_listen_fail, tc)
1277141fe2dcSMark Johnston {
1278141fe2dcSMark Johnston 	struct aiocb iocb;
1279141fe2dcSMark Johnston 	struct sockaddr_un sun;
1280141fe2dcSMark Johnston 	char buf[16];
1281141fe2dcSMark Johnston 	int s;
1282141fe2dcSMark Johnston 
1283141fe2dcSMark Johnston 	s = socket(AF_LOCAL, SOCK_STREAM, 0);
1284141fe2dcSMark Johnston 	ATF_REQUIRE(s != -1);
1285141fe2dcSMark Johnston 
1286141fe2dcSMark Johnston 	memset(&sun, 0, sizeof(sun));
1287141fe2dcSMark Johnston 	snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", "listen.XXXXXX");
1288141fe2dcSMark Johnston 	mktemp(sun.sun_path);
1289141fe2dcSMark Johnston 	sun.sun_family = AF_LOCAL;
1290141fe2dcSMark Johnston 	sun.sun_len = SUN_LEN(&sun);
1291141fe2dcSMark Johnston 
1292141fe2dcSMark Johnston 	ATF_REQUIRE(bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) == 0);
1293141fe2dcSMark Johnston 	ATF_REQUIRE(listen(s, 5) == 0);
1294141fe2dcSMark Johnston 
1295141fe2dcSMark Johnston 	memset(buf, 0, sizeof(buf));
1296141fe2dcSMark Johnston 	memset(&iocb, 0, sizeof(iocb));
1297141fe2dcSMark Johnston 	iocb.aio_fildes = s;
1298141fe2dcSMark Johnston 	iocb.aio_buf = buf;
1299141fe2dcSMark Johnston 	iocb.aio_nbytes = sizeof(buf);
1300141fe2dcSMark Johnston 
1301141fe2dcSMark Johnston 	ATF_REQUIRE_ERRNO(EINVAL, aio_read(&iocb) == -1);
1302141fe2dcSMark Johnston 	ATF_REQUIRE_ERRNO(EINVAL, aio_write(&iocb) == -1);
1303141fe2dcSMark Johnston 
1304141fe2dcSMark Johnston 	ATF_REQUIRE(unlink(sun.sun_path) == 0);
1305141fe2dcSMark Johnston 	close(s);
1306141fe2dcSMark Johnston }
1307141fe2dcSMark Johnston 
1308141fe2dcSMark Johnston /*
1309141fe2dcSMark Johnston  * Verify that listen(2) fails if a socket has pending AIO requests.
1310141fe2dcSMark Johnston  */
1311141fe2dcSMark Johnston ATF_TC_WITHOUT_HEAD(aio_socket_listen_pending);
ATF_TC_BODY(aio_socket_listen_pending,tc)1312141fe2dcSMark Johnston ATF_TC_BODY(aio_socket_listen_pending, tc)
1313141fe2dcSMark Johnston {
1314141fe2dcSMark Johnston 	struct aiocb iocb;
1315141fe2dcSMark Johnston 	struct sockaddr_un sun;
1316141fe2dcSMark Johnston 	char buf[16];
1317141fe2dcSMark Johnston 	int s;
1318141fe2dcSMark Johnston 
1319141fe2dcSMark Johnston 	s = socket(AF_LOCAL, SOCK_STREAM, 0);
1320141fe2dcSMark Johnston 	ATF_REQUIRE(s != -1);
1321141fe2dcSMark Johnston 
1322141fe2dcSMark Johnston 	memset(&sun, 0, sizeof(sun));
1323141fe2dcSMark Johnston 	snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", "listen.XXXXXX");
1324141fe2dcSMark Johnston 	mktemp(sun.sun_path);
1325141fe2dcSMark Johnston 	sun.sun_family = AF_LOCAL;
1326141fe2dcSMark Johnston 	sun.sun_len = SUN_LEN(&sun);
1327141fe2dcSMark Johnston 
1328141fe2dcSMark Johnston 	ATF_REQUIRE(bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) == 0);
1329141fe2dcSMark Johnston 
1330141fe2dcSMark Johnston 	memset(buf, 0, sizeof(buf));
1331141fe2dcSMark Johnston 	memset(&iocb, 0, sizeof(iocb));
1332141fe2dcSMark Johnston 	iocb.aio_fildes = s;
1333141fe2dcSMark Johnston 	iocb.aio_buf = buf;
1334141fe2dcSMark Johnston 	iocb.aio_nbytes = sizeof(buf);
1335141fe2dcSMark Johnston 	ATF_REQUIRE(aio_read(&iocb) == 0);
1336141fe2dcSMark Johnston 
1337141fe2dcSMark Johnston 	ATF_REQUIRE_ERRNO(EINVAL, listen(s, 5) == -1);
1338141fe2dcSMark Johnston 
1339141fe2dcSMark Johnston 	ATF_REQUIRE(aio_cancel(s, &iocb) != -1);
1340141fe2dcSMark Johnston 
1341141fe2dcSMark Johnston 	ATF_REQUIRE(unlink(sun.sun_path) == 0);
1342141fe2dcSMark Johnston 	close(s);
1343141fe2dcSMark Johnston }
1344141fe2dcSMark Johnston 
1345141fe2dcSMark Johnston /*
1346778ce4f2SJohn Baldwin  * This test verifies that cancelling a partially completed socket write
1347778ce4f2SJohn Baldwin  * returns a short write rather than ECANCELED.
1348778ce4f2SJohn Baldwin  */
1349778ce4f2SJohn Baldwin ATF_TC_WITHOUT_HEAD(aio_socket_short_write_cancel);
ATF_TC_BODY(aio_socket_short_write_cancel,tc)1350778ce4f2SJohn Baldwin ATF_TC_BODY(aio_socket_short_write_cancel, tc)
1351778ce4f2SJohn Baldwin {
1352778ce4f2SJohn Baldwin 	struct aiocb iocb, *iocbp;
1353778ce4f2SJohn Baldwin 	char *buffer[2];
1354778ce4f2SJohn Baldwin 	ssize_t done;
1355778ce4f2SJohn Baldwin 	int buffer_size, sb_size;
1356778ce4f2SJohn Baldwin 	socklen_t len;
1357778ce4f2SJohn Baldwin 	int s[2];
1358778ce4f2SJohn Baldwin 
1359778ce4f2SJohn Baldwin 	ATF_REQUIRE_KERNEL_MODULE("aio");
1360778ce4f2SJohn Baldwin 
1361778ce4f2SJohn Baldwin 	ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, s) != -1);
1362778ce4f2SJohn Baldwin 
1363778ce4f2SJohn Baldwin 	len = sizeof(sb_size);
1364778ce4f2SJohn Baldwin 	ATF_REQUIRE(getsockopt(s[0], SOL_SOCKET, SO_RCVBUF, &sb_size, &len) !=
1365778ce4f2SJohn Baldwin 	    -1);
1366778ce4f2SJohn Baldwin 	ATF_REQUIRE(len == sizeof(sb_size));
1367778ce4f2SJohn Baldwin 	buffer_size = sb_size;
1368778ce4f2SJohn Baldwin 
1369778ce4f2SJohn Baldwin 	ATF_REQUIRE(getsockopt(s[1], SOL_SOCKET, SO_SNDBUF, &sb_size, &len) !=
1370778ce4f2SJohn Baldwin 	    -1);
1371778ce4f2SJohn Baldwin 	ATF_REQUIRE(len == sizeof(sb_size));
1372778ce4f2SJohn Baldwin 	if (sb_size > buffer_size)
1373778ce4f2SJohn Baldwin 		buffer_size = sb_size;
1374778ce4f2SJohn Baldwin 
1375778ce4f2SJohn Baldwin 	/*
1376778ce4f2SJohn Baldwin 	 * Use three times the size of the MAX(receive buffer, send
1377778ce4f2SJohn Baldwin 	 * buffer) for the write to ensure that the write is split up
1378778ce4f2SJohn Baldwin 	 * into multiple writes internally.  The recv() ensures that
1379778ce4f2SJohn Baldwin 	 * the write has partially completed, but a remaining size of
1380778ce4f2SJohn Baldwin 	 * two buffers should ensure that the write has not completed
1381778ce4f2SJohn Baldwin 	 * fully when it is cancelled.
1382778ce4f2SJohn Baldwin 	 */
1383778ce4f2SJohn Baldwin 	buffer[0] = malloc(buffer_size);
1384778ce4f2SJohn Baldwin 	ATF_REQUIRE(buffer[0] != NULL);
1385778ce4f2SJohn Baldwin 	buffer[1] = malloc(buffer_size * 3);
1386778ce4f2SJohn Baldwin 	ATF_REQUIRE(buffer[1] != NULL);
1387778ce4f2SJohn Baldwin 
1388778ce4f2SJohn Baldwin 	srandomdev();
1389778ce4f2SJohn Baldwin 	aio_fill_buffer(buffer[1], buffer_size * 3, random());
1390778ce4f2SJohn Baldwin 
1391778ce4f2SJohn Baldwin 	memset(&iocb, 0, sizeof(iocb));
1392778ce4f2SJohn Baldwin 	iocb.aio_fildes = s[1];
1393778ce4f2SJohn Baldwin 	iocb.aio_buf = buffer[1];
1394778ce4f2SJohn Baldwin 	iocb.aio_nbytes = buffer_size * 3;
1395778ce4f2SJohn Baldwin 	ATF_REQUIRE(aio_write(&iocb) == 0);
1396778ce4f2SJohn Baldwin 
1397778ce4f2SJohn Baldwin 	done = recv(s[0], buffer[0], buffer_size, MSG_WAITALL);
1398778ce4f2SJohn Baldwin 	ATF_REQUIRE(done == buffer_size);
1399778ce4f2SJohn Baldwin 
1400778ce4f2SJohn Baldwin 	ATF_REQUIRE(aio_error(&iocb) == EINPROGRESS);
1401778ce4f2SJohn Baldwin 	ATF_REQUIRE(aio_cancel(s[1], &iocb) == AIO_NOTCANCELED);
1402778ce4f2SJohn Baldwin 
1403778ce4f2SJohn Baldwin 	done = aio_waitcomplete(&iocbp, NULL);
1404778ce4f2SJohn Baldwin 	ATF_REQUIRE(iocbp == &iocb);
1405778ce4f2SJohn Baldwin 	ATF_REQUIRE(done >= buffer_size && done <= buffer_size * 2);
1406778ce4f2SJohn Baldwin 
1407778ce4f2SJohn Baldwin 	ATF_REQUIRE(memcmp(buffer[0], buffer[1], buffer_size) == 0);
1408778ce4f2SJohn Baldwin 
1409778ce4f2SJohn Baldwin 	close(s[1]);
1410778ce4f2SJohn Baldwin 	close(s[0]);
1411778ce4f2SJohn Baldwin }
1412778ce4f2SJohn Baldwin 
1413005ce8e4SJohn Baldwin /*
1414c13f6dd7SMark Johnston  * Test handling of aio_read() and aio_write() on shut-down sockets.
1415c13f6dd7SMark Johnston  */
1416c13f6dd7SMark Johnston ATF_TC_WITHOUT_HEAD(aio_socket_shutdown);
ATF_TC_BODY(aio_socket_shutdown,tc)1417c13f6dd7SMark Johnston ATF_TC_BODY(aio_socket_shutdown, tc)
1418c13f6dd7SMark Johnston {
1419c13f6dd7SMark Johnston 	struct aiocb iocb;
1420c13f6dd7SMark Johnston 	sigset_t set;
1421c13f6dd7SMark Johnston 	char *buffer;
1422c13f6dd7SMark Johnston 	ssize_t len;
1423c13f6dd7SMark Johnston 	size_t bsz;
1424c13f6dd7SMark Johnston 	int error, s[2];
1425c13f6dd7SMark Johnston 
1426c13f6dd7SMark Johnston 	ATF_REQUIRE_KERNEL_MODULE("aio");
1427c13f6dd7SMark Johnston 
1428c13f6dd7SMark Johnston 	ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, s) != -1);
1429c13f6dd7SMark Johnston 
1430c13f6dd7SMark Johnston 	bsz = 1024;
1431c13f6dd7SMark Johnston 	buffer = malloc(bsz);
1432c13f6dd7SMark Johnston 	memset(buffer, 0, bsz);
1433c13f6dd7SMark Johnston 
1434c13f6dd7SMark Johnston 	/* Put some data in s[0]'s recv buffer. */
1435c13f6dd7SMark Johnston 	ATF_REQUIRE(send(s[1], buffer, bsz, 0) == (ssize_t)bsz);
1436c13f6dd7SMark Johnston 
1437c13f6dd7SMark Johnston 	/* No more reading from s[0]. */
1438c13f6dd7SMark Johnston 	ATF_REQUIRE(shutdown(s[0], SHUT_RD) != -1);
1439c13f6dd7SMark Johnston 
1440c13f6dd7SMark Johnston 	ATF_REQUIRE(buffer != NULL);
1441c13f6dd7SMark Johnston 
1442c13f6dd7SMark Johnston 	memset(&iocb, 0, sizeof(iocb));
1443c13f6dd7SMark Johnston 	iocb.aio_fildes = s[0];
1444c13f6dd7SMark Johnston 	iocb.aio_buf = buffer;
1445c13f6dd7SMark Johnston 	iocb.aio_nbytes = bsz;
1446c13f6dd7SMark Johnston 	ATF_REQUIRE(aio_read(&iocb) == 0);
1447c13f6dd7SMark Johnston 
1448c13f6dd7SMark Johnston 	/* Expect to see zero bytes, analogous to recv(2). */
1449c13f6dd7SMark Johnston 	while ((error = aio_error(&iocb)) == EINPROGRESS)
1450c13f6dd7SMark Johnston 		usleep(25000);
1451c13f6dd7SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "aio_error() returned %d", error);
1452c13f6dd7SMark Johnston 	len = aio_return(&iocb);
1453c13f6dd7SMark Johnston 	ATF_REQUIRE_MSG(len == 0, "read job returned %zd bytes", len);
1454c13f6dd7SMark Johnston 
1455c13f6dd7SMark Johnston 	/* No more writing to s[1]. */
1456c13f6dd7SMark Johnston 	ATF_REQUIRE(shutdown(s[1], SHUT_WR) != -1);
1457c13f6dd7SMark Johnston 
1458c13f6dd7SMark Johnston 	/* Block SIGPIPE so that we can detect the error in-band. */
1459c13f6dd7SMark Johnston 	sigemptyset(&set);
1460c13f6dd7SMark Johnston 	sigaddset(&set, SIGPIPE);
1461c13f6dd7SMark Johnston 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) == 0);
1462c13f6dd7SMark Johnston 
1463c13f6dd7SMark Johnston 	memset(&iocb, 0, sizeof(iocb));
1464c13f6dd7SMark Johnston 	iocb.aio_fildes = s[1];
1465c13f6dd7SMark Johnston 	iocb.aio_buf = buffer;
1466c13f6dd7SMark Johnston 	iocb.aio_nbytes = bsz;
1467c13f6dd7SMark Johnston 	ATF_REQUIRE(aio_write(&iocb) == 0);
1468c13f6dd7SMark Johnston 
1469c13f6dd7SMark Johnston 	/* Expect an error, analogous to send(2). */
1470c13f6dd7SMark Johnston 	while ((error = aio_error(&iocb)) == EINPROGRESS)
1471c13f6dd7SMark Johnston 		usleep(25000);
1472c13f6dd7SMark Johnston 	ATF_REQUIRE_MSG(error == EPIPE, "aio_error() returned %d", error);
1473c13f6dd7SMark Johnston 
1474c13f6dd7SMark Johnston 	ATF_REQUIRE(close(s[0]) != -1);
1475c13f6dd7SMark Johnston 	ATF_REQUIRE(close(s[1]) != -1);
1476c13f6dd7SMark Johnston 	free(buffer);
1477c13f6dd7SMark Johnston }
1478c13f6dd7SMark Johnston 
1479c13f6dd7SMark Johnston /*
1480604bbb3fSAlan Somers  * test aio_fsync's behavior with bad inputs
1481604bbb3fSAlan Somers  */
1482604bbb3fSAlan Somers ATF_TC_WITHOUT_HEAD(aio_fsync_errors);
ATF_TC_BODY(aio_fsync_errors,tc)1483604bbb3fSAlan Somers ATF_TC_BODY(aio_fsync_errors, tc)
1484604bbb3fSAlan Somers {
1485604bbb3fSAlan Somers 	int fd;
1486604bbb3fSAlan Somers 	struct aiocb iocb;
1487604bbb3fSAlan Somers 
1488604bbb3fSAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("aio");
1489604bbb3fSAlan Somers 	ATF_REQUIRE_UNSAFE_AIO();
1490604bbb3fSAlan Somers 
1491604bbb3fSAlan Somers 	fd = open(FILE_PATHNAME, O_RDWR | O_CREAT, 0600);
1492604bbb3fSAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1493604bbb3fSAlan Somers 	unlink(FILE_PATHNAME);
1494604bbb3fSAlan Somers 
1495801ac943SThomas Munro 	/* aio_fsync should return EINVAL unless op is O_SYNC or O_DSYNC */
1496604bbb3fSAlan Somers 	memset(&iocb, 0, sizeof(iocb));
1497604bbb3fSAlan Somers 	iocb.aio_fildes = fd;
1498604bbb3fSAlan Somers 	ATF_CHECK_EQ(-1, aio_fsync(666, &iocb));
1499604bbb3fSAlan Somers 	ATF_CHECK_EQ(EINVAL, errno);
1500604bbb3fSAlan Somers 
1501604bbb3fSAlan Somers 	/* aio_fsync should return EBADF if fd is not a valid descriptor */
1502604bbb3fSAlan Somers 	memset(&iocb, 0, sizeof(iocb));
1503604bbb3fSAlan Somers 	iocb.aio_fildes = 666;
1504604bbb3fSAlan Somers 	ATF_CHECK_EQ(-1, aio_fsync(O_SYNC, &iocb));
1505604bbb3fSAlan Somers 	ATF_CHECK_EQ(EBADF, errno);
1506604bbb3fSAlan Somers 
1507604bbb3fSAlan Somers 	/* aio_fsync should return EINVAL if sigev_notify is invalid */
1508604bbb3fSAlan Somers 	memset(&iocb, 0, sizeof(iocb));
1509604bbb3fSAlan Somers 	iocb.aio_fildes = fd;
1510604bbb3fSAlan Somers 	iocb.aio_sigevent.sigev_notify = 666;
1511604bbb3fSAlan Somers 	ATF_CHECK_EQ(-1, aio_fsync(666, &iocb));
1512604bbb3fSAlan Somers 	ATF_CHECK_EQ(EINVAL, errno);
1513604bbb3fSAlan Somers }
1514604bbb3fSAlan Somers 
1515604bbb3fSAlan Somers /*
1516005ce8e4SJohn Baldwin  * This test just performs a basic test of aio_fsync().
1517005ce8e4SJohn Baldwin  */
1518801ac943SThomas Munro static void
aio_fsync_test(int op)1519801ac943SThomas Munro aio_fsync_test(int op)
1520005ce8e4SJohn Baldwin {
1521005ce8e4SJohn Baldwin 	struct aiocb synccb, *iocbp;
1522005ce8e4SJohn Baldwin 	struct {
1523005ce8e4SJohn Baldwin 		struct aiocb iocb;
1524005ce8e4SJohn Baldwin 		bool done;
1525005ce8e4SJohn Baldwin 		char *buffer;
1526005ce8e4SJohn Baldwin 	} buffers[16];
1527005ce8e4SJohn Baldwin 	struct stat sb;
1528005ce8e4SJohn Baldwin 	ssize_t rval;
1529005ce8e4SJohn Baldwin 	unsigned i;
1530005ce8e4SJohn Baldwin 	int fd;
1531005ce8e4SJohn Baldwin 
1532005ce8e4SJohn Baldwin 	ATF_REQUIRE_KERNEL_MODULE("aio");
1533005ce8e4SJohn Baldwin 	ATF_REQUIRE_UNSAFE_AIO();
1534005ce8e4SJohn Baldwin 
15359086b30bSJilles Tjoelker 	fd = open(FILE_PATHNAME, O_RDWR | O_CREAT, 0600);
1536740a9bfaSAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1537740a9bfaSAlan Somers 	unlink(FILE_PATHNAME);
1538005ce8e4SJohn Baldwin 
1539005ce8e4SJohn Baldwin 	ATF_REQUIRE(fstat(fd, &sb) == 0);
1540005ce8e4SJohn Baldwin 	ATF_REQUIRE(sb.st_blksize != 0);
1541005ce8e4SJohn Baldwin 	ATF_REQUIRE(ftruncate(fd, sb.st_blksize * nitems(buffers)) == 0);
1542005ce8e4SJohn Baldwin 
1543005ce8e4SJohn Baldwin 	/*
1544005ce8e4SJohn Baldwin 	 * Queue several asynchronous write requests.  Hopefully this
1545005ce8e4SJohn Baldwin 	 * forces the aio_fsync() request to be deferred.  There is no
1546005ce8e4SJohn Baldwin 	 * reliable way to guarantee that however.
1547005ce8e4SJohn Baldwin 	 */
1548005ce8e4SJohn Baldwin 	srandomdev();
1549005ce8e4SJohn Baldwin 	for (i = 0; i < nitems(buffers); i++) {
1550005ce8e4SJohn Baldwin 		buffers[i].done = false;
1551005ce8e4SJohn Baldwin 		memset(&buffers[i].iocb, 0, sizeof(buffers[i].iocb));
1552005ce8e4SJohn Baldwin 		buffers[i].buffer = malloc(sb.st_blksize);
1553005ce8e4SJohn Baldwin 		aio_fill_buffer(buffers[i].buffer, sb.st_blksize, random());
1554005ce8e4SJohn Baldwin 		buffers[i].iocb.aio_fildes = fd;
1555005ce8e4SJohn Baldwin 		buffers[i].iocb.aio_buf = buffers[i].buffer;
1556005ce8e4SJohn Baldwin 		buffers[i].iocb.aio_nbytes = sb.st_blksize;
1557005ce8e4SJohn Baldwin 		buffers[i].iocb.aio_offset = sb.st_blksize * i;
1558005ce8e4SJohn Baldwin 		ATF_REQUIRE(aio_write(&buffers[i].iocb) == 0);
1559005ce8e4SJohn Baldwin 	}
1560005ce8e4SJohn Baldwin 
1561005ce8e4SJohn Baldwin 	/* Queue the aio_fsync request. */
1562005ce8e4SJohn Baldwin 	memset(&synccb, 0, sizeof(synccb));
1563005ce8e4SJohn Baldwin 	synccb.aio_fildes = fd;
1564801ac943SThomas Munro 	ATF_REQUIRE(aio_fsync(op, &synccb) == 0);
1565005ce8e4SJohn Baldwin 
1566005ce8e4SJohn Baldwin 	/* Wait for requests to complete. */
1567005ce8e4SJohn Baldwin 	for (;;) {
1568005ce8e4SJohn Baldwin 	next:
1569005ce8e4SJohn Baldwin 		rval = aio_waitcomplete(&iocbp, NULL);
1570005ce8e4SJohn Baldwin 		ATF_REQUIRE(iocbp != NULL);
1571005ce8e4SJohn Baldwin 		if (iocbp == &synccb) {
1572005ce8e4SJohn Baldwin 			ATF_REQUIRE(rval == 0);
1573005ce8e4SJohn Baldwin 			break;
1574005ce8e4SJohn Baldwin 		}
1575005ce8e4SJohn Baldwin 
1576005ce8e4SJohn Baldwin 		for (i = 0; i < nitems(buffers); i++) {
1577005ce8e4SJohn Baldwin 			if (iocbp == &buffers[i].iocb) {
1578005ce8e4SJohn Baldwin 				ATF_REQUIRE(buffers[i].done == false);
1579005ce8e4SJohn Baldwin 				ATF_REQUIRE(rval == sb.st_blksize);
1580005ce8e4SJohn Baldwin 				buffers[i].done = true;
1581005ce8e4SJohn Baldwin 				goto next;
1582005ce8e4SJohn Baldwin 			}
1583005ce8e4SJohn Baldwin 		}
1584005ce8e4SJohn Baldwin 
1585005ce8e4SJohn Baldwin 		ATF_REQUIRE_MSG(false, "unmatched AIO request");
1586005ce8e4SJohn Baldwin 	}
1587005ce8e4SJohn Baldwin 
1588005ce8e4SJohn Baldwin 	for (i = 0; i < nitems(buffers); i++)
1589005ce8e4SJohn Baldwin 		ATF_REQUIRE_MSG(buffers[i].done,
1590005ce8e4SJohn Baldwin 		    "AIO request %u did not complete", i);
1591005ce8e4SJohn Baldwin 
1592005ce8e4SJohn Baldwin 	close(fd);
1593005ce8e4SJohn Baldwin }
1594005ce8e4SJohn Baldwin 
1595801ac943SThomas Munro ATF_TC_WITHOUT_HEAD(aio_fsync_sync_test);
ATF_TC_BODY(aio_fsync_sync_test,tc)1596801ac943SThomas Munro ATF_TC_BODY(aio_fsync_sync_test, tc)
1597801ac943SThomas Munro {
1598801ac943SThomas Munro 	aio_fsync_test(O_SYNC);
1599801ac943SThomas Munro }
1600801ac943SThomas Munro 
1601801ac943SThomas Munro ATF_TC_WITHOUT_HEAD(aio_fsync_dsync_test);
ATF_TC_BODY(aio_fsync_dsync_test,tc)1602801ac943SThomas Munro ATF_TC_BODY(aio_fsync_dsync_test, tc)
1603801ac943SThomas Munro {
1604801ac943SThomas Munro 	aio_fsync_test(O_DSYNC);
1605801ac943SThomas Munro }
1606801ac943SThomas Munro 
1607022ca2fcSAlan Somers /*
1608022ca2fcSAlan Somers  * We shouldn't be able to DoS the system by setting iov_len to an insane
1609022ca2fcSAlan Somers  * value
1610022ca2fcSAlan Somers  */
1611022ca2fcSAlan Somers ATF_TC_WITHOUT_HEAD(aio_writev_dos_iov_len);
ATF_TC_BODY(aio_writev_dos_iov_len,tc)1612022ca2fcSAlan Somers ATF_TC_BODY(aio_writev_dos_iov_len, tc)
1613022ca2fcSAlan Somers {
1614022ca2fcSAlan Somers 	struct aiocb aio;
1615022ca2fcSAlan Somers 	const struct aiocb *const iocbs[] = {&aio};
1616022ca2fcSAlan Somers 	const char *wbuf = "Hello, world!";
1617022ca2fcSAlan Somers 	struct iovec iov[1];
161857082ce8SAlan Somers 	ssize_t r;
1619022ca2fcSAlan Somers 	int fd;
1620022ca2fcSAlan Somers 
1621022ca2fcSAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("aio");
1622022ca2fcSAlan Somers 	ATF_REQUIRE_UNSAFE_AIO();
1623022ca2fcSAlan Somers 
1624022ca2fcSAlan Somers 	fd = open("testfile", O_RDWR | O_CREAT, 0600);
1625022ca2fcSAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1626022ca2fcSAlan Somers 
1627022ca2fcSAlan Somers 	iov[0].iov_base = __DECONST(void*, wbuf);
1628022ca2fcSAlan Somers 	iov[0].iov_len = 1 << 30;
1629022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
1630022ca2fcSAlan Somers 	aio.aio_fildes = fd;
1631022ca2fcSAlan Somers 	aio.aio_offset = 0;
1632022ca2fcSAlan Somers 	aio.aio_iov = iov;
1633022ca2fcSAlan Somers 	aio.aio_iovcnt = 1;
1634022ca2fcSAlan Somers 
1635022ca2fcSAlan Somers 	r = aio_writev(&aio);
1636022ca2fcSAlan Somers 	ATF_CHECK_EQ_MSG(0, r, "aio_writev returned %zd", r);
1637022ca2fcSAlan Somers 	ATF_REQUIRE_EQ(0, aio_suspend(iocbs, 1, NULL));
1638022ca2fcSAlan Somers 	r = aio_return(&aio);
1639022ca2fcSAlan Somers 	ATF_CHECK_EQ_MSG(-1, r, "aio_return returned %zd", r);
1640022ca2fcSAlan Somers 	ATF_CHECK_MSG(errno == EFAULT || errno == EINVAL,
1641022ca2fcSAlan Somers 	    "aio_writev: %s", strerror(errno));
1642022ca2fcSAlan Somers 
1643022ca2fcSAlan Somers 	close(fd);
1644022ca2fcSAlan Somers }
1645022ca2fcSAlan Somers 
1646022ca2fcSAlan Somers /*
1647022ca2fcSAlan Somers  * We shouldn't be able to DoS the system by setting aio_iovcnt to an insane
1648022ca2fcSAlan Somers  * value
1649022ca2fcSAlan Somers  */
1650022ca2fcSAlan Somers ATF_TC_WITHOUT_HEAD(aio_writev_dos_iovcnt);
ATF_TC_BODY(aio_writev_dos_iovcnt,tc)1651022ca2fcSAlan Somers ATF_TC_BODY(aio_writev_dos_iovcnt, tc)
1652022ca2fcSAlan Somers {
1653022ca2fcSAlan Somers 	struct aiocb aio;
1654022ca2fcSAlan Somers 	const char *wbuf = "Hello, world!";
1655022ca2fcSAlan Somers 	struct iovec iov[1];
1656022ca2fcSAlan Somers 	ssize_t len;
1657022ca2fcSAlan Somers 	int fd;
1658022ca2fcSAlan Somers 
1659022ca2fcSAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("aio");
1660022ca2fcSAlan Somers 	ATF_REQUIRE_UNSAFE_AIO();
1661022ca2fcSAlan Somers 
1662022ca2fcSAlan Somers 	fd = open("testfile", O_RDWR | O_CREAT, 0600);
1663022ca2fcSAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1664022ca2fcSAlan Somers 
1665022ca2fcSAlan Somers 	len = strlen(wbuf);
1666022ca2fcSAlan Somers 	iov[0].iov_base = __DECONST(void*, wbuf);
1667022ca2fcSAlan Somers 	iov[0].iov_len = len;
1668022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
1669022ca2fcSAlan Somers 	aio.aio_fildes = fd;
1670022ca2fcSAlan Somers 	aio.aio_offset = 0;
1671022ca2fcSAlan Somers 	aio.aio_iov = iov;
1672022ca2fcSAlan Somers 	aio.aio_iovcnt = 1 << 30;
1673022ca2fcSAlan Somers 
1674022ca2fcSAlan Somers 	ATF_REQUIRE_EQ(-1, aio_writev(&aio));
1675022ca2fcSAlan Somers 	ATF_CHECK_EQ(EINVAL, errno);
1676022ca2fcSAlan Somers 
1677022ca2fcSAlan Somers 	close(fd);
1678022ca2fcSAlan Somers }
1679022ca2fcSAlan Somers 
1680022ca2fcSAlan Somers ATF_TC_WITH_CLEANUP(aio_writev_efault);
ATF_TC_HEAD(aio_writev_efault,tc)1681022ca2fcSAlan Somers ATF_TC_HEAD(aio_writev_efault, tc)
1682022ca2fcSAlan Somers {
1683022ca2fcSAlan Somers 	atf_tc_set_md_var(tc, "descr",
1684022ca2fcSAlan Somers 	    "Vectored AIO should gracefully handle invalid addresses");
1685022ca2fcSAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
1686022ca2fcSAlan Somers }
ATF_TC_BODY(aio_writev_efault,tc)1687022ca2fcSAlan Somers ATF_TC_BODY(aio_writev_efault, tc)
1688022ca2fcSAlan Somers {
1689022ca2fcSAlan Somers 	struct aiocb aio;
1690022ca2fcSAlan Somers 	ssize_t buflen;
1691022ca2fcSAlan Somers 	char *buffer;
1692022ca2fcSAlan Somers 	struct iovec iov[2];
1693022ca2fcSAlan Somers 	long seed;
1694022ca2fcSAlan Somers 	int fd;
1695022ca2fcSAlan Somers 
1696022ca2fcSAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("aio");
1697022ca2fcSAlan Somers 	ATF_REQUIRE_UNSAFE_AIO();
1698022ca2fcSAlan Somers 
1699022ca2fcSAlan Somers 	fd = aio_md_setup();
1700022ca2fcSAlan Somers 
1701022ca2fcSAlan Somers 	seed = random();
1702022ca2fcSAlan Somers 	buflen = 4096;
1703022ca2fcSAlan Somers 	buffer = malloc(buflen);
1704022ca2fcSAlan Somers 	aio_fill_buffer(buffer, buflen, seed);
1705022ca2fcSAlan Somers 	iov[0].iov_base = buffer;
1706022ca2fcSAlan Somers 	iov[0].iov_len = buflen;
1707022ca2fcSAlan Somers 	iov[1].iov_base = (void*)-1;	/* Invalid! */
1708022ca2fcSAlan Somers 	iov[1].iov_len = buflen;
1709022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
1710022ca2fcSAlan Somers 	aio.aio_fildes = fd;
1711022ca2fcSAlan Somers 	aio.aio_offset = 0;
1712022ca2fcSAlan Somers 	aio.aio_iov = iov;
1713022ca2fcSAlan Somers 	aio.aio_iovcnt = nitems(iov);
1714022ca2fcSAlan Somers 
1715022ca2fcSAlan Somers 	ATF_REQUIRE_EQ(-1, aio_writev(&aio));
1716022ca2fcSAlan Somers 	ATF_CHECK_EQ(EFAULT, errno);
1717022ca2fcSAlan Somers 
1718022ca2fcSAlan Somers 	close(fd);
1719022ca2fcSAlan Somers }
ATF_TC_CLEANUP(aio_writev_efault,tc)1720022ca2fcSAlan Somers ATF_TC_CLEANUP(aio_writev_efault, tc)
1721022ca2fcSAlan Somers {
1722022ca2fcSAlan Somers 	aio_md_cleanup();
1723022ca2fcSAlan Somers }
1724022ca2fcSAlan Somers 
1725022ca2fcSAlan Somers ATF_TC_WITHOUT_HEAD(aio_writev_empty_file_poll);
ATF_TC_BODY(aio_writev_empty_file_poll,tc)1726022ca2fcSAlan Somers ATF_TC_BODY(aio_writev_empty_file_poll, tc)
1727022ca2fcSAlan Somers {
1728022ca2fcSAlan Somers 	struct aiocb aio;
1729022ca2fcSAlan Somers 	int fd;
1730022ca2fcSAlan Somers 
1731022ca2fcSAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("aio");
1732022ca2fcSAlan Somers 	ATF_REQUIRE_UNSAFE_AIO();
1733022ca2fcSAlan Somers 
1734022ca2fcSAlan Somers 	fd = open("testfile", O_RDWR | O_CREAT, 0600);
1735022ca2fcSAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1736022ca2fcSAlan Somers 
1737022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
1738022ca2fcSAlan Somers 	aio.aio_fildes = fd;
1739022ca2fcSAlan Somers 	aio.aio_offset = 0;
1740022ca2fcSAlan Somers 	aio.aio_iovcnt = 0;
1741022ca2fcSAlan Somers 
1742022ca2fcSAlan Somers 	ATF_REQUIRE_EQ(0, aio_writev(&aio));
1743022ca2fcSAlan Somers 	ATF_REQUIRE_EQ(0, suspend(&aio));
1744022ca2fcSAlan Somers 
1745022ca2fcSAlan Somers 	close(fd);
1746022ca2fcSAlan Somers }
1747022ca2fcSAlan Somers 
1748022ca2fcSAlan Somers ATF_TC_WITHOUT_HEAD(aio_writev_empty_file_signal);
ATF_TC_BODY(aio_writev_empty_file_signal,tc)1749022ca2fcSAlan Somers ATF_TC_BODY(aio_writev_empty_file_signal, tc)
1750022ca2fcSAlan Somers {
1751022ca2fcSAlan Somers 	struct aiocb aio;
1752022ca2fcSAlan Somers 	int fd;
1753022ca2fcSAlan Somers 
1754022ca2fcSAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("aio");
1755022ca2fcSAlan Somers 	ATF_REQUIRE_UNSAFE_AIO();
1756022ca2fcSAlan Somers 
1757022ca2fcSAlan Somers 	fd = open("testfile", O_RDWR | O_CREAT, 0600);
1758022ca2fcSAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1759022ca2fcSAlan Somers 
1760022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
1761022ca2fcSAlan Somers 	aio.aio_fildes = fd;
1762022ca2fcSAlan Somers 	aio.aio_offset = 0;
1763022ca2fcSAlan Somers 	aio.aio_iovcnt = 0;
1764022ca2fcSAlan Somers 	aio.aio_sigevent = *setup_signal();
1765022ca2fcSAlan Somers 
1766022ca2fcSAlan Somers 	ATF_REQUIRE_EQ(0, aio_writev(&aio));
1767022ca2fcSAlan Somers 	ATF_REQUIRE_EQ(0, poll_signaled(&aio));
1768022ca2fcSAlan Somers 
1769022ca2fcSAlan Somers 	close(fd);
1770022ca2fcSAlan Somers }
1771022ca2fcSAlan Somers 
177257082ce8SAlan Somers /*
177357082ce8SAlan Somers  * Use an aiocb with kqueue and EV_ONESHOT.  kqueue should deliver the event
177457082ce8SAlan Somers  * only once, even if the user doesn't promptly call aio_return.
177557082ce8SAlan Somers  */
177657082ce8SAlan Somers ATF_TC_WITHOUT_HEAD(ev_oneshot);
ATF_TC_BODY(ev_oneshot,tc)177757082ce8SAlan Somers ATF_TC_BODY(ev_oneshot, tc)
177857082ce8SAlan Somers {
177957082ce8SAlan Somers 	int fd, kq, nevents;
178057082ce8SAlan Somers 	struct aiocb iocb;
178157082ce8SAlan Somers 	struct kevent events[1];
178257082ce8SAlan Somers 	struct timespec timeout;
178357082ce8SAlan Somers 
178457082ce8SAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("aio");
178557082ce8SAlan Somers 
178657082ce8SAlan Somers 	kq = kqueue();
178757082ce8SAlan Somers 	ATF_REQUIRE(kq >= 0);
178857082ce8SAlan Somers 
178957082ce8SAlan Somers 	fd = open(FILE_PATHNAME, O_RDWR | O_CREAT, 0600);
179057082ce8SAlan Somers 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
179157082ce8SAlan Somers 
179257082ce8SAlan Somers 	memset(&iocb, 0, sizeof(iocb));
179357082ce8SAlan Somers 	iocb.aio_fildes = fd;
179457082ce8SAlan Somers 	iocb.aio_sigevent.sigev_notify_kqueue = kq;
179557082ce8SAlan Somers 	iocb.aio_sigevent.sigev_value.sival_ptr = (void*)0xdeadbeef;
179657082ce8SAlan Somers 	iocb.aio_sigevent.sigev_notify_kevent_flags = EV_ONESHOT;
179757082ce8SAlan Somers 	iocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
179857082ce8SAlan Somers 
179957082ce8SAlan Somers 	ATF_CHECK_EQ(0, aio_fsync(O_SYNC, &iocb));
180057082ce8SAlan Somers 
180157082ce8SAlan Somers 	nevents = kevent(kq, NULL, 0, events, 1, NULL);
180257082ce8SAlan Somers 	ATF_CHECK_EQ(1, nevents);
180357082ce8SAlan Somers 	ATF_CHECK_EQ(events[0].ident, (uintptr_t) &iocb);
180457082ce8SAlan Somers 	ATF_CHECK_EQ(events[0].filter, EVFILT_AIO);
180557082ce8SAlan Somers 	ATF_CHECK_EQ(events[0].flags, EV_EOF | EV_ONESHOT);
180657082ce8SAlan Somers 	ATF_CHECK_EQ(events[0].fflags, 0);
180757082ce8SAlan Somers 	ATF_CHECK_EQ(events[0].data, 0);
180857082ce8SAlan Somers 	ATF_CHECK_EQ((uintptr_t)events[0].udata, 0xdeadbeef);
180957082ce8SAlan Somers 
181057082ce8SAlan Somers 	/*
181157082ce8SAlan Somers 	 * Even though we haven't called aio_return, kevent will not return the
181257082ce8SAlan Somers 	 * event again due to EV_ONESHOT.
181357082ce8SAlan Somers 	 */
181457082ce8SAlan Somers 	timeout.tv_sec = 0;
181557082ce8SAlan Somers 	timeout.tv_nsec = 100000000;
181657082ce8SAlan Somers 	nevents = kevent(kq, NULL, 0, events, 1, &timeout);
181757082ce8SAlan Somers 	ATF_CHECK_EQ(0, nevents);
181857082ce8SAlan Somers 
181957082ce8SAlan Somers 	ATF_CHECK_EQ(0, aio_return(&iocb));
182057082ce8SAlan Somers 	close(fd);
182157082ce8SAlan Somers 	close(kq);
182257082ce8SAlan Somers }
182357082ce8SAlan Somers 
182457082ce8SAlan Somers 
1825022ca2fcSAlan Somers // aio_writev and aio_readv should still work even if the iovcnt is greater
1826022ca2fcSAlan Somers // than the number of buffered AIO operations permitted per process.
1827022ca2fcSAlan Somers ATF_TC_WITH_CLEANUP(vectored_big_iovcnt);
ATF_TC_HEAD(vectored_big_iovcnt,tc)1828022ca2fcSAlan Somers ATF_TC_HEAD(vectored_big_iovcnt, tc)
1829022ca2fcSAlan Somers {
1830022ca2fcSAlan Somers 	atf_tc_set_md_var(tc, "descr",
1831022ca2fcSAlan Somers 	    "Vectored AIO should still work even if the iovcnt is greater than "
1832022ca2fcSAlan Somers 	    "the number of buffered AIO operations permitted by the process");
1833022ca2fcSAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
1834022ca2fcSAlan Somers }
ATF_TC_BODY(vectored_big_iovcnt,tc)1835022ca2fcSAlan Somers ATF_TC_BODY(vectored_big_iovcnt, tc)
1836022ca2fcSAlan Somers {
1837022ca2fcSAlan Somers 	struct aiocb aio;
1838022ca2fcSAlan Somers 	struct iovec *iov;
1839022ca2fcSAlan Somers 	ssize_t len, buflen;
1840022ca2fcSAlan Somers 	char *buffer;
1841022ca2fcSAlan Somers 	const char *oid = "vfs.aio.max_buf_aio";
1842022ca2fcSAlan Somers 	long seed;
1843022ca2fcSAlan Somers 	int max_buf_aio;
1844022ca2fcSAlan Somers 	int fd, i;
1845022ca2fcSAlan Somers 	ssize_t sysctl_len = sizeof(max_buf_aio);
1846022ca2fcSAlan Somers 
1847022ca2fcSAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("aio");
1848022ca2fcSAlan Somers 	ATF_REQUIRE_UNSAFE_AIO();
1849022ca2fcSAlan Somers 
1850022ca2fcSAlan Somers 	if (sysctlbyname(oid, &max_buf_aio, &sysctl_len, NULL, 0) == -1)
1851022ca2fcSAlan Somers 		atf_libc_error(errno, "Failed to read %s", oid);
1852022ca2fcSAlan Somers 
1853022ca2fcSAlan Somers 	seed = random();
1854022ca2fcSAlan Somers 	buflen = 512 * (max_buf_aio + 1);
1855022ca2fcSAlan Somers 	buffer = malloc(buflen);
1856022ca2fcSAlan Somers 	aio_fill_buffer(buffer, buflen, seed);
1857022ca2fcSAlan Somers 	iov = calloc(max_buf_aio + 1, sizeof(struct iovec));
1858022ca2fcSAlan Somers 
1859022ca2fcSAlan Somers 	fd = aio_md_setup();
1860022ca2fcSAlan Somers 
1861022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
1862022ca2fcSAlan Somers 	aio.aio_fildes = fd;
1863022ca2fcSAlan Somers 	aio.aio_offset = 0;
1864022ca2fcSAlan Somers 	for (i = 0; i < max_buf_aio + 1; i++) {
1865022ca2fcSAlan Somers 		iov[i].iov_base = &buffer[i * 512];
1866022ca2fcSAlan Somers 		iov[i].iov_len = 512;
1867022ca2fcSAlan Somers 	}
1868022ca2fcSAlan Somers 	aio.aio_iov = iov;
1869022ca2fcSAlan Somers 	aio.aio_iovcnt = max_buf_aio + 1;
1870022ca2fcSAlan Somers 
1871022ca2fcSAlan Somers 	if (aio_writev(&aio) < 0)
1872022ca2fcSAlan Somers 		atf_tc_fail("aio_writev failed: %s", strerror(errno));
1873022ca2fcSAlan Somers 
1874022ca2fcSAlan Somers 	len = poll(&aio);
1875022ca2fcSAlan Somers 	if (len < 0)
1876022ca2fcSAlan Somers 		atf_tc_fail("aio failed: %s", strerror(errno));
1877022ca2fcSAlan Somers 
1878022ca2fcSAlan Somers 	if (len != buflen)
1879022ca2fcSAlan Somers 		atf_tc_fail("aio short write (%jd)", (intmax_t)len);
1880022ca2fcSAlan Somers 
1881022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
1882022ca2fcSAlan Somers 	aio.aio_fildes = fd;
1883022ca2fcSAlan Somers 	aio.aio_offset = 0;
1884022ca2fcSAlan Somers 	aio.aio_iov = iov;
1885022ca2fcSAlan Somers 	aio.aio_iovcnt = max_buf_aio + 1;
1886022ca2fcSAlan Somers 
1887022ca2fcSAlan Somers 	if (aio_readv(&aio) < 0)
1888022ca2fcSAlan Somers 		atf_tc_fail("aio_readv failed: %s", strerror(errno));
1889022ca2fcSAlan Somers 
1890022ca2fcSAlan Somers 	len = poll(&aio);
1891022ca2fcSAlan Somers 	if (len < 0)
1892022ca2fcSAlan Somers 		atf_tc_fail("aio failed: %s", strerror(errno));
1893022ca2fcSAlan Somers 
1894022ca2fcSAlan Somers 	if (len != buflen)
1895022ca2fcSAlan Somers 		atf_tc_fail("aio short read (%jd)", (intmax_t)len);
1896022ca2fcSAlan Somers 
1897022ca2fcSAlan Somers 	if (aio_test_buffer(buffer, buflen, seed) == 0)
1898022ca2fcSAlan Somers 		atf_tc_fail("buffer mismatched");
1899022ca2fcSAlan Somers 
1900022ca2fcSAlan Somers 	close(fd);
1901022ca2fcSAlan Somers }
ATF_TC_CLEANUP(vectored_big_iovcnt,tc)1902022ca2fcSAlan Somers ATF_TC_CLEANUP(vectored_big_iovcnt, tc)
1903022ca2fcSAlan Somers {
1904022ca2fcSAlan Somers 	aio_md_cleanup();
1905022ca2fcSAlan Somers }
1906022ca2fcSAlan Somers 
1907022ca2fcSAlan Somers ATF_TC_WITHOUT_HEAD(vectored_file_poll);
ATF_TC_BODY(vectored_file_poll,tc)1908022ca2fcSAlan Somers ATF_TC_BODY(vectored_file_poll, tc)
1909022ca2fcSAlan Somers {
1910022ca2fcSAlan Somers 	aio_file_test(poll, NULL, true);
1911022ca2fcSAlan Somers }
1912022ca2fcSAlan Somers 
19133904e796SThomas Munro ATF_TC_WITHOUT_HEAD(vectored_thread);
ATF_TC_BODY(vectored_thread,tc)19143904e796SThomas Munro ATF_TC_BODY(vectored_thread, tc)
19153904e796SThomas Munro {
19163904e796SThomas Munro 	aio_file_test(poll_signaled, setup_thread(), true);
19173904e796SThomas Munro }
19183904e796SThomas Munro 
1919022ca2fcSAlan Somers ATF_TC_WITH_CLEANUP(vectored_md_poll);
ATF_TC_HEAD(vectored_md_poll,tc)1920022ca2fcSAlan Somers ATF_TC_HEAD(vectored_md_poll, tc)
1921022ca2fcSAlan Somers {
1922022ca2fcSAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
1923022ca2fcSAlan Somers }
ATF_TC_BODY(vectored_md_poll,tc)1924022ca2fcSAlan Somers ATF_TC_BODY(vectored_md_poll, tc)
1925022ca2fcSAlan Somers {
1926022ca2fcSAlan Somers 	aio_md_test(poll, NULL, true);
1927022ca2fcSAlan Somers }
ATF_TC_CLEANUP(vectored_md_poll,tc)1928022ca2fcSAlan Somers ATF_TC_CLEANUP(vectored_md_poll, tc)
1929022ca2fcSAlan Somers {
1930022ca2fcSAlan Somers 	aio_md_cleanup();
1931022ca2fcSAlan Somers }
1932022ca2fcSAlan Somers 
1933022ca2fcSAlan Somers ATF_TC_WITHOUT_HEAD(vectored_socket_poll);
ATF_TC_BODY(vectored_socket_poll,tc)1934022ca2fcSAlan Somers ATF_TC_BODY(vectored_socket_poll, tc)
1935022ca2fcSAlan Somers {
1936022ca2fcSAlan Somers 	aio_unix_socketpair_test(poll, NULL, true);
1937022ca2fcSAlan Somers }
1938022ca2fcSAlan Somers 
1939022ca2fcSAlan Somers // aio_writev and aio_readv should still work even if the iov contains elements
1940022ca2fcSAlan Somers // that aren't a multiple of the device's sector size, and even if the total
1941022ca2fcSAlan Somers // amount if I/O _is_ a multiple of the device's sector size.
1942022ca2fcSAlan Somers ATF_TC_WITH_CLEANUP(vectored_unaligned);
ATF_TC_HEAD(vectored_unaligned,tc)1943022ca2fcSAlan Somers ATF_TC_HEAD(vectored_unaligned, tc)
1944022ca2fcSAlan Somers {
1945022ca2fcSAlan Somers 	atf_tc_set_md_var(tc, "descr",
1946022ca2fcSAlan Somers 	    "Vectored AIO should still work even if the iov contains elements "
1947022ca2fcSAlan Somers 	    "that aren't a multiple of the sector size.");
1948022ca2fcSAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
1949022ca2fcSAlan Somers }
ATF_TC_BODY(vectored_unaligned,tc)1950022ca2fcSAlan Somers ATF_TC_BODY(vectored_unaligned, tc)
1951022ca2fcSAlan Somers {
1952022ca2fcSAlan Somers 	struct aio_context ac;
1953022ca2fcSAlan Somers 	struct aiocb aio;
1954022ca2fcSAlan Somers 	struct iovec iov[3];
1955022ca2fcSAlan Somers 	ssize_t len, total_len;
1956022ca2fcSAlan Somers 	int fd;
1957022ca2fcSAlan Somers 
19580b159faaSLi-Wen Hsu 	if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false))
19590b159faaSLi-Wen Hsu 		atf_tc_skip("https://bugs.freebsd.org/258766");
19600b159faaSLi-Wen Hsu 
1961022ca2fcSAlan Somers 	ATF_REQUIRE_KERNEL_MODULE("aio");
1962022ca2fcSAlan Somers 	ATF_REQUIRE_UNSAFE_AIO();
1963022ca2fcSAlan Somers 
1964022ca2fcSAlan Somers 	/*
1965022ca2fcSAlan Somers 	 * Use a zvol with volmode=dev, so it will allow .d_write with
1966022ca2fcSAlan Somers 	 * unaligned uio.  geom devices use physio, which doesn't allow that.
1967022ca2fcSAlan Somers 	 */
1968*9cefc0fbSMark Johnston 	fd = aio_zvol_setup(atf_tc_get_ident(tc));
1969022ca2fcSAlan Somers 	aio_context_init(&ac, fd, fd, FILE_LEN);
1970022ca2fcSAlan Somers 
1971022ca2fcSAlan Somers 	/* Break the buffer into 3 parts:
1972022ca2fcSAlan Somers 	 * * A 4kB part, aligned to 4kB
1973022ca2fcSAlan Somers 	 * * Two other parts that add up to 4kB:
1974022ca2fcSAlan Somers 	 *   - 256B
1975022ca2fcSAlan Somers 	 *   - 4kB - 256B
1976022ca2fcSAlan Somers 	 */
1977022ca2fcSAlan Somers 	iov[0].iov_base = ac.ac_buffer;
1978022ca2fcSAlan Somers 	iov[0].iov_len = 4096;
1979022ca2fcSAlan Somers 	iov[1].iov_base = (void*)((uintptr_t)iov[0].iov_base + iov[0].iov_len);
1980022ca2fcSAlan Somers 	iov[1].iov_len = 256;
1981022ca2fcSAlan Somers 	iov[2].iov_base = (void*)((uintptr_t)iov[1].iov_base + iov[1].iov_len);
1982022ca2fcSAlan Somers 	iov[2].iov_len = 4096 - iov[1].iov_len;
1983022ca2fcSAlan Somers 	total_len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
1984022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
1985022ca2fcSAlan Somers 	aio.aio_fildes = ac.ac_write_fd;
1986022ca2fcSAlan Somers 	aio.aio_offset = 0;
1987022ca2fcSAlan Somers 	aio.aio_iov = iov;
1988022ca2fcSAlan Somers 	aio.aio_iovcnt = 3;
1989022ca2fcSAlan Somers 
1990022ca2fcSAlan Somers 	if (aio_writev(&aio) < 0)
1991022ca2fcSAlan Somers 		atf_tc_fail("aio_writev failed: %s", strerror(errno));
1992022ca2fcSAlan Somers 
1993022ca2fcSAlan Somers 	len = poll(&aio);
1994022ca2fcSAlan Somers 	if (len < 0)
1995022ca2fcSAlan Somers 		atf_tc_fail("aio failed: %s", strerror(errno));
1996022ca2fcSAlan Somers 
1997022ca2fcSAlan Somers 	if (len != total_len)
1998022ca2fcSAlan Somers 		atf_tc_fail("aio short write (%jd)", (intmax_t)len);
1999022ca2fcSAlan Somers 
2000022ca2fcSAlan Somers 	bzero(&aio, sizeof(aio));
2001022ca2fcSAlan Somers 	aio.aio_fildes = ac.ac_read_fd;
2002022ca2fcSAlan Somers 	aio.aio_offset = 0;
2003022ca2fcSAlan Somers 	aio.aio_iov = iov;
2004022ca2fcSAlan Somers 	aio.aio_iovcnt = 3;
2005022ca2fcSAlan Somers 
2006022ca2fcSAlan Somers 	if (aio_readv(&aio) < 0)
2007022ca2fcSAlan Somers 		atf_tc_fail("aio_readv failed: %s", strerror(errno));
2008022ca2fcSAlan Somers 	len = poll(&aio);
2009022ca2fcSAlan Somers 
2010022ca2fcSAlan Somers 	ATF_REQUIRE_MSG(aio_test_buffer(ac.ac_buffer, total_len,
2011022ca2fcSAlan Somers 	    ac.ac_seed) != 0, "aio_test_buffer: internal error");
2012022ca2fcSAlan Somers 
2013022ca2fcSAlan Somers 	close(fd);
2014022ca2fcSAlan Somers }
ATF_TC_CLEANUP(vectored_unaligned,tc)2015022ca2fcSAlan Somers ATF_TC_CLEANUP(vectored_unaligned, tc)
2016022ca2fcSAlan Somers {
2017*9cefc0fbSMark Johnston 	aio_zvol_cleanup(atf_tc_get_ident(tc));
2018022ca2fcSAlan Somers }
2019022ca2fcSAlan Somers 
2020022ca2fcSAlan Somers static void
aio_zvol_test(completion comp,struct sigevent * sev,bool vectored,const char * unique)2021*9cefc0fbSMark Johnston aio_zvol_test(completion comp, struct sigevent *sev, bool vectored,
2022*9cefc0fbSMark Johnston     const char *unique)
2023022ca2fcSAlan Somers {
2024022ca2fcSAlan Somers 	struct aio_context ac;
2025022ca2fcSAlan Somers 	int fd;
2026022ca2fcSAlan Somers 
2027*9cefc0fbSMark Johnston 	fd = aio_zvol_setup(unique);
2028022ca2fcSAlan Somers 	aio_context_init(&ac, fd, fd, MD_LEN);
2029022ca2fcSAlan Somers 	if (vectored) {
2030022ca2fcSAlan Somers 		aio_writev_test(&ac, comp, sev);
2031022ca2fcSAlan Somers 		aio_readv_test(&ac, comp, sev);
2032022ca2fcSAlan Somers 	} else {
2033022ca2fcSAlan Somers 		aio_write_test(&ac, comp, sev);
2034022ca2fcSAlan Somers 		aio_read_test(&ac, comp, sev);
2035022ca2fcSAlan Somers 	}
2036022ca2fcSAlan Somers 
2037022ca2fcSAlan Somers 	close(fd);
2038022ca2fcSAlan Somers }
2039022ca2fcSAlan Somers 
2040022ca2fcSAlan Somers /*
2041022ca2fcSAlan Somers  * Note that unlike md, the zvol is not a geom device, does not allow unmapped
2042022ca2fcSAlan Somers  * buffers, and does not use physio.
2043022ca2fcSAlan Somers  */
2044022ca2fcSAlan Somers ATF_TC_WITH_CLEANUP(vectored_zvol_poll);
ATF_TC_HEAD(vectored_zvol_poll,tc)2045022ca2fcSAlan Somers ATF_TC_HEAD(vectored_zvol_poll, tc)
2046022ca2fcSAlan Somers {
2047022ca2fcSAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
2048022ca2fcSAlan Somers }
ATF_TC_BODY(vectored_zvol_poll,tc)2049022ca2fcSAlan Somers ATF_TC_BODY(vectored_zvol_poll, tc)
2050022ca2fcSAlan Somers {
20510b159faaSLi-Wen Hsu 	if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false))
20520b159faaSLi-Wen Hsu 		atf_tc_skip("https://bugs.freebsd.org/258766");
2053*9cefc0fbSMark Johnston 	aio_zvol_test(poll, NULL, true, atf_tc_get_ident(tc));
2054022ca2fcSAlan Somers }
ATF_TC_CLEANUP(vectored_zvol_poll,tc)2055022ca2fcSAlan Somers ATF_TC_CLEANUP(vectored_zvol_poll, tc)
2056022ca2fcSAlan Somers {
2057*9cefc0fbSMark Johnston 	aio_zvol_cleanup(atf_tc_get_ident(tc));
2058022ca2fcSAlan Somers }
2059022ca2fcSAlan Somers 
ATF_TP_ADD_TCS(tp)2060f44eb013SEnji Cooper ATF_TP_ADD_TCS(tp)
2061f44eb013SEnji Cooper {
2062f44eb013SEnji Cooper 
206357082ce8SAlan Somers 	/* Test every file type with every completion method */
206457082ce8SAlan Somers 	ATF_TP_ADD_TC(tp, file_kq);
2065740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, file_poll);
2066314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, file_signal);
2067740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, file_suspend);
2068314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, file_thread);
2069740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, file_waitcomplete);
207057082ce8SAlan Somers 	ATF_TP_ADD_TC(tp, fifo_kq);
2071740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, fifo_poll);
2072314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, fifo_signal);
2073740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, fifo_suspend);
2074314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, fifo_thread);
2075740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, fifo_waitcomplete);
207657082ce8SAlan Somers 	ATF_TP_ADD_TC(tp, socket_kq);
2077740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, socket_poll);
2078314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, socket_signal);
2079740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, socket_suspend);
2080314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, socket_thread);
2081740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, socket_waitcomplete);
208257082ce8SAlan Somers 	ATF_TP_ADD_TC(tp, pty_kq);
2083740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, pty_poll);
2084314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, pty_signal);
2085740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, pty_suspend);
2086314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, pty_thread);
2087740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, pty_waitcomplete);
208857082ce8SAlan Somers 	ATF_TP_ADD_TC(tp, pipe_kq);
2089740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, pipe_poll);
2090314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, pipe_signal);
2091740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, pipe_suspend);
2092314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, pipe_thread);
2093740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, pipe_waitcomplete);
209457082ce8SAlan Somers 	ATF_TP_ADD_TC(tp, md_kq);
2095740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, md_poll);
2096314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, md_signal);
2097740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, md_suspend);
2098314b447fSAlan Somers 	ATF_TP_ADD_TC(tp, md_thread);
2099740a9bfaSAlan Somers 	ATF_TP_ADD_TC(tp, md_waitcomplete);
210057082ce8SAlan Somers 
210157082ce8SAlan Somers 	/* Various special cases */
2102604bbb3fSAlan Somers 	ATF_TP_ADD_TC(tp, aio_fsync_errors);
2103801ac943SThomas Munro 	ATF_TP_ADD_TC(tp, aio_fsync_sync_test);
2104801ac943SThomas Munro 	ATF_TP_ADD_TC(tp, aio_fsync_dsync_test);
2105bb430bc7SJohn Baldwin 	ATF_TP_ADD_TC(tp, aio_large_read_test);
2106d1ad1a73SJohn Baldwin 	ATF_TP_ADD_TC(tp, aio_socket_two_reads);
21071717b68aSJohn Baldwin 	ATF_TP_ADD_TC(tp, aio_socket_blocking_short_write);
2108022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, aio_socket_blocking_short_write_vectored);
2109141fe2dcSMark Johnston 	ATF_TP_ADD_TC(tp, aio_socket_listen_fail);
2110141fe2dcSMark Johnston 	ATF_TP_ADD_TC(tp, aio_socket_listen_pending);
2111778ce4f2SJohn Baldwin 	ATF_TP_ADD_TC(tp, aio_socket_short_write_cancel);
2112c13f6dd7SMark Johnston 	ATF_TP_ADD_TC(tp, aio_socket_shutdown);
2113022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, aio_writev_dos_iov_len);
2114022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, aio_writev_dos_iovcnt);
2115022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, aio_writev_efault);
2116022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, aio_writev_empty_file_poll);
2117022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, aio_writev_empty_file_signal);
211857082ce8SAlan Somers 	ATF_TP_ADD_TC(tp, ev_oneshot);
2119022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, vectored_big_iovcnt);
2120022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, vectored_file_poll);
2121022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, vectored_md_poll);
2122022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, vectored_zvol_poll);
2123022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, vectored_unaligned);
2124022ca2fcSAlan Somers 	ATF_TP_ADD_TC(tp, vectored_socket_poll);
21253904e796SThomas Munro 	ATF_TP_ADD_TC(tp, vectored_thread);
2126f44eb013SEnji Cooper 
2127f44eb013SEnji Cooper 	return (atf_no_error());
2128f44eb013SEnji Cooper }
2129