Print this page
12976 system panics with error in IP module
Reviewed by: Andy Fiddaman <andy@omniosce.org>
Reviewed by: Paul Winder <p.winder@me.com>

@@ -19,14 +19,14 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2019 Joyent, Inc.
  * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2013, 2017 by Delphix. All rights reserved.
  * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
+ * Copyright 2020 Joyent, Inc.
  */
 /* Copyright (c) 1990 Mentat Inc. */
 
 #include <sys/types.h>
 #include <sys/stream.h>

@@ -1017,14 +1017,27 @@
         cv_signal(&tcp->tcp_closecv);
         mutex_exit(&tcp->tcp_closelock);
 
         /* If we have an upper handle (socket), release it */
         if (IPCL_IS_NONSTR(connp)) {
-                ASSERT(connp->conn_upper_handle != NULL);
-                (*connp->conn_upcalls->su_closed)(connp->conn_upper_handle);
+                sock_upcalls_t *upcalls = connp->conn_upcalls;
+                sock_upper_handle_t handle = connp->conn_upper_handle;
+
+                ASSERT(upcalls != NULL);
+                ASSERT(upcalls->su_closed != NULL);
+                ASSERT(handle != NULL);
+                /*
+                 * Set these to NULL first because closed() will free upper
+                 * structures.  Acquire conn_lock because an external caller
+                 * like conn_get_socket_info() will upcall if these are
+                 * non-NULL.
+                 */
+                mutex_enter(&connp->conn_lock);
                 connp->conn_upper_handle = NULL;
                 connp->conn_upcalls = NULL;
+                mutex_exit(&connp->conn_lock);
+                upcalls->su_closed(handle);
         }
 }
 
 void
 tcp_close_common(conn_t *connp, int flags)

@@ -1419,17 +1432,30 @@
          * handle, release it. As a result of fallback we might also see
          * STREAMS based conns with upper handles, in which case there is
          * nothing to do other than clearing the field.
          */
         if (connp->conn_upper_handle != NULL) {
+                sock_upcalls_t *upcalls = connp->conn_upcalls;
+                sock_upper_handle_t handle = connp->conn_upper_handle;
+
+                /*
+                 * Set these to NULL first because closed() will free upper
+                 * structures.  Acquire conn_lock because an external caller
+                 * like conn_get_socket_info() will upcall if these are
+                 * non-NULL.
+                 */
+                mutex_enter(&connp->conn_lock);
+                connp->conn_upper_handle = NULL;
+                connp->conn_upcalls = NULL;
+                mutex_exit(&connp->conn_lock);
                 if (IPCL_IS_NONSTR(connp)) {
-                        (*connp->conn_upcalls->su_closed)(
-                            connp->conn_upper_handle);
+                        ASSERT(upcalls != NULL);
+                        ASSERT(upcalls->su_closed != NULL);
+                        ASSERT(handle != NULL);
+                        upcalls->su_closed(handle);
                         tcp->tcp_detached = B_TRUE;
                 }
-                connp->conn_upper_handle = NULL;
-                connp->conn_upcalls = NULL;
         }
 }
 
 /*
  * tcp_get_conn/tcp_free_conn