Skip to content

Commit 78aaacf

Browse files
ujfalusilgirdwood
authored andcommitted
ASoC: SOF: ipc4-pcm: harden pipeline teardown races
Serialize trigger/free with pipeline_state_mutex and validate pipeline entries before use. Also clear pipeline_list->count when freeing lists to avoid stale entries during concurrent teardown. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent d8a8af7 commit 78aaacf

1 file changed

Lines changed: 16 additions & 2 deletions

File tree

sound/soc/sof/ipc4-pcm.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,12 +434,16 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
434434
spcm_dbg(spcm, substream->stream, "cmd: %d, state: %d\n", cmd, state);
435435

436436
pipeline_list = &spcm->stream[substream->stream].pipeline_list;
437+
guard(mutex)(&ipc4_data->pipeline_state_mutex);
437438

438439
/* nothing to trigger if the list is empty */
439440
if (!pipeline_list->pipelines || !pipeline_list->count)
440441
return 0;
441442

442443
spipe = pipeline_list->pipelines[0];
444+
if (!spipe || !spipe->pipe_widget || !spipe->pipe_widget->private)
445+
return 0;
446+
443447
pipe_widget = spipe->pipe_widget;
444448
pipeline = pipe_widget->private;
445449

@@ -487,8 +491,6 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
487491
return -ENOMEM;
488492
}
489493

490-
guard(mutex)(&ipc4_data->pipeline_state_mutex);
491-
492494
/*
493495
* IPC4 requires pipelines to be triggered in order starting at the sink and
494496
* walking all the way to the source. So traverse the pipeline_list in the order
@@ -501,12 +503,16 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
501503
if (state == SOF_IPC4_PIPE_RUNNING || state == SOF_IPC4_PIPE_RESET)
502504
for (i = pipeline_list->count - 1; i >= 0; i--) {
503505
spipe = pipeline_list->pipelines[i];
506+
if (!spipe || !spipe->pipe_widget || !spipe->pipe_widget->private)
507+
continue;
504508
sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list,
505509
pipe_priority);
506510
}
507511
else
508512
for (i = 0; i < pipeline_list->count; i++) {
509513
spipe = pipeline_list->pipelines[i];
514+
if (!spipe || !spipe->pipe_widget || !spipe->pipe_widget->private)
515+
continue;
510516
sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list,
511517
pipe_priority);
512518
}
@@ -546,6 +552,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
546552
/* update PAUSED state for all pipelines just triggered */
547553
for (i = 0; i < pipeline_list->count ; i++) {
548554
spipe = pipeline_list->pipelines[i];
555+
if (!spipe || !spipe->pipe_widget || !spipe->pipe_widget->private)
556+
continue;
549557
sof_ipc4_update_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, cmd, spipe,
550558
trigger_list);
551559
}
@@ -589,6 +597,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
589597
/* update RUNNING/RESET state for all pipelines that were just triggered */
590598
for (i = 0; i < pipeline_list->count; i++) {
591599
spipe = pipeline_list->pipelines[i];
600+
if (!spipe || !spipe->pipe_widget || !spipe->pipe_widget->private)
601+
continue;
592602
sof_ipc4_update_pipeline_state(sdev, state, cmd, spipe, trigger_list);
593603
}
594604

@@ -903,13 +913,17 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
903913
static void sof_ipc4_pcm_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm)
904914
{
905915
struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
916+
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
906917
struct sof_ipc4_pcm_stream_priv *stream_priv;
907918
int stream;
908919

920+
guard(mutex)(&ipc4_data->pipeline_state_mutex);
921+
909922
for_each_pcm_streams(stream) {
910923
pipeline_list = &spcm->stream[stream].pipeline_list;
911924
kfree(pipeline_list->pipelines);
912925
pipeline_list->pipelines = NULL;
926+
pipeline_list->count = 0;
913927

914928
stream_priv = spcm->stream[stream].private;
915929
kfree(stream_priv->time_info);

0 commit comments

Comments
 (0)