char device migration: don't read or write from/to the device while waiting for migraion data

This commit is contained in:
Yonit Halperin 2012-08-02 22:55:53 +03:00
parent b0264a5e37
commit cb767a83fd
5 changed files with 32 additions and 14 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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) {

View File

@ -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);