changeset 3429:cce097545bd7

4765561 tcp panic due to memory corruption
author vi117747
date Wed, 17 Jan 2007 02:06:46 -0800
parents e02a49834ca2
children 40584439315b
files usr/src/uts/common/inet/tcp.h usr/src/uts/common/inet/tcp/tcp.c usr/src/uts/common/inet/tcp/tcp_fusion.c usr/src/uts/common/inet/tcp/tcp_kssl.c usr/src/uts/common/inet/tcp_impl.h
diffstat 5 files changed, 150 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/inet/tcp.h	Tue Jan 16 16:37:36 2007 -0800
+++ b/usr/src/uts/common/inet/tcp.h	Wed Jan 17 02:06:46 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -235,40 +235,39 @@
 		tcp_fin_rcvd : 1,	/* Have we seen a FIN? */
 		tcp_fin_sent : 1,	/* Have we sent our FIN yet? */
 		tcp_ordrel_done : 1,	/* Have we sent the ord_rel upstream? */
-		tcp_flow_stopped : 1,	/* Have we flow controlled xmitter? */
+		tcp_detached : 1,	/* If we're detached from a stream */
 
-		tcp_detached : 1,	/* If we're detached from a stream */
 		tcp_bind_pending : 1,	/* Client is waiting for bind ack */
 		tcp_unbind_pending : 1, /* Client sent T_UNBIND_REQ */
 		tcp_deferred_clean_death : 1,
 					/* defer tcp endpoint cleanup etc. */
+		tcp_conn_def_q0: 1,	/* move from q0 to q deferred */
 
-		tcp_conn_def_q0: 1,	/* move from q0 to q deferred */
 		tcp_ka_enabled: 1,	/* Connection KeepAlive Timer needed */
 		tcp_zero_win_probe: 1,	/* Zero win probing is in progress */
 		tcp_loopback: 1,	/* src and dst are the same machine */
+		tcp_localnet: 1,	/* src and dst are on the same subnet */
 
-		tcp_localnet: 1,	/* src and dst are on the same subnet */
 		tcp_syn_defense: 1,	/* For defense against SYN attack */
 #define	tcp_dontdrop	tcp_syn_defense
 		tcp_set_timer : 1,
 		tcp_active_open: 1,	/* This is a active open */
+		tcp_timeout : 1,	/* qbufcall failed, qtimeout pending */
 
-		tcp_timeout : 1,	/* qbufcall failed, qtimeout pending */
 		tcp_rexmit : 1,		/* TCP is retransmitting */
 		tcp_snd_sack_ok : 1,	/* Can use SACK for this connection */
 		tcp_empty_flag : 1,	/* Empty flag for future use */
+		tcp_recvdstaddr : 1,	/* return T_EXTCONN_IND with dst addr */
 
-		tcp_recvdstaddr : 1,	/* return T_EXTCONN_IND with dst addr */
 		tcp_hwcksum : 1,	/* The NIC is capable of hwcksum */
 		tcp_ip_forward_progress : 1,
 		tcp_anon_priv_bind : 1,
+		tcp_ecn_ok : 1,		/* Can use ECN for this connection */
 
-		tcp_ecn_ok : 1,		/* Can use ECN for this connection */
 		tcp_ecn_echo_on : 1,	/* Need to do ECN echo */
 		tcp_ecn_cwr_sent : 1,	/* ECN_CWR has been sent */
-		tcp_cwr : 1;		/* Cwnd has reduced recently */
-
+		tcp_cwr : 1,		/* Cwnd has reduced recently */
+		tcp_pad_to_bit31 : 1;
 	/* Following manipulated by TCP under squeue protection */
 	uint32_t
 		tcp_mdt : 1,		/* Lower layer is capable of MDT */
@@ -528,9 +527,11 @@
 	uint_t	tcp_fuse_rcv_unread_hiwater;	/* max # of outstanding pkts */
 	/*
 	 * The following fusion-related fields and bit fields are to be
-	 * manipulated with squeue protection or with tcp_fuse_lock held.
+	 * manipulated with squeue protection or with tcp_non_sq_lock held.
+	 * tcp_non_sq_lock is used to protect fields that may be modified
+	 * accessed outside the squeue.
 	 */
-	kmutex_t tcp_fuse_lock;
+	kmutex_t tcp_non_sq_lock;
 	kcondvar_t tcp_fuse_plugcv;
 	uint_t tcp_fuse_rcv_unread_cnt;	/* # of outstanding pkts */
 	uint32_t
@@ -550,6 +551,7 @@
 	 */
 	boolean_t	tcp_issocket;	/* this is a socket tcp */
 
+	/* protected by the tcp_non_sq_lock lock */
 	uint32_t	tcp_squeue_bytes;
 	/*
 	 * Kernel SSL session information
@@ -579,6 +581,16 @@
 	 */
 	struct tcp_s	*tcp_eager_prev_drop_q0;
 	struct tcp_s	*tcp_eager_next_drop_q0;
+
+	/*
+	 * Have we flow controlled xmitter?
+	 * This variable can be modified outside the squeue and hence must
+	 * not be declared as a bit field along with the rest that are
+	 * modified only within the squeue.
+	 * protected by the tcp_non_sq_lock lock.
+	 */
+	boolean_t	tcp_flow_stopped;
+
 #ifdef DEBUG
 	pc_t			tcmp_stk[15];
 #endif
--- a/usr/src/uts/common/inet/tcp/tcp.c	Tue Jan 16 16:37:36 2007 -0800
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Wed Jan 17 02:06:46 2007 -0800
@@ -3983,9 +3983,11 @@
 	tcp->tcp_linger_tid = 0;
 	if (tcp->tcp_state > TCPS_LISTEN) {
 		tcp_acceptor_hash_remove(tcp);
+		mutex_enter(&tcp->tcp_non_sq_lock);
 		if (tcp->tcp_flow_stopped) {
 			tcp_clrqfull(tcp);
 		}
+		mutex_exit(&tcp->tcp_non_sq_lock);
 
 		if (tcp->tcp_timer_tid != 0) {
 			delta = TCP_TIMER_CANCEL(tcp, tcp->tcp_timer_tid);
@@ -4347,9 +4349,11 @@
 		 */
 		tcp_acceptor_hash_remove(tcp);
 
+		mutex_enter(&tcp->tcp_non_sq_lock);
 		if (tcp->tcp_flow_stopped) {
 			tcp_clrqfull(tcp);
 		}
+		mutex_exit(&tcp->tcp_non_sq_lock);
 
 		if (tcp->tcp_timer_tid != 0) {
 			delta = TCP_TIMER_CANCEL(tcp, tcp->tcp_timer_tid);
@@ -4558,8 +4562,10 @@
 			tcp->tcp_ip_addr_cache = NULL;
 		}
 	}
+	mutex_enter(&tcp->tcp_non_sq_lock);
 	if (tcp->tcp_flow_stopped)
 		tcp_clrqfull(tcp);
+	mutex_exit(&tcp->tcp_non_sq_lock);
 
 	tcp_bind_hash_remove(tcp);
 	/*
@@ -7714,10 +7720,12 @@
 		tcp_zcopy_notify(tcp);
 	tcp->tcp_xmit_last = tcp->tcp_xmit_tail = NULL;
 	tcp->tcp_unsent = tcp->tcp_xmit_tail_unsent = 0;
+	mutex_enter(&tcp->tcp_non_sq_lock);
 	if (tcp->tcp_flow_stopped &&
 	    TCP_UNSENT_BYTES(tcp) <= tcp->tcp_xmit_lowater) {
 		tcp_clrqfull(tcp);
 	}
+	mutex_exit(&tcp->tcp_non_sq_lock);
 	tcp_close_mpp(&tcp->tcp_reass_head);
 	tcp->tcp_reass_tail = NULL;
 	if (tcp->tcp_rcv_list != NULL) {
@@ -10272,8 +10280,6 @@
 				tcp->tcp_dgram_errind = onoff;
 			break;
 		case SO_SNDBUF: {
-			tcp_t *peer_tcp;
-
 			if (*i1 > tcp_max_buf) {
 				*outlenp = 0;
 				return (ENOBUFS);
@@ -10292,22 +10298,13 @@
 			 * There are apps that increase SO_SNDBUF size when
 			 * flow-controlled (EWOULDBLOCK), and expect the flow
 			 * control condition to be lifted right away.
-			 *
-			 * For the fused tcp loopback case, in order to avoid
-			 * a race with the peer's tcp_fuse_rrw() we need to
-			 * hold its fuse_lock while accessing tcp_flow_stopped.
-			 */
-			peer_tcp = tcp->tcp_loopback_peer;
-			ASSERT(!tcp->tcp_fused || peer_tcp != NULL);
-			if (tcp->tcp_fused)
-				mutex_enter(&peer_tcp->tcp_fuse_lock);
-
+			 */
+			mutex_enter(&tcp->tcp_non_sq_lock);
 			if (tcp->tcp_flow_stopped &&
 			    TCP_UNSENT_BYTES(tcp) < tcp->tcp_xmit_hiwater) {
 				tcp_clrqfull(tcp);
 			}
-			if (tcp->tcp_fused)
-				mutex_exit(&peer_tcp->tcp_fuse_lock);
+			mutex_exit(&tcp->tcp_non_sq_lock);
 			break;
 		}
 		case SO_RCVBUF:
@@ -17389,9 +17386,9 @@
 	ASSERT(DB_TYPE(mp) == M_DATA);
 	msize = (mp->b_cont == NULL) ? MBLKL(mp) : msgdsize(mp);
 
-	mutex_enter(&connp->conn_lock);
+	mutex_enter(&tcp->tcp_non_sq_lock);
 	tcp->tcp_squeue_bytes -= msize;
-	mutex_exit(&connp->conn_lock);
+	mutex_exit(&tcp->tcp_non_sq_lock);
 
 	/* Bypass tcp protocol for fused tcp loopback */
 	if (tcp->tcp_fused && tcp_fuse_output(tcp, mp, msize))
@@ -17475,10 +17472,12 @@
 		goto slow;
 	}
 
+	mutex_enter(&tcp->tcp_non_sq_lock);
 	if (tcp->tcp_flow_stopped &&
 	    TCP_UNSENT_BYTES(tcp) <= tcp->tcp_xmit_lowater) {
 		tcp_clrqfull(tcp);
 	}
+	mutex_exit(&tcp->tcp_non_sq_lock);
 
 	/*
 	 * determine if anything to send (Nagle).
@@ -17862,15 +17861,29 @@
 		 * For fused tcp loopback, back-enable peer endpoint
 		 * if it's currently flow-controlled.
 		 */
-		if (tcp->tcp_fused &&
-		    tcp->tcp_loopback_peer->tcp_flow_stopped) {
+		if (tcp->tcp_fused) {
 			tcp_t *peer_tcp = tcp->tcp_loopback_peer;
 
 			ASSERT(peer_tcp != NULL);
 			ASSERT(peer_tcp->tcp_fused);
-
-			tcp_clrqfull(peer_tcp);
-			TCP_STAT(tcp_fusion_backenabled);
+			/*
+			 * In order to change the peer's tcp_flow_stopped,
+			 * we need to take locks for both end points. The
+			 * highest address is taken first.
+			 */
+			if (peer_tcp > tcp) {
+				mutex_enter(&peer_tcp->tcp_non_sq_lock);
+				mutex_enter(&tcp->tcp_non_sq_lock);
+			} else {
+				mutex_enter(&tcp->tcp_non_sq_lock);
+				mutex_enter(&peer_tcp->tcp_non_sq_lock);
+			}
+			if (peer_tcp->tcp_flow_stopped) {
+				tcp_clrqfull(peer_tcp);
+				TCP_STAT(tcp_fusion_backenabled);
+			}
+			mutex_exit(&peer_tcp->tcp_non_sq_lock);
+			mutex_exit(&tcp->tcp_non_sq_lock);
 		}
 	}
 	ASSERT(tcp->tcp_rcv_list == NULL || tcp->tcp_fused_sigurg);
@@ -18228,16 +18241,14 @@
 
 		msize = msgdsize(mp);
 
-		mutex_enter(&connp->conn_lock);
-		CONN_INC_REF_LOCKED(connp);
-
+		mutex_enter(&tcp->tcp_non_sq_lock);
 		tcp->tcp_squeue_bytes += msize;
 		if (TCP_UNSENT_BYTES(tcp) > tcp->tcp_xmit_hiwater) {
-			mutex_exit(&connp->conn_lock);
 			tcp_setqfull(tcp);
-		} else
-			mutex_exit(&connp->conn_lock);
-
+		}
+		mutex_exit(&tcp->tcp_non_sq_lock);
+
+		CONN_INC_REF(connp);
 		(*tcp_squeue_wput_proc)(connp->conn_sqp, mp,
 		    tcp_output, connp, SQTAG_TCP_OUTPUT);
 		return;
@@ -18929,10 +18940,12 @@
 		    (mp->b_datap->db_struioflag & STRUIO_ZCNOTIFY) != 0)
 			tcp_zcopy_notify(tcp);
 		freemsg(mp);
+		mutex_enter(&tcp->tcp_non_sq_lock);
 		if (tcp->tcp_flow_stopped &&
 		    TCP_UNSENT_BYTES(tcp) <= tcp->tcp_xmit_lowater) {
 			tcp_clrqfull(tcp);
 		}
+		mutex_exit(&tcp->tcp_non_sq_lock);
 		return;
 	}
 
@@ -19268,6 +19281,7 @@
 	}
 	/* Note that len is the amount we just sent but with a negative sign */
 	tcp->tcp_unsent += len;
+	mutex_enter(&tcp->tcp_non_sq_lock);
 	if (tcp->tcp_flow_stopped) {
 		if (TCP_UNSENT_BYTES(tcp) <= tcp->tcp_xmit_lowater) {
 			tcp_clrqfull(tcp);
@@ -19275,6 +19289,7 @@
 	} else if (TCP_UNSENT_BYTES(tcp) >= tcp->tcp_xmit_hiwater) {
 		tcp_setqfull(tcp);
 	}
+	mutex_exit(&tcp->tcp_non_sq_lock);
 }
 
 /*
@@ -21537,9 +21552,11 @@
 		 * We have no unsent data, so unsent must be less than
 		 * tcp_xmit_lowater, so re-enable flow.
 		 */
+		mutex_enter(&tcp->tcp_non_sq_lock);
 		if (tcp->tcp_flow_stopped) {
 			tcp_clrqfull(tcp);
 		}
+		mutex_exit(&tcp->tcp_non_sq_lock);
 	}
 	/*
 	 * TODO: you can't just flush these, you have to increase rwnd for one
--- a/usr/src/uts/common/inet/tcp/tcp_fusion.c	Tue Jan 16 16:37:36 2007 -0800
+++ b/usr/src/uts/common/inet/tcp/tcp_fusion.c	Wed Jan 17 02:06:46 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -62,18 +62,18 @@
  * because the tcp_fuse_rrw() path bypasses the M_PROTO processing done
  * by strsock_proto() hook.
  *
- * Sychronization is handled by squeue and the mutex tcp_fuse_lock.
+ * Sychronization is handled by squeue and the mutex tcp_non_sq_lock.
  * One of the requirements for fusion to succeed is that both endpoints
  * need to be using the same squeue.  This ensures that neither side
  * can disappear while the other side is still sending data.  By itself,
  * squeue is not sufficient for guaranteeing safety when synchronous
  * streams is enabled.  The reason is that tcp_fuse_rrw() doesn't enter
  * the squeue and its access to tcp_rcv_list and other fusion-related
- * fields needs to be sychronized with the sender.  tcp_fuse_lock is
+ * fields needs to be sychronized with the sender.  tcp_non_sq_lock is
  * used for this purpose.  When there is urgent data, the sender needs
  * to push the data up the receiver's streams read queue.  In order to
- * avoid holding the tcp_fuse_lock across putnext(), the sender sets
- * the peer tcp's tcp_fuse_syncstr_plugged bit and releases tcp_fuse_lock
+ * avoid holding the tcp_non_sq_lock across putnext(), the sender sets
+ * the peer tcp's tcp_fuse_syncstr_plugged bit and releases tcp_non_sq_lock
  * (see macro TCP_FUSE_SYNCSTR_PLUG_DRAIN()).  If tcp_fuse_rrw() enters
  * after this point, it will see that synchronous streams is plugged and
  * will wait on tcp_fuse_plugcv.  After the sender has finished pushing up
@@ -456,6 +456,8 @@
 
 /*
  * Fusion output routine, called by tcp_output() and tcp_wput_proto().
+ * If we are modifying any member that can be changed outside the squeue,
+ * like tcp_flow_stopped, we need to take tcp_non_sq_lock.
  */
 boolean_t
 tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size)
@@ -597,7 +599,7 @@
 		freemsg(mp1);
 	}
 
-	mutex_enter(&peer_tcp->tcp_fuse_lock);
+	mutex_enter(&peer_tcp->tcp_non_sq_lock);
 	/*
 	 * Wake up and signal the peer; it is okay to do this before
 	 * enqueueing because we are holding the lock.  One of the
@@ -644,6 +646,20 @@
 	if (TCP_IS_DETACHED(peer_tcp) || max_unread == 0)
 		max_unread = UINT_MAX;
 
+	/*
+	 * Since we are accessing our tcp_flow_stopped and might modify it,
+	 * we need to take tcp->tcp_non_sq_lock. The lock for the highest
+	 * address is held first. Dropping peer_tcp->tcp_non_sq_lock should
+	 * not be an issue here since we are within the squeue and the peer
+	 * won't disappear.
+	 */
+	if (tcp > peer_tcp) {
+		mutex_exit(&peer_tcp->tcp_non_sq_lock);
+		mutex_enter(&tcp->tcp_non_sq_lock);
+		mutex_enter(&peer_tcp->tcp_non_sq_lock);
+	} else {
+		mutex_enter(&tcp->tcp_non_sq_lock);
+	}
 	flow_stopped = tcp->tcp_flow_stopped;
 	if (!flow_stopped &&
 	    (((peer_tcp->tcp_direct_sockfs || TCP_IS_DETACHED(peer_tcp)) &&
@@ -662,7 +678,7 @@
 		tcp_clrqfull(tcp);
 		flow_stopped = B_FALSE;
 	}
-
+	mutex_exit(&tcp->tcp_non_sq_lock);
 	loopback_packets++;
 	tcp->tcp_last_sent_len = send_size;
 
@@ -682,7 +698,7 @@
 	BUMP_LOCAL(tcp->tcp_obsegs);
 	BUMP_LOCAL(peer_tcp->tcp_ibsegs);
 
-	mutex_exit(&peer_tcp->tcp_fuse_lock);
+	mutex_exit(&peer_tcp->tcp_non_sq_lock);
 
 	DTRACE_PROBE2(tcp__fuse__output, tcp_t *, tcp, uint_t, send_size);
 
@@ -826,14 +842,26 @@
 /*
  * Synchronous stream entry point for sockfs to retrieve
  * data directly from tcp_rcv_list.
+ * tcp_fuse_rrw() might end up modifying the peer's tcp_flow_stopped,
+ * for which it  must take the tcp_non_sq_lock of the peer as well
+ * making any change. The order of taking the locks is based on
+ * the TCP pointer itself. Before we get the peer we need to take
+ * our tcp_non_sq_lock so that the peer doesn't disappear. However,
+ * we cannot drop the lock if we have to grab the peer's lock (because
+ * of ordering), since the peer might disappear in the interim. So,
+ * we take our tcp_non_sq_lock, get the peer, increment the ref on the
+ * peer's conn, drop all the locks and then take the tcp_non_sq_lock in the
+ * desired order. Incrementing the conn ref on the peer means that the
+ * peer won't disappear when we drop our tcp_non_sq_lock.
  */
 int
 tcp_fuse_rrw(queue_t *q, struiod_t *dp)
 {
 	tcp_t *tcp = Q_TO_CONN(q)->conn_tcp;
 	mblk_t *mp;
+	tcp_t *peer_tcp;
 
-	mutex_enter(&tcp->tcp_fuse_lock);
+	mutex_enter(&tcp->tcp_non_sq_lock);
 
 	/*
 	 * If tcp_fuse_syncstr_plugged is set, then another thread is moving
@@ -841,30 +869,53 @@
 	 * done, then return EBUSY so that strget() will dequeue data from the
 	 * stream head to ensure data is drained in-order.
 	 */
+plugged:
 	if (tcp->tcp_fuse_syncstr_plugged) {
 		do {
-			cv_wait(&tcp->tcp_fuse_plugcv, &tcp->tcp_fuse_lock);
+			cv_wait(&tcp->tcp_fuse_plugcv, &tcp->tcp_non_sq_lock);
 		} while (tcp->tcp_fuse_syncstr_plugged);
 
-		mutex_exit(&tcp->tcp_fuse_lock);
+		mutex_exit(&tcp->tcp_non_sq_lock);
 		TCP_STAT(tcp_fusion_rrw_plugged);
 		TCP_STAT(tcp_fusion_rrw_busy);
 		return (EBUSY);
 	}
 
+	peer_tcp = tcp->tcp_loopback_peer;
+
 	/*
 	 * If someone had turned off tcp_direct_sockfs or if synchronous
 	 * streams is stopped, we return EBUSY.  This causes strget() to
 	 * dequeue data from the stream head instead.
 	 */
 	if (!tcp->tcp_direct_sockfs || tcp->tcp_fuse_syncstr_stopped) {
-		mutex_exit(&tcp->tcp_fuse_lock);
+		mutex_exit(&tcp->tcp_non_sq_lock);
 		TCP_STAT(tcp_fusion_rrw_busy);
 		return (EBUSY);
 	}
 
+	/*
+	 * Grab lock in order. The highest addressed tcp is locked first.
+	 * We don't do this within the tcp_rcv_list check since if we
+	 * have to drop the lock, for ordering, then the tcp_rcv_list
+	 * could change.
+	 */
+	if (peer_tcp > tcp) {
+		CONN_INC_REF(peer_tcp->tcp_connp);
+		mutex_exit(&tcp->tcp_non_sq_lock);
+		mutex_enter(&peer_tcp->tcp_non_sq_lock);
+		mutex_enter(&tcp->tcp_non_sq_lock);
+		CONN_DEC_REF(peer_tcp->tcp_connp);
+		/* This might have changed in the interim */
+		if (tcp->tcp_fuse_syncstr_plugged) {
+			mutex_exit(&peer_tcp->tcp_non_sq_lock);
+			goto plugged;
+		}
+	} else {
+		mutex_enter(&peer_tcp->tcp_non_sq_lock);
+	}
+
 	if ((mp = tcp->tcp_rcv_list) != NULL) {
-		tcp_t *peer_tcp = tcp->tcp_loopback_peer;
 
 		DTRACE_PROBE3(tcp__fuse__rrw, tcp_t *, tcp,
 		    uint32_t, tcp->tcp_rcv_cnt, ssize_t, dp->d_uio.uio_resid);
@@ -892,7 +943,7 @@
 			TCP_STAT(tcp_fusion_backenabled);
 		}
 	}
-
+	mutex_exit(&peer_tcp->tcp_non_sq_lock);
 	/*
 	 * Either we just dequeued everything or we get here from sockfs
 	 * and have nothing to return; in this case clear RSLEEP.
@@ -903,7 +954,7 @@
 	ASSERT(tcp->tcp_fuse_rcv_unread_cnt == 0);
 	STR_WAKEUP_CLEAR(STREAM(q));
 
-	mutex_exit(&tcp->tcp_fuse_lock);
+	mutex_exit(&tcp->tcp_non_sq_lock);
 	dp->d_mp = mp;
 	return (0);
 }
@@ -922,7 +973,7 @@
 	int	error = 0;
 	struct stdata *stp = STREAM(q);
 
-	mutex_enter(&tcp->tcp_fuse_lock);
+	mutex_enter(&tcp->tcp_non_sq_lock);
 	/* If shutdown on read has happened, return nothing */
 	mutex_enter(&stp->sd_lock);
 	if (stp->sd_flag & STREOF) {
@@ -989,7 +1040,7 @@
 		dp->d_cmd &= ~INFOD_COPYOUT;
 	}
 done:
-	mutex_exit(&tcp->tcp_fuse_lock);
+	mutex_exit(&tcp->tcp_non_sq_lock);
 
 	dp->d_res |= res;
 
--- a/usr/src/uts/common/inet/tcp/tcp_kssl.c	Tue Jan 16 16:37:36 2007 -0800
+++ b/usr/src/uts/common/inet/tcp/tcp_kssl.c	Wed Jan 17 02:06:46 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -137,10 +137,9 @@
 			 * outgoing flow. tcp_output() will decrement it
 			 * as they are sent out.
 			 */
-			ASSERT(!MUTEX_HELD(&connp->conn_lock));
-			mutex_enter(&connp->conn_lock);
+			mutex_enter(&tcp->tcp_non_sq_lock);
 			tcp->tcp_squeue_bytes += msgdsize(outmp);
-			mutex_exit(&connp->conn_lock);
+			mutex_exit(&tcp->tcp_non_sq_lock);
 			tcp_output(connp, outmp, NULL);
 
 		/* FALLTHROUGH */
@@ -330,14 +329,11 @@
 			/*
 			 * See comment in tcp_kssl_input() call to tcp_output()
 			 */
-			ASSERT(!MUTEX_HELD(&connp->conn_lock));
-			mutex_enter(&connp->conn_lock);
-			CONN_INC_REF_LOCKED(connp);
+			mutex_enter(&tcp->tcp_non_sq_lock);
 			tcp->tcp_squeue_bytes += msgdsize(mp);
-			mutex_exit(&connp->conn_lock);
-		} else {
-			CONN_INC_REF(connp);
+			mutex_exit(&tcp->tcp_non_sq_lock);
 		}
+		CONN_INC_REF(connp);
 		(*tcp_squeue_wput_proc)(connp->conn_sqp, mp,
 		    tcp_output, connp, SQTAG_TCP_OUTPUT);
 
--- a/usr/src/uts/common/inet/tcp_impl.h	Tue Jan 16 16:37:36 2007 -0800
+++ b/usr/src/uts/common/inet/tcp_impl.h	Wed Jan 17 02:06:46 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -76,9 +76,9 @@
  */
 #define	TCP_FUSE_SYNCSTR_STOP(tcp) {				\
 	if ((tcp)->tcp_direct_sockfs) {				\
-		mutex_enter(&(tcp)->tcp_fuse_lock);		\
+		mutex_enter(&(tcp)->tcp_non_sq_lock);		\
 		(tcp)->tcp_fuse_syncstr_stopped = B_TRUE;	\
-		mutex_exit(&(tcp)->tcp_fuse_lock);		\
+		mutex_exit(&(tcp)->tcp_non_sq_lock);		\
 	}							\
 }
 
@@ -88,10 +88,10 @@
  */
 #define	TCP_FUSE_SYNCSTR_PLUG_DRAIN(tcp) {			\
 	if ((tcp)->tcp_direct_sockfs) {				\
-		mutex_enter(&(tcp)->tcp_fuse_lock);		\
+		mutex_enter(&(tcp)->tcp_non_sq_lock);		\
 		ASSERT(!(tcp)->tcp_fuse_syncstr_plugged);	\
 		(tcp)->tcp_fuse_syncstr_plugged = B_TRUE;	\
-		mutex_exit(&(tcp)->tcp_fuse_lock);		\
+		mutex_exit(&(tcp)->tcp_non_sq_lock);		\
 	}							\
 }
 
@@ -101,10 +101,10 @@
  */
 #define	TCP_FUSE_SYNCSTR_UNPLUG_DRAIN(tcp) {			\
 	if ((tcp)->tcp_direct_sockfs) {				\
-		mutex_enter(&(tcp)->tcp_fuse_lock);		\
+		mutex_enter(&(tcp)->tcp_non_sq_lock);		\
 		(tcp)->tcp_fuse_syncstr_plugged = B_FALSE;	\
 		(void) cv_broadcast(&(tcp)->tcp_fuse_plugcv);	\
-		mutex_exit(&(tcp)->tcp_fuse_lock);		\
+		mutex_exit(&(tcp)->tcp_non_sq_lock);		\
 	}							\
 }