diff --git a/scst/include/scst.h b/scst/include/scst.h index cd74191fd..0c0318f4f 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -416,6 +416,9 @@ enum scst_exec_context { /* Set if session is shutting down */ #define SCST_SESS_SPH_SHUTDOWN 1 +/* Set if session is shutting down */ +#define SCST_SESS_SPH_UNREG_DONE_CALLING 2 + /************************************************************* ** Session's async (atomic) flags *************************************************************/ @@ -783,7 +786,13 @@ struct scst_tgt_template { * After AEN is sent, target driver must call scst_aen_done() and, * optionally, scst_set_aen_delivery_status(). * - * This command is expected to be NON-BLOCKING, but can sleep. + * This function is expected to be NON-BLOCKING, but can sleep. + * + * This function must be prepared to handle AENs between calls for the + * corresponding session of scst_unregister_session() and + * unreg_done_fn() callback called or before scst_unregister_session() + * returned, if its called in the blocking mode. AENs for such sessions + * should be ignored. * * MUST HAVE, if low-level protocol supports AENs. */ diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index e87dafb3e..1ad916371 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -1326,6 +1326,10 @@ void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev, TRACE_ENTRY(); + if ((tgt_dev->sess->init_phase != SCST_SESS_IPH_READY) || + (tgt_dev->sess->shut_phase != SCST_SESS_SPH_READY)) + goto out; + if (tgtt->report_aen != NULL) { struct scst_aen *aen; int rc; @@ -1488,6 +1492,10 @@ static void scst_report_luns_changed_sess(struct scst_session *sess) TRACE_ENTRY(); + if ((sess->init_phase != SCST_SESS_IPH_READY) || + (sess->shut_phase != SCST_SESS_SPH_READY)) + goto out; + TRACE_DBG("REPORTED LUNS DATA CHANGED (sess %p)", sess); for (i = 0; i < TGT_DEV_HASH_SIZE; i++) { @@ -4021,6 +4029,15 @@ void scst_free_session_callback(struct scst_session *sess) c = sess->shutdown_compl; + mutex_lock(&scst_mutex); + /* + * Necessary to sync with other threads trying to queue AEN, which + * the target driver will not be able to serve and crash, because after + * unreg_done_fn() called its internal session data will be destroyed. + */ + sess->shut_phase = SCST_SESS_SPH_UNREG_DONE_CALLING; + mutex_unlock(&scst_mutex); + if (sess->unreg_done_fn) { TRACE_DBG("Calling unreg_done_fn(%p)", sess); sess->unreg_done_fn(sess);