diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-02-09 09:29:11 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-02-13 07:46:31 -0500 |
commit | f058cdf4cf3e5181172455f90fc73f2127b6ddf8 (patch) | |
tree | b67dcec5a9e7d0d4e6cd65033c8f5fb19616e5e2 /drivers/acpi/scan.c | |
parent | 87d4a4da7353c8582049dab50b880798d88ff9d7 (diff) |
ACPI / scan: Make acpi_bus_hot_remove_device() acquire the scan lock
The ACPI scan lock has been introduced to prevent acpi_bus_scan()
and acpi_bus_trim() from running in parallel with each other for
overlapping ACPI namespace scopes. However, it is not sufficient
to do that, because if acpi_bus_scan() is run (for an overlapping
namespace scope) right after the acpi_bus_trim() in
acpi_bus_hot_remove_device(), the subsequent eject will remove
devices without removing the corresponding struct acpi_device
objects (and possibly companion "physical" device objects).
Therefore acpi_bus_hot_remove_device() has to acquire the scan
lock before carrying out the bus trimming and hold it through
the evaluation of _EJ0, so make that happen.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Toshi Kani <toshi.kani@hp.com>
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 31 |
1 files changed, 17 insertions, 14 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index a48b6e92f9f8..75fb14fc19e8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -95,6 +95,8 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha | |||
95 | } | 95 | } |
96 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); | 96 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); |
97 | 97 | ||
98 | static void __acpi_bus_trim(struct acpi_device *start); | ||
99 | |||
98 | /** | 100 | /** |
99 | * acpi_bus_hot_remove_device: hot-remove a device and its children | 101 | * acpi_bus_hot_remove_device: hot-remove a device and its children |
100 | * @context: struct acpi_eject_event pointer (freed in this func) | 102 | * @context: struct acpi_eject_event pointer (freed in this func) |
@@ -114,10 +116,12 @@ void acpi_bus_hot_remove_device(void *context) | |||
114 | acpi_status status = AE_OK; | 116 | acpi_status status = AE_OK; |
115 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ | 117 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ |
116 | 118 | ||
119 | mutex_lock(&acpi_scan_lock); | ||
120 | |||
117 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 121 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
118 | "Hot-removing device %s...\n", dev_name(&device->dev))); | 122 | "Hot-removing device %s...\n", dev_name(&device->dev))); |
119 | 123 | ||
120 | acpi_bus_trim(device); | 124 | __acpi_bus_trim(device); |
121 | /* Device node has been released. */ | 125 | /* Device node has been released. */ |
122 | device = NULL; | 126 | device = NULL; |
123 | 127 | ||
@@ -146,18 +150,14 @@ void acpi_bus_hot_remove_device(void *context) | |||
146 | status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); | 150 | status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); |
147 | if (ACPI_FAILURE(status)) { | 151 | if (ACPI_FAILURE(status)) { |
148 | if (status != AE_NOT_FOUND) | 152 | if (status != AE_NOT_FOUND) |
149 | printk(KERN_WARNING PREFIX | 153 | acpi_handle_warn(handle, "Eject failed\n"); |
150 | "Eject device failed\n"); | ||
151 | goto err_out; | ||
152 | } | ||
153 | 154 | ||
154 | kfree(context); | 155 | /* Tell the firmware the hot-remove operation has failed. */ |
155 | return; | 156 | acpi_evaluate_hotplug_ost(handle, ej_event->event, |
157 | ost_code, NULL); | ||
158 | } | ||
156 | 159 | ||
157 | err_out: | 160 | mutex_unlock(&acpi_scan_lock); |
158 | /* Inform firmware the hot-remove operation has completed w/ error */ | ||
159 | (void) acpi_evaluate_hotplug_ost(handle, | ||
160 | ej_event->event, ost_code, NULL); | ||
161 | kfree(context); | 161 | kfree(context); |
162 | return; | 162 | return; |
163 | } | 163 | } |
@@ -1683,10 +1683,8 @@ static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used, | |||
1683 | return AE_OK; | 1683 | return AE_OK; |
1684 | } | 1684 | } |
1685 | 1685 | ||
1686 | void acpi_bus_trim(struct acpi_device *start) | 1686 | static void __acpi_bus_trim(struct acpi_device *start) |
1687 | { | 1687 | { |
1688 | mutex_lock(&acpi_scan_lock); | ||
1689 | |||
1690 | /* | 1688 | /* |
1691 | * Execute acpi_bus_device_detach() as a post-order callback to detach | 1689 | * Execute acpi_bus_device_detach() as a post-order callback to detach |
1692 | * all ACPI drivers from the device nodes being removed. | 1690 | * all ACPI drivers from the device nodes being removed. |
@@ -1701,7 +1699,12 @@ void acpi_bus_trim(struct acpi_device *start) | |||
1701 | acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, | 1699 | acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, |
1702 | acpi_bus_remove, NULL, NULL); | 1700 | acpi_bus_remove, NULL, NULL); |
1703 | acpi_bus_remove(start->handle, 0, NULL, NULL); | 1701 | acpi_bus_remove(start->handle, 0, NULL, NULL); |
1702 | } | ||
1704 | 1703 | ||
1704 | void acpi_bus_trim(struct acpi_device *start) | ||
1705 | { | ||
1706 | mutex_lock(&acpi_scan_lock); | ||
1707 | __acpi_bus_trim(start); | ||
1705 | mutex_unlock(&acpi_scan_lock); | 1708 | mutex_unlock(&acpi_scan_lock); |
1706 | } | 1709 | } |
1707 | EXPORT_SYMBOL_GPL(acpi_bus_trim); | 1710 | EXPORT_SYMBOL_GPL(acpi_bus_trim); |