Patch "ALSA: usb-audio: Fix recursive locking at XRUN during syncing" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    ALSA: usb-audio: Fix recursive locking at XRUN during syncing

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     alsa-usb-audio-fix-recursive-locking-at-xrun-during-.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit b87766819d01539be785e9b300be440cce8d1319
Author: Takashi Iwai <tiwai@xxxxxxx>
Date:   Mon Mar 20 15:28:38 2023 +0100

    ALSA: usb-audio: Fix recursive locking at XRUN during syncing
    
    [ Upstream commit 8c721c53dda512fdd48eb24d6d99e56deee57898 ]
    
    The recent support of low latency playback in USB-audio driver made
    the snd_usb_queue_pending_output_urbs() function to be called via PCM
    ack ops.  In the new code path, the function is performed already in
    the PCM stream lock.  The problem is that, when an XRUN is detected,
    the function calls snd_pcm_xrun() to notify, but snd_pcm_xrun() is
    supposed to be called only outside the stream lock.  As a result, it
    leads to a deadlock of PCM stream locking.
    
    For avoiding such a recursive locking, this patch adds an additional
    check to the code paths in PCM core that call the ack callback; now it
    checks the error code from the callback, and if it's -EPIPE, the XRUN
    is handled in the PCM core side gracefully.  Along with it, the
    USB-audio driver code is changed to follow that, i.e. -EPIPE is
    returned instead of the explicit snd_pcm_xrun() call when the function
    is performed already in the stream lock.
    
    Fixes: d5f871f89e21 ("ALSA: usb-audio: Improved lowlatency playback support")
    Reported-and-tested-by: John Keeping <john@xxxxxxxxxxxx>
    Link: https://lore.kernel.org/r/20230317195128.3911155-1-john@xxxxxxxxxxxx
    Reviewed-by: Jaroslav Kysela <perex@xxxxxxxx>
    Reviewed-by; Takashi Sakamoto <o-takashi@xxxxxxxxxxxxx>
    Link: https://lore.kernel.org/r/20230320142838.494-1-tiwai@xxxxxxx
    Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 491064f55515b..8947c988b6d34 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -2137,6 +2137,8 @@ int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream,
 		ret = substream->ops->ack(substream);
 		if (ret < 0) {
 			runtime->control->appl_ptr = old_appl_ptr;
+			if (ret == -EPIPE)
+				__snd_pcm_xrun(substream);
 			return ret;
 		}
 	}
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 092350eb5f4e3..6c7d842d04965 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -444,8 +444,8 @@ static void push_back_to_ready_list(struct snd_usb_endpoint *ep,
  * This function is used both for implicit feedback endpoints and in low-
  * latency playback mode.
  */
-void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
-				       bool in_stream_lock)
+int snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
+				      bool in_stream_lock)
 {
 	bool implicit_fb = snd_usb_endpoint_implicit_feedback_sink(ep);
 
@@ -469,7 +469,7 @@ void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
 		spin_unlock_irqrestore(&ep->lock, flags);
 
 		if (ctx == NULL)
-			return;
+			break;
 
 		/* copy over the length information */
 		if (implicit_fb) {
@@ -484,11 +484,14 @@ void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
 			break;
 		if (err < 0) {
 			/* push back to ready list again for -EAGAIN */
-			if (err == -EAGAIN)
+			if (err == -EAGAIN) {
 				push_back_to_ready_list(ep, ctx);
-			else
+				break;
+			}
+
+			if (!in_stream_lock)
 				notify_xrun(ep);
-			return;
+			return -EPIPE;
 		}
 
 		err = usb_submit_urb(ctx->urb, GFP_ATOMIC);
@@ -496,13 +499,16 @@ void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
 			usb_audio_err(ep->chip,
 				      "Unable to submit urb #%d: %d at %s\n",
 				      ctx->index, err, __func__);
-			notify_xrun(ep);
-			return;
+			if (!in_stream_lock)
+				notify_xrun(ep);
+			return -EPIPE;
 		}
 
 		set_bit(ctx->index, &ep->active_mask);
 		atomic_inc(&ep->submitted_urbs);
 	}
+
+	return 0;
 }
 
 /*
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index 6a9af04cf175a..daa7ba063d858 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -49,7 +49,7 @@ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
 int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
 				      struct snd_urb_ctx *ctx, int idx,
 				      unsigned int avail);
-void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
-				       bool in_stream_lock);
+int snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
+				      bool in_stream_lock);
 
 #endif /* __USBAUDIO_ENDPOINT_H */
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 87a30be643242..de0964dbf7a91 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -1557,7 +1557,7 @@ static int snd_usb_pcm_playback_ack(struct snd_pcm_substream *substream)
 	 * outputs here
 	 */
 	if (!ep->active_mask)
-		snd_usb_queue_pending_output_urbs(ep, true);
+		return snd_usb_queue_pending_output_urbs(ep, true);
 	return 0;
 }
 



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux