[ALSA] Fix possible races at free_irq in PCI drivers
The irq handler of PCI drivers must be released before releasing other
resources since the handler for a shared irq can be still called and
may access the freed resource again.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 3818249..ecbe79b 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1114,6 +1114,8 @@
* So we can fix: snd-malloc: Memory leak? pages not freed = 8
*/
}
+ if (chip->irq >= 0)
+ free_irq(chip->irq, chip);
// release the data
#if 1
if (chip->buffer.area)
@@ -1123,9 +1125,6 @@
// release the i/o port
release_and_free_resource(chip->res_port);
- // release the irq
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
pci_disable_device(chip->pci);
kfree(chip);
return 0;
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 87ddffc..e214e56 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2772,6 +2772,9 @@
if (chip->irq >= 0)
free_irq(chip->irq, chip);
+ if (chip->active_ctrl)
+ chip->active_ctrl(chip, -chip->amplifier);
+
for (idx = 0; idx < 5; idx++) {
struct snd_cs46xx_region *region = &chip->region.idx[idx];
if (region->remap_addr)
@@ -2779,9 +2782,6 @@
release_and_free_resource(region->resource);
}
- if (chip->active_ctrl)
- chip->active_ctrl(chip, -chip->amplifier);
-
#ifdef CONFIG_SND_CS46XX_NEW_DSP
if (chip->dsp_spos_instance) {
cs46xx_dsp_spos_destroy(chip);
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 90ec090..e16dc92 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -1852,15 +1852,16 @@
static int snd_echo_free(struct echoaudio *chip)
{
DE_INIT(("Stop DSP...\n"));
- if (chip->comm_page) {
+ if (chip->comm_page)
rest_in_peace(chip);
- snd_dma_free_pages(&chip->commpage_dma_buf);
- }
DE_INIT(("Stopped.\n"));
if (chip->irq >= 0)
free_irq(chip->irq, chip);
+ if (chip->comm_page)
+ snd_dma_free_pages(&chip->commpage_dma_buf);
+
if (chip->dsp_registers)
iounmap(chip->dsp_registers);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 9a9b977..abde5b9 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1249,11 +1249,6 @@
if (emu->port) { /* avoid access to already used hardware */
snd_emu10k1_fx8010_tram_setup(emu, 0);
snd_emu10k1_done(emu);
- /* remove reserved page */
- if (emu->reserved_page) {
- snd_emu10k1_synth_free(emu, (struct snd_util_memblk *)emu->reserved_page);
- emu->reserved_page = NULL;
- }
snd_emu10k1_free_efx(emu);
}
if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
@@ -1262,6 +1257,14 @@
}
if (emu->emu1010.firmware_thread)
kthread_stop(emu->emu1010.firmware_thread);
+ if (emu->irq >= 0)
+ free_irq(emu->irq, emu);
+ /* remove reserved page */
+ if (emu->reserved_page) {
+ snd_emu10k1_synth_free(emu,
+ (struct snd_util_memblk *)emu->reserved_page);
+ emu->reserved_page = NULL;
+ }
if (emu->memhdr)
snd_util_memhdr_free(emu->memhdr);
if (emu->silent_page.area)
@@ -1273,8 +1276,6 @@
#ifdef CONFIG_PM
free_pm_buffer(emu);
#endif
- if (emu->irq >= 0)
- free_irq(emu->irq, emu);
if (emu->port)
pci_release_regions(emu->pci);
if (emu->card_capabilities->ca0151_chip) /* P16V */
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 341f34e..491a4a5 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -754,13 +754,13 @@
// disable audio
outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG);
- // release the i/o port
- release_and_free_resource(chip->res_port);
-
- // release the irq
+ /* release the irq */
if (chip->irq >= 0)
free_irq(chip->irq, chip);
+ // release the i/o port
+ release_and_free_resource(chip->res_port);
+
// release the DMA
if (chip->dma_buffer.area) {
snd_dma_free_pages(&chip->dma_buffer);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 15db810..faf674e 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -985,18 +985,15 @@
/* reset channels */
for (i = 0; i < chip->bdbars_count; i++)
iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
- /* --- */
+ __hw_end:
if (chip->irq >= 0)
- synchronize_irq(chip->irq);
- __hw_end:
+ free_irq(chip->irq, chip);
if (chip->bdbars.area)
snd_dma_free_pages(&chip->bdbars);
if (chip->addr)
pci_iounmap(chip->pci, chip->addr);
if (chip->bmaddr)
pci_iounmap(chip->pci, chip->bmaddr);
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
@@ -1018,7 +1015,6 @@
snd_pcm_suspend_all(chip->pcm[i]);
snd_ac97_suspend(chip->ac97);
if (chip->irq >= 0) {
- synchronize_irq(chip->irq);
free_irq(chip->irq, chip);
chip->irq = -1;
}
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 10c713d..f4c85b5 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2102,7 +2102,6 @@
snd_korg1212_TurnOffIdleMonitor(korg1212);
if (korg1212->irq >= 0) {
- synchronize_irq(korg1212->irq);
snd_korg1212_DisableCardInterrupts(korg1212);
free_irq(korg1212->irq, korg1212);
korg1212->irq = -1;
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 7ac654e..7efb838 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1439,7 +1439,7 @@
snd_nm256_capture_stop(chip);
if (chip->irq >= 0)
- synchronize_irq(chip->irq);
+ free_irq(chip->irq, chip);
if (chip->cport)
iounmap(chip->cport);
@@ -1447,8 +1447,6 @@
iounmap(chip->buffer);
release_and_free_resource(chip->res_cport);
release_and_free_resource(chip->res_buffer);
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
pci_disable_device(chip->pci);
kfree(chip->ac97_regs);
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 71138ff..bbcee2c 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -3676,6 +3676,8 @@
else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
outl(0, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
}
+ if (trident->irq >= 0)
+ free_irq(trident->irq, trident);
if (trident->tlb.buffer.area) {
outl(0, TRID_REG(trident, NX_TLBC));
if (trident->tlb.memhdr)
@@ -3685,8 +3687,6 @@
vfree(trident->tlb.shadow_entries);
snd_dma_free_pages(&trident->tlb.buffer);
}
- if (trident->irq >= 0)
- free_irq(trident->irq, trident);
pci_release_regions(trident->pci);
pci_disable_device(trident->pci);
kfree(trident);