From 0bcc297e2b45c12baf735e1dc1f163e71ea55e16 Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Fri, 6 Jun 2014 17:15:16 +0200 Subject: target: cleanup some boolean tests Convert "x == true" to "x" and "x == false" to "!x". Signed-off-by: Christophe Vu-Brugier Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 789aa9eb0a1e..5f192cafbb79 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -504,7 +504,7 @@ void transport_deregister_session(struct se_session *se_sess) * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group * removal context. */ - if (se_nacl && comp_nacl == true) + if (se_nacl && comp_nacl) target_put_nacl(se_nacl); transport_free_session(se_sess); @@ -2363,7 +2363,7 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, * fabric acknowledgement that requires two target_put_sess_cmd() * invocations before se_cmd descriptor release. */ - if (ack_kref == true) { + if (ack_kref) { kref_get(&se_cmd->cmd_kref); se_cmd->se_cmd_flags |= SCF_ACK_KREF; } -- cgit v1.2.3 From f15e9cd910c4d9da7de43f2181f362082fc45f0f Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 9 Jun 2014 23:13:20 +0000 Subject: target: Set CMD_T_ACTIVE bit for Task Management Requests This patch fixes a bug where se_cmd descriptors associated with a Task Management Request (TMR) where not setting CMD_T_ACTIVE before being dispatched into target_tmr_work() process context. This is required in order for transport_generic_free_cmd() -> transport_wait_for_tasks() to wait on se_cmd->t_transport_stop_comp if a session reset event occurs while an ABORT_TASK is outstanding waiting for another I/O to complete. Cc: Thomas Glanzmann Cc: Charalampos Pournaris Cc: stable@vger.kernel.org # 3.10+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 5f192cafbb79..195435bf1140 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2934,6 +2934,12 @@ static void target_tmr_work(struct work_struct *work) int transport_generic_handle_tmr( struct se_cmd *cmd) { + unsigned long flags; + + spin_lock_irqsave(&cmd->t_state_lock, flags); + cmd->transport_state |= CMD_T_ACTIVE; + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + INIT_WORK(&cmd->work, target_tmr_work); queue_work(cmd->se_dev->tmr_wq, &cmd->work); return 0; -- cgit v1.2.3 From a95d6511303b848da45ee27b35018bb58087bdc6 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 9 Jun 2014 23:36:51 +0000 Subject: target: Use complete_all for se_cmd->t_transport_stop_comp This patch fixes a bug where multiple waiters on ->t_transport_stop_comp occurs due to a concurrent ABORT_TASK and session reset both invoking transport_wait_for_tasks(), while waiting for the associated se_cmd descriptor backend processing to complete. For this case, complete_all() should be invoked in order to wake up both waiters in core_tmr_abort_task() + transport_generic_free_cmd() process contexts. Cc: Thomas Glanzmann Cc: Charalampos Pournaris Cc: stable@vger.kernel.org # 3.10+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 195435bf1140..15dbf6e97289 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -562,7 +562,7 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists, spin_unlock_irqrestore(&cmd->t_state_lock, flags); - complete(&cmd->t_transport_stop_comp); + complete_all(&cmd->t_transport_stop_comp); return 1; } @@ -687,7 +687,7 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) if (cmd->transport_state & CMD_T_ABORTED && cmd->transport_state & CMD_T_STOP) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - complete(&cmd->t_transport_stop_comp); + complete_all(&cmd->t_transport_stop_comp); return; } else if (!success) { INIT_WORK(&cmd->work, target_complete_failure_work); @@ -1761,7 +1761,7 @@ void target_execute_cmd(struct se_cmd *cmd) cmd->se_tfo->get_task_tag(cmd)); spin_unlock_irq(&cmd->t_state_lock); - complete(&cmd->t_transport_stop_comp); + complete_all(&cmd->t_transport_stop_comp); return; } -- cgit v1.2.3 From 2426bd456a61407388b6e61fc5f98dbcbebc50e2 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 10 Jun 2014 11:07:47 -0700 Subject: target: Report correct response length for some commands When an initiator sends an allocation length bigger than what its command consumes, the target should only return the actual response data and set the residual length to the unused part of the allocation length. Add a helper function that command handlers (INQUIRY, READ CAPACITY, etc) can use to do this correctly, and use this code to get the correct residual for commands that don't use the full initiator allocation in the handlers for READ CAPACITY, READ CAPACITY(16), INQUIRY, MODE SENSE and REPORT LUNS. This addresses a handful of failures as reported by Christophe with the Windows Certification Kit: http://permalink.gmane.org/gmane.linux.scsi.target.devel/6515 Signed-off-by: Roland Dreier Tested-by: Christophe Vu-Brugier Cc: stable@vger.kernel.org # 3.10+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 4 ++-- drivers/target/target_core_spc.c | 9 ++++++--- drivers/target/target_core_transport.c | 17 +++++++++++++++++ include/target/target_core_backend.h | 1 + 4 files changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 97a33603795d..1d3a626bf24f 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -81,7 +81,7 @@ sbc_emulate_readcapacity(struct se_cmd *cmd) transport_kunmap_data_sg(cmd); } - target_complete_cmd(cmd, GOOD); + target_complete_cmd_with_length(cmd, GOOD, 8); return 0; } @@ -137,7 +137,7 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd) transport_kunmap_data_sg(cmd); } - target_complete_cmd(cmd, GOOD); + target_complete_cmd_with_length(cmd, GOOD, 32); return 0; } diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 17b5b7e099fa..6cd7222738fc 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -716,6 +716,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) unsigned char *buf; sense_reason_t ret; int p; + int len = 0; buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); if (!buf) { @@ -737,6 +738,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) } ret = spc_emulate_inquiry_std(cmd, buf); + len = buf[4] + 5; goto out; } @@ -744,6 +746,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) if (cdb[2] == evpd_handlers[p].page) { buf[1] = cdb[2]; ret = evpd_handlers[p].emulate(cmd, buf); + len = get_unaligned_be16(&buf[2]) + 4; goto out; } } @@ -760,7 +763,7 @@ out: kfree(buf); if (!ret) - target_complete_cmd(cmd, GOOD); + target_complete_cmd_with_length(cmd, GOOD, len); return ret; } @@ -1098,7 +1101,7 @@ set_length: transport_kunmap_data_sg(cmd); } - target_complete_cmd(cmd, GOOD); + target_complete_cmd_with_length(cmd, GOOD, length); return 0; } @@ -1274,7 +1277,7 @@ done: buf[3] = (lun_count & 0xff); transport_kunmap_data_sg(cmd); - target_complete_cmd(cmd, GOOD); + target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8); return 0; } EXPORT_SYMBOL(spc_emulate_report_luns); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 15dbf6e97289..c9e8b35a954f 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -703,6 +703,23 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) } EXPORT_SYMBOL(target_complete_cmd); +void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) +{ + if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) { + if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { + cmd->residual_count += cmd->data_length - length; + } else { + cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; + cmd->residual_count = cmd->data_length - length; + } + + cmd->data_length = length; + } + + target_complete_cmd(cmd, scsi_status); +} +EXPORT_SYMBOL(target_complete_cmd_with_length); + static void target_add_to_state_list(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 3a1c1eea1fff..9adc1bca1178 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -59,6 +59,7 @@ int transport_subsystem_register(struct se_subsystem_api *); void transport_subsystem_release(struct se_subsystem_api *); void target_complete_cmd(struct se_cmd *, u8); +void target_complete_cmd_with_length(struct se_cmd *, u8, int); sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size); sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd); -- cgit v1.2.3 From 0ed6e189e3f6ac3a25383ed5cc8b0ac24c9b97b7 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 12 Jun 2014 12:45:02 -0700 Subject: target: Fix NULL pointer dereference for XCOPY in target_put_sess_cmd This patch fixes a NULL pointer dereference regression bug that was introduced with: commit 1e1110c43b1cda9fe77fc4a04835e460550e6b3c Author: Mikulas Patocka Date: Sat May 17 06:49:22 2014 -0400 target: fix memory leak on XCOPY Now that target_put_sess_cmd() -> kref_put_spinlock_irqsave() is called with a valid se_cmd->cmd_kref, a NULL pointer dereference is triggered because the XCOPY passthrough commands don't have an associated se_session pointer. To address this bug, go ahead and checking for a NULL se_sess pointer within target_put_sess_cmd(), and call se_cmd->se_tfo->release_cmd() to release the XCOPY's xcopy_pt_cmd memory. Reported-by: Thomas Glanzmann Cc: Thomas Glanzmann Cc: Mikulas Patocka Cc: stable@vger.kernel.org # 3.12+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index c9e8b35a954f..4ef11145c746 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2424,6 +2424,10 @@ static void target_release_cmd_kref(struct kref *kref) */ int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) { + if (!se_sess) { + se_cmd->se_tfo->release_cmd(se_cmd); + return 1; + } return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref, &se_sess->sess_cmd_lock); } -- cgit v1.2.3