From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> This patch converts the TCM_Loop virtual SCSI LLD fabric module to use the new struct target_core_fabrics_ops->new_cmd_map() caller added in commit f3b8d9dfe00. This allows TCM_Loop to do second stage setup of new struct se_cmd descriptors directly within TCM processing thread context, and allows us to drop it's internal per struct tcm_loop_hba->tl_hba_qobj and ->tl_kthread members. This means that tcm_loop_processing_thread() processing of seperate TCM_Loop HBA queue in kthreads now goes away, and the original tcm_loop_execute_core_cmd() now becomes the TFO->new_cmd_map() caller at tcm_loop_new_cmd_map(). This function is called directly from TCM backstore processing thread context after se_cmd->transport_add_cmd_to_queue(se_cmd, TRANSPORT_NEW_CMD_MAP) is invoked by tcm_loop_queuecommand() from within interrupt context. This has been tested so far in KVM guest v2.6.36-rc3 with TCM/FILEIO backstores Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx> --- drivers/target/tcm_loop/tcm_loop_configfs.c | 35 +------- drivers/target/tcm_loop/tcm_loop_core.h | 2 - drivers/target/tcm_loop/tcm_loop_fabric.c | 61 -------------- drivers/target/tcm_loop/tcm_loop_fabric.h | 2 - drivers/target/tcm_loop/tcm_loop_fabric_scsi.c | 100 +++++++----------------- drivers/target/tcm_loop/tcm_loop_fabric_scsi.h | 2 +- 6 files changed, 34 insertions(+), 168 deletions(-) diff --git a/drivers/target/tcm_loop/tcm_loop_configfs.c b/drivers/target/tcm_loop/tcm_loop_configfs.c index fa4d82a..dd60cbf 100644 --- a/drivers/target/tcm_loop/tcm_loop_configfs.c +++ b/drivers/target/tcm_loop/tcm_loop_configfs.c @@ -449,17 +449,6 @@ check_len: snprintf(&tl_hba->tl_wwn_address[0], TL_WWN_ADDR_LEN, "%s", &name[off]); /* - * Setup the tl_hba->tl_hba_qobj - */ - tl_hba->tl_hba_qobj = kzalloc(sizeof(struct se_queue_obj), GFP_KERNEL); - if (!(tl_hba->tl_hba_qobj)) { - kfree(tl_hba); - printk("Unable to allocate tl_hba->tl_hba_qobj\n"); - return ERR_PTR(-ENOMEM); - } - transport_init_queue_obj(tl_hba->tl_hba_qobj); - - /* * Call device_register(tl_hba->dev) to register the emulated * Linux/SCSI LLD of type struct Scsi_Host at tl_hba->sh after * device_register() callbacks in tcm_loop_driver_probe() @@ -469,19 +458,6 @@ check_len: goto out; sh = tl_hba->sh; - /* - * Start up the per struct Scsi_Host tcm_loop processing thread - */ - tl_hba->tl_kthread = kthread_run(tcm_loop_processing_thread, - (void *)tl_hba, "tcm_loop_%d", sh->host_no); - if (IS_ERR(tl_hba->tl_kthread)) { - printk(KERN_ERR "Unable to start tcm_loop kthread\n"); - device_unregister(&tl_hba->dev); - ret = -ENOMEM; - goto out; - } - wait_for_completion(&tl_hba->tl_hba_qobj->thread_create_comp); - tcm_loop_hba_no_cnt++; printk(KERN_INFO "TCM_Loop_ConfigFS: Allocated emulated Target" " %s Address: %s at Linux/SCSI Host ID: %d\n", @@ -489,7 +465,6 @@ check_len: return &tl_hba->tl_hba_wwn; out: - kfree(tl_hba->tl_hba_qobj); kfree(tl_hba); return ERR_PTR(ret); } @@ -500,12 +475,6 @@ void tcm_loop_drop_scsi_hba( struct tcm_loop_hba *tl_hba = container_of(wwn, struct tcm_loop_hba, tl_hba_wwn); int host_no = tl_hba->sh->host_no; - - /* - * Shutdown the per HBA tcm_loop processing kthread - */ - kthread_stop(tl_hba->tl_kthread); - wait_for_completion(&tl_hba->tl_hba_qobj->thread_done_comp); /* * Call device_unregister() on the original tl_hba->dev. * tcm_loop_fabric_scsi.c:tcm_loop_release_adapter() will @@ -590,6 +559,10 @@ int tcm_loop_register_configfs(void) * virtual memory address mappings */ fabric->tf_ops.alloc_cmd_iovecs = NULL; + /* + * Used for setting up remaining TCM resources in process context + */ + fabric->tf_ops.new_cmd_map = &tcm_loop_new_cmd_map; fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free; fabric->tf_ops.release_cmd_to_pool = &tcm_loop_deallocate_core_cmd; fabric->tf_ops.release_cmd_direct = &tcm_loop_deallocate_core_cmd; diff --git a/drivers/target/tcm_loop/tcm_loop_core.h b/drivers/target/tcm_loop/tcm_loop_core.h index eaebe89..69906b7 100644 --- a/drivers/target/tcm_loop/tcm_loop_core.h +++ b/drivers/target/tcm_loop/tcm_loop_core.h @@ -69,8 +69,6 @@ struct tcm_loop_hba { struct se_lun *tl_hba_lun; struct se_port *tl_hba_lun_sep; struct se_device_s *se_dev_hba_ptr; - struct se_queue_obj *tl_hba_qobj; - struct task_struct *tl_kthread; struct tcm_loop_nexus *tl_nexus; struct device dev; struct Scsi_Host *sh; diff --git a/drivers/target/tcm_loop/tcm_loop_fabric.c b/drivers/target/tcm_loop/tcm_loop_fabric.c index ef23f07..abd643d 100644 --- a/drivers/target/tcm_loop/tcm_loop_fabric.c +++ b/drivers/target/tcm_loop/tcm_loop_fabric.c @@ -455,67 +455,6 @@ u64 tcm_loop_pack_lun(unsigned int lun) return cpu_to_le64(result); } -static struct se_queue_req *tcm_loop_get_qr_from_queue(struct se_queue_obj *qobj) -{ - struct se_queue_req *qr; - unsigned long flags; - - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - if (list_empty(&qobj->qobj_list)) { - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return NULL; - } - - qr = list_first_entry(&qobj->qobj_list, struct se_queue_req, qr_list); - list_del(&qr->qr_list); - atomic_dec(&qobj->queue_cnt); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - - return qr; -} - -int tcm_loop_processing_thread(void *p) -{ - struct scsi_cmnd *sc; - struct tcm_loop_cmd *tl_cmd; - struct tcm_loop_hba *tl_hba = (struct tcm_loop_hba *)p; - struct se_queue_obj *qobj = tl_hba->tl_hba_qobj; - struct se_queue_req *qr; - int ret; - - current->policy = SCHED_NORMAL; - set_user_nice(current, -20); - spin_lock_irq(¤t->sighand->siglock); - siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - complete(&qobj->thread_create_comp); - - while (!(kthread_should_stop())) { - ret = wait_event_interruptible(qobj->thread_wq, - atomic_read(&qobj->queue_cnt) || kthread_should_stop()); - if (ret < 0) - goto out; - - qr = tcm_loop_get_qr_from_queue(qobj); - if (!(qr)) - continue; - - tl_cmd = (struct tcm_loop_cmd *)qr->cmd; - sc = tl_cmd->sc; - kfree(qr); - - TL_CDB_DEBUG("processing_thread, calling tcm_loop_execute" - "_core_cmd() for tl_cmd: %p, sc: %p\n", tl_cmd, sc); - tcm_loop_execute_core_cmd(tl_cmd, sc); - } - -out: - complete(&qobj->thread_done_comp); - return 0; -} - static int __init tcm_loop_fabric_init(void) { int ret; diff --git a/drivers/target/tcm_loop/tcm_loop_fabric.h b/drivers/target/tcm_loop/tcm_loop_fabric.h index dde23c5..eef5165 100644 --- a/drivers/target/tcm_loop/tcm_loop_fabric.h +++ b/drivers/target/tcm_loop/tcm_loop_fabric.h @@ -41,5 +41,3 @@ extern int tcm_loop_queue_tm_rsp(struct se_cmd *); extern u16 tcm_loop_set_fabric_sense_len(struct se_cmd *, u32); extern u16 tcm_loop_get_fabric_sense_len(void); extern u64 tcm_loop_pack_lun(unsigned int); - -extern int tcm_loop_processing_thread(void *); diff --git a/drivers/target/tcm_loop/tcm_loop_fabric_scsi.c b/drivers/target/tcm_loop/tcm_loop_fabric_scsi.c index 126f311..78476bc 100644 --- a/drivers/target/tcm_loop/tcm_loop_fabric_scsi.c +++ b/drivers/target/tcm_loop/tcm_loop_fabric_scsi.c @@ -54,12 +54,13 @@ * * Can be called from interrupt context in tcm_loop_queuecommand() below */ -static struct tcm_loop_cmd *tcm_loop_allocate_core_cmd( +static struct se_cmd *tcm_loop_allocate_core_cmd( struct tcm_loop_hba *tl_hba, struct se_portal_group *se_tpg, struct scsi_cmnd *sc, int data_direction) { + struct se_cmd *se_cmd; struct se_session *se_sess; struct tcm_loop_nexus *tl_nexus = tl_hba->tl_nexus; struct tcm_loop_cmd *tl_cmd; @@ -109,62 +110,37 @@ static struct tcm_loop_cmd *tcm_loop_allocate_core_cmd( kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); return NULL; } - - return tl_cmd; -} - -/* - * Queue up the newly allocated struct tcm_loop_cmd to be processed by - * tcm_loop_fabri.c:tcm_loop_processing_thread() - * - * Can be called from interrupt context in tcm_loop_queuecommand() below - */ -static int tcm_loop_queue_core_cmd( - struct se_queue_obj *qobj, - struct tcm_loop_cmd *tl_cmd) -{ - struct se_queue_req *qr; - unsigned long flags; - - qr = kzalloc(sizeof(struct se_queue_req), GFP_ATOMIC); - if (!(qr)) { - printk(KERN_ERR "Unable to allocate memory for" - " struct se_queue_req\n"); - return -1; + se_cmd = tl_cmd->tl_se_cmd; + /* + * Locate the struct se_lun pointer and attach it to struct se_cmd + */ + if (transport_get_lun_for_cmd(se_cmd, NULL, + tl_cmd->sc->device->lun) < 0) { + /* NON_EXISTENT_LUN */ + transport_send_check_condition_and_sense(se_cmd, + se_cmd->scsi_sense_reason, 0); + return 0; } - INIT_LIST_HEAD(&qr->qr_list); - - qr->cmd = (void *)tl_cmd; - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - list_add_tail(&qr->qr_list, &qobj->qobj_list); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + /* + * Make early call to setup se_cmd->transport_add_cmd_to_queue() pointer + */ + transport_device_setup_cmd(se_cmd); - atomic_inc(&qobj->queue_cnt); - wake_up_interruptible(&qobj->thread_wq); - return 0; + return se_cmd; } /* - * Called by tcm_loop_processing_thread() in tcm_loop_fabric.c + * Called by struct target_core_fabric_ops->new_cmd_map() * * Always called in process context */ -int tcm_loop_execute_core_cmd(struct tcm_loop_cmd *tl_cmd, struct scsi_cmnd *sc) +int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) { - struct se_cmd *se_cmd = tl_cmd->tl_se_cmd; + struct tcm_loop_cmd *tl_cmd = se_cmd->se_fabric_cmd_ptr; + struct scsi_cmnd *sc = tl_cmd->sc; void *mem_ptr; int ret; /* - * Locate the struct se_lun pointer and attach it to struct se_cmd - */ - if (transport_get_lun_for_cmd(se_cmd, NULL, - tl_cmd->sc->device->lun) < 0) { - /* NON_EXISTENT_LUN */ - transport_send_check_condition_and_sense(se_cmd, - se_cmd->scsi_sense_reason, 0); - return 0; - } - /* * Allocate the necessary tasks to complete the received CDB+data */ ret = transport_generic_allocate_tasks(se_cmd, tl_cmd->sc->cmnd); @@ -213,11 +189,8 @@ int tcm_loop_execute_core_cmd(struct tcm_loop_cmd *tl_cmd, struct scsi_cmnd *sc) TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); return 0; } - /* - * Queue up the struct se_cmd + tasks to be processed by the - * TCM storage object. - */ - return transport_generic_handle_cdb(se_cmd); + + return 0; } /* @@ -333,9 +306,9 @@ static int tcm_loop_queuecommand( struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) { + struct se_cmd *se_cmd; struct se_portal_group *se_tpg; struct Scsi_Host *host = sc->device->host; - struct tcm_loop_cmd *tl_cmd; struct tcm_loop_hba *tl_hba; struct tcm_loop_tpg *tl_tpg; int data_direction; @@ -380,31 +353,17 @@ static int tcm_loop_queuecommand( * Determine the SAM Task Attribute and allocate tl_cmd and * tl_cmd->tl_se_cmd from TCM infrastructure */ - tl_cmd = tcm_loop_allocate_core_cmd(tl_hba, se_tpg, sc, data_direction); - if (!(tl_cmd)) { + se_cmd = tcm_loop_allocate_core_cmd(tl_hba, se_tpg, sc, data_direction); + if (!(se_cmd)) { spin_lock_irq(host->host_lock); sc->result = host_byte(DID_ERROR); (*done)(sc); return 0; } /* - * Queue the tl_cmd to be executed in process context by the - * tcm_loop kernel thread - */ - if (tcm_loop_queue_core_cmd(tl_hba->tl_hba_qobj, tl_cmd) < 0) { - /* - * Will free both struct tcm_loop_cmd and struct se_cmd - */ - transport_release_cmd_to_pool(tl_cmd->tl_se_cmd); - /* - * Reaquire the struct scsi_host->host_lock, and - * complete the struct scsi_cmnd - */ - spin_lock_irq(host->host_lock); - sc->result = host_byte(DID_ERROR); - (*done)(sc); - return 0; - } + * Queue up the newly allocated to be processed in TCM thread context. + */ + se_cmd->transport_add_cmd_to_queue(se_cmd, TRANSPORT_NEW_CMD_MAP); /* * Reaquire the the struct scsi_host->host_lock before returning */ @@ -585,7 +544,6 @@ static void tcm_loop_release_adapter(struct device *dev) { struct tcm_loop_hba *tl_hba = to_tcm_loop_hba(dev); - kfree(tl_hba->tl_hba_qobj); kfree(tl_hba); } diff --git a/drivers/target/tcm_loop/tcm_loop_fabric_scsi.h b/drivers/target/tcm_loop/tcm_loop_fabric_scsi.h index c93e610..bcba89b 100644 --- a/drivers/target/tcm_loop/tcm_loop_fabric_scsi.h +++ b/drivers/target/tcm_loop/tcm_loop_fabric_scsi.h @@ -1,6 +1,6 @@ extern struct kmem_cache *tcm_loop_cmd_cache; -extern int tcm_loop_execute_core_cmd(struct tcm_loop_cmd *, struct scsi_cmnd *); +extern int tcm_loop_new_cmd_map(struct se_cmd *); extern void tcm_loop_check_stop_free(struct se_cmd *); extern void tcm_loop_deallocate_core_cmd(struct se_cmd *); extern void tcm_loop_scsi_forget_host(struct Scsi_Host *); -- 1.5.6.5 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html