Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/uipc_socket.c
Show First 20 Lines • Show All 414 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* The socket locking protocol allows to lock 2 sockets at a time, | * The socket locking protocol allows to lock 2 sockets at a time, | ||||
* however, the first one must be a listening socket. WITNESS lacks | * however, the first one must be a listening socket. WITNESS lacks | ||||
* a feature to change class of an existing lock, so we use DUPOK. | * a feature to change class of an existing lock, so we use DUPOK. | ||||
*/ | */ | ||||
mtx_init(&so->so_lock, "socket", NULL, MTX_DEF | MTX_DUPOK); | mtx_init(&so->so_lock, "socket", NULL, MTX_DEF | MTX_DUPOK); | ||||
so->so_snd.sb_mtx = &so->so_snd_mtx; | so->so_snd.sb_mtx = &so->so_snd_mtx; | ||||
so->so_rcv.sb_mtx = &so->so_rcv_mtx; | so->so_rcv.sb_mtx = &so->so_rcv_mtx; | ||||
SOCKBUF_LOCK_INIT(&so->so_snd, "so_snd"); | mtx_init(&so->so_snd_mtx, "so_snd", NULL, MTX_DEF); | ||||
SOCKBUF_LOCK_INIT(&so->so_rcv, "so_rcv"); | mtx_init(&so->so_rcv_mtx, "so_rcv", NULL, MTX_DEF); | ||||
so->so_rcv.sb_sel = &so->so_rdsel; | so->so_rcv.sb_sel = &so->so_rdsel; | ||||
so->so_snd.sb_sel = &so->so_wrsel; | so->so_snd.sb_sel = &so->so_wrsel; | ||||
sx_init(&so->so_snd_sx, "so_snd_sx"); | sx_init(&so->so_snd_sx, "so_snd_sx"); | ||||
sx_init(&so->so_rcv_sx, "so_rcv_sx"); | sx_init(&so->so_rcv_sx, "so_rcv_sx"); | ||||
TAILQ_INIT(&so->so_snd.sb_aiojobq); | TAILQ_INIT(&so->so_snd.sb_aiojobq); | ||||
TAILQ_INIT(&so->so_rcv.sb_aiojobq); | TAILQ_INIT(&so->so_rcv.sb_aiojobq); | ||||
TASK_INIT(&so->so_snd.sb_aiotask, 0, soaio_snd, so); | TASK_INIT(&so->so_snd.sb_aiotask, 0, soaio_snd, so); | ||||
TASK_INIT(&so->so_rcv.sb_aiotask, 0, soaio_rcv, so); | TASK_INIT(&so->so_rcv.sb_aiotask, 0, soaio_rcv, so); | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | if (SOLISTENING(so)) { | ||||
if (so->so_rcv.sb_hiwat) | if (so->so_rcv.sb_hiwat) | ||||
(void)chgsbsize(so->so_cred->cr_uidinfo, | (void)chgsbsize(so->so_cred->cr_uidinfo, | ||||
&so->so_rcv.sb_hiwat, 0, RLIM_INFINITY); | &so->so_rcv.sb_hiwat, 0, RLIM_INFINITY); | ||||
if (so->so_snd.sb_hiwat) | if (so->so_snd.sb_hiwat) | ||||
(void)chgsbsize(so->so_cred->cr_uidinfo, | (void)chgsbsize(so->so_cred->cr_uidinfo, | ||||
&so->so_snd.sb_hiwat, 0, RLIM_INFINITY); | &so->so_snd.sb_hiwat, 0, RLIM_INFINITY); | ||||
sx_destroy(&so->so_snd_sx); | sx_destroy(&so->so_snd_sx); | ||||
sx_destroy(&so->so_rcv_sx); | sx_destroy(&so->so_rcv_sx); | ||||
SOCKBUF_LOCK_DESTROY(&so->so_snd); | mtx_destroy(&so->so_snd_mtx); | ||||
SOCKBUF_LOCK_DESTROY(&so->so_rcv); | mtx_destroy(&so->so_rcv_mtx); | ||||
} | } | ||||
crfree(so->so_cred); | crfree(so->so_cred); | ||||
mtx_destroy(&so->so_lock); | mtx_destroy(&so->so_lock); | ||||
uma_zfree(socket_zone, so); | uma_zfree(socket_zone, so); | ||||
} | } | ||||
/* | /* | ||||
* socreate returns a socket with a ref count of 1. The socket should be | * socreate returns a socket with a ref count of 1. The socket should be | ||||
▲ Show 20 Lines • Show All 481 Lines • ▼ Show 20 Lines | solisten_proto(struct socket *so, int backlog) | ||||
sbsnd_lowat = so->so_snd.sb_lowat; | sbsnd_lowat = so->so_snd.sb_lowat; | ||||
sbrcv_hiwat = so->so_rcv.sb_hiwat; | sbrcv_hiwat = so->so_rcv.sb_hiwat; | ||||
sbsnd_hiwat = so->so_snd.sb_hiwat; | sbsnd_hiwat = so->so_snd.sb_hiwat; | ||||
sbrcv_flags = so->so_rcv.sb_flags; | sbrcv_flags = so->so_rcv.sb_flags; | ||||
sbsnd_flags = so->so_snd.sb_flags; | sbsnd_flags = so->so_snd.sb_flags; | ||||
sbrcv_timeo = so->so_rcv.sb_timeo; | sbrcv_timeo = so->so_rcv.sb_timeo; | ||||
sbsnd_timeo = so->so_snd.sb_timeo; | sbsnd_timeo = so->so_snd.sb_timeo; | ||||
sbdestroy(&so->so_snd, so); | sbdestroy(so, SO_SND); | ||||
sbdestroy(&so->so_rcv, so); | sbdestroy(so, SO_RCV); | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
bzero(&so->so_rcv, | bzero(&so->so_rcv, | ||||
sizeof(struct socket) - offsetof(struct socket, so_rcv)); | sizeof(struct socket) - offsetof(struct socket, so_rcv)); | ||||
#endif | #endif | ||||
so->sol_sbrcv_lowat = sbrcv_lowat; | so->sol_sbrcv_lowat = sbrcv_lowat; | ||||
so->sol_sbsnd_lowat = sbsnd_lowat; | so->sol_sbsnd_lowat = sbsnd_lowat; | ||||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | if (pr->pr_usrreqs->pru_detach != NULL) | ||||
(*pr->pr_usrreqs->pru_detach)(so); | (*pr->pr_usrreqs->pru_detach)(so); | ||||
/* | /* | ||||
* From this point on, we assume that no other references to this | * From this point on, we assume that no other references to this | ||||
* socket exist anywhere else in the stack. Therefore, no locks need | * socket exist anywhere else in the stack. Therefore, no locks need | ||||
* to be acquired or held. | * to be acquired or held. | ||||
*/ | */ | ||||
if (!SOLISTENING(so)) { | if (!SOLISTENING(so)) { | ||||
sbdestroy(&so->so_snd, so); | sbdestroy(so, SO_SND); | ||||
sbdestroy(&so->so_rcv, so); | sbdestroy(so, SO_RCV); | ||||
} | } | ||||
seldrain(&so->so_rdsel); | seldrain(&so->so_rdsel); | ||||
seldrain(&so->so_wrsel); | seldrain(&so->so_wrsel); | ||||
knlist_destroy(&so->so_rdsel.si_note); | knlist_destroy(&so->so_rdsel.si_note); | ||||
knlist_destroy(&so->so_wrsel.si_note); | knlist_destroy(&so->so_wrsel.si_note); | ||||
sodealloc(so); | sodealloc(so); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 509 Lines • ▼ Show 20 Lines | do { | ||||
if (space < resid + clen && | if (space < resid + clen && | ||||
(atomic || space < so->so_snd.sb_lowat || space < clen)) { | (atomic || space < so->so_snd.sb_lowat || space < clen)) { | ||||
if ((so->so_state & SS_NBIO) || | if ((so->so_state & SS_NBIO) || | ||||
(flags & (MSG_NBIO | MSG_DONTWAIT)) != 0) { | (flags & (MSG_NBIO | MSG_DONTWAIT)) != 0) { | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
error = EWOULDBLOCK; | error = EWOULDBLOCK; | ||||
goto release; | goto release; | ||||
} | } | ||||
error = sbwait(&so->so_snd); | error = sbwait(so, SO_SND); | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
if (error) | if (error) | ||||
goto release; | goto release; | ||||
goto restart; | goto restart; | ||||
} | } | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
space -= clen; | space -= clen; | ||||
do { | do { | ||||
▲ Show 20 Lines • Show All 315 Lines • ▼ Show 20 Lines | #endif | ||||
if ((so->so_state & SS_NBIO) || | if ((so->so_state & SS_NBIO) || | ||||
(flags & (MSG_DONTWAIT|MSG_NBIO))) { | (flags & (MSG_DONTWAIT|MSG_NBIO))) { | ||||
SOCKBUF_UNLOCK(&so->so_rcv); | SOCKBUF_UNLOCK(&so->so_rcv); | ||||
error = EWOULDBLOCK; | error = EWOULDBLOCK; | ||||
goto release; | goto release; | ||||
} | } | ||||
SBLASTRECORDCHK(&so->so_rcv); | SBLASTRECORDCHK(&so->so_rcv); | ||||
SBLASTMBUFCHK(&so->so_rcv); | SBLASTMBUFCHK(&so->so_rcv); | ||||
error = sbwait(&so->so_rcv); | error = sbwait(so, SO_RCV); | ||||
SOCKBUF_UNLOCK(&so->so_rcv); | SOCKBUF_UNLOCK(&so->so_rcv); | ||||
if (error) | if (error) | ||||
goto release; | goto release; | ||||
goto restart; | goto restart; | ||||
} | } | ||||
dontblock: | dontblock: | ||||
/* | /* | ||||
* From this point onward, we maintain 'nextrecord' as a cache of the | * From this point onward, we maintain 'nextrecord' as a cache of the | ||||
▲ Show 20 Lines • Show All 305 Lines • ▼ Show 20 Lines | while (flags & MSG_WAITALL && m == NULL && uio->uio_resid > 0 && | ||||
} | } | ||||
SBLASTRECORDCHK(&so->so_rcv); | SBLASTRECORDCHK(&so->so_rcv); | ||||
SBLASTMBUFCHK(&so->so_rcv); | SBLASTMBUFCHK(&so->so_rcv); | ||||
/* | /* | ||||
* We could receive some data while was notifying | * We could receive some data while was notifying | ||||
* the protocol. Skip blocking in this case. | * the protocol. Skip blocking in this case. | ||||
*/ | */ | ||||
if (so->so_rcv.sb_mb == NULL) { | if (so->so_rcv.sb_mb == NULL) { | ||||
error = sbwait(&so->so_rcv); | error = sbwait(so, SO_RCV); | ||||
if (error) { | if (error) { | ||||
SOCKBUF_UNLOCK(&so->so_rcv); | SOCKBUF_UNLOCK(&so->so_rcv); | ||||
goto release; | goto release; | ||||
} | } | ||||
} | } | ||||
m = so->so_rcv.sb_mb; | m = so->so_rcv.sb_mb; | ||||
if (m != NULL) | if (m != NULL) | ||||
nextrecord = m->m_nextpkt; | nextrecord = m->m_nextpkt; | ||||
▲ Show 20 Lines • Show All 164 Lines • ▼ Show 20 Lines | restart: | ||||
if ((flags & MSG_WAITALL) && | if ((flags & MSG_WAITALL) && | ||||
(sbavail(sb) >= uio->uio_resid || sbavail(sb) >= sb->sb_hiwat)) | (sbavail(sb) >= uio->uio_resid || sbavail(sb) >= sb->sb_hiwat)) | ||||
goto deliver; | goto deliver; | ||||
/* | /* | ||||
* Wait and block until (more) data comes in. | * Wait and block until (more) data comes in. | ||||
* NB: Drops the sockbuf lock during wait. | * NB: Drops the sockbuf lock during wait. | ||||
*/ | */ | ||||
error = sbwait(sb); | error = sbwait(so, SO_RCV); | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
goto restart; | goto restart; | ||||
deliver: | deliver: | ||||
SOCKBUF_LOCK_ASSERT(&so->so_rcv); | SOCKBUF_LOCK_ASSERT(&so->so_rcv); | ||||
KASSERT(sbavail(sb) > 0, ("%s: sockbuf empty", __func__)); | KASSERT(sbavail(sb) > 0, ("%s: sockbuf empty", __func__)); | ||||
KASSERT(sb->sb_mb != NULL, ("%s: sb_mb == NULL", __func__)); | KASSERT(sb->sb_mb != NULL, ("%s: sb_mb == NULL", __func__)); | ||||
▲ Show 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | while ((m = so->so_rcv.sb_mb) == NULL) { | ||||
} | } | ||||
if ((so->so_state & SS_NBIO) || | if ((so->so_state & SS_NBIO) || | ||||
(flags & (MSG_DONTWAIT|MSG_NBIO))) { | (flags & (MSG_DONTWAIT|MSG_NBIO))) { | ||||
SOCKBUF_UNLOCK(&so->so_rcv); | SOCKBUF_UNLOCK(&so->so_rcv); | ||||
return (EWOULDBLOCK); | return (EWOULDBLOCK); | ||||
} | } | ||||
SBLASTRECORDCHK(&so->so_rcv); | SBLASTRECORDCHK(&so->so_rcv); | ||||
SBLASTMBUFCHK(&so->so_rcv); | SBLASTMBUFCHK(&so->so_rcv); | ||||
error = sbwait(&so->so_rcv); | error = sbwait(so, SO_RCV); | ||||
if (error) { | if (error) { | ||||
SOCKBUF_UNLOCK(&so->so_rcv); | SOCKBUF_UNLOCK(&so->so_rcv); | ||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
SOCKBUF_LOCK_ASSERT(&so->so_rcv); | SOCKBUF_LOCK_ASSERT(&so->so_rcv); | ||||
if (uio->uio_td) | if (uio->uio_td) | ||||
▲ Show 20 Lines • Show All 201 Lines • ▼ Show 20 Lines | if (error != 0) { | ||||
return; | return; | ||||
} | } | ||||
pr = so->so_proto; | pr = so->so_proto; | ||||
if (pr->pr_flags & PR_RIGHTS) { | if (pr->pr_flags & PR_RIGHTS) { | ||||
MPASS(pr->pr_domain->dom_dispose != NULL); | MPASS(pr->pr_domain->dom_dispose != NULL); | ||||
(*pr->pr_domain->dom_dispose)(so); | (*pr->pr_domain->dom_dispose)(so); | ||||
} else { | } else { | ||||
sbrelease(&so->so_rcv, so); | sbrelease(so, SO_RCV); | ||||
SOCK_IO_RECV_UNLOCK(so); | SOCK_IO_RECV_UNLOCK(so); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Wrapper for Socket established helper hook. | * Wrapper for Socket established helper hook. | ||||
* Parameters: socket, context of the hook point, hook id. | * Parameters: socket, context of the hook point, hook id. | ||||
▲ Show 20 Lines • Show All 633 Lines • ▼ Show 20 Lines | if (SOLISTENING(so)) { | ||||
else if ((events & POLLINIGNEOF) == 0 && so->so_error) | else if ((events & POLLINIGNEOF) == 0 && so->so_error) | ||||
revents = (events & (POLLIN | POLLRDNORM)) | POLLHUP; | revents = (events & (POLLIN | POLLRDNORM)) | POLLHUP; | ||||
else { | else { | ||||
selrecord(td, &so->so_rdsel); | selrecord(td, &so->so_rdsel); | ||||
revents = 0; | revents = 0; | ||||
} | } | ||||
} else { | } else { | ||||
revents = 0; | revents = 0; | ||||
SOCKBUF_LOCK(&so->so_snd); | SOCK_SENDBUF_LOCK(so); | ||||
SOCKBUF_LOCK(&so->so_rcv); | SOCK_RECVBUF_LOCK(so); | ||||
if (events & (POLLIN | POLLRDNORM)) | if (events & (POLLIN | POLLRDNORM)) | ||||
if (soreadabledata(so)) | if (soreadabledata(so)) | ||||
revents |= events & (POLLIN | POLLRDNORM); | revents |= events & (POLLIN | POLLRDNORM); | ||||
if (events & (POLLOUT | POLLWRNORM)) | if (events & (POLLOUT | POLLWRNORM)) | ||||
if (sowriteable(so)) | if (sowriteable(so)) | ||||
revents |= events & (POLLOUT | POLLWRNORM); | revents |= events & (POLLOUT | POLLWRNORM); | ||||
if (events & (POLLPRI | POLLRDBAND)) | if (events & (POLLPRI | POLLRDBAND)) | ||||
if (so->so_oobmark || | if (so->so_oobmark || | ||||
Show All 14 Lines | if (revents == 0) { | ||||
selrecord(td, &so->so_rdsel); | selrecord(td, &so->so_rdsel); | ||||
so->so_rcv.sb_flags |= SB_SEL; | so->so_rcv.sb_flags |= SB_SEL; | ||||
} | } | ||||
if (events & (POLLOUT | POLLWRNORM)) { | if (events & (POLLOUT | POLLWRNORM)) { | ||||
selrecord(td, &so->so_wrsel); | selrecord(td, &so->so_wrsel); | ||||
so->so_snd.sb_flags |= SB_SEL; | so->so_snd.sb_flags |= SB_SEL; | ||||
} | } | ||||
} | } | ||||
SOCKBUF_UNLOCK(&so->so_rcv); | SOCK_RECVBUF_UNLOCK(so); | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCK_SENDBUF_UNLOCK(so); | ||||
} | } | ||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
return (revents); | return (revents); | ||||
} | } | ||||
int | int | ||||
soo_kqfilter(struct file *fp, struct knote *kn) | soo_kqfilter(struct file *fp, struct knote *kn) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 637 Lines • ▼ Show 20 Lines | |||||
so_rdknl_assert_lock(void *arg, int what) | so_rdknl_assert_lock(void *arg, int what) | ||||
{ | { | ||||
struct socket *so = arg; | struct socket *so = arg; | ||||
if (what == LA_LOCKED) { | if (what == LA_LOCKED) { | ||||
if (SOLISTENING(so)) | if (SOLISTENING(so)) | ||||
SOCK_LOCK_ASSERT(so); | SOCK_LOCK_ASSERT(so); | ||||
else | else | ||||
SOCKBUF_LOCK_ASSERT(&so->so_rcv); | SOCK_RECVBUF_LOCK_ASSERT(so); | ||||
} else { | } else { | ||||
if (SOLISTENING(so)) | if (SOLISTENING(so)) | ||||
SOCK_UNLOCK_ASSERT(so); | SOCK_UNLOCK_ASSERT(so); | ||||
else | else | ||||
SOCKBUF_UNLOCK_ASSERT(&so->so_rcv); | SOCK_RECVBUF_UNLOCK_ASSERT(so); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
so_wrknl_lock(void *arg) | so_wrknl_lock(void *arg) | ||||
{ | { | ||||
struct socket *so = arg; | struct socket *so = arg; | ||||
if (SOLISTENING(so)) | if (SOLISTENING(so)) | ||||
SOCK_LOCK(so); | SOCK_LOCK(so); | ||||
else | else | ||||
SOCKBUF_LOCK(&so->so_snd); | SOCK_SENDBUF_LOCK(so); | ||||
} | } | ||||
static void | static void | ||||
so_wrknl_unlock(void *arg) | so_wrknl_unlock(void *arg) | ||||
{ | { | ||||
struct socket *so = arg; | struct socket *so = arg; | ||||
if (SOLISTENING(so)) | if (SOLISTENING(so)) | ||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
else | else | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCK_SENDBUF_UNLOCK(so); | ||||
} | } | ||||
static void | static void | ||||
so_wrknl_assert_lock(void *arg, int what) | so_wrknl_assert_lock(void *arg, int what) | ||||
{ | { | ||||
struct socket *so = arg; | struct socket *so = arg; | ||||
if (what == LA_LOCKED) { | if (what == LA_LOCKED) { | ||||
if (SOLISTENING(so)) | if (SOLISTENING(so)) | ||||
SOCK_LOCK_ASSERT(so); | SOCK_LOCK_ASSERT(so); | ||||
else | else | ||||
SOCKBUF_LOCK_ASSERT(&so->so_snd); | SOCK_SENDBUF_LOCK_ASSERT(so); | ||||
} else { | } else { | ||||
if (SOLISTENING(so)) | if (SOLISTENING(so)) | ||||
SOCK_UNLOCK_ASSERT(so); | SOCK_UNLOCK_ASSERT(so); | ||||
else | else | ||||
SOCKBUF_UNLOCK_ASSERT(&so->so_snd); | SOCK_SENDBUF_UNLOCK_ASSERT(so); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Create an external-format (``xsocket'') structure using the information in | * Create an external-format (``xsocket'') structure using the information in | ||||
* the kernel-format socket structure pointed to by so. This is done to | * the kernel-format socket structure pointed to by so. This is done to | ||||
* reduce the spew of irrelevant information over this interface, to isolate | * reduce the spew of irrelevant information over this interface, to isolate | ||||
* user code from changes in the kernel structure, and potentially to provide | * user code from changes in the kernel structure, and potentially to provide | ||||
▲ Show 20 Lines • Show All 163 Lines • Show Last 20 Lines |