1

ALSA: pcm: Use guard() for PCM stream locks

Define guard() usage for PCM stream locking and use it in appropriate
places.

The pair of snd_pcm_stream_lock() and snd_pcm_stream_unlock() can be
presented with guard(pcm_stream_lock) now.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20240227085306.9764-23-tiwai@suse.de
This commit is contained in:
Takashi Iwai 2024-02-27 09:53:04 +01:00
parent dd0da75b9a
commit 650224fe8d
5 changed files with 191 additions and 218 deletions

View File

@ -659,6 +659,18 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
flags = _snd_pcm_stream_lock_irqsave_nested(substream); \ flags = _snd_pcm_stream_lock_irqsave_nested(substream); \
} while (0) } while (0)
/* definitions for guard(); use like guard(pcm_stream_lock) */
DEFINE_LOCK_GUARD_1(pcm_stream_lock, struct snd_pcm_substream,
snd_pcm_stream_lock(_T->lock),
snd_pcm_stream_unlock(_T->lock))
DEFINE_LOCK_GUARD_1(pcm_stream_lock_irq, struct snd_pcm_substream,
snd_pcm_stream_lock_irq(_T->lock),
snd_pcm_stream_unlock_irq(_T->lock))
DEFINE_LOCK_GUARD_1(pcm_stream_lock_irqsave, struct snd_pcm_substream,
snd_pcm_stream_lock_irqsave(_T->lock, _T->flags),
snd_pcm_stream_unlock_irqrestore(_T->lock, _T->flags),
unsigned long flags)
/** /**
* snd_pcm_group_for_each_entry - iterate over the linked substreams * snd_pcm_group_for_each_entry - iterate over the linked substreams
* @s: the iterator * @s: the iterator

View File

@ -1623,9 +1623,8 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
break; break;
result = 0; result = 0;
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream)
state = runtime->state; state = runtime->state;
snd_pcm_stream_unlock_irq(substream);
if (state != SNDRV_PCM_STATE_RUNNING) { if (state != SNDRV_PCM_STATE_RUNNING) {
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
break; break;
@ -2840,23 +2839,23 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
if (psubstream != NULL) { if (psubstream != NULL) {
struct snd_pcm_runtime *runtime = psubstream->runtime; struct snd_pcm_runtime *runtime = psubstream->runtime;
poll_wait(file, &runtime->sleep, wait); poll_wait(file, &runtime->sleep, wait);
snd_pcm_stream_lock_irq(psubstream); scoped_guard(pcm_stream_lock_irq, psubstream) {
if (runtime->state != SNDRV_PCM_STATE_DRAINING && if (runtime->state != SNDRV_PCM_STATE_DRAINING &&
(runtime->state != SNDRV_PCM_STATE_RUNNING || (runtime->state != SNDRV_PCM_STATE_RUNNING ||
snd_pcm_oss_playback_ready(psubstream))) snd_pcm_oss_playback_ready(psubstream)))
mask |= EPOLLOUT | EPOLLWRNORM; mask |= EPOLLOUT | EPOLLWRNORM;
snd_pcm_stream_unlock_irq(psubstream); }
} }
if (csubstream != NULL) { if (csubstream != NULL) {
struct snd_pcm_runtime *runtime = csubstream->runtime; struct snd_pcm_runtime *runtime = csubstream->runtime;
snd_pcm_state_t ostate; snd_pcm_state_t ostate;
poll_wait(file, &runtime->sleep, wait); poll_wait(file, &runtime->sleep, wait);
snd_pcm_stream_lock_irq(csubstream); scoped_guard(pcm_stream_lock_irq, csubstream) {
ostate = runtime->state; ostate = runtime->state;
if (ostate != SNDRV_PCM_STATE_RUNNING || if (ostate != SNDRV_PCM_STATE_RUNNING ||
snd_pcm_oss_capture_ready(csubstream)) snd_pcm_oss_capture_ready(csubstream))
mask |= EPOLLIN | EPOLLRDNORM; mask |= EPOLLIN | EPOLLRDNORM;
snd_pcm_stream_unlock_irq(csubstream); }
if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) { if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
struct snd_pcm_oss_file ofile; struct snd_pcm_oss_file ofile;
memset(&ofile, 0, sizeof(ofile)); memset(&ofile, 0, sizeof(ofile));

View File

@ -432,22 +432,22 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
boundary = recalculate_boundary(runtime); boundary = recalculate_boundary(runtime);
if (!boundary) if (!boundary)
boundary = 0x7fffffff; boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
/* FIXME: we should consider the boundary for the sync from app */ /* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
control->appl_ptr = scontrol.appl_ptr; control->appl_ptr = scontrol.appl_ptr;
else else
scontrol.appl_ptr = control->appl_ptr % boundary; scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min; control->avail_min = scontrol.avail_min;
else else
scontrol.avail_min = control->avail_min; scontrol.avail_min = control->avail_min;
sstatus.state = status->state; sstatus.state = status->state;
sstatus.hw_ptr = status->hw_ptr % boundary; sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp; sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state; sstatus.suspended_state = status->suspended_state;
sstatus.audio_tstamp = status->audio_tstamp; sstatus.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream); }
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (put_user(sstatus.state, &src->s.status.state) || if (put_user(sstatus.state, &src->s.status.state) ||
@ -510,26 +510,24 @@ static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream,
if (err < 0) if (err < 0)
return err; return err;
} }
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr); err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
if (err < 0) { if (err < 0)
snd_pcm_stream_unlock_irq(substream); return err;
return err; } else {
sync_cp->appl_ptr = control->appl_ptr;
} }
} else { if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
sync_cp->appl_ptr = control->appl_ptr; control->avail_min = sync_cp->avail_min;
else
sync_cp->avail_min = control->avail_min;
sync_ptr.s.status.state = status->state;
sync_ptr.s.status.hw_ptr = status->hw_ptr;
sync_ptr.s.status.tstamp = status->tstamp;
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
} }
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = sync_cp->avail_min;
else
sync_cp->avail_min = control->avail_min;
sync_ptr.s.status.state = status->state;
sync_ptr.s.status.hw_ptr = status->hw_ptr;
sync_ptr.s.status.tstamp = status->tstamp;
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))

View File

@ -1744,8 +1744,8 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
void *arg) void *arg)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long flags;
snd_pcm_stream_lock_irqsave(substream, flags); guard(pcm_stream_lock_irqsave)(substream);
if (snd_pcm_running(substream) && if (snd_pcm_running(substream) &&
snd_pcm_update_hw_ptr(substream) >= 0) snd_pcm_update_hw_ptr(substream) >= 0)
runtime->status->hw_ptr %= runtime->buffer_size; runtime->status->hw_ptr %= runtime->buffer_size;
@ -1753,7 +1753,6 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
runtime->status->hw_ptr = 0; runtime->status->hw_ptr = 0;
runtime->hw_ptr_wrap = 0; runtime->hw_ptr_wrap = 0;
} }
snd_pcm_stream_unlock_irqrestore(substream, flags);
return 0; return 0;
} }
@ -1899,14 +1898,11 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock);
*/ */
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
{ {
unsigned long flags;
if (snd_BUG_ON(!substream)) if (snd_BUG_ON(!substream))
return; return;
snd_pcm_stream_lock_irqsave(substream, flags); guard(pcm_stream_lock_irqsave)(substream);
snd_pcm_period_elapsed_under_stream_lock(substream); snd_pcm_period_elapsed_under_stream_lock(substream);
snd_pcm_stream_unlock_irqrestore(substream, flags);
} }
EXPORT_SYMBOL(snd_pcm_period_elapsed); EXPORT_SYMBOL(snd_pcm_period_elapsed);

View File

@ -604,10 +604,9 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
static void snd_pcm_set_state(struct snd_pcm_substream *substream, static void snd_pcm_set_state(struct snd_pcm_substream *substream,
snd_pcm_state_t state) snd_pcm_state_t state)
{ {
snd_pcm_stream_lock_irq(substream); guard(pcm_stream_lock_irq)(substream);
if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED) if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED)
__snd_pcm_set_state(substream->runtime, state); __snd_pcm_set_state(substream->runtime, state);
snd_pcm_stream_unlock_irq(substream);
} }
static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream, static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
@ -733,20 +732,20 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
err = snd_pcm_buffer_access_lock(runtime); err = snd_pcm_buffer_access_lock(runtime);
if (err < 0) if (err < 0)
return err; return err;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
switch (runtime->state) { switch (runtime->state) {
case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_OPEN:
case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_SETUP:
case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PREPARED:
if (!is_oss_stream(substream) && if (!is_oss_stream(substream) &&
atomic_read(&substream->mmap_count)) atomic_read(&substream->mmap_count))
err = -EBADFD;
break;
default:
err = -EBADFD; err = -EBADFD;
break; break;
default: }
err = -EBADFD;
break;
} }
snd_pcm_stream_unlock_irq(substream);
if (err) if (err)
goto unlock; goto unlock;
@ -896,18 +895,18 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
result = snd_pcm_buffer_access_lock(runtime); result = snd_pcm_buffer_access_lock(runtime);
if (result < 0) if (result < 0)
return result; return result;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
switch (runtime->state) { switch (runtime->state) {
case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_SETUP:
case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PREPARED:
if (atomic_read(&substream->mmap_count)) if (atomic_read(&substream->mmap_count))
result = -EBADFD;
break;
default:
result = -EBADFD; result = -EBADFD;
break; break;
default: }
result = -EBADFD;
break;
} }
snd_pcm_stream_unlock_irq(substream);
if (result) if (result)
goto unlock; goto unlock;
result = do_hw_free(substream); result = do_hw_free(substream);
@ -927,12 +926,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
if (PCM_RUNTIME_CHECK(substream)) if (PCM_RUNTIME_CHECK(substream))
return -ENXIO; return -ENXIO;
runtime = substream->runtime; runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
if (runtime->state == SNDRV_PCM_STATE_OPEN) { if (runtime->state == SNDRV_PCM_STATE_OPEN)
snd_pcm_stream_unlock_irq(substream); return -EBADFD;
return -EBADFD;
} }
snd_pcm_stream_unlock_irq(substream);
if (params->tstamp_mode < 0 || if (params->tstamp_mode < 0 ||
params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST) params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
@ -952,24 +949,24 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
err = 0; err = 0;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
runtime->tstamp_mode = params->tstamp_mode; runtime->tstamp_mode = params->tstamp_mode;
if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12)) if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
runtime->tstamp_type = params->tstamp_type; runtime->tstamp_type = params->tstamp_type;
runtime->period_step = params->period_step; runtime->period_step = params->period_step;
runtime->control->avail_min = params->avail_min; runtime->control->avail_min = params->avail_min;
runtime->start_threshold = params->start_threshold; runtime->start_threshold = params->start_threshold;
runtime->stop_threshold = params->stop_threshold; runtime->stop_threshold = params->stop_threshold;
runtime->silence_threshold = params->silence_threshold; runtime->silence_threshold = params->silence_threshold;
runtime->silence_size = params->silence_size; runtime->silence_size = params->silence_size;
params->boundary = runtime->boundary; params->boundary = runtime->boundary;
if (snd_pcm_running(substream)) { if (snd_pcm_running(substream)) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0) runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX); snd_pcm_playback_silence(substream, ULONG_MAX);
err = snd_pcm_update_state(substream, runtime); err = snd_pcm_update_state(substream, runtime);
}
} }
snd_pcm_stream_unlock_irq(substream);
return err; return err;
} }
@ -1003,7 +1000,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream); guard(pcm_stream_lock_irq)(substream);
snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data, snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
&runtime->audio_tstamp_config); &runtime->audio_tstamp_config);
@ -1024,7 +1021,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
status->state = runtime->state; status->state = runtime->state;
status->suspended_state = runtime->suspended_state; status->suspended_state = runtime->suspended_state;
if (status->state == SNDRV_PCM_STATE_OPEN) if (status->state == SNDRV_PCM_STATE_OPEN)
goto _end; return 0;
status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec; status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec;
status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec; status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec;
if (snd_pcm_running(substream)) { if (snd_pcm_running(substream)) {
@ -1069,8 +1066,6 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
status->overrange = runtime->overrange; status->overrange = runtime->overrange;
runtime->avail_max = 0; runtime->avail_max = 0;
runtime->overrange = 0; runtime->overrange = 0;
_end:
snd_pcm_stream_unlock_irq(substream);
return 0; return 0;
} }
@ -1155,12 +1150,10 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
channel = info->channel; channel = info->channel;
runtime = substream->runtime; runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
if (runtime->state == SNDRV_PCM_STATE_OPEN) { if (runtime->state == SNDRV_PCM_STATE_OPEN)
snd_pcm_stream_unlock_irq(substream); return -EBADFD;
return -EBADFD;
} }
snd_pcm_stream_unlock_irq(substream);
if (channel >= runtime->channels) if (channel >= runtime->channels)
return -EINVAL; return -EINVAL;
memset(info, 0, sizeof(*info)); memset(info, 0, sizeof(*info));
@ -1381,12 +1374,8 @@ static int snd_pcm_action_lock_irq(const struct action_ops *ops,
struct snd_pcm_substream *substream, struct snd_pcm_substream *substream,
snd_pcm_state_t state) snd_pcm_state_t state)
{ {
int res; guard(pcm_stream_lock_irq)(substream);
return snd_pcm_action(ops, substream, state);
snd_pcm_stream_lock_irq(substream);
res = snd_pcm_action(ops, substream, state);
snd_pcm_stream_unlock_irq(substream);
return res;
} }
/* /*
@ -1576,12 +1565,9 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream)
*/ */
int snd_pcm_stop_xrun(struct snd_pcm_substream *substream) int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
{ {
unsigned long flags; guard(pcm_stream_lock_irqsave)(substream);
snd_pcm_stream_lock_irqsave(substream, flags);
if (substream->runtime && snd_pcm_running(substream)) if (substream->runtime && snd_pcm_running(substream))
__snd_pcm_xrun(substream); __snd_pcm_xrun(substream);
snd_pcm_stream_unlock_irqrestore(substream, flags);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun); EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
@ -1733,14 +1719,9 @@ static const struct action_ops snd_pcm_action_suspend = {
*/ */
static int snd_pcm_suspend(struct snd_pcm_substream *substream) static int snd_pcm_suspend(struct snd_pcm_substream *substream)
{ {
int err; guard(pcm_stream_lock_irqsave)(substream);
unsigned long flags; return snd_pcm_action(&snd_pcm_action_suspend, substream,
ACTION_ARG_IGNORE);
snd_pcm_stream_lock_irqsave(substream, flags);
err = snd_pcm_action(&snd_pcm_action_suspend, substream,
ACTION_ARG_IGNORE);
snd_pcm_stream_unlock_irqrestore(substream, flags);
return err;
} }
/** /**
@ -1856,22 +1837,17 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream)
static int snd_pcm_xrun(struct snd_pcm_substream *substream) static int snd_pcm_xrun(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
int result;
snd_pcm_stream_lock_irq(substream); guard(pcm_stream_lock_irq)(substream);
switch (runtime->state) { switch (runtime->state) {
case SNDRV_PCM_STATE_XRUN: case SNDRV_PCM_STATE_XRUN:
result = 0; /* already there */ return 0; /* already there */
break;
case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_RUNNING:
__snd_pcm_xrun(substream); __snd_pcm_xrun(substream);
result = 0; return 0;
break;
default: default:
result = -EBADFD; return -EBADFD;
} }
snd_pcm_stream_unlock_irq(substream);
return result;
} }
/* /*
@ -1900,13 +1876,12 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream,
int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
if (err < 0) if (err < 0)
return err; return err;
snd_pcm_stream_lock_irq(substream); guard(pcm_stream_lock_irq)(substream);
runtime->hw_ptr_base = 0; runtime->hw_ptr_base = 0;
runtime->hw_ptr_interrupt = runtime->status->hw_ptr - runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
runtime->status->hw_ptr % runtime->period_size; runtime->status->hw_ptr % runtime->period_size;
runtime->silence_start = runtime->status->hw_ptr; runtime->silence_start = runtime->status->hw_ptr;
runtime->silence_filled = 0; runtime->silence_filled = 0;
snd_pcm_stream_unlock_irq(substream);
return 0; return 0;
} }
@ -1914,12 +1889,11 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream,
snd_pcm_state_t state) snd_pcm_state_t state)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream); guard(pcm_stream_lock_irq)(substream);
runtime->control->appl_ptr = runtime->status->hw_ptr; runtime->control->appl_ptr = runtime->status->hw_ptr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0) runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX); snd_pcm_playback_silence(substream, ULONG_MAX);
snd_pcm_stream_unlock_irq(substream);
} }
static const struct action_ops snd_pcm_action_reset = { static const struct action_ops snd_pcm_action_reset = {
@ -1995,16 +1969,16 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
else else
f_flags = substream->f_flags; f_flags = substream->f_flags;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
switch (substream->runtime->state) { switch (substream->runtime->state) {
case SNDRV_PCM_STATE_PAUSED: case SNDRV_PCM_STATE_PAUSED:
snd_pcm_pause(substream, false); snd_pcm_pause(substream, false);
fallthrough; fallthrough;
case SNDRV_PCM_STATE_SUSPENDED: case SNDRV_PCM_STATE_SUSPENDED:
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
break; break;
}
} }
snd_pcm_stream_unlock_irq(substream);
return snd_pcm_action_nonatomic(&snd_pcm_action_prepare, return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
substream, substream,
@ -2221,14 +2195,13 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
runtime->state == SNDRV_PCM_STATE_DISCONNECTED) runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD; return -EBADFD;
snd_pcm_stream_lock_irq(substream); guard(pcm_stream_lock_irq)(substream);
/* resume pause */ /* resume pause */
if (runtime->state == SNDRV_PCM_STATE_PAUSED) if (runtime->state == SNDRV_PCM_STATE_PAUSED)
snd_pcm_pause(substream, false); snd_pcm_pause(substream, false);
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
/* runtime->control->appl_ptr = runtime->status->hw_ptr; */ /* runtime->control->appl_ptr = runtime->status->hw_ptr; */
snd_pcm_stream_unlock_irq(substream);
return result; return result;
} }
@ -2288,13 +2261,13 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
if (snd_pcm_stream_linked(substream1)) if (snd_pcm_stream_linked(substream1))
return -EALREADY; return -EALREADY;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
if (!snd_pcm_stream_linked(substream)) { if (!snd_pcm_stream_linked(substream)) {
snd_pcm_group_assign(substream, group); snd_pcm_group_assign(substream, group);
group = NULL; /* assigned, don't free this one below */ group = NULL; /* assigned, don't free this one below */
}
target_group = substream->group;
} }
target_group = substream->group;
snd_pcm_stream_unlock_irq(substream);
snd_pcm_group_lock_irq(target_group, nonatomic); snd_pcm_group_lock_irq(target_group, nonatomic);
snd_pcm_stream_lock_nested(substream1); snd_pcm_stream_lock_nested(substream1);
@ -3000,12 +2973,12 @@ static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream,
if (frames == 0) if (frames == 0)
return 0; return 0;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
ret = do_pcm_hwsync(substream); ret = do_pcm_hwsync(substream);
if (!ret) if (!ret)
ret = rewind_appl_ptr(substream, frames, ret = rewind_appl_ptr(substream, frames,
snd_pcm_hw_avail(substream)); snd_pcm_hw_avail(substream));
snd_pcm_stream_unlock_irq(substream); }
if (ret >= 0) if (ret >= 0)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
return ret; return ret;
@ -3019,12 +2992,12 @@ static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream,
if (frames == 0) if (frames == 0)
return 0; return 0;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
ret = do_pcm_hwsync(substream); ret = do_pcm_hwsync(substream);
if (!ret) if (!ret)
ret = forward_appl_ptr(substream, frames, ret = forward_appl_ptr(substream, frames,
snd_pcm_avail(substream)); snd_pcm_avail(substream));
snd_pcm_stream_unlock_irq(substream); }
if (ret >= 0) if (ret >= 0)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
return ret; return ret;
@ -3035,11 +3008,11 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
{ {
int err; int err;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
err = do_pcm_hwsync(substream); err = do_pcm_hwsync(substream);
if (delay && !err) if (delay && !err)
*delay = snd_pcm_calc_delay(substream); *delay = snd_pcm_calc_delay(substream);
snd_pcm_stream_unlock_irq(substream); }
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU); snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
return err; return err;
@ -3071,27 +3044,25 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
if (err < 0) if (err < 0)
return err; return err;
} }
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
err = pcm_lib_apply_appl_ptr(substream, err = pcm_lib_apply_appl_ptr(substream,
sync_ptr.c.control.appl_ptr); sync_ptr.c.control.appl_ptr);
if (err < 0) { if (err < 0)
snd_pcm_stream_unlock_irq(substream); return err;
return err; } else {
sync_ptr.c.control.appl_ptr = control->appl_ptr;
} }
} else { if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
sync_ptr.c.control.appl_ptr = control->appl_ptr; control->avail_min = sync_ptr.c.control.avail_min;
else
sync_ptr.c.control.avail_min = control->avail_min;
sync_ptr.s.status.state = status->state;
sync_ptr.s.status.hw_ptr = status->hw_ptr;
sync_ptr.s.status.tstamp = status->tstamp;
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
} }
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = sync_ptr.c.control.avail_min;
else
sync_ptr.c.control.avail_min = control->avail_min;
sync_ptr.s.status.state = status->state;
sync_ptr.s.status.hw_ptr = status->hw_ptr;
sync_ptr.s.status.tstamp = status->tstamp;
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
@ -3169,27 +3140,25 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
boundary = recalculate_boundary(runtime); boundary = recalculate_boundary(runtime);
if (! boundary) if (! boundary)
boundary = 0x7fffffff; boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream); scoped_guard(pcm_stream_lock_irq, substream) {
/* FIXME: we should consider the boundary for the sync from app */ /* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) { if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
err = pcm_lib_apply_appl_ptr(substream, err = pcm_lib_apply_appl_ptr(substream,
scontrol.appl_ptr); scontrol.appl_ptr);
if (err < 0) { if (err < 0)
snd_pcm_stream_unlock_irq(substream); return err;
return err; } else
} scontrol.appl_ptr = control->appl_ptr % boundary;
} else if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
scontrol.appl_ptr = control->appl_ptr % boundary; control->avail_min = scontrol.avail_min;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) else
control->avail_min = scontrol.avail_min; scontrol.avail_min = control->avail_min;
else sstatus.state = status->state;
scontrol.avail_min = control->avail_min; sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.state = status->state; sstatus.tstamp = status->tstamp;
sstatus.hw_ptr = status->hw_ptr % boundary; sstatus.suspended_state = status->suspended_state;
sstatus.tstamp = status->tstamp; sstatus.audio_tstamp = status->audio_tstamp;
sstatus.suspended_state = status->suspended_state; }
sstatus.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (put_user(sstatus.state, &src->s.status.state) || if (put_user(sstatus.state, &src->s.status.state) ||
@ -3628,7 +3597,7 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
poll_wait(file, &runtime->sleep, wait); poll_wait(file, &runtime->sleep, wait);
mask = 0; mask = 0;
snd_pcm_stream_lock_irq(substream); guard(pcm_stream_lock_irq)(substream);
avail = snd_pcm_avail(substream); avail = snd_pcm_avail(substream);
switch (runtime->state) { switch (runtime->state) {
case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_RUNNING:
@ -3648,7 +3617,6 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
mask = ok | EPOLLERR; mask = ok | EPOLLERR;
break; break;
} }
snd_pcm_stream_unlock_irq(substream);
return mask; return mask;
} }