From: Takashi Iwai Date: Tue, 22 Apr 2008 15:28:11 +0000 (+0200) Subject: [ALSA] Fix possible races at free_irq in PCI drivers X-Git-Tag: v2.6.26-rc1~1087^2~19 X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=commitdiff_plain;h=ebf029da38829ede6b53ac8a5ad45b149064ea16 [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 --- diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 3818249fcc81..ecbe79b67e43 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1114,6 +1114,8 @@ static int snd_ca0106_free(struct snd_ca0106 *chip) * 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 @@ static int snd_ca0106_free(struct snd_ca0106 *chip) // 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 87ddffcd9d89..e214e567dec8 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -2772,6 +2772,9 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip) 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 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip) 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 90ec090792ba..e16dc92e82fb 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1852,15 +1852,16 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id) 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 9a9b977d3cf1..abde5b901884 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1249,11 +1249,6 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) 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 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) } 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 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) #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 341f34e19f3c..491a4a50f869 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -754,13 +754,13 @@ static int snd_emu10k1x_free(struct emu10k1x *chip) // 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 15db810d5893..faf674e671ac 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -985,18 +985,15 @@ static int snd_intel8x0_free(struct intel8x0m *chip) /* 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 @@ static int intel8x0m_suspend(struct pci_dev *pci, pm_message_t state) 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 10c713d9ac49..f4c85b52bde3 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2102,7 +2102,6 @@ snd_korg1212_free(struct snd_korg1212 *korg1212) 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 7ac654e381da..7efb838d18a6 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1439,7 +1439,7 @@ static int snd_nm256_free(struct nm256 *chip) 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 @@ static int snd_nm256_free(struct nm256 *chip) 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 71138ff9b310..bbcee2c09ae4 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3676,6 +3676,8 @@ static int snd_trident_free(struct snd_trident *trident) 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 @@ static int snd_trident_free(struct snd_trident *trident) 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);