- 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
This commit is contained in:
Vladislav Bolkhovitin
2007-11-15 16:12:08 +00:00
parent 93e0f56a01
commit fb3a9201cc
3 changed files with 83 additions and 5 deletions

View File

@@ -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" },

View File

@@ -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) \

View File

@@ -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);