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