From 5cdb901fea5483ba7004650476eb833c21790f0a Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 3 Aug 2007 09:57:15 +0000 Subject: [PATCH] - 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 --- scst/ToDo | 6 +- scst/include/scsi_tgt.h | 14 +++ scst/src/Makefile | 2 +- scst/src/dev_handlers/scst_disk.c | 32 ++++-- scst/src/dev_handlers/scst_modisk.c | 32 ++++-- scst/src/dev_handlers/scst_tape.c | 32 ++++-- scst/src/dev_handlers/scst_user.c | 131 +++++++++++++----------- scst/src/dev_handlers/scst_vdisk.c | 15 +-- scst/src/scst.c | 2 + scst/src/scst_lib.c | 10 +- scst/src/scst_mem.c | 5 +- scst/src/scst_proc.c | 4 +- scst/src/scst_targ.c | 150 ++++++++++++++++++++-------- 13 files changed, 295 insertions(+), 140 deletions(-) diff --git a/scst/ToDo b/scst/ToDo index daa5d3054..a8c016073 100644 --- 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. diff --git a/scst/include/scsi_tgt.h b/scst/include/scsi_tgt.h index 71d48f5e9..eebe43e6b 100644 --- a/scst/include/scsi_tgt.h +++ b/scst/include/scsi_tgt.h @@ -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 diff --git a/scst/src/Makefile b/scst/src/Makefile index ccd369404..2bca0910c 100644 --- a/scst/src/Makefile +++ b/scst/src/Makefile @@ -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: diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index b32f88628..0a6e587ec 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -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"); diff --git a/scst/src/dev_handlers/scst_modisk.c b/scst/src/dev_handlers/scst_modisk.c index b1d420c6d..42f0a8380 100644 --- a/scst/src/dev_handlers/scst_modisk.c +++ b/scst/src/dev_handlers/scst_modisk.c @@ -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"); diff --git a/scst/src/dev_handlers/scst_tape.c b/scst/src/dev_handlers/scst_tape.c index bdbb65588..bd9a0d357 100644 --- a/scst/src/dev_handlers/scst_tape.c +++ b/scst/src/dev_handlers/scst_tape.c @@ -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"); diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index 9b6bad206..7aad5e276 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -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); diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index a0399ad46..1d76d76ca 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -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); diff --git a/scst/src/scst.c b/scst/src/scst.c index 70b4a2a8e..15003bbaa 100644 --- a/scst/src/scst.c +++ b/scst/src/scst.c @@ -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); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 7204ac00c..a169c1f0b 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -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) diff --git a/scst/src/scst_mem.c b/scst/src/scst_mem.c index 2361912d2..f97e65ba0 100644 --- a/scst/src/scst_mem.c +++ b/scst/src/scst_mem.c @@ -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, diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c index f4832a404..78136f41d 100644 --- a/scst/src/scst_proc.c +++ b/scst/src/scst_proc.c @@ -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, diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index c0e921cb9..ae08f1cfd 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -26,6 +26,7 @@ #include #include #include +#include #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