Page MenuHomeFreeBSD

D15430.1792563018.diff
No OneTemporary

Size
18 KB
Referenced Files
None
Subscribers
None

D15430.1792563018.diff

Index: sys/kern/uipc_usrreq.c
===================================================================
--- sys/kern/uipc_usrreq.c
+++ sys/kern/uipc_usrreq.c
@@ -257,13 +257,30 @@
#define UNP_DEFERRED_LOCK() mtx_lock(&unp_defers_lock)
#define UNP_DEFERRED_UNLOCK() mtx_unlock(&unp_defers_lock)
+#define UNP_REF_LIST_LOCK() UNP_DEFERRED_LOCK();
+#define UNP_REF_LIST_UNLOCK() UNP_DEFERRED_UNLOCK();
+
#define UNP_PCB_LOCK_INIT(unp) mtx_init(&(unp)->unp_mtx, \
"unp_mtx", "unp_mtx", \
- MTX_DUPOK|MTX_DEF|MTX_RECURSE)
+ MTX_DUPOK|MTX_DEF)
#define UNP_PCB_LOCK_DESTROY(unp) mtx_destroy(&(unp)->unp_mtx)
#define UNP_PCB_LOCK(unp) mtx_lock(&(unp)->unp_mtx)
+#define UNP_PCB_TRYLOCK(unp) mtx_trylock(&(unp)->unp_mtx)
#define UNP_PCB_UNLOCK(unp) mtx_unlock(&(unp)->unp_mtx)
+#define UNP_PCB_OWNED(unp) mtx_owned(&(unp)->unp_mtx)
#define UNP_PCB_LOCK_ASSERT(unp) mtx_assert(&(unp)->unp_mtx, MA_OWNED)
+#define UNP_PCB_UNLOCK_ASSERT(unp) mtx_assert(&(unp)->unp_mtx, MA_NOTOWNED)
+
+#define UNP_PCB_CONN_LOCK_INIT(unp) mtx_init(&(unp)->unp_conn_mtx, \
+ "unp_conn_mtx", "unp_conn_mtx", \
+ MTX_DUPOK|MTX_DEF)
+#define UNP_PCB_CONN_LOCK_DESTROY(unp) mtx_destroy(&(unp)->unp_conn_mtx)
+#define UNP_PCB_CONN_LOCK(unp) mtx_lock(&(unp)->unp_conn_mtx)
+#define UNP_PCB_CONN_TRYLOCK(unp) mtx_trylock(&(unp)->unp_conn_mtx)
+#define UNP_PCB_CONN_OWNED(unp) mtx_owned(&(unp)->unp_conn_mtx)
+#define UNP_PCB_CONN_UNLOCK(unp) mtx_unlock(&(unp)->unp_conn_mtx)
+#define UNP_PCB_CONN_LOCK_ASSERT(unp) mtx_assert(&(unp)->unp_conn_mtx, MA_OWNED)
+#define UNP_PCB_CONN_UNLOCK_ASSERT(unp) mtx_assert(&(unp)->unp_conn_mtx, MA_NOTOWNED)
static int uipc_connect2(struct socket *, struct socket *);
static int uipc_ctloutput(struct socket *, struct sockopt *);
@@ -289,6 +306,72 @@
static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *);
static void unp_process_defers(void * __unused, int);
+
+static void
+unp_pcb_hold(struct unpcb *unp)
+{
+ UNP_PCB_LOCK_ASSERT(unp);
+ MPASS(unp->unp_refcount);
+ unp->unp_refcount++;
+}
+
+static int
+unp_pcb_rele(struct unpcb *unp)
+{
+ int refcount;
+
+ UNP_PCB_LOCK_ASSERT(unp);
+ MPASS(unp->unp_refcount);
+ unp->unp_refcount--;
+ refcount = unp->unp_refcount;
+ if (refcount == 0) {
+ /* we got here with having detached? */
+ MPASS(unp->unp_socket == NULL);
+ UNP_PCB_UNLOCK(unp);
+ if (UNP_PCB_CONN_OWNED(unp)) {
+ UNP_PCB_CONN_UNLOCK(unp);
+ UNP_PCB_CONN_UNLOCK_ASSERT(unp);
+ }
+ UNP_PCB_LOCK_DESTROY(unp);
+ UNP_PCB_CONN_UNLOCK_ASSERT(unp);
+ UNP_PCB_CONN_LOCK_DESTROY(unp);
+ uma_zfree(unp_zone, unp);
+ }
+ return (refcount == 0);
+}
+
+static void
+unp_pcb_lock2(struct unpcb *unp, struct unpcb *unp2)
+{
+ UNP_PCB_UNLOCK_ASSERT(unp);
+ UNP_PCB_UNLOCK_ASSERT(unp2);
+ if ((uintptr_t)unp2 > (uintptr_t)unp) {
+ UNP_PCB_LOCK(unp);
+ UNP_PCB_LOCK(unp2);
+ } else {
+ UNP_PCB_LOCK(unp2);
+ UNP_PCB_LOCK(unp);
+ }
+}
+
+static void
+unp_pcb_owned_lock2(struct unpcb *unp, struct unpcb *unp2)
+{
+
+ UNP_PCB_LOCK_ASSERT(unp);
+ UNP_PCB_UNLOCK_ASSERT(unp2);
+ if (__predict_true(UNP_PCB_TRYLOCK(unp2)))
+ return;
+ if ((uintptr_t)unp2 > (uintptr_t)unp) {
+ UNP_PCB_LOCK(unp2);
+ } else {
+ UNP_PCB_UNLOCK(unp);
+ UNP_PCB_LOCK(unp2);
+ UNP_PCB_LOCK(unp);
+ }
+}
+
+
/*
* Definitions of protocols supported in the LOCAL domain.
*/
@@ -344,17 +427,17 @@
unp = sotounpcb(so);
KASSERT(unp != NULL, ("uipc_abort: unp == NULL"));
+ UNP_PCB_UNLOCK_ASSERT(unp);
- UNP_LINK_WLOCK();
+ UNP_PCB_CONN_LOCK(unp);
UNP_PCB_LOCK(unp);
unp2 = unp->unp_conn;
if (unp2 != NULL) {
- UNP_PCB_LOCK(unp2);
+ UNP_PCB_UNLOCK_ASSERT(unp2);
unp_drop(unp2);
- UNP_PCB_UNLOCK(unp2);
}
UNP_PCB_UNLOCK(unp);
- UNP_LINK_WUNLOCK();
+ UNP_PCB_CONN_UNLOCK(unp);
}
static int
@@ -424,6 +507,7 @@
return (ENOBUFS);
LIST_INIT(&unp->unp_refs);
UNP_PCB_LOCK_INIT(unp);
+ UNP_PCB_CONN_LOCK_INIT(unp);
unp->unp_socket = so;
so->so_pcb = unp;
unp->unp_refcount = 1;
@@ -551,14 +635,12 @@
ASSERT_VOP_ELOCKED(vp, "uipc_bind");
soun = (struct sockaddr_un *)sodupsockaddr(nam, M_WAITOK);
- UNP_LINK_WLOCK();
UNP_PCB_LOCK(unp);
VOP_UNP_BIND(vp, unp);
unp->unp_vnode = vp;
unp->unp_addr = soun;
unp->unp_flags &= ~UNP_BINDING;
UNP_PCB_UNLOCK(unp);
- UNP_LINK_WUNLOCK();
VOP_UNLOCK(vp, 0);
vn_finished_write(mp);
free(buf, M_TEMP);
@@ -585,9 +667,7 @@
int error;
KASSERT(td == curthread, ("uipc_connect: td != curthread"));
- UNP_LINK_WLOCK();
error = unp_connect(so, nam, td);
- UNP_LINK_WUNLOCK();
return (error);
}
@@ -598,9 +678,7 @@
int error;
KASSERT(td == curthread, ("uipc_connectat: td != curthread"));
- UNP_LINK_WLOCK();
error = unp_connectat(fd, so, nam, td);
- UNP_LINK_WUNLOCK();
return (error);
}
@@ -609,26 +687,40 @@
{
struct unpcb *unp, *unp2;
struct vnode *vp = NULL;
-
+ struct mtx *vplock;
unp = sotounpcb(so);
KASSERT(unp != NULL, ("uipc_close: unp == NULL"));
- UNP_LINK_WLOCK();
+
+ if ((vp = unp->unp_vnode) != NULL) {
+ vplock = mtx_pool_find(mtxpool_sleep, vp);
+ mtx_lock(vplock);
+ } else
+ vplock = NULL;
+ UNP_PCB_CONN_LOCK(unp);
UNP_PCB_LOCK(unp);
unp2 = unp->unp_conn;
- if (unp2 != NULL) {
- UNP_PCB_LOCK(unp2);
- unp_disconnect(unp, unp2);
- UNP_PCB_UNLOCK(unp2);
- }
if (SOLISTENING(so) && ((vp = unp->unp_vnode) != NULL)) {
VOP_UNP_DETACH(vp);
unp->unp_vnode = NULL;
}
- UNP_PCB_UNLOCK(unp);
- UNP_LINK_WUNLOCK();
+ unp_pcb_hold(unp);
+ if (unp2 != NULL) {
+ unp_pcb_owned_lock2(unp, unp2);
+ unp_pcb_hold(unp2);
+ unp_disconnect(unp, unp2);
+ if (unp_pcb_rele(unp2) == 0)
+ UNP_PCB_UNLOCK(unp2);
+ }
+ if (unp_pcb_rele(unp) == 0) {
+ UNP_PCB_CONN_UNLOCK(unp);
+ UNP_PCB_UNLOCK(unp);
+ }
+ if (vplock)
+ mtx_unlock(vplock);
if (vp)
vrele(vp);
+
}
static int
@@ -637,17 +729,16 @@
struct unpcb *unp, *unp2;
int error;
- UNP_LINK_WLOCK();
unp = so1->so_pcb;
KASSERT(unp != NULL, ("uipc_connect2: unp == NULL"));
- UNP_PCB_LOCK(unp);
+ UNP_PCB_CONN_LOCK(unp);
unp2 = so2->so_pcb;
KASSERT(unp2 != NULL, ("uipc_connect2: unp2 == NULL"));
- UNP_PCB_LOCK(unp2);
+ unp_pcb_lock2(unp, unp2);
error = unp_connect2(so1, so2, PRU_CONNECT2);
UNP_PCB_UNLOCK(unp2);
UNP_PCB_UNLOCK(unp);
- UNP_LINK_WUNLOCK();
+ UNP_PCB_CONN_UNLOCK(unp);
return (error);
}
@@ -658,6 +749,7 @@
struct sockaddr_un *saved_unp_addr;
struct vnode *vp;
int freeunp, local_unp_rights;
+ struct mtx *vplock;
unp = sotounpcb(so);
KASSERT(unp != NULL, ("uipc_detach: unp == NULL"));
@@ -669,47 +761,76 @@
LIST_REMOVE(unp, unp_link);
unp->unp_gencnt = ++unp_gencnt;
--unp_count;
- UNP_PCB_LOCK(unp);
- if ((unp->unp_flags & UNP_NASCENT) != 0)
- goto teardown;
+ UNP_LINK_WUNLOCK();
+ UNP_PCB_UNLOCK_ASSERT(unp);
+ restart:
+ if ((vp = unp->unp_vnode) != NULL) {
+ vplock = mtx_pool_find(mtxpool_sleep, vp);
+ mtx_lock(vplock);
+ }
+ UNP_PCB_CONN_LOCK(unp);
+ if ((unp2 = unp->unp_conn) != NULL)
+ unp_pcb_lock2(unp, unp2);
+ else
+ UNP_PCB_LOCK(unp);
+ if (unp->unp_vnode != vp &&
+ unp->unp_vnode != NULL) {
+ mtx_unlock(vplock);
+ UNP_PCB_CONN_UNLOCK(unp);
+ UNP_PCB_UNLOCK(unp);
+ if (unp2)
+ UNP_PCB_UNLOCK(unp2);
+ goto restart;
+ }
+ if ((unp->unp_flags & UNP_NASCENT) != 0) {
+ if (unp2)
+ UNP_PCB_UNLOCK(unp2);
+ UNP_PCB_CONN_UNLOCK(unp);
+ goto teardown;
+ }
if ((vp = unp->unp_vnode) != NULL) {
VOP_UNP_DETACH(vp);
unp->unp_vnode = NULL;
}
- unp2 = unp->unp_conn;
+ unp_pcb_hold(unp);
if (unp2 != NULL) {
- UNP_PCB_LOCK(unp2);
+ unp_pcb_hold(unp2);
unp_disconnect(unp, unp2);
- UNP_PCB_UNLOCK(unp2);
+ if (unp_pcb_rele(unp2) == 0)
+ UNP_PCB_UNLOCK(unp2);
}
-
- /*
- * We hold the linkage lock exclusively, so it's OK to acquire
- * multiple pcb locks at a time.
- */
+ UNP_PCB_UNLOCK(unp);
+ UNP_PCB_CONN_UNLOCK(unp);
+ UNP_REF_LIST_LOCK();
while (!LIST_EMPTY(&unp->unp_refs)) {
struct unpcb *ref = LIST_FIRST(&unp->unp_refs);
- UNP_PCB_LOCK(ref);
+ UNP_REF_LIST_UNLOCK();
+ MPASS(ref != unp);
+ UNP_PCB_UNLOCK_ASSERT(ref);
unp_drop(ref);
- UNP_PCB_UNLOCK(ref);
+ UNP_REF_LIST_LOCK();
}
+
+ UNP_REF_LIST_UNLOCK();
+ UNP_PCB_LOCK(unp);
+ freeunp = unp_pcb_rele(unp);
+ MPASS(freeunp == 0);
local_unp_rights = unp_rights;
teardown:
- UNP_LINK_WUNLOCK();
unp->unp_socket->so_pcb = NULL;
saved_unp_addr = unp->unp_addr;
unp->unp_addr = NULL;
- unp->unp_refcount--;
- freeunp = (unp->unp_refcount == 0);
+ unp->unp_socket = NULL;
+ UNP_PCB_CONN_UNLOCK_ASSERT(unp);
+ freeunp = unp_pcb_rele(unp);
if (saved_unp_addr != NULL)
free(saved_unp_addr, M_SONAME);
- if (freeunp) {
- UNP_PCB_LOCK_DESTROY(unp);
- uma_zfree(unp_zone, unp);
- } else
+ if (!freeunp)
UNP_PCB_UNLOCK(unp);
+ if (vp)
+ mtx_unlock(vplock);
if (vp)
vrele(vp);
if (local_unp_rights)
@@ -720,20 +841,27 @@
uipc_disconnect(struct socket *so)
{
struct unpcb *unp, *unp2;
+ int freed;
unp = sotounpcb(so);
KASSERT(unp != NULL, ("uipc_disconnect: unp == NULL"));
- UNP_LINK_WLOCK();
- UNP_PCB_LOCK(unp);
+ freed = 0;
+ UNP_PCB_CONN_LOCK(unp);
unp2 = unp->unp_conn;
if (unp2 != NULL) {
- UNP_PCB_LOCK(unp2);
+ unp_pcb_lock2(unp, unp2);
+ unp_pcb_hold(unp2);
+ unp_pcb_hold(unp);
unp_disconnect(unp, unp2);
- UNP_PCB_UNLOCK(unp2);
- }
- UNP_PCB_UNLOCK(unp);
- UNP_LINK_WUNLOCK();
+ if (unp_pcb_rele(unp) == 0) {
+ UNP_PCB_CONN_UNLOCK(unp);
+ UNP_PCB_UNLOCK(unp);
+ }
+ if (unp_pcb_rele(unp2) == 0)
+ UNP_PCB_UNLOCK(unp2);
+ } else
+ UNP_PCB_CONN_UNLOCK(unp);
return (0);
}
@@ -858,7 +986,7 @@
struct unpcb *unp, *unp2;
struct socket *so2;
u_int mbcnt, sbcc;
- int error = 0;
+ int freed, error;
unp = sotounpcb(so);
KASSERT(unp != NULL, ("%s: unp == NULL", __func__));
@@ -866,6 +994,7 @@
so->so_type == SOCK_SEQPACKET,
("%s: socktype %d", __func__, so->so_type));
+ freed = error = 0;
if (flags & PRUS_OOB) {
error = EOPNOTSUPP;
goto release;
@@ -873,9 +1002,8 @@
if (control != NULL && (error = unp_internalize(&control, td)))
goto release;
if ((nam != NULL) || (flags & PRUS_EOF))
- UNP_LINK_WLOCK();
- else
- UNP_LINK_RLOCK();
+ UNP_PCB_CONN_LOCK(unp);
+
switch (so->so_type) {
case SOCK_DGRAM:
{
@@ -883,7 +1011,7 @@
unp2 = unp->unp_conn;
if (nam != NULL) {
- UNP_LINK_WLOCK_ASSERT();
+ UNP_PCB_CONN_LOCK_ASSERT(unp);
if (unp2 != NULL) {
error = EISCONN;
break;
@@ -924,13 +1052,17 @@
SOCKBUF_UNLOCK(&so2->so_rcv);
error = ENOBUFS;
}
+ unp_pcb_hold(unp);
if (nam != NULL) {
- UNP_LINK_WLOCK_ASSERT();
- UNP_PCB_LOCK(unp2);
+ UNP_PCB_CONN_LOCK_ASSERT(unp);
+ unp_pcb_owned_lock2(unp, unp2);
+ unp_pcb_hold(unp2);
unp_disconnect(unp, unp2);
- UNP_PCB_UNLOCK(unp2);
+ if (unp_pcb_rele(unp2) == 0)
+ UNP_PCB_UNLOCK(unp2);
}
- UNP_PCB_UNLOCK(unp);
+ if (unp_pcb_rele(unp) == 0)
+ UNP_PCB_UNLOCK(unp);
break;
}
@@ -938,7 +1070,6 @@
case SOCK_STREAM:
if ((so->so_state & SS_ISCONNECTED) == 0) {
if (nam != NULL) {
- UNP_LINK_WLOCK_ASSERT();
error = unp_connect(so, nam, td);
if (error)
break; /* XXX */
@@ -1048,9 +1179,7 @@
}
if ((nam != NULL) || (flags & PRUS_EOF))
- UNP_LINK_WUNLOCK();
- else
- UNP_LINK_RUNLOCK();
+ UNP_PCB_CONN_UNLOCK(unp);
if (control != NULL && error != 0)
unp_dispose_mbuf(control);
@@ -1124,12 +1253,12 @@
unp = sotounpcb(so);
KASSERT(unp != NULL, ("uipc_shutdown: unp == NULL"));
- UNP_LINK_WLOCK();
+ UNP_PCB_CONN_LOCK(unp);
UNP_PCB_LOCK(unp);
socantsendmore(so);
unp_shutdown(unp);
UNP_PCB_UNLOCK(unp);
- UNP_LINK_WUNLOCK();
+ UNP_PCB_CONN_UNLOCK(unp);
return (0);
}
@@ -1334,15 +1463,10 @@
struct sockaddr *sa;
cap_rights_t rights;
int error, len;
+ struct mtx *vplock;
if (nam->sa_family != AF_UNIX)
return (EAFNOSUPPORT);
-
- UNP_LINK_WLOCK_ASSERT();
-
- unp = sotounpcb(so);
- KASSERT(unp != NULL, ("unp_connect: unp == NULL"));
-
if (nam->sa_len > sizeof(struct sockaddr_un))
return (EINVAL);
len = nam->sa_len - offsetof(struct sockaddr_un, sun_path);
@@ -1351,12 +1475,13 @@
bcopy(soun->sun_path, buf, len);
buf[len] = 0;
+ unp = sotounpcb(so);
+ KASSERT(unp != NULL, ("unp_connect: unp == NULL"));
UNP_PCB_LOCK(unp);
if (unp->unp_flags & UNP_CONNECTING) {
UNP_PCB_UNLOCK(unp);
return (EALREADY);
}
- UNP_LINK_WUNLOCK();
unp->unp_flags |= UNP_CONNECTING;
UNP_PCB_UNLOCK(unp);
@@ -1393,8 +1518,10 @@
* Lock linkage lock for two reasons: make sure v_socket is stable,
* and to protect simultaneous locking of multiple pcbs.
*/
- UNP_LINK_WLOCK();
+ vplock = mtx_pool_find(mtxpool_sleep, vp);
+ mtx_lock(vplock);
VOP_UNP_CONNECT(vp, &unp2);
+ UNP_PCB_CONN_LOCK(unp);
if (unp2 == NULL) {
error = ECONNREFUSED;
goto bad2;
@@ -1404,8 +1531,7 @@
error = EPROTOTYPE;
goto bad2;
}
- UNP_PCB_LOCK(unp);
- UNP_PCB_LOCK(unp2);
+ unp_pcb_lock2(unp, unp2);
if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
if (so2->so_options & SO_ACCEPTCONN) {
CURVNET_SET(so2->so_vnet);
@@ -1418,7 +1544,8 @@
goto bad3;
}
unp3 = sotounpcb(so2);
- UNP_PCB_LOCK(unp3);
+ UNP_PCB_UNLOCK(unp);
+ unp_pcb_owned_lock2(unp2, unp3);
if (unp2->unp_addr != NULL) {
bcopy(unp2->unp_addr, sa, unp2->unp_addr->sun_len);
unp3->unp_addr = (struct sockaddr_un *) sa;
@@ -1445,6 +1572,7 @@
unp3->unp_flags |= UNP_WANTCRED;
UNP_PCB_UNLOCK(unp2);
unp2 = unp3;
+ unp_pcb_owned_lock2(unp2, unp);
#ifdef MAC
mac_socketpeer_set_from_socket(so, so2);
mac_socketpeer_set_from_socket(so2, so);
@@ -1459,12 +1587,12 @@
UNP_PCB_UNLOCK(unp2);
UNP_PCB_UNLOCK(unp);
bad2:
- UNP_LINK_WUNLOCK();
+ mtx_unlock(vplock);
+ UNP_PCB_CONN_UNLOCK(unp);
bad:
if (vp != NULL)
vput(vp);
free(sa, M_SONAME);
- UNP_LINK_WLOCK();
UNP_PCB_LOCK(unp);
unp->unp_flags &= ~UNP_CONNECTING;
UNP_PCB_UNLOCK(unp);
@@ -1482,7 +1610,7 @@
unp2 = sotounpcb(so2);
KASSERT(unp2 != NULL, ("unp_connect2: unp2 == NULL"));
- UNP_LINK_WLOCK_ASSERT();
+ UNP_PCB_CONN_LOCK_ASSERT(unp);
UNP_PCB_LOCK_ASSERT(unp);
UNP_PCB_LOCK_ASSERT(unp2);
@@ -1490,10 +1618,13 @@
return (EPROTOTYPE);
unp2->unp_flags &= ~UNP_NASCENT;
unp->unp_conn = unp2;
-
+ unp_pcb_hold(unp2);
+ unp_pcb_hold(unp);
switch (so->so_type) {
case SOCK_DGRAM:
+ UNP_REF_LIST_LOCK();
LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink);
+ UNP_REF_LIST_UNLOCK();
soisconnected(so);
break;
@@ -1517,31 +1648,67 @@
static void
unp_disconnect(struct unpcb *unp, struct unpcb *unp2)
{
- struct socket *so;
+ struct socket *so, *so2;
+ int rele, freed;
KASSERT(unp2 != NULL, ("unp_disconnect: unp2 == NULL"));
- UNP_LINK_WLOCK_ASSERT();
+ UNP_PCB_CONN_LOCK_ASSERT(unp);
UNP_PCB_LOCK_ASSERT(unp);
UNP_PCB_LOCK_ASSERT(unp2);
+ if (unp->unp_conn == NULL && unp2->unp_conn == NULL)
+ return;
+
+ if (UNP_PCB_CONN_TRYLOCK(unp2) == 0) {
+ UNP_PCB_UNLOCK(unp);
+ UNP_PCB_UNLOCK(unp2);
+ if ((uintptr_t)unp2 > (uintptr_t)unp) {
+ UNP_PCB_CONN_LOCK(unp2);
+ } else {
+ UNP_PCB_CONN_UNLOCK(unp);
+ UNP_PCB_CONN_LOCK(unp2);
+ UNP_PCB_CONN_LOCK(unp);
+ }
+ unp_pcb_lock2(unp, unp2);
+ if (unp->unp_conn == NULL && unp2->unp_conn == NULL) {
+ UNP_PCB_CONN_UNLOCK(unp2);
+ return;
+ }
+ }
+
+ MPASS(unp->unp_conn == unp2);
unp->unp_conn = NULL;
+ rele = 0;
+ so = unp->unp_socket;
+ so2 = unp2->unp_socket;
switch (unp->unp_socket->so_type) {
case SOCK_DGRAM:
+ UNP_REF_LIST_LOCK();
LIST_REMOVE(unp, unp_reflink);
- so = unp->unp_socket;
- SOCK_LOCK(so);
- so->so_state &= ~SS_ISCONNECTED;
- SOCK_UNLOCK(so);
+ UNP_REF_LIST_UNLOCK();
+ if (so) {
+ SOCK_LOCK(so);
+ so->so_state &= ~SS_ISCONNECTED;
+ SOCK_UNLOCK(so);
+ }
break;
case SOCK_STREAM:
case SOCK_SEQPACKET:
- soisdisconnected(unp->unp_socket);
+ if (so)
+ soisdisconnected(so);
+ MPASS(unp2->unp_conn == unp);
unp2->unp_conn = NULL;
- soisdisconnected(unp2->unp_socket);
+ if (so2)
+ soisdisconnected(so2);
break;
}
+ UNP_PCB_CONN_UNLOCK(unp2);
+ freed = unp_pcb_rele(unp);
+ MPASS(freed == 0);
+ freed = unp_pcb_rele(unp2);
+ MPASS(freed == 0);
}
/*
@@ -1625,7 +1792,7 @@
continue;
}
unp_list[i++] = unp;
- unp->unp_refcount++;
+ unp_pcb_hold(unp);
}
UNP_PCB_UNLOCK(unp);
}
@@ -1637,8 +1804,9 @@
for (i = 0; i < n; i++) {
unp = unp_list[i];
UNP_PCB_LOCK(unp);
- unp->unp_refcount--;
- if (unp->unp_refcount != 0 && unp->unp_gencnt <= gencnt) {
+ freeunp = unp_pcb_rele(unp);
+
+ if (freeunp == 0 && unp->unp_gencnt <= gencnt) {
xu->xu_len = sizeof *xu;
xu->xu_unpp = unp;
/*
@@ -1665,14 +1833,8 @@
sotoxsocket(unp->unp_socket, &xu->xu_socket);
UNP_PCB_UNLOCK(unp);
error = SYSCTL_OUT(req, xu, sizeof *xu);
- } else {
- freeunp = (unp->unp_refcount == 0);
+ } else if (freeunp == 0)
UNP_PCB_UNLOCK(unp);
- if (freeunp) {
- UNP_PCB_LOCK_DESTROY(unp);
- uma_zfree(unp_zone, unp);
- }
- }
}
free(xu, M_TEMP);
if (!error) {
@@ -1709,7 +1871,7 @@
struct unpcb *unp2;
struct socket *so;
- UNP_LINK_WLOCK_ASSERT();
+ UNP_PCB_CONN_LOCK_ASSERT(unp);
UNP_PCB_LOCK_ASSERT(unp);
unp2 = unp->unp_conn;
@@ -1727,21 +1889,28 @@
struct socket *so = unp->unp_socket;
struct unpcb *unp2;
- UNP_LINK_WLOCK_ASSERT();
- UNP_PCB_LOCK_ASSERT(unp);
-
/*
* Regardless of whether the socket's peer dropped the connection
* with this socket by aborting or disconnecting, POSIX requires
* that ECONNRESET is returned.
*/
+ /* acquire a reference so that unp isn't freed from underneath us */
+
+ UNP_PCB_CONN_LOCK(unp);
+ UNP_PCB_LOCK(unp);
so->so_error = ECONNRESET;
unp2 = unp->unp_conn;
- if (unp2 == NULL)
- return;
- UNP_PCB_LOCK(unp2);
- unp_disconnect(unp, unp2);
- UNP_PCB_UNLOCK(unp2);
+ if (unp2 != NULL) {
+ unp_pcb_owned_lock2(unp, unp2);
+ unp_pcb_hold(unp2);
+ unp_disconnect(unp, unp2);
+ if (unp_pcb_rele(unp2) == 0)
+ UNP_PCB_UNLOCK(unp2);
+ }
+ if (unp_pcb_rele(unp) == 0) {
+ UNP_PCB_UNLOCK(unp);
+ UNP_PCB_CONN_UNLOCK(unp);
+ }
}
static void
@@ -2464,16 +2633,19 @@
{
struct unpcb *unp;
int active;
+ struct mtx *vplock;
ASSERT_VOP_ELOCKED(vp, "vfs_unp_reclaim");
KASSERT(vp->v_type == VSOCK,
("vfs_unp_reclaim: vp->v_type != VSOCK"));
active = 0;
- UNP_LINK_WLOCK();
+ vplock = mtx_pool_find(mtxpool_sleep, vp);
+ mtx_lock(vplock);
VOP_UNP_CONNECT(vp, &unp);
if (unp == NULL)
goto done;
+ UNP_PCB_CONN_LOCK(unp);
UNP_PCB_LOCK(unp);
if (unp->unp_vnode == vp) {
VOP_UNP_DETACH(vp);
@@ -2481,8 +2653,9 @@
active = 1;
}
UNP_PCB_UNLOCK(unp);
-done:
- UNP_LINK_WUNLOCK();
+ UNP_PCB_CONN_UNLOCK(unp);
+ done:
+ mtx_unlock(vplock);
if (active)
vunref(vp);
}
Index: sys/sys/unpcb.h
===================================================================
--- sys/sys/unpcb.h
+++ sys/sys/unpcb.h
@@ -85,6 +85,7 @@
u_int unp_refcount;
u_int unp_msgcount; /* references from message queue */
struct mtx unp_mtx; /* mutex */
+ struct mtx unp_conn_mtx; /* mutex */
};
/*

File Metadata

Mime Type
text/plain
Expires
Wed, Oct 21, 6:10 AM (12 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30578678
Default Alt Text
D15430.1792563018.diff (18 KB)

Event Timeline