This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit c695c5e77db730d824832e2621331e76dc565cdf
Author: jinxiuxu <[email protected]>
AuthorDate: Tue Oct 20 23:08:14 2026 +0800

    drivers/virtio-snd: call the upper half without holding the lock
    
    virtio_snd_pcm_notify_cb() held priv->lock across the UNDERRUN and
    DEQUEUE callbacks.  The upper half can enqueue the next buffer from
    the callback, which takes priv->lock again and deadlocks on SMP.
    
    Hold the lock only while taking a buffer from the virtqueue and
    updating cache_buffers, and invoke the callbacks after releasing it.
    
    Signed-off-by: jinxiuxu <[email protected]>
---
 drivers/virtio/virtio-snd.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/virtio/virtio-snd.c b/drivers/virtio/virtio-snd.c
index c4467c43eab..c9ae4b31397 100644
--- a/drivers/virtio/virtio-snd.c
+++ b/drivers/virtio/virtio-snd.c
@@ -343,23 +343,32 @@ virtio_snd_get_support_formats(FAR const struct 
virtio_snd_pcm_info *info,
 static void virtio_snd_pcm_notify_cb(FAR struct virtqueue *vq)
 {
   FAR struct virtio_snd_s *priv = vq->vq_dev->priv;
+  FAR struct virtio_snd_buffer_s *buf;
+  FAR struct virtio_snd_dev_s *sdev;
   irqstate_t flags;
+  bool underrun;
 
-  flags = spin_lock_irqsave(&priv->lock);
   for (; ; )
     {
-      FAR struct virtio_snd_buffer_s *buf;
-      FAR struct virtio_snd_dev_s *sdev;
+      flags = spin_lock_irqsave(&priv->lock);
       buf = virtqueue_get_buffer(vq, NULL, NULL);
       if (buf == NULL)
         {
+          spin_unlock_irqrestore(&priv->lock, flags);
           break;
         }
 
       sdev = (FAR struct virtio_snd_dev_s *)buf->dev;
       sdev->cache_buffers--;
-      if (sdev->running &&
-          buf->status->latency_bytes < sdev->period_bytes)
+      underrun = sdev->running &&
+                 buf->status->latency_bytes < sdev->period_bytes;
+      spin_unlock_irqrestore(&priv->lock, flags);
+
+      /* The upper half may call back into this driver (enqueue), which
+       * takes priv->lock again.
+       */
+
+      if (underrun)
         {
           buf->dev->upper(buf->dev->priv, AUDIO_CALLBACK_UNDERRUN,
                           NULL, OK);
@@ -373,8 +382,6 @@ static void virtio_snd_pcm_notify_cb(FAR struct virtqueue 
*vq)
                       &buf->apb, OK);
 #endif
     }
-
-  spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 /****************************************************************************

Reply via email to