diff options
| author | Cen Zhang <zzzccc427@gmail.com> | 2026-10-22 18:58:20 +0800 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2026-10-23 21:34:09 +0200 |
| commit | d74eb09af56beda9cbe310e9f6554ff1f35f280f (patch) | |
| tree | 074126b2cad14421ad7db11a85cb8f812617e90c /include | |
| parent | e4a21e95c5577dda3a4049b8eb7f2df7d24b3134 (diff) | |
ALSA: pcm: Drain proc callbacks at device disconnect
Disconnecting an individual PCM leaves its proc files accessible until
snd_pcm_free_stream(). HDA codec-only sysfs unbind can take this path
while the controller and card remain registered. An open proc file pins
the card module, but does not hold a codec PCM reference.
With CONFIG_SND_VERBOSE_PROCFS, a prealloc write is buffered until file
release. Without an attached PCM runtime, its release can replace the
DMA buffer after final PCM cleanup has already freed the preallocation:
HDA codec unbind prealloc file release
---------------- ---------------------
hda_codec_driver_remove()
snd_hda_codec_disconnect_pcms()
snd_device_disconnect()
snd_pcm_dev_disconnect()
/* proc nodes remain */
snd_hda_codec_cleanup_for_unbind()
codec_release_pcms()
snd_device_free()
snd_pcm_free()
free preallocated buffer
snd_info_text_entry_release()
snd_pcm_lib_preallocate_proc_write()
replace DMA buffer
remove stream proc nodes
free substream
The later proc rundown can itself invoke this buffered write and leave
the replacement allocation without a final free. A concurrent release
can also overlap the earlier buffer cleanup.
Extract snd_info_disconnect_entry() from snd_info_free_entry() to remove
proc nodes and drain callbacks without freeing the info entry objects.
Use it for both stream directions at PCM disconnect. Finish the existing
PCM state and device disconnection under open_mutex, then drop that lock
before proc rundown: even an otherwise idle proc file can run its
buffered release callback, which takes open_mutex, during proc_remove().
Keep entry ownership and final cleanup unchanged, including the saved
OSS child entries. As with existing info entry teardown, callers must
serialize registration with disconnection and release.
Suggested-by: Takashi Iwai <tiwai@suse.de>
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Link: https://patch.msgid.link/pm-pmb-2439c851f82c443c3600-v7-2774a482b7f03e1fef60@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'include')
| -rw-r--r-- | include/sound/info.h | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/include/sound/info.h b/include/sound/info.h index adbc506860d6..f216291e5c41 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -117,6 +117,7 @@ struct snd_info_entry *snd_info_create_module_entry(struct module *module, struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry *parent); +void snd_info_disconnect_entry(struct snd_info_entry *entry); void snd_info_free_entry(struct snd_info_entry *entry); int snd_info_card_create(struct snd_card *card); @@ -164,6 +165,7 @@ static inline int snd_info_get_line(struct snd_info_buffer *buffer, char *line, static inline char *snd_info_get_str(char *dest, char *src, int len) { return NULL; } static inline struct snd_info_entry *snd_info_create_module_entry(struct module *module, const char *name, struct snd_info_entry *parent) { return NULL; } static inline struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry *parent) { return NULL; } +static inline void snd_info_disconnect_entry(struct snd_info_entry *entry) { } static inline void snd_info_free_entry(struct snd_info_entry *entry) { ; } static inline int snd_info_card_create(struct snd_card *card) { return 0; } |
