Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 901d46d5 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: pcm - Fix race with proc files



The PCM proc files may open a race against substream close, which can
end up with an Oops.  Use the open_mutex to protect for it.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 8699a0b6
Loading
Loading
Loading
Loading
+24 −9
Original line number Original line Diff line number Diff line
@@ -372,14 +372,17 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
						  struct snd_info_buffer *buffer)
						  struct snd_info_buffer *buffer)
{
{
	struct snd_pcm_substream *substream = entry->private_data;
	struct snd_pcm_substream *substream = entry->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_pcm_runtime *runtime;

	mutex_lock(&substream->pcm->open_mutex);
	runtime = substream->runtime;
	if (!runtime) {
	if (!runtime) {
		snd_iprintf(buffer, "closed\n");
		snd_iprintf(buffer, "closed\n");
		return;
		goto unlock;
	}
	}
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
		snd_iprintf(buffer, "no setup\n");
		snd_iprintf(buffer, "no setup\n");
		return;
		goto unlock;
	}
	}
	snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
	snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
	snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
	snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
@@ -398,20 +401,25 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
		snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
		snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
	}
	}
#endif
#endif
 unlock:
	mutex_unlock(&substream->pcm->open_mutex);
}
}


static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
						  struct snd_info_buffer *buffer)
						  struct snd_info_buffer *buffer)
{
{
	struct snd_pcm_substream *substream = entry->private_data;
	struct snd_pcm_substream *substream = entry->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_pcm_runtime *runtime;

	mutex_lock(&substream->pcm->open_mutex);
	runtime = substream->runtime;
	if (!runtime) {
	if (!runtime) {
		snd_iprintf(buffer, "closed\n");
		snd_iprintf(buffer, "closed\n");
		return;
		goto unlock;
	}
	}
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
		snd_iprintf(buffer, "no setup\n");
		snd_iprintf(buffer, "no setup\n");
		return;
		goto unlock;
	}
	}
	snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
	snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
	snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
	snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
@@ -421,24 +429,29 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
	snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
	snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
	snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
	snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
	snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
	snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
 unlock:
	mutex_unlock(&substream->pcm->open_mutex);
}
}


static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
					       struct snd_info_buffer *buffer)
					       struct snd_info_buffer *buffer)
{
{
	struct snd_pcm_substream *substream = entry->private_data;
	struct snd_pcm_substream *substream = entry->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_pcm_runtime *runtime;
	struct snd_pcm_status status;
	struct snd_pcm_status status;
	int err;
	int err;

	mutex_lock(&substream->pcm->open_mutex);
	runtime = substream->runtime;
	if (!runtime) {
	if (!runtime) {
		snd_iprintf(buffer, "closed\n");
		snd_iprintf(buffer, "closed\n");
		return;
		goto unlock;
	}
	}
	memset(&status, 0, sizeof(status));
	memset(&status, 0, sizeof(status));
	err = snd_pcm_status(substream, &status);
	err = snd_pcm_status(substream, &status);
	if (err < 0) {
	if (err < 0) {
		snd_iprintf(buffer, "error %d\n", err);
		snd_iprintf(buffer, "error %d\n", err);
		return;
		goto unlock;
	}
	}
	snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
	snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
	snd_iprintf(buffer, "owner_pid   : %d\n", pid_vnr(substream->pid));
	snd_iprintf(buffer, "owner_pid   : %d\n", pid_vnr(substream->pid));
@@ -452,6 +465,8 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
	snd_iprintf(buffer, "-----\n");
	snd_iprintf(buffer, "-----\n");
	snd_iprintf(buffer, "hw_ptr      : %ld\n", runtime->status->hw_ptr);
	snd_iprintf(buffer, "hw_ptr      : %ld\n", runtime->status->hw_ptr);
	snd_iprintf(buffer, "appl_ptr    : %ld\n", runtime->control->appl_ptr);
	snd_iprintf(buffer, "appl_ptr    : %ld\n", runtime->control->appl_ptr);
 unlock:
	mutex_unlock(&substream->pcm->open_mutex);
}
}


#ifdef CONFIG_SND_PCM_XRUN_DEBUG
#ifdef CONFIG_SND_PCM_XRUN_DEBUG