aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hansverk@cisco.com>2016-12-09 09:00:49 -0500
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2016-12-21 04:03:27 -0500
commitf60f35609f89ef4fee73776bc1ef697923251995 (patch)
tree0fe5ffbf5548a46f74b70bd40d09eefefcc35600
parentd3d64bc7408f1ff0b0ff8354056e2a48eda5886d (diff)
[media] cec: fix race between configuring and unconfiguring
This race was discovered by running cec-compliance -A with the cec module debug parameter set to 2: suddenly the test would fail. It turns out that this happens when the test configures the adapter in non-blocking mode, then it waits for the CEC_EVENT_STATE_CHANGE event and once the event is received it unconfigures the adapter. What happened was that the unconfigure was executed while the configure was still transmitting the Report Features and Report Physical Address messages. This messed up the internal state of the cec_adapter. The fix is to transmit those messages with the adap->lock mutex held (this will just queue them up in the internal transmit queue, and not actually transmit anything yet). Only unlock the mutex once everything is done. The main thread will dequeue the messages from the internal transmit queue and transmit them one by one, unless an unconfigure was done, and in that case any messages are just dropped. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
-rw-r--r--drivers/media/cec/cec-adap.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index f3d495654a53..ebb5e391b800 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -1256,8 +1256,17 @@ configured:
1256 adap->is_configured = true; 1256 adap->is_configured = true;
1257 adap->is_configuring = false; 1257 adap->is_configuring = false;
1258 cec_post_state_event(adap); 1258 cec_post_state_event(adap);
1259 mutex_unlock(&adap->lock);
1260 1259
1260 /*
1261 * Now post the Report Features and Report Physical Address broadcast
1262 * messages. Note that these are non-blocking transmits, meaning that
1263 * they are just queued up and once adap->lock is unlocked the main
1264 * thread will kick in and start transmitting these.
1265 *
1266 * If after this function is done (but before one or more of these
1267 * messages are actually transmitted) the CEC adapter is unconfigured,
1268 * then any remaining messages will be dropped by the main thread.
1269 */
1261 for (i = 0; i < las->num_log_addrs; i++) { 1270 for (i = 0; i < las->num_log_addrs; i++) {
1262 struct cec_msg msg = {}; 1271 struct cec_msg msg = {};
1263 1272
@@ -1271,7 +1280,7 @@ configured:
1271 if (las->log_addr[i] != CEC_LOG_ADDR_UNREGISTERED && 1280 if (las->log_addr[i] != CEC_LOG_ADDR_UNREGISTERED &&
1272 adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0) { 1281 adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0) {
1273 cec_fill_msg_report_features(adap, &msg, i); 1282 cec_fill_msg_report_features(adap, &msg, i);
1274 cec_transmit_msg(adap, &msg, false); 1283 cec_transmit_msg_fh(adap, &msg, NULL, false);
1275 } 1284 }
1276 1285
1277 /* Report Physical Address */ 1286 /* Report Physical Address */
@@ -1280,12 +1289,11 @@ configured:
1280 dprintk(2, "config: la %d pa %x.%x.%x.%x\n", 1289 dprintk(2, "config: la %d pa %x.%x.%x.%x\n",
1281 las->log_addr[i], 1290 las->log_addr[i],
1282 cec_phys_addr_exp(adap->phys_addr)); 1291 cec_phys_addr_exp(adap->phys_addr));
1283 cec_transmit_msg(adap, &msg, false); 1292 cec_transmit_msg_fh(adap, &msg, NULL, false);
1284 } 1293 }
1285 mutex_lock(&adap->lock);
1286 adap->kthread_config = NULL; 1294 adap->kthread_config = NULL;
1287 mutex_unlock(&adap->lock);
1288 complete(&adap->config_completion); 1295 complete(&adap->config_completion);
1296 mutex_unlock(&adap->lock);
1289 return 0; 1297 return 0;
1290 1298
1291unconfigure: 1299unconfigure: