Commit 1052efe0 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (8505): saa7134-empress.c: fix deadlock



ts_release() locked a mutex that videobuf_stop() also tried to obtain.
But ts_release() shouldn't hold that mutex at all.

Make empress_users atomic as well to prevent possible race condition.

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent feb75f07
Loading
Loading
Loading
Loading
+4 −8
Original line number Original line Diff line number Diff line
@@ -89,14 +89,14 @@ static int ts_open(struct inode *inode, struct file *file)
	err = -EBUSY;
	err = -EBUSY;
	if (!mutex_trylock(&dev->empress_tsq.vb_lock))
	if (!mutex_trylock(&dev->empress_tsq.vb_lock))
		goto done;
		goto done;
	if (dev->empress_users)
	if (atomic_read(&dev->empress_users))
		goto done_up;
		goto done_up;


	/* Unmute audio */
	/* Unmute audio */
	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
		saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
		saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));


	dev->empress_users++;
	atomic_inc(&dev->empress_users);
	file->private_data = dev;
	file->private_data = dev;
	err = 0;
	err = 0;


@@ -110,8 +110,6 @@ static int ts_release(struct inode *inode, struct file *file)
{
{
	struct saa7134_dev *dev = file->private_data;
	struct saa7134_dev *dev = file->private_data;


	mutex_lock(&dev->empress_tsq.vb_lock);

	videobuf_stop(&dev->empress_tsq);
	videobuf_stop(&dev->empress_tsq);
	videobuf_mmap_free(&dev->empress_tsq);
	videobuf_mmap_free(&dev->empress_tsq);


@@ -122,9 +120,7 @@ static int ts_release(struct inode *inode, struct file *file)
	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
		saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
		saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));


	dev->empress_users--;
	atomic_dec(&dev->empress_users);

	mutex_unlock(&dev->empress_tsq.vb_lock);


	return 0;
	return 0;
}
}
@@ -447,7 +443,7 @@ static void empress_signal_update(struct work_struct *work)
		ts_reset_encoder(dev);
		ts_reset_encoder(dev);
	} else {
	} else {
		dprintk("video signal acquired\n");
		dprintk("video signal acquired\n");
		if (dev->empress_users)
		if (atomic_read(&dev->empress_users))
			ts_init_encoder(dev);
			ts_init_encoder(dev);
	}
	}
}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -561,7 +561,7 @@ struct saa7134_dev {
	/* SAA7134_MPEG_EMPRESS only */
	/* SAA7134_MPEG_EMPRESS only */
	struct video_device        *empress_dev;
	struct video_device        *empress_dev;
	struct videobuf_queue      empress_tsq;
	struct videobuf_queue      empress_tsq;
	unsigned int               empress_users;
	atomic_t 		   empress_users;
	struct work_struct         empress_workqueue;
	struct work_struct         empress_workqueue;
	int                        empress_started;
	int                        empress_started;