From cb767a83fda2b93b47de284719353b3d073120be Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Thu, 2 Aug 2012 22:55:53 +0300 Subject: char device migration: don't read or write from/to the device while waiting for migraion data --- 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 84121e6d..d97c6dda 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 186b1f1e..f3278e3d 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 dc44de5f..a5a5a75a 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 2ed0bde8..de86185d 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 36d901f5..8bc23fda 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); -- cgit