[alsa-devel] another locking issue with nonatomic ops?

Ramesh Babu Ramesh.Babu at intel.com
Thu Feb 18 11:28:22 CET 2016


On Wed, Feb 17, 2016 at 02:48:39PM +0100, Takashi Iwai wrote:
> On Wed, 17 Feb 2016 13:41:10 +0100,
> Babu, Ramesh wrote:
> > 
> > I verified the fix and I confirm that it resolved the race 
> > condition issue.
> 
> Good to hear.  Could you try the revised patch below?
> If it still works, give your tested-by tag, so that I can merge to
> upstream.

Yes, patch works well.
Added Tested-by tag in below patch.

> 
> 
> Takashi
> 
> ---
> From: Takashi Iwai <tiwai at suse.de>
> Subject: [PATCH] ALSA: pcm: Fix rwsem deadlock for non-atomic PCM stream
> 
> A non-atomic PCM stream may take snd_pcm_link_rwsem rw semaphore twice
> in the same code path, e.g. one in snd_pcm_action_nonatomic() and
> another in snd_pcm_stream_lock().  Usually this is OK, but when a
> write lock is issued between these two read locks, the problem
> happens: the write lock is blocked due to the first reade lock, and
> the second read lock is also blocked by the write lock.  This
> eventually deadlocks.
> 
> The reason is the way rwsem manages waiters; it's queued like FIFO, so
> even if the writer itself doesn't take the lock yet, it blocks all the
> waiters (including reads) queued after it.
> 
> As a workaround, in this patch, we replace the standard down_write()
> with an spinning loop.  This is far from optimal, but it's good
> enough, as the spinning time is supposed to be relatively short for
> normal PCM operations, and the code paths requiring the write lock
> aren't called so often.
> 
> Reported-by: Vinod Koul <vinod.koul at intel.com>
Tested-by: Ramesh Babu <ramesh.babu at intel.com>
> Cc: <stable at vger.kernel.org> # v3.18+
> Signed-off-by: Takashi Iwai <tiwai at suse.de>
> ---
>  sound/core/pcm_native.c | 16 ++++++++++++++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index fadd3eb8e8bb..9106d8e2300e 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -74,6 +74,18 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
>  static DEFINE_RWLOCK(snd_pcm_link_rwlock);
>  static DECLARE_RWSEM(snd_pcm_link_rwsem);
>  
> +/* Writer in rwsem may block readers even during its waiting in queue,
> + * and this may lead to a deadlock when the code path takes read sem
> + * twice (e.g. one in snd_pcm_action_nonatomic() and another in
> + * snd_pcm_stream_lock()).  As a (suboptimal) workaround, let writer to
> + * spin until it gets the lock.
> + */
> +static inline void down_write_nonblock(struct rw_semaphore *lock)
> +{
> +	while (!down_write_trylock(lock))
> +		cond_resched();
> +}
> +
>  /**
>   * snd_pcm_stream_lock - Lock the PCM stream
>   * @substream: PCM substream
> @@ -1813,7 +1825,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
>  		res = -ENOMEM;
>  		goto _nolock;
>  	}
> -	down_write(&snd_pcm_link_rwsem);
> +	down_write_nonblock(&snd_pcm_link_rwsem);
>  	write_lock_irq(&snd_pcm_link_rwlock);
>  	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
>  	    substream->runtime->status->state != substream1->runtime->status->state ||
> @@ -1860,7 +1872,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
>  	struct snd_pcm_substream *s;
>  	int res = 0;
>  
> -	down_write(&snd_pcm_link_rwsem);
> +	down_write_nonblock(&snd_pcm_link_rwsem);
>  	write_lock_irq(&snd_pcm_link_rwlock);
>  	if (!snd_pcm_stream_linked(substream)) {
>  		res = -EALREADY;
> -- 
> 2.7.1
> 

-- 


More information about the Alsa-devel mailing list