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

Reply via email to