From c37f9fba70085fedc8eede7559489d2321393005 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 7 Aug 2018 14:56:50 +0200 Subject: Update to FreeBSD head 2017-08-01 Git mirror commit f5002f5e5f78cae9f0269d812dc0aedb0339312c. Update #3472. --- freebsd/sys/kern/uipc_usrreq.c | 199 ++++++++++++++++++++--------------------- 1 file changed, 98 insertions(+), 101 deletions(-) (limited to 'freebsd/sys/kern/uipc_usrreq.c') 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; -- cgit v1.2.3