From fb3a9201cc6c151e23d2763efe24db7654100687 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 15 Nov 2007 16:12:08 +0000 Subject: [PATCH] - Fixes hang in TCP CLOSE/CLOSE_WAIT stages - Minor debug improvements git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@223 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/config.c | 1 + iscsi-scst/kernel/iscsi_dbg.h | 15 ++++++++ iscsi-scst/kernel/nthread.c | 72 ++++++++++++++++++++++++++++++++--- 3 files changed, 83 insertions(+), 5 deletions(-) diff --git a/iscsi-scst/kernel/config.c b/iscsi-scst/kernel/config.c index 24d2a3bf0..efda41c4f 100644 --- a/iscsi-scst/kernel/config.c +++ b/iscsi-scst/kernel/config.c @@ -30,6 +30,7 @@ static struct scst_proc_log iscsi_proc_local_trace_tbl[] = { TRACE_D_READ, "d_read" }, { TRACE_D_WRITE, "d_write" }, { TRACE_CONN_OC, "conn" }, + { TRACE_CONN_OC_DBG, "conn_dbg" }, { TRACE_D_IOV, "iov" }, { TRACE_D_DUMP_PDU, "pdu" }, { TRACE_NET_PG, "net_page" }, diff --git a/iscsi-scst/kernel/iscsi_dbg.h b/iscsi-scst/kernel/iscsi_dbg.h index 689d350c1..1f20d00df 100644 --- a/iscsi-scst/kernel/iscsi_dbg.h +++ b/iscsi-scst/kernel/iscsi_dbg.h @@ -26,6 +26,7 @@ #define TRACE_D_IOV 0x10000000 #define TRACE_D_DUMP_PDU 0x08000000 #define TRACE_NET_PG 0x04000000 +#define TRACE_CONN_OC_DBG 0x02000000 #define TRACE_D_DATA (TRACE_D_READ | TRACE_D_WRITE) @@ -68,6 +69,20 @@ do { \ } \ } while(0) +#define TRACE_CONN_CLOSE_DBG(format, args...) \ +do { \ + if (trace_flag & TRACE_CONN_OC_DBG) \ + { \ + char *__tflag = LOG_FLAG; \ + if (debug_print_prefix(trace_flag, LOG_PREFIX, __FUNCTION__, \ + __LINE__) > 0) \ + { \ + __tflag = NO_FLAG; \ + } \ + PRINT(NO_FLAG, "%s" format, __tflag, args); \ + } \ +} while(0) + #define TRACE_NET_PAGE(format, args...) \ do { \ if (trace_flag & TRACE_NET_PG) \ diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 429357416..2a55abe6c 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -54,6 +54,67 @@ enum tx_state { TX_END, }; +#if defined(NET_PAGE_CALLBACKS_DEFINED) +static void iscsi_check_closewait(struct iscsi_conn *conn) +{ + struct iscsi_cmnd *cmnd; + + TRACE_ENTRY(); + + if ((conn->sock->sk->sk_state != TCP_CLOSE_WAIT) && + (conn->sock->sk->sk_state != TCP_CLOSE)) { + TRACE_CONN_CLOSE_DBG("sk_state %d, skipping", + conn->sock->sk->sk_state); + goto out; + } + + /* + * No data are going to be sent, so all being sent buffers can be freed + * now. Strange that TCP doesn't do that itself. + */ + +again: + spin_lock_bh(&conn->cmd_list_lock); + list_for_each_entry(cmnd, &conn->cmd_list, cmd_list_entry) { + TRACE_CONN_CLOSE_DBG("cmd %p, scst_state %x, data_waiting %d, " + "ref_cnt %d, parent_req %p, net_ref_cnt %d, sg %p", + cmnd, cmnd->scst_state, cmnd->data_waiting, + atomic_read(&cmnd->ref_cnt), cmnd->parent_req, + atomic_read(&cmnd->net_ref_cnt), cmnd->sg); + sBUG_ON(cmnd->parent_req != NULL); + if (cmnd->sg != NULL) { + int sg_cnt, i, restart = 0; + sg_cnt = get_pgcnt(cmnd->bufflen, + cmnd->sg[0].offset); + cmnd_get(cmnd); + for(i = 0; i < sg_cnt; i++) { + TRACE_CONN_CLOSE_DBG("page %p, net_priv %p, _count %d", + cmnd->sg[i].page, cmnd->sg[i].page->net_priv, + atomic_read(&cmnd->sg[i].page->_count)); + if (cmnd->sg[i].page->net_priv != NULL) { + if (restart == 0) { + spin_unlock_bh(&conn->cmd_list_lock); + restart = 1; + } + while(cmnd->sg[i].page->net_priv != NULL) + iscsi_put_page_callback(cmnd->sg[i].page); + } + } + cmnd_put(cmnd); + if (restart) + goto again; + } + } + spin_unlock_bh(&conn->cmd_list_lock); + +out: + TRACE_EXIT(); + return; +} +#else +static inline void iscsi_check_closewait(struct iscsi_conn *conn) {}; +#endif + /* No locks */ static void close_conn(struct iscsi_conn *conn) { @@ -114,19 +175,19 @@ static void close_conn(struct iscsi_conn *conn) #endif spin_lock_bh(&conn->cmd_list_lock); list_for_each_entry(cmnd, &conn->cmd_list, cmd_list_entry) { - TRACE_DBG("cmd %p, scst_state %x, data_waiting " + TRACE_CONN_CLOSE_DBG("cmd %p, scst_state %x, data_waiting " "%d, ref_cnt %d, parent_req %p", cmnd, cmnd->scst_state, cmnd->data_waiting, atomic_read(&cmnd->ref_cnt), cmnd->parent_req); #ifdef NET_PAGE_CALLBACKS_DEFINED - TRACE_DBG("net_ref_cnt %d, sg %p", + TRACE_CONN_CLOSE_DBG("net_ref_cnt %d, sg %p", atomic_read(&cmnd->net_ref_cnt), cmnd->sg); if (cmnd->sg != NULL) { int sg_cnt, i; sg_cnt = get_pgcnt(cmnd->bufflen, cmnd->sg[0].offset); for(i = 0; i < sg_cnt; i++) { - TRACE_DBG("page %p, net_priv %p, _count %d", + TRACE_CONN_CLOSE_DBG("page %p, net_priv %p, _count %d", cmnd->sg[i].page, cmnd->sg[i].page->net_priv, atomic_read(&cmnd->sg[i].page->_count)); } @@ -136,7 +197,7 @@ static void close_conn(struct iscsi_conn *conn) spin_lock_bh(&cmnd->rsp_cmd_lock); list_for_each_entry(rsp, &cmnd->rsp_cmd_list, rsp_cmd_list_entry) { - TRACE_DBG(" rsp %p, ref_cnt %d, net_ref_cnt %d, " + TRACE_CONN_CLOSE_DBG(" rsp %p, ref_cnt %d, net_ref_cnt %d, " "sg %p", rsp, atomic_read(&rsp->ref_cnt), atomic_read(&rsp->net_ref_cnt), rsp->sg); if ((rsp->sg != cmnd->sg) && (rsp->sg != NULL)) { @@ -145,7 +206,7 @@ static void close_conn(struct iscsi_conn *conn) rsp->sg[0].offset); sBUG_ON(rsp->sg_cnt != sg_cnt); for(i = 0; i < sg_cnt; i++) { - TRACE_DBG(" page %p, net_priv %p, " + TRACE_CONN_CLOSE_DBG(" page %p, net_priv %p, " "_count %d", rsp->sg[i].page, rsp->sg[i].page->net_priv, atomic_read(&rsp->sg[i].page->_count)); @@ -158,6 +219,7 @@ static void close_conn(struct iscsi_conn *conn) spin_unlock_bh(&conn->cmd_list_lock); } #endif + iscsi_check_closewait(conn); } write_lock_bh(&conn->sock->sk->sk_callback_lock);