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); } /****************************************************************************
