Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F164764711
D58460.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D58460.diff
View Options
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -293,7 +293,7 @@
static int unp_connect(struct socket *, struct sockaddr *,
struct thread *);
static int unp_connectat(int, struct socket *, struct sockaddr *,
- struct thread *, bool);
+ struct thread *, struct socket **);
static int unp_connect_peer(struct socket *, struct unpcb *,
struct sockaddr **, struct thread *, bool);
static void unp_connect2(struct socket *, struct socket *, bool);
@@ -738,7 +738,7 @@
int error;
KASSERT(td == curthread, ("uipc_connectat: td != curthread"));
- error = unp_connectat(fd, so, nam, td, false);
+ error = unp_connectat(fd, so, nam, td, NULL);
return (error);
}
@@ -1989,7 +1989,7 @@
{
struct unpcb *unp, *unp2;
const struct sockaddr *from;
- struct socket *so2;
+ struct socket *so2, *peer;
struct sockbuf *sb;
struct mchain cmc = MCHAIN_INITIALIZER(&cmc);
struct mbuf *f;
@@ -2071,7 +2071,7 @@
SOCK_SENDBUF_UNLOCK(so);
if (addr != NULL) {
- if ((error = unp_connectat(AT_FDCWD, so, addr, td, true)))
+ if ((error = unp_connectat(AT_FDCWD, so, addr, td, &peer)))
goto out3;
UNP_PCB_LOCK_ASSERT(unp);
unp2 = unp->unp_conn;
@@ -2187,9 +2187,10 @@
}
out4:
- if (addr != NULL)
+ if (addr != NULL) {
unp_disconnect(unp, unp2);
- else
+ sorele(peer);
+ } else
unp_pcb_unlock_pair(unp, unp2);
td->td_ru.ru_msgsnd++;
@@ -2893,14 +2894,33 @@
unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
{
- return (unp_connectat(AT_FDCWD, so, nam, td, false));
+ return (unp_connectat(AT_FDCWD, so, nam, td, NULL));
}
+/*
+ * Connect socket 'so' to the unix-domain peer named by 'nam', resolved
+ * relative to descriptor 'fd' (AT_FDCWD for connect(2)).
+ *
+ * 'referenced_peerp' selects how the peer is returned. If NULL, on exit the
+ * peer's PCB is unlocked and the peer is unreferenced, symmetrically releasing
+ * the resources acquired within the function. If non-NULL, the peer's PCB is
+ * returned locked and '*referenced_peerp' receives the referenced peer socket;
+ * the caller is then responsible for first unlocking the peer's PCB and
+ * afterwards releasing the socket.
+ *
+ * The reference is handed back rather than released in the return-unlocked
+ * case, because releasing the last one under the PCB lock could cause
+ * uipc_close() to try to re-acquire that lock.
+ *
+ * Note: the referenced_peerp mechanism is here only for the datagram fast-send
+ * path, which enqueues under the peer's PCB lock.
+ */
static int
unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
- struct thread *td, bool return_locked)
+ struct thread *td, struct socket **referenced_peerp)
{
struct mtx *vplock;
+ struct socket *so2;
struct vnode *vp;
struct unpcb *unp, *unp2;
struct nameidata nd;
@@ -2968,26 +2988,31 @@
cap_rights_init_one(&rights, CAP_CONNECTAT));
error = namei(&nd);
if (error)
- vp = NULL;
- else
- vp = nd.ni_vp;
- ASSERT_VOP_LOCKED(vp, "unp_connect");
- if (error)
- goto bad;
+ goto out;
NDFREE_PNBUF(&nd);
+ vp = nd.ni_vp;
+ ASSERT_VOP_LOCKED(vp, "unp_connect");
+ /*
+ * Resolve the vnode to a referenced peer socket, then drop the vnode
+ * before connecting. Holding a reference on the peer keeps it stable
+ * in place of the per-vnode unp_vp_mtxpool lock, so no vnode lock is
+ * held across unp_connect_peer() -- which is what the return_locked
+ * datagram fast path needs, since vput() must not sleep while the peer
+ * is locked.
+ */
if (vp->v_type != VSOCK) {
error = ENOTSOCK;
- goto bad;
+ goto drop_vp;
}
#ifdef MAC
error = mac_vnode_check_open(td->td_ucred, vp, VWRITE | VREAD);
if (error)
- goto bad;
+ goto drop_vp;
#endif
error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td);
if (error)
- goto bad;
+ goto drop_vp;
vplock = mtx_pool_find(unp_vp_mtxpool, vp);
mtx_lock(vplock);
@@ -2995,19 +3020,20 @@
if (unp2 == NULL)
error = ECONNREFUSED;
else
- error = unp_connect_peer(so, unp2, &sa, td, return_locked);
+ soref(so2 = unp2->unp_socket);
mtx_unlock(vplock);
-bad:
- if (vp != NULL) {
- /*
- * If we are returning locked (called via uipc_sosend_dgram()),
- * we need to be sure that vput() won't sleep. This is
- * guaranteed by VOP_UNP_CONNECT() call above and unp2 lock.
- * SOCK_STREAM/SEQPACKET can't request return_locked (yet).
- */
- MPASS(!(return_locked && connreq));
- vput(vp);
- }
+drop_vp:
+ vput(vp);
+ if (error != 0)
+ goto out;
+ error = unp_connect_peer(so, sotounpcb(so2), &sa, td,
+ referenced_peerp != NULL);
+ /* Transfer the reference; the caller releases it after unlocking. */
+ if (error == 0 && referenced_peerp != NULL)
+ *referenced_peerp = so2;
+ else
+ sorele(so2);
+out:
free(sa, M_SONAME);
if (__predict_false(error)) {
UNP_PCB_LOCK(unp);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Aug 4, 7:47 PM (12 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35563904
Default Alt Text
D58460.diff (4 KB)
Attached To
Mode
D58460: unix: pin the pathname peer by reference across the connect
Attached
Detach File
Event Timeline
Log In to Comment