Re: [PATCH] usb: gadget: fix race condition in UDC class

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

 



Hello.

Michal Nazarewicz wrote:

> This commit fixes a possible race condition in IDC class when
> usb_del_udc() is called concurrently to
> usb_gadget_register_driver() or usb_gadget_unregister_driver().

> * NOT FOR MERGING, NOT TESTED, NOT EVEN COMPILED *

> Signed-off-by: Michal Nazarewicz <m.nazarewicz@xxxxxxxxxxx>

   Only some cosmetic stuff, partly not even related to this patch...

>> Also, the more I think about it, the more I'm convinced that this needs
>> some synchronisation.  If usb_del_udc() is called at the same time as
>> usb_gadget_unregister_driver() funky stuff can happen.  Funky stuff will
>> also happen if usb_del_udc() is called at the same time as
>> usb_gadget_register_driver().
>>
>> I think, spin lock should be replaced with a mutex and the all of the
>> operations need to be performed when holding the mutex.  Alternatively,
>> mutex can be used in addition to spin lock and then usb_add_udc() could
>> work without locking the mutex.  Or, per-UDC mutex needs to be created
>> and registering, unregistering and deleting would be performed while
>> holding this mutex.

> After more thought I came up with a scheme where usage of atomic
> operations (xchg and cmpxchg) is enough to guarantee correctness.

> The idea is that the driver field can have additional value:
> &udc_claimed.  This value means that usb_del_udc(),
> usb_gadget_register_driver() or usb_gadget_unregister_driver() does
> something with the UDC.  So basically, UDC can be in either of three
> states: free, busy or claimed where claimed means the above.

> usb_gadget_register_driver() treats claimed UDCs as busy,
> usb_gadget_unregister_driver() as ones of no interest, and
> usb_del_udc() waits till the UDC is unclaimed.

> To make it possible for usb_del_udc() to wait till
> usb_*register_gadget_driver() finishes work on UDC a wait queue is
> added.

> The busy flag has been removed.

> diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
> index 9334a91..6e40005 100644
> --- a/drivers/usb/gadget/udc-core.c
> +++ b/drivers/usb/gadget/udc-core.c
> @@ -31,6 +31,8 @@ static struct class *udc_class;
>  static struct device_type udc_device_type;
>  static LIST_HEAD(udc_list);
>  static spinlock_t udc_lock;
> +static DECLARE_WAIT_QUEUE_HEAD(udc_wq);
> +static struct usb_gadget_driver udc_claimed;
>  
>  /* ------------------------------------------------------------------------- */
>  
> @@ -98,8 +100,7 @@ int usb_add_udc(struct device *parent, struct usb_udc *udc)
>  	unsigned long		flags;
>  	int			ret;
>  
> -	if (!udc->gadget || !udc->gadget->ops ||
> -			!udc->gadget->ops->start) {
> +	if (!udc->gadget || !udc->gadget->ops || !udc->gadget->ops->start) {
>  		dev_dbg(parent, "unitializaed gadget\n");

   Only "uninitialized". This is probably remark for Felipe...

> @@ -158,6 +159,34 @@ err1:
>  }
>  EXPORT_SYMBOL_GPL(usb_add_udc);
>  
> +
> +static struct usb_gadget_driver *udc_claim_driver_wait(struct usb_udc *udc)
> +{
> +	struct usb_gadget_driver *driver;
> +	wait_event(udc_wq, (driver = xchg(&udc->driver, &udc_claimed))
> +			   != &udc_claimed);
> +	return driver;
> +}
> +
> +static int udc_claim_driver_if(struct usb_udc *udc,
> +			       struct usb_gadget_driver *old)
> +{
> +	return cmpxchg(&udc->driver, old, &udc_claimed) == old
> +		? 0 : -EBUSY;
> +}
> +
> +static void udc_unclaim_driver(struct usb_udc *udc,
> +			       struct usb_gadget_driver *driver)
> +{
> +	smp_wmb();
> +	udc->driver = driver;
> +	wake_up_all(&udc_wq);
> +}
> +
> +static void __usb_gadget_unregister_driver(struct usb_udc *udc,
> +					   struct usb_gadget_driver *driver);
> +
> +

   Probably too many empty lines at the start and end of this hunk...

WBR, Sergei
--
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