From de7ee9a20c7f617cbc5091e84855afcdeb19ba60 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 5 Jan 2016 14:47:58 +0100 Subject: [PATCH] tcm_fc: Wait for command completion before freeing a session This patch avoids that the following kernel crash can occur with later patches in this patch series: general protection fault: 0000 [#1] SMP CPU: 0 PID: 6 Comm: kworker/u8:0 Not tainted 4.3.0-rc1-debug+ #1 Workqueue: tmr-fileio target_tmr_work [target_core_mod] Call Trace: [] lock_acquire+0x65/0x90 [] _raw_spin_lock_irqsave+0x4b/0x60 [] target_release_cmd_kref+0x2a/0xa0 [target_core_mod] [] target_put_sess_cmd+0x28/0x50 [target_core_mod] [] core_tmr_lun_reset+0x390/0x640 [target_core_mod] [] target_tmr_work+0x80/0xd0 [target_core_mod] [] process_one_work+0x19d/0x430 [] worker_thread+0x10f/0x460 [] kthread+0xea/0x100 [] ret_from_fork+0x3f/0x70 Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tfc_sess.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 7b934eac995d..45947e2b6512 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -260,6 +260,14 @@ static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id) return NULL; } +static void ft_close_sess(struct ft_sess *sess) +{ + transport_deregister_session_configfs(sess->se_sess); + target_sess_cmd_list_set_waiting(sess->se_sess); + target_wait_for_sess_cmds(sess->se_sess); + ft_sess_put(sess); +} + /* * Delete all sessions from tport. * Caller holds ft_lport_lock. @@ -273,8 +281,7 @@ static void ft_sess_delete_all(struct ft_tport *tport) head < &tport->hash[FT_SESS_HASH_SIZE]; head++) { hlist_for_each_entry_rcu(sess, head, hash) { ft_sess_unhash(sess); - transport_deregister_session_configfs(sess->se_sess); - ft_sess_put(sess); /* release from table */ + ft_close_sess(sess); /* release from table */ } } } @@ -313,8 +320,7 @@ void ft_sess_close(struct se_session *se_sess) pr_debug("port_id %x\n", port_id); ft_sess_unhash(sess); mutex_unlock(&ft_lport_lock); - transport_deregister_session_configfs(se_sess); - ft_sess_put(sess); + ft_close_sess(sess); /* XXX Send LOGO or PRLO */ synchronize_rcu(); /* let transport deregister happen */ } @@ -460,8 +466,7 @@ static void ft_prlo(struct fc_rport_priv *rdata) return; } mutex_unlock(&ft_lport_lock); - transport_deregister_session_configfs(sess->se_sess); - ft_sess_put(sess); /* release from table */ + ft_close_sess(sess); /* release from table */ rdata->prli_count--; /* XXX TBD - clearing actions. unit attn, see 4.10 */ } -- 2.25.1