[PATCH v4 2/3] iio: accel: bmc150: take the lock before checking ev_enable_state

Gabriel Rondon <[email protected]>
Newsgroups gmane.linux.kernel.iio,gmane.linux.kernel,gmane.linux.kernel.stable
Message-ID <[email protected]>
bmc150_accel_write_event_config() compared the requested state against
data->ev_enable_state before acquiring data->mutex. Two threads racing
to enable and disable the same event can both pass the check and then
both call bmc150_accel_set_interrupt(), which tracks enables with an
atomic users count. The inc/dec can become unbalanced, leaving the
interrupt enabled or disabled against the callers' intent.

Move the check inside the locked region so the test of ev_enable_state
and its update are atomic with respect to the interrupt accounting.

Fixes: 14ee64f438b8 ("iio: bmc150: exit early if event / trigger state is not changed")
Cc: [email protected]
Signed-off-by: Gabriel Rondon <[email protected]>
---
 drivers/iio/accel/bmc150-accel-core.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index d067da9b5ce4..bcbb9f0c830a 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -805,11 +805,13 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
 	int ret;
 
-	if (state == data->ev_enable_state)
-		return 0;
-
 	mutex_lock(&data->mutex);
 
+	if (state == data->ev_enable_state) {
+		mutex_unlock(&data->mutex);
+		return 0;
+	}
+
 	ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_ANY_MOTION,
 					 state);
 	if (ret < 0) {
-- 
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.