A signal can end the interruptible wait while a STOP or RELEASE request
is still pending. A later teardown may then submit another RELEASE
before the first request completes.

Keep both waits non-interruptible and use the existing message timeout.
Other control requests remain interruptible. Device reset still cancels
the pending request and wakes the waiter.

Keep timeout and wait results in the types returned by the kernel wait
APIs.

Assisted-by: LLM
Signed-off-by: Joonho Lee <[email protected]>

---
sound/virtio/virtio_ctl_msg.c |   19 ++++++++++++++++---
 sound/virtio/virtio_ctl_msg.h |    3 +++
 sound/virtio/virtio_pcm_ops.c |   10 +++++-----
 3 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/sound/virtio/virtio_ctl_msg.c b/sound/virtio/virtio_ctl_msg.c
--- a/sound/virtio/virtio_ctl_msg.c
+++ b/sound/virtio/virtio_ctl_msg.c
@@ -265,7 +265,7 @@
 {
        struct virtio_device *vdev = snd->vdev;
        struct virtio_snd_queue *queue = virtsnd_control_queue(snd);
-       unsigned int js = msecs_to_jiffies(virtsnd_msg_timeout_ms);
+       unsigned long js = msecs_to_jiffies(virtsnd_msg_timeout_ms);
        struct virtio_snd_hdr *request = virtsnd_ctl_msg_request(msg);
        struct virtio_snd_hdr *response = virtsnd_ctl_msg_response(msg);
        unsigned int nouts = 0;
@@ -273,7 +273,7 @@
        struct scatterlist *psgs[4];
        bool notify = false;
        unsigned long flags;
-       int rc;
+       long rc;
 
        virtsnd_ctl_msg_ref(msg);
        /* This reference stays with the queue until completion or teardown. */
@@ -314,7 +314,20 @@
                 */
                virtsnd_ctl_msg_unref(msg);
        } else if (!nowait) {
-               rc = wait_for_completion_interruptible_timeout(&msg->notify, 
js);
+               /*
+                * Teardown must observe completion even with a pending signal.
+                * Otherwise a subsequent open can retry RELEASE while the 
device
+                * is still processing the previous teardown request.
+                */
+               switch (le32_to_cpu(request->code)) {
+               case VIRTIO_SND_R_PCM_STOP:
+               case VIRTIO_SND_R_PCM_RELEASE:
+                       rc = wait_for_completion_timeout(&msg->notify, js);
+                       break;
+               default:
+                       rc = 
wait_for_completion_interruptible_timeout(&msg->notify, js);
+                       break;
+               }
                if (!rc) {
                        dev_err(&vdev->dev,
                                "control message (0x%08x) timeout\n",
diff --git a/sound/virtio/virtio_ctl_msg.h b/sound/virtio/virtio_ctl_msg.h
--- a/sound/virtio/virtio_ctl_msg.h
+++ b/sound/virtio/virtio_ctl_msg.h
@@ -47,6 +47,9 @@
  * The msg_timeout_ms module parameter defines the message completion timeout.
  * If the message is not completed within this time, the function will return 
an
  * error.
+ * PCM STOP and RELEASE wait through pending signals within this timeout.
+ * Other requests remain interruptible. Device reset cancels and wakes either
+ * kind of waiter.
  *
  * Context: Any context that permits to sleep.
  * Return: 0 on success, -errno on failure.
diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
--- a/sound/virtio/virtio_pcm_ops.c
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -20,11 +20,11 @@
  *   (RELEASE command in the ops->sync_stop()) and the ops->hw_free() has been
  *   called.
  *
- *   When the substream stops, the ops->sync_stop() waits until the device has
- *   completed all pending messages. This wait can be interrupted either by a
- *   signal or due to a timeout. In this case, the device can still access
- *   messages even after calling ops->hw_free(). It can also issue an 
interrupt,
- *   and the interrupt handler will also try to access message structures.
+ *   When the substream stops, ops->sync_stop() stops and releases the device
+ *   as required, then waits for pending messages. A failed control request or
+ *   timed-out flush can leave the device able to access messages after
+ *   ops->hw_free(). It can also issue an interrupt, and the interrupt handler
+ *   will also try to access message structures.
  *   The messages retain references to the PCM buffer pages until they are
  *   freed, so late DMA does not target pages released by ALSA.
  *

Reply via email to