svn commit: r368653 - in projects/aio_writev: sys/kern tests/sys/aio
Alan Somers
asomers at FreeBSD.org
Tue Dec 15 06:31:47 UTC 2020
Author: asomers
Date: Tue Dec 15 06:31:46 2020
New Revision: 368653
URL: https://svnweb.freebsd.org/changeset/base/368653
Log:
aio_writev and aio_readv work on sockets now
Modified:
projects/aio_writev/sys/kern/sys_socket.c
projects/aio_writev/sys/kern/vfs_aio.c
projects/aio_writev/tests/sys/aio/aio_test.c
Modified: projects/aio_writev/sys/kern/sys_socket.c
==============================================================================
--- projects/aio_writev/sys/kern/sys_socket.c Tue Dec 15 01:45:19 2020 (r368652)
+++ projects/aio_writev/sys/kern/sys_socket.c Tue Dec 15 06:31:46 2020 (r368653)
@@ -459,7 +459,26 @@ static int soaio_lifetime;
SYSCTL_INT(_kern_ipc_aio, OID_AUTO, lifetime, CTLFLAG_RW, &soaio_lifetime, 0,
"Maximum lifetime for idle aiod");
+/* Advance the cursor in a uio by n bytes */
static void
+soaio_advance_uio(struct uio *uio, int n)
+{
+ while (n > 0) {
+ int m = MIN(n, uio->uio_iov[0].iov_len);
+ n -= m;
+ uio->uio_iov[0].iov_base = (char*)uio->uio_iov[0].iov_base + m;
+ uio->uio_iov[0].iov_len -= m;
+ MPASS(uio->uio_resid >= m);
+ uio->uio_resid -= m;
+ if (uio->uio_iov[0].iov_len == 0) {
+ MPASS(uio->uio_iovcnt >= 1);
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ }
+ }
+}
+
+static void
soaio_kproc_loop(void *arg)
{
struct proc *p;
@@ -600,30 +619,48 @@ soaio_process_job(struct socket *so, struct sockbuf *s
struct ucred *td_savedcred;
struct thread *td;
struct file *fp;
- struct uio uio;
+ struct uio uio, *auiop;
struct iovec iov;
- size_t cnt, done;
+ size_t cnt, done, job_total_nbytes;
long ru_before;
- int error, flags;
+ int error, flags, opcode;
+ bool vectored;
SOCKBUF_UNLOCK(sb);
aio_switch_vmspace(job);
td = curthread;
fp = job->fd_file;
+ opcode = job->uaiocb.aio_lio_opcode;
+ vectored = opcode == LIO_WRITEV || opcode == LIO_READV;
retry:
td_savedcred = td->td_ucred;
- td->td_ucred = job->cred;
+ if (vectored) {
+ error = copyinuio(job->uaiocb.aio_iov, job->uaiocb.aio_iovcnt,
+ &auiop);
+ if (error) {
+ aio_complete(job, -1, error);
+ SOCKBUF_LOCK(sb);
+ return;
+ }
+ } else {
+ iov.iov_base = (void *)((uintptr_t)job->uaiocb.aio_buf);
+ uio.uio_resid = job->uaiocb.aio_nbytes;
+ iov.iov_len = uio.uio_resid;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_segflg = UIO_USERSPACE;
+ auiop = &uio;
+ }
+ job_total_nbytes = auiop->uio_resid;
+ auiop->uio_offset = 0;
+ auiop->uio_td = td;
+
+ td->td_ucred = job->cred;
done = job->aio_done;
- cnt = job->uaiocb.aio_nbytes - done;
- iov.iov_base = (void *)((uintptr_t)job->uaiocb.aio_buf + done);
- iov.iov_len = cnt;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_offset = 0;
- uio.uio_resid = cnt;
- uio.uio_segflg = UIO_USERSPACE;
- uio.uio_td = td;
+ soaio_advance_uio(auiop, done);
+ cnt = auiop->uio_resid;
+ MPASS(cnt == job_total_nbytes - done);
flags = MSG_NBIO;
/*
@@ -633,26 +670,26 @@ retry:
*/
if (sb == &so->so_rcv) {
- uio.uio_rw = UIO_READ;
+ auiop->uio_rw = UIO_READ;
ru_before = td->td_ru.ru_msgrcv;
#ifdef MAC
error = mac_socket_check_receive(fp->f_cred, so);
if (error == 0)
#endif
- error = soreceive(so, NULL, &uio, NULL, NULL, &flags);
+ error = soreceive(so, NULL, auiop, NULL, NULL, &flags);
if (td->td_ru.ru_msgrcv != ru_before)
job->msgrcv = 1;
} else {
if (!TAILQ_EMPTY(&sb->sb_aiojobq))
flags |= MSG_MORETOCOME;
- uio.uio_rw = UIO_WRITE;
+ auiop->uio_rw = UIO_WRITE;
ru_before = td->td_ru.ru_msgsnd;
#ifdef MAC
error = mac_socket_check_send(fp->f_cred, so);
if (error == 0)
#endif
- error = sosend(so, NULL, &uio, NULL, NULL, flags, td);
+ error = sosend(so, NULL, auiop, NULL, NULL, flags, td);
if (td->td_ru.ru_msgsnd != ru_before)
job->msgsnd = 1;
if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) {
@@ -662,7 +699,7 @@ retry:
}
}
- done += cnt - uio.uio_resid;
+ done += cnt - auiop->uio_resid;
job->aio_done = done;
td->td_ucred = td_savedcred;
@@ -676,7 +713,7 @@ retry:
* been made, requeue this request at the head of the
* queue to try again when the socket is ready.
*/
- MPASS(done != job->uaiocb.aio_nbytes);
+ MPASS(done != job_total_nbytes);
SOCKBUF_LOCK(sb);
if (done == 0 || !(so->so_state & SS_NBIO)) {
empty_results++;
@@ -696,7 +733,7 @@ retry:
} else {
TAILQ_INSERT_HEAD(&sb->sb_aiojobq, job, list);
}
- return;
+ goto out;
}
SOCKBUF_UNLOCK(sb);
}
@@ -708,6 +745,10 @@ retry:
else
aio_complete(job, done, 0);
SOCKBUF_LOCK(sb);
+
+out:
+ if (vectored)
+ free(auiop, M_IOV);
}
static void
@@ -782,10 +823,10 @@ soo_aio_cancel(struct kaiocb *job)
so = job->fd_file->f_data;
opcode = job->uaiocb.aio_lio_opcode;
- if (opcode == LIO_READ)
+ if (opcode == LIO_READ || opcode == LIO_READV)
sb = &so->so_rcv;
else {
- MPASS(opcode == LIO_WRITE);
+ MPASS(opcode == LIO_WRITE || opcode == LIO_WRITEV);
sb = &so->so_snd;
}
@@ -817,9 +858,11 @@ soo_aio_queue(struct file *fp, struct kaiocb *job)
switch (job->uaiocb.aio_lio_opcode) {
case LIO_READ:
+ case LIO_READV:
sb = &so->so_rcv;
break;
case LIO_WRITE:
+ case LIO_WRITEV:
sb = &so->so_snd;
break;
default:
Modified: projects/aio_writev/sys/kern/vfs_aio.c
==============================================================================
--- projects/aio_writev/sys/kern/vfs_aio.c Tue Dec 15 01:45:19 2020 (r368652)
+++ projects/aio_writev/sys/kern/vfs_aio.c Tue Dec 15 06:31:46 2020 (r368653)
@@ -1695,8 +1695,6 @@ no_kqueue:
error = 0;
} else if (fp->f_ops->fo_aio_queue == NULL)
error = aio_queue_file(fp, job);
- else if (opcode == LIO_WRITEV || opcode == LIO_READV)
- error = EOPNOTSUPP;
else
error = fo_aio_queue(fp, job);
if (error)
Modified: projects/aio_writev/tests/sys/aio/aio_test.c
==============================================================================
--- projects/aio_writev/tests/sys/aio/aio_test.c Tue Dec 15 01:45:19 2020 (r368652)
+++ projects/aio_writev/tests/sys/aio/aio_test.c Tue Dec 15 06:31:46 2020 (r368653)
@@ -365,7 +365,7 @@ aio_readv_test(struct aio_context *ac, completion comp
bzero(ac->ac_buffer, ac->ac_buflen);
bzero(&aio, sizeof(aio));
- aio.aio_fildes = ac->ac_write_fd;
+ aio.aio_fildes = ac->ac_read_fd;
aio.aio_offset = 0;
len0 = ac->ac_buflen * 3 / 4;
len1 = ac->ac_buflen / 4;
@@ -543,17 +543,16 @@ 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));
- if (vectored)
+ if (vectored) {
aio_writev_test(&ac, comp, sev);
- else
+ aio_readv_test(&ac, comp, sev);
+ } else {
aio_write_test(&ac, comp, sev);
+ aio_read_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);
- ru_before = ru_after;
- aio_read_test(&ac, comp, sev);
- ATF_REQUIRE_MSG(getrusage(RUSAGE_SELF, &ru_after) != -1,
- "getrusage failed: %s", strerror(errno));
ATF_REQUIRE(ru_after.ru_msgrcv == ru_before.ru_msgrcv + 1);
close(sockets[0]);
@@ -1054,14 +1053,11 @@ ATF_TC_BODY(aio_socket_two_reads, tc)
close(s[0]);
}
-/*
- * This test ensures that aio_write() on a blocking socket of a "large"
- * buffer does not return a short completion.
- */
-ATF_TC_WITHOUT_HEAD(aio_socket_blocking_short_write);
-ATF_TC_BODY(aio_socket_blocking_short_write, tc)
+static void
+aio_socket_blocking_short_write_test(bool vectored)
{
struct aiocb iocb, *iocbp;
+ struct iovec iov[2];
char *buffer[2];
ssize_t done;
int buffer_size, sb_size;
@@ -1101,9 +1097,19 @@ ATF_TC_BODY(aio_socket_blocking_short_write, tc)
memset(&iocb, 0, sizeof(iocb));
iocb.aio_fildes = s[1];
- iocb.aio_buf = buffer[1];
- iocb.aio_nbytes = buffer_size;
- ATF_REQUIRE(aio_write(&iocb) == 0);
+ if (vectored) {
+ iov[0].iov_base = buffer[1];
+ iov[0].iov_len = buffer_size / 2 + 1;
+ iov[1].iov_base = buffer[1] + buffer_size / 2 + 1;
+ iov[1].iov_len = buffer_size / 2 - 1;
+ iocb.aio_iov = iov;
+ iocb.aio_iovcnt = 2;
+ ATF_REQUIRE(aio_writev(&iocb) == 0);
+ } else {
+ iocb.aio_buf = buffer[1];
+ iocb.aio_nbytes = buffer_size;
+ ATF_REQUIRE(aio_write(&iocb) == 0);
+ }
done = recv(s[0], buffer[0], buffer_size, MSG_WAITALL);
ATF_REQUIRE(done == buffer_size);
@@ -1119,6 +1125,26 @@ ATF_TC_BODY(aio_socket_blocking_short_write, tc)
}
/*
+ * This test ensures that aio_write() on a blocking socket of a "large"
+ * buffer does not return a short completion.
+ */
+ATF_TC_WITHOUT_HEAD(aio_socket_blocking_short_write);
+ATF_TC_BODY(aio_socket_blocking_short_write, tc)
+{
+ aio_socket_blocking_short_write_test(false);
+}
+
+/*
+ * Like aio_socket_blocking_short_write, but also tests that partially
+ * completed vectored sends can be retried correctly.
+ */
+ATF_TC_WITHOUT_HEAD(aio_socket_blocking_short_write_vectored);
+ATF_TC_BODY(aio_socket_blocking_short_write_vectored, tc)
+{
+ aio_socket_blocking_short_write_test(true);
+}
+
+/*
* This test verifies that cancelling a partially completed socket write
* returns a short write rather than ECANCELED.
*/
@@ -1686,6 +1712,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, aio_large_read_test);
ATF_TP_ADD_TC(tp, aio_socket_two_reads);
ATF_TP_ADD_TC(tp, aio_socket_blocking_short_write);
+ ATF_TP_ADD_TC(tp, aio_socket_blocking_short_write_vectored);
ATF_TP_ADD_TC(tp, aio_socket_short_write_cancel);
ATF_TP_ADD_TC(tp, aio_writev_dos_iov_len);
ATF_TP_ADD_TC(tp, aio_writev_dos_iovcnt);
More information about the svn-src-projects
mailing list