From patchwork Wed May 6 09:51:20 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Henriques X-Patchwork-Id: 468752 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id 0B2D51402C6; Wed, 6 May 2015 19:54:17 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1Ypw1t-0003me-3n; Wed, 06 May 2015 09:54:13 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1Ypvz7-0001c7-VB for kernel-team@lists.ubuntu.com; Wed, 06 May 2015 09:51:21 +0000 Received: from av-217-129-142-138.netvisao.pt ([217.129.142.138] helo=localhost) by youngberry.canonical.com with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1Ypvz7-0001Rx-IL; Wed, 06 May 2015 09:51:21 +0000 From: Luis Henriques To: Nicholas Bellinger Subject: [3.16.y-ckt stable] Patch "target: Fix COMPARE_AND_WRITE with SG_TO_MEM_NOALLOC handling" has been added to staging queue Date: Wed, 6 May 2015 10:51:20 +0100 Message-Id: <1430905880-27748-1-git-send-email-luis.henriques@canonical.com> X-Mailer: git-send-email 2.1.4 X-Extended-Stable: 3.16 Cc: kernel-team@lists.ubuntu.com, Christoph Hellwig X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: kernel-team-bounces@lists.ubuntu.com This is a note to let you know that I have just added a patch titled target: Fix COMPARE_AND_WRITE with SG_TO_MEM_NOALLOC handling to the linux-3.16.y-queue branch of the 3.16.y-ckt extended stable tree which can be found at: http://kernel.ubuntu.com/git/ubuntu/linux.git/log/?h=linux-3.16.y-queue This patch is scheduled to be released in version 3.16.7-ckt11. If you, or anyone else, feels it should not be added to this tree, please reply to this email. For more information about the 3.16.y-ckt tree, see https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable Thanks. -Luis ------ From 8c4938438c1d9025ef5efa2cd7a5b66d45d0fe44 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 7 Apr 2015 21:53:27 +0000 Subject: target: Fix COMPARE_AND_WRITE with SG_TO_MEM_NOALLOC handling commit c8e639852ad720499912acedfd6b072325fd2807 upstream. This patch fixes a bug for COMPARE_AND_WRITE handling with fabrics using SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC. It adds the missing allocation for cmd->t_bidi_data_sg within transport_generic_new_cmd() that is used by COMPARE_AND_WRITE for the initial READ payload, even if the fabric is already providing a pre-allocated buffer for cmd->t_data_sg. Also, fix zero-length COMPARE_AND_WRITE handling within the compare_and_write_callback() and target_complete_ok_work() to queue the response, skipping the initial READ. This fixes COMPARE_AND_WRITE emulation with loopback, vhost, and xen-backend fabric drivers using SG_TO_MEM_NOALLOC. Reported-by: Christoph Hellwig Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger Signed-off-by: Luis Henriques --- drivers/target/target_core_sbc.c | 15 +++++++++----- drivers/target/target_core_transport.c | 37 ++++++++++++++++++++++++++++++---- include/target/target_core_base.h | 2 +- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index ccddbd1d97ed..be2a1000e3dd 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -299,7 +299,7 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o return 0; } -static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd) +static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success) { unsigned char *buf, *addr; struct scatterlist *sg; @@ -363,7 +363,7 @@ sbc_execute_rw(struct se_cmd *cmd) cmd->data_direction); } -static sense_reason_t compare_and_write_post(struct se_cmd *cmd) +static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success) { struct se_device *dev = cmd->se_dev; @@ -386,7 +386,7 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd) return TCM_NO_SENSE; } -static sense_reason_t compare_and_write_callback(struct se_cmd *cmd) +static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success) { struct se_device *dev = cmd->se_dev; struct scatterlist *write_sg = NULL, *sg; @@ -401,11 +401,16 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd) /* * Handle early failure in transport_generic_request_failure(), - * which will not have taken ->caw_mutex yet.. + * which will not have taken ->caw_sem yet.. */ - if (!cmd->t_data_sg || !cmd->t_bidi_data_sg) + if (!success && (!cmd->t_data_sg || !cmd->t_bidi_data_sg)) return TCM_NO_SENSE; /* + * Handle special case for zero-length COMPARE_AND_WRITE + */ + if (!cmd->data_length) + goto out; + /* * Immediately exit + release dev->caw_sem if command has already * been failed with a non-zero SCSI status. */ diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 83b0d08c9d5b..b32cbb8ab5b8 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1613,11 +1613,11 @@ void transport_generic_request_failure(struct se_cmd *cmd, transport_complete_task_attr(cmd); /* * Handle special case for COMPARE_AND_WRITE failure, where the - * callback is expected to drop the per device ->caw_mutex. + * callback is expected to drop the per device ->caw_sem. */ if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && cmd->transport_complete_callback) - cmd->transport_complete_callback(cmd); + cmd->transport_complete_callback(cmd, false); switch (sense_reason) { case TCM_NON_EXISTENT_LUN: @@ -1978,8 +1978,12 @@ static void target_complete_ok_work(struct work_struct *work) if (cmd->transport_complete_callback) { sense_reason_t rc; - rc = cmd->transport_complete_callback(cmd); + rc = cmd->transport_complete_callback(cmd, true); if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) { + if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && + !cmd->data_length) + goto queue_rsp; + return; } else if (rc) { ret = transport_send_check_condition_and_sense(cmd, @@ -1993,6 +1997,7 @@ static void target_complete_ok_work(struct work_struct *work) } } +queue_rsp: switch (cmd->data_direction) { case DMA_FROM_DEVICE: spin_lock(&cmd->se_lun->lun_sep_lock); @@ -2097,6 +2102,16 @@ static inline void transport_reset_sgl_orig(struct se_cmd *cmd) static inline void transport_free_pages(struct se_cmd *cmd) { if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) { + /* + * Release special case READ buffer payload required for + * SG_TO_MEM_NOALLOC to function with COMPARE_AND_WRITE + */ + if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) { + transport_free_sgl(cmd->t_bidi_data_sg, + cmd->t_bidi_data_nents); + cmd->t_bidi_data_sg = NULL; + cmd->t_bidi_data_nents = 0; + } transport_reset_sgl_orig(cmd); return; } @@ -2249,6 +2264,7 @@ sense_reason_t transport_generic_new_cmd(struct se_cmd *cmd) { int ret = 0; + bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB); /* * Determine is the TCM fabric module has already allocated physical @@ -2257,7 +2273,6 @@ transport_generic_new_cmd(struct se_cmd *cmd) */ if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) && cmd->data_length) { - bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB); if ((cmd->se_cmd_flags & SCF_BIDI) || (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) { @@ -2288,6 +2303,20 @@ transport_generic_new_cmd(struct se_cmd *cmd) cmd->data_length, zero_flag); if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } else if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && + cmd->data_length) { + /* + * Special case for COMPARE_AND_WRITE with fabrics + * using SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC. + */ + u32 caw_length = cmd->t_task_nolb * + cmd->se_dev->dev_attrib.block_size; + + ret = target_alloc_sgl(&cmd->t_bidi_data_sg, + &cmd->t_bidi_data_nents, + caw_length, zero_flag); + if (ret < 0) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* * If this command is not a write we can execute it right here, diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 9cbe50191dd6..edfd69a25884 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -518,7 +518,7 @@ struct se_cmd { sense_reason_t (*execute_cmd)(struct se_cmd *); sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *, u32, enum dma_data_direction); - sense_reason_t (*transport_complete_callback)(struct se_cmd *); + sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool); unsigned char *t_task_cdb; unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE];