Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/uipc_usrreq.c
Show First 20 Lines • Show All 769 Lines • ▼ Show 20 Lines | uipc_detach(struct socket *so) | ||||
unp = sotounpcb(so); | unp = sotounpcb(so); | ||||
KASSERT(unp != NULL, ("uipc_detach: unp == NULL")); | KASSERT(unp != NULL, ("uipc_detach: unp == NULL")); | ||||
vp = NULL; | vp = NULL; | ||||
vplock = NULL; | vplock = NULL; | ||||
local_unp_rights = 0; | local_unp_rights = 0; | ||||
SOCK_LOCK(so); | |||||
if (!SOLISTENING(so)) { | |||||
/* | |||||
* Once the socket is removed from the global lists, | |||||
* uipc_ready() will not be able to locate its socket buffer, so | |||||
* clear the buffer now. At this point internalized rights have | |||||
* already been disposed of. | |||||
*/ | |||||
sbrelease(&so->so_rcv, so); | |||||
} | |||||
SOCK_UNLOCK(so); | |||||
UNP_LINK_WLOCK(); | UNP_LINK_WLOCK(); | ||||
LIST_REMOVE(unp, unp_link); | LIST_REMOVE(unp, unp_link); | ||||
if (unp->unp_gcflag & UNPGC_DEAD) | if (unp->unp_gcflag & UNPGC_DEAD) | ||||
LIST_REMOVE(unp, unp_dead); | LIST_REMOVE(unp, unp_dead); | ||||
unp->unp_gencnt = ++unp_gencnt; | unp->unp_gencnt = ++unp_gencnt; | ||||
--unp_count; | --unp_count; | ||||
UNP_LINK_WUNLOCK(); | UNP_LINK_WUNLOCK(); | ||||
UNP_PCB_UNLOCK_ASSERT(unp); | UNP_PCB_UNLOCK_ASSERT(unp); | ||||
restart: | restart: | ||||
if ((vp = unp->unp_vnode) != NULL) { | if ((vp = unp->unp_vnode) != NULL) { | ||||
vplock = mtx_pool_find(mtxpool_sleep, vp); | vplock = mtx_pool_find(mtxpool_sleep, vp); | ||||
mtx_lock(vplock); | mtx_lock(vplock); | ||||
} | } | ||||
jah: Does this need to be done while the unp link lock is held? | |||||
Done Inline ActionsGood point. It is sufficient to clear the socket buffer before unlinking the socket. markj: Good point. It is sufficient to clear the socket buffer before unlinking the socket. | |||||
UNP_PCB_LOCK(unp); | UNP_PCB_LOCK(unp); | ||||
if (unp->unp_vnode != vp && unp->unp_vnode != NULL) { | if (unp->unp_vnode != vp && unp->unp_vnode != NULL) { | ||||
if (vplock) | if (vplock) | ||||
mtx_unlock(vplock); | mtx_unlock(vplock); | ||||
UNP_PCB_UNLOCK(unp); | UNP_PCB_UNLOCK(unp); | ||||
goto restart; | goto restart; | ||||
} | } | ||||
if ((vp = unp->unp_vnode) != NULL) { | if ((vp = unp->unp_vnode) != NULL) { | ||||
▲ Show 20 Lines • Show All 439 Lines • ▼ Show 20 Lines | release: | ||||
* In case of PRUS_NOTREADY, uipc_ready() is responsible | * In case of PRUS_NOTREADY, uipc_ready() is responsible | ||||
* for freeing memory. | * for freeing memory. | ||||
*/ | */ | ||||
if (m != NULL && (flags & PRUS_NOTREADY) == 0) | if (m != NULL && (flags & PRUS_NOTREADY) == 0) | ||||
m_freem(m); | m_freem(m); | ||||
return (error); | return (error); | ||||
} | } | ||||
static bool | |||||
uipc_ready_scan(struct socket *so, struct mbuf *m, int count, int *errorp) | |||||
{ | |||||
struct mbuf *mb, *n; | |||||
struct sockbuf *sb; | |||||
SOCK_LOCK(so); | |||||
if (SOLISTENING(so)) { | |||||
SOCK_UNLOCK(so); | |||||
return (false); | |||||
} | |||||
mb = NULL; | |||||
sb = &so->so_rcv; | |||||
SOCKBUF_LOCK(sb); | |||||
if (sb->sb_fnrdy != NULL) { | |||||
for (mb = sb->sb_mb, n = mb->m_nextpkt; mb != NULL;) { | |||||
if (mb == m) { | |||||
*errorp = sbready(sb, m, count); | |||||
break; | |||||
} | |||||
mb = mb->m_next; | |||||
if (mb == NULL) { | |||||
mb = n; | |||||
n = mb->m_nextpkt; | |||||
} | |||||
} | |||||
} | |||||
SOCKBUF_UNLOCK(sb); | |||||
SOCK_UNLOCK(so); | |||||
return (mb != NULL); | |||||
} | |||||
static int | static int | ||||
uipc_ready(struct socket *so, struct mbuf *m, int count) | uipc_ready(struct socket *so, struct mbuf *m, int count) | ||||
{ | { | ||||
struct unpcb *unp, *unp2; | struct unpcb *unp, *unp2; | ||||
struct socket *so2; | struct socket *so2; | ||||
int error; | int error, i; | ||||
unp = sotounpcb(so); | unp = sotounpcb(so); | ||||
KASSERT(so->so_type == SOCK_STREAM, | |||||
("%s: unexpected socket type for %p", __func__, so)); | |||||
UNP_PCB_LOCK(unp); | UNP_PCB_LOCK(unp); | ||||
if ((unp2 = unp->unp_conn) == NULL) { | if ((unp2 = unp->unp_conn) == NULL) { | ||||
UNP_PCB_UNLOCK(unp); | UNP_PCB_UNLOCK(unp); | ||||
goto error; | goto search; | ||||
} | } | ||||
if (unp != unp2) { | if (unp != unp2) { | ||||
if (UNP_PCB_TRYLOCK(unp2) == 0) { | if (UNP_PCB_TRYLOCK(unp2) == 0) { | ||||
unp_pcb_hold(unp2); | unp_pcb_hold(unp2); | ||||
UNP_PCB_UNLOCK(unp); | UNP_PCB_UNLOCK(unp); | ||||
UNP_PCB_LOCK(unp2); | UNP_PCB_LOCK(unp2); | ||||
if (unp_pcb_rele(unp2)) | if (unp_pcb_rele(unp2)) | ||||
goto error; | goto search; | ||||
} else | } else | ||||
UNP_PCB_UNLOCK(unp); | UNP_PCB_UNLOCK(unp); | ||||
} | } | ||||
so2 = unp2->unp_socket; | so2 = unp2->unp_socket; | ||||
SOCKBUF_LOCK(&so2->so_rcv); | SOCKBUF_LOCK(&so2->so_rcv); | ||||
if ((error = sbready(&so2->so_rcv, m, count)) == 0) | if ((error = sbready(&so2->so_rcv, m, count)) == 0) | ||||
sorwakeup_locked(so2); | sorwakeup_locked(so2); | ||||
else | else | ||||
SOCKBUF_UNLOCK(&so2->so_rcv); | SOCKBUF_UNLOCK(&so2->so_rcv); | ||||
UNP_PCB_UNLOCK(unp2); | UNP_PCB_UNLOCK(unp2); | ||||
return (error); | return (error); | ||||
error: | |||||
for (int i = 0; i < count; i++) | search: | ||||
/* | |||||
* The receiving socket has been disconnected, but may still be valid. | |||||
* In this case, the now-ready mbufs are still present in its socket | |||||
* buffer, so perform an exhaustive search before giving up and freeing | |||||
* the mbufs. | |||||
*/ | |||||
UNP_LINK_RLOCK(); | |||||
LIST_FOREACH(unp, &unp_shead, unp_link) { | |||||
if (uipc_ready_scan(unp->unp_socket, m, count, &error)) | |||||
break; | |||||
} | |||||
UNP_LINK_RUNLOCK(); | |||||
if (unp == NULL) { | |||||
for (i = 0; i < count; i++) | |||||
m = m_free(m); | m = m_free(m); | ||||
return (ECONNRESET); | error = ECONNRESET; | ||||
} | |||||
return (error); | |||||
} | } | ||||
static int | static int | ||||
uipc_sense(struct socket *so, struct stat *sb) | uipc_sense(struct socket *so, struct stat *sb) | ||||
{ | { | ||||
struct unpcb *unp; | struct unpcb *unp; | ||||
unp = sotounpcb(so); | unp = sotounpcb(so); | ||||
▲ Show 20 Lines • Show All 1,618 Lines • Show Last 20 Lines |
Does this need to be done while the unp link lock is held?