Skip to content

Commit dc61248

Browse files
committed
ACPI: scan: Fix device object rescan in acpi_scan_clear_dep()
In general, acpi_bus_attach() can only be run safely under acpi_scan_lock, but that lock cannot be acquired under acpi_dep_list_lock, so make acpi_scan_clear_dep() schedule deferred execution of acpi_bus_attach() under acpi_scan_lock instead of calling it directly. This also fixes a possible race between acpi_scan_clear_dep() and device removal that might cause a device object that went away to be accessed, because acpi_scan_clear_dep() is changed to acquire a reference on the consumer device object. Signed-off-by: Rafael J. Wysocki <[email protected]> Reviewed-by: Hans de Goede <[email protected]>
1 parent aff0dbd commit dc61248

File tree

1 file changed

+45
-5
lines changed

1 file changed

+45
-5
lines changed

drivers/acpi/scan.c

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,16 +2109,56 @@ static int acpi_dev_get_first_consumer_dev_cb(struct acpi_dep_data *dep, void *d
21092109
return 0;
21102110
}
21112111

2112-
static int acpi_scan_clear_dep(struct acpi_dep_data *dep, void *data)
2113-
{
2112+
struct acpi_scan_clear_dep_work {
2113+
struct work_struct work;
21142114
struct acpi_device *adev;
2115+
};
2116+
2117+
static void acpi_scan_clear_dep_fn(struct work_struct *work)
2118+
{
2119+
struct acpi_scan_clear_dep_work *cdw;
2120+
2121+
cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
2122+
2123+
acpi_scan_lock_acquire();
2124+
acpi_bus_attach(cdw->adev, true);
2125+
acpi_scan_lock_release();
2126+
2127+
acpi_dev_put(cdw->adev);
2128+
kfree(cdw);
2129+
}
2130+
2131+
static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
2132+
{
2133+
struct acpi_scan_clear_dep_work *cdw;
21152134

2116-
acpi_bus_get_device(dep->consumer, &adev);
2135+
if (adev->dep_unmet)
2136+
return false;
2137+
2138+
cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
2139+
if (!cdw)
2140+
return false;
2141+
2142+
cdw->adev = adev;
2143+
INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
2144+
/*
2145+
* Since the work function may block on the lock until the entire
2146+
* initial enumeration of devices is complete, put it into the unbound
2147+
* workqueue.
2148+
*/
2149+
queue_work(system_unbound_wq, &cdw->work);
2150+
2151+
return true;
2152+
}
2153+
2154+
static int acpi_scan_clear_dep(struct acpi_dep_data *dep, void *data)
2155+
{
2156+
struct acpi_device *adev = acpi_bus_get_acpi_device(dep->consumer);
21172157

21182158
if (adev) {
21192159
adev->dep_unmet--;
2120-
if (!adev->dep_unmet)
2121-
acpi_bus_attach(adev, true);
2160+
if (!acpi_scan_clear_dep_queue(adev))
2161+
acpi_dev_put(adev);
21222162
}
21232163

21242164
list_del(&dep->node);

0 commit comments

Comments
 (0)