[alsa-devel] [PATCH 0/10] snd_pcm_stop() lock fixes
Takashi Iwai
tiwai at suse.de
Tue Jul 16 16:48:02 CEST 2013
At Mon, 15 Jul 2013 15:17:58 +0200,
Takashi Iwai wrote:
>
> At Mon, 15 Jul 2013 15:12:07 +0200,
> Jaroslav Kysela wrote:
> >
> > Date 15.7.2013 15:06, Takashi Iwai wrote:
> > > Hi,
> > >
> > > while reviewing another patch series, I stumbled on the snd_pcm_lock()
> > > call in an unlocked context. Then I started looking through the whole
> > > tree, and found a bunch of drivers doing it wrong, too. So here is a
> > > patch series to fix them.
> > >
> > > [PATCH 01/10] ALSA: asihpi: Fix unlocked snd_pcm_stop() call
> > > [PATCH 02/10] ALSA: atiixp: Fix unlocked snd_pcm_stop() call
> > > [PATCH 03/10] ALSA: 6fire: Fix unlocked snd_pcm_stop() call
> > > [PATCH 04/10] ALSA: ua101: Fix unlocked snd_pcm_stop() call
> > > [PATCH 05/10] ALSA: usx2y: Fix unlocked snd_pcm_stop() call
> > > [PATCH 06/10] ALSA: pxa2xx: Fix unlocked snd_pcm_stop() call
> > > [PATCH 07/10] ASoC: atmel: Fix unlocked snd_pcm_stop() call
> > > [PATCH 08/10] ASoC: s6000: Fix unlocked snd_pcm_stop() call
> > > [PATCH 09/10] [media] saa7134: Fix unlocked snd_pcm_stop() call
> > > [PATCH 10/10] staging: line6: Fix unlocked snd_pcm_stop() call
> >
> > Probably, it may be better to introduce 'snd_pcm_stop_dolock()' helper
> > (inline?) in include/sound/pcm.h .
>
> Yes, it'll be the next step. These patches are done in open-coded way
> so that they can be applied easily to each stable kernel.
BTW the conversion I thought of is a patch like below.
Takashi
---
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 84b10f9..96eda75 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -502,6 +502,7 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
struct snd_pcm_status *status);
int snd_pcm_start(struct snd_pcm_substream *substream);
int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status);
+int snd_pcm_lock_and_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status);
int snd_pcm_drain_done(struct snd_pcm_substream *substream);
#ifdef CONFIG_PM
int snd_pcm_suspend(struct snd_pcm_substream *substream);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index f928181..56582ac 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -809,9 +809,10 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
struct snd_pcm_substream *substream,
int state)
{
+ unsigned long flags;
int res;
- read_lock_irq(&snd_pcm_link_rwlock);
+ read_lock_irqsave(&snd_pcm_link_rwlock, flags);
if (snd_pcm_stream_linked(substream)) {
spin_lock(&substream->group->lock);
spin_lock(&substream->self_group.lock);
@@ -823,7 +824,7 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
res = snd_pcm_action_single(ops, substream, state);
spin_unlock(&substream->self_group.lock);
}
- read_unlock_irq(&snd_pcm_link_rwlock);
+ read_unlock_irqrestore(&snd_pcm_link_rwlock, flags);
return res;
}
@@ -900,6 +901,8 @@ static struct action_ops snd_pcm_action_start = {
* @substream: the PCM substream instance
*
* Return: Zero if successful, or a negative error code.
+ *
+ * Note that this function must be called in substream lock context.
*/
int snd_pcm_start(struct snd_pcm_substream *substream)
{
@@ -955,6 +958,8 @@ static struct action_ops snd_pcm_action_stop = {
* The state of each stream is then changed to the given state unconditionally.
*
* Return: Zero if succesful, or a negative error code.
+ *
+ * Note that this function must be called in substream lock context.
*/
int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
@@ -964,6 +969,20 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
EXPORT_SYMBOL(snd_pcm_stop);
/**
+ * snd_pcm_lock_and_stop - lock substream and call snd_pcm_stop()
+ * @substream: the PCM substream instance
+ * @state: PCM state after stopping the stream
+ *
+ * Call this function instead of snd_pcm_stop() when need to stop a
+ * PCM stream outside the stream lock context.
+ */
+int snd_pcm_lock_and_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
+{
+ return snd_pcm_action_lock_irq(&snd_pcm_action_stop, substream, state);
+}
+EXPORT_SYMBOL_GPL(snd_pcm_lock_and_stop);
+
+/**
* snd_pcm_drain_done - stop the DMA only when the given stream is playback
* @substream: the PCM substream
*
More information about the Alsa-devel
mailing list