Date: Tue, 1 Aug 2006 01:13:06 GMT From: Kip Macy <kmacy@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 102887 for review Message-ID: <200608010113.k711D622008181@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=102887 Change 102887 by kmacy@kmacy_storage:sun4v_work_stable on 2006/08/01 01:12:06 integrate latest to get working uipc_usrreq.c Affected files ... .. //depot/projects/kmacy_sun4v_stable/src/sys/kern/kern_ktrace.c#3 integrate .. //depot/projects/kmacy_sun4v_stable/src/sys/kern/uipc_usrreq.c#2 integrate .. //depot/projects/kmacy_sun4v_stable/src/sys/net/bridgestp.c#3 integrate .. //depot/projects/kmacy_sun4v_stable/src/sys/net/bridgestp.h#2 integrate .. //depot/projects/kmacy_sun4v_stable/src/sys/net/if_bridge.c#4 integrate .. //depot/projects/kmacy_sun4v_stable/src/sys/net/if_bridgevar.h#3 integrate .. //depot/projects/kmacy_sun4v_stable/src/sys/ufs/ufs/ufs_lookup.c#3 integrate Differences ... ==== //depot/projects/kmacy_sun4v_stable/src/sys/kern/kern_ktrace.c#3 (text+ko) ==== @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: src/sys/kern/kern_ktrace.c,v 1.109 2006/06/27 11:29:38 pjd Exp $"); +__FBSDID("$FreeBSD: src/sys/kern/kern_ktrace.c,v 1.110 2006/07/31 15:31:43 jhb Exp $"); #include "opt_ktrace.h" #include "opt_mac.h" @@ -483,15 +483,6 @@ ktr_submitrequest(curthread, req); } -/* - * Since the uio may not stay valid, we can not hand off this request to - * the thread and need to process it synchronously. However, we wish to - * keep the relative order of records in a trace file correct, so we - * do put this request on the queue (if it isn't empty) and then block. - * The ktrace thread waks us back up when it is time for this event to - * be posted and blocks until we have completed writing out the event - * and woken it back up. - */ void ktrgenio(fd, rw, uio, error) int fd; ==== //depot/projects/kmacy_sun4v_stable/src/sys/kern/uipc_usrreq.c#2 (text+ko) ==== @@ -31,8 +31,26 @@ * From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 */ +/* + * UNIX Domain (Local) Sockets + * + * This is an implementation of UNIX (local) domain sockets. Each socket has + * an associated struct unpcb (UNIX protocol control block). Stream sockets + * may be connected to 0 or 1 other socket. Datagram sockets may be + * connected to 0, 1, or many other sockets. Sockets may be created and + * connected in pairs (socketpair(2)), or bound/connected to using the file + * system name space. For most purposes, only the receive socket buffer is + * used, as sending on one socket delivers directly to the receive socket + * buffer of a second socket. The implementation is substantially + * complicated by the fact that "ancillary data", such as file descriptors or + * credentials, may be passed across UNIX domain sockets. The potential for + * passing UNIX domain sockets over other UNIX domain sockets requires the + * implementation of a simple garbage collector to find and tear down cycles + * of disconnected sockets. + */ + #include <sys/cdefs.h> -__FBSDID("$FreeBSD: src/sys/kern/uipc_usrreq.c,v 1.167 2006/04/24 19:09:33 maxim Exp $"); +__FBSDID("$FreeBSD: src/sys/kern/uipc_usrreq.c,v 1.183 2006/07/31 23:00:05 rwatson Exp $"); #include "opt_mac.h" @@ -88,6 +106,38 @@ struct mbuf *unp_addsockcred(struct thread *, struct mbuf *); /* + * Both send and receive buffers are allocated PIPSIZ bytes of buffering for + * stream sockets, although the total for sender and receiver is actually + * only PIPSIZ. + * + * Datagram sockets really use the sendspace as the maximum datagram size, + * and don't really want to reserve the sendspace. Their recvspace should be + * large enough for at least one max-size datagram plus address. + */ +#ifndef PIPSIZ +#define PIPSIZ 8192 +#endif +static u_long unpst_sendspace = PIPSIZ; +static u_long unpst_recvspace = PIPSIZ; +static u_long unpdg_sendspace = 2*1024; /* really max datagram size */ +static u_long unpdg_recvspace = 4*1024; + +static int unp_rights; /* file descriptors in flight */ + +SYSCTL_DECL(_net_local_stream); +SYSCTL_ULONG(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW, + &unpst_sendspace, 0, ""); +SYSCTL_ULONG(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW, + &unpst_recvspace, 0, ""); +SYSCTL_DECL(_net_local_dgram); +SYSCTL_ULONG(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW, + &unpdg_sendspace, 0, ""); +SYSCTL_ULONG(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW, + &unpdg_recvspace, 0, ""); +SYSCTL_DECL(_net_local); +SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, ""); + +/* * Currently, UNIX domain sockets are protected by a single subsystem lock, * which covers global data structures and variables, the contents of each * per-socket unpcb structure, and the so_pcb field in sockets attached to @@ -123,9 +173,6 @@ */ static struct task unp_gc_task; -static int unp_attach(struct socket *); -static void unp_detach(struct unpcb *); -static int unp_bind(struct unpcb *,struct sockaddr *, struct thread *); static int unp_connect(struct socket *,struct sockaddr *, struct thread *); static int unp_connect2(struct socket *so, struct socket *so2, int); static void unp_disconnect(struct unpcb *); @@ -149,8 +196,7 @@ KASSERT(unp != NULL, ("uipc_abort: unp == NULL")); UNP_LOCK(); unp_drop(unp, ECONNABORTED); - unp_detach(unp); - UNP_UNLOCK_ASSERT(); + UNP_UNLOCK(); } static int @@ -160,9 +206,8 @@ const struct sockaddr *sa; /* - * Pass back name of connected socket, - * if it was bound and we are still connected - * (our peer may have closed already!). + * Pass back name of connected socket, if it was bound and we are + * still connected (our peer may have closed already!). */ unp = sotounpcb(so); KASSERT(unp != NULL, ("uipc_accept: unp == NULL")); @@ -180,39 +225,181 @@ static int uipc_attach(struct socket *so, int proto, struct thread *td) { + struct unpcb *unp; + int error; + + KASSERT(so->so_pcb == NULL, ("uipc_attach: so_pcb != NULL")); + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { + switch (so->so_type) { + + case SOCK_STREAM: + error = soreserve(so, unpst_sendspace, unpst_recvspace); + break; + + case SOCK_DGRAM: + error = soreserve(so, unpdg_sendspace, unpdg_recvspace); + break; + + default: + panic("unp_attach"); + } + if (error) + return (error); + } + unp = uma_zalloc(unp_zone, M_WAITOK | M_ZERO); + if (unp == NULL) + return (ENOBUFS); + LIST_INIT(&unp->unp_refs); + unp->unp_socket = so; + so->so_pcb = unp; + + UNP_LOCK(); + unp->unp_gencnt = ++unp_gencnt; + unp_count++; + LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead + : &unp_shead, unp, unp_link); + UNP_UNLOCK(); - return (unp_attach(so)); + return (0); } static int uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) { + struct sockaddr_un *soun = (struct sockaddr_un *)nam; + struct vattr vattr; + int error, namelen; + struct nameidata nd; struct unpcb *unp; - int error; + struct vnode *vp; + struct mount *mp; + char *buf; unp = sotounpcb(so); KASSERT(unp != NULL, ("uipc_bind: unp == NULL")); + + namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path); + if (namelen <= 0) + return (EINVAL); + + /* + * We don't allow simultaneous bind() calls on a single UNIX domain + * socket, so flag in-progress operations, and return an error if an + * operation is already in progress. + * + * Historically, we have not allowed a socket to be rebound, so this + * also returns an error. Not allowing re-binding certainly + * simplifies the implementation and avoids a great many possible + * failure modes. + */ UNP_LOCK(); - error = unp_bind(unp, nam, td); + if (unp->unp_vnode != NULL) { + UNP_UNLOCK(); + return (EINVAL); + } + if (unp->unp_flags & UNP_BINDING) { + UNP_UNLOCK(); + return (EALREADY); + } + unp->unp_flags |= UNP_BINDING; + UNP_UNLOCK(); + + buf = malloc(namelen + 1, M_TEMP, M_WAITOK); + strlcpy(buf, soun->sun_path, namelen + 1); + + mtx_lock(&Giant); +restart: + mtx_assert(&Giant, MA_OWNED); + NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT | SAVENAME, UIO_SYSSPACE, + buf, td); +/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ + error = namei(&nd); + if (error) + goto error; + vp = nd.ni_vp; + if (vp != NULL || vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { + NDFREE(&nd, NDF_ONLY_PNBUF); + if (nd.ni_dvp == vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + if (vp != NULL) { + vrele(vp); + error = EADDRINUSE; + goto error; + } + error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH); + if (error) + goto error; + goto restart; + } + VATTR_NULL(&vattr); + vattr.va_type = VSOCK; + vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask); +#ifdef MAC + error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, + &vattr); +#endif + if (error == 0) { + VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); + error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); + } + NDFREE(&nd, NDF_ONLY_PNBUF); + vput(nd.ni_dvp); + if (error) { + vn_finished_write(mp); + goto error; + } + vp = nd.ni_vp; + ASSERT_VOP_LOCKED(vp, "uipc_bind"); + soun = (struct sockaddr_un *)sodupsockaddr(nam, M_WAITOK); + UNP_LOCK(); + vp->v_socket = unp->unp_socket; + unp->unp_vnode = vp; + unp->unp_addr = soun; + unp->unp_flags &= ~UNP_BINDING; + UNP_UNLOCK(); + VOP_UNLOCK(vp, 0, td); + vn_finished_write(mp); + mtx_unlock(&Giant); + free(buf, M_TEMP); + return (0); +error: + UNP_LOCK(); + unp->unp_flags &= ~UNP_BINDING; UNP_UNLOCK(); + mtx_unlock(&Giant); + free(buf, M_TEMP); return (error); } static int uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) { - struct unpcb *unp; int error; KASSERT(td == curthread, ("uipc_connect: td != curthread")); - unp = sotounpcb(so); - KASSERT(unp != NULL, ("uipc_connect: unp == NULL")); UNP_LOCK(); error = unp_connect(so, nam, td); UNP_UNLOCK(); return (error); } +/* + * XXXRW: Should also unbind? + */ +static void +uipc_close(struct socket *so) +{ + struct unpcb *unp; + + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_close: unp == NULL")); + UNP_LOCK(); + unp_disconnect(unp); + UNP_UNLOCK(); +} + int uipc_connect2(struct socket *so1, struct socket *so2) { @@ -232,13 +419,45 @@ static void uipc_detach(struct socket *so) { + int local_unp_rights; struct unpcb *unp; + struct vnode *vp; unp = sotounpcb(so); KASSERT(unp != NULL, ("uipc_detach: unp == NULL")); UNP_LOCK(); - unp_detach(unp); - UNP_UNLOCK_ASSERT(); + LIST_REMOVE(unp, unp_link); + unp->unp_gencnt = ++unp_gencnt; + --unp_count; + if ((vp = unp->unp_vnode) != NULL) { + /* + * XXXRW: should v_socket be frobbed only while holding + * Giant? + */ + unp->unp_vnode->v_socket = NULL; + unp->unp_vnode = NULL; + } + if (unp->unp_conn != NULL) + unp_disconnect(unp); + while (!LIST_EMPTY(&unp->unp_refs)) { + struct unpcb *ref = LIST_FIRST(&unp->unp_refs); + unp_drop(ref, ECONNRESET); + } + unp->unp_socket->so_pcb = NULL; + local_unp_rights = unp_rights; + UNP_UNLOCK(); + if (unp->unp_addr != NULL) + FREE(unp->unp_addr, M_SONAME); + uma_zfree(unp_zone, unp); + if (vp) { + int vfslocked; + + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + vrele(vp); + VFS_UNLOCK_GIANT(vfslocked); + } + if (local_unp_rights) + taskqueue_enqueue(taskqueue_thread, &unp_gc_task); } static int @@ -302,41 +521,45 @@ { struct unpcb *unp; struct socket *so2; + u_int mbcnt, sbcc; u_long newhiwat; unp = sotounpcb(so); KASSERT(unp != NULL, ("uipc_rcvd: unp == NULL")); - UNP_LOCK(); switch (so->so_type) { case SOCK_DGRAM: panic("uipc_rcvd DGRAM?"); /*NOTREACHED*/ case SOCK_STREAM: - if (unp->unp_conn == NULL) + /* + * Adjust backpressure on sender and wakeup any waiting to + * write. + */ + SOCKBUF_LOCK(&so->so_rcv); + mbcnt = so->so_rcv.sb_mbcnt; + sbcc = so->so_rcv.sb_cc; + SOCKBUF_UNLOCK(&so->so_rcv); + UNP_LOCK(); + if (unp->unp_conn == NULL) { + UNP_UNLOCK(); break; + } so2 = unp->unp_conn->unp_socket; SOCKBUF_LOCK(&so2->so_snd); - SOCKBUF_LOCK(&so->so_rcv); - /* - * Adjust backpressure on sender - * and wakeup any waiting to write. - */ - so2->so_snd.sb_mbmax += unp->unp_mbcnt - so->so_rcv.sb_mbcnt; - unp->unp_mbcnt = so->so_rcv.sb_mbcnt; - newhiwat = so2->so_snd.sb_hiwat + unp->unp_cc - - so->so_rcv.sb_cc; + so2->so_snd.sb_mbmax += unp->unp_mbcnt - mbcnt; + newhiwat = so2->so_snd.sb_hiwat + unp->unp_cc - sbcc; (void)chgsbsize(so2->so_cred->cr_uidinfo, &so2->so_snd.sb_hiwat, newhiwat, RLIM_INFINITY); - unp->unp_cc = so->so_rcv.sb_cc; - SOCKBUF_UNLOCK(&so->so_rcv); sowwakeup_locked(so2); + unp->unp_mbcnt = mbcnt; + unp->unp_cc = sbcc; + UNP_UNLOCK(); break; default: panic("uipc_rcvd unknown socktype"); } - UNP_UNLOCK(); return (0); } @@ -346,10 +569,11 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct thread *td) { - int error = 0; - struct unpcb *unp; + struct unpcb *unp, *unp2; struct socket *so2; + u_int mbcnt, sbcc; u_long newhiwat; + int error = 0; unp = sotounpcb(so); KASSERT(unp != NULL, ("uipc_send: unp == NULL")); @@ -381,12 +605,24 @@ break; } } - so2 = unp->unp_conn->unp_socket; + /* + * Because connect() and send() are non-atomic in a sendto() + * with a target address, it's possible that the socket will + * have disconnected before the send() can run. In that case + * return the slightly counter-intuitive but otherwise + * correct error that the socket is not connected. + */ + unp2 = unp->unp_conn; + if (unp2 == NULL) { + error = ENOTCONN; + break; + } + so2 = unp2->unp_socket; if (unp->unp_addr != NULL) from = (struct sockaddr *)unp->unp_addr; else from = &sun_noname; - if (unp->unp_conn->unp_flags & UNP_WANTCRED) + if (unp2->unp_flags & UNP_WANTCRED) control = unp_addsockcred(td, control); SOCKBUF_LOCK(&so2->so_rcv); if (sbappendaddr_locked(&so2->so_rcv, from, m, control)) { @@ -403,10 +639,11 @@ } case SOCK_STREAM: - /* Connect if not connected yet. */ /* - * Note: A better implementation would complain - * if not equal to the peer's address. + * Connect if not connected yet. + * + * Note: A better implementation would complain if not equal + * to the peer's address. */ if ((so->so_state & SS_ISCONNECTED) == 0) { if (nam != NULL) { @@ -419,28 +656,36 @@ } } - SOCKBUF_LOCK(&so->so_snd); + /* Lockless read. */ if (so->so_snd.sb_state & SBS_CANTSENDMORE) { - SOCKBUF_UNLOCK(&so->so_snd); error = EPIPE; break; } - if (unp->unp_conn == NULL) - panic("uipc_send connected but no connection?"); - so2 = unp->unp_conn->unp_socket; + /* + * Because connect() and send() are non-atomic in a sendto() + * with a target address, it's possible that the socket will + * have disconnected before the send() can run. In that case + * return the slightly counter-intuitive but otherwise + * correct error that the socket is not connected. + */ + unp2 = unp->unp_conn; + if (unp2 == NULL) { + error = ENOTCONN; + break; + } + so2 = unp2->unp_socket; SOCKBUF_LOCK(&so2->so_rcv); - if (unp->unp_conn->unp_flags & UNP_WANTCRED) { + if (unp2->unp_flags & UNP_WANTCRED) { /* * Credentials are passed only once on * SOCK_STREAM. */ - unp->unp_conn->unp_flags &= ~UNP_WANTCRED; + unp2->unp_flags &= ~UNP_WANTCRED; control = unp_addsockcred(td, control); } /* - * Send to paired receive port, and then reduce - * send buffer hiwater marks to maintain backpressure. - * Wake up readers. + * Send to paired receive port, and then reduce send buffer + * hiwater marks to maintain backpressure. Wake up readers. */ if (control != NULL) { if (sbappendcontrol_locked(&so2->so_rcv, m, control)) @@ -448,16 +693,19 @@ } else { sbappend_locked(&so2->so_rcv, m); } - so->so_snd.sb_mbmax -= - so2->so_rcv.sb_mbcnt - unp->unp_conn->unp_mbcnt; - unp->unp_conn->unp_mbcnt = so2->so_rcv.sb_mbcnt; - newhiwat = so->so_snd.sb_hiwat - - (so2->so_rcv.sb_cc - unp->unp_conn->unp_cc); + mbcnt = so2->so_rcv.sb_mbcnt - unp2->unp_mbcnt; + unp2->unp_mbcnt = so2->so_rcv.sb_mbcnt; + sbcc = so2->so_rcv.sb_cc; + sorwakeup_locked(so2); + + SOCKBUF_LOCK(&so->so_snd); + newhiwat = so->so_snd.sb_hiwat - (sbcc - unp2->unp_cc); (void)chgsbsize(so->so_cred->cr_uidinfo, &so->so_snd.sb_hiwat, newhiwat, RLIM_INFINITY); + so->so_snd.sb_mbmax -= mbcnt; SOCKBUF_UNLOCK(&so->so_snd); - unp->unp_conn->unp_cc = so2->so_rcv.sb_cc; - sorwakeup_locked(so2); + + unp2->unp_cc = sbcc; m = NULL; break; @@ -557,9 +805,10 @@ .pru_sense = uipc_sense, .pru_shutdown = uipc_shutdown, .pru_sockaddr = uipc_sockaddr, - .pru_sosend = sosend, - .pru_soreceive = soreceive, - .pru_sopoll = sopoll, + .pru_sosend = sosend_generic, + .pru_soreceive = soreceive_generic, + .pru_sopoll = sopoll_generic, + .pru_close = uipc_close, }; int @@ -644,212 +893,6 @@ return (error); } -/* - * Both send and receive buffers are allocated PIPSIZ bytes of buffering - * for stream sockets, although the total for sender and receiver is - * actually only PIPSIZ. - * Datagram sockets really use the sendspace as the maximum datagram size, - * and don't really want to reserve the sendspace. Their recvspace should - * be large enough for at least one max-size datagram plus address. - */ -#ifndef PIPSIZ -#define PIPSIZ 8192 -#endif -static u_long unpst_sendspace = PIPSIZ; -static u_long unpst_recvspace = PIPSIZ; -static u_long unpdg_sendspace = 2*1024; /* really max datagram size */ -static u_long unpdg_recvspace = 4*1024; - -static int unp_rights; /* file descriptors in flight */ - -SYSCTL_DECL(_net_local_stream); -SYSCTL_ULONG(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW, - &unpst_sendspace, 0, ""); -SYSCTL_ULONG(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW, - &unpst_recvspace, 0, ""); -SYSCTL_DECL(_net_local_dgram); -SYSCTL_ULONG(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW, - &unpdg_sendspace, 0, ""); -SYSCTL_ULONG(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW, - &unpdg_recvspace, 0, ""); -SYSCTL_DECL(_net_local); -SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, ""); - -static int -unp_attach(struct socket *so) -{ - struct unpcb *unp; - int error; - - KASSERT(so->so_pcb == NULL, ("unp_attach: so_pcb != NULL")); - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { - switch (so->so_type) { - - case SOCK_STREAM: - error = soreserve(so, unpst_sendspace, unpst_recvspace); - break; - - case SOCK_DGRAM: - error = soreserve(so, unpdg_sendspace, unpdg_recvspace); - break; - - default: - panic("unp_attach"); - } - if (error) - return (error); - } - unp = uma_zalloc(unp_zone, M_WAITOK | M_ZERO); - if (unp == NULL) - return (ENOBUFS); - LIST_INIT(&unp->unp_refs); - unp->unp_socket = so; - so->so_pcb = unp; - - UNP_LOCK(); - unp->unp_gencnt = ++unp_gencnt; - unp_count++; - LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead - : &unp_shead, unp, unp_link); - UNP_UNLOCK(); - - return (0); -} - -static void -unp_detach(struct unpcb *unp) -{ - struct vnode *vp; - int local_unp_rights; - - UNP_LOCK_ASSERT(); - - LIST_REMOVE(unp, unp_link); - unp->unp_gencnt = ++unp_gencnt; - --unp_count; - if ((vp = unp->unp_vnode) != NULL) { - /* - * XXXRW: should v_socket be frobbed only while holding - * Giant? - */ - unp->unp_vnode->v_socket = NULL; - unp->unp_vnode = NULL; - } - if (unp->unp_conn != NULL) - unp_disconnect(unp); - while (!LIST_EMPTY(&unp->unp_refs)) { - struct unpcb *ref = LIST_FIRST(&unp->unp_refs); - unp_drop(ref, ECONNRESET); - } - soisdisconnected(unp->unp_socket); - unp->unp_socket->so_pcb = NULL; - local_unp_rights = unp_rights; - UNP_UNLOCK(); - if (unp->unp_addr != NULL) - FREE(unp->unp_addr, M_SONAME); - uma_zfree(unp_zone, unp); - if (vp) { - int vfslocked; - - vfslocked = VFS_LOCK_GIANT(vp->v_mount); - vrele(vp); - VFS_UNLOCK_GIANT(vfslocked); - } - if (local_unp_rights) - taskqueue_enqueue(taskqueue_thread, &unp_gc_task); -} - -static int -unp_bind(struct unpcb *unp, struct sockaddr *nam, struct thread *td) -{ - struct sockaddr_un *soun = (struct sockaddr_un *)nam; - struct vnode *vp; - struct mount *mp; - struct vattr vattr; - int error, namelen; - struct nameidata nd; - char *buf; - - UNP_LOCK_ASSERT(); - - /* - * XXXRW: This test-and-set of unp_vnode is non-atomic; the - * unlocked read here is fine, but the value of unp_vnode needs - * to be tested again after we do all the lookups to see if the - * pcb is still unbound? - */ - if (unp->unp_vnode != NULL) - return (EINVAL); - - namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path); - if (namelen <= 0) - return (EINVAL); - - UNP_UNLOCK(); - - buf = malloc(namelen + 1, M_TEMP, M_WAITOK); - strlcpy(buf, soun->sun_path, namelen + 1); - - mtx_lock(&Giant); -restart: - mtx_assert(&Giant, MA_OWNED); - NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT | SAVENAME, UIO_SYSSPACE, - buf, td); -/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ - error = namei(&nd); - if (error) - goto done; - vp = nd.ni_vp; - if (vp != NULL || vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - if (vp != NULL) { - vrele(vp); - error = EADDRINUSE; - goto done; - } - error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH); - if (error) - goto done; - goto restart; - } - VATTR_NULL(&vattr); - vattr.va_type = VSOCK; - vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask); -#ifdef MAC - error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, - &vattr); -#endif - if (error == 0) { - VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); - error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); - } - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_dvp); - if (error) { - vn_finished_write(mp); - goto done; - } - vp = nd.ni_vp; - ASSERT_VOP_LOCKED(vp, "unp_bind"); - soun = (struct sockaddr_un *)sodupsockaddr(nam, M_WAITOK); - UNP_LOCK(); - vp->v_socket = unp->unp_socket; - unp->unp_vnode = vp; - unp->unp_addr = soun; - UNP_UNLOCK(); - VOP_UNLOCK(vp, 0, td); - vn_finished_write(mp); -done: - mtx_unlock(&Giant); - free(buf, M_TEMP); - UNP_LOCK(); - return (error); -} - static int unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) { @@ -870,6 +913,10 @@ if (len <= 0) return (EINVAL); strlcpy(buf, soun->sun_path, len + 1); + if (unp->unp_flags & UNP_CONNECTING) { + UNP_UNLOCK(); + return (EALREADY); + } UNP_UNLOCK(); sa = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); mtx_lock(&Giant); @@ -907,10 +954,10 @@ if (so->so_proto->pr_flags & PR_CONNREQUIRED) { if (so2->so_options & SO_ACCEPTCONN) { /* - * NB: drop locks here so unp_attach is entered - * w/o locks; this avoids a recursive lock - * of the head and holding sleep locks across - * a (potentially) blocking malloc. + * NB: drop locks here so unp_attach is entered w/o + * locks; this avoids a recursive lock of the head + * and holding sleep locks across a (potentially) + * blocking malloc. */ UNP_UNLOCK(); so3 = sonewconn(so2, 0); @@ -932,18 +979,16 @@ /* * unp_peercred management: * - * The connecter's (client's) credentials are copied - * from its process structure at the time of connect() - * (which is now). + * The connecter's (client's) credentials are copied from its + * process structure at the time of connect() (which is now). */ cru2x(td->td_ucred, &unp3->unp_peercred); unp3->unp_flags |= UNP_HAVEPC; /* - * The receiver's (server's) credentials are copied - * from the unp_peercred member of socket on which the - * former called listen(); unp_listen() cached that - * process's credentials at that time so we can use - * them now. + * The receiver's (server's) credentials are copied from the + * unp_peercred member of socket on which the former called + * listen(); unp_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")); @@ -972,6 +1017,7 @@ mtx_unlock(&Giant); free(sa, M_SONAME); UNP_LOCK(); + unp->unp_flags &= ~UNP_CONNECTING; return (error); } @@ -1039,21 +1085,11 @@ } } -#ifdef notdef -void -unp_abort(struct unpcb *unp) -{ - - unp_detach(unp); - UNP_UNLOCK_ASSERT(); -} -#endif - /* - * unp_pcblist() assumes that UNIX domain socket memory is never reclaimed - * by the zone (UMA_ZONE_NOFREE), and as such potentially stale pointers - * are safe to reference. It first scans the list of struct unpcb's to - * generate a pointer list, then it rescans its list one entry at a time to + * unp_pcblist() assumes that UNIX domain socket memory is never reclaimed by + * the zone (UMA_ZONE_NOFREE), and as such potentially stale pointers are + * safe to reference. It first scans the list of struct unpcb's to generate + * a pointer list, then it rescans its list one entry at a time to * externalize and copyout. It checks the generation number to see if a * struct unpcb has been reused, and will skip it if so. */ @@ -1115,7 +1151,7 @@ } } UNP_UNLOCK(); - n = i; /* in case we lost some during malloc */ + n = i; /* In case we lost some during malloc. */ error = 0; xu = malloc(sizeof(*xu), M_TEMP, M_WAITOK | M_ZERO); @@ -1144,11 +1180,10 @@ free(xu, M_TEMP); if (!error) { /* - * Give the user an updated idea of our state. - * If the generation differs from what we told - * her before, she knows that something happened - * while we were processing this request, and it - * might be necessary to retry. + * Give the user an updated idea of our state. If the + * generation differs from what we told her before, she knows + * that something happened while we were processing this + * request, and it might be necessary to retry. */ xug->xug_gen = unp_gencnt; xug->xug_sogen = so_gencnt; @@ -1190,14 +1225,6 @@ unp_disconnect(unp); } -#ifdef notdef -void -unp_drain(void) -{ - -} -#endif - static void unp_freerights(struct file **rp, int fdcount) { @@ -1207,9 +1234,8 @@ for (i = 0; i < fdcount; i++) { fp = *rp; /* - * zero the pointer before calling - * unp_discard since it may end up - * in unp_gc().. + * Zero the pointer before calling unp_discard since it may + * end up in unp_gc().. * * XXXRW: This is less true than it used to be. */ @@ -1267,10 +1293,10 @@ goto next; } /* - * now change each pointer to an fd in the global - * table to an integer that is the index to the - * local fd table entry that we set up to point - * to the global one we are transferring. + * Now change each pointer to an fd in the global + * table to an integer that is the index to the local + * fd table entry that we set up to point to the + * global one we are transferring. */ newlen = newfds * sizeof(int); *controlp = sbcreatecontrol(NULL, newlen, @@ -1296,7 +1322,8 @@ *fdp++ = f; } FILEDESC_UNLOCK(td->td_proc->p_fd); - } else { /* We can just copy anything else across */ + } else { + /* We can just copy anything else across. */ if (error || controlp == NULL) goto next; *controlp = sbcreatecontrol(NULL, datalen, @@ -1338,6 +1365,7 @@ void unp_init(void) { + unp_zone = uma_zcreate("unpcb", sizeof(struct unpcb), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); if (unp_zone == NULL) @@ -1411,8 +1439,8 @@ case SCM_RIGHTS: oldfds = datalen / sizeof (int); /* - * check that all the FDs passed in refer to legal files - * If not, reject the entire operation. + * Check that all the FDs passed in refer to legal + * files. If not, reject the entire operation. */ fdp = data; FILEDESC_LOCK(fdescp); @@ -1433,8 +1461,8 @@ } /* - * Now replace the integer FDs with pointers to - * the associated global file table entry.. + * Now replace the integer FDs with pointers to the + * associated global file table entry.. */ newlen = oldfds * sizeof(struct file *); *controlp = sbcreatecontrol(NULL, newlen, @@ -1498,8 +1526,9 @@ struct mbuf * unp_addsockcred(struct thread *td, struct mbuf *control) { - struct mbuf *m, *n; + struct mbuf *m, *n, *n_prev; struct sockcred *sc; + const struct cmsghdr *cm; int ngroups; int i; >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200608010113.k711D622008181>