From ba698dbdd5ee681fb4498775f30ecc945914c89a Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 29 Jan 2009 18:25:45 +0000 Subject: [PATCH] - Fix for iSCSI RFC violation: TARGET COLD RESET must close all connections/sessions, not only the current one - Cleanups git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@648 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/iscsi.c | 39 ++++++++++++++++++++++++++++++------- iscsi-scst/kernel/iscsi.h | 2 ++ iscsi-scst/kernel/nthread.c | 10 ++++++++++ iscsi-scst/kernel/session.c | 3 ++- iscsi-scst/kernel/target.c | 38 +++++++++++++++++++++++++----------- 5 files changed, 73 insertions(+), 19 deletions(-) diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index 64a38d920..d2eb2b75b 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -100,6 +100,7 @@ static inline void iscsi_restart_cmnd(struct iscsi_cmnd *cmnd) cmnd->scst_state = ISCSI_CMD_STATE_RESTARTED; scst_restart_cmd(cmnd->scst_cmd, SCST_PREPROCESS_STATUS_SUCCESS, SCST_CONTEXT_THREAD); + return; } static inline void iscsi_restart_waiting_cmnd(struct iscsi_cmnd *cmnd) @@ -112,6 +113,7 @@ static inline void iscsi_restart_waiting_cmnd(struct iscsi_cmnd *cmnd) cmnd->data_waiting = 0; iscsi_restart_cmnd(cmnd); + return; } static inline void iscsi_fail_waiting_cmnd(struct iscsi_cmnd *cmnd) @@ -758,6 +760,7 @@ static void iscsi_cmnd_reject(struct iscsi_cmnd *req, int reason) ISCSI_INIT_WRITE_WAKE); cmnd_prepare_get_rejected_cmd_data(req); + return; } static inline int iscsi_get_allowed_cmds(struct iscsi_session *sess) @@ -802,6 +805,7 @@ static void __update_stat_sn(struct iscsi_cmnd *cmnd) /* free pdu resources */ cmnd->conn->exp_stat_sn = exp_stat_sn; } + return; } static inline void update_stat_sn(struct iscsi_cmnd *cmnd) @@ -809,6 +813,7 @@ static inline void update_stat_sn(struct iscsi_cmnd *cmnd) spin_lock(&cmnd->conn->session->sn_lock); __update_stat_sn(cmnd); spin_unlock(&cmnd->conn->session->sn_lock); + return; } /* Called under sn_lock */ @@ -932,6 +937,7 @@ static void cmnd_remove_hash(struct iscsi_cmnd *cmnd) } spin_unlock(&session->cmnd_hash_lock); + return; } static void cmnd_prepare_get_rejected_cmd_data(struct iscsi_cmnd *cmnd) @@ -1997,6 +2003,7 @@ static void noop_out_exec(struct iscsi_cmnd *req) req_cmnd_release(req); } else cmnd_put(req); + return; } static void logout_exec(struct iscsi_cmnd *req) @@ -2019,6 +2026,7 @@ static void logout_exec(struct iscsi_cmnd *req) iscsi_cmnd_init_write(rsp, ISCSI_INIT_WRITE_REMOVE_HASH | ISCSI_INIT_WRITE_WAKE); req_cmnd_release(req); + return; } static void iscsi_cmnd_exec(struct iscsi_cmnd *cmnd) @@ -2094,6 +2102,7 @@ static void __cmnd_send_pdu(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd, conn->write_offset = offset; conn->write_size += size; + return; } static void cmnd_send_pdu(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) @@ -2107,6 +2116,7 @@ static void cmnd_send_pdu(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) sBUG_ON(cmnd->sg == NULL); sBUG_ON(cmnd->bufflen != size); __cmnd_send_pdu(conn, cmnd, 0, size); + return; } /* @@ -2125,6 +2135,7 @@ static void set_cork(struct socket *sock, int on) sock->ops->setsockopt(sock, SOL_TCP, TCP_CORK, (void __force __user *)&opt, sizeof(opt)); set_fs(oldfs); + return; } void cmnd_tx_start(struct iscsi_cmnd *cmnd) @@ -2190,14 +2201,16 @@ void cmnd_tx_start(struct iscsi_cmnd *cmnd) /* move this? */ conn->write_size = (conn->write_size + 3) & -4; iscsi_dump_pdu(&cmnd->pdu); + return; } void cmnd_tx_end(struct iscsi_cmnd *cmnd) { struct iscsi_conn *conn = cmnd->conn; - TRACE_DBG("%p:%x (should_close_conn %d)", cmnd, cmnd_opcode(cmnd), - cmnd->should_close_conn); + TRACE_DBG("%p:%x (should_close_conn %d, should_close_all_conn %d)", + cmnd, cmnd_opcode(cmnd), cmnd->should_close_conn, + cmnd->should_close_all_conn); switch (cmnd_opcode(cmnd)) { case ISCSI_OP_NOOP_IN: @@ -2216,13 +2229,22 @@ void cmnd_tx_end(struct iscsi_cmnd *cmnd) break; } - if (cmnd->should_close_conn) { - PRINT_INFO("Closing connection at initiator %s request", - conn->session->initiator_name); - mark_conn_closed(conn); + if (unlikely(cmnd->should_close_conn)) { + if (cmnd->should_close_all_conn) { + PRINT_INFO("Closing all connections for target %x at " + "initiator's %s request", + cmnd->conn->session->target->tid, + conn->session->initiator_name); + target_del_all_sess(cmnd->conn->session->target, false); + } else { + PRINT_INFO("Closing connection at initiator's %s " + "request", conn->session->initiator_name); + mark_conn_closed(conn); + } } set_cork(cmnd->conn->sock, 0); + return; } /* @@ -2807,8 +2829,10 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status) rsp_hdr->itt = req_hdr->itt; rsp_hdr->response = status; - if (fn == ISCSI_FUNCTION_TARGET_COLD_RESET) + if (fn == ISCSI_FUNCTION_TARGET_COLD_RESET) { rsp->should_close_conn = 1; + rsp->should_close_all_conn = 1; + } sBUG_ON(sess->tm_rsp != NULL); @@ -2946,6 +2970,7 @@ static void iscsi_stop_threads(void) list_del(&t->threads_list_entry); kfree(t); } + return; } static int __init iscsi_init(void) diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index 750db9cd8..fbfca4f0b 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -261,6 +261,7 @@ struct iscsi_cmnd { */ unsigned int hashed:1; unsigned int should_close_conn:1; + unsigned int should_close_all_conn:1; unsigned int pending:1; unsigned int own_sg:1; unsigned int on_write_list:1; @@ -391,6 +392,7 @@ extern int istwr(void *arg); struct iscsi_target *target_lookup_by_id(u32); extern int target_add(struct target_info *); extern int target_del(u32 id); +extern void target_del_all_sess(struct iscsi_target *target, bool deleting); extern void target_del_all(void); /* config.c */ diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 410996342..9ce66ef78 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -219,6 +219,7 @@ static void free_pending_commands(struct iscsi_conn *conn) } } while (req_freed); spin_unlock(&session->sn_lock); + return; } static void free_orphaned_pending_commands(struct iscsi_conn *conn) @@ -257,6 +258,7 @@ static void free_orphaned_pending_commands(struct iscsi_conn *conn) } } while (req_freed); spin_unlock(&session->sn_lock); + return; } #ifdef CONFIG_SCST_DEBUG @@ -323,6 +325,7 @@ static void trace_conn_close(struct iscsi_conn *conn) #endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */ } spin_unlock_bh(&conn->cmd_list_lock); + return; } #else /* CONFIG_SCST_DEBUG */ static void trace_conn_close(struct iscsi_conn *conn) {} @@ -545,6 +548,7 @@ static inline void iscsi_conn_init_read(struct iscsi_conn *conn, conn->read_msg.msg_iov = conn->read_iov; conn->read_msg.msg_iovlen = 1; conn->read_size = (len + 3) & -4; + return; } static void iscsi_conn_read_ahs(struct iscsi_conn *conn, @@ -555,6 +559,7 @@ static void iscsi_conn_read_ahs(struct iscsi_conn *conn, sBUG_ON(cmnd->pdu.ahs == NULL); iscsi_conn_init_read(conn, (void __force __user *)cmnd->pdu.ahs, cmnd->pdu.ahssize); + return; } static struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn) @@ -923,6 +928,7 @@ static inline void __iscsi_get_page_callback(struct iscsi_cmnd *cmd) TRACE_NET_PAGE("getting cmd %p", cmd); cmnd_get(cmd); } + return; } void iscsi_get_page_callback(struct page *page) @@ -933,6 +939,7 @@ void iscsi_get_page_callback(struct page *page) atomic_read(&page->_count)); __iscsi_get_page_callback(cmd); + return; } static inline void __iscsi_put_page_callback(struct iscsi_cmnd *cmd) @@ -950,6 +957,7 @@ static inline void __iscsi_put_page_callback(struct iscsi_cmnd *cmd) } cmnd_put(cmd); } + return; } void iscsi_put_page_callback(struct page *page) @@ -960,6 +968,7 @@ void iscsi_put_page_callback(struct page *page) atomic_read(&page->_count)); __iscsi_put_page_callback(cmd); + return; } static void check_net_priv(struct iscsi_cmnd *cmd, struct page *page) @@ -969,6 +978,7 @@ static void check_net_priv(struct iscsi_cmnd *cmd, struct page *page) "%p (page %p)", page->net_priv, page); page->net_priv = NULL; } + return; } #else static inline void check_net_priv(struct iscsi_cmnd *cmd, struct page *page) {} diff --git a/iscsi-scst/kernel/session.c b/iscsi-scst/kernel/session.c index 8ada3f4f1..0e3ef40e7 100644 --- a/iscsi-scst/kernel/session.c +++ b/iscsi-scst/kernel/session.c @@ -183,12 +183,13 @@ static void iscsi_session_info_show(struct seq_file *seq, list_for_each_entry(session, &target->session_list, session_list_entry) { - seq_printf(seq, "\tsid:%llu initiator:%s shutting down %d\n", + seq_printf(seq, "\tsid:%llx initiator:%s shutting down %d\n", (long long unsigned int)session->sid, session->initiator_name, session->shutting_down); conn_info_show(seq, session); } + return; } static int iscsi_sessions_info_show(struct seq_file *seq, void *v) diff --git a/iscsi-scst/kernel/target.c b/iscsi-scst/kernel/target.c index dd1648ee5..278dcdff8 100644 --- a/iscsi-scst/kernel/target.c +++ b/iscsi-scst/kernel/target.c @@ -216,16 +216,20 @@ out: } static void target_del_session(struct iscsi_target *target, - struct iscsi_session *session) + struct iscsi_session *session, bool deleting) { + int flags = ISCSI_CONN_ACTIVE_CLOSE; + + if (deleting) + flags |= ISCSI_CONN_DELETING; + TRACE_MGMT_DBG("Cleaning up session %p", session); if (!list_empty(&session->conn_list)) { struct iscsi_conn *conn, *tc; list_for_each_entry_safe(conn, tc, &session->conn_list, conn_list_entry) { TRACE_MGMT_DBG("Mark conn %p closing", conn); - __mark_conn_closed(conn, - ISCSI_CONN_ACTIVE_CLOSE|ISCSI_CONN_DELETING); + __mark_conn_closed(conn, flags); } } else { TRACE_MGMT_DBG("Freeing session %p without connections", @@ -234,6 +238,25 @@ static void target_del_session(struct iscsi_target *target, } } +/* target_mutex supposed to be locked */ +void target_del_all_sess(struct iscsi_target *target, bool deleting) +{ + struct iscsi_session *session, *ts; + + TRACE_ENTRY(); + + if (!list_empty(&target->session_list)) { + TRACE_MGMT_DBG("Deleting all sessions from target %p", target); + list_for_each_entry_safe(session, ts, &target->session_list, + session_list_entry) { + target_del_session(target, session, deleting); + } + } + + TRACE_EXIT(); + return; +} + void target_del_all(void) { struct iscsi_target *target, *t; @@ -251,16 +274,9 @@ void target_del_all(void) list_for_each_entry_safe(target, t, &target_list, target_list_entry) { - struct iscsi_session *session, *ts; mutex_lock(&target->target_mutex); if (!list_empty(&target->session_list)) { - TRACE_MGMT_DBG("Cleaning up target %p", - target); - list_for_each_entry_safe(session, ts, - &target->session_list, - session_list_entry) { - target_del_session(target, session); - } + target_del_all_sess(target, true); mutex_unlock(&target->target_mutex); } else { TRACE_MGMT_DBG("Deleting target %p", target);