From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> This patch converts core_tpg_del_initiator_node_acl() shutdown from configfs context to use se_node_acl->acl_kref and ->acl_free_comp in order to wait for outstanding fabric callbacks to complete via transport_deregister_session() callbacks before waking ->acl_free_comp from the last ->acl_kref put. It also changes core_tpg_del_initiator_node_acl() to setup a local sess_list with target_get_session() + acl->acl_stop = 1 for active sessions that will be shutdown, and changes transport_deregister_session_configfs() to check for ->acl_stop usage. Signed-off-by: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> --- drivers/target/target_core_tpg.c | 31 ++++++++++++++++++++----------- drivers/target/target_core_transport.c | 3 ++- include/target/target_core_base.h | 1 + 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 6a5cf64..f3ea385 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -452,6 +452,7 @@ int core_tpg_del_initiator_node_acl( struct se_node_acl *acl, int force) { + LIST_HEAD(sess_list); struct se_session *sess, *sess_tmp; unsigned long flags; int dynamic_acl = 0, rc; @@ -465,26 +466,34 @@ int core_tpg_del_initiator_node_acl( tpg->num_node_acls--; spin_unlock_irq(&tpg->acl_node_lock); - spin_lock_irqsave(&tpg->session_lock, flags); - list_for_each_entry_safe(sess, sess_tmp, - &tpg->tpg_sess_list, sess_list) { - if (sess->se_node_acl != acl) + spin_lock_irqsave(&acl->nacl_sess_lock, flags); + acl->acl_stop = 1; + + list_for_each_entry_safe(sess, sess_tmp, &acl->acl_sess_list, + sess_acl_list) { + if (sess->sess_tearing_down != 0) continue; - kref_get(&sess->sess_kref); - spin_unlock_irqrestore(&tpg->session_lock, flags); + target_get_session(sess); + list_move(&sess->sess_acl_list, &sess_list); + } + spin_unlock_irqrestore(&acl->nacl_sess_lock, flags); + + list_for_each_entry_safe(sess, sess_tmp, &sess_list, sess_acl_list) { + list_del(&sess->sess_acl_list); rc = tpg->se_tpg_tfo->shutdown_session(sess); target_put_session(sess); if (!rc) continue; target_put_session(sess); - /* Wait for fabric session shutdown to complete.. */ - wait_for_completion(&acl->acl_free_comp); - - spin_lock_irqsave(&tpg->session_lock, flags); } - spin_unlock_irqrestore(&tpg->session_lock, flags); + target_put_nacl(acl); + /* + * Wait for last target_put_nacl() to complete in target_complete_nacl() + * for active fabric session transport_deregister_session() callbacks. + */ + wait_for_completion(&acl->acl_free_comp); core_tpg_wait_for_nacl_pr_ref(acl); core_clear_initiator_node_from_tpg(acl, tpg); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 2c1d777..961d8b7 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -360,7 +360,8 @@ void transport_deregister_session_configfs(struct se_session *se_sess) se_nacl = se_sess->se_node_acl; if (se_nacl) { spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); - list_del(&se_sess->sess_acl_list); + if (se_nacl->acl_stop == 0) + list_del(&se_sess->sess_acl_list); /* * If the session list is empty, then clear the pointer. * Otherwise, set the struct se_session pointer from the tail diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index d7976a5..eec61d9 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -621,6 +621,7 @@ struct se_node_acl { char initiatorname[TRANSPORT_IQN_LEN]; /* Used to signal demo mode created ACL, disabled by default */ bool dynamic_node_acl; + bool acl_stop:1; u32 queue_depth; u32 acl_index; u64 num_cmds; -- 1.7.2.5 -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html