summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-03-27 13:34:02 +0200
committerHans de Goede <hdegoede@redhat.com>2012-03-27 13:34:02 +0200
commit9a58d8ee70c13677a1b62a2c8af694829c7afec5 (patch)
treeafe2d6f5ddaae603a911aed9acac4e3afe55b212
parent58b52e83c50c3b91264547d096f78bfdbe25e32e (diff)
vdagentd: Fix a race-condition when opening the virtio serial port
See the (large) comment added in src/vdagent-virtio-port.c for details. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--src/vdagent-virtio-port.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/src/vdagent-virtio-port.c b/src/vdagent-virtio-port.c
index 84e2e67..47de48d 100644
--- a/src/vdagent-virtio-port.c
+++ b/src/vdagent-virtio-port.c
@@ -49,6 +49,7 @@ struct vdagent_virtio_port_chunk_port_data {
struct vdagent_virtio_port {
int fd;
+ int opening;
FILE *errfile;
/* Chunk read stuff, single buffer, separate header and data buffer */
@@ -90,6 +91,7 @@ struct vdagent_virtio_port *vdagent_virtio_port_create(const char *portname,
free(vport);
return NULL;
}
+ vport->opening = 1;
vport->read_callback = read_callback;
vport->disconnect_callback = disconnect_callback;
@@ -345,10 +347,35 @@ static void vdagent_virtio_port_do_read(struct vdagent_virtio_port **vportp)
fprintf(vport->errfile, "reading from vdagent virtio port: %s\n",
strerror(errno));
}
+ if (n == 0 && vport->opening) {
+ /* When we open the virtio serial port, the following happens:
+ 1) The linux kernel virtio_console driver sends a
+ VIRTIO_CONSOLE_PORT_OPEN message to qemu
+ 2) qemu's spicevmc chardev driver calls qemu_spice_add_interface to
+ register the agent chardev with the spice-server
+ 3) spice-server then calls the spicevmc chardev driver's state
+ callback to let it know it is ready to receive data
+ 4) The state callback sends a CHR_EVENT_OPENED to the virtio-console
+ chardev backend
+ 5) The virtio-console chardev backend sends VIRTIO_CONSOLE_PORT_OPEN
+ to the linux kernel virtio_console driver
+
+ Until steps 1 - 5 have completed the linux kernel virtio_console
+ driver sees the virtio serial port as being in a disconnected state
+ and read will return 0 ! So if we blindly assume that a read 0 means
+ that the channel is closed we will hit a race here.
+
+ Therefore we ignore read returning 0 until we've successfully read
+ or written some data. If we hit this race we also sleep a bit here
+ to avoid busy waiting until the above steps complete */
+ usleep(10000);
+ return;
+ }
if (n <= 0) {
vdagent_virtio_port_destroy(vportp);
return;
}
+ vport->opening = 0;
if (vport->chunk_header_read < sizeof(vport->chunk_header)) {
vport->chunk_header_read += n;
@@ -402,6 +429,8 @@ static void vdagent_virtio_port_do_write(struct vdagent_virtio_port **vportp)
vdagent_virtio_port_destroy(vportp);
return;
}
+ if (n > 0)
+ vport->opening = 0;
wbuf->pos += n;
if (wbuf->pos == wbuf->size) {