| From a8ff48cb70835f48de5703052760312019afea55 Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Fri, 8 Jul 2016 08:23:43 +0200 |
| Subject: ALSA: pcm: Free chmap at PCM free callback, too |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| commit a8ff48cb70835f48de5703052760312019afea55 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: Laxminath Kasam <b_lkasam@codeaurora.org> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/core/pcm.c | 14 ++++++++++---- |
| 1 file changed, 10 insertions(+), 4 deletions(-) |
| |
| --- a/sound/core/pcm.c |
| +++ b/sound/core/pcm.c |
| @@ -849,6 +849,14 @@ int snd_pcm_new_internal(struct snd_card |
| } |
| 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) |
| { |
| struct snd_pcm_substream *substream, *substream_next; |
| @@ -871,6 +879,7 @@ static void snd_pcm_free_stream(struct s |
| kfree(setup); |
| } |
| #endif |
| + free_chmap(pstr); |
| if (pstr->substream_count) |
| put_device(&pstr->dev); |
| } |
| @@ -1135,10 +1144,7 @@ static int snd_pcm_dev_disconnect(struct |
| for (cidx = 0; cidx < 2; cidx++) { |
| if (!pcm->internal) |
| snd_unregister_device(&pcm->streams[cidx].dev); |
| - if (pcm->streams[cidx].chmap_kctl) { |
| - snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl); |
| - pcm->streams[cidx].chmap_kctl = NULL; |
| - } |
| + free_chmap(&pcm->streams[cidx]); |
| } |
| mutex_unlock(&pcm->open_mutex); |
| mutex_unlock(®ister_mutex); |