- In scst_user fixed potential deadlock
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Fri, 3 Aug 2007 09:57:15 +0000 (09:57 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Fri, 3 Aug 2007 09:57:15 +0000 (09:57 +0000)
 - scst_check_local_events() added
 - Minor cleanups and fixes

git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@155 d57e44dd-8a1f-0410-8b47-8ef2f437770f

13 files changed:
scst/ToDo
scst/include/scsi_tgt.h
scst/src/Makefile
scst/src/dev_handlers/scst_disk.c
scst/src/dev_handlers/scst_modisk.c
scst/src/dev_handlers/scst_tape.c
scst/src/dev_handlers/scst_user.c
scst/src/dev_handlers/scst_vdisk.c
scst/src/scst.c
scst/src/scst_lib.c
scst/src/scst_mem.c
scst/src/scst_proc.c
scst/src/scst_targ.c

index daa5d30..a8c0160 100644 (file)
--- a/scst/ToDo
+++ b/scst/ToDo
@@ -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.
index 71d48f5..eebe43e 100644 (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
index ccd3694..2bca091 100644 (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:
index b32f886..0a6e587 100644 (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");
index b1d420c..42f0a83 100644 (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");
index bdbb655..bd9a0d3 100644 (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");
index 9b6bad2..7aad5e2 100644 (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);
 
index a0399ad..1d76d76 100644 (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);
index 70b4a2a..15003bb 100644 (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);
index 7204ac0..a169c1f 100644 (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)
index 2361912..f97e65b 100644 (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,
index f4832a4..78136f4 100644 (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,
index c0e921c..ae08f1c 100644 (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