1138447Srwatson/*-
2138447Srwatson * Copyright (c) 2004 Robert N. M. Watson
3138447Srwatson * All rights reserved.
4138447Srwatson *
5138447Srwatson * Redistribution and use in source and binary forms, with or without
6138447Srwatson * modification, are permitted provided that the following conditions
7138447Srwatson * are met:
8138447Srwatson * 1. Redistributions of source code must retain the above copyright
9138447Srwatson *    notice, this list of conditions and the following disclaimer.
10138447Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11138447Srwatson *    notice, this list of conditions and the following disclaimer in the
12138447Srwatson *    documentation and/or other materials provided with the distribution.
13138447Srwatson *
14138447Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15138447Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16138447Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17138447Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18138447Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19138447Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20138447Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21138447Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22138447Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23138447Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24138447Srwatson * SUCH DAMAGE.
25138447Srwatson *
26138447Srwatson * $FreeBSD$
27138447Srwatson */
28138447Srwatson
29138447Srwatson/*
30138447Srwatson * Regression test to do some very basic AIO exercising on several types of
31138447Srwatson * file descriptors.  Currently, the tests consist of initializing a fixed
32138447Srwatson * size buffer with pseudo-random data, writing it to one fd using AIO, then
33138447Srwatson * reading it from a second descriptor using AIO.  For some targets, the same
34138447Srwatson * fd is used for write and read (i.e., file, md device), but for others the
35138447Srwatson * operation is performed on a peer (pty, socket, fifo, etc).  A timeout is
36138447Srwatson * initiated to detect undo blocking.  This test does not attempt to exercise
37138447Srwatson * error cases or more subtle asynchronous behavior, just make sure that the
38138447Srwatson * basic operations work on some basic object types.
39138447Srwatson */
40138447Srwatson
41280893Sngie#include <sys/param.h>
42280893Sngie#include <sys/module.h>
43138447Srwatson#include <sys/socket.h>
44205224Skib#include <sys/stat.h>
45138447Srwatson#include <sys/mdioctl.h>
46138447Srwatson
47138447Srwatson#include <aio.h>
48138447Srwatson#include <err.h>
49138447Srwatson#include <errno.h>
50138447Srwatson#include <fcntl.h>
51205224Skib#include <libutil.h>
52138447Srwatson#include <limits.h>
53253526Skib#include <stdint.h>
54138447Srwatson#include <stdio.h>
55205224Skib#include <stdlib.h>
56138447Srwatson#include <string.h>
57138447Srwatson#include <termios.h>
58138447Srwatson#include <unistd.h>
59138447Srwatson
60281593Sngie#include <atf-c.h>
61138447Srwatson
62282858Sngie#include "freebsd_test_suite/macros.h"
63282858Sngie
64281593Sngie#define	PATH_TEMPLATE	"aio.XXXXXXXXXX"
65281593Sngie
66138447Srwatson/*
67138447Srwatson * GLOBAL_MAX sets the largest usable buffer size to be read and written, as
68138447Srwatson * it sizes ac_buffer in the aio_context structure.  It is also the default
69138447Srwatson * size for file I/O.  For other types, we use smaller blocks or we risk
70138447Srwatson * blocking (and we run in a single process/thread so that would be bad).
71138447Srwatson */
72138447Srwatson#define	GLOBAL_MAX	16384
73138447Srwatson
74138447Srwatson#define	BUFFER_MAX	GLOBAL_MAX
75138447Srwatsonstruct aio_context {
76138447Srwatson	int		 ac_read_fd, ac_write_fd;
77138447Srwatson	long		 ac_seed;
78138447Srwatson	char		 ac_buffer[GLOBAL_MAX];
79138447Srwatson	int		 ac_buflen;
80138447Srwatson	int		 ac_seconds;
81138447Srwatson	void		 (*ac_cleanup)(void *arg);
82138447Srwatson	void		*ac_cleanup_arg;
83138447Srwatson};
84138447Srwatson
85138447Srwatsonstatic int	aio_timedout;
86138447Srwatson
87138447Srwatson/*
88138447Srwatson * Each test run specifies a timeout in seconds.  Use the somewhat obsoleted
89138447Srwatson * signal(3) and alarm(3) APIs to set this up.
90138447Srwatson */
91138447Srwatsonstatic void
92280893Sngieaio_timeout_signal(int sig __unused)
93138447Srwatson{
94138447Srwatson
95138447Srwatson	aio_timedout = 1;
96138447Srwatson}
97138447Srwatson
98138447Srwatsonstatic void
99281593Sngieaio_timeout_start(int seconds)
100138447Srwatson{
101138447Srwatson
102138447Srwatson	aio_timedout = 0;
103281593Sngie	ATF_REQUIRE_MSG(signal(SIGALRM, aio_timeout_signal) != SIG_ERR,
104281593Sngie	    "failed to set SIGALRM handler: %s", strerror(errno));
105138447Srwatson	alarm(seconds);
106138447Srwatson}
107138447Srwatson
108138447Srwatsonstatic void
109281593Sngieaio_timeout_stop(void)
110138447Srwatson{
111138447Srwatson
112281593Sngie	ATF_REQUIRE_MSG(signal(SIGALRM, NULL) != SIG_ERR,
113281593Sngie	    "failed to reset SIGALRM handler to default: %s", strerror(errno));
114138447Srwatson	alarm(0);
115138447Srwatson}
116138447Srwatson
117138447Srwatson/*
118138447Srwatson * Fill a buffer given a seed that can be fed into srandom() to initialize
119138447Srwatson * the PRNG in a repeatable manner.
120138447Srwatson */
121138447Srwatsonstatic void
122138447Srwatsonaio_fill_buffer(char *buffer, int len, long seed)
123138447Srwatson{
124138447Srwatson	char ch;
125138447Srwatson	int i;
126138447Srwatson
127138447Srwatson	srandom(seed);
128138447Srwatson	for (i = 0; i < len; i++) {
129138447Srwatson		ch = random() & 0xff;
130138447Srwatson		buffer[i] = ch;
131138447Srwatson	}
132138447Srwatson}
133138447Srwatson
134138447Srwatson/*
135138447Srwatson * Test that a buffer matches a given seed.  See aio_fill_buffer().  Return
136138447Srwatson * (1) on a match, (0) on a mismatch.
137138447Srwatson */
138138447Srwatsonstatic int
139138447Srwatsonaio_test_buffer(char *buffer, int len, long seed)
140138447Srwatson{
141138447Srwatson	char ch;
142138447Srwatson	int i;
143138447Srwatson
144138447Srwatson	srandom(seed);
145138447Srwatson	for (i = 0; i < len; i++) {
146138447Srwatson		ch = random() & 0xff;
147138447Srwatson		if (buffer[i] != ch)
148138447Srwatson			return (0);
149138447Srwatson	}
150138447Srwatson	return (1);
151138447Srwatson}
152138447Srwatson
153138447Srwatson/*
154138447Srwatson * Initialize a testing context given the file descriptors provided by the
155138447Srwatson * test setup.
156138447Srwatson */
157138447Srwatsonstatic void
158281593Sngieaio_context_init(struct aio_context *ac, int read_fd,
159138447Srwatson    int write_fd, int buflen, int seconds, void (*cleanup)(void *),
160138447Srwatson    void *cleanup_arg)
161138447Srwatson{
162138447Srwatson
163281593Sngie	ATF_REQUIRE_MSG(buflen <= BUFFER_MAX,
164281593Sngie	    "aio_context_init: buffer too large (%d > %d)",
165281593Sngie	    buflen, BUFFER_MAX);
166138447Srwatson	bzero(ac, sizeof(*ac));
167138447Srwatson	ac->ac_read_fd = read_fd;
168138447Srwatson	ac->ac_write_fd = write_fd;
169138447Srwatson	ac->ac_buflen = buflen;
170138447Srwatson	srandomdev();
171138447Srwatson	ac->ac_seed = random();
172138447Srwatson	aio_fill_buffer(ac->ac_buffer, buflen, ac->ac_seed);
173281593Sngie	ATF_REQUIRE_MSG(aio_test_buffer(ac->ac_buffer, buflen,
174281593Sngie	    ac->ac_seed) != 0, "aio_test_buffer: internal error");
175138447Srwatson	ac->ac_seconds = seconds;
176138447Srwatson	ac->ac_cleanup = cleanup;
177138447Srwatson	ac->ac_cleanup_arg = cleanup_arg;
178138447Srwatson}
179138447Srwatson
180138447Srwatson/*
181138447Srwatson * Each tester can register a callback to clean up in the event the test
182138447Srwatson * fails.  Preserve the value of errno so that subsequent calls to errx()
183138447Srwatson * work properly.
184138447Srwatson */
185138447Srwatsonstatic void
186138447Srwatsonaio_cleanup(struct aio_context *ac)
187138447Srwatson{
188138447Srwatson	int error;
189138447Srwatson
190138447Srwatson	if (ac->ac_cleanup == NULL)
191138447Srwatson		return;
192138447Srwatson	error = errno;
193138447Srwatson	(ac->ac_cleanup)(ac->ac_cleanup_arg);
194138447Srwatson	errno = error;
195138447Srwatson}
196138447Srwatson
197138447Srwatson/*
198138447Srwatson * Perform a simple write test of our initialized data buffer to the provided
199138447Srwatson * file descriptor.
200138447Srwatson */
201138447Srwatsonstatic void
202138447Srwatsonaio_write_test(struct aio_context *ac)
203138447Srwatson{
204138447Srwatson	struct aiocb aio, *aiop;
205138447Srwatson	ssize_t len;
206138447Srwatson
207282858Sngie	ATF_REQUIRE_KERNEL_MODULE("aio");
208280893Sngie
209138447Srwatson	bzero(&aio, sizeof(aio));
210138447Srwatson	aio.aio_buf = ac->ac_buffer;
211138447Srwatson	aio.aio_nbytes = ac->ac_buflen;
212138447Srwatson	aio.aio_fildes = ac->ac_write_fd;
213138447Srwatson	aio.aio_offset = 0;
214138447Srwatson
215281593Sngie	aio_timeout_start(ac->ac_seconds);
216138447Srwatson
217138447Srwatson	if (aio_write(&aio) < 0) {
218138447Srwatson		if (errno == EINTR) {
219138447Srwatson			if (aio_timedout) {
220138447Srwatson				aio_cleanup(ac);
221281593Sngie				atf_tc_fail("aio_write timed out");
222138447Srwatson			}
223138447Srwatson		}
224138447Srwatson		aio_cleanup(ac);
225281593Sngie		atf_tc_fail("aio_write failed: %s", strerror(errno));
226138447Srwatson	}
227138447Srwatson
228138447Srwatson	len = aio_waitcomplete(&aiop, NULL);
229138447Srwatson	if (len < 0) {
230138447Srwatson		if (errno == EINTR) {
231138447Srwatson			if (aio_timedout) {
232138447Srwatson				aio_cleanup(ac);
233281593Sngie				atf_tc_fail("aio_waitcomplete timed out");
234138447Srwatson			}
235138447Srwatson		}
236138447Srwatson		aio_cleanup(ac);
237281593Sngie		atf_tc_fail("aio_waitcomplete failed: %s", strerror(errno));
238138447Srwatson	}
239138447Srwatson
240281593Sngie	aio_timeout_stop();
241138447Srwatson
242138447Srwatson	if (len != ac->ac_buflen) {
243138447Srwatson		aio_cleanup(ac);
244281593Sngie		atf_tc_fail("aio_waitcomplete short write (%jd)",
245281593Sngie		    (intmax_t)len);
246138447Srwatson	}
247138447Srwatson}
248138447Srwatson
249138447Srwatson/*
250138447Srwatson * Perform a simple read test of our initialized data buffer from the
251138447Srwatson * provided file descriptor.
252138447Srwatson */
253138447Srwatsonstatic void
254138447Srwatsonaio_read_test(struct aio_context *ac)
255138447Srwatson{
256138447Srwatson	struct aiocb aio, *aiop;
257138447Srwatson	ssize_t len;
258138447Srwatson
259282858Sngie	ATF_REQUIRE_KERNEL_MODULE("aio");
260280893Sngie
261138447Srwatson	bzero(ac->ac_buffer, ac->ac_buflen);
262138447Srwatson	bzero(&aio, sizeof(aio));
263138447Srwatson	aio.aio_buf = ac->ac_buffer;
264138447Srwatson	aio.aio_nbytes = ac->ac_buflen;
265138447Srwatson	aio.aio_fildes = ac->ac_read_fd;
266138447Srwatson	aio.aio_offset = 0;
267138447Srwatson
268281593Sngie	aio_timeout_start(ac->ac_seconds);
269138447Srwatson
270138447Srwatson	if (aio_read(&aio) < 0) {
271138447Srwatson		if (errno == EINTR) {
272138447Srwatson			if (aio_timedout) {
273138447Srwatson				aio_cleanup(ac);
274281593Sngie				atf_tc_fail("aio_write timed out");
275138447Srwatson			}
276138447Srwatson		}
277138447Srwatson		aio_cleanup(ac);
278281593Sngie		atf_tc_fail("aio_read failed: %s", strerror(errno));
279138447Srwatson	}
280138447Srwatson
281138447Srwatson	len = aio_waitcomplete(&aiop, NULL);
282138447Srwatson	if (len < 0) {
283138447Srwatson		if (errno == EINTR) {
284138447Srwatson			if (aio_timedout) {
285138447Srwatson				aio_cleanup(ac);
286281593Sngie				atf_tc_fail("aio_waitcomplete timed out");
287138447Srwatson			}
288138447Srwatson		}
289138447Srwatson		aio_cleanup(ac);
290281593Sngie		atf_tc_fail("aio_waitcomplete failed: %s", strerror(errno));
291138447Srwatson	}
292138447Srwatson
293281593Sngie	aio_timeout_stop();
294138447Srwatson
295138447Srwatson	if (len != ac->ac_buflen) {
296138447Srwatson		aio_cleanup(ac);
297281593Sngie		atf_tc_fail("aio_waitcomplete short read (%jd)",
298281593Sngie		    (intmax_t)len);
299138447Srwatson	}
300138447Srwatson
301138447Srwatson	if (aio_test_buffer(ac->ac_buffer, ac->ac_buflen, ac->ac_seed) == 0) {
302138447Srwatson		aio_cleanup(ac);
303281593Sngie		atf_tc_fail("buffer mismatched");
304138447Srwatson	}
305138447Srwatson}
306138447Srwatson
307138447Srwatson/*
308138447Srwatson * Series of type-specific tests for AIO.  For now, we just make sure we can
309138447Srwatson * issue a write and then a read to each type.  We assume that once a write
310138447Srwatson * is issued, a read can follow.
311138447Srwatson */
312138447Srwatson
313138447Srwatson/*
314138447Srwatson * Test with a classic file.  Assumes we can create a moderate size temporary
315138447Srwatson * file.
316138447Srwatson */
317138447Srwatsonstruct aio_file_arg {
318138447Srwatson	int	 afa_fd;
319138447Srwatson	char	*afa_pathname;
320138447Srwatson};
321138447Srwatson
322138447Srwatsonstatic void
323138447Srwatsonaio_file_cleanup(void *arg)
324138447Srwatson{
325138447Srwatson	struct aio_file_arg *afa;
326138447Srwatson
327138447Srwatson	afa = arg;
328138447Srwatson	close(afa->afa_fd);
329138447Srwatson	unlink(afa->afa_pathname);
330138447Srwatson}
331138447Srwatson
332138447Srwatson#define	FILE_LEN	GLOBAL_MAX
333138447Srwatson#define	FILE_TIMEOUT	30
334281593SngieATF_TC_WITHOUT_HEAD(aio_file_test);
335281593SngieATF_TC_BODY(aio_file_test, tc)
336138447Srwatson{
337138447Srwatson	char pathname[PATH_MAX];
338138447Srwatson	struct aio_file_arg arg;
339138447Srwatson	struct aio_context ac;
340138447Srwatson	int fd;
341138447Srwatson
342282858Sngie	ATF_REQUIRE_KERNEL_MODULE("aio");
343280893Sngie
344138447Srwatson	strcpy(pathname, PATH_TEMPLATE);
345138447Srwatson	fd = mkstemp(pathname);
346281593Sngie	ATF_REQUIRE_MSG(fd != -1, "mkstemp failed: %s", strerror(errno));
347138447Srwatson
348138447Srwatson	arg.afa_fd = fd;
349138447Srwatson	arg.afa_pathname = pathname;
350138447Srwatson
351281593Sngie	aio_context_init(&ac, fd, fd, FILE_LEN,
352138447Srwatson	    FILE_TIMEOUT, aio_file_cleanup, &arg);
353138447Srwatson	aio_write_test(&ac);
354138447Srwatson	aio_read_test(&ac);
355138447Srwatson
356138447Srwatson	aio_file_cleanup(&arg);
357138447Srwatson}
358138447Srwatson
359138447Srwatsonstruct aio_fifo_arg {
360138447Srwatson	int	 afa_read_fd;
361138447Srwatson	int	 afa_write_fd;
362138447Srwatson	char	*afa_pathname;
363138447Srwatson};
364138447Srwatson
365138447Srwatsonstatic void
366138447Srwatsonaio_fifo_cleanup(void *arg)
367138447Srwatson{
368138447Srwatson	struct aio_fifo_arg *afa;
369138447Srwatson
370138447Srwatson	afa = arg;
371138447Srwatson	if (afa->afa_read_fd != -1)
372138447Srwatson		close(afa->afa_read_fd);
373138447Srwatson	if (afa->afa_write_fd != -1)
374138447Srwatson		close(afa->afa_write_fd);
375138447Srwatson	unlink(afa->afa_pathname);
376138447Srwatson}
377138447Srwatson
378138447Srwatson#define	FIFO_LEN	256
379138447Srwatson#define	FIFO_TIMEOUT	30
380281593SngieATF_TC_WITHOUT_HEAD(aio_fifo_test);
381281593SngieATF_TC_BODY(aio_fifo_test, tc)
382138447Srwatson{
383138447Srwatson	int error, read_fd = -1, write_fd = -1;
384138447Srwatson	struct aio_fifo_arg arg;
385138447Srwatson	char pathname[PATH_MAX];
386138447Srwatson	struct aio_context ac;
387138447Srwatson
388282858Sngie	ATF_REQUIRE_KERNEL_MODULE("aio");
389280893Sngie
390138447Srwatson	/*
391280893Sngie	 * In theory, mkstemp() can return a name that is then collided with.
392138447Srwatson	 * Because this is a regression test, we treat that as a test failure
393138447Srwatson	 * rather than retrying.
394138447Srwatson	 */
395138447Srwatson	strcpy(pathname, PATH_TEMPLATE);
396281593Sngie	ATF_REQUIRE_MSG(mkstemp(pathname) != -1,
397281593Sngie	    "mkstemp failed: %s", strerror(errno));
398281593Sngie	ATF_REQUIRE_MSG(unlink(pathname) == 0,
399281593Sngie	    "unlink failed: %s", strerror(errno));
400281593Sngie	ATF_REQUIRE_MSG(mkfifo(pathname, 0600) != -1,
401281593Sngie	    "mkfifo failed: %s", strerror(errno));
402138447Srwatson	arg.afa_pathname = pathname;
403138447Srwatson	arg.afa_read_fd = -1;
404138447Srwatson	arg.afa_write_fd = -1;
405138447Srwatson
406138447Srwatson	read_fd = open(pathname, O_RDONLY | O_NONBLOCK);
407138447Srwatson	if (read_fd == -1) {
408138447Srwatson		error = errno;
409138447Srwatson		aio_fifo_cleanup(&arg);
410138447Srwatson		errno = error;
411281593Sngie		atf_tc_fail("read_fd open failed: %s",
412138447Srwatson		    strerror(errno));
413138447Srwatson	}
414138447Srwatson	arg.afa_read_fd = read_fd;
415138447Srwatson
416138447Srwatson	write_fd = open(pathname, O_WRONLY);
417138447Srwatson	if (write_fd == -1) {
418138447Srwatson		error = errno;
419138447Srwatson		aio_fifo_cleanup(&arg);
420138447Srwatson		errno = error;
421281593Sngie		atf_tc_fail("write_fd open failed: %s",
422138447Srwatson		    strerror(errno));
423138447Srwatson	}
424138447Srwatson	arg.afa_write_fd = write_fd;
425138447Srwatson
426281593Sngie	aio_context_init(&ac, read_fd, write_fd, FIFO_LEN,
427138447Srwatson	    FIFO_TIMEOUT, aio_fifo_cleanup, &arg);
428138447Srwatson	aio_write_test(&ac);
429138447Srwatson	aio_read_test(&ac);
430138447Srwatson
431138447Srwatson	aio_fifo_cleanup(&arg);
432138447Srwatson}
433138447Srwatson
434138447Srwatsonstruct aio_unix_socketpair_arg {
435138447Srwatson	int	asa_sockets[2];
436138447Srwatson};
437138447Srwatson
438138447Srwatsonstatic void
439138447Srwatsonaio_unix_socketpair_cleanup(void *arg)
440138447Srwatson{
441138447Srwatson	struct aio_unix_socketpair_arg *asa;
442138447Srwatson
443138447Srwatson	asa = arg;
444138447Srwatson	close(asa->asa_sockets[0]);
445138447Srwatson	close(asa->asa_sockets[1]);
446138447Srwatson}
447138447Srwatson
448138447Srwatson#define	UNIX_SOCKETPAIR_LEN	256
449138447Srwatson#define	UNIX_SOCKETPAIR_TIMEOUT	30
450281593SngieATF_TC_WITHOUT_HEAD(aio_unix_socketpair_test);
451281593SngieATF_TC_BODY(aio_unix_socketpair_test, tc)
452138447Srwatson{
453138447Srwatson	struct aio_unix_socketpair_arg arg;
454138447Srwatson	struct aio_context ac;
455138447Srwatson	int sockets[2];
456138447Srwatson
457282858Sngie	ATF_REQUIRE_KERNEL_MODULE("aio");
458280893Sngie
459281593Sngie	ATF_REQUIRE_MSG(socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) != -1,
460281593Sngie	    "socketpair failed: %s", strerror(errno));
461138447Srwatson
462138447Srwatson	arg.asa_sockets[0] = sockets[0];
463138447Srwatson	arg.asa_sockets[1] = sockets[1];
464281593Sngie	aio_context_init(&ac, sockets[0],
465138447Srwatson	    sockets[1], UNIX_SOCKETPAIR_LEN, UNIX_SOCKETPAIR_TIMEOUT,
466138447Srwatson	    aio_unix_socketpair_cleanup, &arg);
467138447Srwatson	aio_write_test(&ac);
468138447Srwatson	aio_read_test(&ac);
469138447Srwatson
470138447Srwatson	aio_unix_socketpair_cleanup(&arg);
471138447Srwatson}
472138447Srwatson
473138447Srwatsonstruct aio_pty_arg {
474138447Srwatson	int	apa_read_fd;
475138447Srwatson	int	apa_write_fd;
476138447Srwatson};
477138447Srwatson
478138447Srwatsonstatic void
479138447Srwatsonaio_pty_cleanup(void *arg)
480138447Srwatson{
481138447Srwatson	struct aio_pty_arg *apa;
482138447Srwatson
483253526Skib	apa = arg;
484138447Srwatson	close(apa->apa_read_fd);
485138447Srwatson	close(apa->apa_write_fd);
486138447Srwatson};
487138447Srwatson
488138447Srwatson#define	PTY_LEN		256
489138447Srwatson#define	PTY_TIMEOUT	30
490281593SngieATF_TC_WITHOUT_HEAD(aio_pty_test);
491281593SngieATF_TC_BODY(aio_pty_test, tc)
492138447Srwatson{
493138447Srwatson	struct aio_pty_arg arg;
494138447Srwatson	struct aio_context ac;
495138447Srwatson	int read_fd, write_fd;
496138447Srwatson	struct termios ts;
497138447Srwatson	int error;
498138447Srwatson
499282858Sngie	ATF_REQUIRE_KERNEL_MODULE("aio");
500280893Sngie
501281593Sngie	ATF_REQUIRE_MSG(openpty(&read_fd, &write_fd, NULL, NULL, NULL) == 0,
502281593Sngie	    "openpty failed: %s", strerror(errno));
503138447Srwatson
504138447Srwatson	arg.apa_read_fd = read_fd;
505138447Srwatson	arg.apa_write_fd = write_fd;
506138447Srwatson
507138447Srwatson	if (tcgetattr(write_fd, &ts) < 0) {
508138447Srwatson		error = errno;
509138447Srwatson		aio_pty_cleanup(&arg);
510138447Srwatson		errno = error;
511281593Sngie		atf_tc_fail("tcgetattr failed: %s", strerror(errno));
512138447Srwatson	}
513138447Srwatson	cfmakeraw(&ts);
514138447Srwatson	if (tcsetattr(write_fd, TCSANOW, &ts) < 0) {
515138447Srwatson		error = errno;
516138447Srwatson		aio_pty_cleanup(&arg);
517138447Srwatson		errno = error;
518281593Sngie		atf_tc_fail("tcsetattr failed: %s", strerror(errno));
519138447Srwatson	}
520281593Sngie	aio_context_init(&ac, read_fd, write_fd, PTY_LEN,
521281593Sngie	    PTY_TIMEOUT, aio_pty_cleanup, &arg);
522138447Srwatson
523138447Srwatson	aio_write_test(&ac);
524138447Srwatson	aio_read_test(&ac);
525138447Srwatson
526138447Srwatson	aio_pty_cleanup(&arg);
527138447Srwatson}
528138447Srwatson
529138447Srwatsonstatic void
530138447Srwatsonaio_pipe_cleanup(void *arg)
531138447Srwatson{
532138447Srwatson	int *pipes = arg;
533138447Srwatson
534138447Srwatson	close(pipes[0]);
535138447Srwatson	close(pipes[1]);
536138447Srwatson}
537138447Srwatson
538138447Srwatson#define	PIPE_LEN	256
539138447Srwatson#define	PIPE_TIMEOUT	30
540281593SngieATF_TC_WITHOUT_HEAD(aio_pipe_test);
541281593SngieATF_TC_BODY(aio_pipe_test, tc)
542281593Sngie{
543138447Srwatson	struct aio_context ac;
544138447Srwatson	int pipes[2];
545138447Srwatson
546282858Sngie	ATF_REQUIRE_KERNEL_MODULE("aio");
547280893Sngie
548281593Sngie	ATF_REQUIRE_MSG(pipe(pipes) != -1,
549281593Sngie	    "pipe failed: %s", strerror(errno));
550138447Srwatson
551281593Sngie	aio_context_init(&ac, pipes[0], pipes[1], PIPE_LEN,
552138447Srwatson	    PIPE_TIMEOUT, aio_pipe_cleanup, pipes);
553138447Srwatson	aio_write_test(&ac);
554138447Srwatson	aio_read_test(&ac);
555138447Srwatson
556138447Srwatson	aio_pipe_cleanup(pipes);
557138447Srwatson}
558138447Srwatson
559138447Srwatsonstruct aio_md_arg {
560138447Srwatson	int	ama_mdctl_fd;
561138447Srwatson	int	ama_unit;
562138447Srwatson	int	ama_fd;
563138447Srwatson};
564138447Srwatson
565138447Srwatsonstatic void
566138447Srwatsonaio_md_cleanup(void *arg)
567138447Srwatson{
568138447Srwatson	struct aio_md_arg *ama;
569138447Srwatson	struct md_ioctl mdio;
570138447Srwatson	int error;
571138447Srwatson
572138447Srwatson	ama = arg;
573138447Srwatson
574138447Srwatson	if (ama->ama_fd != -1)
575138447Srwatson		close(ama->ama_fd);
576138447Srwatson
577138447Srwatson	if (ama->ama_unit != -1) {
578138447Srwatson		bzero(&mdio, sizeof(mdio));
579138447Srwatson		mdio.md_version = MDIOVERSION;
580138447Srwatson		mdio.md_unit = ama->ama_unit;
581281593Sngie		if (ioctl(ama->ama_mdctl_fd, MDIOCDETACH, &mdio) == -1) {
582138447Srwatson			error = errno;
583138447Srwatson			close(ama->ama_mdctl_fd);
584138447Srwatson			errno = error;
585281593Sngie			atf_tc_fail("ioctl MDIOCDETACH failed: %s",
586138447Srwatson			    strerror(errno));
587138447Srwatson		}
588138447Srwatson	}
589138447Srwatson
590138447Srwatson	close(ama->ama_mdctl_fd);
591138447Srwatson}
592138447Srwatson
593138447Srwatson#define	MD_LEN		GLOBAL_MAX
594138447Srwatson#define	MD_TIMEOUT	30
595281593SngieATF_TC(aio_md_test);
596281593SngieATF_TC_HEAD(aio_md_test, tc)
597138447Srwatson{
598281593Sngie
599281593Sngie	atf_tc_set_md_var(tc, "require.user", "root");
600281593Sngie}
601281593SngieATF_TC_BODY(aio_md_test, tc)
602281593Sngie{
603280893Sngie	int error, fd, mdctl_fd, unit;
604138447Srwatson	char pathname[PATH_MAX];
605138447Srwatson	struct aio_md_arg arg;
606138447Srwatson	struct aio_context ac;
607138447Srwatson	struct md_ioctl mdio;
608138447Srwatson
609282858Sngie	ATF_REQUIRE_KERNEL_MODULE("aio");
610280893Sngie
611138447Srwatson	mdctl_fd = open("/dev/" MDCTL_NAME, O_RDWR, 0);
612281593Sngie	ATF_REQUIRE_MSG(mdctl_fd != -1,
613281593Sngie	    "opening /dev/%s failed: %s", MDCTL_NAME, strerror(errno));
614138447Srwatson
615138447Srwatson	bzero(&mdio, sizeof(mdio));
616138447Srwatson	mdio.md_version = MDIOVERSION;
617138447Srwatson	mdio.md_type = MD_MALLOC;
618138447Srwatson	mdio.md_options = MD_AUTOUNIT | MD_COMPRESS;
619138447Srwatson	mdio.md_mediasize = GLOBAL_MAX;
620138447Srwatson	mdio.md_sectorsize = 512;
621138447Srwatson
622138447Srwatson	arg.ama_mdctl_fd = mdctl_fd;
623138447Srwatson	arg.ama_unit = -1;
624138447Srwatson	arg.ama_fd = -1;
625138447Srwatson	if (ioctl(mdctl_fd, MDIOCATTACH, &mdio) < 0) {
626138447Srwatson		error = errno;
627138447Srwatson		aio_md_cleanup(&arg);
628138447Srwatson		errno = error;
629281593Sngie		atf_tc_fail("ioctl MDIOCATTACH failed: %s", strerror(errno));
630138447Srwatson	}
631138447Srwatson
632138447Srwatson	arg.ama_unit = unit = mdio.md_unit;
633138447Srwatson	snprintf(pathname, PATH_MAX, "/dev/md%d", unit);
634138447Srwatson	fd = open(pathname, O_RDWR);
635281593Sngie	ATF_REQUIRE_MSG(fd != -1,
636281593Sngie	    "opening %s failed: %s", pathname, strerror(errno));
637138447Srwatson	arg.ama_fd = fd;
638138447Srwatson
639281593Sngie	aio_context_init(&ac, fd, fd, MD_LEN, MD_TIMEOUT,
640138447Srwatson	    aio_md_cleanup, &arg);
641138447Srwatson	aio_write_test(&ac);
642138447Srwatson	aio_read_test(&ac);
643138447Srwatson
644138447Srwatson	aio_md_cleanup(&arg);
645138447Srwatson}
646138447Srwatson
647281593SngieATF_TP_ADD_TCS(tp)
648138447Srwatson{
649138447Srwatson
650281593Sngie	ATF_TP_ADD_TC(tp, aio_file_test);
651281593Sngie	ATF_TP_ADD_TC(tp, aio_fifo_test);
652281593Sngie	ATF_TP_ADD_TC(tp, aio_unix_socketpair_test);
653281593Sngie	ATF_TP_ADD_TC(tp, aio_pty_test);
654281593Sngie	ATF_TP_ADD_TC(tp, aio_pipe_test);
655281593Sngie	ATF_TP_ADD_TC(tp, aio_md_test);
656280893Sngie
657281593Sngie	return (atf_no_error());
658138447Srwatson}
659