diff options
author | Wenkai Du <wenkai.du@intel.com> | 2014-04-23 06:29:30 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-04-23 07:11:20 -0400 |
commit | d132cb0a162fa55c82e06b771fcaa871d30c9398 (patch) | |
tree | 73bb32ad7e94188caf7ecbc992a3eb6b12eefdba /sound | |
parent | 95e9ee92e20162681e9f65c25962e0606db9d149 (diff) |
ASoC: Intel: Fix audio crash due to race condition in stream deletion
There is a race between sst_byt_stream_free() and sst_byt_get_stream()
if sst_byt_get_stream() called from sst_byt_irq_thread() context is
accessing the byt->stream_list while a stream is deleted from the list.
A stream is added to byt->stream_list in sst_byt_stream_new() and deleted in
sst_byt_stream_free(). sst_byt_get_stream() is always protected by
sst->spinlock, but the stream addition and deletion are not protected.
The patch adds spinlock to both stream addition and deletion.
[Jarkko: Same fix added to sst-haswell-ipc.c too]
Signed-off-by: Wenkai Du <wenkai.du@intel.com>
Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/intel/sst-baytrail-ipc.c | 8 | ||||
-rw-r--r-- | sound/soc/intel/sst-haswell-ipc.c | 8 |
2 files changed, 16 insertions, 0 deletions
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index d0eaeee21be4..0d31dbbf4806 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c | |||
@@ -542,16 +542,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, | |||
542 | void *data) | 542 | void *data) |
543 | { | 543 | { |
544 | struct sst_byt_stream *stream; | 544 | struct sst_byt_stream *stream; |
545 | struct sst_dsp *sst = byt->dsp; | ||
546 | unsigned long flags; | ||
545 | 547 | ||
546 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | 548 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
547 | if (stream == NULL) | 549 | if (stream == NULL) |
548 | return NULL; | 550 | return NULL; |
549 | 551 | ||
552 | spin_lock_irqsave(&sst->spinlock, flags); | ||
550 | list_add(&stream->node, &byt->stream_list); | 553 | list_add(&stream->node, &byt->stream_list); |
551 | stream->notify_position = notify_position; | 554 | stream->notify_position = notify_position; |
552 | stream->pdata = data; | 555 | stream->pdata = data; |
553 | stream->byt = byt; | 556 | stream->byt = byt; |
554 | stream->str_id = id; | 557 | stream->str_id = id; |
558 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
555 | 559 | ||
556 | return stream; | 560 | return stream; |
557 | } | 561 | } |
@@ -630,6 +634,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) | |||
630 | { | 634 | { |
631 | u64 header; | 635 | u64 header; |
632 | int ret = 0; | 636 | int ret = 0; |
637 | struct sst_dsp *sst = byt->dsp; | ||
638 | unsigned long flags; | ||
633 | 639 | ||
634 | if (!stream->commited) | 640 | if (!stream->commited) |
635 | goto out; | 641 | goto out; |
@@ -644,8 +650,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) | |||
644 | 650 | ||
645 | stream->commited = false; | 651 | stream->commited = false; |
646 | out: | 652 | out: |
653 | spin_lock_irqsave(&sst->spinlock, flags); | ||
647 | list_del(&stream->node); | 654 | list_del(&stream->node); |
648 | kfree(stream); | 655 | kfree(stream); |
656 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
649 | 657 | ||
650 | return ret; | 658 | return ret; |
651 | } | 659 | } |
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 50e4246d4b57..6c0b4f247a86 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
@@ -1159,11 +1159,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | |||
1159 | void *data) | 1159 | void *data) |
1160 | { | 1160 | { |
1161 | struct sst_hsw_stream *stream; | 1161 | struct sst_hsw_stream *stream; |
1162 | struct sst_dsp *sst = hsw->dsp; | ||
1163 | unsigned long flags; | ||
1162 | 1164 | ||
1163 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | 1165 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
1164 | if (stream == NULL) | 1166 | if (stream == NULL) |
1165 | return NULL; | 1167 | return NULL; |
1166 | 1168 | ||
1169 | spin_lock_irqsave(&sst->spinlock, flags); | ||
1167 | list_add(&stream->node, &hsw->stream_list); | 1170 | list_add(&stream->node, &hsw->stream_list); |
1168 | stream->notify_position = notify_position; | 1171 | stream->notify_position = notify_position; |
1169 | stream->pdata = data; | 1172 | stream->pdata = data; |
@@ -1172,6 +1175,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | |||
1172 | 1175 | ||
1173 | /* work to process notification messages */ | 1176 | /* work to process notification messages */ |
1174 | INIT_WORK(&stream->notify_work, hsw_notification_work); | 1177 | INIT_WORK(&stream->notify_work, hsw_notification_work); |
1178 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
1175 | 1179 | ||
1176 | return stream; | 1180 | return stream; |
1177 | } | 1181 | } |
@@ -1180,6 +1184,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1180 | { | 1184 | { |
1181 | u32 header; | 1185 | u32 header; |
1182 | int ret = 0; | 1186 | int ret = 0; |
1187 | struct sst_dsp *sst = hsw->dsp; | ||
1188 | unsigned long flags; | ||
1183 | 1189 | ||
1184 | /* dont free DSP streams that are not commited */ | 1190 | /* dont free DSP streams that are not commited */ |
1185 | if (!stream->commited) | 1191 | if (!stream->commited) |
@@ -1201,8 +1207,10 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1201 | trace_hsw_stream_free_req(stream, &stream->free_req); | 1207 | trace_hsw_stream_free_req(stream, &stream->free_req); |
1202 | 1208 | ||
1203 | out: | 1209 | out: |
1210 | spin_lock_irqsave(&sst->spinlock, flags); | ||
1204 | list_del(&stream->node); | 1211 | list_del(&stream->node); |
1205 | kfree(stream); | 1212 | kfree(stream); |
1213 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
1206 | 1214 | ||
1207 | return ret; | 1215 | return ret; |
1208 | } | 1216 | } |