summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/uipc_usrreq.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-08-07 14:56:50 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-21 10:29:37 +0200
commitc37f9fba70085fedc8eede7559489d2321393005 (patch)
tree042455ebf1fa89a277a825f72e1ed805d0b4d296 /freebsd/sys/kern/uipc_usrreq.c
parentUpdate to FreeBSD head 2017-06-01 (diff)
downloadrtems-libbsd-c37f9fba70085fedc8eede7559489d2321393005.tar.bz2
Update to FreeBSD head 2017-08-01
Git mirror commit f5002f5e5f78cae9f0269d812dc0aedb0339312c. Update #3472.
Diffstat (limited to 'freebsd/sys/kern/uipc_usrreq.c')
-rw-r--r--freebsd/sys/kern/uipc_usrreq.c199
1 files changed, 98 insertions, 101 deletions
diff --git a/freebsd/sys/kern/uipc_usrreq.c b/freebsd/sys/kern/uipc_usrreq.c
index 8e60f227..7237956a 100644
--- a/freebsd/sys/kern/uipc_usrreq.c
+++ b/freebsd/sys/kern/uipc_usrreq.c
@@ -202,10 +202,9 @@ SYSCTL_INT(_net_local, OID_AUTO, deferred, CTLFLAG_RD,
/*
* Locking and synchronization:
*
- * Three types of locks exit in the local domain socket implementation: a
- * global list mutex, a global linkage rwlock, and per-unpcb mutexes. Of the
- * global locks, the list lock protects the socket count, global generation
- * number, and stream/datagram global lists. The linkage lock protects the
+ * Two types of locks exist in the local domain socket implementation: a
+ * a global linkage rwlock and per-unpcb mutexes. The linkage lock protects
+ * the socket count, global generation number, stream/datagram global lists and
* interconnection of unpcbs, the v_socket and unp_vnode pointers, and can be
* held exclusively over the acquisition of multiple unpcb locks to prevent
* deadlock.
@@ -246,7 +245,6 @@ SYSCTL_INT(_net_local, OID_AUTO, deferred, CTLFLAG_RD,
* to perform namei() and other file system operations.
*/
static struct rwlock unp_link_rwlock;
-static struct mtx unp_list_lock;
static struct mtx unp_defers_lock;
#define UNP_LINK_LOCK_INIT() rw_init(&unp_link_rwlock, \
@@ -263,11 +261,7 @@ static struct mtx unp_defers_lock;
#define UNP_LINK_WUNLOCK() rw_wunlock(&unp_link_rwlock)
#define UNP_LINK_WLOCK_ASSERT() rw_assert(&unp_link_rwlock, \
RA_WLOCKED)
-
-#define UNP_LIST_LOCK_INIT() mtx_init(&unp_list_lock, \
- "unp_list_lock", NULL, MTX_DEF)
-#define UNP_LIST_LOCK() mtx_lock(&unp_list_lock)
-#define UNP_LIST_UNLOCK() mtx_unlock(&unp_list_lock)
+#define UNP_LINK_WOWNED() rw_wowned(&unp_link_rwlock)
#define UNP_DEFERRED_LOCK_INIT() mtx_init(&unp_defers_lock, \
"unp_defer", NULL, MTX_DEF)
@@ -417,6 +411,7 @@ uipc_attach(struct socket *so, int proto, struct thread *td)
u_long sendspace, recvspace;
struct unpcb *unp;
int error;
+ bool locked;
KASSERT(so->so_pcb == NULL, ("uipc_attach: so_pcb != NULL"));
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
@@ -451,10 +446,12 @@ uipc_attach(struct socket *so, int proto, struct thread *td)
unp->unp_socket = so;
so->so_pcb = unp;
unp->unp_refcount = 1;
- if (so->so_head != NULL)
+ if (so->so_listen != NULL)
unp->unp_flags |= UNP_NASCENT;
- UNP_LIST_LOCK();
+ if ((locked = UNP_LINK_WOWNED()) == false)
+ UNP_LINK_WLOCK();
+
unp->unp_gencnt = ++unp_gencnt;
unp_count++;
switch (so->so_type) {
@@ -473,7 +470,9 @@ uipc_attach(struct socket *so, int proto, struct thread *td)
default:
panic("uipc_attach");
}
- UNP_LIST_UNLOCK();
+
+ if (locked == false)
+ UNP_LINK_WUNLOCK();
return (0);
}
@@ -516,6 +515,14 @@ static const IMFS_node_control rtems_uipc_imfs_control =
static const IMFS_node_control rtems_uipc_imfs_zombi_control =
IMFS_GENERIC_INITIALIZER(&rtems_filesystem_handlers_default, NULL,
IMFS_node_destroy_default);
+
+static void
+VOP_UNP_DETACH(IMFS_generic_t *vp)
+{
+
+ vp->Node.control = &rtems_uipc_imfs_zombi_control;
+ vp->context = NULL;
+}
#endif /* __rtems__ */
static int
uipc_bindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td)
@@ -630,7 +637,7 @@ restart:
UNP_LINK_WLOCK();
UNP_PCB_LOCK(unp);
#ifndef __rtems__
- VOP_UNP_BIND(vp, unp->unp_socket);
+ VOP_UNP_BIND(vp, unp);
unp->unp_vnode = vp;
#endif /* __rtems__ */
unp->unp_addr = soun;
@@ -690,6 +697,11 @@ static void
uipc_close(struct socket *so)
{
struct unpcb *unp, *unp2;
+#ifndef __rtems__
+ struct vnode *vp;
+#else /* __rtems__ */
+ IMFS_generic_t *vp;
+#endif /* __rtems__ */
unp = sotounpcb(so);
KASSERT(unp != NULL, ("uipc_close: unp == NULL"));
@@ -702,8 +714,16 @@ uipc_close(struct socket *so)
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();
+#ifndef __rtems__
+ if (vp)
+ vrele(vp);
+#endif /* __rtems__ */
}
static int
@@ -747,29 +767,16 @@ uipc_detach(struct socket *so)
local_unp_rights = 0;
#endif /* __rtems__ */
- UNP_LIST_LOCK();
+ UNP_LINK_WLOCK();
LIST_REMOVE(unp, unp_link);
unp->unp_gencnt = ++unp_gencnt;
--unp_count;
- UNP_LIST_UNLOCK();
-
- if ((unp->unp_flags & UNP_NASCENT) != 0) {
- UNP_PCB_LOCK(unp);
- goto teardown;
- }
- UNP_LINK_WLOCK();
UNP_PCB_LOCK(unp);
+ if ((unp->unp_flags & UNP_NASCENT) != 0)
+ goto teardown;
- /*
- * XXXRW: Should assert vp->v_socket == so.
- */
if ((vp = unp->unp_vnode) != NULL) {
-#ifndef __rtems__
VOP_UNP_DETACH(vp);
-#else /* __rtems__ */
- vp->Node.control = &rtems_uipc_imfs_zombi_control;
- vp->context = NULL;
-#endif /* __rtems__ */
unp->unp_vnode = NULL;
}
unp2 = unp->unp_conn;
@@ -793,8 +800,8 @@ uipc_detach(struct socket *so)
#ifndef __rtems__
local_unp_rights = unp_rights;
#endif /* __rtems__ */
- UNP_LINK_WUNLOCK();
teardown:
+ UNP_LINK_WUNLOCK();
unp->unp_socket->so_pcb = NULL;
saved_unp_addr = unp->unp_addr;
unp->unp_addr = NULL;
@@ -860,7 +867,6 @@ uipc_listen(struct socket *so, int backlog, struct thread *td)
error = solisten_proto_check(so);
if (error == 0) {
cru2x(td->td_ucred, &unp->unp_peercred);
- unp->unp_flags |= UNP_HAVEPCCACHED;
solisten_proto(so, backlog);
}
SOCK_UNLOCK(so);
@@ -1439,7 +1445,7 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
#else /* __rtems__ */
struct IMFS_jnode_tt *vp;
#endif /* __rtems__ */
- struct socket *so2, *so3;
+ struct socket *so2;
struct unpcb *unp, *unp2, *unp3;
#ifndef __rtems__
struct nameidata nd;
@@ -1450,7 +1456,9 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
const rtems_filesystem_location_info_t *currentloc;
#endif /* __rtems__ */
struct sockaddr *sa;
+#ifndef __rtems__
cap_rights_t rights;
+#endif /* __rtems__ */
int error, len;
if (nam->sa_family != AF_UNIX)
@@ -1535,34 +1543,38 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
*/
UNP_LINK_WLOCK();
#ifndef __rtems__
- VOP_UNP_CONNECT(vp, &so2);
+ VOP_UNP_CONNECT(vp, &unp2);
+ if (unp2 == NULL) {
+ error = ECONNREFUSED;
+ goto bad2;
+ }
+ so2 = unp2->unp_socket;
#else /* __rtems__ */
so2 = IMFS_generic_get_context_by_node(vp);
-#endif /* __rtems__ */
if (so2 == NULL) {
error = ECONNREFUSED;
goto bad2;
}
+ unp2 = sotounpcb(so2);
+#endif /* __rtems__ */
if (so->so_type != so2->so_type) {
error = EPROTOTYPE;
goto bad2;
}
+ UNP_PCB_LOCK(unp);
+ UNP_PCB_LOCK(unp2);
if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
if (so2->so_options & SO_ACCEPTCONN) {
CURVNET_SET(so2->so_vnet);
- so3 = sonewconn(so2, 0);
+ so2 = sonewconn(so2, 0);
CURVNET_RESTORE();
} else
- so3 = NULL;
- if (so3 == NULL) {
+ so2 = NULL;
+ if (so2 == NULL) {
error = ECONNREFUSED;
- goto bad2;
+ goto bad3;
}
- unp = sotounpcb(so);
- unp2 = sotounpcb(so2);
- unp3 = sotounpcb(so3);
- UNP_PCB_LOCK(unp);
- UNP_PCB_LOCK(unp2);
+ unp3 = sotounpcb(so2);
UNP_PCB_LOCK(unp3);
if (unp2->unp_addr != NULL) {
bcopy(unp2->unp_addr, sa, unp2->unp_addr->sun_len);
@@ -1583,30 +1595,24 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
* listen(); uipc_listen() cached that process's credentials
* at that time so we can use them now.
*/
- KASSERT(unp2->unp_flags & UNP_HAVEPCCACHED,
- ("unp_connect: listener without cached peercred"));
memcpy(&unp->unp_peercred, &unp2->unp_peercred,
sizeof(unp->unp_peercred));
unp->unp_flags |= UNP_HAVEPC;
if (unp2->unp_flags & UNP_WANTCRED)
unp3->unp_flags |= UNP_WANTCRED;
- UNP_PCB_UNLOCK(unp3);
UNP_PCB_UNLOCK(unp2);
- UNP_PCB_UNLOCK(unp);
+ unp2 = unp3;
#ifdef MAC
- mac_socketpeer_set_from_socket(so, so3);
- mac_socketpeer_set_from_socket(so3, so);
+ mac_socketpeer_set_from_socket(so, so2);
+ mac_socketpeer_set_from_socket(so2, so);
#endif
-
- so2 = so3;
}
- unp = sotounpcb(so);
- KASSERT(unp != NULL, ("unp_connect: unp == NULL"));
- unp2 = sotounpcb(so2);
- KASSERT(unp2 != NULL, ("unp_connect: unp2 == NULL"));
- UNP_PCB_LOCK(unp);
- UNP_PCB_LOCK(unp2);
+
+ KASSERT(unp2 != NULL && so2 != NULL && unp2->unp_socket == so2 &&
+ sotounpcb(so2) == unp2,
+ ("%s: unp2 %p so2 %p", __func__, unp2, so2));
error = unp_connect2(so, so2, PRU_CONNECT);
+bad3:
UNP_PCB_UNLOCK(unp2);
UNP_PCB_UNLOCK(unp);
bad2:
@@ -1750,10 +1756,10 @@ unp_pcblist(SYSCTL_HANDLER_ARGS)
* OK, now we're committed to doing something.
*/
xug = malloc(sizeof(*xug), M_TEMP, M_WAITOK);
- UNP_LIST_LOCK();
+ UNP_LINK_RLOCK();
gencnt = unp_gencnt;
n = unp_count;
- UNP_LIST_UNLOCK();
+ UNP_LINK_RUNLOCK();
xug->xug_len = sizeof *xug;
xug->xug_count = n;
@@ -1767,7 +1773,7 @@ unp_pcblist(SYSCTL_HANDLER_ARGS)
unp_list = malloc(n * sizeof *unp_list, M_TEMP, M_WAITOK);
- UNP_LIST_LOCK();
+ UNP_LINK_RLOCK();
for (unp = LIST_FIRST(head), i = 0; unp && i < n;
unp = LIST_NEXT(unp, unp_link)) {
UNP_PCB_LOCK(unp);
@@ -1782,7 +1788,7 @@ unp_pcblist(SYSCTL_HANDLER_ARGS)
}
UNP_PCB_UNLOCK(unp);
}
- UNP_LIST_UNLOCK();
+ UNP_LINK_RUNLOCK();
n = i; /* In case we lost some during malloc. */
error = 0;
@@ -2044,7 +2050,6 @@ unp_init(void)
TASK_INIT(&unp_defer_task, 0, unp_process_defers, NULL);
#endif /* __rtems__ */
UNP_LINK_LOCK_INIT();
- UNP_LIST_LOCK_INIT();
UNP_DEFERRED_LOCK_INIT();
}
@@ -2396,8 +2401,7 @@ unp_accessable(struct filedescent **fdep, int fdcount)
static void
unp_gc_process(struct unpcb *unp)
{
- struct socket *soa;
- struct socket *so;
+ struct socket *so, *soa;
struct file *fp;
/* Already processed. */
@@ -2417,28 +2421,30 @@ unp_gc_process(struct unpcb *unp)
return;
}
- /*
- * Mark all sockets we reference with RIGHTS.
- */
so = unp->unp_socket;
- if ((unp->unp_gcflag & UNPGC_IGNORE_RIGHTS) == 0) {
- SOCKBUF_LOCK(&so->so_rcv);
- unp_scan(so->so_rcv.sb_mb, unp_accessable);
- SOCKBUF_UNLOCK(&so->so_rcv);
- }
-
- /*
- * Mark all sockets in our accept queue.
- */
- ACCEPT_LOCK();
- TAILQ_FOREACH(soa, &so->so_comp, so_list) {
- if ((sotounpcb(soa)->unp_gcflag & UNPGC_IGNORE_RIGHTS) != 0)
- continue;
- SOCKBUF_LOCK(&soa->so_rcv);
- unp_scan(soa->so_rcv.sb_mb, unp_accessable);
- SOCKBUF_UNLOCK(&soa->so_rcv);
+ SOCK_LOCK(so);
+ if (SOLISTENING(so)) {
+ /*
+ * Mark all sockets in our accept queue.
+ */
+ TAILQ_FOREACH(soa, &so->sol_comp, so_list) {
+ if (sotounpcb(soa)->unp_gcflag & UNPGC_IGNORE_RIGHTS)
+ continue;
+ SOCKBUF_LOCK(&soa->so_rcv);
+ unp_scan(soa->so_rcv.sb_mb, unp_accessable);
+ SOCKBUF_UNLOCK(&soa->so_rcv);
+ }
+ } else {
+ /*
+ * Mark all sockets we reference with RIGHTS.
+ */
+ if ((unp->unp_gcflag & UNPGC_IGNORE_RIGHTS) == 0) {
+ SOCKBUF_LOCK(&so->so_rcv);
+ unp_scan(so->so_rcv.sb_mb, unp_accessable);
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ }
}
- ACCEPT_UNLOCK();
+ SOCK_UNLOCK(so);
unp->unp_gcflag |= UNPGC_SCANNED;
}
@@ -2461,7 +2467,7 @@ unp_gc(__unused void *arg, int pending)
int i, total;
unp_taskcount++;
- UNP_LIST_LOCK();
+ UNP_LINK_RLOCK();
/*
* First clear all gc flags from previous runs, apart from
* UNPGC_IGNORE_RIGHTS.
@@ -2484,7 +2490,7 @@ unp_gc(__unused void *arg, int pending)
LIST_FOREACH(unp, *head, unp_link)
unp_gc_process(unp);
} while (unp_marked);
- UNP_LIST_UNLOCK();
+ UNP_LINK_RUNLOCK();
if (unp_unreachable == 0)
return;
@@ -2499,7 +2505,6 @@ unp_gc(__unused void *arg, int pending)
* as as unreachable and store them locally.
*/
UNP_LINK_RLOCK();
- UNP_LIST_LOCK();
for (total = 0, head = heads; *head != NULL; head++)
LIST_FOREACH(unp, *head, unp_link)
if ((unp->unp_gcflag & UNPGC_DEAD) != 0) {
@@ -2512,7 +2517,6 @@ unp_gc(__unused void *arg, int pending)
KASSERT(total <= unp_unreachable,
("unp_gc: incorrect unreachable count."));
}
- UNP_LIST_UNLOCK();
UNP_LINK_RUNLOCK();
/*
@@ -2555,10 +2559,11 @@ unp_dispose(struct socket *so)
struct unpcb *unp;
unp = sotounpcb(so);
- UNP_LIST_LOCK();
+ UNP_LINK_WLOCK();
unp->unp_gcflag |= UNPGC_IGNORE_RIGHTS;
- UNP_LIST_UNLOCK();
- unp_dispose_mbuf(so->so_rcv.sb_mb);
+ UNP_LINK_WUNLOCK();
+ if (!SOLISTENING(so))
+ unp_dispose_mbuf(so->so_rcv.sb_mb);
}
static void
@@ -2613,7 +2618,6 @@ unp_scan(struct mbuf *m0, void (*op)(struct filedescent **, int))
void
vfs_unp_reclaim(struct vnode *vp)
{
- struct socket *so;
struct unpcb *unp;
int active;
@@ -2623,10 +2627,7 @@ vfs_unp_reclaim(struct vnode *vp)
active = 0;
UNP_LINK_WLOCK();
- VOP_UNP_CONNECT(vp, &so);
- if (so == NULL)
- goto done;
- unp = sotounpcb(so);
+ VOP_UNP_CONNECT(vp, &unp);
if (unp == NULL)
goto done;
UNP_PCB_LOCK(unp);
@@ -2663,10 +2664,6 @@ db_print_unpflags(int unp_flags)
db_printf("%sUNP_HAVEPC", comma ? ", " : "");
comma = 1;
}
- if (unp_flags & UNP_HAVEPCCACHED) {
- db_printf("%sUNP_HAVEPCCACHED", comma ? ", " : "");
- comma = 1;
- }
if (unp_flags & UNP_WANTCRED) {
db_printf("%sUNP_WANTCRED", comma ? ", " : "");
comma = 1;