aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2006-09-23 21:30:50 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2006-10-03 14:13:38 -0400
commit759100531d76f36714dde0f05a09245e9e921e4c (patch)
tree453877480d05adcab9b2f49c3a5511878aef13fe
parent32ffa9ae03c529df4208b63b4b17c6d84141faa3 (diff)
V4L/DVB (4663): Pvrusb2: Get rid of private global context array brain damage
A previous attempt to deal with the upcoming loss of video_set_drvdata() and video_get_drvdata() resulted in logic which causes a circular locking dependency - also known as a deadlock. This changeset attacks the problem in a different manner, using a technique that no longer requires the problematic mutex (or that private global array either). Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c111
1 files changed, 36 insertions, 75 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 156e375c93e9..f4c54ef4beaa 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -28,6 +28,7 @@
28#include "pvrusb2-debug.h" 28#include "pvrusb2-debug.h"
29#include "pvrusb2-v4l2.h" 29#include "pvrusb2-v4l2.h"
30#include "pvrusb2-ioread.h" 30#include "pvrusb2-ioread.h"
31#include <linux/videodev.h>
31#include <linux/videodev2.h> 32#include <linux/videodev2.h>
32#include <media/v4l2-common.h> 33#include <media/v4l2-common.h>
33 34
@@ -35,21 +36,10 @@ struct pvr2_v4l2_dev;
35struct pvr2_v4l2_fh; 36struct pvr2_v4l2_fh;
36struct pvr2_v4l2; 37struct pvr2_v4l2;
37 38
38/* V4L no longer provide the ability to set / get a private context pointer
39 (i.e. video_get_drvdata / video_set_drvdata), which means we have to
40 concoct our own context locating mechanism. Supposedly this is intended
41 to simplify driver implementation. It's not clear to me how that can
42 possibly be true. Our solution here is to maintain a lookup table of
43 our context instances, indexed by the minor device number of the V4L
44 device. See pvr2_v4l2_open() for some implications of this approach. */
45static struct pvr2_v4l2_dev *devices[256];
46static DEFINE_MUTEX(device_lock);
47
48struct pvr2_v4l2_dev { 39struct pvr2_v4l2_dev {
40 struct video_device devbase; /* MUST be first! */
49 struct pvr2_v4l2 *v4lp; 41 struct pvr2_v4l2 *v4lp;
50 struct video_device *vdev;
51 struct pvr2_context_stream *stream; 42 struct pvr2_context_stream *stream;
52 int ctxt_idx;
53 enum pvr2_config config; 43 enum pvr2_config config;
54}; 44};
55 45
@@ -74,7 +64,7 @@ struct pvr2_v4l2 {
74 struct v4l2_prio_state prio; 64 struct v4l2_prio_state prio;
75 65
76 /* streams */ 66 /* streams */
77 struct pvr2_v4l2_dev video_dev; 67 struct pvr2_v4l2_dev *vdev;
78}; 68};
79 69
80static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1}; 70static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
@@ -718,21 +708,22 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
718static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) 708static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
719{ 709{
720 printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n", 710 printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n",
721 dip->vdev->minor,pvr2_config_get_name(dip->config)); 711 dip->devbase.minor,pvr2_config_get_name(dip->config));
722 if (dip->ctxt_idx >= 0) { 712
723 mutex_lock(&device_lock); 713 /* Paranoia */
724 devices[dip->ctxt_idx] = NULL; 714 dip->v4lp = 0;
725 dip->ctxt_idx = -1; 715 dip->stream = 0;
726 mutex_unlock(&device_lock); 716
727 } 717 /* Actual deallocation happens later when all internal references
728 video_unregister_device(dip->vdev); 718 are gone. */
719 video_unregister_device(&dip->devbase);
729} 720}
730 721
731 722
732static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp) 723static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
733{ 724{
734 pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1); 725 pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);
735 pvr2_v4l2_dev_destroy(&vp->video_dev); 726 pvr2_v4l2_dev_destroy(vp->vdev);
736 727
737 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp); 728 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
738 pvr2_channel_done(&vp->channel); 729 pvr2_channel_done(&vp->channel);
@@ -740,6 +731,14 @@ static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
740} 731}
741 732
742 733
734static void pvr2_video_device_release(struct video_device *vdev)
735{
736 struct pvr2_v4l2_dev *dev;
737 dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);
738 kfree(dev);
739}
740
741
743static void pvr2_v4l2_internal_check(struct pvr2_channel *chp) 742static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
744{ 743{
745 struct pvr2_v4l2 *vp; 744 struct pvr2_v4l2 *vp;
@@ -811,40 +810,12 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
811 810
812static int pvr2_v4l2_open(struct inode *inode, struct file *file) 811static int pvr2_v4l2_open(struct inode *inode, struct file *file)
813{ 812{
814 struct pvr2_v4l2_dev *dip = NULL; /* Our own context pointer */ 813 struct pvr2_v4l2_dev *dip; /* Our own context pointer */
815 struct pvr2_v4l2_fh *fhp; 814 struct pvr2_v4l2_fh *fhp;
816 struct pvr2_v4l2 *vp; 815 struct pvr2_v4l2 *vp;
817 struct pvr2_hdw *hdw; 816 struct pvr2_hdw *hdw;
818 817
819 mutex_lock(&device_lock); 818 dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
820 /* MCI 7-Jun-2006 Even though we're just doing what amounts to an
821 atomic read of the device mapping array here, we still need the
822 mutex. The problem is that there is a tiny race possible when
823 we register the device. We can't update the device mapping
824 array until after the device has been registered, owing to the
825 fact that we can't know the minor device number until after the
826 registration succeeds. And if another thread tries to open the
827 device in the window of time after registration but before the
828 map is updated, then it will get back an erroneous null pointer
829 and the open will result in a spurious failure. The only way to
830 prevent that is to (a) be inside the mutex here before we access
831 the array, and (b) cover the entire registration process later
832 on with this same mutex. Thus if we get inside the mutex here,
833 then we can be assured that the registration process actually
834 completed correctly. This is an unhappy complication from the
835 use of global data in a driver that lives in a preemptible
836 environment. It sure would be nice if the video device itself
837 had a means for storing and retrieving a local context pointer.
838 Oh wait. It did. But now it's gone. Silly me. */
839 {
840 unsigned int midx = iminor(file->f_dentry->d_inode);
841 if (midx < sizeof(devices)/sizeof(devices[0])) {
842 dip = devices[midx];
843 }
844 }
845 mutex_unlock(&device_lock);
846
847 if (!dip) return -ENODEV; /* Should be impossible but I'm paranoid */
848 819
849 vp = dip->v4lp; 820 vp = dip->v4lp;
850 hdw = vp->channel.hdw; 821 hdw = vp->channel.hdw;
@@ -1074,38 +1045,24 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
1074 return; 1045 return;
1075 } 1046 }
1076 1047
1077 dip->vdev = video_device_alloc(); 1048 memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
1078 if (!dip->vdev) { 1049 dip->devbase.release = pvr2_video_device_release;
1079 err("Alloc of pvrusb2 v4l video device failed");
1080 return;
1081 }
1082
1083 memcpy(dip->vdev,&vdev_template,sizeof(vdev_template));
1084 dip->vdev->release = video_device_release;
1085 mutex_lock(&device_lock);
1086 1050
1087 mindevnum = -1; 1051 mindevnum = -1;
1088 unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw); 1052 unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
1089 if ((unit_number >= 0) && (unit_number < PVR_NUM)) { 1053 if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
1090 mindevnum = video_nr[unit_number]; 1054 mindevnum = video_nr[unit_number];
1091 } 1055 }
1092 if ((video_register_device(dip->vdev, v4l_type, mindevnum) < 0) && 1056 if ((video_register_device(&dip->devbase, v4l_type, mindevnum) < 0) &&
1093 (video_register_device(dip->vdev, v4l_type, -1) < 0)) { 1057 (video_register_device(&dip->devbase, v4l_type, -1) < 0)) {
1094 err("Failed to register pvrusb2 v4l video device"); 1058 err("Failed to register pvrusb2 v4l video device");
1095 } else { 1059 } else {
1096 printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n", 1060 printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
1097 dip->vdev->minor,pvr2_config_get_name(dip->config)); 1061 dip->devbase.minor,pvr2_config_get_name(dip->config));
1098 } 1062 }
1099 1063
1100 if ((dip->vdev->minor < sizeof(devices)/sizeof(devices[0])) &&
1101 (devices[dip->vdev->minor] == NULL)) {
1102 dip->ctxt_idx = dip->vdev->minor;
1103 devices[dip->ctxt_idx] = dip;
1104 }
1105 mutex_unlock(&device_lock);
1106
1107 pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, 1064 pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
1108 dip->vdev->minor); 1065 dip->devbase.minor);
1109} 1066}
1110 1067
1111 1068
@@ -1116,15 +1073,19 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
1116 vp = kmalloc(sizeof(*vp),GFP_KERNEL); 1073 vp = kmalloc(sizeof(*vp),GFP_KERNEL);
1117 if (!vp) return vp; 1074 if (!vp) return vp;
1118 memset(vp,0,sizeof(*vp)); 1075 memset(vp,0,sizeof(*vp));
1119 vp->video_dev.ctxt_idx = -1; 1076 vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL);
1077 if (!vp->vdev) {
1078 kfree(vp);
1079 return 0;
1080 }
1081 memset(vp->vdev,0,sizeof(*vp->vdev));
1120 pvr2_channel_init(&vp->channel,mnp); 1082 pvr2_channel_init(&vp->channel,mnp);
1121 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp); 1083 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
1122 1084
1123 vp->channel.check_func = pvr2_v4l2_internal_check; 1085 vp->channel.check_func = pvr2_v4l2_internal_check;
1124 1086
1125 /* register streams */ 1087 /* register streams */
1126 pvr2_v4l2_dev_init(&vp->video_dev,vp,pvr2_config_mpeg); 1088 pvr2_v4l2_dev_init(vp->vdev,vp,pvr2_config_mpeg);
1127
1128 1089
1129 return vp; 1090 return vp;
1130} 1091}