From: <vl...@us...> - 2007-08-03 09:57:45
|
Revision: 155 http://scst.svn.sourceforge.net/scst/?rev=155&view=rev Author: vlnb Date: 2007-08-03 02:57:15 -0700 (Fri, 03 Aug 2007) Log Message: ----------- - In scst_user fixed potential deadlock - scst_check_local_events() added - Minor cleanups and fixes Modified Paths: -------------- trunk/scst/ToDo trunk/scst/include/scsi_tgt.h trunk/scst/src/Makefile trunk/scst/src/dev_handlers/scst_disk.c trunk/scst/src/dev_handlers/scst_modisk.c trunk/scst/src/dev_handlers/scst_tape.c trunk/scst/src/dev_handlers/scst_user.c trunk/scst/src/dev_handlers/scst_vdisk.c trunk/scst/src/scst.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_mem.c trunk/scst/src/scst_proc.c trunk/scst/src/scst_targ.c Modified: trunk/scst/ToDo =================================================================== --- trunk/scst/ToDo 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/ToDo 2007-08-03 09:57:15 UTC (rev 155) @@ -8,7 +8,7 @@ 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 @@ - 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. Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/include/scsi_tgt.h 2007-08-03 09:57:15 UTC (rev 155) @@ -678,6 +678,9 @@ * 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_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 Modified: trunk/scst/src/Makefile =================================================================== --- trunk/scst/src/Makefile 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/Makefile 2007-08-03 09:57:15 UTC (rev 155) @@ -117,7 +117,7 @@ # 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: Modified: trunk/scst/src/dev_handlers/scst_disk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_disk.c 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/dev_handlers/scst_disk.c 2007-08-03 09:57:15 UTC (rev 155) @@ -344,11 +344,19 @@ ********************************************************************/ 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 @@ 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"); Modified: trunk/scst/src/dev_handlers/scst_modisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_modisk.c 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/dev_handlers/scst_modisk.c 2007-08-03 09:57:15 UTC (rev 155) @@ -358,11 +358,19 @@ ********************************************************************/ 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 @@ 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"); Modified: trunk/scst/src/dev_handlers/scst_tape.c =================================================================== --- trunk/scst/src/dev_handlers/scst_tape.c 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/dev_handlers/scst_tape.c 2007-08-03 09:57:15 UTC (rev 155) @@ -389,26 +389,40 @@ ********************************************************************/ 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"); Modified: trunk/scst/src/dev_handlers/scst_user.c =================================================================== --- trunk/scst/src/dev_handlers/scst_user.c 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/dev_handlers/scst_user.c 2007-08-03 09:57:15 UTC (rev 155) @@ -191,7 +191,7 @@ 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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ */ 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 @@ 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 @@ 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_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 @@ 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 @@ 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,16 +2790,20 @@ 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); TRACE_DBG("Releasing dev %p", dev); Modified: trunk/scst/src/dev_handlers/scst_vdisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_vdisk.c 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/dev_handlers/scst_vdisk.c 2007-08-03 09:57:15 UTC (rev 155) @@ -636,6 +636,7 @@ 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 @@ 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); Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/scst.c 2007-08-03 09:57:15 UTC (rev 155) @@ -1656,6 +1656,8 @@ 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); Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/scst_lib.c 2007-08-03 09:57:15 UTC (rev 155) @@ -2699,7 +2699,7 @@ #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 @@ 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 @@ { 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 @@ 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) Modified: trunk/scst/src/scst_mem.c =================================================================== --- trunk/scst/src/scst_mem.c 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/scst_mem.c 2007-08-03 09:57:15 UTC (rev 155) @@ -210,8 +210,9 @@ 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, Modified: trunk/scst/src/scst_proc.c =================================================================== --- trunk/scst/src/scst_proc.c 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/scst_proc.c 2007-08-03 09:57:15 UTC (rev 155) @@ -1694,12 +1694,12 @@ 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, Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2007-07-31 14:21:46 UTC (rev 154) +++ trunk/scst/src/scst_targ.c 2007-08-03 09:57:15 UTC (rev 155) @@ -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 @@ 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 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 @@ 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 @@ out_done: cmd->completed = 1; +out_uncompl: /* Report the result */ scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT); @@ -1388,16 +1403,7 @@ 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 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 @@ 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: 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 @@ } 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 @@ 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 @@ (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 @@ spin_unlock_bh(&dev->dev_lock); if (done) - goto out_done; + goto out_complete; } } @@ -1575,10 +1617,36 @@ { 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 @@ SCST_LOAD_SENSE(scst_sense_data_protect)); goto out_done; } + out: TRACE_EXIT_RES(res); return res; @@ -1667,11 +1736,6 @@ 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 @@ 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_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 @@ #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 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |