Re: [PATCH] hdpvr: fix locking and a missing msleep

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

 



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@xxxxxxxxxxxxx>
Suggested-by: Keith Pyle <kpyle@xxxxxxxxxxxxx>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xxxxxxxxx>
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);





[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux