When re-connecting an already connected datagram socket be sure to clean
authorMatthew Dillon <dillon@dragonflybsd.org>
Thu, 13 Jan 2005 23:05:32 +0000 (23:05 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Thu, 13 Jan 2005 23:05:32 +0000 (23:05 +0000)
up its pending error state, which may be set in some rare conditions
resulting in the connect() syscall returning a bogus error and making
application believe that the attempt to change association has failed,
when in fact it has succeeded.

Submitted-by: Maxim Sobolev <sobomax@FreeBSD.org>
Taken-from: FreeBSD/1.225 (Maxim Sobolev)

sys/kern/kern_descrip.c
sys/kern/kern_synch.c
sys/kern/uipc_socket.c

index 7e5b555..4ba162e 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_descrip.c      8.6 (Berkeley) 4/19/94
  * $FreeBSD: src/sys/kern/kern_descrip.c,v 1.81.2.19 2004/02/28 00:43:31 tegge Exp $
- * $DragonFly: src/sys/kern/kern_descrip.c,v 1.34 2004/11/24 22:51:01 joerg Exp $
+ * $DragonFly: src/sys/kern/kern_descrip.c,v 1.35 2005/01/13 23:05:32 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -993,21 +993,27 @@ fdinit(struct proc *p)
        struct filedesc *fdp = p->p_fd;
 
        newfdp = malloc(sizeof(struct filedesc0), M_FILEDESC, M_WAITOK|M_ZERO);
-       newfdp->fd_fd.fd_cdir = fdp->fd_cdir;
-       if (newfdp->fd_fd.fd_cdir) {
+       if (fdp->fd_cdir) {
+               newfdp->fd_fd.fd_cdir = fdp->fd_cdir;
                vref(newfdp->fd_fd.fd_cdir);
                newfdp->fd_fd.fd_ncdir = cache_hold(fdp->fd_ncdir);
        }
-       newfdp->fd_fd.fd_rdir = fdp->fd_rdir;
-       newfdp->fd_fd.fd_nrdir = cache_hold(fdp->fd_nrdir);
-       vref(newfdp->fd_fd.fd_rdir);
-       newfdp->fd_fd.fd_jdir = fdp->fd_jdir;
-       if (newfdp->fd_fd.fd_jdir) {
+
+       /*
+        * rdir may not be set in e.g. proc0 or anything vm_fork'd off of
+        * proc0, but should unconditionally exist in other processes.
+        */
+       if (fdp->fd_rdir) {
+               newfdp->fd_fd.fd_rdir = fdp->fd_rdir;
+               vref(newfdp->fd_fd.fd_rdir);
+               newfdp->fd_fd.fd_nrdir = cache_hold(fdp->fd_nrdir);
+       }
+       if (fdp->fd_jdir) {
+               newfdp->fd_fd.fd_jdir = fdp->fd_jdir;
                vref(newfdp->fd_fd.fd_jdir);
                newfdp->fd_fd.fd_njdir = cache_hold(fdp->fd_njdir);
        }
 
-
        /* Create the file descriptor table. */
        newfdp->fd_fd.fd_refcnt = 1;
        newfdp->fd_fd.fd_cmask = cmask;
@@ -1221,8 +1227,10 @@ fdfree(struct proc *p)
                cache_drop(fdp->fd_ncdir);
                vrele(fdp->fd_cdir);
        }
-       cache_drop(fdp->fd_nrdir);
-       vrele(fdp->fd_rdir);
+       if (fdp->fd_rdir) {
+               cache_drop(fdp->fd_nrdir);
+               vrele(fdp->fd_rdir);
+       }
        if (fdp->fd_jdir) {
                cache_drop(fdp->fd_njdir);
                vrele(fdp->fd_jdir);
index 50afd92..9c7dc11 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_synch.c        8.9 (Berkeley) 5/19/95
  * $FreeBSD: src/sys/kern/kern_synch.c,v 1.87.2.6 2002/10/13 07:29:53 kbyanc Exp $
- * $DragonFly: src/sys/kern/kern_synch.c,v 1.38 2004/11/10 08:27:54 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_synch.c,v 1.39 2005/01/13 23:05:32 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -371,6 +371,7 @@ tsleep(void *ident, int flags, const char *wmesg, int timo)
 
        td->td_wchan = ident;
        td->td_wmesg = wmesg;
+       td->td_wdomain = flags & PDOMAIN_MASK;
        if (p) {
                if (flags & PNORESCHED)
                        td->td_flags |= TDF_NORESCHED;
@@ -543,7 +544,7 @@ xwakeup(struct xwait *w)
  * Make all processes sleeping on the specified identifier runnable.
  */
 static void
-_wakeup(void *ident, int count)
+_wakeup(void *ident, int domain, int count)
 {
        struct slpquehead *qp;
        struct thread *td;
@@ -556,7 +557,7 @@ _wakeup(void *ident, int count)
 restart:
        for (td = TAILQ_FIRST(qp); td != NULL; td = ntd) {
                ntd = TAILQ_NEXT(td, td_threadq);
-               if (td->td_wchan == ident) {
+               if (td->td_wchan == ident && td->td_wdomain == domain) {
                        TAILQ_REMOVE(qp, td, td_threadq);
                        td->td_wchan = NULL;
                        if ((p = td->td_proc) != NULL && p->p_stat == SSLEEP) {
@@ -594,13 +595,25 @@ restart:
 void
 wakeup(void *ident)
 {
-    _wakeup(ident, 0);
+    _wakeup(ident, 0, 0);
 }
 
 void
 wakeup_one(void *ident)
 {
-    _wakeup(ident, 1);
+    _wakeup(ident, 0, 1);
+}
+
+void
+wakeup_domain(void *ident, int domain)
+{
+    _wakeup(ident, domain, 0);
+}
+
+void
+wakeup_domain_one(void *ident, int domain)
+{
+    _wakeup(ident, domain, 1);
 }
 
 /*
index f2ce205..d2cb5d5 100644 (file)
@@ -82,7 +82,7 @@
  *
  *     @(#)uipc_socket.c       8.3 (Berkeley) 4/15/94
  * $FreeBSD: src/sys/kern/uipc_socket.c,v 1.68.2.24 2003/11/11 17:18:18 silby Exp $
- * $DragonFly: src/sys/kern/uipc_socket.c,v 1.26 2004/12/08 23:59:01 hsu Exp $
+ * $DragonFly: src/sys/kern/uipc_socket.c,v 1.27 2005/01/13 23:05:32 dillon Exp $
  */
 
 #include "opt_inet.h"
@@ -423,10 +423,16 @@ soconnect(struct socket *so, struct sockaddr *nam, struct thread *td)
         */
        if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
            ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
-           (error = sodisconnect(so))))
+           (error = sodisconnect(so)))) {
                error = EISCONN;
-       else
+       } else {
+               /*
+                * Prevent accumulated error from previous connection
+                * from biting us.
+                */
+               so->so_error = 0;
                error = so_pru_connect(so, nam, td);
+       }
        splx(s);
        return (error);
 }