| From: Takashi Iwai <tiwai@suse.de> |
| Date: Tue, 15 May 2018 20:25:29 +0200 |
| Subject: ALSA: core: Assure control device to be registered at last |
| |
| commit dc82e52492f684dcd5ed9e4773e72dbf2203d75e upstream. |
| |
| The commit 289ca025ee1d ("ALSA: Use priority list for managing device |
| list") changed the way to register/disconnect/free devices via a |
| single priority list. This helped to make behavior consistent, but it |
| also changed a slight behavior change: namely, the control device is |
| registered earlier than others, while it was supposed to be the very |
| last one. |
| |
| I've put SNDRV_DEV_CONTROL in the current position as the release of |
| ctl elements often conflict with the private ctl elements some PCM or |
| other components may create, which often leads to a double-free. |
| But, the order of register and disconnect should be indeed fixed as |
| expected in the early days: the control device gets registered at |
| last, and disconnected at first. |
| |
| This patch changes the priority list order to move SNDRV_DEV_CONTROL |
| as the last guy to assure the register / disconnect order. Meanwhile, |
| for keeping the messy resource release order, manually treat the |
| control and lowlevel devices as last freed one. |
| |
| Additional note: |
| The lowlevel device is the device where a card driver creates at |
| probe. And, we still keep the release order control -> lowlevel, as |
| there might be link from a control element back to a lowlevel object. |
| |
| Fixes: 289ca025ee1d ("ALSA: Use priority list for managing device list") |
| Reported-by: Tzung-Bi Shih <tzungbi@google.com> |
| Tested-by: Tzung-Bi Shih <tzungbi@google.com> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| include/sound/core.h | 2 +- |
| sound/core/device.c | 9 +++++++++ |
| 2 files changed, 10 insertions(+), 1 deletion(-) |
| |
| --- a/include/sound/core.h |
| +++ b/include/sound/core.h |
| @@ -51,7 +51,6 @@ struct completion; |
| */ |
| enum snd_device_type { |
| SNDRV_DEV_LOWLEVEL, |
| - SNDRV_DEV_CONTROL, |
| SNDRV_DEV_INFO, |
| SNDRV_DEV_BUS, |
| SNDRV_DEV_CODEC, |
| @@ -62,6 +61,7 @@ enum snd_device_type { |
| SNDRV_DEV_SEQUENCER, |
| SNDRV_DEV_HWDEP, |
| SNDRV_DEV_JACK, |
| + SNDRV_DEV_CONTROL, /* NOTE: this must be the last one */ |
| }; |
| |
| enum snd_device_state { |
| --- a/sound/core/device.c |
| +++ b/sound/core/device.c |
| @@ -219,6 +219,15 @@ void snd_device_free_all(struct snd_card |
| |
| if (snd_BUG_ON(!card)) |
| return; |
| + list_for_each_entry_safe_reverse(dev, next, &card->devices, list) { |
| + /* exception: free ctl and lowlevel stuff later */ |
| + if (dev->type == SNDRV_DEV_CONTROL || |
| + dev->type == SNDRV_DEV_LOWLEVEL) |
| + continue; |
| + __snd_device_free(dev); |
| + } |
| + |
| + /* free all */ |
| list_for_each_entry_safe_reverse(dev, next, &card->devices, list) |
| __snd_device_free(dev); |
| } |