Skip to content

Commit

Permalink
[ALSA] Fix possible races at free_irq in PCI drivers
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
tiwai committed Apr 24, 2008
1 parent 6b9a9b3 commit ebf029d
Show file tree
Hide file tree
Showing 9 changed files with 26 additions and 32 deletions.
5 changes: 2 additions & 3 deletions sound/pci/ca0106/ca0106_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions sound/pci/cs46xx/cs46xx_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -2772,16 +2772,16 @@ 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)
iounmap(region->remap_addr);
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);
Expand Down
7 changes: 4 additions & 3 deletions sound/pci/echoaudio/echoaudio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
15 changes: 8 additions & 7 deletions sound/pci/emu10k1/emu10k1_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)
Expand All @@ -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 */
Expand Down
8 changes: 4 additions & 4 deletions sound/pci/emu10k1/emu10k1x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 2 additions & 6 deletions sound/pci/intel8x0m.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down
1 change: 0 additions & 1 deletion sound/pci/korg1212/korg1212.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 1 addition & 3 deletions sound/pci/nm256/nm256.c
Original file line number Diff line number Diff line change
Expand Up @@ -1439,16 +1439,14 @@ 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);
if (chip->buffer)
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);
Expand Down
4 changes: 2 additions & 2 deletions sound/pci/trident/trident_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
Expand Down

0 comments on commit ebf029d

Please sign in to comment.