- 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
This commit is contained in:
Vladislav Bolkhovitin
2009-01-29 18:25:45 +00:00
parent a03936f3bc
commit ba698dbdd5
5 changed files with 73 additions and 19 deletions

View File

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

View File

@@ -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 */

View File

@@ -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) {}

View File

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

View File

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