RE: [PATCH 4/8] musb_host: fix endpoint_disable() method (take 2)

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

 



> -----Original Message-----
> From: linux-usb-owner@xxxxxxxxxxxxxxx [mailto:linux-usb-owner@xxxxxxxxxxxxxxx] On Behalf Of Sergei
> Shtylyov
> Sent: Wednesday, January 28, 2009 3:03 AM
> To: felipe.balbi@xxxxxxxxx; gregkh@xxxxxxx
> Cc: linux-usb@xxxxxxxxxxxxxxx; davinci-linux-open-source@xxxxxxxxxxxxxxxxxxxx; david-b@xxxxxxxxxxx
> Subject: [PATCH 4/8] musb_host: fix endpoint_disable() method (take 2)
> 
> The end of musb_h_disable() is totally insane: list_for_each_entry_safe_from()
> will obviously cause a kernel oops given a NULL pointer and otherwise it'd be
> too late to give back the first URB in the list as musb_cleanup_urb() called
> beforehand would have already done that, unlinking it from the URB list and
> thus causing the interator to loop on this URB forever. The list interator is
> not safe to use either as URBs may be explicitly dequeued by upper layers while
> it's running. As if that was not enough, musb_giveback() is not safe to call
> from here either because:
> - when we're disabling an endpoint with an URB being currently active, once
>   URB list empties, we must immediately switch to serving the next endpoint
>   (represented by 'struct musb_qh') or risk the schedule list being stalled;
> - when we're disabling an endpoint not being currently active, musb_giveback()
>   may e.g. spoil the saved data toggle since it'll be reading it while another
>   logical endpoint ('struct musb_qh') is active.


> Finally, it doesn't seem to be safe to read 'hep->hcpriv' before taking hold of
> 'musb->lock'... phew. :-)

Even in musb_urb_enqueue() we should read 'hep->hcpriv' within 'musb->lock'.

-Ajay

> 
> Signed-off-by: Sergei Shtylyov <sshtylyov@xxxxxxxxxxxxx>
> 
> ---
> The patch is against the recent Linus' kernel.
> I wonder who wrote the original code... :-/
> 
>  drivers/usb/musb/musb_host.c |   32 +++++++++++++++++++++-----------
>  1 files changed, 21 insertions(+), 11 deletions(-)
> 
> Index: linux-2.6/drivers/usb/musb/musb_host.c
> ===================================================================
> --- linux-2.6.orig/drivers/usb/musb/musb_host.c
> +++ linux-2.6/drivers/usb/musb/musb_host.c
> @@ -2099,15 +2099,16 @@ musb_h_disable(struct usb_hcd *hcd, stru
>  	unsigned long		flags;
>  	struct musb		*musb = hcd_to_musb(hcd);
>  	u8			is_in = epnum & USB_DIR_IN;
> -	struct musb_qh		*qh = hep->hcpriv;
> -	struct urb		*urb, *tmp;
> +	struct musb_qh		*qh;
> +	struct urb		*urb;
>  	struct list_head	*sched;
> 
> -	if (!qh)
> -		return;
> -
>  	spin_lock_irqsave(&musb->lock, flags);
> 
> +	qh = hep->hcpriv;
> +	if (qh == NULL)
> +		goto exit;
> +
>  	switch (qh->type) {
>  	case USB_ENDPOINT_XFER_CONTROL:
>  		sched = &musb->control;
> @@ -2141,13 +2142,22 @@ musb_h_disable(struct usb_hcd *hcd, stru
> 
>  		/* cleanup */
>  		musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
> -	} else
> -		urb = NULL;
> -
> -	/* then just nuke all the others */
> -	list_for_each_entry_safe_from(urb, tmp, &hep->urb_list, urb_list)
> -		musb_giveback(qh, urb, -ESHUTDOWN);
> 
> +		/* Then just nuke all the others */
> +		while (!list_empty(&hep->urb_list)) {
> +			urb = next_urb(qh);
> +			urb->status = -ESHUTDOWN;
> +			musb_advance_schedule(musb, urb, qh->hw_ep, is_in);
> +		}
> +	} else {
> +		while (!list_empty(&hep->urb_list))
> +			__musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
> +
> +		hep->hcpriv = NULL;
> +		list_del(&qh->ring);
> +		kfree(qh);
> +	}
> +exit:
>  	spin_unlock_irqrestore(&musb->lock, flags);
>  }
> 
> 
> --
> 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

--
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