diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-11-20 08:30:26 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-11-20 15:12:02 -0500 |
commit | 818a557eeb9c16a9a2dc93df348b0ff68fbc487f (patch) | |
tree | d1ac8a7c8ad69f603100e13f5170525259e6385c | |
parent | cce257109f534b4954a5d04aa4ba6905f4682f93 (diff) |
V4L/DVB (9668): em28xx: fix a race condition with hald
Newer versions of hald tries to open it to call QUERYCAP.
Due to the lack of a proper locking, it is possible to open the device
before it finishes initialization.
This patch adds a lock to avoid this risk, and to protect the list of
em28xx devices.
While here, remove the uneeded BKL lock.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 128 |
1 files changed, 75 insertions, 53 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index c32fc7d24a42..90a11b5ac0b1 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -73,6 +73,7 @@ MODULE_DESCRIPTION(DRIVER_DESC); | |||
73 | MODULE_LICENSE("GPL"); | 73 | MODULE_LICENSE("GPL"); |
74 | 74 | ||
75 | static LIST_HEAD(em28xx_devlist); | 75 | static LIST_HEAD(em28xx_devlist); |
76 | static DEFINE_MUTEX(em28xx_devlist_mutex); | ||
76 | 77 | ||
77 | static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; | 78 | static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; |
78 | static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; | 79 | static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; |
@@ -1519,7 +1520,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
1519 | struct em28xx_fh *fh; | 1520 | struct em28xx_fh *fh; |
1520 | enum v4l2_buf_type fh_type = 0; | 1521 | enum v4l2_buf_type fh_type = 0; |
1521 | 1522 | ||
1522 | lock_kernel(); | 1523 | mutex_lock(&em28xx_devlist_mutex); |
1523 | list_for_each_entry(h, &em28xx_devlist, devlist) { | 1524 | list_for_each_entry(h, &em28xx_devlist, devlist) { |
1524 | if (h->vdev->minor == minor) { | 1525 | if (h->vdev->minor == minor) { |
1525 | dev = h; | 1526 | dev = h; |
@@ -1535,10 +1536,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
1535 | dev = h; | 1536 | dev = h; |
1536 | } | 1537 | } |
1537 | } | 1538 | } |
1538 | if (NULL == dev) { | 1539 | mutex_unlock(&em28xx_devlist_mutex); |
1539 | unlock_kernel(); | 1540 | if (NULL == dev) |
1540 | return -ENODEV; | 1541 | return -ENODEV; |
1541 | } | 1542 | |
1543 | mutex_lock(&dev->lock); | ||
1542 | 1544 | ||
1543 | em28xx_videodbg("open minor=%d type=%s users=%d\n", | 1545 | em28xx_videodbg("open minor=%d type=%s users=%d\n", |
1544 | minor, v4l2_type_names[fh_type], dev->users); | 1546 | minor, v4l2_type_names[fh_type], dev->users); |
@@ -1547,10 +1549,9 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
1547 | fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); | 1549 | fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); |
1548 | if (!fh) { | 1550 | if (!fh) { |
1549 | em28xx_errdev("em28xx-video.c: Out of memory?!\n"); | 1551 | em28xx_errdev("em28xx-video.c: Out of memory?!\n"); |
1550 | unlock_kernel(); | 1552 | mutex_unlock(&dev->lock); |
1551 | return -ENOMEM; | 1553 | return -ENOMEM; |
1552 | } | 1554 | } |
1553 | mutex_lock(&dev->lock); | ||
1554 | fh->dev = dev; | 1555 | fh->dev = dev; |
1555 | fh->radio = radio; | 1556 | fh->radio = radio; |
1556 | fh->type = fh_type; | 1557 | fh->type = fh_type; |
@@ -1584,7 +1585,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
1584 | sizeof(struct em28xx_buffer), fh); | 1585 | sizeof(struct em28xx_buffer), fh); |
1585 | 1586 | ||
1586 | mutex_unlock(&dev->lock); | 1587 | mutex_unlock(&dev->lock); |
1587 | unlock_kernel(); | ||
1588 | 1588 | ||
1589 | return errCode; | 1589 | return errCode; |
1590 | } | 1590 | } |
@@ -1871,6 +1871,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) | |||
1871 | { | 1871 | { |
1872 | struct em28xx *dev = NULL; | 1872 | struct em28xx *dev = NULL; |
1873 | 1873 | ||
1874 | mutex_lock(&em28xx_devlist_mutex); | ||
1874 | mutex_lock(&em28xx_extension_devlist_lock); | 1875 | mutex_lock(&em28xx_extension_devlist_lock); |
1875 | list_add_tail(&ops->next, &em28xx_extension_devlist); | 1876 | list_add_tail(&ops->next, &em28xx_extension_devlist); |
1876 | list_for_each_entry(dev, &em28xx_devlist, devlist) { | 1877 | list_for_each_entry(dev, &em28xx_devlist, devlist) { |
@@ -1879,6 +1880,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) | |||
1879 | } | 1880 | } |
1880 | printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); | 1881 | printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); |
1881 | mutex_unlock(&em28xx_extension_devlist_lock); | 1882 | mutex_unlock(&em28xx_extension_devlist_lock); |
1883 | mutex_unlock(&em28xx_devlist_mutex); | ||
1882 | return 0; | 1884 | return 0; |
1883 | } | 1885 | } |
1884 | EXPORT_SYMBOL(em28xx_register_extension); | 1886 | EXPORT_SYMBOL(em28xx_register_extension); |
@@ -1887,6 +1889,7 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) | |||
1887 | { | 1889 | { |
1888 | struct em28xx *dev = NULL; | 1890 | struct em28xx *dev = NULL; |
1889 | 1891 | ||
1892 | mutex_lock(&em28xx_devlist_mutex); | ||
1890 | list_for_each_entry(dev, &em28xx_devlist, devlist) { | 1893 | list_for_each_entry(dev, &em28xx_devlist, devlist) { |
1891 | if (dev) | 1894 | if (dev) |
1892 | ops->fini(dev); | 1895 | ops->fini(dev); |
@@ -1896,6 +1899,7 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) | |||
1896 | printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); | 1899 | printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); |
1897 | list_del(&ops->next); | 1900 | list_del(&ops->next); |
1898 | mutex_unlock(&em28xx_extension_devlist_lock); | 1901 | mutex_unlock(&em28xx_extension_devlist_lock); |
1902 | mutex_unlock(&em28xx_devlist_mutex); | ||
1899 | } | 1903 | } |
1900 | EXPORT_SYMBOL(em28xx_unregister_extension); | 1904 | EXPORT_SYMBOL(em28xx_unregister_extension); |
1901 | 1905 | ||
@@ -1921,6 +1925,60 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, | |||
1921 | } | 1925 | } |
1922 | 1926 | ||
1923 | 1927 | ||
1928 | static int register_analog_devices(struct em28xx *dev) | ||
1929 | { | ||
1930 | int ret; | ||
1931 | |||
1932 | /* allocate and fill video video_device struct */ | ||
1933 | dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); | ||
1934 | if (!dev->vdev) { | ||
1935 | em28xx_errdev("cannot allocate video_device.\n"); | ||
1936 | return -ENODEV; | ||
1937 | } | ||
1938 | |||
1939 | /* register v4l2 video video_device */ | ||
1940 | ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, | ||
1941 | video_nr[dev->devno]); | ||
1942 | if (ret) { | ||
1943 | em28xx_errdev("unable to register video device (error=%i).\n", | ||
1944 | ret); | ||
1945 | return ret; | ||
1946 | } | ||
1947 | |||
1948 | /* Allocate and fill vbi video_device struct */ | ||
1949 | dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); | ||
1950 | |||
1951 | /* register v4l2 vbi video_device */ | ||
1952 | ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, | ||
1953 | vbi_nr[dev->devno]); | ||
1954 | if (ret < 0) { | ||
1955 | em28xx_errdev("unable to register vbi device\n"); | ||
1956 | return ret; | ||
1957 | } | ||
1958 | |||
1959 | if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { | ||
1960 | dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio"); | ||
1961 | if (!dev->radio_dev) { | ||
1962 | em28xx_errdev("cannot allocate video_device.\n"); | ||
1963 | return -ENODEV; | ||
1964 | } | ||
1965 | ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, | ||
1966 | radio_nr[dev->devno]); | ||
1967 | if (ret < 0) { | ||
1968 | em28xx_errdev("can't register radio device\n"); | ||
1969 | return ret; | ||
1970 | } | ||
1971 | em28xx_info("Registered radio device as /dev/radio%d\n", | ||
1972 | dev->radio_dev->num); | ||
1973 | } | ||
1974 | |||
1975 | em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", | ||
1976 | dev->vdev->num, dev->vbi_dev->num); | ||
1977 | |||
1978 | return 0; | ||
1979 | } | ||
1980 | |||
1981 | |||
1924 | /* | 1982 | /* |
1925 | * em28xx_init_dev() | 1983 | * em28xx_init_dev() |
1926 | * allocates and inits the device structs, registers i2c bus and v4l device | 1984 | * allocates and inits the device structs, registers i2c bus and v4l device |
@@ -2000,50 +2058,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
2000 | return errCode; | 2058 | return errCode; |
2001 | } | 2059 | } |
2002 | 2060 | ||
2003 | list_add_tail(&dev->devlist, &em28xx_devlist); | ||
2004 | |||
2005 | /* allocate and fill video video_device struct */ | ||
2006 | dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); | ||
2007 | if (NULL == dev->vdev) { | ||
2008 | em28xx_errdev("cannot allocate video_device.\n"); | ||
2009 | goto fail_unreg; | ||
2010 | } | ||
2011 | |||
2012 | /* register v4l2 video video_device */ | ||
2013 | retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, | ||
2014 | video_nr[dev->devno]); | ||
2015 | if (retval) { | ||
2016 | em28xx_errdev("unable to register video device (error=%i).\n", | ||
2017 | retval); | ||
2018 | goto fail_unreg; | ||
2019 | } | ||
2020 | |||
2021 | /* Allocate and fill vbi video_device struct */ | ||
2022 | dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); | ||
2023 | /* register v4l2 vbi video_device */ | ||
2024 | if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, | ||
2025 | vbi_nr[dev->devno]) < 0) { | ||
2026 | em28xx_errdev("unable to register vbi device\n"); | ||
2027 | retval = -ENODEV; | ||
2028 | goto fail_unreg; | ||
2029 | } | ||
2030 | |||
2031 | if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { | ||
2032 | dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio"); | ||
2033 | if (NULL == dev->radio_dev) { | ||
2034 | em28xx_errdev("cannot allocate video_device.\n"); | ||
2035 | goto fail_unreg; | ||
2036 | } | ||
2037 | retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, | ||
2038 | radio_nr[dev->devno]); | ||
2039 | if (retval < 0) { | ||
2040 | em28xx_errdev("can't register radio device\n"); | ||
2041 | goto fail_unreg; | ||
2042 | } | ||
2043 | em28xx_info("Registered radio device as /dev/radio%d\n", | ||
2044 | dev->radio_dev->num); | ||
2045 | } | ||
2046 | |||
2047 | /* init video dma queues */ | 2061 | /* init video dma queues */ |
2048 | INIT_LIST_HEAD(&dev->vidq.active); | 2062 | INIT_LIST_HEAD(&dev->vidq.active); |
2049 | INIT_LIST_HEAD(&dev->vidq.queued); | 2063 | INIT_LIST_HEAD(&dev->vidq.queued); |
@@ -2070,8 +2084,14 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
2070 | 2084 | ||
2071 | video_mux(dev, 0); | 2085 | video_mux(dev, 0); |
2072 | 2086 | ||
2073 | em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", | 2087 | mutex_lock(&em28xx_devlist_mutex); |
2074 | dev->vdev->num, dev->vbi_dev->num); | 2088 | list_add_tail(&dev->devlist, &em28xx_devlist); |
2089 | retval = register_analog_devices(dev); | ||
2090 | if (retval < 0) { | ||
2091 | em28xx_release_resources(dev); | ||
2092 | mutex_unlock(&em28xx_devlist_mutex); | ||
2093 | goto fail_reg_devices; | ||
2094 | } | ||
2075 | 2095 | ||
2076 | mutex_lock(&em28xx_extension_devlist_lock); | 2096 | mutex_lock(&em28xx_extension_devlist_lock); |
2077 | if (!list_empty(&em28xx_extension_devlist)) { | 2097 | if (!list_empty(&em28xx_extension_devlist)) { |
@@ -2081,11 +2101,13 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
2081 | } | 2101 | } |
2082 | } | 2102 | } |
2083 | mutex_unlock(&em28xx_extension_devlist_lock); | 2103 | mutex_unlock(&em28xx_extension_devlist_lock); |
2104 | mutex_unlock(&em28xx_devlist_mutex); | ||
2084 | 2105 | ||
2085 | return 0; | 2106 | return 0; |
2086 | 2107 | ||
2087 | fail_unreg: | 2108 | fail_unreg: |
2088 | em28xx_release_resources(dev); | 2109 | em28xx_release_resources(dev); |
2110 | fail_reg_devices: | ||
2089 | mutex_unlock(&dev->lock); | 2111 | mutex_unlock(&dev->lock); |
2090 | return retval; | 2112 | return retval; |
2091 | } | 2113 | } |