Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ebf029da authored by Takashi Iwai's avatar Takashi Iwai
Browse files

[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: default avatarTakashi Iwai <tiwai@suse.de>
parent 6b9a9b32
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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;
+3 −3
Original line number Diff line number Diff line
@@ -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);
+4 −3
Original line number Diff line number Diff line
@@ -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);

+8 −7
Original line number Diff line number Diff line
@@ -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 */	
+4 −4
Original line number Diff line number Diff line
@@ -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);
Loading