: Implement tcp "nowait" option for migration
PATCH 1/1 : Implement tcp "nowait" option for migration
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.
qemu/migration.c +82 -19
@@ -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; }
Quoted 10 lines · Chris Lalancette
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.
Anthony,
Any comments on this patch? I'd like to try to get this in the KVM tree
once Avi gets back, so I would prefer to do any iterations/cleanups now.
Thanks,
Chris Lalancette