15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* 25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * QEMU live migration 35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright IBM, Corp. 2008 55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright Dell MessageOne 2008 65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Authors: 85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Anthony Liguori <aliguori@us.ibm.com> 95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Charles Duffy <charles_duffy@messageone.com> 105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This work is licensed under the terms of the GNU GPL, version 2. See 125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the COPYING file in the top-level directory. 135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h" 175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu_socket.h" 185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "migration.h" 195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-char.h" 205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "sysemu.h" 215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "buffered_file.h" 225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "block.h" 23986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#include <sys/types.h> 24986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#include <sys/wait.h> 255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner//#define DEBUG_MIGRATION_EXEC 275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef DEBUG_MIGRATION_EXEC 29986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define DPRINTF(fmt, ...) \ 305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { printf("migration-exec: " fmt, ## __VA_ARGS__); } while (0) 315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 32986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define DPRINTF(fmt, ...) \ 335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { } while (0) 345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_errno(FdMigrationState *s) 375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return errno; 395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_write(FdMigrationState *s, const void * buf, size_t size) 425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return write(s->fd, buf, size); 445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int exec_close(FdMigrationState *s) 475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 48986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner int ret = 0; 49986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner DPRINTF("exec_close\n"); 505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (s->opaque) { 51986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner ret = qemu_fclose(s->opaque); 525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->opaque = NULL; 535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->fd = -1; 54986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner if (ret != -1 && 55986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner WIFEXITED(ret) 56986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner && WEXITSTATUS(ret) == 0) { 57986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner ret = 0; 58986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } else { 59986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner ret = -1; 605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 61986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner } 62986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner return ret; 635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerMigrationState *exec_start_outgoing_migration(const char *command, 665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t bandwidth_limit, 675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int detach) 685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner FdMigrationState *s; 705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner FILE *f; 715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s = qemu_mallocz(sizeof(*s)); 735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f = popen(command, "w"); 755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f == NULL) { 76986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner DPRINTF("Unable to popen exec target\n"); 775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto err_after_alloc; 785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->fd = fileno(f); 815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (s->fd == -1) { 82986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner DPRINTF("Unable to retrieve file descriptor for popen'd handle\n"); 835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto err_after_open; 845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (fcntl(s->fd, F_SETFD, O_NONBLOCK) == -1) { 87986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner DPRINTF("Unable to set nonblocking mode on file descriptor\n"); 885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto err_after_open; 895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->opaque = qemu_popen(f, "w"); 925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->close = exec_close; 945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->get_error = file_errno; 955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->write = file_write; 965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->mig_state.cancel = migrate_fd_cancel; 975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->mig_state.get_status = migrate_fd_get_status; 985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->mig_state.release = migrate_fd_release; 995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->state = MIG_STATE_ACTIVE; 1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->mon_resume = NULL; 1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->bandwidth_limit = bandwidth_limit; 1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!detach) 1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner migrate_fd_monitor_suspend(s); 1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner migrate_fd_connect(s); 1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return &s->mig_state; 1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnererr_after_open: 1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pclose(f); 1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnererr_after_alloc: 1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void exec_accept_incoming_migration(void *opaque) 1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f = opaque; 1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); /* just in case */ 1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_loadvm_state(f); 1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "load of migration failed\n"); 1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto err; 1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_announce_self(); 129986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner DPRINTF("successfully loaded vm state\n"); 1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* we've successfully migrated, close the fd */ 131986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, NULL, NULL, NULL); 1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnererr: 1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fclose(f); 1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint exec_start_incoming_migration(const char *command) 1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 142986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner DPRINTF("Attempting to start an incoming migration\n"); 1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f = qemu_popen_cmd(command, "r"); 1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(f == NULL) { 145986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner DPRINTF("Unable to apply qemu wrapper to popen file\n"); 1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -errno; 1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 149986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, 1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exec_accept_incoming_migration, NULL, 1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (void *)(unsigned long)f); 1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 155