diff options
Diffstat (limited to 'sys/kern/uipc_usrreq.c')
-rw-r--r-- | sys/kern/uipc_usrreq.c | 57 |
1 files changed, 35 insertions, 22 deletions
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 8920201..4bad386 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1311,7 +1311,9 @@ unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) } if (so->so_proto->pr_flags & PR_CONNREQUIRED) { if (so2->so_options & SO_ACCEPTCONN) { + CURVNET_SET(so2->so_vnet); so3 = sonewconn(so2, 0); + CURVNET_RESTORE(); } else so3 = NULL; if (so3 == NULL) { @@ -1601,15 +1603,16 @@ unp_pcblist(SYSCTL_HANDLER_ARGS) return (error); } -SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLFLAG_RD, - (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb", - "List of active local datagram sockets"); -SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD, - (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb", - "List of active local stream sockets"); -SYSCTL_PROC(_net_local_seqpacket, OID_AUTO, pcblist, CTLFLAG_RD, - (caddr_t)(long)SOCK_SEQPACKET, 0, unp_pcblist, "S,xunpcb", - "List of active local seqpacket sockets"); +SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLTYPE_OPAQUE | CTLFLAG_RD, + (void *)(intptr_t)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb", + "List of active local datagram sockets"); +SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLTYPE_OPAQUE | CTLFLAG_RD, + (void *)(intptr_t)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb", + "List of active local stream sockets"); +SYSCTL_PROC(_net_local_seqpacket, OID_AUTO, pcblist, + CTLTYPE_OPAQUE | CTLFLAG_RD, + (void *)(intptr_t)SOCK_SEQPACKET, 0, unp_pcblist, "S,xunpcb", + "List of active local seqpacket sockets"); static void unp_shutdown(struct unpcb *unp) @@ -2152,9 +2155,9 @@ unp_gc(__unused void *arg, int pending) struct unp_head *heads[] = { &unp_dhead, &unp_shead, &unp_sphead, NULL }; struct unp_head **head; - struct file **unref; + struct file *f, **unref; struct unpcb *unp; - int i; + int i, total; unp_taskcount++; UNP_LIST_LOCK(); @@ -2192,33 +2195,43 @@ unp_gc(__unused void *arg, int pending) * Iterate looking for sockets which have been specifically marked * as as unreachable and store them locally. */ + UNP_LINK_RLOCK(); UNP_LIST_LOCK(); - for (i = 0, head = heads; *head != NULL; head++) + for (total = 0, head = heads; *head != NULL; head++) LIST_FOREACH(unp, *head, unp_link) - if (unp->unp_gcflag & UNPGC_DEAD) { - unref[i++] = unp->unp_file; - fhold(unp->unp_file); - KASSERT(unp->unp_file != NULL, - ("unp_gc: Invalid unpcb.")); - KASSERT(i <= unp_unreachable, + if ((unp->unp_gcflag & UNPGC_DEAD) != 0) { + f = unp->unp_file; + if (unp->unp_msgcount == 0 || f == NULL || + f->f_count != unp->unp_msgcount) + continue; + unref[total++] = f; + fhold(f); + KASSERT(total <= unp_unreachable, ("unp_gc: incorrect unreachable count.")); } UNP_LIST_UNLOCK(); + UNP_LINK_RUNLOCK(); /* * Now flush all sockets, free'ing rights. This will free the * struct files associated with these sockets but leave each socket * with one remaining ref. */ - for (i = 0; i < unp_unreachable; i++) - sorflush(unref[i]->f_data); + for (i = 0; i < total; i++) { + struct socket *so; + + so = unref[i]->f_data; + CURVNET_SET(so->so_vnet); + sorflush(so); + CURVNET_RESTORE(); + } /* * And finally release the sockets so they can be reclaimed. */ - for (i = 0; i < unp_unreachable; i++) + for (i = 0; i < total; i++) fdrop(unref[i], NULL); - unp_recycled += unp_unreachable; + unp_recycled += total; free(unref, M_TEMP); } |