aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Zago <frank@zago.net>2008-09-28 07:12:22 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-10-12 07:37:12 -0400
commit6b060ffea0722cfe4f5156a73a6424130d3d804a (patch)
treefa3351600d2fe6dd3ac955e2954c42d6675e78bf
parent6c49da7f169c25eb39b80ff168f5bdbacf8457e1 (diff)
V4L/DVB (9086): gspca: Use a kref to avoid potentialy blocking forever in disconnect.
Signed-off-by: Frank Zago <frank@zago.net> Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/gspca/gspca.c39
-rw-r--r--drivers/media/video/gspca/gspca.h1
2 files changed, 28 insertions, 12 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 3f0fd44f19ab..342a0f39e5d5 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -29,6 +29,7 @@
29#include <linux/string.h> 29#include <linux/string.h>
30#include <linux/pagemap.h> 30#include <linux/pagemap.h>
31#include <linux/io.h> 31#include <linux/io.h>
32#include <linux/kref.h>
32#include <asm/page.h> 33#include <asm/page.h>
33#include <linux/uaccess.h> 34#include <linux/uaccess.h>
34#include <linux/jiffies.h> 35#include <linux/jiffies.h>
@@ -834,6 +835,16 @@ out:
834 return ret; 835 return ret;
835} 836}
836 837
838static void gspca_delete(struct kref *kref)
839{
840 struct gspca_dev *gspca_dev = container_of(kref, struct gspca_dev, kref);
841
842 PDEBUG(D_STREAM, "device deleted");
843
844 kfree(gspca_dev->usb_buf);
845 kfree(gspca_dev);
846}
847
837static int dev_open(struct inode *inode, struct file *file) 848static int dev_open(struct inode *inode, struct file *file)
838{ 849{
839 struct gspca_dev *gspca_dev; 850 struct gspca_dev *gspca_dev;
@@ -853,6 +864,10 @@ static int dev_open(struct inode *inode, struct file *file)
853 goto out; 864 goto out;
854 } 865 }
855 gspca_dev->users++; 866 gspca_dev->users++;
867
868 /* one more user */
869 kref_get(&gspca_dev->kref);
870
856 file->private_data = gspca_dev; 871 file->private_data = gspca_dev;
857#ifdef GSPCA_DEBUG 872#ifdef GSPCA_DEBUG
858 /* activate the v4l2 debug */ 873 /* activate the v4l2 debug */
@@ -895,7 +910,11 @@ static int dev_close(struct inode *inode, struct file *file)
895 } 910 }
896 file->private_data = NULL; 911 file->private_data = NULL;
897 mutex_unlock(&gspca_dev->queue_lock); 912 mutex_unlock(&gspca_dev->queue_lock);
913
898 PDEBUG(D_STREAM, "close done"); 914 PDEBUG(D_STREAM, "close done");
915
916 kref_put(&gspca_dev->kref, gspca_delete);
917
899 return 0; 918 return 0;
900} 919}
901 920
@@ -1809,6 +1828,7 @@ int gspca_dev_probe(struct usb_interface *intf,
1809 err("couldn't kzalloc gspca struct"); 1828 err("couldn't kzalloc gspca struct");
1810 return -EIO; 1829 return -EIO;
1811 } 1830 }
1831 kref_init(&gspca_dev->kref);
1812 gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); 1832 gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL);
1813 if (!gspca_dev->usb_buf) { 1833 if (!gspca_dev->usb_buf) {
1814 err("out of memory"); 1834 err("out of memory");
@@ -1858,8 +1878,7 @@ int gspca_dev_probe(struct usb_interface *intf,
1858 PDEBUG(D_PROBE, "probe ok"); 1878 PDEBUG(D_PROBE, "probe ok");
1859 return 0; 1879 return 0;
1860out: 1880out:
1861 kfree(gspca_dev->usb_buf); 1881 kref_put(&gspca_dev->kref, gspca_delete);
1862 kfree(gspca_dev);
1863 return ret; 1882 return ret;
1864} 1883}
1865EXPORT_SYMBOL(gspca_dev_probe); 1884EXPORT_SYMBOL(gspca_dev_probe);
@@ -1874,8 +1893,8 @@ void gspca_disconnect(struct usb_interface *intf)
1874{ 1893{
1875 struct gspca_dev *gspca_dev = usb_get_intfdata(intf); 1894 struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
1876 1895
1877 if (!gspca_dev) 1896 usb_set_intfdata(intf, NULL);
1878 return; 1897
1879 gspca_dev->present = 0; 1898 gspca_dev->present = 0;
1880 mutex_lock(&gspca_dev->queue_lock); 1899 mutex_lock(&gspca_dev->queue_lock);
1881 mutex_lock(&gspca_dev->usb_lock); 1900 mutex_lock(&gspca_dev->usb_lock);
@@ -1883,16 +1902,12 @@ void gspca_disconnect(struct usb_interface *intf)
1883 destroy_urbs(gspca_dev); 1902 destroy_urbs(gspca_dev);
1884 mutex_unlock(&gspca_dev->usb_lock); 1903 mutex_unlock(&gspca_dev->usb_lock);
1885 mutex_unlock(&gspca_dev->queue_lock); 1904 mutex_unlock(&gspca_dev->queue_lock);
1886 while (gspca_dev->users != 0) { /* wait until fully closed */ 1905
1887 atomic_inc(&gspca_dev->nevent);
1888 wake_up_interruptible(&gspca_dev->wq); /* wake processes */
1889 schedule();
1890 }
1891/* We don't want people trying to open up the device */ 1906/* We don't want people trying to open up the device */
1892 video_unregister_device(&gspca_dev->vdev); 1907 video_unregister_device(&gspca_dev->vdev);
1893/* Free the memory */ 1908
1894 kfree(gspca_dev->usb_buf); 1909 kref_put(&gspca_dev->kref, gspca_delete);
1895 kfree(gspca_dev); 1910
1896 PDEBUG(D_PROBE, "disconnect complete"); 1911 PDEBUG(D_PROBE, "disconnect complete");
1897} 1912}
1898EXPORT_SYMBOL(gspca_disconnect); 1913EXPORT_SYMBOL(gspca_disconnect);
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index b0bdae194bb6..192dffdcd9cd 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -121,6 +121,7 @@ struct gspca_dev {
121 struct video_device vdev; /* !! must be the first item */ 121 struct video_device vdev; /* !! must be the first item */
122 struct file_operations fops; 122 struct file_operations fops;
123 struct usb_device *dev; 123 struct usb_device *dev;
124 struct kref kref;
124 struct file *capt_file; /* file doing video capture */ 125 struct file *capt_file; /* file doing video capture */
125 126
126 struct cam cam; /* device information */ 127 struct cam cam; /* device information */