Sometimes you want to be able to start up the receiving side of a live migration and actually be able to run monitor commands before you do the migration. Libvirt, in particular, wants to do this for setting up the migration. This patch implements a "nowait" option to the receiving side so that you start up the receiving side similar to:
qemu-kvm -M pc -S blah blah -incoming tcp://0:4444,nowait Then you are able to interact with the monitor before the live migration takes place. Signed-off-by: Chris Lalancette <[EMAIL PROTECTED]>
diff --git a/qemu/migration.c b/qemu/migration.c index a64a287..d16e289 100644 --- a/qemu/migration.c +++ b/qemu/migration.c @@ -886,13 +886,10 @@ static int migrate_incoming_fd(int fd) return ret; } -static int migrate_incoming_tcp(const char *host) +static int migrate_listen_tcp(const char *host, int *outfd) { struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); - int fd, sfd; - ssize_t len; - uint8_t status = 0; + int fd = -1; int reuse = 1; int rc; @@ -928,19 +925,43 @@ static int migrate_incoming_tcp(const char *host) goto error_socket; } + *outfd = fd; + + return 0; + +error_socket: + close(fd); +error: + return rc; +} + +struct migrate_tcp_data { + int listen_fd; + int rc; +}; + +static void migrate_incoming_tcp(void *opaque) +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + struct migrate_tcp_data *data = (struct migrate_tcp_data *)opaque; + int sfd; + ssize_t len; + uint8_t status = 0; + again: - sfd = accept(fd, (struct sockaddr *)&addr, &addrlen); + sfd = accept(data->listen_fd, (struct sockaddr *)&addr, &addrlen); if (sfd == -1) { if (errno == EINTR) goto again; perror("accept() failed"); - rc = MIG_STAT_DST_ACCEPT_FAILED; + data->rc = MIG_STAT_DST_ACCEPT_FAILED; goto error_socket; } - rc = migrate_incoming_fd(sfd); - if (rc != 0) { - fprintf(stderr, "migrate_incoming_fd failed (rc=%d)\n", rc); + data->rc = migrate_incoming_fd(sfd); + if (data->rc != 0) { + fprintf(stderr, "migrate_incoming_fd failed (rc=%d)\n", data->rc); goto error_accept; } @@ -951,13 +972,13 @@ send_ack: if (len != 1) { fprintf(stderr, "migration: send_ack: write error len=%zu (%s)\n", len, strerror(errno)); - rc = MIG_STAT_DST_WRITE_FAILED; + data->rc = MIG_STAT_DST_WRITE_FAILED; goto error_accept; } - rc = wait_for_message("WAIT FOR GO", sfd, wait_for_message_timeout); - if (rc) { - rc += 200; + data->rc = wait_for_message("WAIT FOR GO", sfd, wait_for_message_timeout); + if (data->rc) { + data->rc += 200; goto error_accept; } @@ -966,7 +987,7 @@ wait_for_go: if (len == -1 && errno == EAGAIN) goto wait_for_go; if (len != 1) { - rc = MIG_STAT_DST_READ_FAILED; + data->rc = MIG_STAT_DST_READ_FAILED; fprintf(stderr, "migration: wait_for_go: read error len=%zu (%s)\n", len, strerror(errno)); } @@ -974,9 +995,10 @@ wait_for_go: error_accept: close(sfd); error_socket: - close(fd); -error: - return rc; + qemu_set_fd_handler(data->listen_fd, NULL, NULL, NULL); + close(data->listen_fd); + + qemu_free(data); } int migrate_incoming(const char *device) @@ -996,16 +1018,57 @@ int migrate_incoming(const char *device) } } else if (strstart(device, "tcp://", &ptr)) { char *host, *end; + struct migrate_tcp_data *data; + int is_waitconnect = 1; + host = strdup(ptr); + if (!host) + goto fail; end = strchr(host, '/'); if (end) *end = 0; - ret = migrate_incoming_tcp(host); + + data = qemu_mallocz(sizeof(struct migrate_tcp_data)); + if (!data) { + qemu_free(host); + goto fail; + } + + ptr = host; + while((ptr = strchr(ptr,','))) { + ptr++; + if (!strncmp(ptr,"nowait",6)) { + is_waitconnect = 0; + } else { + printf("Unknown option: %s\n", ptr); + qemu_free(host); + goto fail; + } + } + + ret = migrate_listen_tcp(host, &(data->listen_fd)); qemu_free(host); + if (ret != 0) + goto fail; + + /* + * if we made it here, then migrate_incoming_tcp is responsible for + * freeing the "data" structure + */ + if (!is_waitconnect) { + socket_set_nonblock(data->listen_fd); + qemu_set_fd_handler(data->listen_fd, migrate_incoming_tcp, NULL, data); + } + else { + migrate_incoming_tcp(data); + ret = data->rc; + } + } else { errno = EINVAL; ret = MIG_STAT_DST_INVALID_PARAMS; } + fail: return ret; }