Here is my patch to implement proper timing of synchronous unlinks.  
Basically it just uses a spinlock to cause unlink requests during a 
completion handler to wait until the handler has returned before carrying 
out the unlink.  This seems like a pretty small and uninvasive sort of 
change.

Alan Stern

===== drivers/usb/core/hcd.c 1.89 vs edited =====
--- 1.89/drivers/usb/core/hcd.c Thu Jan 16 04:29:28 2003
+++ edited/drivers/usb/core/hcd.c       Wed Jan 22 16:25:26 2003
@@ -1116,8 +1116,13 @@
         * lock sequence needed for the usb_hcd_giveback_urb() code paths
         * (urb lock, then hcd_data_lock) in case some other CPU is now
         * unlinking it.
+        *
+        * In case the completion handler is already running, we first
+        * acquire urb->handler_lock; this will cause us to wait until
+        * the handler has returned.
         */
-       spin_lock_irqsave (&urb->lock, flags);
+       spin_lock_irqsave (&urb->handler_lock, flags);
+       spin_lock (&urb->lock);
        spin_lock (&hcd_data_lock);
 
        if (!urb->dev || !urb->dev->bus) {
@@ -1170,7 +1175,8 @@
                urb->status = -ECONNRESET;
        }
        spin_unlock (&hcd_data_lock);
-       spin_unlock_irqrestore (&urb->lock, flags);
+       spin_unlock (&urb->lock);
+       spin_unlock_irqrestore (&urb->handler_lock, flags);
 
        if (urb == (struct urb *) hcd->rh_timer.data) {
                usb_rh_status_dequeue (hcd, urb);
@@ -1200,7 +1206,8 @@
 
 done:
        spin_unlock (&hcd_data_lock);
-       spin_unlock_irqrestore (&urb->lock, flags);
+       spin_unlock (&urb->lock);
+       spin_unlock_irqrestore (&urb->handler_lock, flags);
 bye:
        if (retval && sys)
                dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
@@ -1307,7 +1314,9 @@
        }
 
        /* pass ownership to the completion handler */
+       spin_lock (&urb->handler_lock);
        urb->complete (urb, regs);
+       spin_unlock (&urb->handler_lock);
        usb_put_urb (urb);
 }
 EXPORT_SYMBOL (usb_hcd_giveback_urb);
===== drivers/usb/core/urb.c 1.19 vs edited =====
--- 1.19/drivers/usb/core/urb.c Wed Oct 30 22:55:08 2002
+++ edited/drivers/usb/core/urb.c       Wed Jan 22 16:13:58 2003
@@ -44,6 +44,7 @@
        memset(urb, 0, sizeof(*urb));
        urb->count = (atomic_t)ATOMIC_INIT(1);
        spin_lock_init(&urb->lock);
+       spin_lock_init(&urb->handler_lock);
 
        return urb;
 }
===== include/linux/usb.h 1.123 vs edited =====
--- 1.123/include/linux/usb.h   Fri Jan 17 13:21:23 2003
+++ edited/include/linux/usb.h  Wed Jan 22 16:04:12 2003
@@ -728,6 +728,7 @@
 {
        spinlock_t lock;                /* lock for the URB */
        atomic_t count;                 /* reference count of the URB */
+       spinlock_t handler_lock;        /* lock during completion routine */
        void *hcpriv;                   /* private data for host controller */
        struct list_head urb_list;      /* list pointer to all active urbs */
        struct usb_device *dev;         /* (in) pointer to associated device */



-------------------------------------------------------
This SF.net email is sponsored by: Scholarships for Techies!
Can't afford IT training? All 2003 ictp students receive scholarships.
Get hands-on training in Microsoft, Cisco, Sun, Linux/UNIX, and more.
www.ictp.com/training/sourceforge.asp
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to