[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>
This commit is contained in:
@@ -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
|
* So we can fix: snd-malloc: Memory leak? pages not freed = 8
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
if (chip->irq >= 0)
|
||||||
|
free_irq(chip->irq, chip);
|
||||||
// release the data
|
// release the data
|
||||||
#if 1
|
#if 1
|
||||||
if (chip->buffer.area)
|
if (chip->buffer.area)
|
||||||
@@ -1123,9 +1125,6 @@ static int snd_ca0106_free(struct snd_ca0106 *chip)
|
|||||||
// release the i/o port
|
// release the i/o port
|
||||||
release_and_free_resource(chip->res_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);
|
pci_disable_device(chip->pci);
|
||||||
kfree(chip);
|
kfree(chip);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -2772,6 +2772,9 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
|
|||||||
if (chip->irq >= 0)
|
if (chip->irq >= 0)
|
||||||
free_irq(chip->irq, chip);
|
free_irq(chip->irq, chip);
|
||||||
|
|
||||||
|
if (chip->active_ctrl)
|
||||||
|
chip->active_ctrl(chip, -chip->amplifier);
|
||||||
|
|
||||||
for (idx = 0; idx < 5; idx++) {
|
for (idx = 0; idx < 5; idx++) {
|
||||||
struct snd_cs46xx_region *region = &chip->region.idx[idx];
|
struct snd_cs46xx_region *region = &chip->region.idx[idx];
|
||||||
if (region->remap_addr)
|
if (region->remap_addr)
|
||||||
@@ -2779,9 +2782,6 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
|
|||||||
release_and_free_resource(region->resource);
|
release_and_free_resource(region->resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chip->active_ctrl)
|
|
||||||
chip->active_ctrl(chip, -chip->amplifier);
|
|
||||||
|
|
||||||
#ifdef CONFIG_SND_CS46XX_NEW_DSP
|
#ifdef CONFIG_SND_CS46XX_NEW_DSP
|
||||||
if (chip->dsp_spos_instance) {
|
if (chip->dsp_spos_instance) {
|
||||||
cs46xx_dsp_spos_destroy(chip);
|
cs46xx_dsp_spos_destroy(chip);
|
||||||
|
|||||||
@@ -1852,15 +1852,16 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
|
|||||||
static int snd_echo_free(struct echoaudio *chip)
|
static int snd_echo_free(struct echoaudio *chip)
|
||||||
{
|
{
|
||||||
DE_INIT(("Stop DSP...\n"));
|
DE_INIT(("Stop DSP...\n"));
|
||||||
if (chip->comm_page) {
|
if (chip->comm_page)
|
||||||
rest_in_peace(chip);
|
rest_in_peace(chip);
|
||||||
snd_dma_free_pages(&chip->commpage_dma_buf);
|
|
||||||
}
|
|
||||||
DE_INIT(("Stopped.\n"));
|
DE_INIT(("Stopped.\n"));
|
||||||
|
|
||||||
if (chip->irq >= 0)
|
if (chip->irq >= 0)
|
||||||
free_irq(chip->irq, chip);
|
free_irq(chip->irq, chip);
|
||||||
|
|
||||||
|
if (chip->comm_page)
|
||||||
|
snd_dma_free_pages(&chip->commpage_dma_buf);
|
||||||
|
|
||||||
if (chip->dsp_registers)
|
if (chip->dsp_registers)
|
||||||
iounmap(chip->dsp_registers);
|
iounmap(chip->dsp_registers);
|
||||||
|
|
||||||
|
|||||||
@@ -1249,11 +1249,6 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
|
|||||||
if (emu->port) { /* avoid access to already used hardware */
|
if (emu->port) { /* avoid access to already used hardware */
|
||||||
snd_emu10k1_fx8010_tram_setup(emu, 0);
|
snd_emu10k1_fx8010_tram_setup(emu, 0);
|
||||||
snd_emu10k1_done(emu);
|
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);
|
snd_emu10k1_free_efx(emu);
|
||||||
}
|
}
|
||||||
if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
|
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)
|
if (emu->emu1010.firmware_thread)
|
||||||
kthread_stop(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)
|
if (emu->memhdr)
|
||||||
snd_util_memhdr_free(emu->memhdr);
|
snd_util_memhdr_free(emu->memhdr);
|
||||||
if (emu->silent_page.area)
|
if (emu->silent_page.area)
|
||||||
@@ -1273,8 +1276,6 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
|
|||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
free_pm_buffer(emu);
|
free_pm_buffer(emu);
|
||||||
#endif
|
#endif
|
||||||
if (emu->irq >= 0)
|
|
||||||
free_irq(emu->irq, emu);
|
|
||||||
if (emu->port)
|
if (emu->port)
|
||||||
pci_release_regions(emu->pci);
|
pci_release_regions(emu->pci);
|
||||||
if (emu->card_capabilities->ca0151_chip) /* P16V */
|
if (emu->card_capabilities->ca0151_chip) /* P16V */
|
||||||
|
|||||||
@@ -754,13 +754,13 @@ static int snd_emu10k1x_free(struct emu10k1x *chip)
|
|||||||
// disable audio
|
// disable audio
|
||||||
outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG);
|
outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG);
|
||||||
|
|
||||||
// release the i/o port
|
/* release the irq */
|
||||||
release_and_free_resource(chip->res_port);
|
|
||||||
|
|
||||||
// release the irq
|
|
||||||
if (chip->irq >= 0)
|
if (chip->irq >= 0)
|
||||||
free_irq(chip->irq, chip);
|
free_irq(chip->irq, chip);
|
||||||
|
|
||||||
|
// release the i/o port
|
||||||
|
release_and_free_resource(chip->res_port);
|
||||||
|
|
||||||
// release the DMA
|
// release the DMA
|
||||||
if (chip->dma_buffer.area) {
|
if (chip->dma_buffer.area) {
|
||||||
snd_dma_free_pages(&chip->dma_buffer);
|
snd_dma_free_pages(&chip->dma_buffer);
|
||||||
|
|||||||
@@ -985,18 +985,15 @@ static int snd_intel8x0_free(struct intel8x0m *chip)
|
|||||||
/* reset channels */
|
/* reset channels */
|
||||||
for (i = 0; i < chip->bdbars_count; i++)
|
for (i = 0; i < chip->bdbars_count; i++)
|
||||||
iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
|
iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
|
||||||
/* --- */
|
|
||||||
if (chip->irq >= 0)
|
|
||||||
synchronize_irq(chip->irq);
|
|
||||||
__hw_end:
|
__hw_end:
|
||||||
|
if (chip->irq >= 0)
|
||||||
|
free_irq(chip->irq, chip);
|
||||||
if (chip->bdbars.area)
|
if (chip->bdbars.area)
|
||||||
snd_dma_free_pages(&chip->bdbars);
|
snd_dma_free_pages(&chip->bdbars);
|
||||||
if (chip->addr)
|
if (chip->addr)
|
||||||
pci_iounmap(chip->pci, chip->addr);
|
pci_iounmap(chip->pci, chip->addr);
|
||||||
if (chip->bmaddr)
|
if (chip->bmaddr)
|
||||||
pci_iounmap(chip->pci, chip->bmaddr);
|
pci_iounmap(chip->pci, chip->bmaddr);
|
||||||
if (chip->irq >= 0)
|
|
||||||
free_irq(chip->irq, chip);
|
|
||||||
pci_release_regions(chip->pci);
|
pci_release_regions(chip->pci);
|
||||||
pci_disable_device(chip->pci);
|
pci_disable_device(chip->pci);
|
||||||
kfree(chip);
|
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_pcm_suspend_all(chip->pcm[i]);
|
||||||
snd_ac97_suspend(chip->ac97);
|
snd_ac97_suspend(chip->ac97);
|
||||||
if (chip->irq >= 0) {
|
if (chip->irq >= 0) {
|
||||||
synchronize_irq(chip->irq);
|
|
||||||
free_irq(chip->irq, chip);
|
free_irq(chip->irq, chip);
|
||||||
chip->irq = -1;
|
chip->irq = -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2102,7 +2102,6 @@ snd_korg1212_free(struct snd_korg1212 *korg1212)
|
|||||||
snd_korg1212_TurnOffIdleMonitor(korg1212);
|
snd_korg1212_TurnOffIdleMonitor(korg1212);
|
||||||
|
|
||||||
if (korg1212->irq >= 0) {
|
if (korg1212->irq >= 0) {
|
||||||
synchronize_irq(korg1212->irq);
|
|
||||||
snd_korg1212_DisableCardInterrupts(korg1212);
|
snd_korg1212_DisableCardInterrupts(korg1212);
|
||||||
free_irq(korg1212->irq, korg1212);
|
free_irq(korg1212->irq, korg1212);
|
||||||
korg1212->irq = -1;
|
korg1212->irq = -1;
|
||||||
|
|||||||
@@ -1439,7 +1439,7 @@ static int snd_nm256_free(struct nm256 *chip)
|
|||||||
snd_nm256_capture_stop(chip);
|
snd_nm256_capture_stop(chip);
|
||||||
|
|
||||||
if (chip->irq >= 0)
|
if (chip->irq >= 0)
|
||||||
synchronize_irq(chip->irq);
|
free_irq(chip->irq, chip);
|
||||||
|
|
||||||
if (chip->cport)
|
if (chip->cport)
|
||||||
iounmap(chip->cport);
|
iounmap(chip->cport);
|
||||||
@@ -1447,8 +1447,6 @@ static int snd_nm256_free(struct nm256 *chip)
|
|||||||
iounmap(chip->buffer);
|
iounmap(chip->buffer);
|
||||||
release_and_free_resource(chip->res_cport);
|
release_and_free_resource(chip->res_cport);
|
||||||
release_and_free_resource(chip->res_buffer);
|
release_and_free_resource(chip->res_buffer);
|
||||||
if (chip->irq >= 0)
|
|
||||||
free_irq(chip->irq, chip);
|
|
||||||
|
|
||||||
pci_disable_device(chip->pci);
|
pci_disable_device(chip->pci);
|
||||||
kfree(chip->ac97_regs);
|
kfree(chip->ac97_regs);
|
||||||
|
|||||||
@@ -3676,6 +3676,8 @@ static int snd_trident_free(struct snd_trident *trident)
|
|||||||
else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
|
else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
|
||||||
outl(0, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
|
outl(0, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
|
||||||
}
|
}
|
||||||
|
if (trident->irq >= 0)
|
||||||
|
free_irq(trident->irq, trident);
|
||||||
if (trident->tlb.buffer.area) {
|
if (trident->tlb.buffer.area) {
|
||||||
outl(0, TRID_REG(trident, NX_TLBC));
|
outl(0, TRID_REG(trident, NX_TLBC));
|
||||||
if (trident->tlb.memhdr)
|
if (trident->tlb.memhdr)
|
||||||
@@ -3685,8 +3687,6 @@ static int snd_trident_free(struct snd_trident *trident)
|
|||||||
vfree(trident->tlb.shadow_entries);
|
vfree(trident->tlb.shadow_entries);
|
||||||
snd_dma_free_pages(&trident->tlb.buffer);
|
snd_dma_free_pages(&trident->tlb.buffer);
|
||||||
}
|
}
|
||||||
if (trident->irq >= 0)
|
|
||||||
free_irq(trident->irq, trident);
|
|
||||||
pci_release_regions(trident->pci);
|
pci_release_regions(trident->pci);
|
||||||
pci_disable_device(trident->pci);
|
pci_disable_device(trident->pci);
|
||||||
kfree(trident);
|
kfree(trident);
|
||||||
|
|||||||
Reference in New Issue
Block a user