diff options
author | Alexey Khoroshilov <khoroshilov@ispras.ru> | 2013-04-13 17:52:04 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-04-22 09:08:30 -0400 |
commit | 5ddfbbb9ca2e74d4b392ccef675641babba6b7f8 (patch) | |
tree | 8e2be3b14c057112be5d5d9fb8a708df2f06cc1e /drivers/media/pci | |
parent | cdcfe40a5fee6a3300632b9a6e7f9de596f0b450 (diff) |
[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: Alexey Khoroshilov <khoroshilov@ispras.ru>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/pci')
-rw-r--r-- | drivers/media/pci/cx88/cx88-mpeg.c | 10 | ||||
-rw-r--r-- | drivers/media/pci/cx88/cx88-video.c | 10 |
2 files changed, 12 insertions, 8 deletions
diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index c9d3182f79d5..2d3507eb4897 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c | |||
@@ -532,16 +532,17 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) | |||
532 | { | 532 | { |
533 | struct cx8802_dev *dev = pci_get_drvdata(pci_dev); | 533 | struct cx8802_dev *dev = pci_get_drvdata(pci_dev); |
534 | struct cx88_core *core = dev->core; | 534 | struct cx88_core *core = dev->core; |
535 | unsigned long flags; | ||
535 | 536 | ||
536 | /* stop mpeg dma */ | 537 | /* stop mpeg dma */ |
537 | spin_lock(&dev->slock); | 538 | spin_lock_irqsave(&dev->slock, flags); |
538 | if (!list_empty(&dev->mpegq.active)) { | 539 | if (!list_empty(&dev->mpegq.active)) { |
539 | dprintk( 2, "suspend\n" ); | 540 | dprintk( 2, "suspend\n" ); |
540 | printk("%s: suspend mpeg\n", core->name); | 541 | printk("%s: suspend mpeg\n", core->name); |
541 | cx8802_stop_dma(dev); | 542 | cx8802_stop_dma(dev); |
542 | del_timer(&dev->mpegq.timeout); | 543 | del_timer(&dev->mpegq.timeout); |
543 | } | 544 | } |
544 | spin_unlock(&dev->slock); | 545 | spin_unlock_irqrestore(&dev->slock, flags); |
545 | 546 | ||
546 | /* FIXME -- shutdown device */ | 547 | /* FIXME -- shutdown device */ |
547 | cx88_shutdown(dev->core); | 548 | cx88_shutdown(dev->core); |
@@ -558,6 +559,7 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) | |||
558 | { | 559 | { |
559 | struct cx8802_dev *dev = pci_get_drvdata(pci_dev); | 560 | struct cx8802_dev *dev = pci_get_drvdata(pci_dev); |
560 | struct cx88_core *core = dev->core; | 561 | struct cx88_core *core = dev->core; |
562 | unsigned long flags; | ||
561 | int err; | 563 | int err; |
562 | 564 | ||
563 | if (dev->state.disabled) { | 565 | if (dev->state.disabled) { |
@@ -584,12 +586,12 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) | |||
584 | cx88_reset(dev->core); | 586 | cx88_reset(dev->core); |
585 | 587 | ||
586 | /* restart video+vbi capture */ | 588 | /* restart video+vbi capture */ |
587 | spin_lock(&dev->slock); | 589 | spin_lock_irqsave(&dev->slock, flags); |
588 | if (!list_empty(&dev->mpegq.active)) { | 590 | if (!list_empty(&dev->mpegq.active)) { |
589 | printk("%s: resume mpeg\n", core->name); | 591 | printk("%s: resume mpeg\n", core->name); |
590 | cx8802_restart_queue(dev,&dev->mpegq); | 592 | cx8802_restart_queue(dev,&dev->mpegq); |
591 | } | 593 | } |
592 | spin_unlock(&dev->slock); | 594 | spin_unlock_irqrestore(&dev->slock, flags); |
593 | 595 | ||
594 | return 0; | 596 | return 0; |
595 | } | 597 | } |
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index e3f6181d1044..1b00615fd395 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c | |||
@@ -1954,9 +1954,10 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) | |||
1954 | { | 1954 | { |
1955 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); | 1955 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); |
1956 | struct cx88_core *core = dev->core; | 1956 | struct cx88_core *core = dev->core; |
1957 | unsigned long flags; | ||
1957 | 1958 | ||
1958 | /* stop video+vbi capture */ | 1959 | /* stop video+vbi capture */ |
1959 | spin_lock(&dev->slock); | 1960 | spin_lock_irqsave(&dev->slock, flags); |
1960 | if (!list_empty(&dev->vidq.active)) { | 1961 | if (!list_empty(&dev->vidq.active)) { |
1961 | printk("%s/0: suspend video\n", core->name); | 1962 | printk("%s/0: suspend video\n", core->name); |
1962 | stop_video_dma(dev); | 1963 | stop_video_dma(dev); |
@@ -1967,7 +1968,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) | |||
1967 | cx8800_stop_vbi_dma(dev); | 1968 | cx8800_stop_vbi_dma(dev); |
1968 | del_timer(&dev->vbiq.timeout); | 1969 | del_timer(&dev->vbiq.timeout); |
1969 | } | 1970 | } |
1970 | spin_unlock(&dev->slock); | 1971 | spin_unlock_irqrestore(&dev->slock, flags); |
1971 | 1972 | ||
1972 | if (core->ir) | 1973 | if (core->ir) |
1973 | cx88_ir_stop(core); | 1974 | cx88_ir_stop(core); |
@@ -1986,6 +1987,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) | |||
1986 | { | 1987 | { |
1987 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); | 1988 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); |
1988 | struct cx88_core *core = dev->core; | 1989 | struct cx88_core *core = dev->core; |
1990 | unsigned long flags; | ||
1989 | int err; | 1991 | int err; |
1990 | 1992 | ||
1991 | if (dev->state.disabled) { | 1993 | if (dev->state.disabled) { |
@@ -2016,7 +2018,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) | |||
2016 | cx_set(MO_PCI_INTMSK, core->pci_irqmask); | 2018 | cx_set(MO_PCI_INTMSK, core->pci_irqmask); |
2017 | 2019 | ||
2018 | /* restart video+vbi capture */ | 2020 | /* restart video+vbi capture */ |
2019 | spin_lock(&dev->slock); | 2021 | spin_lock_irqsave(&dev->slock, flags); |
2020 | if (!list_empty(&dev->vidq.active)) { | 2022 | if (!list_empty(&dev->vidq.active)) { |
2021 | printk("%s/0: resume video\n", core->name); | 2023 | printk("%s/0: resume video\n", core->name); |
2022 | restart_video_queue(dev,&dev->vidq); | 2024 | restart_video_queue(dev,&dev->vidq); |
@@ -2025,7 +2027,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) | |||
2025 | printk("%s/0: resume vbi\n", core->name); | 2027 | printk("%s/0: resume vbi\n", core->name); |
2026 | cx8800_restart_vbi_queue(dev,&dev->vbiq); | 2028 | cx8800_restart_vbi_queue(dev,&dev->vbiq); |
2027 | } | 2029 | } |
2028 | spin_unlock(&dev->slock); | 2030 | spin_unlock_irqrestore(&dev->slock, flags); |
2029 | 2031 | ||
2030 | return 0; | 2032 | return 0; |
2031 | } | 2033 | } |