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