Commit 3c09ac6e authored by Takashi Iwai's avatar Takashi Iwai Committed by Ben Hutchings

ALSA: pcm: Free chmap at PCM free callback, too

commit a8ff48cb upstream.

The chmap ctls assigned to PCM streams are freed in the PCM disconnect
callback.  However, since the disconnect callback isn't called when
the card gets freed before registering, the chmap ctls may still be
left assigned.  They are eventually freed together with other ctls,
but it may cause an Oops at pcm_chmap_ctl_private_free(), as the
function refers to the assigned PCM stream, while the PCM objects have
been already freed beforehand.

The fix is to free the chmap ctls also at PCM free callback, not only
at PCM disconnect.
Reported-by: default avatarLaxminath Kasam <b_lkasam@codeaurora.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent a2bc6933
...@@ -806,6 +806,14 @@ int snd_pcm_new_internal(struct snd_card *card, const char *id, int device, ...@@ -806,6 +806,14 @@ int snd_pcm_new_internal(struct snd_card *card, const char *id, int device,
} }
EXPORT_SYMBOL(snd_pcm_new_internal); EXPORT_SYMBOL(snd_pcm_new_internal);
static void free_chmap(struct snd_pcm_str *pstr)
{
if (pstr->chmap_kctl) {
snd_ctl_remove(pstr->pcm->card, pstr->chmap_kctl);
pstr->chmap_kctl = NULL;
}
}
static void snd_pcm_free_stream(struct snd_pcm_str * pstr) static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
{ {
struct snd_pcm_substream *substream, *substream_next; struct snd_pcm_substream *substream, *substream_next;
...@@ -828,6 +836,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) ...@@ -828,6 +836,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
kfree(setup); kfree(setup);
} }
#endif #endif
free_chmap(pstr);
} }
static int snd_pcm_free(struct snd_pcm *pcm) static int snd_pcm_free(struct snd_pcm *pcm)
...@@ -1142,10 +1151,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) ...@@ -1142,10 +1151,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
break; break;
} }
snd_unregister_device(devtype, pcm->card, pcm->device); snd_unregister_device(devtype, pcm->card, pcm->device);
if (pcm->streams[cidx].chmap_kctl) { free_chmap(&pcm->streams[cidx]);
snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
pcm->streams[cidx].chmap_kctl = NULL;
}
} }
mutex_unlock(&pcm->open_mutex); mutex_unlock(&pcm->open_mutex);
unlock: unlock:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment