Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/sys_socket.c
Show First 20 Lines • Show All 594 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
soaio_process_job(struct socket *so, struct sockbuf *sb, struct kaiocb *job) | soaio_process_job(struct socket *so, struct sockbuf *sb, struct kaiocb *job) | ||||
{ | { | ||||
struct ucred *td_savedcred; | struct ucred *td_savedcred; | ||||
struct thread *td; | struct thread *td; | ||||
struct file *fp; | struct file *fp; | ||||
struct uio uio; | size_t cnt, done, job_total_nbytes; | ||||
struct iovec iov; | |||||
size_t cnt, done; | |||||
long ru_before; | long ru_before; | ||||
int error, flags; | int error, flags; | ||||
SOCKBUF_UNLOCK(sb); | SOCKBUF_UNLOCK(sb); | ||||
aio_switch_vmspace(job); | aio_switch_vmspace(job); | ||||
td = curthread; | td = curthread; | ||||
fp = job->fd_file; | fp = job->fd_file; | ||||
retry: | retry: | ||||
td_savedcred = td->td_ucred; | td_savedcred = td->td_ucred; | ||||
td->td_ucred = job->cred; | td->td_ucred = job->cred; | ||||
job_total_nbytes = job->uiop->uio_resid + job->aio_done; | |||||
done = job->aio_done; | done = job->aio_done; | ||||
cnt = job->uaiocb.aio_nbytes - done; | cnt = job->uiop->uio_resid; | ||||
iov.iov_base = (void *)((uintptr_t)job->uaiocb.aio_buf + done); | job->uiop->uio_offset = 0; | ||||
iov.iov_len = cnt; | job->uiop->uio_td = td; | ||||
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; | |||||
flags = MSG_NBIO; | flags = MSG_NBIO; | ||||
/* | /* | ||||
* For resource usage accounting, only count a completed request | * For resource usage accounting, only count a completed request | ||||
* as a single message to avoid counting multiple calls to | * as a single message to avoid counting multiple calls to | ||||
* sosend/soreceive on a blocking socket. | * sosend/soreceive on a blocking socket. | ||||
*/ | */ | ||||
if (sb == &so->so_rcv) { | if (sb == &so->so_rcv) { | ||||
uio.uio_rw = UIO_READ; | |||||
ru_before = td->td_ru.ru_msgrcv; | ru_before = td->td_ru.ru_msgrcv; | ||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_socket_check_receive(fp->f_cred, so); | error = mac_socket_check_receive(fp->f_cred, so); | ||||
if (error == 0) | if (error == 0) | ||||
#endif | #endif | ||||
error = soreceive(so, NULL, &uio, NULL, NULL, &flags); | error = soreceive(so, NULL, job->uiop, NULL, NULL, | ||||
&flags); | |||||
if (td->td_ru.ru_msgrcv != ru_before) | if (td->td_ru.ru_msgrcv != ru_before) | ||||
job->msgrcv = 1; | job->msgrcv = 1; | ||||
} else { | } else { | ||||
if (!TAILQ_EMPTY(&sb->sb_aiojobq)) | if (!TAILQ_EMPTY(&sb->sb_aiojobq)) | ||||
flags |= MSG_MORETOCOME; | flags |= MSG_MORETOCOME; | ||||
uio.uio_rw = UIO_WRITE; | |||||
ru_before = td->td_ru.ru_msgsnd; | ru_before = td->td_ru.ru_msgsnd; | ||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_socket_check_send(fp->f_cred, so); | error = mac_socket_check_send(fp->f_cred, so); | ||||
if (error == 0) | if (error == 0) | ||||
#endif | #endif | ||||
error = sosend(so, NULL, &uio, NULL, NULL, flags, td); | error = sosend(so, NULL, job->uiop, NULL, NULL, flags, | ||||
td); | |||||
if (td->td_ru.ru_msgsnd != ru_before) | if (td->td_ru.ru_msgsnd != ru_before) | ||||
job->msgsnd = 1; | job->msgsnd = 1; | ||||
if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) { | if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) { | ||||
PROC_LOCK(job->userproc); | PROC_LOCK(job->userproc); | ||||
kern_psignal(job->userproc, SIGPIPE); | kern_psignal(job->userproc, SIGPIPE); | ||||
PROC_UNLOCK(job->userproc); | PROC_UNLOCK(job->userproc); | ||||
} | } | ||||
} | } | ||||
done += cnt - uio.uio_resid; | done += cnt - job->uiop->uio_resid; | ||||
job->aio_done = done; | job->aio_done = done; | ||||
td->td_ucred = td_savedcred; | td->td_ucred = td_savedcred; | ||||
if (error == EWOULDBLOCK) { | if (error == EWOULDBLOCK) { | ||||
/* | /* | ||||
* The request was either partially completed or not | * The request was either partially completed or not | ||||
* completed at all due to racing with a read() or | * completed at all due to racing with a read() or | ||||
* write() on the socket. If the socket is | * write() on the socket. If the socket is | ||||
* non-blocking, return with any partial completion. | * non-blocking, return with any partial completion. | ||||
* If the socket is blocking or if no progress has | * If the socket is blocking or if no progress has | ||||
* been made, requeue this request at the head of the | * been made, requeue this request at the head of the | ||||
* queue to try again when the socket is ready. | * queue to try again when the socket is ready. | ||||
*/ | */ | ||||
MPASS(done != job->uaiocb.aio_nbytes); | MPASS(done != job_total_nbytes); | ||||
SOCKBUF_LOCK(sb); | SOCKBUF_LOCK(sb); | ||||
if (done == 0 || !(so->so_state & SS_NBIO)) { | if (done == 0 || !(so->so_state & SS_NBIO)) { | ||||
empty_results++; | empty_results++; | ||||
if (soaio_ready(so, sb)) { | if (soaio_ready(so, sb)) { | ||||
empty_retries++; | empty_retries++; | ||||
SOCKBUF_UNLOCK(sb); | SOCKBUF_UNLOCK(sb); | ||||
goto retry; | goto retry; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct socket *so; | struct socket *so; | ||||
struct sockbuf *sb; | struct sockbuf *sb; | ||||
long done; | long done; | ||||
int opcode; | int opcode; | ||||
so = job->fd_file->f_data; | so = job->fd_file->f_data; | ||||
opcode = job->uaiocb.aio_lio_opcode; | opcode = job->uaiocb.aio_lio_opcode; | ||||
if (opcode == LIO_READ) | if (opcode == LIO_READ || opcode == LIO_READV) | ||||
sb = &so->so_rcv; | sb = &so->so_rcv; | ||||
else { | else { | ||||
MPASS(opcode == LIO_WRITE); | MPASS(opcode == LIO_WRITE || opcode == LIO_WRITEV); | ||||
sb = &so->so_snd; | sb = &so->so_snd; | ||||
} | } | ||||
SOCKBUF_LOCK(sb); | SOCKBUF_LOCK(sb); | ||||
if (!aio_cancel_cleared(job)) | if (!aio_cancel_cleared(job)) | ||||
TAILQ_REMOVE(&sb->sb_aiojobq, job, list); | TAILQ_REMOVE(&sb->sb_aiojobq, job, list); | ||||
if (TAILQ_EMPTY(&sb->sb_aiojobq)) | if (TAILQ_EMPTY(&sb->sb_aiojobq)) | ||||
sb->sb_flags &= ~SB_AIO; | sb->sb_flags &= ~SB_AIO; | ||||
Show All 15 Lines | soo_aio_queue(struct file *fp, struct kaiocb *job) | ||||
so = fp->f_data; | so = fp->f_data; | ||||
error = (*so->so_proto->pr_usrreqs->pru_aio_queue)(so, job); | error = (*so->so_proto->pr_usrreqs->pru_aio_queue)(so, job); | ||||
if (error == 0) | if (error == 0) | ||||
return (0); | return (0); | ||||
switch (job->uaiocb.aio_lio_opcode) { | switch (job->uaiocb.aio_lio_opcode) { | ||||
case LIO_READ: | case LIO_READ: | ||||
case LIO_READV: | |||||
sb = &so->so_rcv; | sb = &so->so_rcv; | ||||
break; | break; | ||||
case LIO_WRITE: | case LIO_WRITE: | ||||
case LIO_WRITEV: | |||||
sb = &so->so_snd; | sb = &so->so_snd; | ||||
break; | break; | ||||
default: | default: | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
SOCKBUF_LOCK(sb); | SOCKBUF_LOCK(sb); | ||||
if (!aio_set_cancel_function(job, soo_aio_cancel)) | if (!aio_set_cancel_function(job, soo_aio_cancel)) | ||||
Show All 11 Lines |