--- /dev/null
+From: Mike Christie <michaelc@cs.wisc.edu>
+Date: Tue, 28 Apr 2009 13:38:18 -0400
+Subject: libiscsi: fix nop response/reply and session cleanup race
+References: bnc#499558
+
+If we are responding to a nop from the target by sending our nop,
+and the session is getting torn down, then iscsi_start_session_recovery
+could set the conn stop bits while the recv path is sending the nop
+response and we will hit the bug ons in __iscsi_conn_send_pdu.
+
+This has us check the state in __iscsi_conn_send_pdu and fail all
+incoming mgmt IO if we are not logged in and if the pdu is not login
+related. It also changes the ordering of the setting of conn stop state
+bits so they are set after the session state is set (both are set under
+the session lock).
+
+Acked-by: Jean Delvare <jdelvare@suse.de>
+---
+ drivers/scsi/libiscsi.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -502,6 +502,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn
+ */
+ task = conn->login_task;
+ else {
++ if (session->state != ISCSI_STATE_LOGGED_IN)
++ return NULL;
++
+ BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
+ BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
+
+@@ -2414,8 +2417,6 @@ static void iscsi_start_session_recovery
+ {
+ int old_stop_stage;
+
+- del_timer_sync(&conn->transport_timer);
+-
+ mutex_lock(&session->eh_mutex);
+ spin_lock_bh(&session->lock);
+ if (conn->stop_stage == STOP_CONN_TERM) {
+@@ -2433,13 +2434,17 @@ static void iscsi_start_session_recovery
+ session->state = ISCSI_STATE_TERMINATE;
+ else if (conn->stop_stage != STOP_CONN_RECOVER)
+ session->state = ISCSI_STATE_IN_RECOVERY;
++ spin_unlock_bh(&session->lock);
+
++ del_timer_sync(&conn->transport_timer);
++ iscsi_suspend_tx(conn);
++
++ spin_lock_bh(&session->lock);
+ old_stop_stage = conn->stop_stage;
+ conn->stop_stage = flag;
+ conn->c_stage = ISCSI_CONN_STOPPED;
+ spin_unlock_bh(&session->lock);
+
+- iscsi_suspend_tx(conn);
+ /*
+ * for connection level recovery we should not calculate
+ * header digest. conn->hdr_size used for optimization