From fdd64df7b9d1e20dbe28c9c205682b66ad821e6c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 17 Jan 2020 10:47:13 -0500 Subject: [PATCH] USB: usbfs: Always unlink URBs in reverse order 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 Signed-off-by: Alan Stern Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.2001171045380.1571-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 12bb572..6833c918 100644 --- a/drivers/usb/core/devio.c +++ b/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_state *ps, struct list_head *list) 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); -- 2.7.4