aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-11-06 19:41:14 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-11-06 19:41:14 -0500
commit7f28ddeccea453fd20b1c74a88df19590ad9203c (patch)
tree4bf876eeb9adf2107f1c03178059bcd1676a9ee1 /drivers/acpi
parent6931007cc90ba94b3c2b29179d0a7cde194dabe8 (diff)
ACPI / hotplug: Refuse to hot-remove all objects with disabled hotplug
In theory, an ACPI device object may be the parent of another device object whose hotplug is disabled by user space through its scan handler. In that case, the eject operation targeting the parent should fail as though the parent's own hotplug was disabled, but currently this is not the case, because acpi_scan_hot_remove() doesn't check the disable/enable hotplug status of the children of the top-most object passed to it. To fix this, modify acpi_bus_offline_companions() to return an error code if hotplug is disabled for the given device object. [Also change the name of the function to acpi_bus_offline(), because it is not only about companions any more, and change the name of acpi_bus_online_companions() accordingly.] Make acpi_scan_hot_remove() propagate that error to its callers. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Toshi Kani <toshi.kani@hp.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/scan.c57
1 files changed, 36 insertions, 21 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 4d377a22622a..9bdcc187bf4b 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -125,8 +125,8 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
125} 125}
126static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); 126static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
127 127
128static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl, 128static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data,
129 void *data, void **ret_p) 129 void **ret_p)
130{ 130{
131 struct acpi_device *device = NULL; 131 struct acpi_device *device = NULL;
132 struct acpi_device_physical_node *pn; 132 struct acpi_device_physical_node *pn;
@@ -136,6 +136,11 @@ static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl,
136 if (acpi_bus_get_device(handle, &device)) 136 if (acpi_bus_get_device(handle, &device))
137 return AE_OK; 137 return AE_OK;
138 138
139 if (device->handler && !device->handler->hotplug.enabled) {
140 *ret_p = &device->dev;
141 return AE_SUPPORT;
142 }
143
139 mutex_lock(&device->physical_node_lock); 144 mutex_lock(&device->physical_node_lock);
140 145
141 list_for_each_entry(pn, &device->physical_node_list, node) { 146 list_for_each_entry(pn, &device->physical_node_list, node) {
@@ -168,8 +173,8 @@ static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl,
168 return status; 173 return status;
169} 174}
170 175
171static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl, 176static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data,
172 void *data, void **ret_p) 177 void **ret_p)
173{ 178{
174 struct acpi_device *device = NULL; 179 struct acpi_device *device = NULL;
175 struct acpi_device_physical_node *pn; 180 struct acpi_device_physical_node *pn;
@@ -214,26 +219,32 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
214 * If the first pass is successful, the second one isn't needed, though. 219 * If the first pass is successful, the second one isn't needed, though.
215 */ 220 */
216 errdev = NULL; 221 errdev = NULL;
217 acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, 222 status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
218 NULL, acpi_bus_offline_companions, 223 NULL, acpi_bus_offline, (void *)false,
219 (void *)false, (void **)&errdev); 224 (void **)&errdev);
220 acpi_bus_offline_companions(handle, 0, (void *)false, (void **)&errdev); 225 if (status == AE_SUPPORT) {
226 dev_warn(errdev, "Offline disabled.\n");
227 acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
228 acpi_bus_online, NULL, NULL, NULL);
229 put_device(&device->dev);
230 return -EPERM;
231 }
232 acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev);
221 if (errdev) { 233 if (errdev) {
222 errdev = NULL; 234 errdev = NULL;
223 acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, 235 acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
224 NULL, acpi_bus_offline_companions, 236 NULL, acpi_bus_offline, (void *)true,
225 (void *)true , (void **)&errdev); 237 (void **)&errdev);
226 if (!errdev || acpi_force_hot_remove) 238 if (!errdev || acpi_force_hot_remove)
227 acpi_bus_offline_companions(handle, 0, (void *)true, 239 acpi_bus_offline(handle, 0, (void *)true,
228 (void **)&errdev); 240 (void **)&errdev);
229 241
230 if (errdev && !acpi_force_hot_remove) { 242 if (errdev && !acpi_force_hot_remove) {
231 dev_warn(errdev, "Offline failed.\n"); 243 dev_warn(errdev, "Offline failed.\n");
232 acpi_bus_online_companions(handle, 0, NULL, NULL); 244 acpi_bus_online(handle, 0, NULL, NULL);
233 acpi_walk_namespace(ACPI_TYPE_ANY, handle, 245 acpi_walk_namespace(ACPI_TYPE_ANY, handle,
234 ACPI_UINT32_MAX, 246 ACPI_UINT32_MAX, acpi_bus_online,
235 acpi_bus_online_companions, NULL, 247 NULL, NULL, NULL);
236 NULL, NULL);
237 put_device(&device->dev); 248 put_device(&device->dev);
238 return -EBUSY; 249 return -EBUSY;
239 } 250 }
@@ -290,10 +301,9 @@ static void acpi_bus_device_eject(void *context)
290 goto err_out; 301 goto err_out;
291 302
292 handler = device->handler; 303 handler = device->handler;
293 if (!handler || !handler->hotplug.enabled) { 304 if (!handler || !handler->hotplug.enabled)
294 ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; 305 goto err_support;
295 goto err_out; 306
296 }
297 acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, 307 acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
298 ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); 308 ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
299 if (handler->hotplug.mode == AHM_CONTAINER) 309 if (handler->hotplug.mode == AHM_CONTAINER)
@@ -301,14 +311,19 @@ static void acpi_bus_device_eject(void *context)
301 311
302 get_device(&device->dev); 312 get_device(&device->dev);
303 error = acpi_scan_hot_remove(device); 313 error = acpi_scan_hot_remove(device);
304 if (error) 314 if (error == -EPERM) {
315 goto err_support;
316 } else if (error) {
305 goto err_out; 317 goto err_out;
318 }
306 319
307 out: 320 out:
308 mutex_unlock(&acpi_scan_lock); 321 mutex_unlock(&acpi_scan_lock);
309 unlock_device_hotplug(); 322 unlock_device_hotplug();
310 return; 323 return;
311 324
325 err_support:
326 ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
312 err_out: 327 err_out:
313 acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code, 328 acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code,
314 NULL); 329 NULL);