diff mbox

[v2,media] dvb-frontends/stv0910: prevent consecutive mutex_unlock()'s

Message ID 20171026183737.10655-1-d.scheller.oss@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Daniel Scheller Oct. 26, 2017, 6:37 p.m. UTC
From: Daniel Scheller <d.scheller@gmx.net>

When calling gate_ctrl() with enable=0 if previously the mutex wasn't
locked (ie. on enable=1 failure and subdrivers not handling this properly,
or by otherwise badly behaving drivers), the i2c_lock could be unlocked
consecutively which isn't allowed. Prevent this by checking the lock
state, and actually call mutex_unlock() only when certain the lock
is actually held.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
Tested-by: Jasmin Jessich <jasmin@anw.at>
Cc: Ralph Metzler <rjkm@metzlerbros.de>
---
Changes from v1 to v2:
 - use mutex_is_locked() instead of tracking the lock state in a separate
   variable
 - print message to KERN_DEBUG after a double unlock was prevented

 drivers/media/dvb-frontends/stv0910.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)
diff mbox

Patch

diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c
index 73f6df0abbfe..5d0146782488 100644
--- a/drivers/media/dvb-frontends/stv0910.c
+++ b/drivers/media/dvb-frontends/stv0910.c
@@ -1240,8 +1240,17 @@  static int gate_ctrl(struct dvb_frontend *fe, int enable)
 
 	if (write_reg(state, state->nr ? RSTV0910_P2_I2CRPT :
 		      RSTV0910_P1_I2CRPT, i2crpt) < 0) {
-		/* don't hold the I2C bus lock on failure */
-		mutex_unlock(&state->base->i2c_lock);
+		/*
+		 * don't hold the I2C bus lock on failure while preventing
+		 * consecutive and disallowed calls to mutex_unlock()
+		 */
+		if (mutex_is_locked(&state->base->i2c_lock))
+			mutex_unlock(&state->base->i2c_lock);
+		else
+			dev_dbg(&state->base->i2c->dev,
+				"%s(): prevented consecutive mutex_unlock\n",
+				__func__);
+
 		dev_err(&state->base->i2c->dev,
 			"%s() write_reg failure (enable=%d)\n",
 			__func__, enable);
@@ -1250,8 +1259,15 @@  static int gate_ctrl(struct dvb_frontend *fe, int enable)
 
 	state->i2crpt = i2crpt;
 
-	if (!enable)
-		mutex_unlock(&state->base->i2c_lock);
+	if (!enable) {
+		if (mutex_is_locked(&state->base->i2c_lock))
+			mutex_unlock(&state->base->i2c_lock);
+		else
+			dev_dbg(&state->base->i2c->dev,
+				"%s(): prevented consecutive mutex_unlock\n",
+				__func__);
+	}
+
 	return 0;
 }