- 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:
Vladislav Bolkhovitin
2007-08-14 16:54:54 +00:00
parent 89ca743fc6
commit 83d65b018c
12 changed files with 265 additions and 242 deletions

View File

@@ -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()

View File

@@ -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;
};

View File

@@ -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) $@

View File

@@ -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");

View File

@@ -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");

View File

@@ -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");

View File

@@ -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

View File

@@ -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:

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;