svn commit: r368595 - in projects/aio_writev: lib/libc/sys sys/bsm sys/compat/freebsd32 sys/kern sys/sys tests/sys/aio

Alan Somers asomers at FreeBSD.org
Sat Dec 12 22:51:36 UTC 2020


Author: asomers
Date: Sat Dec 12 22:51:30 2020
New Revision: 368595
URL: https://svnweb.freebsd.org/changeset/base/368595

Log:
  WIP adding aio_writev.
  
  [x] Slow path
  [ ] Bio path
  [ ] Socket path
  [x] Man pages
  [ ] Complete tests

Modified:
  projects/aio_writev/lib/libc/sys/Makefile.inc
  projects/aio_writev/lib/libc/sys/Symbol.map
  projects/aio_writev/lib/libc/sys/aio_write.2
  projects/aio_writev/sys/bsm/audit_kevents.h
  projects/aio_writev/sys/compat/freebsd32/freebsd32_proto.h
  projects/aio_writev/sys/compat/freebsd32/freebsd32_syscall.h
  projects/aio_writev/sys/compat/freebsd32/freebsd32_syscalls.c
  projects/aio_writev/sys/compat/freebsd32/freebsd32_sysent.c
  projects/aio_writev/sys/compat/freebsd32/freebsd32_systrace_args.c
  projects/aio_writev/sys/compat/freebsd32/syscalls.master
  projects/aio_writev/sys/kern/capabilities.conf
  projects/aio_writev/sys/kern/init_sysent.c
  projects/aio_writev/sys/kern/syscalls.c
  projects/aio_writev/sys/kern/syscalls.master
  projects/aio_writev/sys/kern/systrace_args.c
  projects/aio_writev/sys/kern/vfs_aio.c
  projects/aio_writev/sys/sys/aio.h
  projects/aio_writev/sys/sys/syscall.h
  projects/aio_writev/sys/sys/syscall.mk
  projects/aio_writev/sys/sys/sysproto.h
  projects/aio_writev/tests/sys/aio/aio_test.c

Modified: projects/aio_writev/lib/libc/sys/Makefile.inc
==============================================================================
--- projects/aio_writev/lib/libc/sys/Makefile.inc	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/lib/libc/sys/Makefile.inc	Sat Dec 12 22:51:30 2020	(r368595)
@@ -353,6 +353,7 @@ MAN+=	sctp_generic_recvmsg.2 \
 	write.2 \
 	_umtx_op.2
 
+MLINKS+=aio_write.2 aio_writev.2
 MLINKS+=accept.2 accept4.2
 MLINKS+=access.2 eaccess.2 \
 	access.2 faccessat.2

Modified: projects/aio_writev/lib/libc/sys/Symbol.map
==============================================================================
--- projects/aio_writev/lib/libc/sys/Symbol.map	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/lib/libc/sys/Symbol.map	Sat Dec 12 22:51:30 2020	(r368595)
@@ -413,6 +413,7 @@ FBSD_1.6 {
 	memfd_create;
 	shm_create_largepage;
 	shm_rename;
+	aio_writev;
 };
 
 FBSDprivate_1.0 {

Modified: projects/aio_writev/lib/libc/sys/aio_write.2
==============================================================================
--- projects/aio_writev/lib/libc/sys/aio_write.2	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/lib/libc/sys/aio_write.2	Sat Dec 12 22:51:30 2020	(r368595)
@@ -24,11 +24,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd August 19, 2016
+.Dd November 29, 2020
 .Dt AIO_WRITE 2
 .Os
 .Sh NAME
-.Nm aio_write
+.Nm aio_write ,
+.Nm aio_writev
 .Nd asynchronous write to a file (REALTIME)
 .Sh LIBRARY
 .Lb libc
@@ -36,27 +37,62 @@
 .In aio.h
 .Ft int
 .Fn aio_write "struct aiocb *iocb"
+.Ft int
+.Fn aio_writev "struct aiocb *iocb"
 .Sh DESCRIPTION
 The
 .Fn aio_write
-system call allows the calling process to write
-.Fa iocb->aio_nbytes
-from the buffer pointed to by
-.Fa iocb->aio_buf
+and
+.Fn aio_writev
+system calls allow the calling process to write
 to the descriptor
 .Fa iocb->aio_fildes .
-The call returns immediately after the write request has been enqueued
+.Fn aio_write
+will write
+.Fa iocb->aio_nbytes
+from the buffer pointed to by
+.Fa iocb->aio_buf ,
+whereas
+.Fn aio_writev
+gathers the data from the
+.Fa iocb->aio_iovcnt
+buffers specified by the members of the
+.Fa iocb->aio_iov
+array.
+Both syscalls return immediately after the write request has been enqueued
 to the descriptor; the write may or may not have completed at the time
 the call returns.
 If the request could not be enqueued, generally due
 to invalid arguments, the call returns without having enqueued the
 request.
 .Pp
+For
+.Fn aio_writev
+the
+.Fa iovec
+structure is defined as:
+.Pp
+.Bd -literal -offset indent -compact
+struct iovec {
+	void   *iov_base;  /* Base address. */
+	size_t iov_len;    /* Length. */
+};
+.Ed
+.Pp
+Each
+.Fa iovec
+entry specifies the base address and length of an area
+in memory from which data should be written.
+The
+.Fn aio_writev
+system call
+will always write a complete area before proceeding
+to the next.
+.Pp
 If
 .Dv O_APPEND
 is set for
 .Fa iocb->aio_fildes ,
-.Fn aio_write
 operations append to the file in the same order as the calls were
 made.
 If
@@ -103,6 +139,8 @@ The asynchronous I/O control buffer
 .Fa iocb
 should be zeroed before the
 .Fn aio_write
+or
+.Fn aio_writev
 system call to avoid passing bogus context information to the kernel.
 .Pp
 Modifications of the Asynchronous I/O Control Block structure or the
@@ -114,11 +152,13 @@ is past the offset maximum for
 .Fa iocb->aio_fildes ,
 no I/O will occur.
 .Sh RETURN VALUES
-.Rv -std aio_write
+.Rv -std aio_write aio_writev
 .Sh ERRORS
 The
 .Fn aio_write
-system call will fail if:
+and
+.Fn aio_writev
+system calls will fail if:
 .Bl -tag -width Er
 .It Bq Er EAGAIN
 The request was not queued because of system resource limitations.
@@ -134,10 +174,14 @@ are unsafe and unsafe asynchronous I/O operations are 
 .Pp
 The following conditions may be synchronously detected when the
 .Fn aio_write
+or
+.Fn aio_writev
 system call is made, or asynchronously, at any time thereafter.
 If they
 are detected at call time,
 .Fn aio_write
+or
+.Fn aio_writev
 returns -1 and sets
 .Va errno
 appropriately; otherwise the
@@ -203,11 +247,19 @@ system call
 is expected to conform to the
 .St -p1003.1
 standard.
+.Pp
+The
+.Fn aio_writev
+system call is a FreeBSD extension, and should not be used in portable code.
 .Sh HISTORY
 The
 .Fn aio_write
 system call first appeared in
 .Fx 3.0 .
+The
+.Fn aio_writev
+system call first appeared in
+.Fx 13.0 .
 .Sh AUTHORS
 This manual page was written by
 .An Wes Peters Aq Mt wes at softweyr.com .

Modified: projects/aio_writev/sys/bsm/audit_kevents.h
==============================================================================
--- projects/aio_writev/sys/bsm/audit_kevents.h	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/bsm/audit_kevents.h	Sat Dec 12 22:51:30 2020	(r368595)
@@ -659,6 +659,7 @@
 #define	AUE_SHMRENAME		43263	/* FreeBSD-specific. */
 #define	AUE_REALPATHAT		43264	/* FreeBSD-specific. */
 #define	AUE_CLOSERANGE		43265	/* FreeBSD-specific. */
+#define	AUE_AIO_WRITEV		43266	/* FreeBSD-specific. */
 
 /*
  * Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the

Modified: projects/aio_writev/sys/compat/freebsd32/freebsd32_proto.h
==============================================================================
--- projects/aio_writev/sys/compat/freebsd32/freebsd32_proto.h	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/compat/freebsd32/freebsd32_proto.h	Sat Dec 12 22:51:30 2020	(r368595)
@@ -251,6 +251,9 @@ struct freebsd32_lio_listio_args {
 	char nent_l_[PADL_(int)]; int nent; char nent_r_[PADR_(int)];
 	char sig_l_[PADL_(struct sigevent32 *)]; struct sigevent32 * sig; char sig_r_[PADR_(struct sigevent32 *)];
 };
+struct freebsd32_aio_writev_args {
+	char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)];
+};
 struct freebsd32_lutimes_args {
 	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
 	char tptr_l_[PADL_(struct timeval32 *)]; struct timeval32 * tptr; char tptr_r_[PADR_(struct timeval32 *)];
@@ -789,6 +792,7 @@ int	freebsd32_clock_getcpuclockid2(struct thread *, st
 int	freebsd32_aio_read(struct thread *, struct freebsd32_aio_read_args *);
 int	freebsd32_aio_write(struct thread *, struct freebsd32_aio_write_args *);
 int	freebsd32_lio_listio(struct thread *, struct freebsd32_lio_listio_args *);
+int	freebsd32_aio_writev(struct thread *, struct freebsd32_aio_writev_args *);
 int	freebsd32_lutimes(struct thread *, struct freebsd32_lutimes_args *);
 int	freebsd32_preadv(struct thread *, struct freebsd32_preadv_args *);
 int	freebsd32_pwritev(struct thread *, struct freebsd32_pwritev_args *);
@@ -1374,6 +1378,7 @@ int	freebsd11_freebsd32_fstatat(struct thread *, struc
 #define	FREEBSD32_SYS_AUE_freebsd32_aio_read	AUE_AIO_READ
 #define	FREEBSD32_SYS_AUE_freebsd32_aio_write	AUE_AIO_WRITE
 #define	FREEBSD32_SYS_AUE_freebsd32_lio_listio	AUE_LIO_LISTIO
+#define	FREEBSD32_SYS_AUE_freebsd32_aio_writev	AUE_AIO_WRITEV
 #define	FREEBSD32_SYS_AUE_freebsd11_freebsd32_getdents	AUE_O_GETDENTS
 #define	FREEBSD32_SYS_AUE_freebsd32_lutimes	AUE_LUTIMES
 #define	FREEBSD32_SYS_AUE_freebsd32_preadv	AUE_PREADV

Modified: projects/aio_writev/sys/compat/freebsd32/freebsd32_syscall.h
==============================================================================
--- projects/aio_writev/sys/compat/freebsd32/freebsd32_syscall.h	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/compat/freebsd32/freebsd32_syscall.h	Sat Dec 12 22:51:30 2020	(r368595)
@@ -229,6 +229,7 @@
 #define	FREEBSD32_SYS_freebsd32_aio_read	255
 #define	FREEBSD32_SYS_freebsd32_aio_write	256
 #define	FREEBSD32_SYS_freebsd32_lio_listio	257
+#define	FREEBSD32_SYS_freebsd32_aio_writev	258
 #define	FREEBSD32_SYS_freebsd11_freebsd32_getdents	272
 #define	FREEBSD32_SYS_lchmod	274
 				/* 275 is obsolete netbsd_lchown */

Modified: projects/aio_writev/sys/compat/freebsd32/freebsd32_syscalls.c
==============================================================================
--- projects/aio_writev/sys/compat/freebsd32/freebsd32_syscalls.c	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/compat/freebsd32/freebsd32_syscalls.c	Sat Dec 12 22:51:30 2020	(r368595)
@@ -267,7 +267,7 @@ const char *freebsd32_syscallnames[] = {
 	"freebsd32_aio_read",			/* 255 = freebsd32_aio_read */
 	"freebsd32_aio_write",			/* 256 = freebsd32_aio_write */
 	"freebsd32_lio_listio",			/* 257 = freebsd32_lio_listio */
-	"#258",			/* 258 = nosys */
+	"freebsd32_aio_writev",			/* 258 = freebsd32_aio_writev */
 	"#259",			/* 259 = nosys */
 	"#260",			/* 260 = nosys */
 	"#261",			/* 261 = nosys */

Modified: projects/aio_writev/sys/compat/freebsd32/freebsd32_sysent.c
==============================================================================
--- projects/aio_writev/sys/compat/freebsd32/freebsd32_sysent.c	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/compat/freebsd32/freebsd32_sysent.c	Sat Dec 12 22:51:30 2020	(r368595)
@@ -320,7 +320,7 @@ struct sysent freebsd32_sysent[] = {
 	{ .sy_narg = AS(freebsd32_aio_read_args), .sy_call = (sy_call_t *)freebsd32_aio_read, .sy_auevent = AUE_AIO_READ, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC },	/* 255 = freebsd32_aio_read */
 	{ .sy_narg = AS(freebsd32_aio_write_args), .sy_call = (sy_call_t *)freebsd32_aio_write, .sy_auevent = AUE_AIO_WRITE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC },	/* 256 = freebsd32_aio_write */
 	{ .sy_narg = AS(freebsd32_lio_listio_args), .sy_call = (sy_call_t *)freebsd32_lio_listio, .sy_auevent = AUE_LIO_LISTIO, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC },	/* 257 = freebsd32_lio_listio */
-	{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT },			/* 258 = nosys */
+	{ .sy_narg = AS(freebsd32_aio_writev_args), .sy_call = (sy_call_t *)freebsd32_aio_writev, .sy_auevent = AUE_AIO_WRITEV, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC },	/* 258 = freebsd32_aio_writev */
 	{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT },			/* 259 = nosys */
 	{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT },			/* 260 = nosys */
 	{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT },			/* 261 = nosys */

Modified: projects/aio_writev/sys/compat/freebsd32/freebsd32_systrace_args.c
==============================================================================
--- projects/aio_writev/sys/compat/freebsd32/freebsd32_systrace_args.c	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/compat/freebsd32/freebsd32_systrace_args.c	Sat Dec 12 22:51:30 2020	(r368595)
@@ -1284,6 +1284,13 @@ systrace_args(int sysnum, void *params, uint64_t *uarg
 		*n_args = 4;
 		break;
 	}
+	/* freebsd32_aio_writev */
+	case 258: {
+		struct freebsd32_aio_writev_args *p = params;
+		uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb32 * */
+		*n_args = 1;
+		break;
+	}
 	/* lchmod */
 	case 274: {
 		struct lchmod_args *p = params;
@@ -5411,6 +5418,16 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *d
 			break;
 		};
 		break;
+	/* freebsd32_aio_writev */
+	case 258:
+		switch(ndx) {
+		case 0:
+			p = "userland struct aiocb32 *";
+			break;
+		default:
+			break;
+		};
+		break;
 	/* lchmod */
 	case 274:
 		switch(ndx) {
@@ -9865,6 +9882,11 @@ systrace_return_setargdesc(int sysnum, int ndx, char *
 		break;
 	/* freebsd32_lio_listio */
 	case 257:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* freebsd32_aio_writev */
+	case 258:
 		if (ndx == 0 || ndx == 1)
 			p = "int";
 		break;

Modified: projects/aio_writev/sys/compat/freebsd32/syscalls.master
==============================================================================
--- projects/aio_writev/sys/compat/freebsd32/syscalls.master	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/compat/freebsd32/syscalls.master	Sat Dec 12 22:51:30 2020	(r368595)
@@ -493,7 +493,8 @@
 257	AUE_LIO_LISTIO	STD	{ int freebsd32_lio_listio(int mode, \
 				    struct aiocb32 * const *acb_list, \
 				    int nent, struct sigevent32 *sig); }
-258	AUE_NULL	UNIMPL	nosys
+258	AUE_AIO_WRITEV	STD	{ int freebsd32_aio_writev( \
+				    struct aiocb32 *aiocbp); }
 259	AUE_NULL	UNIMPL	nosys
 260	AUE_NULL	UNIMPL	nosys
 261	AUE_NULL	UNIMPL	nosys

Modified: projects/aio_writev/sys/kern/capabilities.conf
==============================================================================
--- projects/aio_writev/sys/kern/capabilities.conf	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/kern/capabilities.conf	Sat Dec 12 22:51:30 2020	(r368595)
@@ -95,6 +95,7 @@ aio_return
 aio_suspend
 aio_waitcomplete
 aio_write
+aio_writev
 
 ##
 ## audit(2) is a global operation, submitting to the global trail, but it is

Modified: projects/aio_writev/sys/kern/init_sysent.c
==============================================================================
--- projects/aio_writev/sys/kern/init_sysent.c	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/kern/init_sysent.c	Sat Dec 12 22:51:30 2020	(r368595)
@@ -313,7 +313,7 @@ struct sysent sysent[] = {
 	{ .sy_narg = AS(aio_read_args), .sy_call = (sy_call_t *)sys_aio_read, .sy_auevent = AUE_AIO_READ, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC },	/* 255 = aio_read */
 	{ .sy_narg = AS(aio_write_args), .sy_call = (sy_call_t *)sys_aio_write, .sy_auevent = AUE_AIO_WRITE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC },	/* 256 = aio_write */
 	{ .sy_narg = AS(lio_listio_args), .sy_call = (sy_call_t *)sys_lio_listio, .sy_auevent = AUE_LIO_LISTIO, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC },	/* 257 = lio_listio */
-	{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT },			/* 258 = nosys */
+	{ .sy_narg = AS(aio_writev_args), .sy_call = (sy_call_t *)sys_aio_writev, .sy_auevent = AUE_AIO_WRITEV, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC },	/* 258 = aio_writev */
 	{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT },			/* 259 = nosys */
 	{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT },			/* 260 = nosys */
 	{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT },			/* 261 = nosys */

Modified: projects/aio_writev/sys/kern/syscalls.c
==============================================================================
--- projects/aio_writev/sys/kern/syscalls.c	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/kern/syscalls.c	Sat Dec 12 22:51:30 2020	(r368595)
@@ -264,7 +264,7 @@ const char *syscallnames[] = {
 	"aio_read",			/* 255 = aio_read */
 	"aio_write",			/* 256 = aio_write */
 	"lio_listio",			/* 257 = lio_listio */
-	"#258",			/* 258 = nosys */
+	"aio_writev",			/* 258 = aio_writev */
 	"#259",			/* 259 = nosys */
 	"#260",			/* 260 = nosys */
 	"#261",			/* 261 = nosys */

Modified: projects/aio_writev/sys/kern/syscalls.master
==============================================================================
--- projects/aio_writev/sys/kern/syscalls.master	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/kern/syscalls.master	Sat Dec 12 22:51:30 2020	(r368595)
@@ -1477,7 +1477,12 @@
 		    _In_opt_ struct sigevent *sig
 		);
 	}
-258-271	AUE_NULL	UNIMPL	nosys
+258	AUE_AIO_WRITEV	STD {
+		int aio_writev(
+		    _Inout_ struct aiocb *aiocbp
+		);
+	}
+259-271	AUE_NULL	UNIMPL	nosys
 272	AUE_O_GETDENTS	COMPAT11 {
 		int getdents(
 		    int fd,

Modified: projects/aio_writev/sys/kern/systrace_args.c
==============================================================================
--- projects/aio_writev/sys/kern/systrace_args.c	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/kern/systrace_args.c	Sat Dec 12 22:51:30 2020	(r368595)
@@ -1320,6 +1320,13 @@ systrace_args(int sysnum, void *params, uint64_t *uarg
 		*n_args = 4;
 		break;
 	}
+	/* aio_writev */
+	case 258: {
+		struct aio_writev_args *p = params;
+		uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb * */
+		*n_args = 1;
+		break;
+	}
 	/* lchmod */
 	case 274: {
 		struct lchmod_args *p = params;
@@ -5462,6 +5469,16 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *d
 			break;
 		};
 		break;
+	/* aio_writev */
+	case 258:
+		switch(ndx) {
+		case 0:
+			p = "userland struct aiocb *";
+			break;
+		default:
+			break;
+		};
+		break;
 	/* lchmod */
 	case 274:
 		switch(ndx) {
@@ -9792,6 +9809,11 @@ systrace_return_setargdesc(int sysnum, int ndx, char *
 		break;
 	/* lio_listio */
 	case 257:
+		if (ndx == 0 || ndx == 1)
+			p = "int";
+		break;
+	/* aio_writev */
+	case 258:
 		if (ndx == 0 || ndx == 1)
 			p = "int";
 		break;

Modified: projects/aio_writev/sys/kern/vfs_aio.c
==============================================================================
--- projects/aio_writev/sys/kern/vfs_aio.c	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/kern/vfs_aio.c	Sat Dec 12 22:51:30 2020	(r368595)
@@ -756,6 +756,7 @@ aio_process_rw(struct kaiocb *job)
 	struct file *fp;
 	struct uio auio;
 	struct iovec aiov;
+	struct uio *auiop;
 	ssize_t cnt;
 	long msgsnd_st, msgsnd_end;
 	long msgrcv_st, msgrcv_end;
@@ -764,7 +765,8 @@ aio_process_rw(struct kaiocb *job)
 	int error;
 
 	KASSERT(job->uaiocb.aio_lio_opcode == LIO_READ ||
-	    job->uaiocb.aio_lio_opcode == LIO_WRITE,
+	    job->uaiocb.aio_lio_opcode == LIO_WRITE ||
+	    job->uaiocb.aio_lio_opcode == LIO_WRITEV,
 	    ("%s: opcode %d", __func__, job->uaiocb.aio_lio_opcode));
 
 	aio_switch_vmspace(job);
@@ -774,16 +776,26 @@ aio_process_rw(struct kaiocb *job)
 	cb = &job->uaiocb;
 	fp = job->fd_file;
 
-	aiov.iov_base = (void *)(uintptr_t)cb->aio_buf;
-	aiov.iov_len = cb->aio_nbytes;
+	if (job->uaiocb.aio_lio_opcode == LIO_WRITEV) {
+		error = copyinuio(job->uaiocb.aio_iov, job->uaiocb.aio_iovcnt,
+		    &auiop);
+		if (error) {
+			aio_complete(job, -1, error);
+			return;
+		}
+	} else {
+		aiov.iov_base = (void *)(uintptr_t)cb->aio_buf;
+		aiov.iov_len = cb->aio_nbytes;
+		auio.uio_iov = &aiov;
+		auio.uio_iovcnt = 1;
+		auio.uio_resid = cb->aio_nbytes;
+		auio.uio_segflg = UIO_USERSPACE;
+		auiop = &auio;
+	}
 
-	auio.uio_iov = &aiov;
-	auio.uio_iovcnt = 1;
-	auio.uio_offset = cb->aio_offset;
-	auio.uio_resid = cb->aio_nbytes;
-	cnt = cb->aio_nbytes;
-	auio.uio_segflg = UIO_USERSPACE;
-	auio.uio_td = td;
+	auiop->uio_offset = cb->aio_offset;
+	auiop->uio_td = td;
+	cnt = auiop->uio_resid;
 
 	msgrcv_st = td->td_ru.ru_msgrcv;
 	msgsnd_st = td->td_ru.ru_msgsnd;
@@ -795,16 +807,16 @@ aio_process_rw(struct kaiocb *job)
 	 * released in aio_free_entry().
 	 */
 	if (cb->aio_lio_opcode == LIO_READ) {
-		auio.uio_rw = UIO_READ;
-		if (auio.uio_resid == 0)
+		auiop->uio_rw = UIO_READ;
+		if (auiop->uio_resid == 0)
 			error = 0;
 		else
-			error = fo_read(fp, &auio, fp->f_cred, FOF_OFFSET, td);
+			error = fo_read(fp, auiop, fp->f_cred, FOF_OFFSET, td);
 	} else {
 		if (fp->f_type == DTYPE_VNODE)
 			bwillwrite();
-		auio.uio_rw = UIO_WRITE;
-		error = fo_write(fp, &auio, fp->f_cred, FOF_OFFSET, td);
+		auiop->uio_rw = UIO_WRITE;
+		error = fo_write(fp, auiop, fp->f_cred, FOF_OFFSET, td);
 	}
 	msgrcv_end = td->td_ru.ru_msgrcv;
 	msgsnd_end = td->td_ru.ru_msgsnd;
@@ -816,7 +828,7 @@ aio_process_rw(struct kaiocb *job)
 	job->inblock = inblock_end - inblock_st;
 	job->outblock = oublock_end - oublock_st;
 
-	if ((error) && (auio.uio_resid != cnt)) {
+	if ((error) && (auiop->uio_resid != cnt)) {
 		if (error == ERESTART || error == EINTR || error == EWOULDBLOCK)
 			error = 0;
 		if ((error == EPIPE) && (cb->aio_lio_opcode == LIO_WRITE)) {
@@ -826,8 +838,10 @@ aio_process_rw(struct kaiocb *job)
 		}
 	}
 
-	cnt -= auio.uio_resid;
+	cnt -= auiop->uio_resid;
 	td->td_ucred = td_savedcred;
+	if (job->uaiocb.aio_lio_opcode == LIO_WRITEV)
+		free(auiop, M_IOV);
 	if (error)
 		aio_complete(job, -1, error);
 	else
@@ -1222,6 +1236,7 @@ aio_qbio(struct proc *p, struct kaiocb *job)
 	cb = &job->uaiocb;
 	fp = job->fd_file;
 
+	// TODO: handle LIO_WRITEV
 	if (!(cb->aio_lio_opcode == LIO_WRITE ||
 	    cb->aio_lio_opcode == LIO_READ))
 		return (-1);
@@ -1278,6 +1293,7 @@ aio_qbio(struct proc *p, struct kaiocb *job)
 		AIO_UNLOCK(ki);
 		job->pages = pbuf->b_pages;
 	}
+	/* For LIO_WRITEV, create a parent bio with multiple child bios */
 	job->bp = bp = g_alloc_bio();
 
 	bp->bio_length = cb->aio_nbytes;
@@ -1533,6 +1549,7 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, stru
 	fd = job->uaiocb.aio_fildes;
 	switch (opcode) {
 	case LIO_WRITE:
+	case LIO_WRITEV:
 		error = fget_write(td, fd, &cap_pwrite_rights, &fp);
 		break;
 	case LIO_READ:
@@ -1561,9 +1578,9 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, stru
 		goto aqueue_fail;
 	}
 
-	if ((opcode == LIO_READ || opcode == LIO_WRITE) &&
-	    job->uaiocb.aio_offset < 0 &&
-	    (fp->f_vnode == NULL || fp->f_vnode->v_type != VCHR)) {
+	if ((opcode == LIO_READ || opcode == LIO_WRITE || opcode == LIO_WRITEV)
+	    && job->uaiocb.aio_offset < 0
+	    && (fp->f_vnode == NULL || fp->f_vnode->v_type != VCHR)) {
 		error = EINVAL;
 		goto aqueue_fail;
 	}
@@ -1619,6 +1636,8 @@ no_kqueue:
 		error = 0;
 	} else if (fp->f_ops->fo_aio_queue == NULL)
 		error = aio_queue_file(fp, job);
+	else if (opcode == LIO_WRITEV)
+		error = EOPNOTSUPP;
 	else
 		error = fo_aio_queue(fp, job);
 	if (error)
@@ -1724,6 +1743,7 @@ aio_queue_file(struct file *fp, struct kaiocb *job)
 	switch (job->uaiocb.aio_lio_opcode) {
 	case LIO_READ:
 	case LIO_WRITE:
+	case LIO_WRITEV:
 		aio_schedule(job, aio_process_rw);
 		error = 0;
 		break;
@@ -2116,6 +2136,13 @@ sys_aio_write(struct thread *td, struct aio_write_args
 }
 
 int
+sys_aio_writev(struct thread *td, struct aio_writev_args *uap)
+{
+
+	return (aio_aqueue(td, uap->aiocbp, NULL, LIO_WRITEV, &aiocb_ops));
+}
+
+int
 sys_aio_mlock(struct thread *td, struct aio_mlock_args *uap)
 {
 
@@ -2856,6 +2883,14 @@ freebsd32_aio_write(struct thread *td, struct freebsd3
 {
 
 	return (aio_aqueue(td, (struct aiocb *)uap->aiocbp, NULL, LIO_WRITE,
+	    &aiocb32_ops));
+}
+
+int
+freebsd32_aio_writev(struct thread *td, struct freebsd32_aio_writev_args *uap)
+{
+
+	return (aio_aqueue(td, (struct aiocb *)uap->aiocbp, NULL, LIO_WRITEV,
 	    &aiocb32_ops));
 }
 

Modified: projects/aio_writev/sys/sys/aio.h
==============================================================================
--- projects/aio_writev/sys/sys/aio.h	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/sys/aio.h	Sat Dec 12 22:51:30 2020	(r368595)
@@ -45,6 +45,8 @@
 #ifdef _KERNEL
 #define	LIO_SYNC		0x3
 #define	LIO_MLOCK		0x4
+#define	LIO_WRITEV		0x5
+#define	LIO_READV		0x6
 #endif
 
 /*
@@ -92,8 +94,14 @@ struct __aiocb_private {
 typedef struct aiocb {
 	int	aio_fildes;		/* File descriptor */
 	off_t	aio_offset;		/* File offset for I/O */
-	volatile void *aio_buf;         /* I/O buffer in process space */
-	size_t	aio_nbytes;		/* Number of bytes for I/O */
+	union {
+		volatile void *aio_buf;	/* I/O buffer in process space */
+		struct iovec *aio_iov; /* I/O scatter/gather list */
+	};
+	union {
+		size_t	aio_nbytes;		/* Number of bytes for I/O */
+		int	aio_iovcnt;		/* Length of aio_iov */
+	};
 	int	__spare__[2];
 	void	*__spare2__;
 	int	aio_lio_opcode;		/* LIO opcode */
@@ -214,6 +222,7 @@ int	aio_read(struct aiocb *);
  * Asynchronously write to file
  */
 int	aio_write(struct aiocb *);
+int	aio_writev(struct aiocb *);
 
 /*
  * List I/O Asynchronously/synchronously read/write to/from file

Modified: projects/aio_writev/sys/sys/syscall.h
==============================================================================
--- projects/aio_writev/sys/sys/syscall.h	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/sys/syscall.h	Sat Dec 12 22:51:30 2020	(r368595)
@@ -234,6 +234,7 @@
 #define	SYS_aio_read	255
 #define	SYS_aio_write	256
 #define	SYS_lio_listio	257
+#define	SYS_aio_writev	258
 #define	SYS_freebsd11_getdents	272
 #define	SYS_lchmod	274
 				/* 275 is obsolete netbsd_lchown */

Modified: projects/aio_writev/sys/sys/syscall.mk
==============================================================================
--- projects/aio_writev/sys/sys/syscall.mk	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/sys/syscall.mk	Sat Dec 12 22:51:30 2020	(r368595)
@@ -168,6 +168,7 @@ MIASM =  \
 	aio_read.o \
 	aio_write.o \
 	lio_listio.o \
+	aio_writev.o \
 	freebsd11_getdents.o \
 	lchmod.o \
 	lutimes.o \

Modified: projects/aio_writev/sys/sys/sysproto.h
==============================================================================
--- projects/aio_writev/sys/sys/sysproto.h	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/sys/sys/sysproto.h	Sat Dec 12 22:51:30 2020	(r368595)
@@ -714,6 +714,9 @@ struct lio_listio_args {
 	char nent_l_[PADL_(int)]; int nent; char nent_r_[PADR_(int)];
 	char sig_l_[PADL_(struct sigevent *)]; struct sigevent * sig; char sig_r_[PADR_(struct sigevent *)];
 };
+struct aio_writev_args {
+	char aiocbp_l_[PADL_(struct aiocb *)]; struct aiocb * aiocbp; char aiocbp_r_[PADR_(struct aiocb *)];
+};
 struct lchmod_args {
 	char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
 	char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
@@ -1991,6 +1994,7 @@ int	sys_lchown(struct thread *, struct lchown_args *);
 int	sys_aio_read(struct thread *, struct aio_read_args *);
 int	sys_aio_write(struct thread *, struct aio_write_args *);
 int	sys_lio_listio(struct thread *, struct lio_listio_args *);
+int	sys_aio_writev(struct thread *, struct aio_writev_args *);
 int	sys_lchmod(struct thread *, struct lchmod_args *);
 int	sys_lutimes(struct thread *, struct lutimes_args *);
 int	sys_preadv(struct thread *, struct preadv_args *);
@@ -2901,6 +2905,7 @@ int	freebsd12_closefrom(struct thread *, struct freebs
 #define	SYS_AUE_aio_read	AUE_AIO_READ
 #define	SYS_AUE_aio_write	AUE_AIO_WRITE
 #define	SYS_AUE_lio_listio	AUE_LIO_LISTIO
+#define	SYS_AUE_aio_writev	AUE_AIO_WRITEV
 #define	SYS_AUE_freebsd11_getdents	AUE_O_GETDENTS
 #define	SYS_AUE_lchmod	AUE_LCHMOD
 #define	SYS_AUE_lutimes	AUE_LUTIMES

Modified: projects/aio_writev/tests/sys/aio/aio_test.c
==============================================================================
--- projects/aio_writev/tests/sys/aio/aio_test.c	Sat Dec 12 22:47:57 2020	(r368594)
+++ projects/aio_writev/tests/sys/aio/aio_test.c	Sat Dec 12 22:51:30 2020	(r368595)
@@ -282,6 +282,49 @@ aio_write_test(struct aio_context *ac, completion comp
 }
 
 /*
+ * Perform a vectored I/O test of our initialized data buffer to the provided
+ * file descriptor.
+ *
+ * To vectorize the linear buffer, chop it up into two pieces of dissimilar
+ * size, and swap their offsets.
+ */
+static void
+aio_writev_test(struct aio_context *ac, completion comp, struct sigevent *sev)
+{
+	struct aiocb aio;
+	struct iovec iov[2];
+	size_t len0, len1;
+	ssize_t len;
+
+	bzero(&aio, sizeof(aio));
+
+	aio.aio_fildes = ac->ac_write_fd;
+	aio.aio_offset = 0;
+	len0 = ac->ac_buflen * 3 / 4;
+	len1 = ac->ac_buflen / 4;
+	// TODO: once aio_readv is ready, swap the offsets of the two parts of
+	// the buffer.
+	iov[0].iov_base = ac->ac_buffer;
+	iov[0].iov_len = len0;
+	iov[1].iov_base = ac->ac_buffer + len0;
+	iov[1].iov_len = len1;
+	aio.aio_iov = iov;
+	aio.aio_iovcnt = 2;
+	if (sev)
+		aio.aio_sigevent = *sev;
+
+	if (aio_writev(&aio) < 0)
+		atf_tc_fail("aio_writev failed: %s", strerror(errno));
+
+	len = comp(&aio);
+	if (len < 0)
+		atf_tc_fail("aio failed: %s", strerror(errno));
+
+	if (len != ac->ac_buflen)
+		atf_tc_fail("aio short write (%jd)", (intmax_t)len);
+}
+
+/*
  * Perform a simple read test of our initialized data buffer from the
  * provided file descriptor.
  */
@@ -328,7 +371,7 @@ aio_read_test(struct aio_context *ac, completion comp,
 #define	FILE_PATHNAME	"testfile"
 
 static void
-aio_file_test(completion comp, struct sigevent *sev)
+aio_file_test(completion comp, struct sigevent *sev, bool vectored)
 {
 	struct aio_context ac;
 	int fd;
@@ -340,7 +383,10 @@ aio_file_test(completion comp, struct sigevent *sev)
 	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
 
 	aio_context_init(&ac, fd, fd, FILE_LEN);
-	aio_write_test(&ac, comp, sev);
+	if (vectored)
+		aio_writev_test(&ac, comp, sev);
+	else
+		aio_write_test(&ac, comp, sev);
 	aio_read_test(&ac, comp, sev);
 	close(fd);
 }
@@ -348,31 +394,31 @@ aio_file_test(completion comp, struct sigevent *sev)
 ATF_TC_WITHOUT_HEAD(file_poll);
 ATF_TC_BODY(file_poll, tc)
 {
-	aio_file_test(poll, NULL);
+	aio_file_test(poll, NULL, false);
 }
 
 ATF_TC_WITHOUT_HEAD(file_signal);
 ATF_TC_BODY(file_signal, tc)
 {
-	aio_file_test(poll_signaled, setup_signal());
+	aio_file_test(poll_signaled, setup_signal(), false);
 }
 
 ATF_TC_WITHOUT_HEAD(file_suspend);
 ATF_TC_BODY(file_suspend, tc)
 {
-	aio_file_test(suspend, NULL);
+	aio_file_test(suspend, NULL, false);
 }
 
 ATF_TC_WITHOUT_HEAD(file_thread);
 ATF_TC_BODY(file_thread, tc)
 {
-	aio_file_test(poll_signaled, setup_thread());
+	aio_file_test(poll_signaled, setup_thread(), false);
 }
 
 ATF_TC_WITHOUT_HEAD(file_waitcomplete);
 ATF_TC_BODY(file_waitcomplete, tc)
 {
-	aio_file_test(waitcomplete, NULL);
+	aio_file_test(waitcomplete, NULL, false);
 }
 
 #define	FIFO_LEN	256
@@ -446,7 +492,7 @@ ATF_TC_BODY(fifo_waitcomplete, tc)
 
 #define	UNIX_SOCKETPAIR_LEN	256
 static void
-aio_unix_socketpair_test(completion comp, struct sigevent *sev)
+aio_unix_socketpair_test(completion comp, struct sigevent *sev, bool vectored)
 {
 	struct aio_context ac;
 	struct rusage ru_before, ru_after;
@@ -460,7 +506,10 @@ aio_unix_socketpair_test(completion comp, struct sigev
 	aio_context_init(&ac, sockets[0], sockets[1], UNIX_SOCKETPAIR_LEN);
 	ATF_REQUIRE_MSG(getrusage(RUSAGE_SELF, &ru_before) != -1,
 	    "getrusage failed: %s", strerror(errno));
-	aio_write_test(&ac, comp, sev);
+	if (vectored)
+		aio_writev_test(&ac, comp, sev);
+	else
+		aio_write_test(&ac, comp, sev);
 	ATF_REQUIRE_MSG(getrusage(RUSAGE_SELF, &ru_after) != -1,
 	    "getrusage failed: %s", strerror(errno));
 	ATF_REQUIRE(ru_after.ru_msgsnd == ru_before.ru_msgsnd + 1);
@@ -477,31 +526,31 @@ aio_unix_socketpair_test(completion comp, struct sigev
 ATF_TC_WITHOUT_HEAD(socket_poll);
 ATF_TC_BODY(socket_poll, tc)
 {
-	aio_unix_socketpair_test(poll, NULL);
+	aio_unix_socketpair_test(poll, NULL, false);
 }
 
 ATF_TC_WITHOUT_HEAD(socket_signal);
 ATF_TC_BODY(socket_signal, tc)
 {
-	aio_unix_socketpair_test(poll_signaled, setup_signal());
+	aio_unix_socketpair_test(poll_signaled, setup_signal(), false);
 }
 
 ATF_TC_WITHOUT_HEAD(socket_suspend);
 ATF_TC_BODY(socket_suspend, tc)
 {
-	aio_unix_socketpair_test(suspend, NULL);
+	aio_unix_socketpair_test(suspend, NULL, false);
 }
 
 ATF_TC_WITHOUT_HEAD(socket_thread);
 ATF_TC_BODY(socket_thread, tc)
 {
-	aio_unix_socketpair_test(poll_signaled, setup_thread());
+	aio_unix_socketpair_test(poll_signaled, setup_thread(), false);
 }
 
 ATF_TC_WITHOUT_HEAD(socket_waitcomplete);
 ATF_TC_BODY(socket_waitcomplete, tc)
 {
-	aio_unix_socketpair_test(waitcomplete, NULL);
+	aio_unix_socketpair_test(waitcomplete, NULL, false);
 }
 
 struct aio_pty_arg {
@@ -658,7 +707,7 @@ aio_md_cleanup(void)
 }
 
 static void
-aio_md_test(completion comp, struct sigevent *sev)
+aio_md_test(completion comp, struct sigevent *sev, bool vectored)
 {
 	int error, fd, mdctl_fd, unit;
 	char pathname[PATH_MAX];
@@ -696,7 +745,10 @@ aio_md_test(completion comp, struct sigevent *sev)
 	    "opening %s failed: %s", pathname, strerror(errno));
 
 	aio_context_init(&ac, fd, fd, MD_LEN);
-	aio_write_test(&ac, comp, sev);
+	if (vectored)
+		aio_writev_test(&ac, comp, sev);
+	else
+		aio_write_test(&ac, comp, sev);
 	aio_read_test(&ac, comp, sev);
 	
 	close(fd);
@@ -710,7 +762,7 @@ ATF_TC_HEAD(md_poll, tc)
 }
 ATF_TC_BODY(md_poll, tc)
 {
-	aio_md_test(poll, NULL);
+	aio_md_test(poll, NULL, false);
 }
 ATF_TC_CLEANUP(md_poll, tc)
 {
@@ -725,7 +777,7 @@ ATF_TC_HEAD(md_signal, tc)
 }
 ATF_TC_BODY(md_signal, tc)
 {
-	aio_md_test(poll_signaled, setup_signal());
+	aio_md_test(poll_signaled, setup_signal(), false);
 }
 ATF_TC_CLEANUP(md_signal, tc)
 {
@@ -740,7 +792,7 @@ ATF_TC_HEAD(md_suspend, tc)
 }
 ATF_TC_BODY(md_suspend, tc)
 {
-	aio_md_test(suspend, NULL);
+	aio_md_test(suspend, NULL, false);
 }
 ATF_TC_CLEANUP(md_suspend, tc)
 {
@@ -755,7 +807,7 @@ ATF_TC_HEAD(md_thread, tc)
 }
 ATF_TC_BODY(md_thread, tc)
 {
-	aio_md_test(poll_signaled, setup_thread());
+	aio_md_test(poll_signaled, setup_thread(), false);
 }
 ATF_TC_CLEANUP(md_thread, tc)
 {
@@ -770,7 +822,7 @@ ATF_TC_HEAD(md_waitcomplete, tc)
 }
 ATF_TC_BODY(md_waitcomplete, tc)
 {
-	aio_md_test(waitcomplete, NULL);
+	aio_md_test(waitcomplete, NULL, false);
 }
 ATF_TC_CLEANUP(md_waitcomplete, tc)
 {
@@ -1155,6 +1207,134 @@ ATF_TC_BODY(aio_fsync_test, tc)
 	close(fd);
 }
 
+// We shouldn't be able to DOS the system by setting iov_len to an insane
+// value
+ATF_TC_WITHOUT_HEAD(aio_writev_dos_iov_len);
+ATF_TC_BODY(aio_writev_dos_iov_len, tc)
+{
+	struct aiocb aio;
+	const struct aiocb *const iocbs[] = {&aio};
+	const char *wbuf = "Hello, world!";
+	struct iovec iov[1];
+	ssize_t len, r;
+	int fd;
+
+	ATF_REQUIRE_KERNEL_MODULE("aio");
+	ATF_REQUIRE_UNSAFE_AIO();
+
+	fd = open("testfile", O_RDWR | O_CREAT, 0600);
+	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
+
+	len = strlen(wbuf);
+	iov[0].iov_base = __DECONST(void*, wbuf);
+	iov[0].iov_len = 1 << 30;
+	bzero(&aio, sizeof(aio));
+	aio.aio_fildes = fd;
+	aio.aio_offset = 0;
+	aio.aio_iov = iov;
+	aio.aio_iovcnt = 1;
+
+	r = aio_writev(&aio);
+	ATF_CHECK_EQ_MSG(0, r, "aio_writev returned %ld", r);
+	ATF_REQUIRE_EQ(0, aio_suspend(iocbs, 1, NULL));
+	r = aio_return(&aio);
+	ATF_CHECK_EQ_MSG(-1, r, "aio_return returned %ld", r);
+	ATF_CHECK_MSG(errno == EFAULT || errno == EINVAL,
+	    "aio_writev: %s", strerror(errno));
+
+	close(fd);
+}
+
+// We shouldn't be able to DOS the system by setting aio_iovcnt to an insane
+// value
+ATF_TC_WITHOUT_HEAD(aio_writev_dos_iovcnt);
+ATF_TC_BODY(aio_writev_dos_iovcnt, tc)
+{
+	struct aiocb aio;
+	const struct aiocb *const iocbs[] = {&aio};
+	const char *wbuf = "Hello, world!";
+	struct iovec iov[1];
+	ssize_t len, r;
+	int fd;
+
+	ATF_REQUIRE_KERNEL_MODULE("aio");
+	ATF_REQUIRE_UNSAFE_AIO();
+
+	fd = open("testfile", O_RDWR | O_CREAT, 0600);
+	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
+
+	len = strlen(wbuf);
+	iov[0].iov_base = __DECONST(void*, wbuf);
+	iov[0].iov_len = len;
+	bzero(&aio, sizeof(aio));
+	aio.aio_fildes = fd;
+	aio.aio_offset = 0;
+	aio.aio_iov = iov;
+	aio.aio_iovcnt = 1 << 30;
+
+	r = aio_writev(&aio);
+	ATF_CHECK_EQ_MSG(0, r, "aio_writev returned %ld", r);
+	ATF_REQUIRE_EQ(0, aio_suspend(iocbs, 1, NULL));
+	r = aio_return(&aio);
+	ATF_CHECK_EQ_MSG(-1, r, "aio_return returned %ld", r);
+	ATF_CHECK_MSG(errno == EFAULT || errno == EINVAL,
+	    "aio_writev: %s", strerror(errno));
+
+	close(fd);
+}
+
+ATF_TC_WITHOUT_HEAD(aio_writev_empty);
+ATF_TC_BODY(aio_writev_empty, tc)
+{
+	struct aiocb aio;
+	const struct aiocb *const iocbs[] = {&aio};
+	int fd;
+
+	ATF_REQUIRE_KERNEL_MODULE("aio");
+	ATF_REQUIRE_UNSAFE_AIO();
+
+	fd = open("testfile", O_RDWR | O_CREAT, 0600);
+	ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
+
+	bzero(&aio, sizeof(aio));
+	aio.aio_fildes = fd;
+	aio.aio_offset = 0;
+	aio.aio_iovcnt = 0;
+
+	ATF_REQUIRE_EQ(0, aio_writev(&aio));
+
+	ATF_REQUIRE_EQ(0, aio_suspend(iocbs, 1, NULL));
+	ATF_REQUIRE_EQ(0, aio_return(&aio));
+
+	close(fd);
+}
+
+ATF_TC_WITHOUT_HEAD(vectored_file_poll);
+ATF_TC_BODY(vectored_file_poll, tc)
+{
+	aio_file_test(poll, NULL, true);
+}
+
+ATF_TC_WITH_CLEANUP(vectored_md_poll);
+ATF_TC_HEAD(vectored_md_poll, tc)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-projects mailing list