* [PATCH] hdpvr: fix locking and a missing msleep
@ 2019-06-20 11:43 Hans Verkuil
2019-06-21 2:48 ` Keith Pyle
0 siblings, 1 reply; 2+ messages in thread
From: Hans Verkuil @ 2019-06-20 11:43 UTC (permalink / raw)
To: Linux Media Mailing List; +Cc: Keith Pyle
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: Keith Pyle <kpyle@austin.rr.com>
Suggested-by: Keith Pyle <kpyle@austin.rr.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 3786ddcc0d18..5b3e67b80627 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -435,7 +435,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
/* wait for the first buffer */
if (!(file->f_flags & O_NONBLOCK)) {
if (wait_event_interruptible(dev->wait_data,
- hdpvr_get_next_buffer(dev)))
+ !list_empty_careful(&dev->rec_buff_list)))
return -ERESTARTSYS;
}
@@ -461,10 +461,17 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
goto err;
}
if (!err) {
- v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
- "timeout: restart streaming\n");
+ v4l2_info(&dev->v4l2_dev,
+ "timeout: restart streaming\n");
+ mutex_lock(&dev->io_mutex);
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);
if (err) {
ret = err;
@@ -1124,9 +1131,7 @@ static void hdpvr_device_release(struct video_device *vdev)
struct hdpvr_device *dev = video_get_drvdata(vdev);
hdpvr_delete(dev);
- mutex_lock(&dev->io_mutex);
flush_work(&dev->worker);
- mutex_unlock(&dev->io_mutex);
v4l2_device_unregister(&dev->v4l2_dev);
v4l2_ctrl_handler_free(&dev->hdl);
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] hdpvr: fix locking and a missing msleep
2019-06-20 11:43 [PATCH] hdpvr: fix locking and a missing msleep Hans Verkuil
@ 2019-06-21 2:48 ` Keith Pyle
0 siblings, 0 replies; 2+ messages in thread
From: Keith Pyle @ 2019-06-21 2:48 UTC (permalink / raw)
To: Hans Verkuil, Linux Media Mailing List
On 06/20/19 06:43, Hans Verkuil wrote:
> 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: Keith Pyle <kpyle@austin.rr.com>
> Suggested-by: Keith Pyle <kpyle@austin.rr.com>
> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This patch looks good.
I have repeated my tests and all passed (simple captures, capture with
HD-PVR restart streaming) . There were no lockdep reports and no
process deadlocks. The streaming restart now works and logs the restart
in kern.log.
Keith
> ---
> diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
> index 3786ddcc0d18..5b3e67b80627 100644
> --- a/drivers/media/usb/hdpvr/hdpvr-video.c
> +++ b/drivers/media/usb/hdpvr/hdpvr-video.c
> @@ -435,7 +435,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
> /* wait for the first buffer */
> if (!(file->f_flags & O_NONBLOCK)) {
> if (wait_event_interruptible(dev->wait_data,
> - hdpvr_get_next_buffer(dev)))
> + !list_empty_careful(&dev->rec_buff_list)))
> return -ERESTARTSYS;
> }
>
> @@ -461,10 +461,17 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
> goto err;
> }
> if (!err) {
> - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
> - "timeout: restart streaming\n");
> + v4l2_info(&dev->v4l2_dev,
> + "timeout: restart streaming\n");
> + mutex_lock(&dev->io_mutex);
> 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);
> if (err) {
> ret = err;
> @@ -1124,9 +1131,7 @@ static void hdpvr_device_release(struct video_device *vdev)
> struct hdpvr_device *dev = video_get_drvdata(vdev);
>
> hdpvr_delete(dev);
> - mutex_lock(&dev->io_mutex);
> flush_work(&dev->worker);
> - mutex_unlock(&dev->io_mutex);
>
> v4l2_device_unregister(&dev->v4l2_dev);
> v4l2_ctrl_handler_free(&dev->hdl);
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2019-06-21 2:48 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-20 11:43 [PATCH] hdpvr: fix locking and a missing msleep Hans Verkuil
2019-06-21 2:48 ` Keith Pyle
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).