- In scst_user fixed potential deadlock

- scst_check_local_events() added
 - Minor cleanups and fixes 


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@155 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2007-08-03 09:57:15 +00:00
parent 10f17420b5
commit 5cdb901fea
13 changed files with 295 additions and 140 deletions

View File

@@ -8,7 +8,7 @@ To be done
the page cache (in order to avoid data copy between it and internal
buffers). Requires modifications of the kernel.
- O_DIRECT mode doesn't work (oops'es somewhere in the kernel)
- O_DIRECT mode doesn't work for FILEIO (oops'es somewhere in the kernel)
- Close integration with Linux initiator SCSI mil-level, including
queue types (simple, ordered, etc.) and local initiators (sd, st, sg,
@@ -17,11 +17,11 @@ To be done
- Improve task management and Unit Attention conditions handling
using ACA in order to make them always reliable. Honoring NACA, QErr,
TST, UA_INTLCK_CTRL bits. Requires deep modifications of the kernel.
- Better handle of devices DMA restrictions.
- Move linear searches to hash-table based.
- Redone some semaphores with completion interface.
- HIGHMEM cleanup. Looks like HIGHMEM usage doesn't worth the effort and
performance hit, at least until VDISK handler doesn't use the page
cache directly, so disable it for now, although the code looks ready.

View File

@@ -678,6 +678,9 @@ struct scst_dev_type
* by scst_cmd_atomic(): it is true if the function called in the
* atomic (non-sleeping) context.
*
* !! If this function is implemented, scst_check_local_events() shall !!
* !! be called inside it just before the actual command's execution. !!
*
* OPTIONAL, if not set, the commands will be sent directly to SCSI
* device.
*/
@@ -2117,6 +2120,17 @@ void scst_resume_activity(void);
*/
void scst_process_active_cmd(struct scst_cmd *cmd, int context);
/*
* Checks if command can be executed (reservations, etc.) or there are local
* events, like pending UAs. Returns < 0 if command must be aborted, > 0 if
* there is an event and command should be immediately completed, or 0
* otherwise.
*
* !! Dev handlers implementing exec() callback must call this function there !!
* !! just before the actual command's execution !!
*/
int scst_check_local_events(struct scst_cmd *cmd);
/*
* Returns target driver's root entry in SCST's /proc hierarchy.
* The driver can create own files/directoryes here, which should

View File

@@ -117,7 +117,7 @@ EXTRA_CFLAGS += -DDEBUG -g
# If defined, allows SCST to use HIGHMEM. It's unclear, if it brings
# something valuable, except performance hit in some cases,
# so let it be off. Untested.
# so let it be off. Untested and unsupported.
#EXTRA_CFLAGS += -DSCST_HIGHMEM
clean:

View File

@@ -344,11 +344,19 @@ int disk_done(struct scst_cmd *cmd)
********************************************************************/
int disk_exec(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED;
int res = SCST_EXEC_NOT_COMPLETED, rc;
int opcode = cmd->cdb[0];
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 WRITE_10:
@@ -358,18 +366,24 @@ int disk_exec(struct scst_cmd *cmd)
case READ_10:
case READ_12:
case READ_16:
res = SCST_EXEC_COMPLETED;
cmd->status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
cmd->driver_status = 0;
cmd->completed = 1;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
break;
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:
res = SCST_EXEC_COMPLETED;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
goto out;
}
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");

View File

@@ -358,11 +358,19 @@ int modisk_done(struct scst_cmd *cmd)
********************************************************************/
int modisk_exec(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED;
int res = SCST_EXEC_NOT_COMPLETED, rc;
int opcode = cmd->cdb[0];
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 WRITE_10:
@@ -372,18 +380,24 @@ int modisk_exec(struct scst_cmd *cmd)
case READ_10:
case READ_12:
case READ_16:
res = SCST_EXEC_COMPLETED;
cmd->status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
cmd->driver_status = 0;
cmd->completed = 1;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
break;
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:
res = SCST_EXEC_COMPLETED;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
goto out;
}
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");

View File

@@ -389,26 +389,40 @@ int tape_done(struct scst_cmd *cmd)
********************************************************************/
int tape_exec(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED;
int res = SCST_EXEC_NOT_COMPLETED, rc;
int opcode = cmd->cdb[0];
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:
res = SCST_EXEC_COMPLETED;
cmd->status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
cmd->driver_status = 0;
cmd->completed = 1;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
break;
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:
res = SCST_EXEC_COMPLETED;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
goto out;
}
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");

View File

@@ -191,7 +191,7 @@ static int dev_user_release(struct inode *inode, struct file *file);
static struct kmem_cache *user_cmd_cachep;
static DEFINE_MUTEX(dev_user_mutex);
static DEFINE_MUTEX(dev_priv_mutex);
static struct file_operations dev_user_fops = {
.poll = dev_user_poll,
@@ -204,6 +204,7 @@ static struct file_operations dev_user_fops = {
static struct class *dev_user_sysfs_class;
static spinlock_t dev_list_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(dev_list);
static spinlock_t cleanup_lock = SPIN_LOCK_UNLOCKED;
@@ -1383,15 +1384,15 @@ static int dev_user_reply_cmd(struct file *file, unsigned long arg)
TRACE_ENTRY();
mutex_lock(&dev_user_mutex);
mutex_lock(&dev_priv_mutex);
dev = (struct scst_user_dev*)file->private_data;
res = dev_user_check_reg(dev);
if (res != 0) {
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
goto out;
}
down_read(&dev->dev_rwsem);
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
reply = kzalloc(sizeof(*reply), GFP_KERNEL);
if (reply == NULL) {
@@ -1452,16 +1453,28 @@ again:
TRACE_DBG("Found ready ucmd %p", u);
list_del(&u->ready_cmd_list_entry);
EXTRACHECKS_BUG_ON(u->state & UCMD_STATE_JAMMED_MASK);
if ((u->cmd != NULL) &&
unlikely(test_bit(SCST_CMD_ABORTED,
&u->cmd->cmd_flags))) {
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;
if (u->cmd != NULL) {
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);
goto again;
}
} else if (unlikely(test_bit(SCST_CMD_ABORTED,
&u->cmd->cmd_flags))) {
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;
}
}
}
u->state |= UCMD_STATE_SENT_MASK;
@@ -1604,15 +1617,15 @@ static int dev_user_reply_get_cmd(struct file *file, unsigned long arg,
TRACE_ENTRY();
mutex_lock(&dev_user_mutex);
mutex_lock(&dev_priv_mutex);
dev = (struct scst_user_dev*)file->private_data;
res = dev_user_check_reg(dev);
if (res != 0) {
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
goto out;
}
down_read(&dev->dev_rwsem);
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
res = copy_from_user(&ureply, (void*)arg, sizeof(ureply));
if (res < 0)
@@ -1742,15 +1755,15 @@ static unsigned int dev_user_poll(struct file *file, poll_table *wait)
TRACE_ENTRY();
mutex_lock(&dev_user_mutex);
mutex_lock(&dev_priv_mutex);
dev = (struct scst_user_dev*)file->private_data;
res = dev_user_check_reg(dev);
if (res != 0) {
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
goto out;
}
down_read(&dev->dev_rwsem);
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
@@ -1828,7 +1841,8 @@ static void dev_user_unjam_cmd(struct dev_user_cmd *ucmd, int busy,
scst_set_cmd_error(ucmd->cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
TRACE_MGMT_DBG("EXEC: unjamming ucmd %p", ucmd);
ucmd->cmd->completed = 1;
if (!test_bit(SCST_CMD_ABORTED, &ucmd->cmd->cmd_flags))
ucmd->cmd->completed = 1;
ucmd->cmd->scst_cmd_done(ucmd->cmd, SCST_CMD_STATE_DEFAULT);
if (flags != NULL)
spin_lock_irqsave(&dev->cmd_lists.cmd_list_lock, *flags);
@@ -2136,14 +2150,14 @@ static int dev_user_attach(struct scst_device *sdev)
TRACE_ENTRY();
mutex_lock(&dev_user_mutex);
spin_lock(&dev_list_lock);
list_for_each_entry(d, &dev_list, dev_list_entry) {
if (strcmp(d->name, sdev->virt_name) == 0) {
dev = d;
break;
}
}
mutex_unlock(&dev_user_mutex);
spin_unlock(&dev_list_lock);
if (dev == NULL) {
PRINT_ERROR_PR("Device %s not found", sdev->virt_name);
res = -EINVAL;
@@ -2539,17 +2553,6 @@ static int dev_user_register_dev(struct file *file,
strncpy(dev->name, dev_desc->name, sizeof(dev->name)-1);
dev->name[sizeof(dev->name)-1] = '\0';
mutex_lock(&dev_user_mutex);
list_for_each_entry(d, &dev_list, dev_list_entry) {
if (strcmp(d->name, dev->name) == 0) {
PRINT_ERROR_PR("Device %s already exist",
dev->name);
res = -EEXIST;
goto out_free_unlock;
}
}
/*
* We don't use clustered pool, since it implies pages reordering,
* which isn't possible with user space supplied buffers. Although
@@ -2558,7 +2561,7 @@ static int dev_user_register_dev(struct file *file,
*/
dev->pool = sgv_pool_create(dev->name, 0);
if (dev->pool == NULL)
goto out_free_unlock;
goto out_put;
sgv_pool_set_allocator(dev->pool, dev_user_alloc_pages,
dev_user_free_sg_entries);
@@ -2588,16 +2591,28 @@ static int dev_user_register_dev(struct file *file,
TRACE_MEM("dev %p, name %s", dev, dev->name);
spin_lock(&dev_list_lock);
list_for_each_entry(d, &dev_list, dev_list_entry) {
if (strcmp(d->name, dev->name) == 0) {
PRINT_ERROR_PR("Device %s already exist",
dev->name);
res = -EEXIST;
spin_unlock(&dev_list_lock);
goto out_free;
}
}
list_add_tail(&dev->dev_list_entry, &dev_list);
mutex_unlock(&dev_user_mutex);
spin_unlock(&dev_list_lock);
if (res != 0)
goto out_free_pool;
goto out_del_free;
res = scst_register_virtual_dev_driver(&dev->devtype);
if (res < 0)
goto out_free_pool;
goto out_del_free;
dev->virt_id = scst_register_virtual_device(&dev->devtype, dev->name);
if (dev->virt_id < 0) {
@@ -2605,15 +2620,15 @@ static int dev_user_register_dev(struct file *file,
goto out_unreg_handler;
}
mutex_lock(&dev_user_mutex);
mutex_lock(&dev_priv_mutex);
if (file->private_data != NULL) {
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
PRINT_ERROR_PR("%s", "Device already registered");
res = -EINVAL;
goto out_unreg_drv;
}
file->private_data = dev;
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
out:
TRACE_EXIT_RES(res);
@@ -2625,18 +2640,16 @@ out_unreg_drv:
out_unreg_handler:
scst_unregister_virtual_dev_driver(&dev->devtype);
out_free_pool:
mutex_lock(&dev_user_mutex);
out_del_free:
spin_lock(&dev_list_lock);
list_del(&dev->dev_list_entry);
mutex_unlock(&dev_user_mutex);
spin_unlock(&dev_list_lock);
out_free:
sgv_pool_destroy(dev->pool);
kfree(dev);
goto out_put;
out_free_unlock:
kfree(dev);
mutex_unlock(&dev_user_mutex);
out_put:
module_put(THIS_MODULE);
goto out;
@@ -2696,15 +2709,15 @@ static int dev_user_set_opt(struct file *file, const struct scst_user_opt *opt)
TRACE_ENTRY();
mutex_lock(&dev_user_mutex);
mutex_lock(&dev_priv_mutex);
dev = (struct scst_user_dev*)file->private_data;
res = dev_user_check_reg(dev);
if (res != 0) {
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
goto out;
}
down_read(&dev->dev_rwsem);
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
scst_suspend_activity();
res = __dev_user_set_opt(dev, opt);
@@ -2725,15 +2738,15 @@ static int dev_user_get_opt(struct file *file, void *arg)
TRACE_ENTRY();
mutex_lock(&dev_user_mutex);
mutex_lock(&dev_priv_mutex);
dev = (struct scst_user_dev*)file->private_data;
res = dev_user_check_reg(dev);
if (res != 0) {
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
goto out;
}
down_read(&dev->dev_rwsem);
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
opt.parse_type = dev->parse_type;
opt.on_free_cmd_type = dev->on_free_cmd_type;
@@ -2777,15 +2790,19 @@ static int dev_user_release(struct inode *inode, struct file *file)
TRACE_ENTRY();
mutex_lock(&dev_user_mutex);
mutex_lock(&dev_priv_mutex);
dev = (struct scst_user_dev*)file->private_data;
if (dev == NULL) {
mutex_unlock(&dev_user_mutex);
mutex_unlock(&dev_priv_mutex);
goto out;
}
file->private_data = NULL;
spin_lock(&dev_list_lock);
list_del(&dev->dev_list_entry);
mutex_unlock(&dev_user_mutex);
spin_unlock(&dev_list_lock);
mutex_unlock(&dev_priv_mutex);
down_write(&dev->dev_rwsem);

View File

@@ -636,6 +636,7 @@ static inline int vdisk_need_pre_sync(enum scst_cmd_queue_type cur,
static int vdisk_do_job(struct scst_cmd *cmd)
{
int rc;
uint64_t lba_start = 0;
loff_t data_len = 0;
uint8_t *cdb = cmd->cdb;
@@ -650,17 +651,19 @@ 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;
}
cmd->status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
cmd->driver_status = 0;
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
TRACE_MGMT_DBG("Flag ABORTED set for "
"cmd %p (tag %llu), skipping", cmd, cmd->tag);
goto done_uncompl;
}
d = scst_find_thr_data(cmd->tgt_dev);
if (unlikely(d == NULL)) {
thr = vdisk_init_thr_data(cmd->tgt_dev);

View File

@@ -1656,6 +1656,8 @@ EXPORT_SYMBOL(scst_put);
EXPORT_SYMBOL(scst_alloc);
EXPORT_SYMBOL(scst_free);
EXPORT_SYMBOL(scst_check_local_events);
/* Tgt_dev's threads local storage */
EXPORT_SYMBOL(scst_add_thr_data);
EXPORT_SYMBOL(scst_del_all_thr_data);

View File

@@ -2699,7 +2699,7 @@ int scst_inc_on_dev_cmd(struct scst_cmd *cmd)
#ifdef STRICT_SERIALIZING
spin_lock_bh(&dev->dev_lock);
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
goto out_unlock;
if (dev->block_count > 0) {
scst_dec_on_dev_cmd(cmd);
@@ -2718,7 +2718,7 @@ int scst_inc_on_dev_cmd(struct scst_cmd *cmd)
repeat:
if (unlikely(dev->block_count > 0)) {
spin_lock_bh(&dev->dev_lock);
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
goto out_unlock;
barrier(); /* to reread block_count */
if (dev->block_count > 0) {
@@ -3184,6 +3184,9 @@ void tm_dbg_task_mgmt(const char *fn, int force)
{
unsigned long flags;
if (!tm_dbg_flags.tm_dbg_active)
goto out;
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
if ((tm_dbg_state != TM_DBG_STATE_OFFLINE) || force) {
TRACE_MGMT_DBG("%s: freeing %d delayed cmds", fn,
@@ -3196,6 +3199,9 @@ void tm_dbg_task_mgmt(const char *fn, int force)
TRACE_MGMT_DBG("%s: while OFFLINE state, doing nothing", fn);
}
spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
out:
return;
}
int tm_dbg_is_release(void)

View File

@@ -210,8 +210,9 @@ static int scst_alloc_sg_entries(struct scatterlist *sg, int pages,
for (pg = 0; pg < pages; pg++) {
void *rc;
#ifdef DEBUG_OOM
if ((scst_random() % 10000) == 55)
void *rc = NULL;
if (((gfp_mask & __GFP_NOFAIL) == 0) &&
((scst_random() % 10000) == 55))
rc = NULL;
else
#endif
rc = alloc_fns->alloc_pages_fn(&sg[sg_count], gfp_mask,

View File

@@ -1694,12 +1694,12 @@ static int scst_sessions_info_show(struct seq_file *seq, void *v)
goto out;
}
seq_printf(seq, "%-20s%-35s%-35s%-15s\n", "Target name", "Initiator name",
seq_printf(seq, "%-20s %-35s %-35s %-15s\n", "Target name", "Initiator name",
"Group name", "Command Count");
list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
seq_printf(seq, "%-20s%-35s%-35s%-15d\n",
seq_printf(seq, "%-20s %-35s %-35s %-15d\n",
sess->tgt->tgtt->name,
sess->initiator_name,
acg->acg_name,

View File

@@ -26,6 +26,7 @@
#include <asm/unistd.h>
#include <asm/string.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include "scsi_tgt.h"
#include "scst_priv.h"
@@ -142,6 +143,11 @@ out_redirect:
sBUG_ON(context != SCST_CONTEXT_DIRECT);
scst_set_busy(cmd);
cmd->state = SCST_CMD_STATE_XMIT_RESP;
/* Keep initiator away from too many BUSY commands */
if (!in_interrupt() && !in_atomic())
ssleep(2);
else
WARN_ON_ONCE(1);
} else {
unsigned long flags;
spin_lock_irqsave(&scst_init_lock, flags);
@@ -1270,7 +1276,7 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state)
static int scst_report_luns_local(struct scst_cmd *cmd)
{
int res = SCST_EXEC_COMPLETED;
int res = SCST_EXEC_COMPLETED, rc;
int dev_cnt = 0;
int buffer_size;
int i;
@@ -1280,6 +1286,14 @@ 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;
}
cmd->status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
@@ -1355,6 +1369,7 @@ inc_dev_cnt:
out_done:
cmd->completed = 1;
out_uncompl:
/* Report the result */
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
@@ -1388,16 +1403,7 @@ static int scst_pre_select(struct scst_cmd *cmd)
scst_block_dev_cmd(cmd, 1);
if (test_bit(SCST_TGT_DEV_UA_PENDING, &cmd->tgt_dev->tgt_dev_flags)) {
int rc = scst_set_pending_UA(cmd);
if (rc == 0) {
res = SCST_EXEC_COMPLETED;
cmd->completed = 1;
/* Report the result */
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
goto out;
}
}
/* Check for local events will be done when cmd will be executed */
out:
TRACE_EXIT_RES(res);
@@ -1419,7 +1425,7 @@ static inline void scst_report_reserved(struct scst_cmd *cmd)
static int scst_reserve_local(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED;
int res = SCST_EXEC_NOT_COMPLETED, rc;
struct scst_device *dev;
struct scst_tgt_dev *tgt_dev_tmp;
@@ -1444,6 +1450,14 @@ 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;
}
spin_lock_bh(&dev->dev_lock);
if (test_bit(SCST_TGT_DEV_RESERVED, &cmd->tgt_dev->tgt_dev_flags)) {
@@ -1468,20 +1482,42 @@ out_unlock:
out:
TRACE_EXIT_RES(res);
return res;
out_compl:
cmd->completed = 1;
out_uncompl:
res = SCST_EXEC_COMPLETED;
/* Report the result */
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
goto out;
}
static int scst_release_local(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED;
int res = SCST_EXEC_NOT_COMPLETED, rc;
struct scst_tgt_dev *tgt_dev_tmp;
struct scst_device *dev;
TRACE_ENTRY();
if (scst_cmd_atomic(cmd)) {
res = SCST_EXEC_NEED_THREAD;
goto out;
}
dev = cmd->dev;
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;
}
spin_lock_bh(&dev->dev_lock);
/*
@@ -1498,8 +1534,7 @@ static int scst_release_local(struct scst_cmd *cmd)
} else {
list_for_each_entry(tgt_dev_tmp,
&dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry)
{
dev_tgt_dev_list_entry) {
clear_bit(SCST_TGT_DEV_RESERVED,
&tgt_dev_tmp->tgt_dev_flags);
}
@@ -1508,27 +1543,35 @@ static int scst_release_local(struct scst_cmd *cmd)
spin_unlock_bh(&dev->dev_lock);
if (res == SCST_EXEC_COMPLETED) {
cmd->completed = 1;
/* Report the result */
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
}
if (res == SCST_EXEC_COMPLETED)
goto out_compl;
out:
TRACE_EXIT_RES(res);
return res;
out_compl:
cmd->completed = 1;
out_uncompl:
res = SCST_EXEC_COMPLETED;
/* Report the result */
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
goto out;
}
/*
* The result of cmd execution, if any, should be reported
* via scst_cmd_done_local()
*/
static int scst_pre_exec(struct scst_cmd *cmd)
int scst_check_local_events(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED, rc;
int res, rc;
struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
TRACE_ENTRY();
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
TRACE_MGMT_DBG("ABORTED set, aborting cmd %p", cmd);
goto out_uncomplete;
}
/* Reserve check before Unit Attention */
if (unlikely(test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags))) {
if ((cmd->cdb[0] != INQUIRY) && (cmd->cdb[0] != REPORT_LUNS) &&
@@ -1538,8 +1581,7 @@ static int scst_pre_exec(struct scst_cmd *cmd)
(cmd->cdb[0] != LOG_SENSE) && (cmd->cdb[0] != REQUEST_SENSE))
{
scst_report_reserved(cmd);
res = SCST_EXEC_COMPLETED;
goto out;
goto out_complete;
}
}
@@ -1565,7 +1607,7 @@ static int scst_pre_exec(struct scst_cmd *cmd)
spin_unlock_bh(&dev->dev_lock);
if (done)
goto out_done;
goto out_complete;
}
}
@@ -1575,10 +1617,36 @@ static int scst_pre_exec(struct scst_cmd *cmd)
{
rc = scst_set_pending_UA(cmd);
if (rc == 0)
goto out_done;
goto out_complete;
}
}
res = 0;
out:
TRACE_EXIT_RES(res);
return res;
out_complete:
res = 1;
goto out;
out_uncomplete:
res = -1;
goto out;
}
/*
* The result of cmd execution, if any, should be reported
* via scst_cmd_done_local()
*/
static int scst_pre_exec(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED;
struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
TRACE_ENTRY();
/* Check READ_ONLY device status */
if (tgt_dev->acg_dev->rd_only_flag &&
(cmd->cdb[0] == WRITE_6 || /* ToDo: full list of the modify cmds */
@@ -1595,6 +1663,7 @@ static int scst_pre_exec(struct scst_cmd *cmd)
SCST_LOAD_SENSE(scst_sense_data_protect));
goto out_done;
}
out:
TRACE_EXIT_RES(res);
return res;
@@ -1667,11 +1736,6 @@ static int scst_do_send_to_midlev(struct scst_cmd *cmd)
set_bit(SCST_CMD_EXECUTING, &cmd->cmd_flags);
smp_mb__after_set_bit();
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
TRACE_MGMT_DBG("ABORTED set, aborting cmd %p", cmd);
goto out_aborted;
}
rc = scst_pre_exec(cmd);
/* !! At this point cmd, sess & tgt_dev can be already freed !! */
if (rc != SCST_EXEC_NOT_COMPLETED) {
@@ -1721,6 +1785,14 @@ static int scst_do_send_to_midlev(struct scst_cmd *cmd)
goto out_error;
}
rc = scst_check_local_events(cmd);
if (unlikely(rc != 0)) {
if (rc > 0)
goto out_compl;
else
goto out_aborted;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
if (unlikely(scst_alloc_request(cmd) != 0)) {
if (scst_cmd_atomic(cmd)) {
@@ -1772,8 +1844,9 @@ out_rc_error:
out_error:
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
out_compl:
cmd->completed = 1;
cmd->state = SCST_CMD_STATE_DEV_DONE;
rc = SCST_EXEC_COMPLETED;
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
goto out;
@@ -1781,10 +1854,7 @@ out_error:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
out_busy:
scst_set_busy(cmd);
cmd->completed = 1;
cmd->state = SCST_CMD_STATE_DEV_DONE;
rc = SCST_EXEC_COMPLETED;
scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
goto out_compl;
goto out;
#endif