Re: [PATCH 2/2] net2280: Fix tmp reusage in net2280 driver

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

 



On Wed, 8 Feb 2017, Raz Manor wrote:

> In the function scan_dma_completions() there is a reusage of tmp
> variable. That coused a wrong value being used in some case when
> reading a short packet terminated transaction from an endpoint,
> in 2 concecutive reads.
> 
> This was my logic for the patch:
> 
> The req->td->dmadesc equals to 0 iff:
> -- There was a transaction ending with a short packet, and
> -- The read() to read it was shorter than the transaction length, and
> -- The read() to complete it is longer than the residue.
> I believe this is true from the printouts of various cases,
> but I can't be positive it is correct.
> 
> Entering this if, there should be no more data in the endpoint
> (a short packet terminated the transaction).
> If there is, the transaction wasn't really done and we should exit and
> wait for it to finish entirely. That is the inner if.
> That inner if should never happen, but it is there to be on the safe
> side. That is why it is marked with the comment /* paranoia */.
> The size of the data available in the endpoint is ep->dma->dmacount
> and it is read to tmp.
> This entire clause is based on my own educated guesses.
> 
> If we passed that inner if without breaking in the original code,
> than tmp & DMA_BYTE_MASK_COUNT== 0.
> That means we will always pass dma bytes count of 0 to dma_done(),
> meaning all the requested bytes were read.
> 
> dma_done() reports back to the upper layer that the request (read())
> was done and how many bytes were read.
> In the original code that would always be the request size,
> regardless of the actual size of the data.
> That did not make sense to me at all.
> 
> However, the original value of tmp is req->td->dmacount,
> which is the dmacount value when the request's dma transaction was
> finished. And that is a much more reasonable value to report back to
> the caller.
> 
> To recreate the problem:
> Read from a bulk out endpoint in a loop, 1024 * n bytes in each
> iteration.
> Connect the PLX to a host you can control.
> Send to that endpoint 1024 * n + x bytes,
> such that 0 < x < 1024 * n and (x % 1024) != 0
> You would expect the first read() to return 1024 * n
> and the second read() to return x.
> But you will get the first read to return 1024 * n
> and the second one to return 1024 * n.
> That is true for every positive integer n.
> 
> Cc: Felipe Balbi <balbi@xxxxxxxxxx>
> Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
> Cc: linux-usb@xxxxxxxxxxxxxxx
> Signed-off-by: Raz Manor <Raz.Manor@xxxxxxxxxx>
> ---
>  drivers/usb/gadget/udc/net2280.c | 25 +++++++++++++------------
>  1 file changed, 13 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
> index 8550441..a853347 100644
> --- a/drivers/usb/gadget/udc/net2280.c
> +++ b/drivers/usb/gadget/udc/net2280.c
> @@ -1146,15 +1146,15 @@ static int scan_dma_completions(struct net2280_ep *ep)
>  	 */
>  	while (!list_empty(&ep->queue)) {
>  		struct net2280_request	*req;
> -		u32			tmp;
> +		u32 const req_dma_count;

What is the "const" doing here?  It looks like a mistake.  You aren't
allowed to have a const definition without an initializer.

>  
>  		req = list_entry(ep->queue.next,
>  				struct net2280_request, queue);
>  		if (!req->valid)
>  			break;
>  		rmb();
> -		tmp = le32_to_cpup(&req->td->dmacount);
> -		if ((tmp & BIT(VALID_BIT)) != 0)
> +		req_dma_count = le32_to_cpup(&req->td->dmacount);

This assignment is not allowed if req_dma_count truly is const.  A 
const variable cannot be assigned to.

> +		if ((req_dma_count & BIT(VALID_BIT)) != 0)
>  			break;
>  
>  		/* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short"
> @@ -1163,40 +1163,41 @@ static int scan_dma_completions(struct net2280_ep *ep)
>  		 */
>  		if (unlikely(req->td->dmadesc == 0)) {
>  			/* paranoia */
> -			tmp = readl(&ep->dma->dmacount);
> -			if (tmp & DMA_BYTE_COUNT_MASK)
> +			u32 const ep_dmacount = readl(&ep->dma->dmacount);

This also looks odd, although at least it doesn't violate the language 
spec.  I suggest you don't use const definitions at all in this patch.

Alan Stern

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



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux