[Spice-devel] [PATCH spice] server: do not fail to read all agent data when called recursively

Hans de Goede hdegoede at redhat.com
Wed Oct 13 14:02:01 PDT 2010


We can loose (not handle) a virtio port write from the guest:

- server/reds.c: vdagent_char_device_wakeup get called
  by hw/spice-vmc.c because data has arrived from the guest,
- hw/spice-vmc.c: vmc_read get calls
- If the vmc_read call depletes the current buffer it calls
  virtio_serial_throttle_port(&svc->port, false)
- This causes vmc_have_data to get called, which if in the
  mean time another buffer has arrived causes
  vdagent_char_device_wakeup to gets called again
  (so recursively)
- vdagent_char_device_wakeup is protected against recursive
  calling and ignores the second call (a nasty hack)
- if no other data arrives, the arrived data will not get read

Together with another nasty hack in the linux guest virtio_console
driver, where it waits for a write to be acked by the host before
continuing with the next one, this can lead to the guest
getting stuck / hang (until the write is read by the spice-server
which never happens becaus of the above issues).
---
 server/reds.c |   23 ++++++++++++++---------
 1 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/server/reds.c b/server/reds.c
index a88ca95..f4dfa46 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1231,21 +1231,14 @@ static void dispatch_vdi_port_data(int port, VDIReadBuf *buf)
 
 static int read_from_vdi_port(void)
 {
-    // FIXME: UGLY HACK. Result of spice-vmc vmc_read triggering flush of throttled data, and recalling this.
-    static int inside_call = 0;
     int quit_loop = 0;
     VDIPortState *state = &reds->agent_state;
     SpiceCharDeviceInterface *sif;
     VDIReadBuf *dispatch_buf;
     int total = 0;
     int n;
-    if (inside_call) {
-        return 0;
-    }
-    inside_call = 1;
 
     if (!reds->agent_state.connected || reds->mig_target) {
-        inside_call = 0;
         return 0;
     }
 
@@ -1314,13 +1307,25 @@ static int read_from_vdi_port(void)
             dispatch_vdi_port_data(state->vdi_chunk_header.port, dispatch_buf);
         }
     }
-    inside_call = 0;
     return total;
 }
 
 void vdagent_char_device_wakeup(SpiceCharDeviceInstance *sin)
 {
-    while (read_from_vdi_port());
+    static int vdagent_char_device_wakeups = 0;
+
+    vdagent_char_device_wakeups++;
+
+    if (vdagent_char_device_wakeups != 1) {
+        /* When spice-vmc vmc_read triggers flush of throttled data, we may get
+           recalled and we may not call read_from_vdi_port() recursively */
+        return;
+    }
+
+    while (vdagent_char_device_wakeups) {
+        while (read_from_vdi_port()) {}
+        vdagent_char_device_wakeups--;
+    }
 }
 
 static void reds_handle_agent_mouse_event()
-- 
1.7.3.1



More information about the Spice-devel mailing list