Re: [PATCH 05/19] target: Allocate sg-list correctly

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2017-05-04 at 15:50 -0700, Bart Van Assche wrote:
> Avoid that the iSCSI target driver complains about "Initial page entry
> out-of-bounds" and closes the connection if the SCSI Data-Out buffer
> is larger than the buffer size specified through the CDB. This patch
> prevents that running the libiscsi regression tests against LIO trigger
> an infinite loop of libiscsi submitting a command, LIO closing the
> connection and libiscsi resubmitting the same command.
> 

This statement and patch is incorrect.

target-core has always rejected SCF_SCSI_DATA_CDB WRITEs with
overflow/underflow since day one:

>From target_cmd_size_check():

        } else if (size != cmd->data_length) {
                pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
                        " %u does not match SCSI CDB Length: %u for SAM Opcode:"
                        " 0x%02x\n", cmd->se_tfo->get_fabric_name(),
                                cmd->data_length, size, cmd->t_task_cdb[0]);

                if (cmd->data_direction == DMA_TO_DEVICE &&
                    cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
                        pr_err("Rejecting underflow/overflow WRITE data\n");
                        return TCM_INVALID_CDB_FIELD;
                }

                ......
        }

The reason you're suddenly hitting this now is because your patch in
target-pending/for-next:

   commit 0e2eb7d12eaa8e391bf5615d4271bb87a649caaa
   Author: Bart Van Assche <bart.vanassche@xxxxxxxxxxx>
   Date:   Thu Mar 30 10:12:39 2017 -0700

incorrectly started allowing WRITE_VERIFY_* w/ bytchk = 0, without
actually setting SCF_SCSI_DATA_CDB in sbc_parse_verify():

        switch (bytchk) {
        case 0:
                *bufflen = 0;
                break;
        case 1:
                *bufflen = sbc_get_size(cmd, *sectors);
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
                break;
        default:
                pr_err("Unsupported BYTCHK value %d for SCSI opcode %#x\n",
                       bytchk, cdb[0]);
                return TCM_INVALID_CDB_FIELD;
        }

Patch #18 is also trying to (incorrectly) address the same problem.

I'll post the proper fix for the regression introduced by your earlier
patch there.

> Signed-off-by: Bart Van Assche <bart.vanassche@xxxxxxxxxxx>
> Cc: Hannes Reinecke <hare@xxxxxxxx>
> Cc: Christoph Hellwig <hch@xxxxxx>
> Cc: Andy Grover <agrover@xxxxxxxxxx>
> Cc: David Disseldorp <ddiss@xxxxxxx>
> Cc: <stable@xxxxxxxxxxxxxxx>
> ---
>  drivers/target/target_core_transport.c | 29 ++++++++++-------------------
>  include/target/target_core_base.h      |  4 +++-
>  2 files changed, 13 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
> index df1ceb2dd110..86b6b0238975 100644
> --- a/drivers/target/target_core_transport.c
> +++ b/drivers/target/target_core_transport.c
> @@ -1159,11 +1159,11 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
>  
>  	if (cmd->unknown_data_length) {
>  		cmd->data_length = size;
> -	} else if (size != cmd->data_length) {
> +	} else if (size != cmd->buffer_length) {
>  		pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
>  			" %u does not match SCSI CDB Length: %u for SAM Opcode:"
>  			" 0x%02x\n", cmd->se_tfo->get_fabric_name(),
> -				cmd->data_length, size, cmd->t_task_cdb[0]);
> +			cmd->buffer_length, size, cmd->t_task_cdb[0]);
>  
>  		if (cmd->data_direction == DMA_TO_DEVICE &&
>  		    cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
> @@ -1183,7 +1183,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
>  		}
>  		/*
>  		 * For the overflow case keep the existing fabric provided
> -		 * ->data_length.  Otherwise for the underflow case, reset
> +		 * ->buffer_length.  Otherwise for the underflow case, reset
>  		 * ->data_length to the smaller SCSI expected data transfer
>  		 * length.
>  		 */
> @@ -1227,6 +1227,7 @@ void transport_init_se_cmd(
>  
>  	cmd->se_tfo = tfo;
>  	cmd->se_sess = se_sess;
> +	cmd->buffer_length = data_length;
>  	cmd->data_length = data_length;
>  	cmd->data_direction = data_direction;
>  	cmd->sam_task_attr = task_attr;
> @@ -2412,41 +2413,31 @@ transport_generic_new_cmd(struct se_cmd *cmd)
>  	 * beforehand.
>  	 */
>  	if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) &&
> -	    cmd->data_length) {
> +	    cmd->buffer_length) {
>  
>  		if ((cmd->se_cmd_flags & SCF_BIDI) ||
>  		    (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) {
> -			u32 bidi_length;
> -
> -			if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)
> -				bidi_length = cmd->t_task_nolb *
> -					      cmd->se_dev->dev_attrib.block_size;
> -			else
> -				bidi_length = cmd->data_length;
> -
>  			ret = target_alloc_sgl(&cmd->t_bidi_data_sg,
>  					       &cmd->t_bidi_data_nents,
> -					       bidi_length, zero_flag, false);
> +					       cmd->buffer_length, zero_flag,
> +					       false);
>  			if (ret < 0)
>  				return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
>  		}
>  
>  		ret = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents,
> -				       cmd->data_length, zero_flag, false);
> +				       cmd->buffer_length, zero_flag, false);
>  		if (ret < 0)
>  			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
>  	} else if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
> -		    cmd->data_length) {
> +		    cmd->buffer_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, false);
> +				       cmd->buffer_length, zero_flag, false);
>  		if (ret < 0)
>  			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
>  	}
> diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
> index 49cd03c2d943..0660585cb03d 100644
> --- a/include/target/target_core_base.h
> +++ b/include/target/target_core_base.h
> @@ -455,7 +455,9 @@ struct se_cmd {
>  	enum transport_state_table t_state;
>  	/* See se_cmd_flags_table */
>  	u32			se_cmd_flags;
> -	/* Total size in bytes associated with command */
> +	/* Length of Data-Out or Data-In buffer */
> +	u32			buffer_length;
> +	/* Number of bytes affected on storage medium */
>  	u32			data_length;
>  	u32			residual_count;
>  	u64			orig_fe_lun;





[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]