On Thu, 8 Apr 2004, Marcel Holtmann wrote: > Hi Alan, > > many thanks for looking at the problem.
You're welcome. > I am not an expert when it comes > to USB internals, but from your explanation I ask myself why we don't > have an unlink function that will wait until the last reference to the > URB is gone. Why do we have to do it in the driver itself? I feel the same way. The API works as designed, but the design itself should be improved. A function very much like the one I added to your driver will probably go into the USB core, but I don't know when. Another change I would like to see would be to have separate usb_unlink_urb functions for synchronous and asynchronous; that would affect so many drivers that it's not likely to happen any time soon. > > By the way, I noticed a couple of other little things in the driver that > > could be improved. The first is _urb_alloc() -- it should call > > usb_init_urb() rather than initializing the URB by hand. The second was > > the test of the HCI_RUNNING flags bit in the hci_usb_{t,r}x_complete() > > functions. Those tests should be made while holding hci->completion_lock > > for proper synchronization. Otherwise you can have a race on an SMP > > system in which hci_usb_rx_complete() finds the bit is set; then on > > another processor hci_usb_close() clears the bit, grabs & releases the > > lock, and unlinks all the active URBs; then the first processor acquires > > the lock and resubmits the URB. > > Good points. Do you have a patch for me? Here's a combined patch. Would you like to submit these changes to Greg? Alan Stern ===== drivers/bluetooth/hci_usb.c 1.42 vs edited ===== --- 1.42/drivers/bluetooth/hci_usb.c Tue Mar 30 17:57:21 2004 +++ edited/drivers/bluetooth/hci_usb.c Fri Apr 9 11:28:24 2004 @@ -109,8 +109,7 @@ sizeof(struct usb_iso_packet_descriptor) * isoc, gfp); if (_urb) { memset(_urb, 0, sizeof(*_urb)); - _urb->urb.count = (atomic_t)ATOMIC_INIT(1); - spin_lock_init(&_urb->urb.lock); + usb_init_urb(&_urb->urb); } return _urb; } @@ -341,6 +340,14 @@ return 0; } +static void inline wait_for_urb(struct urb *urb) +{ + while (atomic_read(&urb->count) > 1) { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout((5 * HZ + 999) / 1000); + } +} + static void hci_usb_unlink_urbs(struct hci_usb *husb) { int i; @@ -357,6 +364,7 @@ BT_DBG("%s unlinking _urb %p type %d urb %p", husb->hdev->name, _urb, _urb->type, urb); usb_unlink_urb(urb); + wait_for_urb(urb); _urb_queue_tail(__completed_q(husb, _urb->type), _urb); } @@ -699,11 +707,11 @@ BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb, _urb->type, urb->status, count, urb->transfer_flags); - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return; - read_lock(&husb->completion_lock); + if (!test_bit(HCI_RUNNING, &hdev->flags)) + goto done; + if (urb->status || !count) goto resubmit; @@ -739,6 +747,7 @@ BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb, _urb->type, err); +done: read_unlock(&husb->completion_lock); } ------------------------------------------------------- This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel