summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@linux.intel.com>2026-10-07 11:49:30 +0300
committerMark Brown <broonie@kernel.org>2026-10-07 13:16:48 +0200
commitb04c9229ee31be8f3cd87d15648b040bee2e64ae (patch)
tree0002d6fbb817fe48ff8aa90ff8afc6e7929b1239
parentfd7f98db9c28574b102303e317f4dca712281003 (diff)
downloadlinux-next-b04c9229ee31be8f3cd87d15648b040bee2e64ae.tar.gz
linux-next-b04c9229ee31be8f3cd87d15648b040bee2e64ae.zip
ALSA: compress: stop active streams on disconnect
Track open compressed streams per device so disconnect can stop active streams and wake waiters before snd_unregister_device(). This aligns compressed stream teardown with PCM disconnect behavior and prevents active userspace streams from running into unregister races. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com> Reviewed-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20261007084955.1256-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--include/sound/compress_driver.h2
-rw-r--r--sound/core/compress_offload.c48
2 files changed, 41 insertions, 9 deletions
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index 9e3d801e45ec..84f51edc3f9d 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -188,6 +188,7 @@ struct snd_compr_ops {
* @card: sound card pointer
* @direction: Playback or capture direction
* @lock: device lock
+ * @open_list: list of open compress files
* @device: device id
* @use_pause_in_draining: allow pause in draining, true when set
*/
@@ -199,6 +200,7 @@ struct snd_compr {
struct snd_card *card;
unsigned int direction;
struct mutex lock;
+ struct list_head open_list;
int device;
bool use_pause_in_draining;
#ifdef CONFIG_SND_VERBOSE_PROCFS
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index aaed865f8175..89435e4394ef 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -42,6 +42,7 @@
#endif
struct snd_compr_file {
+ struct list_head list;
unsigned long caps;
struct snd_compr_stream stream;
};
@@ -124,6 +125,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
ret = -ENOMEM;
goto __error;
}
+ INIT_LIST_HEAD(&data->list);
INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work);
@@ -143,8 +145,11 @@ static int snd_compr_open(struct inode *inode, struct file *f)
#endif
data->stream.runtime = runtime;
f->private_data = (void *)data;
- scoped_guard(mutex, &compr->lock)
+ scoped_guard(mutex, &compr->lock) {
ret = compr->ops->open(&data->stream);
+ if (!ret)
+ list_add_tail(&data->list, &compr->open_list);
+ }
__error:
if (ret) {
@@ -165,14 +170,19 @@ static int snd_compr_free(struct inode *inode, struct file *f)
cancel_delayed_work_sync(&data->stream.error_work);
- switch (runtime->state) {
- case SNDRV_PCM_STATE_RUNNING:
- case SNDRV_PCM_STATE_DRAINING:
- case SNDRV_PCM_STATE_PAUSED:
- data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP);
- break;
- default:
- break;
+ scoped_guard(mutex, &compr->lock) {
+ if (!list_empty(&data->list))
+ list_del_init(&data->list);
+
+ switch (runtime->state) {
+ case SNDRV_PCM_STATE_RUNNING:
+ case SNDRV_PCM_STATE_DRAINING:
+ case SNDRV_PCM_STATE_PAUSED:
+ data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP);
+ break;
+ default:
+ break;
+ }
}
snd_compr_task_free_all(&data->stream);
@@ -1450,8 +1460,27 @@ static int snd_compress_dev_register(struct snd_device *device)
static int snd_compress_dev_disconnect(struct snd_device *device)
{
struct snd_compr *compr;
+ struct snd_compr_file *data;
compr = device->device_data;
+ scoped_guard(mutex, &compr->lock) {
+ list_for_each_entry(data, &compr->open_list, list) {
+ switch (data->stream.runtime->state) {
+ case SNDRV_PCM_STATE_RUNNING:
+ case SNDRV_PCM_STATE_DRAINING:
+ case SNDRV_PCM_STATE_PAUSED:
+ data->stream.ops->trigger(&data->stream,
+ SNDRV_PCM_TRIGGER_STOP);
+ break;
+ default:
+ break;
+ }
+
+ data->stream.runtime->state = SNDRV_PCM_STATE_DISCONNECTED;
+ wake_up(&data->stream.runtime->sleep);
+ }
+ }
+
snd_unregister_device(compr->dev);
return 0;
}
@@ -1559,6 +1588,7 @@ int snd_compress_new(struct snd_card *card, int device,
compr->device = device;
compr->direction = dirn;
mutex_init(&compr->lock);
+ INIT_LIST_HEAD(&compr->open_list);
snd_compress_set_id(compr, id);