[Spice-devel] [spice PATCH 20/55] char device migration: don't read or write from/to the device while waiting for migraion data

Yonit Halperin yhalperi at redhat.com
Wed Aug 15 00:56:00 PDT 2012


---
 server/char_device.c |   24 +++++++++++++++++++-----
 server/char_device.h |    3 ++-
 server/reds.c        |   13 +++++++------
 server/smartcard.c   |    3 ++-
 server/spicevmc.c    |    3 ++-
 5 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/server/char_device.c b/server/char_device.c
index 84121e6..d97c6dd 100644
--- a/server/char_device.c
+++ b/server/char_device.c
@@ -45,6 +45,8 @@ struct SpiceCharDeviceClientState {
 
 struct SpiceCharDeviceState {
     int running;
+    int active; /* has read/write been performed since the device was started */
+    int wait_for_migrate_data;
     uint32_t refs;
 
     Ring write_queue;
@@ -268,7 +270,7 @@ static int spice_char_device_read_from_device(SpiceCharDeviceState *dev)
     uint64_t max_send_tokens;
     int did_read = FALSE;
 
-    if (!dev->running) {
+    if (!dev->running || dev->wait_for_migrate_data) {
         return FALSE;
     }
 
@@ -307,6 +309,7 @@ static int spice_char_device_read_from_device(SpiceCharDeviceState *dev)
     }
     dev->during_read_from_device = 0;
     spice_char_device_state_unref(dev);
+    dev->active = dev->active || did_read;
     return did_read;
 }
 
@@ -415,7 +418,7 @@ static int spice_char_device_write_to_device(SpiceCharDeviceState *dev)
     int total = 0;
     int n;
 
-    if (!dev->running) {
+    if (!dev->running || dev->wait_for_migrate_data) {
         return 0;
     }
 
@@ -462,6 +465,7 @@ static int spice_char_device_write_to_device(SpiceCharDeviceState *dev)
         spice_assert(ring_is_empty(&dev->write_queue));
     }
     spice_char_device_state_unref(dev);
+    dev->active = dev->active || total;
     return total;
 }
 
@@ -682,13 +686,17 @@ void spice_char_device_client_add(SpiceCharDeviceState *dev,
                                   int do_flow_control,
                                   uint32_t max_send_queue_size,
                                   uint32_t num_client_tokens,
-                                  uint32_t num_send_tokens)
+                                  uint32_t num_send_tokens,
+                                  int wait_for_migrate_data)
 {
     SpiceCharDeviceClientState *dev_client;
 
     spice_assert(dev);
     spice_assert(client);
 
+    spice_assert(!wait_for_migrate_data || (dev->num_clients == 0 && !dev->active));
+    dev->wait_for_migrate_data = wait_for_migrate_data;
+
     spice_debug("dev_state %p client %p", dev, client);
     dev_client = spice_new0(SpiceCharDeviceClientState, 1);
     dev_client->dev = dev;
@@ -727,8 +735,12 @@ void spice_char_device_client_remove(SpiceCharDeviceState *dev,
         spice_error("client wasn't found");
         return;
     }
-
     spice_char_device_client_free(dev, dev_client);
+    if (dev->wait_for_migrate_data) {
+        spice_assert(dev->num_clients == 0);
+        dev->wait_for_migrate_data  = FALSE;
+        spice_char_device_read_from_device(dev);
+    }
 }
 
 int spice_char_device_client_exists(SpiceCharDeviceState *dev,
@@ -751,14 +763,16 @@ void spice_char_device_stop(SpiceCharDeviceState *dev)
 {
     spice_debug("dev_state %p", dev);
     dev->running = FALSE;
+    dev->active = FALSE;
     core->timer_cancel(dev->write_to_dev_timer);
 }
 
 void spice_char_device_reset(SpiceCharDeviceState *dev)
 {
     RingItem *client_item;
-    spice_char_device_stop(dev);
 
+    spice_char_device_stop(dev);
+    dev->wait_for_migrate_data = FALSE;
     spice_debug("dev_state %p", dev);
     while (!ring_is_empty(&dev->write_queue)) {
         RingItem *item = ring_get_tail(&dev->write_queue);
diff --git a/server/char_device.h b/server/char_device.h
index 186b1f1..f3278e3 100644
--- a/server/char_device.h
+++ b/server/char_device.h
@@ -150,7 +150,8 @@ void spice_char_device_client_add(SpiceCharDeviceState *dev,
                                   int do_flow_control,
                                   uint32_t max_send_queue_size,
                                   uint32_t num_client_tokens,
-                                  uint32_t num_send_tokens);
+                                  uint32_t num_send_tokens,
+                                  int wait_for_migrate_data);
 
 void spice_char_device_client_remove(SpiceCharDeviceState *dev,
                                      RedClient *client);
diff --git a/server/reds.c b/server/reds.c
index 3b53056..7e31b18 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1090,13 +1090,13 @@ void reds_fill_channels(SpiceMsgChannels *channels_info)
 void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens)
 {
     SpiceCharDeviceState *dev_state = reds->agent_state.base;
-    RedClient *client;
+    RedChannelClient *rcc;
 
     if (!vdagent) {
         return;
     }
     spice_assert(vdagent->st && vdagent->st == dev_state);
-    client = main_channel_client_get_base(mcc)->client;
+    rcc = main_channel_client_get_base(mcc);
     /*
      * Note that in older releases, send_tokens were set to ~0 on both client
      * and server. The server ignored the client given tokens.
@@ -1104,16 +1104,17 @@ void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens)
      * and vice versa, the sending from the server to the client won't have
      * flow control, but will have no other problem.
      */
-    if (!spice_char_device_client_exists(dev_state, client)) {
+    if (!spice_char_device_client_exists(dev_state, rcc->client)) {
         spice_char_device_client_add(dev_state,
-                                     client,
+                                     rcc->client,
                                      TRUE, /* flow control */
                                      REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
                                      REDS_AGENT_WINDOW_SIZE,
-                                     num_tokens);
+                                     num_tokens,
+                                     red_channel_client_waits_for_migrate_data(rcc));
     } else {
         spice_char_device_send_to_client_tokens_set(dev_state,
-                                                    client,
+                                                    rcc->client,
                                                     num_tokens);
     }
     reds->agent_state.write_filter.discard_all = FALSE;
diff --git a/server/smartcard.c b/server/smartcard.c
index 2ed0bde..de86185 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -326,7 +326,8 @@ static void smartcard_char_device_attach(SpiceCharDeviceInstance *char_device,
                                  FALSE, /* no flow control yet */
                                  0, /* send queue size */
                                  ~0,
-                                 ~0);
+                                 ~0,
+                                 red_channel_client_waits_for_migrate_data(&scc->base));
     scc->smartcard_state = st;
     write_buf = spice_char_device_write_buffer_get(st->chardev_st, NULL, sizeof(vheader));
     if (!write_buf) {
diff --git a/server/spicevmc.c b/server/spicevmc.c
index 36d901f..8bc23fd 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -309,7 +309,8 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client,
     state->rcc = rcc;
     red_channel_client_ack_zero_messages_window(rcc);
 
-    spice_char_device_client_add(state->chardev_st, client, FALSE, 0, ~0, ~0);
+    spice_char_device_client_add(state->chardev_st, client, FALSE, 0, ~0, ~0,
+                                 red_channel_client_waits_for_migrate_data(rcc));
 
     if (sif->state) {
         sif->state(sin, 1);
-- 
1.7.7.6



More information about the Spice-devel mailing list