diff mbox

[v2,1/3] scsi_cmnd: Introduce scsi_transfer_length helper

Message ID yq1mwd2h3ju.fsf@sermon.lab.mkp.net (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Martin K. Petersen June 24, 2014, 12:53 p.m. UTC
>>>>> "Mike" == Mike Christie <michaelc@cs.wisc.edu> writes:

Mike> The problem is WRITE_SAME requests are setup so that
Mike> req->__data_len is the value of the entire request when the setup
Mike> is completed but during the setup process it's value changes

Oh, I see. So things break because iSCSI uses scsi_transfer_length()
where the scatterlist length was used in the past.

How about this?


SCSI: Use SCSI data buffer length to extract transfer size
    
Commit 8846bab180fa introduced a helper that can be used to query the
wire transfer size for a SCSI command taking protection information into
account.
    
However, some commands do not have a 1:1 mapping between the block range
they work on and the payload size (discard, write same). After the
scatterlist has been set up these requests use __data_len to store the
number of bytes to report completion on. This means that callers of
scsi_transfer_length() would get the wrong byte count for these types of
requests.

To overcome this we make scsi_transfer_length() use the scatterlist
length in the scsi_data_buffer as basis for the wire transfer
calculation instead of __data_len.

Reported-by: Christoph Hellwig <hch@infradead.org>
Debugged-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Sagi Grimberg June 24, 2014, 1:08 p.m. UTC | #1
On 6/24/2014 3:53 PM, Martin K. Petersen wrote:
>>>>>> "Mike" == Mike Christie <michaelc@cs.wisc.edu> writes:
> Mike> The problem is WRITE_SAME requests are setup so that
> Mike> req->__data_len is the value of the entire request when the setup
> Mike> is completed but during the setup process it's value changes
>
> Oh, I see. So things break because iSCSI uses scsi_transfer_length()
> where the scatterlist length was used in the past.

Ohhh, didn't notice this one and sent out a duplicate...

The patch looks good to me obviously.

Sagi.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoph Hellwig June 24, 2014, 2:03 p.m. UTC | #2
On Tue, Jun 24, 2014 at 08:53:25AM -0400, Martin K. Petersen wrote:
> Oh, I see. So things break because iSCSI uses scsi_transfer_length()
> where the scatterlist length was used in the past.
> 
> How about this?

This fixes the regression for me.

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoph Hellwig June 24, 2014, 2:55 p.m. UTC | #3
On Tue, Jun 24, 2014 at 04:08:25PM +0300, Sagi Grimberg wrote:
> >Oh, I see. So things break because iSCSI uses scsi_transfer_length()
> >where the scatterlist length was used in the past.
> 
> Ohhh, didn't notice this one and sent out a duplicate...
> 
> The patch looks good to me obviously.

Can you give me a real reviewed-by?

> 
> Sagi.
---end quoted text---
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sagi Grimberg June 24, 2014, 3:29 p.m. UTC | #4
On 6/24/2014 3:53 PM, Martin K. Petersen wrote:
>
>
> SCSI: Use SCSI data buffer length to extract transfer size
>      
> Commit 8846bab180fa introduced a helper that can be used to query the
> wire transfer size for a SCSI command taking protection information into
> account.
>      
> However, some commands do not have a 1:1 mapping between the block range
> they work on and the payload size (discard, write same). After the
> scatterlist has been set up these requests use __data_len to store the
> number of bytes to report completion on. This means that callers of
> scsi_transfer_length() would get the wrong byte count for these types of
> requests.
>
> To overcome this we make scsi_transfer_length() use the scatterlist
> length in the scsi_data_buffer as basis for the wire transfer
> calculation instead of __data_len.
>
> Reported-by: Christoph Hellwig <hch@infradead.org>
> Debugged-by: Mike Christie <michaelc@cs.wisc.edu>
> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
>
> diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
> index 42ed789ebafc..e0ae71098144 100644
> --- a/include/scsi/scsi_cmnd.h
> +++ b/include/scsi/scsi_cmnd.h
> @@ -318,7 +318,7 @@ static inline void set_driver_byte(struct scsi_cmnd *cmd, char status)
>   
>   static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd)
>   {
> -	unsigned int xfer_len = blk_rq_bytes(scmd->request);
> +	unsigned int xfer_len = scsi_out(scmd)->length;
>   	unsigned int prot_op = scsi_get_prot_op(scmd);
>   	unsigned int sector_size = scmd->device->sector_size;
>   

Reviewed-by: Sagi Grimberg <sagig@mellanox.com>

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mike Christie June 24, 2014, 4:08 p.m. UTC | #5
On Jun 24, 2014, at 7:53 AM, Martin K. Petersen <martin.petersen@oracle.com> wrote:

>>>>>> "Mike" == Mike Christie <michaelc@cs.wisc.edu> writes:
> 
> Mike> The problem is WRITE_SAME requests are setup so that
> Mike> req->__data_len is the value of the entire request when the setup
> Mike> is completed but during the setup process it's value changes
> 
> Oh, I see. So things break because iSCSI uses scsi_transfer_length()
> where the scatterlist length was used in the past.
> 
> How about this?
> 
> 
> SCSI: Use SCSI data buffer length to extract transfer size
> 
> Commit 8846bab180fa introduced a helper that can be used to query the
> wire transfer size for a SCSI command taking protection information into
> account.
> 
> However, some commands do not have a 1:1 mapping between the block range
> they work on and the payload size (discard, write same). After the
> scatterlist has been set up these requests use __data_len to store the
> number of bytes to report completion on. This means that callers of
> scsi_transfer_length() would get the wrong byte count for these types of
> requests.
> 
> To overcome this we make scsi_transfer_length() use the scatterlist
> length in the scsi_data_buffer as basis for the wire transfer
> calculation instead of __data_len.
> 
> Reported-by: Christoph Hellwig <hch@infradead.org>
> Debugged-by: Mike Christie <michaelc@cs.wisc.edu>
> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
> 
> diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
> index 42ed789ebafc..e0ae71098144 100644
> --- a/include/scsi/scsi_cmnd.h
> +++ b/include/scsi/scsi_cmnd.h
> @@ -318,7 +318,7 @@ static inline void set_driver_byte(struct scsi_cmnd *cmd, char status)
> 
> static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd)
> {
> -	unsigned int xfer_len = blk_rq_bytes(scmd->request);
> +	unsigned int xfer_len = scsi_out(scmd)->length;
> 	unsigned int prot_op = scsi_get_prot_op(scmd);
> 	unsigned int sector_size = scmd->device->sector_size;


Do we need to check for the data direction. Something like

if (scmd->sc_data_direction == DMA_TO_DEVICE)
	xfer_len = scsi_out(scmnd)->length;
else
	xfer_len = scsi_in(scmnd)->length;

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoph Hellwig June 24, 2014, 4:27 p.m. UTC | #6
On Tue, Jun 24, 2014 at 11:08:54AM -0500, Michael Christie wrote:
> > static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd)
> > {
> > -	unsigned int xfer_len = blk_rq_bytes(scmd->request);
> > +	unsigned int xfer_len = scsi_out(scmd)->length;
> > 	unsigned int prot_op = scsi_get_prot_op(scmd);
> > 	unsigned int sector_size = scmd->device->sector_size;
> 
> 
> Do we need to check for the data direction. Something like
> 
> if (scmd->sc_data_direction == DMA_TO_DEVICE)
> 	xfer_len = scsi_out(scmnd)->length;
> else
> 	xfer_len = scsi_in(scmnd)->length;

For non-bidi commands those are the same, but I suspect we'd need
something like that for bidi commands.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Martin K. Petersen June 24, 2014, 4:31 p.m. UTC | #7
>>>>> "Mike" == Michael Christie <michaelc@cs.wisc.edu> writes:

Mike> Do we need to check for the data direction. Something like

Mike> if (scmd->sc_data_direction == DMA_TO_DEVICE)
Mike> 	xfer_len = scsi_out(scmnd)->length;
Mike> else
Mike> 	xfer_len = scsi_in(scmnd)->length;

I guess that depends on the context the wrapper is called in. I think
iscsi is the only place where there's a distinction thanks to bidi.

Looks like there are several places where that's done. In that case I
wonder if we should have explicit scsi_in_transfer_length() and
scsi_out_transfer_length() wrappers?
Mike Christie June 24, 2014, 5:05 p.m. UTC | #8
On 06/24/2014 11:31 AM, Martin K. Petersen wrote:
>>>>>> "Mike" == Michael Christie <michaelc@cs.wisc.edu> writes:
> 
> Mike> Do we need to check for the data direction. Something like
> 
> Mike> if (scmd->sc_data_direction == DMA_TO_DEVICE)
> Mike> 	xfer_len = scsi_out(scmnd)->length;
> Mike> else
> Mike> 	xfer_len = scsi_in(scmnd)->length;
> 
> I guess that depends on the context the wrapper is called in. I think
> iscsi is the only place where there's a distinction thanks to bidi.
> 

We were using it generically, so we did not check if bidi or t10 pi. We
were calling it just expecting it to do the right thing for us.

> Looks like there are several places where that's done. In that case I
> wonder if we should have explicit scsi_in_transfer_length() and
> scsi_out_transfer_length() wrappers?

Yeah, maybe.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 42ed789ebafc..e0ae71098144 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -318,7 +318,7 @@  static inline void set_driver_byte(struct scsi_cmnd *cmd, char status)
 
 static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd)
 {
-	unsigned int xfer_len = blk_rq_bytes(scmd->request);
+	unsigned int xfer_len = scsi_out(scmd)->length;
 	unsigned int prot_op = scsi_get_prot_op(scmd);
 	unsigned int sector_size = scmd->device->sector_size;