aboutsummaryrefslogtreecommitdiff
path: root/savevm.c
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2013-02-11 17:01:45 +0100
committerAnthony Liguori <aliguori@us.ibm.com>2013-02-11 13:22:52 -0600
commitd7cd369402191814a1bb339a730f3af411e9682f (patch)
tree7d073bdab810935815661826e533b49f346f865d /savevm.c
parentd0bce760e04b1658a3b4ac95be2839ae20fd86db (diff)
migration: restrict scope of incoming fd read handler
The incoming migration is processed in a coroutine and uses an fd read handler to enter the yielded coroutine when data becomes available. The read handler was set too broadly, so that spurious coroutine entries were be triggered if other coroutine users yielded (like the block layer's bdrv_write() function). Install the fd read only only when yielding for more data to become available. This prevents spurious coroutine entries which break code that assumes only a specific set of places can re-enter the coroutine. This patch fixes crashes in block/raw-posix.c that are triggered with "migrate -b" when qiov becomes a dangling pointer due to a spurious coroutine entry that frees qiov early. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 1360598505-5512-1-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'savevm.c')
-rw-r--r--savevm.c34
1 files changed, 30 insertions, 4 deletions
diff --git a/savevm.c b/savevm.c
index 4eb29b2ae2..0b6724dddb 100644
--- a/savevm.c
+++ b/savevm.c
@@ -140,6 +140,34 @@ typedef struct QEMUFileSocket
QEMUFile *file;
} QEMUFileSocket;
+typedef struct {
+ Coroutine *co;
+ int fd;
+} FDYieldUntilData;
+
+static void fd_coroutine_enter(void *opaque)
+{
+ FDYieldUntilData *data = opaque;
+ qemu_set_fd_handler(data->fd, NULL, NULL, NULL);
+ qemu_coroutine_enter(data->co, NULL);
+}
+
+/**
+ * Yield until a file descriptor becomes readable
+ *
+ * Note that this function clobbers the handlers for the file descriptor.
+ */
+static void coroutine_fn yield_until_fd_readable(int fd)
+{
+ FDYieldUntilData data;
+
+ assert(qemu_in_coroutine());
+ data.co = qemu_coroutine_self();
+ data.fd = fd;
+ qemu_set_fd_handler(fd, fd_coroutine_enter, NULL, &data);
+ qemu_coroutine_yield();
+}
+
static int socket_get_fd(void *opaque)
{
QEMUFileSocket *s = opaque;
@@ -158,8 +186,7 @@ static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
break;
}
if (socket_error() == EAGAIN) {
- assert(qemu_in_coroutine());
- qemu_coroutine_yield();
+ yield_until_fd_readable(s->fd);
} else if (socket_error() != EINTR) {
break;
}
@@ -205,8 +232,7 @@ static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
break;
}
if (errno == EAGAIN) {
- assert(qemu_in_coroutine());
- qemu_coroutine_yield();
+ yield_until_fd_readable(fileno(fp));
} else if (errno != EINTR) {
break;
}