Revert "Revert "ALSA: pcm: Fix potential AB/BA lock with buffer_mutex and mmap_lock""
This reverts commit 990e8bd6d9
.
It is no longer needed as we are able to update the abi at this point in
time.
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: Id685a5c9bca0cd0aa8bcc0d2da6288b9220456c8
This commit is contained in:
parent
f817274eea
commit
6bfa0e0bc8
|
@ -399,6 +399,7 @@ struct snd_pcm_runtime {
|
||||||
struct fasync_struct *fasync;
|
struct fasync_struct *fasync;
|
||||||
bool stop_operating; /* sync_stop will be called */
|
bool stop_operating; /* sync_stop will be called */
|
||||||
struct mutex buffer_mutex; /* protect for buffer changes */
|
struct mutex buffer_mutex; /* protect for buffer changes */
|
||||||
|
atomic_t buffer_accessing; /* >0: in r/w operation, <0: blocked */
|
||||||
|
|
||||||
/* -- private section -- */
|
/* -- private section -- */
|
||||||
void *private_data;
|
void *private_data;
|
||||||
|
|
|
@ -970,6 +970,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
|
||||||
|
|
||||||
runtime->status->state = SNDRV_PCM_STATE_OPEN;
|
runtime->status->state = SNDRV_PCM_STATE_OPEN;
|
||||||
mutex_init(&runtime->buffer_mutex);
|
mutex_init(&runtime->buffer_mutex);
|
||||||
|
atomic_set(&runtime->buffer_accessing, 0);
|
||||||
|
|
||||||
substream->runtime = runtime;
|
substream->runtime = runtime;
|
||||||
substream->private_data = pcm->private_data;
|
substream->private_data = pcm->private_data;
|
||||||
|
|
|
@ -1905,11 +1905,9 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
|
||||||
if (avail >= runtime->twake)
|
if (avail >= runtime->twake)
|
||||||
break;
|
break;
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
snd_pcm_stream_unlock_irq(substream);
|
||||||
mutex_unlock(&runtime->buffer_mutex);
|
|
||||||
|
|
||||||
tout = schedule_timeout(wait_time);
|
tout = schedule_timeout(wait_time);
|
||||||
|
|
||||||
mutex_lock(&runtime->buffer_mutex);
|
|
||||||
snd_pcm_stream_lock_irq(substream);
|
snd_pcm_stream_lock_irq(substream);
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
switch (runtime->status->state) {
|
switch (runtime->status->state) {
|
||||||
|
@ -2203,7 +2201,6 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
|
||||||
|
|
||||||
nonblock = !!(substream->f_flags & O_NONBLOCK);
|
nonblock = !!(substream->f_flags & O_NONBLOCK);
|
||||||
|
|
||||||
mutex_lock(&runtime->buffer_mutex);
|
|
||||||
snd_pcm_stream_lock_irq(substream);
|
snd_pcm_stream_lock_irq(substream);
|
||||||
err = pcm_accessible_state(runtime);
|
err = pcm_accessible_state(runtime);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -2258,10 +2255,15 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto _end_unlock;
|
goto _end_unlock;
|
||||||
}
|
}
|
||||||
|
if (!atomic_inc_unless_negative(&runtime->buffer_accessing)) {
|
||||||
|
err = -EBUSY;
|
||||||
|
goto _end_unlock;
|
||||||
|
}
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
snd_pcm_stream_unlock_irq(substream);
|
||||||
err = writer(substream, appl_ofs, data, offset, frames,
|
err = writer(substream, appl_ofs, data, offset, frames,
|
||||||
transfer);
|
transfer);
|
||||||
snd_pcm_stream_lock_irq(substream);
|
snd_pcm_stream_lock_irq(substream);
|
||||||
|
atomic_dec(&runtime->buffer_accessing);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto _end_unlock;
|
goto _end_unlock;
|
||||||
err = pcm_accessible_state(runtime);
|
err = pcm_accessible_state(runtime);
|
||||||
|
@ -2291,7 +2293,6 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
|
||||||
if (xfer > 0 && err >= 0)
|
if (xfer > 0 && err >= 0)
|
||||||
snd_pcm_update_state(substream, runtime);
|
snd_pcm_update_state(substream, runtime);
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
snd_pcm_stream_unlock_irq(substream);
|
||||||
mutex_unlock(&runtime->buffer_mutex);
|
|
||||||
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
|
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__snd_pcm_lib_xfer);
|
EXPORT_SYMBOL(__snd_pcm_lib_xfer);
|
||||||
|
|
|
@ -672,6 +672,24 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* acquire buffer_mutex; if it's in r/w operation, return -EBUSY, otherwise
|
||||||
|
* block the further r/w operations
|
||||||
|
*/
|
||||||
|
static int snd_pcm_buffer_access_lock(struct snd_pcm_runtime *runtime)
|
||||||
|
{
|
||||||
|
if (!atomic_dec_unless_positive(&runtime->buffer_accessing))
|
||||||
|
return -EBUSY;
|
||||||
|
mutex_lock(&runtime->buffer_mutex);
|
||||||
|
return 0; /* keep buffer_mutex, unlocked by below */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release buffer_mutex and clear r/w access flag */
|
||||||
|
static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime)
|
||||||
|
{
|
||||||
|
mutex_unlock(&runtime->buffer_mutex);
|
||||||
|
atomic_inc(&runtime->buffer_accessing);
|
||||||
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
|
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
|
||||||
#define is_oss_stream(substream) ((substream)->oss.oss)
|
#define is_oss_stream(substream) ((substream)->oss.oss)
|
||||||
#else
|
#else
|
||||||
|
@ -682,14 +700,16 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params *params)
|
struct snd_pcm_hw_params *params)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime;
|
struct snd_pcm_runtime *runtime;
|
||||||
int err = 0, usecs;
|
int err, usecs;
|
||||||
unsigned int bits;
|
unsigned int bits;
|
||||||
snd_pcm_uframes_t frames;
|
snd_pcm_uframes_t frames;
|
||||||
|
|
||||||
if (PCM_RUNTIME_CHECK(substream))
|
if (PCM_RUNTIME_CHECK(substream))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
mutex_lock(&runtime->buffer_mutex);
|
err = snd_pcm_buffer_access_lock(runtime);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
snd_pcm_stream_lock_irq(substream);
|
||||||
switch (runtime->status->state) {
|
switch (runtime->status->state) {
|
||||||
case SNDRV_PCM_STATE_OPEN:
|
case SNDRV_PCM_STATE_OPEN:
|
||||||
|
@ -807,7 +827,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
snd_pcm_lib_free_pages(substream);
|
snd_pcm_lib_free_pages(substream);
|
||||||
}
|
}
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&runtime->buffer_mutex);
|
snd_pcm_buffer_access_unlock(runtime);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -852,7 +872,9 @@ static int snd_pcm_hw_free(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;
|
||||||
mutex_lock(&runtime->buffer_mutex);
|
result = snd_pcm_buffer_access_lock(runtime);
|
||||||
|
if (result < 0)
|
||||||
|
return result;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
snd_pcm_stream_lock_irq(substream);
|
||||||
switch (runtime->status->state) {
|
switch (runtime->status->state) {
|
||||||
case SNDRV_PCM_STATE_SETUP:
|
case SNDRV_PCM_STATE_SETUP:
|
||||||
|
@ -871,7 +893,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||||
snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
|
snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
|
||||||
cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
|
cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&runtime->buffer_mutex);
|
snd_pcm_buffer_access_unlock(runtime);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1356,12 +1378,15 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops,
|
||||||
|
|
||||||
/* Guarantee the group members won't change during non-atomic action */
|
/* Guarantee the group members won't change during non-atomic action */
|
||||||
down_read(&snd_pcm_link_rwsem);
|
down_read(&snd_pcm_link_rwsem);
|
||||||
mutex_lock(&substream->runtime->buffer_mutex);
|
res = snd_pcm_buffer_access_lock(substream->runtime);
|
||||||
|
if (res < 0)
|
||||||
|
goto unlock;
|
||||||
if (snd_pcm_stream_linked(substream))
|
if (snd_pcm_stream_linked(substream))
|
||||||
res = snd_pcm_action_group(ops, substream, state, false);
|
res = snd_pcm_action_group(ops, substream, state, false);
|
||||||
else
|
else
|
||||||
res = snd_pcm_action_single(ops, substream, state);
|
res = snd_pcm_action_single(ops, substream, state);
|
||||||
mutex_unlock(&substream->runtime->buffer_mutex);
|
snd_pcm_buffer_access_unlock(substream->runtime);
|
||||||
|
unlock:
|
||||||
up_read(&snd_pcm_link_rwsem);
|
up_read(&snd_pcm_link_rwsem);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue