diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -562,12 +562,16 @@ ktruio = cloneuio(auio); #endif cnt = auio->uio_resid; - if ((error = fo_write(fp, auio, td->td_ucred, flags, td))) { + error = fo_write(fp, auio, td->td_ucred, flags, td); + /* + * Socket layer is responsible for special error handling, + * see sousrsend(). + */ + if (error != 0 && fp->f_type != DTYPE_SOCKET) { if (auio->uio_resid != cnt && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; - /* Socket layer is responsible for issuing SIGPIPE. */ - if (fp->f_type != DTYPE_SOCKET && error == EPIPE) { + if (error == EPIPE) { PROC_LOCK(td->td_proc); tdsignal(td, SIGPIPE); PROC_UNLOCK(td->td_proc); diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c --- a/sys/kern/sys_socket.c +++ b/sys/kern/sys_socket.c @@ -145,13 +145,7 @@ if (error) return (error); #endif - error = sosend(so, 0, uio, 0, 0, 0, uio->uio_td); - if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) { - PROC_LOCK(uio->uio_td->td_proc); - tdsignal(uio->uio_td, SIGPIPE); - PROC_UNLOCK(uio->uio_td->td_proc); - } - return (error); + return (sousrsend(so, NULL, uio, NULL, 0, NULL)); } static int @@ -646,15 +640,10 @@ error = mac_socket_check_send(fp->f_cred, so); if (error == 0) #endif - error = sosend(so, NULL, job->uiop, NULL, NULL, flags, - td); + error = sousrsend(so, NULL, job->uiop, NULL, flags, + job->userproc); if (td->td_ru.ru_msgsnd != ru_before) job->msgsnd = 1; - if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) { - PROC_LOCK(job->userproc); - kern_psignal(job->userproc, SIGPIPE); - PROC_UNLOCK(job->userproc); - } } done += cnt - job->uiop->uio_resid; diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1822,6 +1822,14 @@ return (error); } +/* + * Send to a socket from a kernel thread. + * + * XXXGL: in almost all cases uio is NULL and the mbuf is supplied. + * Exception is nfs/bootp_subr.c. It is arguable that the VNET context needs + * to be set at all. This function should just boil down to a static inline + * calling the protocol method. + */ int sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, struct mbuf *top, struct mbuf *control, int flags, struct thread *td) @@ -1835,6 +1843,47 @@ return (error); } +/* + * send(2), write(2) or aio_write(2) on a socket. + */ +int +sousrsend(struct socket *so, struct sockaddr *addr, struct uio *uio, + struct mbuf *control, int flags, struct proc *userproc) +{ + struct thread *td; + ssize_t len; + int error; + + td = uio->uio_td; + len = uio->uio_resid; + CURVNET_SET(so->so_vnet); + error = so->so_proto->pr_sosend(so, addr, uio, NULL, control, flags, + td); + CURVNET_RESTORE(); + if (error != 0) { + if (uio->uio_resid != len && + (so->so_proto->pr_flags & PR_ATOMIC) == 0 && + (error == ERESTART || error == EINTR || + error == EWOULDBLOCK)) + error = 0; + /* Generation of SIGPIPE can be controlled per socket. */ + if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0 && + (flags & MSG_NOSIGNAL) == 0) { + if (userproc != NULL) { + /* aio(4) job */ + PROC_LOCK(userproc); + kern_psignal(userproc, SIGPIPE); + PROC_UNLOCK(userproc); + } else { + PROC_LOCK(td->td_proc); + tdsignal(td, SIGPIPE); + PROC_UNLOCK(td->td_proc); + } + } + } + return (error); +} + /* * The part of soreceive() that implements reading non-inline out-of-band * data from a socket. For more complete comments, see soreceive(), from diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -798,21 +798,7 @@ ktruio = cloneuio(&auio); #endif len = auio.uio_resid; - error = sosend(so, mp->msg_name, &auio, 0, control, flags, td); - if (error != 0) { - if (auio.uio_resid != len && - (so->so_proto->pr_flags & PR_ATOMIC) == 0 && - (error == ERESTART || error == EINTR || - error == EWOULDBLOCK)) - error = 0; - /* Generation of SIGPIPE can be controlled per socket */ - if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) && - !(flags & MSG_NOSIGNAL)) { - PROC_LOCK(td->td_proc); - tdsignal(td, SIGPIPE); - PROC_UNLOCK(td->td_proc); - } - } + error = sousrsend(so, mp->msg_name, &auio, control, flags, NULL); if (error == 0) td->td_retval[0] = len - auio.uio_resid; #ifdef KTRACE diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -506,6 +506,8 @@ int sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, struct mbuf *top, struct mbuf *control, int flags, struct thread *td); +int sousrsend(struct socket *so, struct sockaddr *addr, struct uio *uio, + struct mbuf *control, int flags, struct proc *); int sosend_dgram(struct socket *so, struct sockaddr *addr, struct uio *uio, struct mbuf *top, struct mbuf *control, int flags, struct thread *td);