aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-10-12 09:07:34 -0400
committerTakashi Iwai <tiwai@suse.de>2012-10-30 06:06:48 -0400
commit9b0573c07f278e9888c352aa9724035c75784ea0 (patch)
treea5729ddd409994d5912ba71b372169e3fa7f879d /sound
parent1693849f71b818be9e6e2b6e6fbcb45f6f518f96 (diff)
ALSA: PCM: Fix some races at disconnection
Fix races at PCM disconnection: - while a PCM device is being opened or closed - while the PCM state is being changed without lock in prepare, hw_params, hw_free ops Reported-by: Matthieu CASTET <matthieu.castet@parrot.com> Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/core/pcm.c7
-rw-r--r--sound/core/pcm_native.c16
2 files changed, 18 insertions, 5 deletions
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index f2991940b271..993b2405fdfe 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -1086,11 +1086,15 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
1086 if (list_empty(&pcm->list)) 1086 if (list_empty(&pcm->list))
1087 goto unlock; 1087 goto unlock;
1088 1088
1089 mutex_lock(&pcm->open_mutex);
1089 list_del_init(&pcm->list); 1090 list_del_init(&pcm->list);
1090 for (cidx = 0; cidx < 2; cidx++) 1091 for (cidx = 0; cidx < 2; cidx++)
1091 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) 1092 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
1093 snd_pcm_stream_lock_irq(substream);
1092 if (substream->runtime) 1094 if (substream->runtime)
1093 substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; 1095 substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
1096 snd_pcm_stream_unlock_irq(substream);
1097 }
1094 list_for_each_entry(notify, &snd_pcm_notify_list, list) { 1098 list_for_each_entry(notify, &snd_pcm_notify_list, list) {
1095 notify->n_disconnect(pcm); 1099 notify->n_disconnect(pcm);
1096 } 1100 }
@@ -1110,6 +1114,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
1110 pcm->streams[cidx].chmap_kctl = NULL; 1114 pcm->streams[cidx].chmap_kctl = NULL;
1111 } 1115 }
1112 } 1116 }
1117 mutex_unlock(&pcm->open_mutex);
1113 unlock: 1118 unlock:
1114 mutex_unlock(&register_mutex); 1119 mutex_unlock(&register_mutex);
1115 return 0; 1120 return 0;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 5e12e5bacbba..8753c89f3290 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -369,6 +369,14 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
369 return usecs; 369 return usecs;
370} 370}
371 371
372static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
373{
374 snd_pcm_stream_lock_irq(substream);
375 if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED)
376 substream->runtime->status->state = state;
377 snd_pcm_stream_unlock_irq(substream);
378}
379
372static int snd_pcm_hw_params(struct snd_pcm_substream *substream, 380static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
373 struct snd_pcm_hw_params *params) 381 struct snd_pcm_hw_params *params)
374{ 382{
@@ -452,7 +460,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
452 runtime->boundary *= 2; 460 runtime->boundary *= 2;
453 461
454 snd_pcm_timer_resolution_change(substream); 462 snd_pcm_timer_resolution_change(substream);
455 runtime->status->state = SNDRV_PCM_STATE_SETUP; 463 snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
456 464
457 if (pm_qos_request_active(&substream->latency_pm_qos_req)) 465 if (pm_qos_request_active(&substream->latency_pm_qos_req))
458 pm_qos_remove_request(&substream->latency_pm_qos_req); 466 pm_qos_remove_request(&substream->latency_pm_qos_req);
@@ -464,7 +472,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
464 /* hardware might be unusable from this time, 472 /* hardware might be unusable from this time,
465 so we force application to retry to set 473 so we force application to retry to set
466 the correct hardware parameter settings */ 474 the correct hardware parameter settings */
467 runtime->status->state = SNDRV_PCM_STATE_OPEN; 475 snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
468 if (substream->ops->hw_free != NULL) 476 if (substream->ops->hw_free != NULL)
469 substream->ops->hw_free(substream); 477 substream->ops->hw_free(substream);
470 return err; 478 return err;
@@ -512,7 +520,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
512 return -EBADFD; 520 return -EBADFD;
513 if (substream->ops->hw_free) 521 if (substream->ops->hw_free)
514 result = substream->ops->hw_free(substream); 522 result = substream->ops->hw_free(substream);
515 runtime->status->state = SNDRV_PCM_STATE_OPEN; 523 snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
516 pm_qos_remove_request(&substream->latency_pm_qos_req); 524 pm_qos_remove_request(&substream->latency_pm_qos_req);
517 return result; 525 return result;
518} 526}
@@ -1320,7 +1328,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state)
1320{ 1328{
1321 struct snd_pcm_runtime *runtime = substream->runtime; 1329 struct snd_pcm_runtime *runtime = substream->runtime;
1322 runtime->control->appl_ptr = runtime->status->hw_ptr; 1330 runtime->control->appl_ptr = runtime->status->hw_ptr;
1323 runtime->status->state = SNDRV_PCM_STATE_PREPARED; 1331 snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
1324} 1332}
1325 1333
1326static struct action_ops snd_pcm_action_prepare = { 1334static struct action_ops snd_pcm_action_prepare = {