Skip to content

Commit 6ec4147

Browse files
jwrdegoedegregkh
authored andcommitted
usb-anchor: Delay usb_wait_anchor_empty_timeout wake up till completion is done
usb_wait_anchor_empty_timeout() should wait till the completion handler has run. Both the zd1211rw driver and the uas driver (in its task mgmt) depend on the completion handler having completed when usb_wait_anchor_empty_timeout() returns, as they read state set by the completion handler after an usb_wait_anchor_empty_timeout() call. But __usb_hcd_giveback_urb() calls usb_unanchor_urb before calling the completion handler. This is necessary as the completion handler may re-submit and re-anchor the urb. But this introduces a race where the state these drivers want to read has not been set yet by the completion handler (this race is easily triggered with the uas task mgmt code). I've considered adding an anchor_count to struct urb, which would be incremented on anchor and decremented on unanchor, and then only actually do the anchor / unanchor on 0 -> 1 and 1 -> 0 transtions, combined with moving the unanchor call in hcd_giveback_urb to after calling the completion handler. But this will only work if urb's are only re-anchored to the same anchor as they were anchored to before the completion handler ran. And at least one driver re-anchors to another anchor from the completion handler (rtlwifi). So I have come up with this patch instead, which adds the ability to suspend wakeups of usb_wait_anchor_empty_timeout() waiters to the usb_anchor functionality, and uses this in __usb_hcd_giveback_urb() to delay wake-ups until the completion handler has run. Signed-off-by: Hans de Goede <[email protected]> Acked-by: Oliver Neukum <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 9ef73db commit 6ec4147

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed

drivers/usb/core/hcd.c

+3
Original file line numberDiff line numberDiff line change
@@ -1652,6 +1652,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
16521652
static void __usb_hcd_giveback_urb(struct urb *urb)
16531653
{
16541654
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
1655+
struct usb_anchor *anchor = urb->anchor;
16551656
int status = urb->unlinked;
16561657
unsigned long flags;
16571658

@@ -1663,6 +1664,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
16631664

16641665
unmap_urb_for_dma(hcd, urb);
16651666
usbmon_urb_complete(&hcd->self, urb, status);
1667+
usb_anchor_suspend_wakeups(anchor);
16661668
usb_unanchor_urb(urb);
16671669

16681670
/* pass ownership to the completion handler */
@@ -1682,6 +1684,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
16821684
urb->complete(urb);
16831685
local_irq_restore(flags);
16841686

1687+
usb_anchor_resume_wakeups(anchor);
16851688
atomic_dec(&urb->use_count);
16861689
if (unlikely(atomic_read(&urb->reject)))
16871690
wake_up(&usb_kill_urb_queue);

drivers/usb/core/urb.c

+42-2
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,19 @@ void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
138138
}
139139
EXPORT_SYMBOL_GPL(usb_anchor_urb);
140140

141+
static int usb_anchor_check_wakeup(struct usb_anchor *anchor)
142+
{
143+
return atomic_read(&anchor->suspend_wakeups) == 0 &&
144+
list_empty(&anchor->urb_list);
145+
}
146+
141147
/* Callers must hold anchor->lock */
142148
static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor)
143149
{
144150
urb->anchor = NULL;
145151
list_del(&urb->anchor_list);
146152
usb_put_urb(urb);
147-
if (list_empty(&anchor->urb_list))
153+
if (usb_anchor_check_wakeup(anchor))
148154
wake_up(&anchor->wait);
149155
}
150156

@@ -845,6 +851,39 @@ void usb_unlink_anchored_urbs(struct usb_anchor *anchor)
845851
}
846852
EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);
847853

854+
/**
855+
* usb_anchor_suspend_wakeups
856+
* @anchor: the anchor you want to suspend wakeups on
857+
*
858+
* Call this to stop the last urb being unanchored from waking up any
859+
* usb_wait_anchor_empty_timeout waiters. This is used in the hcd urb give-
860+
* back path to delay waking up until after the completion handler has run.
861+
*/
862+
void usb_anchor_suspend_wakeups(struct usb_anchor *anchor)
863+
{
864+
if (anchor)
865+
atomic_inc(&anchor->suspend_wakeups);
866+
}
867+
EXPORT_SYMBOL_GPL(usb_anchor_suspend_wakeups);
868+
869+
/**
870+
* usb_anchor_resume_wakeups
871+
* @anchor: the anchor you want to resume wakeups on
872+
*
873+
* Allow usb_wait_anchor_empty_timeout waiters to be woken up again, and
874+
* wake up any current waiters if the anchor is empty.
875+
*/
876+
void usb_anchor_resume_wakeups(struct usb_anchor *anchor)
877+
{
878+
if (!anchor)
879+
return;
880+
881+
atomic_dec(&anchor->suspend_wakeups);
882+
if (usb_anchor_check_wakeup(anchor))
883+
wake_up(&anchor->wait);
884+
}
885+
EXPORT_SYMBOL_GPL(usb_anchor_resume_wakeups);
886+
848887
/**
849888
* usb_wait_anchor_empty_timeout - wait for an anchor to be unused
850889
* @anchor: the anchor you want to become unused
@@ -858,7 +897,8 @@ EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);
858897
int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
859898
unsigned int timeout)
860899
{
861-
return wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list),
900+
return wait_event_timeout(anchor->wait,
901+
usb_anchor_check_wakeup(anchor),
862902
msecs_to_jiffies(timeout));
863903
}
864904
EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);

include/linux/usb.h

+3
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,7 @@ struct usb_anchor {
12091209
struct list_head urb_list;
12101210
wait_queue_head_t wait;
12111211
spinlock_t lock;
1212+
atomic_t suspend_wakeups;
12121213
unsigned int poisoned:1;
12131214
};
12141215

@@ -1575,6 +1576,8 @@ extern void usb_kill_anchored_urbs(struct usb_anchor *anchor);
15751576
extern void usb_poison_anchored_urbs(struct usb_anchor *anchor);
15761577
extern void usb_unpoison_anchored_urbs(struct usb_anchor *anchor);
15771578
extern void usb_unlink_anchored_urbs(struct usb_anchor *anchor);
1579+
extern void usb_anchor_suspend_wakeups(struct usb_anchor *anchor);
1580+
extern void usb_anchor_resume_wakeups(struct usb_anchor *anchor);
15781581
extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor);
15791582
extern void usb_unanchor_urb(struct urb *urb);
15801583
extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,

0 commit comments

Comments
 (0)