]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/uipc_usrreq.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / bsd / kern / uipc_usrreq.c
index 78487fdcfcaa05dae0001c088a25916984a90790..986209b66bd4cdc3cc3a087056fe647820d705a8 100644 (file)
@@ -1,23 +1,31 @@
 /*
  * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
+ * This file contains Original Code and/or Modifications of Original Code 
+ * as defined in and that are subject to the Apple Public Source License 
+ * Version 2.0 (the 'License'). You may not use this file except in 
+ * compliance with the License.  The rights granted to you under the 
+ * License may not be used to create, or enable the creation or 
+ * redistribution of, unlawful or unlicensed copies of an Apple operating 
+ * system, or to circumvent, violate, or enable the circumvention or 
+ * violation of, any terms of an Apple operating system software license 
+ * agreement.
+ *
+ * Please obtain a copy of the License at 
+ * http://www.opensource.apple.com/apsl/ and read it before using this 
+ * file.
+ *
+ * The Original Code and all software distributed under the License are 
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
+ * Please see the License for the specific language governing rights and 
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
  */
 /*
  * Copyright (c) 1982, 1986, 1989, 1991, 1993
 struct zone *unp_zone;
 static unp_gen_t unp_gencnt;
 static u_int unp_count;
-static lck_mtx_t               *unp_mutex;
+
+static lck_attr_t              *unp_mtx_attr;
+static lck_grp_t               *unp_mtx_grp;
+static lck_grp_attr_t          *unp_mtx_grp_attr;
+static lck_rw_t                *unp_list_mtx;
 
 extern lck_mtx_t * uipc_lock;
 static struct unp_head unp_shead, unp_dhead;
@@ -303,8 +315,13 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
                goto release;
        }
 
-       if (control && (error = unp_internalize(control, p)))
-               goto release;
+       if (control) {
+               socket_unlock(so, 0); /* release global lock to avoid deadlock (4436174) */ 
+               error = unp_internalize(control, p);
+               socket_lock(so, 0);
+               if (error)
+                       goto release;
+       }
 
        switch (so->so_type) {
        case SOCK_DGRAM: 
@@ -559,7 +576,7 @@ unp_attach(struct socket *so)
        if (unp == NULL)
                return (ENOBUFS);
        bzero(unp, sizeof *unp);
-       lck_mtx_lock(unp_mutex);
+       lck_rw_lock_exclusive(unp_list_mtx);
        LIST_INIT(&unp->unp_refs);
        unp->unp_socket = so;
        unp->unp_gencnt = ++unp_gencnt;
@@ -567,16 +584,17 @@ unp_attach(struct socket *so)
        LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead
                         : &unp_shead, unp, unp_link);
        so->so_pcb = (caddr_t)unp;
-       lck_mtx_unlock(unp_mutex);
+       lck_rw_done(unp_list_mtx);
        return (0);
 }
 
 static void
 unp_detach(struct unpcb *unp)
 {
-       lck_mtx_assert(unp_mutex, LCK_MTX_ASSERT_OWNED);
+       lck_rw_lock_exclusive(unp_list_mtx);
        LIST_REMOVE(unp, unp_link);
        unp->unp_gencnt = ++unp_gencnt;
+       lck_rw_done(unp_list_mtx);
        --unp_count;
        if (unp->unp_vnode) {
                struct vnode *tvp = unp->unp_vnode;
@@ -722,7 +740,7 @@ unp_connect(
        if (error)
                goto bad;
        so2 = vp->v_socket;
-       if (so2 == 0) {
+       if (so2 == 0 || so2->so_pcb == NULL ) {
                error = ECONNREFUSED;
                goto bad;
        }
@@ -787,8 +805,10 @@ unp_connect(
        }
        error = unp_connect2(so, so2);
 bad:
-       if (so2 != NULL)
-               so2->so_usecount--; /* release count on socket */
+        
+       if (so2 != NULL) 
+                       so2->so_usecount--;     /* release count on socket */
+       
        vnode_put(vp);
        return (error);
 }
@@ -844,12 +864,13 @@ unp_disconnect(struct unpcb *unp)
 
        if (unp2 == 0)
                return;
-       lck_mtx_assert(unp_mutex, LCK_MTX_ASSERT_OWNED);
        unp->unp_conn = 0;
        switch (unp->unp_socket->so_type) {
 
        case SOCK_DGRAM:
+               lck_rw_lock_exclusive(unp_list_mtx);
                LIST_REMOVE(unp, unp_reflink);
+               lck_rw_done(unp_list_mtx);
                unp->unp_socket->so_state &= ~SS_ISCONNECTED;
                break;
 
@@ -879,7 +900,7 @@ unp_pcblist SYSCTL_HANDLER_ARGS
        struct xunpgen xug;
        struct unp_head *head;
 
-       lck_mtx_lock(unp_mutex);
+       lck_rw_lock_shared(unp_list_mtx);
        head = ((intptr_t)arg1 == SOCK_DGRAM ? &unp_dhead : &unp_shead);
 
        /*
@@ -890,12 +911,12 @@ unp_pcblist SYSCTL_HANDLER_ARGS
                n = unp_count;
                req->oldidx = 2 * (sizeof xug)
                        + (n + n/8) * sizeof(struct xunpcb);
-               lck_mtx_unlock(unp_mutex);
+               lck_rw_done(unp_list_mtx);
                return 0;
        }
 
        if (req->newptr != USER_ADDR_NULL) {
-               lck_mtx_unlock(unp_mutex);
+               lck_rw_done(unp_list_mtx);
                return EPERM;
        }
 
@@ -912,7 +933,7 @@ unp_pcblist SYSCTL_HANDLER_ARGS
        xug.xug_sogen = so_gencnt;
        error = SYSCTL_OUT(req, &xug, sizeof xug);
        if (error) {
-               lck_mtx_unlock(unp_mutex);
+               lck_rw_done(unp_list_mtx);
                return error;
        }
 
@@ -920,13 +941,13 @@ unp_pcblist SYSCTL_HANDLER_ARGS
         * We are done if there is no pcb
         */
        if (n == 0)  {
-           lck_mtx_unlock(unp_mutex);
+           lck_rw_done(unp_list_mtx);
            return 0;
        }
 
        MALLOC(unp_list, struct unpcb **, n * sizeof *unp_list, M_TEMP, M_WAITOK);
        if (unp_list == 0) {
-               lck_mtx_unlock(unp_mutex);
+               lck_rw_done(unp_list_mtx);
                return ENOMEM;
        }
        
@@ -978,7 +999,7 @@ unp_pcblist SYSCTL_HANDLER_ARGS
                error = SYSCTL_OUT(req, &xug, sizeof xug);
        }
        FREE(unp_list, M_TEMP);
-       lck_mtx_unlock(unp_mutex);
+       lck_rw_done(unp_list_mtx);
        return error;
 }
 
@@ -1081,7 +1102,18 @@ unp_init(void)
        LIST_INIT(&unp_dhead);
        LIST_INIT(&unp_shead);
        
-       unp_mutex = localdomain.dom_mtx;
+       /*
+        * allocate lock group attribute and group for udp pcb mutexes
+        */
+       unp_mtx_grp_attr = lck_grp_attr_alloc_init();
+
+       unp_mtx_grp = lck_grp_alloc_init("unp_list", unp_mtx_grp_attr);
+               
+       unp_mtx_attr = lck_attr_alloc_init();
+
+       if ((unp_list_mtx = lck_rw_alloc_init(unp_mtx_grp, unp_mtx_attr)) == NULL)
+               return; /* pretty much dead if this fails... */
+
 }
 
 #ifndef MIN