mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-25 07:51:28 +00:00
- Call of pre_unreg_sess() moved to scst_mgmt_thread, because of scst_mutex deadlock with scst_user's pre_unreg_sess() handler
- scst_check_local_events() cleanups - In scst_user notification about aborted commands added, user space interface changed - Other minor fixes and cleanups git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@159 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -285,6 +285,19 @@
|
||||
/* 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
|
||||
*************************************************************/
|
||||
@@ -833,20 +846,27 @@ struct scst_tgt
|
||||
|
||||
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
|
||||
* and suspended activity
|
||||
@@ -859,22 +879,11 @@ struct scst_session
|
||||
/* 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;
|
||||
|
||||
@@ -882,7 +891,10 @@ struct scst_session
|
||||
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.
|
||||
@@ -891,12 +903,16 @@ struct scst_session
|
||||
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()
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#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)
|
||||
@@ -95,7 +95,7 @@ struct scst_user_opt
|
||||
|
||||
struct scst_user_dev_desc
|
||||
{
|
||||
uint8_t version;
|
||||
uint32_t version;
|
||||
uint8_t type;
|
||||
struct scst_user_opt opt;
|
||||
uint32_t block_size;
|
||||
@@ -168,6 +168,7 @@ struct scst_user_scsi_on_free_cmd
|
||||
aligned_u64 pbuf;
|
||||
int32_t resp_data_len;
|
||||
uint8_t buffer_cached;
|
||||
uint8_t aborted;
|
||||
uint8_t status;
|
||||
};
|
||||
|
||||
|
||||
@@ -81,6 +81,12 @@ ifneq ($(MOD_VERS),)
|
||||
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) $@
|
||||
|
||||
@@ -350,12 +350,13 @@ int disk_exec(struct scst_cmd *cmd)
|
||||
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:
|
||||
@@ -366,24 +367,16 @@ int disk_exec(struct scst_cmd *cmd)
|
||||
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");
|
||||
|
||||
@@ -364,12 +364,13 @@ int modisk_exec(struct scst_cmd *cmd)
|
||||
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:
|
||||
@@ -380,24 +381,16 @@ int modisk_exec(struct scst_cmd *cmd)
|
||||
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");
|
||||
|
||||
@@ -395,34 +395,27 @@ int tape_exec(struct scst_cmd *cmd)
|
||||
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;
|
||||
|
||||
switch (opcode) {
|
||||
case WRITE_6:
|
||||
case READ_6:
|
||||
goto out_compl;
|
||||
}
|
||||
|
||||
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:
|
||||
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");
|
||||
|
||||
@@ -124,6 +124,7 @@ struct dev_user_cmd
|
||||
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;
|
||||
|
||||
@@ -842,6 +843,7 @@ static void dev_user_on_free_cmd(struct scst_cmd *cmd)
|
||||
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;
|
||||
@@ -1251,6 +1253,7 @@ static int dev_user_process_reply_exec(struct dev_user_cmd *ucmd,
|
||||
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);
|
||||
@@ -1445,9 +1448,10 @@ static int dev_user_process_scst_commands(struct scst_user_dev *dev)
|
||||
|
||||
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);
|
||||
@@ -1457,12 +1461,17 @@ again:
|
||||
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,
|
||||
@@ -1470,10 +1479,11 @@ again:
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1819,11 +1829,15 @@ static void dev_user_unjam_cmd(struct dev_user_cmd *ucmd, int busy,
|
||||
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);
|
||||
@@ -1835,15 +1849,23 @@ static void dev_user_unjam_cmd(struct dev_user_cmd *ucmd, int busy,
|
||||
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
|
||||
|
||||
@@ -652,12 +652,8 @@ static int vdisk_do_job(struct scst_cmd *cmd)
|
||||
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;
|
||||
@@ -669,7 +665,7 @@ static int vdisk_do_job(struct scst_cmd *cmd)
|
||||
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
|
||||
@@ -734,7 +730,7 @@ static int vdisk_do_job(struct scst_cmd *cmd)
|
||||
(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) {
|
||||
@@ -780,7 +776,7 @@ static int vdisk_do_job(struct scst_cmd *cmd)
|
||||
(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);
|
||||
@@ -815,7 +811,7 @@ static int vdisk_do_job(struct scst_cmd *cmd)
|
||||
(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);
|
||||
@@ -903,10 +899,10 @@ static int vdisk_do_job(struct scst_cmd *cmd)
|
||||
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:
|
||||
|
||||
@@ -52,7 +52,14 @@
|
||||
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);
|
||||
@@ -109,7 +116,8 @@ DECLARE_WAIT_QUEUE_HEAD(scst_mgmt_cmd_list_waitQ);
|
||||
|
||||
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);
|
||||
|
||||
@@ -369,7 +377,7 @@ void scst_unregister(struct scst_tgt *tgt)
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -1048,6 +1048,7 @@ struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask,
|
||||
#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 =
|
||||
@@ -1137,8 +1138,8 @@ void scst_sched_session_free(struct scst_session *sess)
|
||||
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);
|
||||
|
||||
@@ -198,7 +198,8 @@ extern struct scst_tasklet scst_tasklets[NR_CPUS];
|
||||
|
||||
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;
|
||||
|
||||
@@ -61,7 +61,7 @@ struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
|
||||
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();
|
||||
}
|
||||
@@ -145,7 +145,7 @@ out_redirect:
|
||||
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 {
|
||||
@@ -1287,12 +1287,8 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
|
||||
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;
|
||||
@@ -1366,10 +1362,10 @@ inc_dev_cnt:
|
||||
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);
|
||||
|
||||
@@ -1382,12 +1378,12 @@ out_put_err:
|
||||
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)
|
||||
@@ -1451,12 +1447,8 @@ static int scst_reserve_local(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);
|
||||
|
||||
@@ -1483,10 +1475,7 @@ 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);
|
||||
@@ -1511,12 +1500,8 @@ static int scst_release_local(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);
|
||||
|
||||
@@ -1544,16 +1529,13 @@ static int scst_release_local(struct scst_cmd *cmd)
|
||||
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);
|
||||
@@ -1629,6 +1611,7 @@ out:
|
||||
|
||||
out_complete:
|
||||
res = 1;
|
||||
cmd->completed = 1;
|
||||
goto out;
|
||||
|
||||
out_uncomplete:
|
||||
@@ -1786,12 +1769,8 @@ static int scst_do_send_to_midlev(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
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)) {
|
||||
@@ -1845,20 +1824,14 @@ out_rc_error:
|
||||
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);
|
||||
@@ -4052,7 +4025,7 @@ static int scst_post_rx_mgmt_cmd(struct scst_session *sess,
|
||||
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();
|
||||
@@ -4346,9 +4319,9 @@ struct scst_session *scst_register_session(struct scst_tgt *tgt, int atomic,
|
||||
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 {
|
||||
@@ -4367,47 +4340,6 @@ out_free:
|
||||
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
|
||||
@@ -4429,9 +4361,10 @@ void scst_unregister_session(struct scst_session *sess, int wait,
|
||||
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;
|
||||
@@ -4446,13 +4379,7 @@ void scst_unregister_session(struct scst_session *sess, int wait,
|
||||
|
||||
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);
|
||||
@@ -4467,9 +4394,47 @@ void scst_unregister_session(struct scst_session *sess, int wait,
|
||||
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;
|
||||
}
|
||||
@@ -4500,36 +4465,64 @@ int scst_mgmt_thread(void *arg)
|
||||
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) {
|
||||
sBUG_ON(atomic_read(&sess->refcnt) != 0);
|
||||
scst_free_session_callback(sess);
|
||||
} else {
|
||||
else {
|
||||
PRINT_ERROR_PR("session %p is in "
|
||||
"scst_sess_mgmt_list, but in unknown "
|
||||
"phase %x", sess, sess->init_phase);
|
||||
"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);
|
||||
break;
|
||||
default:
|
||||
PRINT_ERROR_PR("session %p is in "
|
||||
"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;
|
||||
|
||||
Reference in New Issue
Block a user