Brian Murphy <[EMAIL PROTECTED]> said: > Alan Stern wrote: > > >On Mon, 14 Mar 2005, Brian Murphy wrote: > > > > > > > >>This was nice in theory and partially fixes the problem (no more crash) > >>unfortunately > >>the module removal hangs if the data interface is attempted to be > >>removed first. > >> > >>This seems to be because usb_driver_claim_interface is not the same as > >>claiming > >>the interface in the probe routine causing the call to > >>usb_driver_release_interface to > >>not decrement some reference count somewhere. > >> > >> > > > >That's bad. usb_driver_claim_interface and returning 0 from probe are > >supposed to have the same overall effect. Is there any way you can track > >down the missing reference count? > > > >Alan Stern > > > > > > > > > Yes. I'll look at it tomorrow. If you have any ideas about a good place > to look then > that might save me some time. > > /Brian > >
The problem is not reference counting the problem is some code in driver/base/bus.c. First I will describe the scenario: Insert the cdc_acm module and plug in a supported device then remove the module with the device plugged in. This leads to the modprobe process using 100% cpu and never returns. The reason for this is that the removal process ends up busy waiting in driver_detach. The process by which this happens is driver_detach is called with our cdc_acm driver as argument. This has two dependent devices which are the two interfaces. The code is thus: static void driver_detach(struct device_driver * drv) { struct list_head * entry, * next; list_for_each_safe(entry, next, &drv->devices) { struct device * dev = container_of(entry, struct device, driver_list); device_release_driver(dev); } } so device_release_driver is called with the first interface as argument it's code looks like this: void device_release_driver(struct device * dev) { struct device_driver * drv = dev->driver; if (drv) { sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&dev->kobj, "driver"); list_del_init(&dev->driver_list); device_detach_shutdown(dev); if (drv->remove) drv->remove(dev); dev->driver = NULL; } } All is well and we call the driver remove function which calls acm_disconnect. acm_disconnect calls usb_driver_release_interface with the other interface which re-enters device_release_driver and removes its entry from the list. Unfortunately this call detaches driver_detach's next pointer from the list it is iterating over so when we return from the outside call of device_release_driver next->next is itself and will never be equal to the list head which is list_for_each_safe's loop end condition. This is very bad. I don't really understand why this is such an unusual situation but it results from us freeing the interfaces in a different order to that we claim them in - shouldn't the device driver interface handle this - at least without an infinite loop? As far as I can see device_release_driver should *never* be called from somewhere which is called from device_release_driver with the current implimentation and I really can't understand that this has never happened before... I will be less tired later and try to propose a solution. At least you know what the problem is now. /Brian ------------------------------------------------------- SF email is sponsored by - The IT Product Guide Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now. http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel