Skip to content

Commit a29bd0d

Browse files
ujfalusilgirdwood
authored andcommitted
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>
1 parent 6314c8b commit a29bd0d

2 files changed

Lines changed: 42 additions & 9 deletions

File tree

include/sound/compress_driver.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ struct snd_compr_ops {
188188
* @card: sound card pointer
189189
* @direction: Playback or capture direction
190190
* @lock: device lock
191+
* @open_list: list of open compress files
191192
* @device: device id
192193
* @use_pause_in_draining: allow pause in draining, true when set
193194
*/
@@ -199,6 +200,7 @@ struct snd_compr {
199200
struct snd_card *card;
200201
unsigned int direction;
201202
struct mutex lock;
203+
struct list_head open_list;
202204
int device;
203205
bool use_pause_in_draining;
204206
#ifdef CONFIG_SND_VERBOSE_PROCFS

sound/core/compress_offload.c

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#endif
4343

4444
struct snd_compr_file {
45+
struct list_head list;
4546
unsigned long caps;
4647
struct snd_compr_stream stream;
4748
};
@@ -117,6 +118,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
117118
ret = -ENOMEM;
118119
goto __error;
119120
}
121+
INIT_LIST_HEAD(&data->list);
120122

121123
INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work);
122124

@@ -136,8 +138,11 @@ static int snd_compr_open(struct inode *inode, struct file *f)
136138
#endif
137139
data->stream.runtime = runtime;
138140
f->private_data = (void *)data;
139-
scoped_guard(mutex, &compr->lock)
141+
scoped_guard(mutex, &compr->lock) {
140142
ret = compr->ops->open(&data->stream);
143+
if (!ret)
144+
list_add_tail(&data->list, &compr->open_list);
145+
}
141146

142147
__error:
143148
if (ret) {
@@ -153,17 +158,23 @@ static int snd_compr_free(struct inode *inode, struct file *f)
153158
{
154159
struct snd_compr_file *data = f->private_data;
155160
struct snd_compr_runtime *runtime = data->stream.runtime;
161+
struct snd_compr *compr = data->stream.device;
156162

157163
cancel_delayed_work_sync(&data->stream.error_work);
158164

159-
switch (runtime->state) {
160-
case SNDRV_PCM_STATE_RUNNING:
161-
case SNDRV_PCM_STATE_DRAINING:
162-
case SNDRV_PCM_STATE_PAUSED:
163-
data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP);
164-
break;
165-
default:
166-
break;
165+
scoped_guard(mutex, &compr->lock) {
166+
if (!list_empty(&data->list))
167+
list_del_init(&data->list);
168+
169+
switch (runtime->state) {
170+
case SNDRV_PCM_STATE_RUNNING:
171+
case SNDRV_PCM_STATE_DRAINING:
172+
case SNDRV_PCM_STATE_PAUSED:
173+
data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP);
174+
break;
175+
default:
176+
break;
177+
}
167178
}
168179

169180
snd_compr_task_free_all(&data->stream);
@@ -1440,8 +1451,27 @@ static int snd_compress_dev_register(struct snd_device *device)
14401451
static int snd_compress_dev_disconnect(struct snd_device *device)
14411452
{
14421453
struct snd_compr *compr;
1454+
struct snd_compr_file *data;
14431455

14441456
compr = device->device_data;
1457+
scoped_guard(mutex, &compr->lock) {
1458+
list_for_each_entry(data, &compr->open_list, list) {
1459+
switch (data->stream.runtime->state) {
1460+
case SNDRV_PCM_STATE_RUNNING:
1461+
case SNDRV_PCM_STATE_DRAINING:
1462+
case SNDRV_PCM_STATE_PAUSED:
1463+
data->stream.ops->trigger(&data->stream,
1464+
SNDRV_PCM_TRIGGER_STOP);
1465+
break;
1466+
default:
1467+
break;
1468+
}
1469+
1470+
data->stream.runtime->state = SNDRV_PCM_STATE_DISCONNECTED;
1471+
wake_up(&data->stream.runtime->sleep);
1472+
}
1473+
}
1474+
14451475
snd_unregister_device(compr->dev);
14461476
return 0;
14471477
}
@@ -1549,6 +1579,7 @@ int snd_compress_new(struct snd_card *card, int device,
15491579
compr->device = device;
15501580
compr->direction = dirn;
15511581
mutex_init(&compr->lock);
1582+
INIT_LIST_HEAD(&compr->open_list);
15521583

15531584
snd_compress_set_id(compr, id);
15541585

0 commit comments

Comments
 (0)