At the end of September, I wrote:
> For some time now I've been getting a kernel panic when I kill the
> Speed Touch user-space daemon, modem_run, and I finally found the
> time to investigate. The information below is from the
> linux-2.6.0-test6 kernel but the problem has been going on for a
> while.
I've done some digging and come up with a patch against
linux-2.6.0-test9 that Works For Me which I'm offering up criticism.
Of interest is the comment at the beginning hcd_unlink_urb
(hcd.c:1155):
/*
* called in any context; note ASYNC_UNLINK restrictions
*
* caller guarantees urb won't be recycled till both unlink()
* and the urb's completion function return
*/
static int hcd_unlink_urb (struct urb *urb)
I note that the destroy_async function (devio.c:274) does not wait
until the URB's completion function has returned. A comment
(devio.c:284) suggests that a call to usb_unlink_urb will immediately
move a URB from the list of outstanding async operations to the list
of completed ones (which it then purges). Unfortunately, this is not
the case if URB_ASYNC_UNLINK is set, as described in usb_unlink_urb's
comment (urb.c:378):
/**
* usb_unlink_urb - abort/cancel a transfer request for an endpoint
* @urb: pointer to urb describing a previously submitted request
*
[snip]
*
* When the URB_ASYNC_UNLINK transfer flag for the URB is set, this
* request is asynchronous. Success is indicated by returning -EINPROGRESS,
* at which time the urb will normally not have been unlinked.
* The completion function will see urb->status -ECONNRESET. Failure
* is indicated by any other return value.
*/
The patch below resolves this inconsistency by having destroy_async
count the number of async operations as it unlinks them and then make
sure that it reaps completed ones before it returns. I don't know if
this is legitimate (can the operations be reaped elsewhere?) but it
resolves the issue I was seeing.
--- usb.diff ---
--- ./linux-2.6.0-test9/drivers/usb/core/devio.c 2003-11-03 00:20:02.000000000
+0000
+++ ./linux-2.6.0-test9/drivers/usb/core/devio.c 2003-11-03 00:29:20.000000000
+0000
@@ -275,7 +275,9 @@
{
struct async *as;
unsigned long flags;
+ unsigned int count;
+ count = 0;
spin_lock_irqsave(&ps->lock, flags);
while (!list_empty(list)) {
as = list_entry(list->next, struct async, asynclist);
@@ -284,10 +286,20 @@
/* usb_unlink_urb calls the completion handler with status == -ENOENT
*/
usb_unlink_urb(as->urb);
spin_lock_irqsave(&ps->lock, flags);
+ count++;
}
spin_unlock_irqrestore(&ps->lock, flags);
- while ((as = async_getcompleted(ps)))
- free_async(as);
+
+ /* Make sure we wait for all of the async entries to complete */
+ while (count) {
+ while ((as = async_getcompleted(ps))) {
+ free_async(as);
+ count--;
+ }
+
+ if (count)
+ schedule();
+ }
}
static void destroy_async_on_interface (struct dev_state *ps, unsigned int intf)
--- end usb.diff ---
Thanks,
-Ted
-------------------------------------------------------
This SF.net email is sponsored by: SF.net Giveback Program.
Does SourceForge.net help you be more productive? Does it
help you create better code? SHARE THE LOVE, and help us help
YOU! Click Here: http://sourceforge.net/donate/
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-users