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

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
...@@ -364,15 +364,16 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, ...@@ -364,15 +364,16 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
enum dmx_success success) enum dmx_success success)
{ {
struct dmxdev_filter *dmxdevfilter = filter->priv; struct dmxdev_filter *dmxdevfilter = filter->priv;
unsigned long flags;
int ret; int ret;
if (dmxdevfilter->buffer.error) { if (dmxdevfilter->buffer.error) {
wake_up(&dmxdevfilter->buffer.queue); wake_up(&dmxdevfilter->buffer.queue);
return 0; return 0;
} }
spin_lock(&dmxdevfilter->dev->lock); spin_lock_irqsave(&dmxdevfilter->dev->lock, flags);
if (dmxdevfilter->state != DMXDEV_STATE_GO) { if (dmxdevfilter->state != DMXDEV_STATE_GO) {
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
return 0; return 0;
} }
del_timer(&dmxdevfilter->timer); del_timer(&dmxdevfilter->timer);
...@@ -391,7 +392,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, ...@@ -391,7 +392,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
} }
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
dmxdevfilter->state = DMXDEV_STATE_DONE; dmxdevfilter->state = DMXDEV_STATE_DONE;
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
wake_up(&dmxdevfilter->buffer.queue); wake_up(&dmxdevfilter->buffer.queue);
return 0; return 0;
} }
...@@ -403,11 +404,12 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, ...@@ -403,11 +404,12 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
{ {
struct dmxdev_filter *dmxdevfilter = feed->priv; struct dmxdev_filter *dmxdevfilter = feed->priv;
struct dvb_ringbuffer *buffer; struct dvb_ringbuffer *buffer;
unsigned long flags;
int ret; int ret;
spin_lock(&dmxdevfilter->dev->lock); spin_lock_irqsave(&dmxdevfilter->dev->lock, flags);
if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
return 0; return 0;
} }
...@@ -417,7 +419,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, ...@@ -417,7 +419,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
else else
buffer = &dmxdevfilter->dev->dvr_buffer; buffer = &dmxdevfilter->dev->dvr_buffer;
if (buffer->error) { if (buffer->error) {
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
wake_up(&buffer->queue); wake_up(&buffer->queue);
return 0; return 0;
} }
...@@ -428,7 +430,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, ...@@ -428,7 +430,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
dvb_ringbuffer_flush(buffer); dvb_ringbuffer_flush(buffer);
buffer->error = ret; buffer->error = ret;
} }
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
wake_up(&buffer->queue); wake_up(&buffer->queue);
return 0; return 0;
} }
......
...@@ -399,7 +399,9 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) ...@@ -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, void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
size_t count) size_t count)
{ {
spin_lock(&demux->lock); unsigned long flags;
spin_lock_irqsave(&demux->lock, flags);
while (count--) { while (count--) {
if (buf[0] == 0x47) if (buf[0] == 0x47)
...@@ -407,16 +409,17 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, ...@@ -407,16 +409,17 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
buf += 188; buf += 188;
} }
spin_unlock(&demux->lock); spin_unlock_irqrestore(&demux->lock, flags);
} }
EXPORT_SYMBOL(dvb_dmx_swfilter_packets); EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
{ {
unsigned long flags;
int p = 0, i, j; int p = 0, i, j;
spin_lock(&demux->lock); spin_lock_irqsave(&demux->lock, flags);
if (demux->tsbufp) { if (demux->tsbufp) {
i = demux->tsbufp; i = demux->tsbufp;
...@@ -449,17 +452,18 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) ...@@ -449,17 +452,18 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
} }
bailout: bailout:
spin_unlock(&demux->lock); spin_unlock_irqrestore(&demux->lock, flags);
} }
EXPORT_SYMBOL(dvb_dmx_swfilter); EXPORT_SYMBOL(dvb_dmx_swfilter);
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
{ {
unsigned long flags;
int p = 0, i, j; int p = 0, i, j;
u8 tmppack[188]; u8 tmppack[188];
spin_lock(&demux->lock); spin_lock_irqsave(&demux->lock, flags);
if (demux->tsbufp) { if (demux->tsbufp) {
i = demux->tsbufp; i = demux->tsbufp;
...@@ -500,7 +504,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) ...@@ -500,7 +504,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
} }
bailout: bailout:
spin_unlock(&demux->lock); spin_unlock_irqrestore(&demux->lock, flags);
} }
EXPORT_SYMBOL(dvb_dmx_swfilter_204); EXPORT_SYMBOL(dvb_dmx_swfilter_204);
......
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