aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2012-04-18 05:43:09 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-04-26 10:30:12 -0400
commit2f9a0c880d5c1e159f647950a2eed26618ad2ff1 (patch)
tree99bc40ffdac05c88f97eb5e49afe01c2a85440a9
parente631f578048e2afd8bfede2e9dc86aa4592def3a (diff)
[media] V4L: soc-camera: protect hosts during probing from overzealous user-space
If multiple clients are registered on a single camera host interface, the user-space hot-plug software can try to access the one, that probed first, before probing of the second one has completed. This can be handled by individual host drivers, but it is even better to hold back the user-space until all the probing on this host has completed. This fixes a race on ecovec with two clients registered on the CEU1 host, which otherwise triggers a BUG() in sh_mobile_ceu_remove_device(). Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/soc_camera.c8
-rw-r--r--include/media/soc_camera.h3
2 files changed, 8 insertions, 3 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index eb25756a07af..aedb970d13f6 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -530,7 +530,10 @@ static int soc_camera_open(struct file *file)
530 if (icl->reset) 530 if (icl->reset)
531 icl->reset(icd->pdev); 531 icl->reset(icd->pdev);
532 532
533 /* Don't mess with the host during probe */
534 mutex_lock(&ici->host_lock);
533 ret = ici->ops->add(icd); 535 ret = ici->ops->add(icd);
536 mutex_unlock(&ici->host_lock);
534 if (ret < 0) { 537 if (ret < 0) {
535 dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret); 538 dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
536 goto eiciadd; 539 goto eiciadd;
@@ -956,7 +959,7 @@ static void scan_add_host(struct soc_camera_host *ici)
956{ 959{
957 struct soc_camera_device *icd; 960 struct soc_camera_device *icd;
958 961
959 mutex_lock(&list_lock); 962 mutex_lock(&ici->host_lock);
960 963
961 list_for_each_entry(icd, &devices, list) { 964 list_for_each_entry(icd, &devices, list) {
962 if (icd->iface == ici->nr) { 965 if (icd->iface == ici->nr) {
@@ -967,7 +970,7 @@ static void scan_add_host(struct soc_camera_host *ici)
967 } 970 }
968 } 971 }
969 972
970 mutex_unlock(&list_lock); 973 mutex_unlock(&ici->host_lock);
971} 974}
972 975
973#ifdef CONFIG_I2C_BOARDINFO 976#ifdef CONFIG_I2C_BOARDINFO
@@ -1313,6 +1316,7 @@ int soc_camera_host_register(struct soc_camera_host *ici)
1313 list_add_tail(&ici->list, &hosts); 1316 list_add_tail(&ici->list, &hosts);
1314 mutex_unlock(&list_lock); 1317 mutex_unlock(&list_lock);
1315 1318
1319 mutex_init(&ici->host_lock);
1316 scan_add_host(ici); 1320 scan_add_host(ici);
1317 1321
1318 return 0; 1322 return 0;
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index b5c2b6cb0d81..cad374bdcf4b 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -59,7 +59,8 @@ struct soc_camera_device {
59struct soc_camera_host { 59struct soc_camera_host {
60 struct v4l2_device v4l2_dev; 60 struct v4l2_device v4l2_dev;
61 struct list_head list; 61 struct list_head list;
62 unsigned char nr; /* Host number */ 62 struct mutex host_lock; /* Protect during probing */
63 unsigned char nr; /* Host number */
63 void *priv; 64 void *priv;
64 const char *drv_name; 65 const char *drv_name;
65 struct soc_camera_host_ops *ops; 66 struct soc_camera_host_ops *ops;