diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2006-05-02 20:46:40 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-05-10 11:12:04 -0400 |
commit | ed2abc7ff19dc99c6242a70f8578a17b2ff0d0ce (patch) | |
tree | 3bf226387f002ee6c67619afd1a950e1d0bde30f /drivers/scsi | |
parent | 264faaaa12544e7914928ad57ccba21907cad56b (diff) |
[SCSI] iscsi: fix manamgement task oops
from patmans@us.ibm.com and michaelc@cs.wisc.edu
Fix bugs when forcing a mgmt task to fail and allow
session recovery to cleanup the session/connection
of any running mgmt tasks. When called during
the in login state.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libiscsi.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 274a1374ab64..8c51f6c36661 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -1538,10 +1538,11 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) | |||
1538 | /* handle running */ | 1538 | /* handle running */ |
1539 | list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { | 1539 | list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { |
1540 | debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); | 1540 | debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); |
1541 | list_del(&mtask->running); | ||
1542 | |||
1541 | if (mtask == conn->login_mtask) | 1543 | if (mtask == conn->login_mtask) |
1542 | continue; | 1544 | continue; |
1543 | list_del(&mtask->running); | 1545 | __kfifo_put(session->mgmtpool.queue, (void*)&mtask, |
1544 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask, | ||
1545 | sizeof(void*)); | 1546 | sizeof(void*)); |
1546 | } | 1547 | } |
1547 | 1548 | ||
@@ -1573,12 +1574,22 @@ static void fail_all_commands(struct iscsi_conn *conn) | |||
1573 | void iscsi_start_session_recovery(struct iscsi_session *session, | 1574 | void iscsi_start_session_recovery(struct iscsi_session *session, |
1574 | struct iscsi_conn *conn, int flag) | 1575 | struct iscsi_conn *conn, int flag) |
1575 | { | 1576 | { |
1577 | int old_stop_stage; | ||
1578 | |||
1576 | spin_lock_bh(&session->lock); | 1579 | spin_lock_bh(&session->lock); |
1577 | if (conn->stop_stage == STOP_CONN_RECOVER || | 1580 | if (conn->stop_stage == STOP_CONN_TERM) { |
1578 | conn->stop_stage == STOP_CONN_TERM) { | ||
1579 | spin_unlock_bh(&session->lock); | 1581 | spin_unlock_bh(&session->lock); |
1580 | return; | 1582 | return; |
1581 | } | 1583 | } |
1584 | |||
1585 | /* | ||
1586 | * When this is called for the in_login state, we only want to clean | ||
1587 | * up the login task and connection. | ||
1588 | */ | ||
1589 | if (conn->stop_stage != STOP_CONN_RECOVER) | ||
1590 | session->conn_cnt--; | ||
1591 | |||
1592 | old_stop_stage = conn->stop_stage; | ||
1582 | conn->stop_stage = flag; | 1593 | conn->stop_stage = flag; |
1583 | spin_unlock_bh(&session->lock); | 1594 | spin_unlock_bh(&session->lock); |
1584 | 1595 | ||
@@ -1590,7 +1601,6 @@ void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1590 | conn->c_stage = ISCSI_CONN_STOPPED; | 1601 | conn->c_stage = ISCSI_CONN_STOPPED; |
1591 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | 1602 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
1592 | 1603 | ||
1593 | session->conn_cnt--; | ||
1594 | if (session->conn_cnt == 0 || session->leadconn == conn) | 1604 | if (session->conn_cnt == 0 || session->leadconn == conn) |
1595 | session->state = ISCSI_STATE_FAILED; | 1605 | session->state = ISCSI_STATE_FAILED; |
1596 | 1606 | ||
@@ -1615,7 +1625,12 @@ void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1615 | conn->hdrdgst_en = 0; | 1625 | conn->hdrdgst_en = 0; |
1616 | conn->datadgst_en = 0; | 1626 | conn->datadgst_en = 0; |
1617 | 1627 | ||
1618 | if (session->state == ISCSI_STATE_FAILED) | 1628 | /* |
1629 | * if this is called from the eh and and from userspace | ||
1630 | * then we only need to block once. | ||
1631 | */ | ||
1632 | if (session->state == ISCSI_STATE_FAILED && | ||
1633 | old_stop_stage != STOP_CONN_RECOVER) | ||
1619 | iscsi_block_session(session_to_cls(session)); | 1634 | iscsi_block_session(session_to_cls(session)); |
1620 | } | 1635 | } |
1621 | mutex_unlock(&conn->xmitmutex); | 1636 | mutex_unlock(&conn->xmitmutex); |