[V4L] fix for races in v4l

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



Hi,

the attached patch fixes an SMP race in open and makes sure that read & write
are not called at the same time.
It compiles and I can still watch TV, but please test this.

	Regards
		Oliver
--- include/linux/videodev.h.alt	Mon Oct 30 07:41:41 2000
+++ include/linux/videodev.h	Mon Oct 30 07:41:44 2000
@@ -32,6 +32,7 @@
 	int busy;
 	int minor;
 	devfs_handle_t devfs_handle;
+        struct semaphore lock;
 };
 
 extern int videodev_init(void);
--- drivers/media/video/videodev.c.alt	Sun Oct 29 20:42:54 2000
+++ drivers/media/video/videodev.c	Mon Oct 30 07:41:48 2000
@@ -30,16 +30,17 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/bitops.h>
 
 #include <linux/kmod.h>
 
 
-#define VIDEO_NUM_DEVICES	256 
+#define VIDEO_NUM_DEVICES	256
 
 /*
- *	Active devices 
+ *	Active devices
  */
- 
+
 static struct video_device *video_device[VIDEO_NUM_DEVICES];
 
 
@@ -78,31 +79,36 @@
 static struct video_init video_init_list[]={
 #ifdef CONFIG_VIDEO_BWQCAM
 	{"bw-qcam", init_bw_qcams},
-#endif	
+#endif
 #ifdef CONFIG_VIDEO_CPIA
 	{"cpia", cpia_init},
-#endif	
+#endif
 #ifdef CONFIG_VIDEO_PLANB
 	{"planb", init_planbs},
 #endif
 #ifdef CONFIG_VIDEO_ZORAN
 	{"zoran", init_zoran_cards},
-#endif	
+#endif
 	{"end", NULL}
 };
 
 /*
  *	Read will do some smarts later on. Buffer pin etc.
  */
- 
+
 static ssize_t video_read(struct file *file,
 	char *buf, size_t count, loff_t *ppos)
 {
+        ssize_t retval;
 	struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
-	if(vfl->read)
-		return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+	if(vfl->read) {
+                down(&(vfl->lock));
+		retval = vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+                up(&(vfl->lock));
+        }
 	else
-		return -EINVAL;
+		retval = -EINVAL;
+        return retval;
 }
 
 
@@ -111,14 +117,19 @@
  *	for some boards I guess..
  */
 
-static ssize_t video_write(struct file *file, const char *buf, 
+static ssize_t video_write(struct file *file, const char *buf,
 	size_t count, loff_t *ppos)
 {
+        ssize_t retval;
 	struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
-	if(vfl->write)
-		return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+	if(vfl->write) {
+                down(&(vfl->lock));
+		retval = vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+                up(&(vfl->lock));
+        }
 	else
-		return 0;
+		retval = 0;
+        return retval;
 }
 
 /*
@@ -145,10 +156,10 @@
 	unsigned int minor = MINOR(inode->i_rdev);
 	int err;
 	struct video_device *vfl;
-	
+
 	if(minor>=VIDEO_NUM_DEVICES)
 		return -ENODEV;
-		
+
 	vfl=video_device[minor];
 	if(vfl==NULL) {
 		char modname[20];
@@ -159,26 +170,26 @@
 		if (vfl==NULL)
 			return -ENODEV;
 	}
-	if(vfl->busy)
+	if(test_and_set_bit(0,&(vfl->busy)))
 		return -EBUSY;
-	vfl->busy=1;		/* In case vfl->open sleeps */
-	
+
 	if(vfl->open)
 	{
 		err=vfl->open(vfl,0);	/* Tell the device it is open */
 		if(err)
 		{
-			vfl->busy=0;
+			clear_bit(0,&(vfl->busy));
 			return err;
 		}
 	}
+        init_MUTEX(&(vfl->lock));
 	return 0;
 }
 
 /*
  *	Last close of a video for Linux device
  */
-	
+
 static int video_release(struct inode *inode, struct file *file)
 {
 	struct video_device *vfl;
@@ -186,7 +197,7 @@
 	vfl=video_device[MINOR(inode->i_rdev)];
 	if(vfl->close)
 		vfl->close(vfl);
-	vfl->busy=0;
+	clear_bit(0,&(vfl->busy));
 	unlock_kernel();
 	return 0;
 }
@@ -195,7 +206,7 @@
  *	Question: Should we be able to capture and then seek around the
  *	image ?
  */
- 
+
 static long long video_lseek(struct file * file,
 			  long long offset, int origin)
 {
@@ -210,26 +221,22 @@
 
 	if(err!=-ENOIOCTLCMD)
 		return err;
-	
-	switch(cmd)
-	{
-		default:
-			return -EINVAL;
-	}
+        else
+		return -EINVAL;
 }
 
 /*
  *	We need to do MMAP support
  */
- 
- 
+
+
 int video_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	int ret = -EINVAL;
 	struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
 	if(vfl->mmap) {
 		lock_kernel();
-		ret = vfl->mmap(vfl, (char *)vma->vm_start, 
+		ret = vfl->mmap(vfl, (char *)vma->vm_start,
 				(unsigned long)(vma->vm_end-vma->vm_start));
 		unlock_kernel();
 	}
@@ -264,7 +271,7 @@
 	/* Sanity check */
 	if (tmp == &videodev_proc_list)
 		goto skip;
-		
+
 #define PRINT_VID_TYPE(x) do { if (vfd->type & x) \
 	out += sprintf (out, "%c%s", c, #x); c='|';} while (0)
 
@@ -393,7 +400,7 @@
  *	@vfd: video device structure we want to register
  *	@type: type of device to register
  *	FIXME: needs a semaphore on 2.3.x
- *	
+ *
  *	The registration code assigns minor numbers based on the type
  *	requested. -ENFILE is returned in all the device slots for this
  *	category are full. If not then the minor field is set and the
@@ -409,9 +416,9 @@
  *
  *	%VFL_TYPE_VBI - Vertical blank data (undecoded)
  *
- *	%VFL_TYPE_RADIO - A radio card	
+ *	%VFL_TYPE_RADIO - A radio card
  */
- 
+
 int video_register_device(struct video_device *vfd, int type)
 {
 	int i=0;
@@ -419,7 +426,7 @@
 	int err;
 	int end;
 	char *name_base;
-	
+
 	switch(type)
 	{
 		case VFL_TYPE_GRABBER:

[Index of Archives]     [Linux DVB]     [Video Disk Recorder]     [Asterisk]     [Photo]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Free Photo Albums]     [Fedora Users]     [Fedora Women]     [ALSA Users]     [ALSA Devel]     [Linux USB]

Powered by Linux