On Sun, Jun 23, 2013 at 2:59 AM, Rafael J. Wysocki <rjw@xxxxxxx> wrote: > On Saturday, June 22, 2013 05:22:20 PM Yinghai Lu wrote: >> On Sat, Jun 22, 2013 at 2:25 PM, Rafael J. Wysocki <rjw@xxxxxxx> wrote: >> > From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> >> > >> > To resolve that deadlock use the observation that >> > unregister_hotplug_dock_device() won't need to acquire hp_lock >> > if PCI bridges the devices on the dock station depend on are >> > prevented from being removed prematurely while the first loop in >> > hotplug_dock_devices() is in progress. >> > >> > To make that possible, introduce a mechanism by which the callers of >> > register_hotplug_dock_device() can provide "init" and "release" >> > routines that will be executed, respectively, after the addition >> > and removal of the physical device object associated with the >> > given ACPI device handle. Make acpiphp use two new functions, >> > acpiphp_dock_init() and acpiphp_dock_release(), respectively, >> > calling get_bridge() and put_bridge() on the PCI bridge holding the >> > given device, respectively, for this purpose. >> > >> > In addition to that, remove the dock station's list of >> > "hotplug devices" and make the dock code always walk the whole list >> > of "dependent devices" instead in such a way that the loops in >> > hotplug_dock_devices() and dock_event() (replacing the loops over >> > "hotplug devices") will take references to the list entries that >> > register_hotplug_dock_device() has been called for. That prevents >> > the "release" routines associated with those entries from being >> > called while the given entry is being processed and for PCI >> > devices this means that their bridges won't be removed (by a >> > concurrent thread) while hotplug_event_func() handling them is >> > being executed. >> .. >> > -static void >> > -dock_del_hotplug_device(struct dock_station *ds, >> > - struct dock_dependent_device *dd) >> > +static void dock_release_hotplug(struct dock_dependent_device *dd) >> > { >> > - mutex_lock(&ds->hp_lock); >> > - list_del(&dd->hotplug_list); >> > - mutex_unlock(&ds->hp_lock); >> > + void (*release)(void *) = NULL; >> > + void *context = NULL; >> > + >> > + mutex_lock(&hotplug_lock); >> > + >> > + if (dd->hp_context && !--dd->hp_refcount) { >> > + dd->hp_ops = NULL; >> > + context = dd->hp_context; >> > + dd->hp_context = NULL; >> > + release = dd->hp_release; >> > + dd->hp_release = NULL; >> > + } >> > + >> > + if (release && context) >> > + release(context); >> > + >> > + mutex_unlock(&hotplug_lock); >> > +} >> > + >> > +static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, >> > + bool uevent) >> > +{ >> > + acpi_notify_handler cb = NULL; >> > + bool run = false; >> > + >> > + mutex_lock(&hotplug_lock); >> > + >> > + if (dd->hp_context) { >> > + run = true; >> > + dd->hp_refcount++; >> > + if (dd->hp_ops) >> > + cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler; >> > + } >> > + >> > + mutex_unlock(&hotplug_lock); >> > + >> > + if (!run) >> > + return; >> > + >> > + if (cb) >> > + cb(dd->handle, event, dd->hp_context); >> > + >> > + dock_release_hotplug(dd); >> >> during DOCKING, dock_release_hotplug get called too? > > Yes, we need to drop down the refcount we've just bumped up. > ok, I see. Acked-by: Yinghai Lu <yinghai@xxxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html