Fixes deadlock on iSCSI session freeing. Reported by andy yan <andyysj@gmail.com>
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Wed, 25 Mar 2009 13:03:29 +0000 (13:03 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Wed, 25 Mar 2009 13:03:29 +0000 (13:03 +0000)
git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@718 d57e44dd-8a1f-0410-8b47-8ef2f437770f

iscsi-scst/kernel/iscsi.h
iscsi-scst/kernel/nthread.c
iscsi-scst/kernel/session.c

index c0e0d77..ecd7dcf 100644 (file)
@@ -122,6 +122,7 @@ struct iscsi_session {
        struct iscsi_session *sess_reinst_successor;
        unsigned int sess_reinstating:1;
        unsigned int sess_shutting_down:1;
+       unsigned int deleted_from_session_list:1;
 
        /* All don't need any protection */
        char *initiator_name;
index 8b8a4f4..5cb1c67 100644 (file)
@@ -552,6 +552,17 @@ static void close_conn(struct iscsi_conn *conn)
 
        if (list_empty(&session->conn_list)) {
                sBUG_ON(session->sess_reinst_successor != NULL);
+
+               list_del(&session->session_list_entry);
+               session->deleted_from_session_list = 1;
+
+               mutex_unlock(&target->target_mutex);
+               if (session->scst_sess != NULL) {
+                       scst_unregister_session(session->scst_sess, 1, NULL);
+                       session->scst_sess = NULL;
+               }
+               mutex_lock(&target->target_mutex);
+
                session_free(session);
        }
 
index 39e05c6..6a54100 100644 (file)
@@ -215,8 +215,7 @@ int session_free(struct iscsi_session *session)
        for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++)
                sBUG_ON(!list_empty(&session->cmnd_hash[i]));
 
-       if (session->scst_sess != NULL)
-               scst_unregister_session(session->scst_sess, 1, NULL);
+       sBUG_ON(session->scst_sess != NULL);
 
        if (session->sess_reinst_successor != NULL)
                sess_enable_reinstated_sess(session->sess_reinst_successor);
@@ -233,7 +232,8 @@ int session_free(struct iscsi_session *session)
                }
        }
 
-       list_del(&session->session_list_entry);
+       if (!session->deleted_from_session_list)
+               list_del(&session->session_list_entry);
 
        kfree(session->initiator_name);
        kfree(session);
@@ -267,10 +267,10 @@ 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:%llx initiator:%s reinstating %d\n",
+               seq_printf(seq, "\tsid:%llx initiator:%s (reinstating %s)\n",
                        (long long unsigned int)session->sid,
                        session->initiator_name,
-                       session->sess_reinstating);
+                       session->sess_reinstating ? "yes" : "no");
                conn_info_show(seq, session);
        }
        return;