From dc82e52492f684dcd5ed9e4773e72dbf2203d75e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 May 2018 20:25:29 +0200 Subject: ALSA: core: Assure control device to be registered at last 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 Tested-by: Tzung-Bi Shih Signed-off-by: Takashi Iwai --- sound/core/device.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound/core/device.c') diff --git a/sound/core/device.c b/sound/core/device.c index cb0e46f66cc9..535102d564e3 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -240,6 +240,15 @@ void snd_device_free_all(struct snd_card *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); } -- cgit