diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-08-30 08:14:25 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-08-30 08:14:25 -0400 |
commit | 7bc583d102d6f89c3dc4b502caec6ba03c9d318f (patch) | |
tree | 550e6333f2205f006849984b52408ed796bcd0c5 /drivers | |
parent | da48afb26b40ebb5d6b0e84793e0662859c7ea20 (diff) | |
parent | f943db40c29f3c82a56956e9ca36f21d6d855db9 (diff) |
Merge branch 'acpi-hotplug'
* acpi-hotplug:
ACPI / hotplug: Remove containers synchronously
driver core / ACPI: Avoid device hot remove locking issues
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/scan.c | 49 | ||||
-rw-r--r-- | drivers/base/core.c | 43 | ||||
-rw-r--r-- | drivers/base/memory.c | 4 |
3 files changed, 46 insertions, 50 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e76365136ba3..61d090b6ce25 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -287,6 +287,7 @@ static void acpi_bus_device_eject(void *context) | |||
287 | struct acpi_device *device = NULL; | 287 | struct acpi_device *device = NULL; |
288 | struct acpi_scan_handler *handler; | 288 | struct acpi_scan_handler *handler; |
289 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | 289 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |
290 | int error; | ||
290 | 291 | ||
291 | mutex_lock(&acpi_scan_lock); | 292 | mutex_lock(&acpi_scan_lock); |
292 | 293 | ||
@@ -301,17 +302,13 @@ static void acpi_bus_device_eject(void *context) | |||
301 | } | 302 | } |
302 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, | 303 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, |
303 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | 304 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); |
304 | if (handler->hotplug.mode == AHM_CONTAINER) { | 305 | if (handler->hotplug.mode == AHM_CONTAINER) |
305 | device->flags.eject_pending = true; | ||
306 | kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); | 306 | kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); |
307 | } else { | ||
308 | int error; | ||
309 | 307 | ||
310 | get_device(&device->dev); | 308 | get_device(&device->dev); |
311 | error = acpi_scan_hot_remove(device); | 309 | error = acpi_scan_hot_remove(device); |
312 | if (error) | 310 | if (error) |
313 | goto err_out; | 311 | goto err_out; |
314 | } | ||
315 | 312 | ||
316 | out: | 313 | out: |
317 | mutex_unlock(&acpi_scan_lock); | 314 | mutex_unlock(&acpi_scan_lock); |
@@ -496,7 +493,6 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, | |||
496 | struct acpi_eject_event *ej_event; | 493 | struct acpi_eject_event *ej_event; |
497 | acpi_object_type not_used; | 494 | acpi_object_type not_used; |
498 | acpi_status status; | 495 | acpi_status status; |
499 | u32 ost_source; | ||
500 | int ret; | 496 | int ret; |
501 | 497 | ||
502 | if (!count || buf[0] != '1') | 498 | if (!count || buf[0] != '1') |
@@ -510,43 +506,28 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, | |||
510 | if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) | 506 | if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) |
511 | return -ENODEV; | 507 | return -ENODEV; |
512 | 508 | ||
513 | mutex_lock(&acpi_scan_lock); | ||
514 | |||
515 | if (acpi_device->flags.eject_pending) { | ||
516 | /* ACPI eject notification event. */ | ||
517 | ost_source = ACPI_NOTIFY_EJECT_REQUEST; | ||
518 | acpi_device->flags.eject_pending = 0; | ||
519 | } else { | ||
520 | /* Eject initiated by user space. */ | ||
521 | ost_source = ACPI_OST_EC_OSPM_EJECT; | ||
522 | } | ||
523 | ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); | 509 | ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); |
524 | if (!ej_event) { | 510 | if (!ej_event) { |
525 | ret = -ENOMEM; | 511 | ret = -ENOMEM; |
526 | goto err_out; | 512 | goto err_out; |
527 | } | 513 | } |
528 | acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source, | 514 | acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, |
529 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | 515 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); |
530 | ej_event->device = acpi_device; | 516 | ej_event->device = acpi_device; |
531 | ej_event->event = ost_source; | 517 | ej_event->event = ACPI_OST_EC_OSPM_EJECT; |
532 | get_device(&acpi_device->dev); | 518 | get_device(&acpi_device->dev); |
533 | status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event); | 519 | status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event); |
534 | if (ACPI_FAILURE(status)) { | 520 | if (ACPI_SUCCESS(status)) |
535 | put_device(&acpi_device->dev); | 521 | return count; |
536 | kfree(ej_event); | ||
537 | ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; | ||
538 | goto err_out; | ||
539 | } | ||
540 | ret = count; | ||
541 | 522 | ||
542 | out: | 523 | put_device(&acpi_device->dev); |
543 | mutex_unlock(&acpi_scan_lock); | 524 | kfree(ej_event); |
544 | return ret; | 525 | ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; |
545 | 526 | ||
546 | err_out: | 527 | err_out: |
547 | acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source, | 528 | acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, |
548 | ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); | 529 | ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); |
549 | goto out; | 530 | return ret; |
550 | } | 531 | } |
551 | 532 | ||
552 | static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); | 533 | static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); |
diff --git a/drivers/base/core.c b/drivers/base/core.c index 8856d74545d9..ac419a15fcd4 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -49,6 +49,28 @@ static struct kobject *dev_kobj; | |||
49 | struct kobject *sysfs_dev_char_kobj; | 49 | struct kobject *sysfs_dev_char_kobj; |
50 | struct kobject *sysfs_dev_block_kobj; | 50 | struct kobject *sysfs_dev_block_kobj; |
51 | 51 | ||
52 | static DEFINE_MUTEX(device_hotplug_lock); | ||
53 | |||
54 | void lock_device_hotplug(void) | ||
55 | { | ||
56 | mutex_lock(&device_hotplug_lock); | ||
57 | } | ||
58 | |||
59 | void unlock_device_hotplug(void) | ||
60 | { | ||
61 | mutex_unlock(&device_hotplug_lock); | ||
62 | } | ||
63 | |||
64 | int lock_device_hotplug_sysfs(void) | ||
65 | { | ||
66 | if (mutex_trylock(&device_hotplug_lock)) | ||
67 | return 0; | ||
68 | |||
69 | /* Avoid busy looping (5 ms of sleep should do). */ | ||
70 | msleep(5); | ||
71 | return restart_syscall(); | ||
72 | } | ||
73 | |||
52 | #ifdef CONFIG_BLOCK | 74 | #ifdef CONFIG_BLOCK |
53 | static inline int device_is_not_partition(struct device *dev) | 75 | static inline int device_is_not_partition(struct device *dev) |
54 | { | 76 | { |
@@ -408,9 +430,9 @@ static ssize_t show_online(struct device *dev, struct device_attribute *attr, | |||
408 | { | 430 | { |
409 | bool val; | 431 | bool val; |
410 | 432 | ||
411 | lock_device_hotplug(); | 433 | device_lock(dev); |
412 | val = !dev->offline; | 434 | val = !dev->offline; |
413 | unlock_device_hotplug(); | 435 | device_unlock(dev); |
414 | return sprintf(buf, "%u\n", val); | 436 | return sprintf(buf, "%u\n", val); |
415 | } | 437 | } |
416 | 438 | ||
@@ -424,7 +446,10 @@ static ssize_t store_online(struct device *dev, struct device_attribute *attr, | |||
424 | if (ret < 0) | 446 | if (ret < 0) |
425 | return ret; | 447 | return ret; |
426 | 448 | ||
427 | lock_device_hotplug(); | 449 | ret = lock_device_hotplug_sysfs(); |
450 | if (ret) | ||
451 | return ret; | ||
452 | |||
428 | ret = val ? device_online(dev) : device_offline(dev); | 453 | ret = val ? device_online(dev) : device_offline(dev); |
429 | unlock_device_hotplug(); | 454 | unlock_device_hotplug(); |
430 | return ret < 0 ? ret : count; | 455 | return ret < 0 ? ret : count; |
@@ -1479,18 +1504,6 @@ EXPORT_SYMBOL_GPL(put_device); | |||
1479 | EXPORT_SYMBOL_GPL(device_create_file); | 1504 | EXPORT_SYMBOL_GPL(device_create_file); |
1480 | EXPORT_SYMBOL_GPL(device_remove_file); | 1505 | EXPORT_SYMBOL_GPL(device_remove_file); |
1481 | 1506 | ||
1482 | static DEFINE_MUTEX(device_hotplug_lock); | ||
1483 | |||
1484 | void lock_device_hotplug(void) | ||
1485 | { | ||
1486 | mutex_lock(&device_hotplug_lock); | ||
1487 | } | ||
1488 | |||
1489 | void unlock_device_hotplug(void) | ||
1490 | { | ||
1491 | mutex_unlock(&device_hotplug_lock); | ||
1492 | } | ||
1493 | |||
1494 | static int device_check_offline(struct device *dev, void *not_used) | 1507 | static int device_check_offline(struct device *dev, void *not_used) |
1495 | { | 1508 | { |
1496 | int ret; | 1509 | int ret; |
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 2b7813ec6d02..6f4c99ff1ce7 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -351,7 +351,9 @@ store_mem_state(struct device *dev, | |||
351 | 351 | ||
352 | mem = container_of(dev, struct memory_block, dev); | 352 | mem = container_of(dev, struct memory_block, dev); |
353 | 353 | ||
354 | lock_device_hotplug(); | 354 | ret = lock_device_hotplug_sysfs(); |
355 | if (ret) | ||
356 | return ret; | ||
355 | 357 | ||
356 | if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) { | 358 | if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) { |
357 | offline = false; | 359 | offline = false; |