mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-21 12:41:26 +00:00
- 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:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user