diff mbox series

[v2] scsi: Fix scsi_get/set_resid() interface

Message ID 20191030090847.25650-1-damien.lemoal@wdc.com (mailing list archive)
State Mainlined
Commit 9237f04e12cc385334043cd7cf84b74dcbda0256
Headers show
Series [v2] scsi: Fix scsi_get/set_resid() interface | expand

Commit Message

Damien Le Moal Oct. 30, 2019, 9:08 a.m. UTC
struct scsi_cmnd cmd->req.resid_len which is returned and set
respectively by the helper functions scsi_get_resid() and
scsi_set_resid() is an unsigned int. Reflect this fact in the interface
of these helper functions.

Also fix compilation errors due to min() and max() type mismatch
introduced by this change in scsi debug code, usb transport code and in
the USB ENE card reader driver.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---

Changes from v1:
* Fix compilation error in the USB ENE card reader driver

 drivers/scsi/scsi_debug.c        | 4 ++--
 drivers/usb/storage/ene_ub6250.c | 2 +-
 drivers/usb/storage/transport.c  | 3 +--
 include/scsi/scsi_cmnd.h         | 4 ++--
 4 files changed, 6 insertions(+), 7 deletions(-)

Comments

Bart Van Assche Oct. 30, 2019, 3:15 p.m. UTC | #1
On 10/30/19 2:08 AM, Damien Le Moal wrote:
> struct scsi_cmnd cmd->req.resid_len which is returned and set
> respectively by the helper functions scsi_get_resid() and
> scsi_set_resid() is an unsigned int. Reflect this fact in the interface
> of these helper functions.
> 
> Also fix compilation errors due to min() and max() type mismatch
> introduced by this change in scsi debug code, usb transport code and in
> the USB ENE card reader driver.
  Please answer my question about how a SCSI LLD should report residual 
overflows. I think this patch is incompatible with the approach used by 
the SRP initiator driver:

if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER))
	scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt));
else if (unlikely(rsp->flags & SRP_RSP_FLAG_DIOVER))
	scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_in_res_cnt));
else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOUNDER))
	scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt));
else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOOVER))
	scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_out_res_cnt));

Thanks,

Bart.
Damien Le Moal Oct. 30, 2019, 4:21 p.m. UTC | #2
On 2019/10/30 16:15, Bart Van Assche wrote:
> On 10/30/19 2:08 AM, Damien Le Moal wrote:
>> struct scsi_cmnd cmd->req.resid_len which is returned and set
>> respectively by the helper functions scsi_get_resid() and
>> scsi_set_resid() is an unsigned int. Reflect this fact in the interface
>> of these helper functions.
>>
>> Also fix compilation errors due to min() and max() type mismatch
>> introduced by this change in scsi debug code, usb transport code and in
>> the USB ENE card reader driver.
>   Please answer my question about how a SCSI LLD should report residual 
> overflows. I think this patch is incompatible with the approach used by 
> the SRP initiator driver:
> 
> if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER))
> 	scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt));

be32_to_cpu(rsp->data_in_res_cnt) is always >= 0 so no problems.

> else if (unlikely(rsp->flags & SRP_RSP_FLAG_DIOVER))
> 	scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_in_res_cnt));

-be32_to_cpu(rsp->data_in_res_cnt) is always <= 0. But it does *not*
matter if my patch is applied or not, this negative value gets stored
into scmd->req.resid_len which is an *unsigned int*.
How does that work ?

My patch changes the function resid argument type and that function is
inline, so in practice, there are 0 changes, none whatsoever, isn't it ?

The problem you are raising here may exist, and how the scsi core will
handle a negative value cast to an unsigned int, likely resulting in a
value far larger than the command buffer size, is certainly a serious
concern. But it is unrelated to what my patch does.

If you feel strongly about it, I have absolutely no problem with
dropping the patch. I just would like that it be dropped for the right
reasons...

> else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOUNDER))
> 	scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt));
> else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOOVER))
> 	scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_out_res_cnt));
> 
> Thanks,
> 
> Bart.
>
Bart Van Assche Oct. 30, 2019, 5:01 p.m. UTC | #3
On 10/30/19 9:21 AM, Damien Le Moal wrote:
> If you feel strongly about it, I have absolutely no problem with
> dropping the patch. I just would like that it be dropped for the right
> reasons...

Hi Damien,

What I'm wondering about is how the SCSI core should support residual
overflow. Should a new member be introduced in struct scsi_request?
Should resid_len be changed from unsigned int to int or should we
perhaps follow yet another approach?

Thanks,

Bart.
Hannes Reinecke Oct. 31, 2019, 8:39 a.m. UTC | #4
On 10/30/19 6:01 PM, Bart Van Assche wrote:
> On 10/30/19 9:21 AM, Damien Le Moal wrote:
>> If you feel strongly about it, I have absolutely no problem with
>> dropping the patch. I just would like that it be dropped for the right
>> reasons...
> 
> Hi Damien,
> 
> What I'm wondering about is how the SCSI core should support residual
> overflow. Should a new member be introduced in struct scsi_request?
> Should resid_len be changed from unsigned int to int or should we
> perhaps follow yet another approach?
> 
Please introduce a new member to hold any overflow value.
And document where it is needed.

Cheers,

Hannes
Damien Le Moal Nov. 5, 2019, 12:11 a.m. UTC | #5
Bart,

On 2019/10/31 17:39, Hannes Reinecke wrote:
> On 10/30/19 6:01 PM, Bart Van Assche wrote:
>> On 10/30/19 9:21 AM, Damien Le Moal wrote:
>>> If you feel strongly about it, I have absolutely no problem with
>>> dropping the patch. I just would like that it be dropped for the right
>>> reasons...
>>
>> Hi Damien,
>>
>> What I'm wondering about is how the SCSI core should support residual
>> overflow. Should a new member be introduced in struct scsi_request?
>> Should resid_len be changed from unsigned int to int or should we
>> perhaps follow yet another approach?
>>
> Please introduce a new member to hold any overflow value.
> And document where it is needed.

Yes, I also think this is the best approach. The current resid_len
member of struct scsi_request can be kept as is, encoding actual
underflow of a command (less bytes transferred than asked for). The new
field would only be used in the case of "overflow", which are not actual
buffer overflows as Hannes pointed out (otherwise, we would get memory
corruptions, iommu screaming etc). The SG driver can make use of this
field to keep the io header resid as an int, with negative values
indicating overflows and positive values underflows.

Best regards.
Martin K. Petersen Nov. 5, 2019, 5:18 a.m. UTC | #6
Damien,

> The SG driver can make use of this field to keep the io header resid
> as an int, with negative values indicating overflows and positive
> values underflows.

I am all for synthesizing what SG returns to userland.

That is also the case in the context of Hannes' SCSI result revamp. I
would much prefer to have well-defined and consistent internal kernel
status fields and then transmogrify those into something compatible with
what userland applications might expect. As opposed to perpetuating the
train wreck that is the current scsi_cmnd result.
Damien Le Moal Nov. 5, 2019, 5:24 a.m. UTC | #7
On 2019/11/05 14:19, Martin K. Petersen wrote:
> 
> Damien,
> 
>> The SG driver can make use of this field to keep the io header resid
>> as an int, with negative values indicating overflows and positive
>> values underflows.
> 
> I am all for synthesizing what SG returns to userland.
> 
> That is also the case in the context of Hannes' SCSI result revamp. I
> would much prefer to have well-defined and consistent internal kernel
> status fields and then transmogrify those into something compatible with
> what userland applications might expect. As opposed to perpetuating the
> train wreck that is the current scsi_cmnd result.

OK. But just to clarify, do you mean changing struct scsi_request
resid_len field to an int and considering positive values of it as
underflow and negative values as overflow ? Or keeping resid_len as an
unsigned int and adding a flag specifying if the value means underflow
or overflow ?

I am rely surprised that my simple patch resulted in such a big
discussion. But if that leads to code improvements, then let's drop it
and work on a new series !
Martin K. Petersen Nov. 6, 2019, 4:31 a.m. UTC | #8
Damien,

> Or keeping resid_len as an unsigned int and adding a flag specifying
> if the value means underflow or overflow ?

It's been broken for so long I'd rather make the overflow case an
opt-in. So a separate flag, please.
Bart Van Assche Nov. 8, 2019, 4:24 p.m. UTC | #9
On 10/30/19 2:08 AM, Damien Le Moal wrote:
> struct scsi_cmnd cmd->req.resid_len which is returned and set
> respectively by the helper functions scsi_get_resid() and
> scsi_set_resid() is an unsigned int. Reflect this fact in the interface
> of these helper functions.
> 
> Also fix compilation errors due to min() and max() type mismatch
> introduced by this change in scsi debug code, usb transport code and in
> the USB ENE card reader driver.

Since there is agreement that residual overflow should use another field 
than scsi_request.resid_len:

Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Martin K. Petersen Nov. 9, 2019, 2:36 a.m. UTC | #10
Damien,

> struct scsi_cmnd cmd->req.resid_len which is returned and set
> respectively by the helper functions scsi_get_resid() and
> scsi_set_resid() is an unsigned int. Reflect this fact in the
> interface of these helper functions.

Applied to 5.5/scsi-queue, thanks!
diff mbox series

Patch

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index d323523f5f9d..4daf2637c011 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1025,7 +1025,7 @@  static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
 static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
 				  int arr_len, unsigned int off_dst)
 {
-	int act_len, n;
+	unsigned int act_len, n;
 	struct scsi_data_buffer *sdb = &scp->sdb;
 	off_t skip = off_dst;
 
@@ -1039,7 +1039,7 @@  static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
 		 __func__, off_dst, scsi_bufflen(scp), act_len,
 		 scsi_get_resid(scp));
-	n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
+	n = scsi_bufflen(scp) - (off_dst + act_len);
 	scsi_set_resid(scp, min(scsi_get_resid(scp), n));
 	return 0;
 }
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index 8b1b73065421..98c1aa594e6c 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -561,7 +561,7 @@  static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
 		residue = min(residue, transfer_length);
 		if (us->srb != NULL)
 			scsi_set_resid(us->srb, max(scsi_get_resid(us->srb),
-								(int)residue));
+								residue));
 	}
 
 	if (bcs->Status != US_BULK_STAT_OK)
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 96cb0409dd89..238a8088e17f 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1284,8 +1284,7 @@  int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
 
 		} else {
 			residue = min(residue, transfer_length);
-			scsi_set_resid(srb, max(scsi_get_resid(srb),
-			                                       (int) residue));
+			scsi_set_resid(srb, max(scsi_get_resid(srb), residue));
 		}
 	}
 
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 91bd749a02f7..3772ae5d40cd 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -190,12 +190,12 @@  static inline unsigned scsi_bufflen(struct scsi_cmnd *cmd)
 	return cmd->sdb.length;
 }
 
-static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
+static inline void scsi_set_resid(struct scsi_cmnd *cmd, unsigned int resid)
 {
 	cmd->req.resid_len = resid;
 }
 
-static inline int scsi_get_resid(struct scsi_cmnd *cmd)
+static inline unsigned int scsi_get_resid(struct scsi_cmnd *cmd)
 {
 	return cmd->req.resid_len;
 }