diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/inet/tcp/tcp.c | 37 | ||||
-rw-r--r-- | usr/src/uts/common/inet/tcp/tcp_fusion.c | 98 |
2 files changed, 67 insertions, 68 deletions
diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c index c84de5bf29..b9ef642919 100644 --- a/usr/src/uts/common/inet/tcp/tcp.c +++ b/usr/src/uts/common/inet/tcp/tcp.c @@ -21700,8 +21700,7 @@ tcp_wput_proto(void *arg, mblk_t *mp, void *arg2) if ((mp->b_wptr - rptr) >= sizeof (t_scalar_t)) { type = ((union T_primitives *)rptr)->type; if (type == T_EXDATA_REQ) { - tcp_output_urgent(connp, mp->b_cont, arg2); - freeb(mp); + tcp_output_urgent(connp, mp, arg2); } else if (type != T_DATA_REQ) { goto non_urgent_data; } else { @@ -26721,9 +26720,8 @@ tcp_output_urgent(void *arg, mblk_t *mp, void *arg2) } /* - * Try to force urgent data out on the wire. - * Even if we have unsent data this will - * at least send the urgent flag. + * Try to force urgent data out on the wire. Even if we have unsent + * data this will at least send the urgent flag. * XXX does not handle more flag correctly. */ len += tcp->tcp_unsent; @@ -26734,6 +26732,14 @@ tcp_output_urgent(void *arg, mblk_t *mp, void *arg2) /* Bypass tcp protocol for fused tcp loopback */ if (tcp->tcp_fused && tcp_fuse_output(tcp, mp, msize)) return; + + /* Strip off the T_EXDATA_REQ if the data is from TPI */ + if (DB_TYPE(mp) != M_DATA) { + mblk_t *mp1 = mp; + ASSERT(!IPCL_IS_NONSTR(connp)); + mp = mp->b_cont; + freeb(mp1); + } tcp_wput_data(tcp, mp, B_TRUE); } @@ -26920,7 +26926,6 @@ tcp_fallback(sock_lower_handle_t proto_handle, queue_t *q, int error; mblk_t *stropt_mp; mblk_t *ordrel_mp; - mblk_t *fused_sigurp_mp; tcp = connp->conn_tcp; @@ -26935,9 +26940,6 @@ tcp_fallback(sock_lower_handle_t proto_handle, queue_t *q, ((struct T_ordrel_ind *)ordrel_mp->b_rptr)->PRIM_type = T_ORDREL_IND; ordrel_mp->b_wptr += sizeof (struct T_ordrel_ind); - /* Pre-allocate the M_PCSIG used by fusion */ - fused_sigurp_mp = allocb_wait(1, BPRI_HI, STR_NOSIG, NULL); - /* * Enter the squeue so that no new packets can come in */ @@ -26946,7 +26948,6 @@ tcp_fallback(sock_lower_handle_t proto_handle, queue_t *q, /* failed to enter, free all the pre-allocated messages. */ freeb(stropt_mp); freeb(ordrel_mp); - freeb(fused_sigurp_mp); /* * We cannot process the eager, so at least send out a * RST so the peer can reconnect. @@ -26959,19 +26960,19 @@ tcp_fallback(sock_lower_handle_t proto_handle, queue_t *q, } /* + * Both endpoints must be of the same type (either STREAMS or + * non-STREAMS) for fusion to be enabled. So if we are fused, + * we have to unfuse. + */ + if (tcp->tcp_fused) + tcp_unfuse(tcp); + + /* * No longer a direct socket */ connp->conn_flags &= ~IPCL_NONSTR; - tcp->tcp_ordrel_mp = ordrel_mp; - if (tcp->tcp_fused) { - ASSERT(tcp->tcp_fused_sigurg_mp == NULL); - tcp->tcp_fused_sigurg_mp = fused_sigurp_mp; - } else { - freeb(fused_sigurp_mp); - } - if (tcp->tcp_listener != NULL) { /* The eager will deal with opts when accept() is called */ freeb(stropt_mp); diff --git a/usr/src/uts/common/inet/tcp/tcp_fusion.c b/usr/src/uts/common/inet/tcp/tcp_fusion.c index 4e4802c063..c6af3564bc 100644 --- a/usr/src/uts/common/inet/tcp/tcp_fusion.c +++ b/usr/src/uts/common/inet/tcp/tcp_fusion.c @@ -226,15 +226,17 @@ tcp_fuse(tcp_t *tcp, uchar_t *iphdr, tcph_t *tcph) /* * We can only proceed if peer exists, resides in the same squeue - * as our conn and is not raw-socket. The squeue assignment of - * this eager tcp was done earlier at the time of SYN processing - * in ip_fanout_tcp{_v6}. Note that similar squeues by itself - * doesn't guarantee a safe condition to fuse, hence we perform + * as our conn and is not raw-socket. We also restrict fusion to + * endpoints of the same type (STREAMS or non-STREAMS). The squeue + * assignment of this eager tcp was done earlier at the time of SYN + * processing in ip_fanout_tcp{_v6}. Note that similar squeues by + * itself doesn't guarantee a safe condition to fuse, hence we perform * additional tests below. */ ASSERT(peer_connp == NULL || peer_connp != connp); if (peer_connp == NULL || peer_connp->conn_sqp != connp->conn_sqp || - !IPCL_IS_TCP(peer_connp)) { + !IPCL_IS_TCP(peer_connp) || + IPCL_IS_NONSTR(connp) != IPCL_IS_NONSTR(peer_connp)) { if (peer_connp != NULL) { TCP_STAT(tcps, tcp_fusion_unqualified); CONN_DEC_REF(peer_connp); @@ -289,23 +291,19 @@ tcp_fuse(tcp_t *tcp, uchar_t *iphdr, tcph_t *tcph) * endpoints which will only be used during/after unfuse. */ if (!IPCL_IS_NONSTR(tcp->tcp_connp)) { + ASSERT(!IPCL_IS_NONSTR(peer_tcp->tcp_connp)); + if ((mp = allocb(1, BPRI_HI)) == NULL) goto failed; - tcp->tcp_fused_sigurg_mp = mp; - } - if (!IPCL_IS_NONSTR(peer_tcp->tcp_connp)) { if ((mp = allocb(1, BPRI_HI)) == NULL) goto failed; - peer_tcp->tcp_fused_sigurg_mp = mp; - } - if (!IPCL_IS_NONSTR(peer_tcp->tcp_connp) && - (mp = allocb(sizeof (struct stroptions), - BPRI_HI)) == NULL) { - goto failed; + if ((mp = allocb(sizeof (struct stroptions), + BPRI_HI)) == NULL) + goto failed; } /* Fuse both endpoints */ @@ -458,8 +456,9 @@ tcp_unfuse(tcp_t *tcp) } /* - * Fusion output routine for urgent data. This routine is called by - * tcp_fuse_output() for handling non-M_DATA mblks. + * Fusion output routine used to handle urgent data sent by STREAMS based + * endpoints. This routine is called by tcp_fuse_output() for handling + * non-M_DATA mblks. */ void tcp_fuse_output_urg(tcp_t *tcp, mblk_t *mp) @@ -471,6 +470,7 @@ tcp_fuse_output_urg(tcp_t *tcp, mblk_t *mp) tcp_stack_t *tcps = tcp->tcp_tcps; ASSERT(tcp->tcp_fused); + ASSERT(!IPCL_IS_NONSTR(tcp->tcp_connp)); ASSERT(peer_tcp != NULL && peer_tcp->tcp_loopback_peer == tcp); ASSERT(DB_TYPE(mp) == M_PROTO || DB_TYPE(mp) == M_PCPROTO); ASSERT(mp->b_cont != NULL && DB_TYPE(mp->b_cont) == M_DATA); @@ -924,7 +924,8 @@ tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size) DTRACE_PROBE2(tcp__fuse__output, tcp_t *, tcp, uint_t, send_size); - if (!TCP_IS_DETACHED(peer_tcp)) { + if (!IPCL_IS_NONSTR(peer_tcp->tcp_connp) && + !TCP_IS_DETACHED(peer_tcp)) { /* * Drain the peer's receive queue it has urgent data or if * we're not flow-controlled. There is no need for draining @@ -932,8 +933,7 @@ tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size) * will pull the data via tcp_fuse_rrw(). */ if (urgent || (!flow_stopped && !peer_tcp->tcp_direct_sockfs)) { - ASSERT(IPCL_IS_NONSTR(peer_tcp->tcp_connp) || - peer_tcp->tcp_rcv_list != NULL); + ASSERT(peer_tcp->tcp_rcv_list != NULL); /* * For TLI-based streams, a thread in tcp_accept_swap() * can race with us. That thread will ensure that the @@ -995,41 +995,39 @@ tcp_fuse_rcv_drain(queue_t *q, tcp_t *tcp, mblk_t **sigurg_mpp) * works properly. */ if (tcp->tcp_fused_sigurg) { + ASSERT(!IPCL_IS_NONSTR(tcp->tcp_connp)); + tcp->tcp_fused_sigurg = B_FALSE; - if (IPCL_IS_NONSTR(connp)) { - (*connp->conn_upcalls->su_signal_oob) - (connp->conn_upper_handle, 0); - } else { + /* + * sigurg_mpp is normally NULL, i.e. when we're still + * fused and didn't get here because of tcp_unfuse(). + * In this case try hard to allocate the M_PCSIG mblk. + */ + if (sigurg_mpp == NULL && + (mp = allocb(1, BPRI_HI)) == NULL && + (mp = allocb_tryhard(1)) == NULL) { + /* Alloc failed; try again next time */ + tcp->tcp_push_tid = TCP_TIMER(tcp, + tcp_push_timer, + MSEC_TO_TICK( + tcps->tcps_push_timer_interval)); + return (B_TRUE); + } else if (sigurg_mpp != NULL) { /* - * sigurg_mpp is normally NULL, i.e. when we're still - * fused and didn't get here because of tcp_unfuse(). - * In this case try hard to allocate the M_PCSIG mblk. + * Use the supplied M_PCSIG mblk; it means we're + * either unfused or in the process of unfusing, + * and the drain must happen now. */ - if (sigurg_mpp == NULL && - (mp = allocb(1, BPRI_HI)) == NULL && - (mp = allocb_tryhard(1)) == NULL) { - /* Alloc failed; try again next time */ - tcp->tcp_push_tid = TCP_TIMER(tcp, - tcp_push_timer, - MSEC_TO_TICK( - tcps->tcps_push_timer_interval)); - return (B_TRUE); - } else if (sigurg_mpp != NULL) { - /* - * Use the supplied M_PCSIG mblk; it means we're - * either unfused or in the process of unfusing, - * and the drain must happen now. - */ - mp = *sigurg_mpp; - *sigurg_mpp = NULL; - } - ASSERT(mp != NULL); - - /* Send up the signal */ - DB_TYPE(mp) = M_PCSIG; - *mp->b_wptr++ = (uchar_t)SIGURG; - putnext(q, mp); + mp = *sigurg_mpp; + *sigurg_mpp = NULL; } + ASSERT(mp != NULL); + + /* Send up the signal */ + DB_TYPE(mp) = M_PCSIG; + *mp->b_wptr++ = (uchar_t)SIGURG; + putnext(q, mp); + /* * Let the regular tcp_rcv_drain() path handle * draining the data if we're no longer fused. |