}
 EXPORT_SYMBOL_GPL(usb_anchor_urb);
 
+/* Callers must hold anchor->lock */
+static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor)
+{
+       urb->anchor = NULL;
+       list_del(&urb->anchor_list);
+       usb_put_urb(urb);
+       if (list_empty(&anchor->urb_list))
+               wake_up(&anchor->wait);
+}
+
 /**
  * usb_unanchor_urb - unanchors an URB
  * @urb: pointer to the urb to anchor
                return;
 
        spin_lock_irqsave(&anchor->lock, flags);
-       if (unlikely(anchor != urb->anchor)) {
-               /* we've lost the race to another thread */
-               spin_unlock_irqrestore(&anchor->lock, flags);
-               return;
-       }
-       urb->anchor = NULL;
-       list_del(&urb->anchor_list);
+       /*
+        * At this point, we could be competing with another thread which
+        * has the same intention. To protect the urb from being unanchored
+        * twice, only the winner of the race gets the job.
+        */
+       if (likely(anchor == urb->anchor))
+               __usb_unanchor_urb(urb, anchor);
        spin_unlock_irqrestore(&anchor->lock, flags);
-       usb_put_urb(urb);
-       if (list_empty(&anchor->urb_list))
-               wake_up(&anchor->wait);
 }
 EXPORT_SYMBOL_GPL(usb_unanchor_urb);
 
 void usb_unlink_anchored_urbs(struct usb_anchor *anchor)
 {
        struct urb *victim;
-       unsigned long flags;
 
-       spin_lock_irqsave(&anchor->lock, flags);
-       while (!list_empty(&anchor->urb_list)) {
-               victim = list_entry(anchor->urb_list.prev, struct urb,
-                                   anchor_list);
-               usb_get_urb(victim);
-               spin_unlock_irqrestore(&anchor->lock, flags);
-               /* this will unanchor the URB */
+       while ((victim = usb_get_from_anchor(anchor)) != NULL) {
                usb_unlink_urb(victim);
                usb_put_urb(victim);
-               spin_lock_irqsave(&anchor->lock, flags);
        }
-       spin_unlock_irqrestore(&anchor->lock, flags);
 }
 EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);
 
                victim = list_entry(anchor->urb_list.next, struct urb,
                                    anchor_list);
                usb_get_urb(victim);
-               spin_unlock_irqrestore(&anchor->lock, flags);
-               usb_unanchor_urb(victim);
+               __usb_unanchor_urb(victim, anchor);
        } else {
-               spin_unlock_irqrestore(&anchor->lock, flags);
                victim = NULL;
        }
+       spin_unlock_irqrestore(&anchor->lock, flags);
 
        return victim;
 }
        while (!list_empty(&anchor->urb_list)) {
                victim = list_entry(anchor->urb_list.prev, struct urb,
                                    anchor_list);
-               usb_get_urb(victim);
-               spin_unlock_irqrestore(&anchor->lock, flags);
-               /* this may free the URB */
-               usb_unanchor_urb(victim);
-               usb_put_urb(victim);
-               spin_lock_irqsave(&anchor->lock, flags);
+               __usb_unanchor_urb(victim, anchor);
        }
        spin_unlock_irqrestore(&anchor->lock, flags);
 }