Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dda06a8e authored by Andreas Oberritter's avatar Andreas Oberritter Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (9029): Fix deadlock in demux code



The functions dvb_dmxdev_section_callback, dvb_dmxdev_ts_callback,
dvb_dmx_swfilter_packet, dvb_dmx_swfilter_packets, dvb_dmx_swfilter and
dvb_dmx_swfilter_204 may be called from both interrupt and process
context. Therefore they need to be protected by spin_lock_irqsave()
instead of spin_lock().

This fixes a deadlock discovered by lockdep.

Signed-off-by: default avatarAndreas Oberritter <obi@linuxtv.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 3d843c92
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -364,15 +364,16 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
				       enum dmx_success success)
{
	struct dmxdev_filter *dmxdevfilter = filter->priv;
	unsigned long flags;
	int ret;

	if (dmxdevfilter->buffer.error) {
		wake_up(&dmxdevfilter->buffer.queue);
		return 0;
	}
	spin_lock(&dmxdevfilter->dev->lock);
	spin_lock_irqsave(&dmxdevfilter->dev->lock, flags);
	if (dmxdevfilter->state != DMXDEV_STATE_GO) {
		spin_unlock(&dmxdevfilter->dev->lock);
		spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
		return 0;
	}
	del_timer(&dmxdevfilter->timer);
@@ -391,7 +392,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
	}
	if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
		dmxdevfilter->state = DMXDEV_STATE_DONE;
	spin_unlock(&dmxdevfilter->dev->lock);
	spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
	wake_up(&dmxdevfilter->buffer.queue);
	return 0;
}
@@ -403,11 +404,12 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
{
	struct dmxdev_filter *dmxdevfilter = feed->priv;
	struct dvb_ringbuffer *buffer;
	unsigned long flags;
	int ret;

	spin_lock(&dmxdevfilter->dev->lock);
	spin_lock_irqsave(&dmxdevfilter->dev->lock, flags);
	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
		spin_unlock(&dmxdevfilter->dev->lock);
		spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
		return 0;
	}

@@ -417,7 +419,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
	else
		buffer = &dmxdevfilter->dev->dvr_buffer;
	if (buffer->error) {
		spin_unlock(&dmxdevfilter->dev->lock);
		spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
		wake_up(&buffer->queue);
		return 0;
	}
@@ -428,7 +430,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
		dvb_ringbuffer_flush(buffer);
		buffer->error = ret;
	}
	spin_unlock(&dmxdevfilter->dev->lock);
	spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
	wake_up(&buffer->queue);
	return 0;
}
+10 −6
Original line number Diff line number Diff line
@@ -399,7 +399,9 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
			      size_t count)
{
	spin_lock(&demux->lock);
	unsigned long flags;

	spin_lock_irqsave(&demux->lock, flags);

	while (count--) {
		if (buf[0] == 0x47)
@@ -407,16 +409,17 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
		buf += 188;
	}

	spin_unlock(&demux->lock);
	spin_unlock_irqrestore(&demux->lock, flags);
}

EXPORT_SYMBOL(dvb_dmx_swfilter_packets);

void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
{
	unsigned long flags;
	int p = 0, i, j;

	spin_lock(&demux->lock);
	spin_lock_irqsave(&demux->lock, flags);

	if (demux->tsbufp) {
		i = demux->tsbufp;
@@ -449,17 +452,18 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
	}

bailout:
	spin_unlock(&demux->lock);
	spin_unlock_irqrestore(&demux->lock, flags);
}

EXPORT_SYMBOL(dvb_dmx_swfilter);

void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
{
	unsigned long flags;
	int p = 0, i, j;
	u8 tmppack[188];

	spin_lock(&demux->lock);
	spin_lock_irqsave(&demux->lock, flags);

	if (demux->tsbufp) {
		i = demux->tsbufp;
@@ -500,7 +504,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
	}

bailout:
	spin_unlock(&demux->lock);
	spin_unlock_irqrestore(&demux->lock, flags);
}

EXPORT_SYMBOL(dvb_dmx_swfilter_204);