multiple interface test case
Roman Kagan
rkagan at mail.ru
Tue Apr 12 15:56:22 EDT 2005
On Tue, Apr 12, 2005 at 11:08:27PM +0400, Roman Kagan wrote:
> On Tue, Apr 12, 2005 at 10:08:56PM +0400, Roman Kagan wrote:
> > in drivers/base/bus.c:
> >
> > 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;
> > }
> > }
> >
> > 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);
> > }
> > }
> > [...]
> > yet. Can't it be that list_for_each_safe() is not that safe against
> > removal of the entries inside the loop body?
>
> Hmm, looks fishy to me:
>
> #define list_for_each_safe(pos, n, head) \
> for (pos = (head)->next, n = pos->next; pos != (head); \
> pos = n, n = pos->next)
>
> So if entries are deleted inside the loop body (with list_del_init() in
> our case), the loop is screwed up?
To make my point clear: list_for_each_safe() seems to be safe only
w.r.t. the deletion of the current entry. However, in our
multi-interface scenario, we start with device_release_driver() for the
first interface on the drv->devices list, and then (through
drv->remove(), which calls disconnect(), which calls
usb_driver_release_interface() for other interfaces) we call
device_release_driver() for other interfaces and empty the drv->devices
list, while list_for_each_safe() has already cached the (now invalid)
next entry, and thus goes into an infinite loop.
Does it look reasonable? I'll try to look how it maps to -mm klist
stuff tomorrow, now I'm falling asleep, sorry.
Roman.
More information about the Usbatm
mailing list