[WIP PATCH 4/4] ACPI: button: Fix lid notification locks

From: Benjamin Tissoires
Date: Thu Jun 01 2017 - 14:47:24 EST


From: Lv Zheng <lv.zheng@xxxxxxxxx>

acpi/button.c now contains the logic to avoid frequently replayed events
which originally was ensured by using blocking notifier.
On the contrary, using a blocking notifier is wrong as it could keep on
returning NOTIFY_DONE, causing events lost.

This patch thus changes lid notification to raw notifier in order not to
have any events lost.

Signed-off-by: Lv Zheng <lv.zheng@xxxxxxxxx>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@xxxxxxxxxx>
---
drivers/acpi/button.c | 68 ++++++++++++++++++++-------------------------------
1 file changed, 27 insertions(+), 41 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 03e5981..1927b08 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -114,7 +114,7 @@ struct acpi_button {

static DEFINE_MUTEX(button_input_lock);

-static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
+static RAW_NOTIFIER_HEAD(acpi_lid_notifier);
static struct acpi_device *lid_device;
static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;

@@ -179,14 +179,12 @@ static int acpi_lid_evaluate_state(struct acpi_device *device)
return lid_state ? 1 : 0;
}

-static int acpi_lid_notify_state(struct acpi_device *device, int state)
+static void acpi_lid_notify_state(struct acpi_device *device, int state)
{
struct acpi_button *button = acpi_driver_data(device);

- /* button_input_lock must be held */
-
if (!button->input)
- return 0;
+ return;

/*
* If the lid is unreliable, always send an "open" event before any
@@ -201,8 +199,6 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state)

if (state)
pm_wakeup_hard_event(&device->dev);
-
- return 0;
}

/*
@@ -214,28 +210,14 @@ static void acpi_button_lid_events(struct input_handle *handle,
{
const struct input_value *v;
int state = -1;
- int ret;

for (v = vals; v != vals + count; v++) {
switch (v->type) {
case EV_SYN:
- if (v->code == SYN_REPORT && state >= 0) {
- ret = blocking_notifier_call_chain(&acpi_lid_notifier,
+ if (v->code == SYN_REPORT && state >= 0)
+ (void)raw_notifier_call_chain(&acpi_lid_notifier,
state,
lid_device);
- if (ret == NOTIFY_DONE)
- ret = blocking_notifier_call_chain(&acpi_lid_notifier,
- state,
- lid_device);
- if (ret == NOTIFY_DONE || ret == NOTIFY_OK) {
- /*
- * It is also regarded as success if
- * the notifier_chain returns NOTIFY_OK
- * or NOTIFY_DONE.
- */
- ret = 0;
- }
- }
break;
case EV_SW:
if (v->code == SW_LID)
@@ -433,13 +415,25 @@ static int acpi_button_remove_fs(struct acpi_device *device)
-------------------------------------------------------------------------- */
int acpi_lid_notifier_register(struct notifier_block *nb)
{
- return blocking_notifier_chain_register(&acpi_lid_notifier, nb);
+ return raw_notifier_chain_register(&acpi_lid_notifier, nb);
}
EXPORT_SYMBOL(acpi_lid_notifier_register);

+static inline int __acpi_lid_notifier_unregister(struct notifier_block *nb,
+ bool sync)
+{
+ int ret;
+
+ ret = raw_notifier_chain_unregister(&acpi_lid_notifier, nb);
+ if (sync)
+ synchronize_rcu();
+
+ return ret;
+}
+
int acpi_lid_notifier_unregister(struct notifier_block *nb)
{
- return blocking_notifier_chain_unregister(&acpi_lid_notifier, nb);
+ return __acpi_lid_notifier_unregister(nb, false);
}
EXPORT_SYMBOL(acpi_lid_notifier_unregister);

@@ -452,40 +446,36 @@ int acpi_lid_open(void)
}
EXPORT_SYMBOL(acpi_lid_open);

-static int acpi_lid_update_state(struct acpi_device *device)
+static void acpi_lid_update_state(struct acpi_device *device)
{
int state;

state = acpi_lid_evaluate_state(device);
if (state < 0)
- return state;
+ return;

- return acpi_lid_notify_state(device, state);
+ acpi_lid_notify_state(device, state);
}

-static int acpi_lid_notify(struct acpi_device *device)
+static void acpi_lid_notify(struct acpi_device *device)
{
struct acpi_button *button = acpi_driver_data(device);
- int ret;

mutex_lock(&button_input_lock);
if (!button->input)
acpi_button_add_input(device);
- ret = acpi_lid_update_state(device);
+ acpi_lid_update_state(device);
mutex_unlock(&button_input_lock);
-
-
- return ret;
}

static void acpi_lid_initialize_state(struct acpi_device *device)
{
switch (lid_init_state) {
case ACPI_BUTTON_LID_INIT_OPEN:
- (void)acpi_lid_notify_state(device, 1);
+ acpi_lid_notify_state(device, 1);
break;
case ACPI_BUTTON_LID_INIT_METHOD:
- (void)acpi_lid_update_state(device);
+ acpi_lid_update_state(device);
break;
case ACPI_BUTTON_LID_INIT_IGNORE:
default:
@@ -641,11 +631,7 @@ static int acpi_lid_update_reliable(struct acpi_device *device)
if (error)
return error;

- error = acpi_lid_update_state(device);
- if (error) {
- acpi_button_remove_input(device);
- return error;
- }
+ acpi_lid_update_state(device);
}

if (!lid_reliable && button->input)
--
2.9.4