diff options
author | tanimura <tanimura@FreeBSD.org> | 2002-05-20 05:41:09 +0000 |
---|---|---|
committer | tanimura <tanimura@FreeBSD.org> | 2002-05-20 05:41:09 +0000 |
commit | 92d8381dd544a8237b3fd68c4e7fce9bd0903fb2 (patch) | |
tree | 2465ddbcecac65f96c5c6d5cef1a4fe3f1ac03f8 /sys/kern/uipc_syscalls.c | |
parent | 969293170b27461145f69a538d5abd15fea34ba1 (diff) | |
download | FreeBSD-src-92d8381dd544a8237b3fd68c4e7fce9bd0903fb2.zip FreeBSD-src-92d8381dd544a8237b3fd68c4e7fce9bd0903fb2.tar.gz |
Lock down a socket, milestone 1.
o Add a mutex (sb_mtx) to struct sockbuf. This protects the data in a
socket buffer. The mutex in the receive buffer also protects the data
in struct socket.
o Determine the lock strategy for each members in struct socket.
o Lock down the following members:
- so_count
- so_options
- so_linger
- so_state
o Remove *_locked() socket APIs. Make the following socket APIs
touching the members above now require a locked socket:
- sodisconnect()
- soisconnected()
- soisconnecting()
- soisdisconnected()
- soisdisconnecting()
- sofree()
- soref()
- sorele()
- sorwakeup()
- sotryfree()
- sowakeup()
- sowwakeup()
Reviewed by: alfred
Diffstat (limited to 'sys/kern/uipc_syscalls.c')
-rw-r--r-- | sys/kern/uipc_syscalls.c | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index f80dcc9..0c00fe5 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -245,12 +245,15 @@ accept1(td, uap, compat) if (error) goto done2; s = splnet(); + SOCK_LOCK(head); if ((head->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(head); splx(s); error = EINVAL; goto done; } if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) { + SOCK_UNLOCK(head); splx(s); error = EWOULDBLOCK; goto done; @@ -260,13 +263,16 @@ accept1(td, uap, compat) head->so_error = ECONNABORTED; break; } - error = tsleep((caddr_t)&head->so_timeo, PSOCK | PCATCH, + error = msleep((caddr_t)&head->so_timeo, + SOCK_MTX(head), PSOCK | PCATCH, "accept", 0); if (error) { + SOCK_UNLOCK(head); splx(s); goto done; } } + SOCK_UNLOCK(head); if (head->so_error) { error = head->so_error; head->so_error = 0; @@ -305,13 +311,17 @@ accept1(td, uap, compat) /* connection has been removed from the listen queue */ KNOTE(&head->so_rcv.sb_sel.si_note, 0); + SOCK_LOCK(so); so->so_state &= ~SS_COMP; + SOCK_UNLOCK(so); so->so_head = NULL; if (head->so_sigio != NULL) fsetown(fgetown(head->so_sigio), &so->so_sigio); FILE_LOCK(nfp); + SOCK_LOCK(so); soref(so); /* file descriptor reference */ + SOCK_UNLOCK(so); nfp->f_data = (caddr_t)so; /* nfp has ref count from falloc */ nfp->f_flag = fflag; nfp->f_ops = &socketops; @@ -432,24 +442,30 @@ connect(td, uap) mtx_lock(&Giant); if ((error = fgetsock(td, uap->s, &so, NULL)) != 0) goto done2; + SOCK_LOCK(so); if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { + SOCK_UNLOCK(so); error = EALREADY; goto done1; } + SOCK_UNLOCK(so); error = getsockaddr(&sa, uap->name, uap->namelen); if (error) goto done1; error = soconnect(so, sa, td); if (error) goto bad; + SOCK_LOCK(so); if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { + SOCK_UNLOCK(so); FREE(sa, M_SONAME); error = EINPROGRESS; goto done1; } s = splnet(); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { - error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, "connec", 0); + error = msleep((caddr_t)&so->so_timeo, + SOCK_MTX(so), PSOCK | PCATCH, "connec", 0); if (error) break; } @@ -457,9 +473,12 @@ connect(td, uap) error = so->so_error; so->so_error = 0; } + SOCK_UNLOCK(so); splx(s); bad: + SOCK_LOCK(so); so->so_state &= ~SS_ISCONNECTING; + SOCK_UNLOCK(so); FREE(sa, M_SONAME); if (error == ERESTART) error = EINTR; @@ -1412,10 +1431,13 @@ getpeername1(td, uap, compat) mtx_lock(&Giant); if ((error = fgetsock(td, uap->fdes, &so, NULL)) != 0) goto done2; + SOCK_LOCK(so); if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) { + SOCK_UNLOCK(so); error = ENOTCONN; goto done1; } + SOCK_UNLOCK(so); error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)); if (error) goto done1; @@ -1673,10 +1695,13 @@ sendfile(struct thread *td, struct sendfile_args *uap) error = EINVAL; goto done; } + SOCK_LOCK(so); if ((so->so_state & SS_ISCONNECTED) == 0) { + SOCK_UNLOCK(so); error = ENOTCONN; goto done; } + SOCK_UNLOCK(so); if (uap->offset < 0) { error = EINVAL; goto done; @@ -1739,14 +1764,17 @@ retry_lookup: * Optimize the non-blocking case by looking at the socket space * before going to the extra work of constituting the sf_buf. */ + SOCK_LOCK(so); if ((so->so_state & SS_NBIO) && sbspace(&so->so_snd) <= 0) { if (so->so_state & SS_CANTSENDMORE) error = EPIPE; else error = EAGAIN; + SOCK_UNLOCK(so); sbunlock(&so->so_snd); goto done; } + SOCK_UNLOCK(so); /* * Attempt to look up the page. * @@ -1869,6 +1897,7 @@ retry_space: * blocks before the pru_send (or more accurately, any blocking * results in a loop back to here to re-check). */ + SOCK_LOCK(so); if ((so->so_state & SS_CANTSENDMORE) || so->so_error) { if (so->so_state & SS_CANTSENDMORE) { error = EPIPE; @@ -1876,6 +1905,7 @@ retry_space: error = so->so_error; so->so_error = 0; } + SOCK_UNLOCK(so); m_freem(m); sbunlock(&so->so_snd); splx(s); @@ -1888,12 +1918,14 @@ retry_space: */ if (sbspace(&so->so_snd) < so->so_snd.sb_lowat) { if (so->so_state & SS_NBIO) { + SOCK_UNLOCK(so); m_freem(m); sbunlock(&so->so_snd); splx(s); error = EAGAIN; goto done; } + SOCK_UNLOCK(so); error = sbwait(&so->so_snd); /* * An error from sbwait usually indicates that we've @@ -1908,6 +1940,7 @@ retry_space: } goto retry_space; } + SOCK_UNLOCK(so); error = (*so->so_proto->pr_usrreqs->pru_send)(so, 0, m, 0, 0, td); splx(s); if (error) { |