After completing a name lookup for a target UNIX domain socket to

connect to, re-check that the local UNIX domain socket hasn't been
closed while we slept, and if so, return EINVAL.  This affects the
system running both with and without Giant over the network stack,
and recent ULE changes appear to cause it to trigger more
frequently than previously under load.  While here, improve catching
of possibly closed UNIX domain sockets in one or two additional
circumstances.  I have a much larger set of related changes in
Perforce, but they require more testing before they can be merged.

One debugging printf is left in place to indicate when such a race
takes place: this is typically triggered by a buggy application
that simultaenously connect()'s and close()'s a UNIX domain socket
file descriptor.  I'll remove this at some point in the future, but
am interested in seeing how frequently this is reported.  In the
case of Martin's reported problem, it appears to be a result of a
non-thread safe syslog() implementation in the C library, which
does not synchronize access to its logging file descriptor.

Reported by:	mbr
This commit is contained in:
Robert Watson 2004-08-14 03:43:49 +00:00
parent 6a0724a89e
commit b295bdcded
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=133709

View File

@ -168,15 +168,19 @@ uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
static int
uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
{
struct unpcb *unp = sotounpcb(so);
struct unpcb *unp;
int error;
KASSERT(td == curthread, ("uipc_connect: td != curthread"));
if (unp == NULL)
return (EINVAL);
UNP_LOCK();
unp = sotounpcb(so);
if (unp == NULL) {
error = EINVAL;
goto out;
}
error = unp_connect(so, nam, td);
out:
UNP_UNLOCK();
return (error);
}
@ -762,14 +766,14 @@ unp_connect(so, nam, td)
register struct sockaddr_un *soun = (struct sockaddr_un *)nam;
register struct vnode *vp;
register struct socket *so2, *so3;
struct unpcb *unp = sotounpcb(so);
struct unpcb *unp2, *unp3;
struct unpcb *unp, *unp2, *unp3;
int error, len;
struct nameidata nd;
char buf[SOCK_MAXADDRLEN];
struct sockaddr *sa;
UNP_LOCK_ASSERT();
unp = sotounpcb(so);
len = nam->sa_len - offsetof(struct sockaddr_un, sun_path);
if (len <= 0)
@ -798,6 +802,15 @@ unp_connect(so, nam, td)
goto bad;
mtx_unlock(&Giant);
UNP_LOCK();
unp = sotounpcb(so);
if (unp == NULL) {
/*
* XXXRW: Temporary debugging printf.
*/
printf("unp_connect(): lost race to another thread\n");
error = EINVAL;
goto bad2;
}
so2 = vp->v_socket;
if (so2 == NULL) {
error = ECONNREFUSED;