/* Set if session is initialized and ready */
#define SCST_SESS_IPH_READY 3
+/*************************************************************
+ ** Session shutdown phases
+ *************************************************************/
+
+/* Set if session is initialized and ready */
+#define SCST_SESS_SPH_READY 0
+
+/* Set if session is on calling pre_unreg_sess() phase */
+#define SCST_SESS_SPH_PRE_UNREG 1
+
+/* Set if session is shutting down */
+#define SCST_SESS_SPH_SHUTDOWN 2
+
/*************************************************************
** Cmd's async (atomic) flags
*************************************************************/
struct scst_session
{
- /* Initialization phase, one of SCST_SESS_IPH_* constants */
+ /*
+ * Initialization phase, one of SCST_SESS_IPH_* constants, protected by
+ * sess_list_lock
+ */
int init_phase;
atomic_t refcnt; /* get/put counter */
- /*************************************************************
- ** Session's flags. Serialized by scst_mgmt_lock
- *************************************************************/
+ /**************************************************************/
- /* Set if the session is shutting down */
- unsigned int shutting_down:1;
+ /* Alive commands for this session. ToDo: make it part of the common IO flow control */
+ atomic_t sess_cmd_count;
- /**************************************************************/
+ spinlock_t sess_list_lock; /* protects search_cmd_list, etc */
+
+ /*
+ * List of cmds in this session. Used to find a cmd in the
+ * session. Protected by sess_list_lock.
+ */
+ struct list_head search_cmd_list;
/*
* Hash list of tgt_dev's for this session, protected by scst_mutex
/* List entry for the sessions list inside ACG */
struct list_head acg_sess_list_entry;
+ struct scst_tgt *tgt; /* corresponding target */
+
/* Used for storage of target driver private stuff */
void *tgt_priv;
- /* Alive commands for this session. ToDo: make it part of common IO flow control */
- atomic_t sess_cmd_count;
-
- spinlock_t sess_list_lock; /* protects search_cmd_list, etc */
-
- /*
- * List of cmds in this session. Used to find a cmd in the
- * session. Protected by sess_list_lock.
- */
- struct list_head search_cmd_list;
-
- struct scst_tgt *tgt; /* corresponding target */
-
/* Name of attached initiator */
const char *initiator_name;
struct list_head sess_list_entry;
/* List entry for the list that keeps session, waiting for the init */
- struct list_head sess_mgmt_list_entry;
+ struct list_head sess_init_list_entry;
+
+ /* List entry for the list that keeps session, waiting for the shutdown */
+ struct list_head sess_shut_list_entry;
/*
* Lists of deffered during session initialization commands.
struct list_head init_deferred_cmd_list;
struct list_head init_deferred_mcmd_list;
+ /*
+ * Shutdown phase, one of SCST_SESS_SPH_* constants, unprotected.
+ * Async. relating to init_phase, must be a separate variable, because
+ * session could be unregistered before async. registration is finished.
+ */
+ unsigned long shut_phase;
+
/* Used if scst_unregister_session() called in wait mode */
struct completion *shutdown_compl;
- /* Used to push some unregister_session() works out of IRQ */
- struct work_struct unreg_work;
-
/*
* Functions and data for user callbacks from scst_register_session()
* and scst_unregister_session()
#define DEV_USER_NAME "scst_user"
#define DEV_USER_PATH "/dev/"
-#define DEV_USER_VERSION 96
+#define DEV_USER_VERSION 961
/*
* Chosen so sizeof(scst_user_sess) <= sizeof(scst_user_scsi_cmd_exec)
struct scst_user_dev_desc
{
- uint8_t version;
+ uint32_t version;
uint8_t type;
struct scst_user_opt opt;
uint32_t block_size;
aligned_u64 pbuf;
int32_t resp_data_len;
uint8_t buffer_cached;
+ uint8_t aborted;
uint8_t status;
};
install -m 644 Module.symvers $(INSTALL_DIR_H)
endif
-depmod -a $(KVER)
+ @echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+ @echo "!! Now don't forget to rebuild and reinstall all your !!"
+ @echo "!! target drivers, custom dev handlers and necessary user !!"
+ @echo "!! space applications. Otherwise, because of the versions !!"
+ @echo "!! mismatch, you could have many problems and crashes! !!"
+ @echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
uninstall:
cd $(DEV_HANDLERS_DIR) && $(MAKE) $@
TRACE_ENTRY();
rc = scst_check_local_events(cmd);
- if (unlikely(rc != 0)) {
- if (rc > 0)
- goto out_compl;
- else
- goto out_uncompl;
- }
+ if (unlikely(rc != 0))
+ goto out_done;
+
+ cmd->status = 0;
+ cmd->msg_status = 0;
+ cmd->host_status = DID_OK;
+ cmd->driver_status = 0;
switch (opcode) {
case WRITE_6:
case READ_10:
case READ_12:
case READ_16:
- goto out_compl;
+ cmd->completed = 1;
+ break;
}
-out:
- TRACE_EXIT_RES(res);
- return res;
-
-out_compl:
- cmd->completed = 1;
- cmd->status = 0;
- cmd->msg_status = 0;
- cmd->host_status = DID_OK;
- cmd->driver_status = 0;
-
-out_uncompl:
+out_done:
res = SCST_EXEC_COMPLETED;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
- goto out;
+
+ TRACE_EXIT_RES(res);
+ return res;
}
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
TRACE_ENTRY();
rc = scst_check_local_events(cmd);
- if (unlikely(rc != 0)) {
- if (rc > 0)
- goto out_compl;
- else
- goto out_uncompl;
- }
+ if (unlikely(rc != 0))
+ goto out_done;
+
+ cmd->status = 0;
+ cmd->msg_status = 0;
+ cmd->host_status = DID_OK;
+ cmd->driver_status = 0;
switch (opcode) {
case WRITE_6:
case READ_10:
case READ_12:
case READ_16:
- goto out_compl;
+ cmd->completed = 1;
+ break;
}
-out:
- TRACE_EXIT_RES(res);
- return res;
-
-out_compl:
- cmd->completed = 1;
- cmd->status = 0;
- cmd->msg_status = 0;
- cmd->host_status = DID_OK;
- cmd->driver_status = 0;
-
-out_uncompl:
+out_done:
res = SCST_EXEC_COMPLETED;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
- goto out;
+
+ TRACE_EXIT_RES(res);
+ return res;
}
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
TRACE_ENTRY();
rc = scst_check_local_events(cmd);
- if (unlikely(rc != 0)) {
- if (rc > 0)
- goto out_compl;
- else
- goto out_uncompl;
- }
-
- switch (opcode) {
- case WRITE_6:
- case READ_6:
- goto out_compl;
- }
-
-out:
- TRACE_EXIT_RES(res);
- return res;
+ if (unlikely(rc != 0))
+ goto out_done;
-out_compl:
- cmd->completed = 1;
cmd->status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
cmd->driver_status = 0;
-out_uncompl:
+ switch (opcode) {
+ case WRITE_6:
+ case READ_6:
+ cmd->completed = 1;
+ break;
+ }
+
+out_done:
res = SCST_EXEC_COMPLETED;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
- goto out;
+
+ TRACE_EXIT_RES(res);
+ return res;
}
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
unsigned int buf_dirty:1;
unsigned int background_exec:1;
unsigned int internal_reset_tm:1;
+ unsigned int aborted:1;
struct dev_user_cmd *buf_ucmd;
ucmd->user_cmd.on_free_cmd.pbuf = ucmd->ubuff;
ucmd->user_cmd.on_free_cmd.resp_data_len = cmd->resp_data_len;
ucmd->user_cmd.on_free_cmd.buffer_cached = ucmd->buff_cached;
+ ucmd->user_cmd.on_free_cmd.aborted = ucmd->aborted;
ucmd->user_cmd.on_free_cmd.status = cmd->status;
ucmd->state = UCMD_STATE_ON_FREEING;
out_compl:
cmd->completed = 1;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
+ /* !! At this point cmd can be already freed !! */
out:
TRACE_EXIT_RES(res);
struct dev_user_cmd *__dev_user_get_next_cmd(struct list_head *cmd_list)
{
- struct dev_user_cmd *u = NULL;
+ struct dev_user_cmd *u;
again:
+ u = NULL;
if (!list_empty(cmd_list)) {
u = list_entry(cmd_list->next, typeof(*u), ready_cmd_list_entry);
TRACE_DBG("Found ready ucmd %p", u);
if (u->state == UCMD_STATE_EXECING) {
int rc = scst_check_local_events(u->cmd);
if (unlikely(rc != 0)) {
- if (rc > 0) {
- u->cmd->completed = 1;
- u->cmd->scst_cmd_done(
- u->cmd, SCST_CMD_STATE_DEFAULT);
- } else
- dev_user_unjam_cmd(u, 0, NULL);
+ struct scst_user_dev *dev = u->dev;
+ spin_unlock_irq(
+ &dev->cmd_lists.cmd_list_lock);
+ u->cmd->scst_cmd_done(u->cmd,
+ SCST_CMD_STATE_DEFAULT);
+ /*
+ * !! At this point cmd & u can be !!
+ * !! already freed !!
+ */
+ spin_lock_irq(
+ &dev->cmd_lists.cmd_list_lock);
goto again;
}
} else if (unlikely(test_bit(SCST_CMD_ABORTED,
switch(u->state) {
case UCMD_STATE_PARSING:
case UCMD_STATE_BUF_ALLOCING:
- case UCMD_STATE_EXECING:
TRACE_MGMT_DBG("Aborting ucmd %p", u);
dev_user_unjam_cmd(u, 0, NULL);
goto again;
+ case UCMD_STATE_EXECING:
+ EXTRACHECKS_BUG_ON(1);
}
}
}
switch(state) {
case UCMD_STATE_PARSING:
case UCMD_STATE_BUF_ALLOCING:
- if (busy)
- scst_set_busy(ucmd->cmd);
- else
- scst_set_cmd_error(ucmd->cmd,
- SCST_LOAD_SENSE(scst_sense_hardw_error));
+ if (test_bit(SCST_CMD_ABORTED, &ucmd->cmd->cmd_flags))
+ ucmd->aborted = 1;
+ else {
+ if (busy)
+ scst_set_busy(ucmd->cmd);
+ else
+ scst_set_cmd_error(ucmd->cmd,
+ SCST_LOAD_SENSE(scst_sense_hardw_error));
+ }
TRACE_MGMT_DBG("Adding ucmd %p to active list", ucmd);
list_add(&ucmd->cmd->cmd_list_entry,
&ucmd->cmd->cmd_lists->active_cmd_list);
spin_unlock_irqrestore(&dev->cmd_lists.cmd_list_lock, *flags);
else
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
- if (busy)
- scst_set_busy(ucmd->cmd);
- else
- scst_set_cmd_error(ucmd->cmd,
- SCST_LOAD_SENSE(scst_sense_hardw_error));
+
TRACE_MGMT_DBG("EXEC: unjamming ucmd %p", ucmd);
- if (!test_bit(SCST_CMD_ABORTED, &ucmd->cmd->cmd_flags))
+
+ if (test_bit(SCST_CMD_ABORTED, &ucmd->cmd->cmd_flags))
+ ucmd->aborted = 1;
+ else {
ucmd->cmd->completed = 1;
+ if (busy)
+ scst_set_busy(ucmd->cmd);
+ else
+ scst_set_cmd_error(ucmd->cmd,
+ SCST_LOAD_SENSE(scst_sense_hardw_error));
+ }
+
ucmd->cmd->scst_cmd_done(ucmd->cmd, SCST_CMD_STATE_DEFAULT);
+ /* !! At this point cmd ans ucmd can be already freed !! */
+
if (flags != NULL)
spin_lock_irqsave(&dev->cmd_lists.cmd_list_lock, *flags);
else
TRACE_ENTRY();
rc = scst_check_local_events(cmd);
- if (unlikely(rc != 0)) {
- if (rc > 0)
- goto done;
- else
- goto done_uncompl;
- }
+ if (unlikely(rc != 0))
+ goto out_done;
cmd->status = 0;
cmd->msg_status = 0;
thr = vdisk_init_thr_data(cmd->tgt_dev);
if (thr == NULL) {
scst_set_busy(cmd);
- goto done;
+ goto out_compl;
}
scst_thr_data_get(&thr->hdr);
} else
(uint64_t)virt_dev->file_size, (uint64_t)data_len);
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
scst_sense_block_out_range_error));
- goto done;
+ goto out_compl;
}
switch (opcode) {
(uint64_t)data_len);
do_fsync = 1;
if (vdisk_fsync(thr, 0, 0, cmd) != 0)
- goto done;
+ goto out_compl;
}
if (virt_dev->blockio) {
blockio_exec_rw(cmd, thr, lba_start, 1);
(uint64_t)data_len);
do_fsync = 1;
if (vdisk_fsync(thr, 0, 0, cmd) != 0)
- goto done;
+ goto out_compl;
}
/* ToDo: BLOCKIO VERIFY */
vdisk_exec_write(cmd, thr, loff);
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
}
-done:
+out_compl:
cmd->completed = 1;
-done_uncompl:
+out_done:
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
out:
not be supported.
#endif
-/* All targets, devices and dev_types management is done under this mutex */
+/*
+ * All targets, devices and dev_types management is done under this mutex.
+ *
+ * It must NOT be used in any works (schedule_work(), etc.), because
+ * otherwise a deadlock (double lock, actually) is possible, e.g., with
+ * scst_user detach_tgt(), which is called under scst_mutex and calls
+ * flush_scheduled_work().
+ */
DEFINE_MUTEX(scst_mutex);
LIST_HEAD(scst_template_list);
DECLARE_WAIT_QUEUE_HEAD(scst_mgmt_waitQ);
spinlock_t scst_mgmt_lock = SPIN_LOCK_UNLOCKED;
-LIST_HEAD(scst_sess_mgmt_list);
+LIST_HEAD(scst_sess_init_list);
+LIST_HEAD(scst_sess_shut_list);
DECLARE_WAIT_QUEUE_HEAD(scst_dev_cmd_waitQ);
mutex_lock(&scst_mutex);
list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) {
- sBUG_ON(!sess->shutting_down);
+ sBUG_ON(sess->shut_phase == SCST_SESS_SPH_READY);
}
mutex_unlock(&scst_mutex);
#endif
sess->init_phase = SCST_SESS_IPH_INITING;
+ sess->shut_phase = SCST_SESS_SPH_READY;
atomic_set(&sess->refcnt, 0);
for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
struct list_head *sess_tgt_dev_list_head =
TRACE_ENTRY();
spin_lock_irqsave(&scst_mgmt_lock, flags);
- TRACE_DBG("Adding sess %p to scst_sess_mgmt_list", sess);
- list_add_tail(&sess->sess_mgmt_list_entry, &scst_sess_mgmt_list);
+ TRACE_DBG("Adding sess %p to scst_sess_shut_list", sess);
+ list_add_tail(&sess->sess_shut_list_entry, &scst_sess_shut_list);
spin_unlock_irqrestore(&scst_mgmt_lock, flags);
wake_up(&scst_mgmt_waitQ);
extern wait_queue_head_t scst_mgmt_waitQ;
extern spinlock_t scst_mgmt_lock;
-extern struct list_head scst_sess_mgmt_list;
+extern struct list_head scst_sess_init_list;
+extern struct list_head scst_sess_shut_list;
struct scst_cmd_thread_t {
struct task_struct *cmd_thread;
TRACE_ENTRY();
#ifdef EXTRACHECKS
- if (unlikely(sess->shutting_down)) {
+ if (unlikely(sess->shut_phase != SCST_SESS_SPH_READY)) {
PRINT_ERROR_PR("%s", "New cmd while shutting down the session");
sBUG();
}
cmd->state = SCST_CMD_STATE_XMIT_RESP;
/* Keep initiator away from too many BUSY commands */
if (!in_interrupt() && !in_atomic())
- ssleep(2);
+ msleep(50);
else
WARN_ON_ONCE(1);
} else {
TRACE_ENTRY();
rc = scst_check_local_events(cmd);
- if (unlikely(rc != 0)) {
- if (rc > 0)
- goto out_done;
- else
- goto out_uncompl;
- }
+ if (unlikely(rc != 0))
+ goto out_done;
cmd->status = 0;
cmd->msg_status = 0;
if (dev_cnt < cmd->resp_data_len)
scst_set_resp_data_len(cmd, dev_cnt);
-out_done:
+out_compl:
cmd->completed = 1;
-out_uncompl:
+out_done:
/* Report the result */
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
out_err:
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
- goto out_done;
+ goto out_compl;
out_put_hw_err:
scst_put_buf(cmd, buffer);
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
- goto out_done;
+ goto out_compl;
}
static int scst_pre_select(struct scst_cmd *cmd)
scst_block_dev_cmd(cmd, 1);
rc = scst_check_local_events(cmd);
- if (unlikely(rc != 0)) {
- if (rc > 0)
- goto out_compl;
- else
- goto out_uncompl;
- }
+ if (unlikely(rc != 0))
+ goto out_done;
spin_lock_bh(&dev->dev_lock);
TRACE_EXIT_RES(res);
return res;
-out_compl:
- cmd->completed = 1;
-
-out_uncompl:
+out_done:
res = SCST_EXEC_COMPLETED;
/* Report the result */
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
scst_block_dev_cmd(cmd, 1);
rc = scst_check_local_events(cmd);
- if (unlikely(rc != 0)) {
- if (rc > 0)
- goto out_compl;
- else
- goto out_uncompl;
- }
+ if (unlikely(rc != 0))
+ goto out_done;
spin_lock_bh(&dev->dev_lock);
spin_unlock_bh(&dev->dev_lock);
if (res == SCST_EXEC_COMPLETED)
- goto out_compl;
+ goto out_done;
out:
TRACE_EXIT_RES(res);
return res;
-out_compl:
- cmd->completed = 1;
-
-out_uncompl:
+out_done:
res = SCST_EXEC_COMPLETED;
/* Report the result */
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
out_complete:
res = 1;
+ cmd->completed = 1;
goto out;
out_uncomplete:
}
rc = scst_check_local_events(cmd);
- if (unlikely(rc != 0)) {
- if (rc > 0)
- goto out_compl;
- else
- goto out_aborted;
- }
+ if (unlikely(rc != 0))
+ goto out_done;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
if (unlikely(scst_alloc_request(cmd) != 0)) {
out_error:
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
-out_compl:
- cmd->completed = 1;
- rc = SCST_EXEC_COMPLETED;
- scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
- goto out;
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
out_busy:
scst_set_busy(cmd);
- goto out_compl;
- goto out;
+ cmd->completed = 1;
+ /* go through */
#endif
-out_aborted:
+out_done:
rc = SCST_EXEC_COMPLETED;
/* Report the result. The cmd is not completed */
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
atomic_inc(&sess->sess_cmd_count);
#ifdef EXTRACHECKS
- if (unlikely(sess->shutting_down)) {
+ if (unlikely(sess->shut_phase != SCST_SESS_SPH_READY)) {
PRINT_ERROR_PR("%s",
"New mgmt cmd while shutting down the session");
sBUG();
sess->reg_sess_data = data;
sess->init_result_fn = result_fn;
spin_lock_irqsave(&scst_mgmt_lock, flags);
- TRACE_DBG("Adding sess %p to scst_sess_mgmt_list", sess);
- list_add_tail(&sess->sess_mgmt_list_entry,
- &scst_sess_mgmt_list);
+ TRACE_DBG("Adding sess %p to scst_sess_init_list", sess);
+ list_add_tail(&sess->sess_init_list_entry,
+ &scst_sess_init_list);
spin_unlock_irqrestore(&scst_mgmt_lock, flags);
wake_up(&scst_mgmt_waitQ);
} else {
goto out;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-static void scst_unreg_work_fn(void *p)
-#else
-static void scst_unreg_work_fn(struct work_struct *work)
-#endif
-{
- int i;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- struct scst_session *sess = (struct scst_session*)p;
-#else
- struct scst_session *sess = container_of(work, struct scst_session,
- unreg_work);
-#endif
- struct scst_tgt_dev *tgt_dev;
-
- TRACE_ENTRY();
-
- mutex_lock(&scst_mutex);
- for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
- struct list_head *sess_tgt_dev_list_head =
- &sess->sess_tgt_dev_list_hash[i];
- list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
- sess_tgt_dev_list_entry) {
- struct scst_dev_type *handler = tgt_dev->dev->handler;
- if (handler && handler->pre_unreg_sess) {
- TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)",
- tgt_dev);
- handler->pre_unreg_sess(tgt_dev);
- TRACE_DBG("%s", "Dev handler's pre_unreg_sess() "
- "returned");
- }
- }
- }
- mutex_unlock(&scst_mutex);
-
- scst_sess_put(sess);
-
- TRACE_EXIT();
- return;
-}
-
/*
* Must not been called in parallel with scst_rx_cmd() or
* scst_rx_mgmt_fn_*() for the same sess
pc = &c;
#endif
+ sess->shut_phase = SCST_SESS_SPH_PRE_UNREG;
+
spin_lock_irqsave(&scst_mgmt_lock, flags);
- sess->shutting_down = 1;
sess->unreg_done_fn = unreg_done_fn;
if (wait) {
sess->shutdown_compl = pc;
tm_dbg_task_mgmt("UNREGISTER SESSION", 1);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- INIT_WORK(&sess->unreg_work, scst_unreg_work_fn, sess);
-#else
- INIT_WORK(&sess->unreg_work, scst_unreg_work_fn);
-#endif
-
- schedule_work(&sess->unreg_work);
+ scst_sess_put(sess);
if (wait) {
TRACE_DBG("Waiting for session %p to complete", sess);
return;
}
+static void scst_pre_unreg_sess(struct scst_session *sess)
+{
+ int i;
+ struct scst_tgt_dev *tgt_dev;
+ unsigned long flags;
+
+ TRACE_ENTRY();
+
+ mutex_lock(&scst_mutex);
+ for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
+ struct list_head *sess_tgt_dev_list_head =
+ &sess->sess_tgt_dev_list_hash[i];
+ list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
+ sess_tgt_dev_list_entry) {
+ struct scst_dev_type *handler = tgt_dev->dev->handler;
+ if (handler && handler->pre_unreg_sess) {
+ TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)",
+ tgt_dev);
+ handler->pre_unreg_sess(tgt_dev);
+ TRACE_DBG("%s", "Dev handler's pre_unreg_sess() "
+ "returned");
+ }
+ }
+ }
+ mutex_unlock(&scst_mutex);
+
+ sess->shut_phase = SCST_SESS_SPH_SHUTDOWN;
+
+ spin_lock_irqsave(&scst_mgmt_lock, flags);
+ TRACE_DBG("Adding sess %p to scst_sess_shut_list", sess);
+ list_add_tail(&sess->sess_shut_list_entry, &scst_sess_shut_list);
+ spin_unlock_irqrestore(&scst_mgmt_lock, flags);
+
+ TRACE_EXIT();
+ return;
+}
+
static inline int test_mgmt_list(void)
{
- int res = !list_empty(&scst_sess_mgmt_list) ||
+ int res = !list_empty(&scst_sess_init_list) ||
+ !list_empty(&scst_sess_shut_list) ||
unlikely(kthread_should_stop());
return res;
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&scst_mgmt_waitQ, &wait);
}
-restart:
- list_for_each_entry(sess, &scst_sess_mgmt_list,
- sess_mgmt_list_entry)
- {
- TRACE_DBG("Removing sess %p from scst_sess_mgmt_list",
+
+ while (!list_empty(&scst_sess_init_list)) {
+ sess = list_entry(scst_sess_init_list.next,
+ typeof(*sess), sess_init_list_entry);
+ TRACE_DBG("Removing sess %p from scst_sess_init_list",
sess);
- list_del(&sess->sess_mgmt_list_entry);
+ list_del(&sess->sess_init_list_entry);
spin_unlock_irq(&scst_mgmt_lock);
- if (sess->init_phase == SCST_SESS_IPH_INITING) {
+
+ if (sess->init_phase == SCST_SESS_IPH_INITING)
scst_init_session(sess);
- } else if (sess->shutting_down) {
+ else {
+ PRINT_ERROR_PR("session %p is in "
+ "scst_sess_init_list, but in unknown "
+ "init phase %x", sess,
+ sess->init_phase);
+ sBUG();
+ }
+
+ spin_lock_irq(&scst_mgmt_lock);
+ }
+
+ while (!list_empty(&scst_sess_shut_list)) {
+ sess = list_entry(scst_sess_shut_list.next,
+ typeof(*sess), sess_shut_list_entry);
+ TRACE_DBG("Removing sess %p from scst_sess_shut_list",
+ sess);
+ list_del(&sess->sess_shut_list_entry);
+ spin_unlock_irq(&scst_mgmt_lock);
+
+ switch(sess->shut_phase) {
+ case SCST_SESS_SPH_PRE_UNREG:
+ scst_pre_unreg_sess(sess);
+ break;
+ case SCST_SESS_SPH_SHUTDOWN:
sBUG_ON(atomic_read(&sess->refcnt) != 0);
scst_free_session_callback(sess);
- } else {
+ break;
+ default:
PRINT_ERROR_PR("session %p is in "
- "scst_sess_mgmt_list, but in unknown "
- "phase %x", sess, sess->init_phase);
+ "scst_sess_shut_list, but in unknown "
+ "shut phase %lx", sess,
+ sess->shut_phase);
sBUG();
+ break;
}
+
spin_lock_irq(&scst_mgmt_lock);
- goto restart;
}
}
spin_unlock_irq(&scst_mgmt_lock);
/*
* If kthread_should_stop() is true, we are guaranteed to be
- * on the module unload, so scst_sess_mgmt_list must be empty.
+ * on the module unload, so both lists must be empty.
*/
- sBUG_ON(!list_empty(&scst_sess_mgmt_list));
+ sBUG_ON(!list_empty(&scst_sess_init_list));
+ sBUG_ON(!list_empty(&scst_sess_shut_list));
TRACE_EXIT();
return 0;