Commit 6bc5a4a1 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

media: hdpvr: fix locking and a missing msleep

This driver has three locking issues:

- The wait_event_interruptible() condition calls hdpvr_get_next_buffer(dev)
  which uses a mutex, which is not allowed. Rewrite with list_empty_careful()
  that doesn't need locking.

- In hdpvr_read() the call to hdpvr_stop_streaming() didn't lock io_mutex,
  but it should have since stop_streaming expects that.

- In hdpvr_device_release() io_mutex was locked when calling flush_work(),
  but there it shouldn't take that mutex since the work done by flush_work()
  also wants to lock that mutex.

There are also two other changes (suggested by Keith):

- msecs_to_jiffies(4000); (a NOP) should have been msleep(4000).
- Change v4l2_dbg to v4l2_info to always log if streaming had to be restarted.
Reported-by: default avatarKeith Pyle <kpyle@austin.rr.com>
Suggested-by: default avatarKeith Pyle <kpyle@austin.rr.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 07d89227
...@@ -435,7 +435,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, ...@@ -435,7 +435,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
/* wait for the first buffer */ /* wait for the first buffer */
if (!(file->f_flags & O_NONBLOCK)) { if (!(file->f_flags & O_NONBLOCK)) {
if (wait_event_interruptible(dev->wait_data, if (wait_event_interruptible(dev->wait_data,
hdpvr_get_next_buffer(dev))) !list_empty_careful(&dev->rec_buff_list)))
return -ERESTARTSYS; return -ERESTARTSYS;
} }
...@@ -461,10 +461,17 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, ...@@ -461,10 +461,17 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
goto err; goto err;
} }
if (!err) { if (!err) {
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, v4l2_info(&dev->v4l2_dev,
"timeout: restart streaming\n"); "timeout: restart streaming\n");
mutex_lock(&dev->io_mutex);
hdpvr_stop_streaming(dev); hdpvr_stop_streaming(dev);
msecs_to_jiffies(4000); mutex_unlock(&dev->io_mutex);
/*
* The FW needs about 4 seconds after streaming
* stopped before it is ready to restart
* streaming.
*/
msleep(4000);
err = hdpvr_start_streaming(dev); err = hdpvr_start_streaming(dev);
if (err) { if (err) {
ret = err; ret = err;
...@@ -1124,9 +1131,7 @@ static void hdpvr_device_release(struct video_device *vdev) ...@@ -1124,9 +1131,7 @@ static void hdpvr_device_release(struct video_device *vdev)
struct hdpvr_device *dev = video_get_drvdata(vdev); struct hdpvr_device *dev = video_get_drvdata(vdev);
hdpvr_delete(dev); hdpvr_delete(dev);
mutex_lock(&dev->io_mutex);
flush_work(&dev->worker); flush_work(&dev->worker);
mutex_unlock(&dev->io_mutex);
v4l2_device_unregister(&dev->v4l2_dev); v4l2_device_unregister(&dev->v4l2_dev);
v4l2_ctrl_handler_free(&dev->hdl); v4l2_ctrl_handler_free(&dev->hdl);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment