From c44027c89e19adafccd404bbe6f9686722ff4217 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Oct 2017 06:36:13 +0000 Subject: ALSA: add snd_card_disconnect_sync() In case of user unbind ALSA driver during playing back / capturing, each driver needs to stop and remove it correctly. One note here is that we can't cancel from remove function in such case, because unbind operation doesn't check return value from remove function. So, we *must* stop and remove in this case. For this purpose, we need to sync (= wait) until the all top-level operations are canceled at remove function. For example, snd_card_free() processes the disconnection procedure at first, then waits for the completion. That's how the hot-unplug works safely. It's implemented, at least, in the top-level driver removal. Now for the lower level driver, we need a similar strategy. Notify to the toplevel for hot-unplug (disconnect in ALSA), and sync with the stop operation, then continue the rest of its own remove procedure. This patch adds snd_card_disconnect_sync(), and driver can use it from remove function. Note: the "lower level" driver here refers to a middle layer driver (e.g. ASoC components) that can be unbound freely during operation. Most of legacy ALSA helper drivers don't have such a problem because they can't be unbound. Note#2: snd_card_disconnect_sync() merely calls snd_card_disconnect() and syncs with closing all pending files. It takes only the files opened by user-space into account, and doesn't care about object refcounts. (The latter is handled by snd_card_free() completion call, BTW.) Also, the function doesn't free resources by itself. Tested-by: Kuninori Morimoto Signed-off-by: Takashi Iwai --- include/sound/core.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/sound') diff --git a/include/sound/core.h b/include/sound/core.h index 4104a9d1001f..5f181b875c2f 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -133,6 +133,7 @@ struct snd_card { struct device card_dev; /* cardX object for sysfs */ const struct attribute_group *dev_groups[4]; /* assigned sysfs attr */ bool registered; /* card_dev is registered? */ + wait_queue_head_t remove_sleep; #ifdef CONFIG_PM unsigned int power_state; /* power state */ @@ -240,6 +241,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid, struct snd_card **card_ret); int snd_card_disconnect(struct snd_card *card); +void snd_card_disconnect_sync(struct snd_card *card); int snd_card_free(struct snd_card *card); int snd_card_free_when_closed(struct snd_card *card); void snd_card_set_id(struct snd_card *card, const char *id); -- cgit v1.2.3 From 9780ded39bef5d22a84bdc39112df93f70a58bdd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 18 Oct 2017 15:51:59 +0200 Subject: ALSA: hda: Avoid racy recreation of widget kobjects The refresh of HD-audio widget sysfs kobjects via snd_hdac_refresh_widget_sysfs() is slightly racy. The driver recreates the whole tree from scratch after deleting the whole. When CONFIG_DEBUG_KOBJECT_RELEASE option is used, kobject release doesn't happen immediately but delayed, while the re-creation of the same named kobject happens soon after invoking kobject_put(). This may end up with the conflicts of duplicated kobjects, as found in the bug report below. In this patch, we take another approach to refresh the tree: instead of recreating the whole tree, just add the new nodes and delete the non-existing nodes. Since the refresh happens only once at initialization, no longer race would happen. Along with the code change, merge snd_hdac_refresh_widget_sysfs() with the existing snd_hdac_refresh_widgets() with an additional bool flag for simplifying the code. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=197307 Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include/sound') diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 96546b30e900..6f1118545bb8 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -111,8 +111,7 @@ void snd_hdac_device_unregister(struct hdac_device *codec); int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name); int snd_hdac_codec_modalias(struct hdac_device *hdac, char *buf, size_t size); -int snd_hdac_refresh_widgets(struct hdac_device *codec); -int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec); +int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs); unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, unsigned int verb, unsigned int parm); -- cgit v1.2.3 From 57e69e2f06e8fe4949c54e438c9faae0731e92f8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 24 Oct 2017 08:35:09 -0700 Subject: ALSA: wavefront: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Signed-off-by: Kees Cook Signed-off-by: Takashi Iwai --- include/sound/snd_wavefront.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/sound') diff --git a/include/sound/snd_wavefront.h b/include/sound/snd_wavefront.h index cd0bab1ef6f1..fcd770fdcda5 100644 --- a/include/sound/snd_wavefront.h +++ b/include/sound/snd_wavefront.h @@ -28,6 +28,7 @@ struct _snd_wavefront_midi { struct snd_rawmidi_substream *substream_output[2]; struct snd_rawmidi_substream *substream_input[2]; struct timer_list timer; + snd_wavefront_card_t *timer_card; spinlock_t open; spinlock_t virtual; /* protects isvirtual */ }; -- cgit v1.2.3