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

[PATCH 2/2] ALSA: xen-front: Connect event channel after stream prepare



The request channel must be connected from ALSA .open(), because hw-rule
queries and the stream open request use it. The event channel is
different: XENSND_EVT_CUR_POS handling uses ALSA runtime buffer and
period geometry, and the corresponding Xen stream parameters are not
submitted to the backend until .prepare() sends XENSND_OP_OPEN.

Currently .open() connects both channels. A backend current-position
event, or a stale event queued for an earlier stream instance, can
therefore reach xen_snd_front_alsa_handle_cur_pos() before
runtime->buffer_size and runtime->period_size are valid.

Add a per-channel connection helper, connect only the request channel in
.open(), connect the event channel after a successful stream prepare,
and disconnect it before stream close/free. Re-check the event-channel
state after taking ring_io_lock so disconnecting the event channel
synchronizes against a threaded IRQ that passed the initial lockless
state test. Keep defensive runtime geometry checks in the position
handler.

Fixes: 1cee559351a7 ("ALSA: xen-front: Implement ALSA virtual sound driver")
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@xxxxxxxxx>
---
 sound/xen/xen_snd_front_alsa.c    | 17 ++++++++++++-----
 sound/xen/xen_snd_front_evtchnl.c | 20 +++++++++++++-------
 sound/xen/xen_snd_front_evtchnl.h |  2 ++
 3 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c
index dc626480123a..a6dd196f73d6 100644
--- a/sound/xen/xen_snd_front_alsa.c
+++ b/sound/xen/xen_snd_front_alsa.c
@@ -378,7 +378,7 @@ static int alsa_open(struct snd_pcm_substream *substream)
 
        stream_clear(stream);
 
-       xen_snd_front_evtchnl_pair_set_connected(stream->evt_pair, true);
+       xen_snd_front_evtchnl_set_connected(&stream->evt_pair->req, true);
 
        ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
                                  alsa_hw_rule, stream,
@@ -498,6 +498,8 @@ static int alsa_hw_free(struct snd_pcm_substream *substream)
        struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
        int ret;
 
+       xen_snd_front_evtchnl_set_connected(&stream->evt_pair->evt, false);
+
        ret = xen_snd_front_stream_close(&stream->evt_pair->req);
        stream_free(stream);
        return ret;
@@ -532,6 +534,7 @@ static int alsa_prepare(struct snd_pcm_substream *substream)
                        return ret;
 
                stream->is_open = true;
+               xen_snd_front_evtchnl_set_connected(&stream->evt_pair->evt, 
true);
        }
 
        return 0;
@@ -571,20 +574,24 @@ void xen_snd_front_alsa_handle_cur_pos(struct 
xen_snd_front_evtchnl *evtchnl,
 {
        struct snd_pcm_substream *substream = evtchnl->u.evt.substream;
        struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t delta, new_hw_ptr, cur_frame;
 
-       cur_frame = bytes_to_frames(substream->runtime, pos_bytes);
+       if (!runtime->buffer_size || !runtime->period_size)
+               return;
+
+       cur_frame = bytes_to_frames(runtime, pos_bytes);
 
        delta = cur_frame - stream->be_cur_frame;
        stream->be_cur_frame = cur_frame;
 
        new_hw_ptr = (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr);
-       new_hw_ptr = (new_hw_ptr + delta) % substream->runtime->buffer_size;
+       new_hw_ptr = (new_hw_ptr + delta) % runtime->buffer_size;
        atomic_set(&stream->hw_ptr, (int)new_hw_ptr);
 
        stream->out_frames += delta;
-       if (stream->out_frames > substream->runtime->period_size) {
-               stream->out_frames %= substream->runtime->period_size;
+       if (stream->out_frames > runtime->period_size) {
+               stream->out_frames %= runtime->period_size;
                snd_pcm_period_elapsed(substream);
        }
 }
diff --git a/sound/xen/xen_snd_front_evtchnl.c 
b/sound/xen/xen_snd_front_evtchnl.c
index 09e4c1d05636..17a30452c0cc 100644
--- a/sound/xen/xen_snd_front_evtchnl.c
+++ b/sound/xen/xen_snd_front_evtchnl.c
@@ -94,6 +94,9 @@ static irqreturn_t evtchnl_interrupt_evt(int irq, void 
*dev_id)
 
        guard(mutex)(&channel->ring_io_lock);
 
+       if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED))
+               return IRQ_HANDLED;
+
        prod = page->in_prod;
        /* Ensure we see ring contents up to prod. */
        virt_rmb();
@@ -430,8 +433,8 @@ int xen_snd_front_evtchnl_publish_all(struct 
xen_snd_front_info *front_info)
        return ret;
 }
 
-void xen_snd_front_evtchnl_pair_set_connected(struct 
xen_snd_front_evtchnl_pair *evt_pair,
-                                             bool is_connected)
+void xen_snd_front_evtchnl_set_connected(struct xen_snd_front_evtchnl *channel,
+                                        bool is_connected)
 {
        enum xen_snd_front_evtchnl_state state;
 
@@ -440,13 +443,16 @@ void xen_snd_front_evtchnl_pair_set_connected(struct 
xen_snd_front_evtchnl_pair
        else
                state = EVTCHNL_STATE_DISCONNECTED;
 
-       scoped_guard(mutex, &evt_pair->req.ring_io_lock) {
-               evt_pair->req.state = state;
+       scoped_guard(mutex, &channel->ring_io_lock) {
+               channel->state = state;
        }
+}
 
-       scoped_guard(mutex, &evt_pair->evt.ring_io_lock) {
-               evt_pair->evt.state = state;
-       }
+void xen_snd_front_evtchnl_pair_set_connected(struct 
xen_snd_front_evtchnl_pair *evt_pair,
+                                             bool is_connected)
+{
+       xen_snd_front_evtchnl_set_connected(&evt_pair->req, is_connected);
+       xen_snd_front_evtchnl_set_connected(&evt_pair->evt, is_connected);
 }
 
 void xen_snd_front_evtchnl_pair_clear(struct xen_snd_front_evtchnl_pair 
*evt_pair)
diff --git a/sound/xen/xen_snd_front_evtchnl.h 
b/sound/xen/xen_snd_front_evtchnl.h
index 8400261ac466..f6ebdb09c029 100644
--- a/sound/xen/xen_snd_front_evtchnl.h
+++ b/sound/xen/xen_snd_front_evtchnl.h
@@ -77,6 +77,8 @@ void xen_snd_front_evtchnl_free_all(struct xen_snd_front_info 
*front_info);
 int xen_snd_front_evtchnl_publish_all(struct xen_snd_front_info *front_info);
 
 void xen_snd_front_evtchnl_flush(struct xen_snd_front_evtchnl *evtchnl);
+void xen_snd_front_evtchnl_set_connected(struct xen_snd_front_evtchnl *channel,
+                                        bool is_connected);
 
 void xen_snd_front_evtchnl_pair_set_connected(struct 
xen_snd_front_evtchnl_pair *evt_pair,
                                              bool is_connected);

-- 
2.54.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.