diff mbox series

USB: usbfs: Always unlink URBs in reverse order

Message ID Pine.LNX.4.44L0.2001171045380.1571-100000@iolanthe.rowland.org (mailing list archive)
State Mainlined
Commit fdd64df7b9d1e20dbe28c9c205682b66ad821e6c
Headers show
Series USB: usbfs: Always unlink URBs in reverse order | expand

Commit Message

Alan Stern Jan. 17, 2020, 3:47 p.m. UTC
When the kernel unlinks a bunch of URBs for a single endpoint, it
should always unlink them in reverse order.  This eliminates any
possibility that some URB x will be unlinked before it can execute but
the following URB x+1 will execute before it can be unlinked.  Such an
event would be bad, for obvious reasons.

Chris Dickens pointed out that usbfs doesn't behave this way when it
is unbound from an interface.  All pending URBs are cancelled, but in
the order of submission.  This patch changes the behavior to make the
unlinks occur in reverse order.  It similarly changes the behavior
when usbfs cancels the continuation URBs for a BULK endpoint.

Suggested-by: Chris Dickens <christopher.a.dickens@gmail.com>
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>

---

This doesn't fix any reported bugs, so I don't think it needs to go 
into the -stable kernels.


[as1929]


 drivers/usb/core/devio.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff mbox series

Patch

Index: usb-devel/drivers/usb/core/devio.c
===================================================================
--- usb-devel.orig/drivers/usb/core/devio.c
+++ usb-devel/drivers/usb/core/devio.c
@@ -574,7 +574,7 @@  __acquires(ps->lock)
 
 	/* Now carefully unlink all the marked pending URBs */
  rescan:
-	list_for_each_entry(as, &ps->async_pending, asynclist) {
+	list_for_each_entry_reverse(as, &ps->async_pending, asynclist) {
 		if (as->bulk_status == AS_UNLINK) {
 			as->bulk_status = 0;		/* Only once */
 			urb = as->urb;
@@ -636,7 +636,7 @@  static void destroy_async(struct usb_dev
 
 	spin_lock_irqsave(&ps->lock, flags);
 	while (!list_empty(list)) {
-		as = list_entry(list->next, struct async, asynclist);
+		as = list_last_entry(list, struct async, asynclist);
 		list_del_init(&as->asynclist);
 		urb = as->urb;
 		usb_get_urb(urb);