char_device: don't connect a migrated client if the state of the device might have changed since it was created

If reading/writing from the device have occured before migration data
has arrived, the migration data might no longer be relvant, and we
disconnect the client.
This commit is contained in:
Yonit Halperin 2012-08-14 15:42:36 +03:00
parent a180fc5e0b
commit 9c6a49c364
5 changed files with 72 additions and 38 deletions

View File

@ -681,20 +681,25 @@ void spice_char_device_state_destroy(SpiceCharDeviceState *char_dev)
spice_char_device_state_unref(char_dev);
}
void spice_char_device_client_add(SpiceCharDeviceState *dev,
RedClient *client,
int do_flow_control,
uint32_t max_send_queue_size,
uint32_t num_client_tokens,
uint32_t num_send_tokens,
int wait_for_migrate_data)
int spice_char_device_client_add(SpiceCharDeviceState *dev,
RedClient *client,
int do_flow_control,
uint32_t max_send_queue_size,
uint32_t num_client_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));
if (wait_for_migrate_data && (dev->num_clients > 0 || dev->active)) {
spice_warning("can't restore device %p from migration data. The device "
"has already been active", dev);
return FALSE;
}
dev->wait_for_migrate_data = wait_for_migrate_data;
spice_debug("dev_state %p client %p", dev, client);
@ -721,6 +726,7 @@ void spice_char_device_client_add(SpiceCharDeviceState *dev,
dev->num_clients++;
/* Now that we have a client, forward any pending device data */
spice_char_device_wakeup(dev);
return TRUE;
}
void spice_char_device_client_remove(SpiceCharDeviceState *dev,

View File

@ -148,13 +148,13 @@ void spice_char_device_reset(SpiceCharDeviceState *dev);
/* max_send_queue_size = how many messages we can read from the device and enqueue for this client,
* when we have tokens for other clients and no tokens for this one */
void spice_char_device_client_add(SpiceCharDeviceState *dev,
RedClient *client,
int do_flow_control,
uint32_t max_send_queue_size,
uint32_t num_client_tokens,
uint32_t num_send_tokens,
int wait_for_migrate_data);
int spice_char_device_client_add(SpiceCharDeviceState *dev,
RedClient *client,
int do_flow_control,
uint32_t max_send_queue_size,
uint32_t num_client_tokens,
uint32_t num_send_tokens,
int wait_for_migrate_data);
void spice_char_device_client_remove(SpiceCharDeviceState *dev,
RedClient *client);

View File

@ -1111,13 +1111,21 @@ void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens)
* flow control, but will have no other problem.
*/
if (!spice_char_device_client_exists(dev_state, rcc->client)) {
spice_char_device_client_add(dev_state,
rcc->client,
TRUE, /* flow control */
REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
REDS_AGENT_WINDOW_SIZE,
num_tokens,
red_channel_client_waits_for_migrate_data(rcc));
int client_added;
client_added = spice_char_device_client_add(dev_state,
rcc->client,
TRUE, /* flow control */
REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
REDS_AGENT_WINDOW_SIZE,
num_tokens,
red_channel_client_waits_for_migrate_data(rcc));
if (!client_added) {
spice_warning("failed to add client to agent");
reds_client_disconnect(rcc->client);
return;
}
} else {
spice_char_device_send_to_client_tokens_set(dev_state,
rcc->client,
@ -3580,13 +3588,21 @@ static SpiceCharDeviceState *attach_to_red_agent(SpiceCharDeviceInstance *sin)
} else {
spice_debug("waiting for migration data");
if (!spice_char_device_client_exists(reds->agent_state.base, reds_get_client())) {
spice_char_device_client_add(reds->agent_state.base,
reds_get_client(),
TRUE, /* flow control */
REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
REDS_AGENT_WINDOW_SIZE,
~0,
TRUE);
int client_added;
client_added = spice_char_device_client_add(reds->agent_state.base,
reds_get_client(),
TRUE, /* flow control */
REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
REDS_AGENT_WINDOW_SIZE,
~0,
TRUE);
if (!client_added) {
spice_warning("failed to add client to agent");
reds_disconnect();
}
}
}
return state->base;

View File

@ -339,17 +339,25 @@ static void smartcard_char_device_attach_client(SpiceCharDeviceInstance *char_de
SmartCardChannelClient *scc)
{
SmartCardDeviceState *st = spice_char_device_state_opaque_get(char_device->st);
int client_added;
spice_assert(!scc->smartcard_state && !st->scc);
st->scc = scc;
spice_char_device_client_add(st->chardev_st,
scc->base.client,
FALSE, /* no flow control yet */
0, /* send queue size */
~0,
~0,
red_channel_client_waits_for_migrate_data(&scc->base));
scc->smartcard_state = st;
client_added = spice_char_device_client_add(st->chardev_st,
scc->base.client,
FALSE, /* no flow control yet */
0, /* send queue size */
~0,
~0,
red_channel_client_waits_for_migrate_data(
&scc->base));
if (!client_added) {
spice_warning("failed");
st->scc = NULL;
scc->smartcard_state = NULL;
red_channel_client_disconnect(&scc->base);
}
}
static void smartcard_char_device_notify_reader_remove(SmartCardDeviceState *st)

View File

@ -384,8 +384,12 @@ 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,
red_channel_client_waits_for_migrate_data(rcc));
if (!spice_char_device_client_add(state->chardev_st, client, FALSE, 0, ~0, ~0,
red_channel_client_waits_for_migrate_data(rcc))) {
spice_warning("failed to add client to spicevmc");
red_channel_client_disconnect(rcc);
return;
}
if (sif->state) {
sif->state(sin, 1);