linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] ALSA: aloop: Remove redundant locking in timer open function
@ 2019-11-22 17:52 Andrew Gabbasov
  2019-11-22 17:52 ` [PATCH 2/2] ALSA: aloop: Avoid unexpected timer event callback tasklets Andrew Gabbasov
  2019-11-22 18:13 ` [PATCH 1/2] ALSA: aloop: Remove redundant locking in timer open function Takashi Iwai
  0 siblings, 2 replies; 4+ messages in thread
From: Andrew Gabbasov @ 2019-11-22 17:52 UTC (permalink / raw)
  To: alsa-devel, linux-kernel, Jaroslav Kysela, Takashi Iwai,
	Timo Wischer, Andrew Gabbasov

loopback_parse_timer_id() uses snd_card_ref(), that can lock on mutex,
also snd_timer_instance_new() uses non-atomic allocation, that can sleep.
So, both functions can not be called from loopback_snd_timer_open()
with cable->lock spinlock locked.

Moreover, most part of loopback_snd_timer_open() function body works
when the opposite stream of the same cable does not yet exist, and
the current stream is not yet completely open and can't be running,
so existing locking of loopback->cable_lock mutex is enough to protect
from conflicts with simultaneous opening or closing.
Locking of cable->lock spinlock is not needed in this case.

Fixes: 26c53379f98d ("ALSA: aloop: Support selection of snd_timer instead of jiffies")
Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com>
---
 sound/drivers/aloop.c | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 1408403f727a..6408932f5f72 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -1107,20 +1107,18 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm)
 	struct snd_timer_instance *timeri;
 	struct loopback_cable *cable = dpcm->cable;
 
-	spin_lock_irq(&cable->lock);
-
 	/* check if timer was already opened. It is only opened once
 	 * per playback and capture subdevice (aka cable).
 	 */
 	if (cable->snd_timer.instance)
-		goto unlock;
+		goto exit;
 
 	err = loopback_parse_timer_id(dpcm->loopback->timer_source, &tid);
 	if (err < 0) {
 		pcm_err(dpcm->substream->pcm,
 			"Parsing timer source \'%s\' failed with %d",
 			dpcm->loopback->timer_source, err);
-		goto unlock;
+		goto exit;
 	}
 
 	cable->snd_timer.stream = dpcm->substream->stream;
@@ -1129,7 +1127,7 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm)
 	timeri = snd_timer_instance_new(dpcm->loopback->card->id);
 	if (!timeri) {
 		err = -ENOMEM;
-		goto unlock;
+		goto exit;
 	}
 	/* The callback has to be called from another tasklet. If
 	 * SNDRV_TIMER_IFLG_FAST is specified it will be called from the
@@ -1148,10 +1146,9 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm)
 	tasklet_init(&cable->snd_timer.event_tasklet,
 		     loopback_snd_timer_tasklet, (unsigned long)timeri);
 
-	/* snd_timer_close() and snd_timer_open() should not be called with
-	 * locked spinlock because both functions can block on a mutex. The
-	 * mutex loopback->cable_lock is kept locked. Therefore snd_timer_open()
-	 * cannot be called a second time by the other device of the same cable.
+	/* The mutex loopback->cable_lock is kept locked.
+	 * Therefore snd_timer_open() cannot be called a second time
+	 * by the other device of the same cable.
 	 * Therefore the following issue cannot happen:
 	 * [proc1] Call loopback_timer_open() ->
 	 *	   Unlock cable->lock for snd_timer_close/open() call
@@ -1160,9 +1157,7 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm)
 	 * [proc1] Call snd_timer_open() and overwrite running timer
 	 *	   instance
 	 */
-	spin_unlock_irq(&cable->lock);
 	err = snd_timer_open(timeri, &cable->snd_timer.id, current->pid);
-	spin_lock_irq(&cable->lock);
 	if (err < 0) {
 		pcm_err(dpcm->substream->pcm,
 			"snd_timer_open (%d,%d,%d) failed with %d",
@@ -1171,14 +1166,12 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm)
 			cable->snd_timer.id.subdevice,
 			err);
 		snd_timer_instance_free(timeri);
-		goto unlock;
+		goto exit;
 	}
 
 	cable->snd_timer.instance = timeri;
 
-unlock:
-	spin_unlock_irq(&cable->lock);
-
+exit:
 	return err;
 }
 
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] ALSA: aloop: Avoid unexpected timer event callback tasklets
  2019-11-22 17:52 [PATCH 1/2] ALSA: aloop: Remove redundant locking in timer open function Andrew Gabbasov
@ 2019-11-22 17:52 ` Andrew Gabbasov
  2019-11-22 18:14   ` Takashi Iwai
  2019-11-22 18:13 ` [PATCH 1/2] ALSA: aloop: Remove redundant locking in timer open function Takashi Iwai
  1 sibling, 1 reply; 4+ messages in thread
From: Andrew Gabbasov @ 2019-11-22 17:52 UTC (permalink / raw)
  To: alsa-devel, linux-kernel, Jaroslav Kysela, Takashi Iwai,
	Timo Wischer, Andrew Gabbasov

loopback_snd_timer_close_cable() function waits until all
scheduled tasklets are completed, but the timer is closed after that
and can generate more event callbacks, scheduling new tasklets,
that will not be synchronized with cable closing.
Move tasklet_kill() call to be executed after snd_timer_close()
call to avoid such case.

Fixes: 26c53379f98d ("ALSA: aloop: Support selection of snd_timer instead of jiffies")
Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com>
---
 sound/drivers/aloop.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 6408932f5f72..0ebfbe70db00 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -302,15 +302,16 @@ static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
 	if (!cable->snd_timer.instance)
 		return 0;
 
-	/* wait till drain tasklet has finished if requested */
-	tasklet_kill(&cable->snd_timer.event_tasklet);
-
 	/* will only be called from free_cable() when other stream was
 	 * already closed. Other stream cannot be reopened as long as
 	 * loopback->cable_lock is locked. Therefore no need to lock
 	 * cable->lock;
 	 */
 	snd_timer_close(cable->snd_timer.instance);
+
+	/* wait till drain tasklet has finished if requested */
+	tasklet_kill(&cable->snd_timer.event_tasklet);
+
 	snd_timer_instance_free(cable->snd_timer.instance);
 	memset(&cable->snd_timer, 0, sizeof(cable->snd_timer));
 
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] ALSA: aloop: Remove redundant locking in timer open function
  2019-11-22 17:52 [PATCH 1/2] ALSA: aloop: Remove redundant locking in timer open function Andrew Gabbasov
  2019-11-22 17:52 ` [PATCH 2/2] ALSA: aloop: Avoid unexpected timer event callback tasklets Andrew Gabbasov
@ 2019-11-22 18:13 ` Takashi Iwai
  1 sibling, 0 replies; 4+ messages in thread
From: Takashi Iwai @ 2019-11-22 18:13 UTC (permalink / raw)
  To: Andrew Gabbasov
  Cc: alsa-devel, linux-kernel, Jaroslav Kysela, Takashi Iwai, Timo Wischer

On Fri, 22 Nov 2019 18:52:17 +0100,
Andrew Gabbasov wrote:
> 
> loopback_parse_timer_id() uses snd_card_ref(), that can lock on mutex,
> also snd_timer_instance_new() uses non-atomic allocation, that can sleep.
> So, both functions can not be called from loopback_snd_timer_open()
> with cable->lock spinlock locked.
> 
> Moreover, most part of loopback_snd_timer_open() function body works
> when the opposite stream of the same cable does not yet exist, and
> the current stream is not yet completely open and can't be running,
> so existing locking of loopback->cable_lock mutex is enough to protect
> from conflicts with simultaneous opening or closing.
> Locking of cable->lock spinlock is not needed in this case.
> 
> Fixes: 26c53379f98d ("ALSA: aloop: Support selection of snd_timer instead of jiffies")
> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com>

Applied, thanks.


Takashi

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 2/2] ALSA: aloop: Avoid unexpected timer event callback tasklets
  2019-11-22 17:52 ` [PATCH 2/2] ALSA: aloop: Avoid unexpected timer event callback tasklets Andrew Gabbasov
@ 2019-11-22 18:14   ` Takashi Iwai
  0 siblings, 0 replies; 4+ messages in thread
From: Takashi Iwai @ 2019-11-22 18:14 UTC (permalink / raw)
  To: Andrew Gabbasov
  Cc: alsa-devel, linux-kernel, Jaroslav Kysela, Takashi Iwai, Timo Wischer

On Fri, 22 Nov 2019 18:52:18 +0100,
Andrew Gabbasov wrote:
> 
> loopback_snd_timer_close_cable() function waits until all
> scheduled tasklets are completed, but the timer is closed after that
> and can generate more event callbacks, scheduling new tasklets,
> that will not be synchronized with cable closing.
> Move tasklet_kill() call to be executed after snd_timer_close()
> call to avoid such case.
> 
> Fixes: 26c53379f98d ("ALSA: aloop: Support selection of snd_timer instead of jiffies")
> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com>

Applied, thanks.


Takashi

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-11-22 18:14 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-22 17:52 [PATCH 1/2] ALSA: aloop: Remove redundant locking in timer open function Andrew Gabbasov
2019-11-22 17:52 ` [PATCH 2/2] ALSA: aloop: Avoid unexpected timer event callback tasklets Andrew Gabbasov
2019-11-22 18:14   ` Takashi Iwai
2019-11-22 18:13 ` [PATCH 1/2] ALSA: aloop: Remove redundant locking in timer open function Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).