lkml.org 
[lkml]   [2012]   [Sep]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[ 060/218] ACPI / PM: Fix resource_lock dead lock in acpi_power_on_device
    Date
    3.4-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Lin Ming <ming.m.lin@intel.com>

    commit 40bf66ec9791f1452b90b82aadc3b6e6aee201f5 upstream.

    Commit 0090def("ACPI: Add interface to register/unregister device
    to/from power resources") used resource_lock to protect the devices list
    that relies on power resource. It caused a mutex dead lock, as below

    acpi_power_on ---> lock resource_lock
    __acpi_power_on
    acpi_power_on_device
    acpi_power_get_inferred_state
    acpi_power_get_list_state ---> lock resource_lock

    This patch adds a new mutex "devices_lock" to protect the devices list
    and calls acpi_power_on_device in acpi_power_on, instead of
    __acpi_power_on, after the resource_lock is released.

    [rjw: Changed data type of a boolean variable to bool.]

    Signed-off-by: Lin Ming <ming.m.lin@intel.com>
    Signed-off-by: Aaron Lu <aaron.lu@intel.com>
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/acpi/power.c | 34 +++++++++++++++++++++++-----------
    1 file changed, 23 insertions(+), 11 deletions(-)

    --- a/drivers/acpi/power.c
    +++ b/drivers/acpi/power.c
    @@ -103,6 +103,7 @@ struct acpi_power_resource {

    /* List of devices relying on this power resource */
    struct acpi_power_resource_device *devices;
    + struct mutex devices_lock;
    };

    static struct list_head acpi_power_resource_list;
    @@ -221,7 +222,6 @@ static void acpi_power_on_device(struct

    static int __acpi_power_on(struct acpi_power_resource *resource)
    {
    - struct acpi_power_resource_device *device_list = resource->devices;
    acpi_status status = AE_OK;

    status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
    @@ -234,19 +234,15 @@ static int __acpi_power_on(struct acpi_p
    ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
    resource->name));

    - while (device_list) {
    - acpi_power_on_device(device_list->device);
    -
    - device_list = device_list->next;
    - }
    -
    return 0;
    }

    static int acpi_power_on(acpi_handle handle)
    {
    int result = 0;
    + bool resume_device = false;
    struct acpi_power_resource *resource = NULL;
    + struct acpi_power_resource_device *device_list;

    result = acpi_power_get_context(handle, &resource);
    if (result)
    @@ -262,10 +258,25 @@ static int acpi_power_on(acpi_handle han
    result = __acpi_power_on(resource);
    if (result)
    resource->ref_count--;
    + else
    + resume_device = true;
    }

    mutex_unlock(&resource->resource_lock);

    + if (!resume_device)
    + return result;
    +
    + mutex_lock(&resource->devices_lock);
    +
    + device_list = resource->devices;
    + while (device_list) {
    + acpi_power_on_device(device_list->device);
    + device_list = device_list->next;
    + }
    +
    + mutex_unlock(&resource->devices_lock);
    +
    return result;
    }

    @@ -351,7 +362,7 @@ static void __acpi_power_resource_unregi
    if (acpi_power_get_context(res_handle, &resource))
    return;

    - mutex_lock(&resource->resource_lock);
    + mutex_lock(&resource->devices_lock);
    prev = NULL;
    curr = resource->devices;
    while (curr) {
    @@ -368,7 +379,7 @@ static void __acpi_power_resource_unregi
    prev = curr;
    curr = curr->next;
    }
    - mutex_unlock(&resource->resource_lock);
    + mutex_unlock(&resource->devices_lock);
    }

    /* Unlink dev from all power resources in _PR0 */
    @@ -409,10 +420,10 @@ static int __acpi_power_resource_registe

    power_resource_device->device = powered_device;

    - mutex_lock(&resource->resource_lock);
    + mutex_lock(&resource->devices_lock);
    power_resource_device->next = resource->devices;
    resource->devices = power_resource_device;
    - mutex_unlock(&resource->resource_lock);
    + mutex_unlock(&resource->devices_lock);

    return 0;
    }
    @@ -715,6 +726,7 @@ static int acpi_power_add(struct acpi_de

    resource->device = device;
    mutex_init(&resource->resource_lock);
    + mutex_init(&resource->devices_lock);
    strcpy(resource->name, device->pnp.bus_id);
    strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
    strcpy(acpi_device_class(device), ACPI_POWER_CLASS);



    \
     
     \ /
      Last update: 2012-09-29 02:21    [W:2.325 / U:0.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site