cxgbei: Wait for the final CPL to be received in icl_cxgbei_conn_close.
A socket in the FIN_WAIT_1 state is marked disconnected by do_close_con_rpl() even though there might still receive data pending. This is because the socket at that point has set SBS_CANTRCVMORE which causes the protocol layer to discard any data received before the FIN. However, icl_cxgbei_conn_close needs to wait until all the data has been discarded. Replace the wait for SS_ISDISCONNECTED with instead waiting for final_cpl_received() to be called. Reported by: Jithesh Arakkan @ Chelsio Sponsored by: Chelsio Communications
This commit is contained in:
parent
95941b9636
commit
2eb0e53a6b
@ -947,6 +947,18 @@ icl_cxgbei_conn_close(struct icl_conn *ic)
|
||||
icl_cxgbei_pdu_done(ip, ENOTCONN);
|
||||
}
|
||||
SOCKBUF_UNLOCK(sb);
|
||||
|
||||
/*
|
||||
* Grab a reference to use when waiting for the final
|
||||
* CPL to be received. If toep->inp is NULL, then
|
||||
* final_cpl_received() has already been called (e.g.
|
||||
* due to the peer sending a RST).
|
||||
*/
|
||||
if (toep->inp != NULL) {
|
||||
toep = hold_toepcb(toep);
|
||||
toep->flags |= TPF_WAITING_FOR_FINAL;
|
||||
} else
|
||||
toep = NULL;
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
|
||||
@ -959,7 +971,6 @@ icl_cxgbei_conn_close(struct icl_conn *ic)
|
||||
* queues were purged instead of delivered reliably but soabort isn't
|
||||
* really general purpose and wouldn't do the right thing here.
|
||||
*/
|
||||
soref(so);
|
||||
soclose(so);
|
||||
|
||||
/*
|
||||
@ -969,12 +980,15 @@ icl_cxgbei_conn_close(struct icl_conn *ic)
|
||||
* Callers assume that it is safe to free buffers for tasks
|
||||
* and transfers after this function returns.
|
||||
*/
|
||||
SOCK_LOCK(so);
|
||||
while ((so->so_state & SS_ISDISCONNECTED) == 0)
|
||||
mtx_sleep(&so->so_timeo, SOCK_MTX(so), PSOCK, "conclo2", 0);
|
||||
CURVNET_SET(so->so_vnet);
|
||||
sorele(so);
|
||||
CURVNET_RESTORE();
|
||||
if (toep != NULL) {
|
||||
struct mtx *lock = mtx_pool_find(mtxpool_sleep, toep);
|
||||
|
||||
mtx_lock(lock);
|
||||
while ((toep->flags & TPF_WAITING_FOR_FINAL) != 0)
|
||||
mtx_sleep(toep, lock, PSOCK, "conclo2", 0);
|
||||
mtx_unlock(lock);
|
||||
free_toepcb(toep);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1008,6 +1008,7 @@ void
|
||||
final_cpl_received(struct toepcb *toep)
|
||||
{
|
||||
struct inpcb *inp = toep->inp;
|
||||
bool need_wakeup;
|
||||
|
||||
KASSERT(inp != NULL, ("%s: inp is NULL", __func__));
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
@ -1022,7 +1023,8 @@ final_cpl_received(struct toepcb *toep)
|
||||
else if (ulp_mode(toep) == ULP_MODE_TLS)
|
||||
tls_detach(toep);
|
||||
toep->inp = NULL;
|
||||
toep->flags &= ~TPF_CPL_PENDING;
|
||||
need_wakeup = (toep->flags & TPF_WAITING_FOR_FINAL) != 0;
|
||||
toep->flags &= ~(TPF_CPL_PENDING | TPF_WAITING_FOR_FINAL);
|
||||
mbufq_drain(&toep->ulp_pduq);
|
||||
mbufq_drain(&toep->ulp_pdu_reclaimq);
|
||||
|
||||
@ -1031,6 +1033,14 @@ final_cpl_received(struct toepcb *toep)
|
||||
|
||||
if (!in_pcbrele_wlocked(inp))
|
||||
INP_WUNLOCK(inp);
|
||||
|
||||
if (need_wakeup) {
|
||||
struct mtx *lock = mtx_pool_find(mtxpool_sleep, toep);
|
||||
|
||||
mtx_lock(lock);
|
||||
wakeup(toep);
|
||||
mtx_unlock(lock);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -76,6 +76,7 @@ enum {
|
||||
TPF_INITIALIZED = (1 << 12), /* init_toepcb has been called */
|
||||
TPF_TLS_RECEIVE = (1 << 13), /* should receive TLS records */
|
||||
TPF_TLS_ESTABLISHED = (1 << 14), /* TLS handshake timer initialized */
|
||||
TPF_WAITING_FOR_FINAL = (1<< 15), /* waiting for wakeup on final CPL */
|
||||
};
|
||||
|
||||
enum {
|
||||
|
Loading…
x
Reference in New Issue
Block a user