Commit 5ddfbbb9 authored by Alexey Khoroshilov's avatar Alexey Khoroshilov Committed by Mauro Carvalho Chehab

[media] cx88: Fix unsafe locking in suspend-resume

Legacy PCI suspend-resume handlers are called with interrupts enabled.

But cx8800_suspend/cx8800_resume and
cx8802_suspend_common/cx8802_resume_common use spin_lock/spin_unlock
functions to acquire dev->slock, while the same lock is acquired in the
corresponding irq-handlers: cx8800_irq and cx8802_irq.

That means a deadlock is possible if an interrupt happens while suspend
or resume owns the lock. The patch replaces spin_lock/spin_unlock with
spin_lock_irqsave/spin_unlock_irqrestore.

Found by Linux Driver Verification project (linuxtesting.org).

[mchehab@redhat.com: Fix CodingStyle]
Signed-off-by: default avatarAlexey Khoroshilov <khoroshilov@ispras.ru>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent cdcfe40a
...@@ -532,16 +532,17 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) ...@@ -532,16 +532,17 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
{ {
struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core; struct cx88_core *core = dev->core;
unsigned long flags;
/* stop mpeg dma */ /* stop mpeg dma */
spin_lock(&dev->slock); spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->mpegq.active)) { if (!list_empty(&dev->mpegq.active)) {
dprintk( 2, "suspend\n" ); dprintk( 2, "suspend\n" );
printk("%s: suspend mpeg\n", core->name); printk("%s: suspend mpeg\n", core->name);
cx8802_stop_dma(dev); cx8802_stop_dma(dev);
del_timer(&dev->mpegq.timeout); del_timer(&dev->mpegq.timeout);
} }
spin_unlock(&dev->slock); spin_unlock_irqrestore(&dev->slock, flags);
/* FIXME -- shutdown device */ /* FIXME -- shutdown device */
cx88_shutdown(dev->core); cx88_shutdown(dev->core);
...@@ -558,6 +559,7 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) ...@@ -558,6 +559,7 @@ static int cx8802_resume_common(struct pci_dev *pci_dev)
{ {
struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core; struct cx88_core *core = dev->core;
unsigned long flags;
int err; int err;
if (dev->state.disabled) { if (dev->state.disabled) {
...@@ -584,12 +586,12 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) ...@@ -584,12 +586,12 @@ static int cx8802_resume_common(struct pci_dev *pci_dev)
cx88_reset(dev->core); cx88_reset(dev->core);
/* restart video+vbi capture */ /* restart video+vbi capture */
spin_lock(&dev->slock); spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->mpegq.active)) { if (!list_empty(&dev->mpegq.active)) {
printk("%s: resume mpeg\n", core->name); printk("%s: resume mpeg\n", core->name);
cx8802_restart_queue(dev,&dev->mpegq); cx8802_restart_queue(dev,&dev->mpegq);
} }
spin_unlock(&dev->slock); spin_unlock_irqrestore(&dev->slock, flags);
return 0; return 0;
} }
......
...@@ -1954,9 +1954,10 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) ...@@ -1954,9 +1954,10 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
{ {
struct cx8800_dev *dev = pci_get_drvdata(pci_dev); struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core; struct cx88_core *core = dev->core;
unsigned long flags;
/* stop video+vbi capture */ /* stop video+vbi capture */
spin_lock(&dev->slock); spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->vidq.active)) { if (!list_empty(&dev->vidq.active)) {
printk("%s/0: suspend video\n", core->name); printk("%s/0: suspend video\n", core->name);
stop_video_dma(dev); stop_video_dma(dev);
...@@ -1967,7 +1968,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) ...@@ -1967,7 +1968,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
cx8800_stop_vbi_dma(dev); cx8800_stop_vbi_dma(dev);
del_timer(&dev->vbiq.timeout); del_timer(&dev->vbiq.timeout);
} }
spin_unlock(&dev->slock); spin_unlock_irqrestore(&dev->slock, flags);
if (core->ir) if (core->ir)
cx88_ir_stop(core); cx88_ir_stop(core);
...@@ -1986,6 +1987,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) ...@@ -1986,6 +1987,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
{ {
struct cx8800_dev *dev = pci_get_drvdata(pci_dev); struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core; struct cx88_core *core = dev->core;
unsigned long flags;
int err; int err;
if (dev->state.disabled) { if (dev->state.disabled) {
...@@ -2016,7 +2018,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) ...@@ -2016,7 +2018,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
cx_set(MO_PCI_INTMSK, core->pci_irqmask); cx_set(MO_PCI_INTMSK, core->pci_irqmask);
/* restart video+vbi capture */ /* restart video+vbi capture */
spin_lock(&dev->slock); spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->vidq.active)) { if (!list_empty(&dev->vidq.active)) {
printk("%s/0: resume video\n", core->name); printk("%s/0: resume video\n", core->name);
restart_video_queue(dev,&dev->vidq); restart_video_queue(dev,&dev->vidq);
...@@ -2025,7 +2027,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) ...@@ -2025,7 +2027,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
printk("%s/0: resume vbi\n", core->name); printk("%s/0: resume vbi\n", core->name);
cx8800_restart_vbi_queue(dev,&dev->vbiq); cx8800_restart_vbi_queue(dev,&dev->vbiq);
} }
spin_unlock(&dev->slock); spin_unlock_irqrestore(&dev->slock, flags);
return 0; return 0;
} }
......
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