Home | History | Annotate | Download | only in qemu
      1 /*
      2  * QEMU live migration
      3  *
      4  * Copyright IBM, Corp. 2008
      5  * Copyright Dell MessageOne 2008
      6  *
      7  * Authors:
      8  *  Anthony Liguori   <aliguori (at) us.ibm.com>
      9  *  Charles Duffy     <charles_duffy (at) messageone.com>
     10  *
     11  * This work is licensed under the terms of the GNU GPL, version 2.  See
     12  * the COPYING file in the top-level directory.
     13  *
     14  */
     15 
     16 #include "qemu-common.h"
     17 #include "qemu_socket.h"
     18 #include "migration.h"
     19 #include "qemu-char.h"
     20 #include "sysemu.h"
     21 #include "buffered_file.h"
     22 #include "block.h"
     23 
     24 //#define DEBUG_MIGRATION_EXEC
     25 
     26 #ifdef DEBUG_MIGRATION_EXEC
     27 #define dprintf(fmt, ...) \
     28     do { printf("migration-exec: " fmt, ## __VA_ARGS__); } while (0)
     29 #else
     30 #define dprintf(fmt, ...) \
     31     do { } while (0)
     32 #endif
     33 
     34 static int file_errno(FdMigrationState *s)
     35 {
     36     return errno;
     37 }
     38 
     39 static int file_write(FdMigrationState *s, const void * buf, size_t size)
     40 {
     41     return write(s->fd, buf, size);
     42 }
     43 
     44 static int exec_close(FdMigrationState *s)
     45 {
     46     dprintf("exec_close\n");
     47     if (s->opaque) {
     48         qemu_fclose(s->opaque);
     49         s->opaque = NULL;
     50         s->fd = -1;
     51     }
     52     return 0;
     53 }
     54 
     55 MigrationState *exec_start_outgoing_migration(const char *command,
     56                                              int64_t bandwidth_limit,
     57                                              int detach)
     58 {
     59     FdMigrationState *s;
     60     FILE *f;
     61 
     62     s = qemu_mallocz(sizeof(*s));
     63 
     64     f = popen(command, "w");
     65     if (f == NULL) {
     66         dprintf("Unable to popen exec target\n");
     67         goto err_after_alloc;
     68     }
     69 
     70     s->fd = fileno(f);
     71     if (s->fd == -1) {
     72         dprintf("Unable to retrieve file descriptor for popen'd handle\n");
     73         goto err_after_open;
     74     }
     75 
     76     if (fcntl(s->fd, F_SETFD, O_NONBLOCK) == -1) {
     77         dprintf("Unable to set nonblocking mode on file descriptor\n");
     78         goto err_after_open;
     79     }
     80 
     81     s->opaque = qemu_popen(f, "w");
     82 
     83     s->close = exec_close;
     84     s->get_error = file_errno;
     85     s->write = file_write;
     86     s->mig_state.cancel = migrate_fd_cancel;
     87     s->mig_state.get_status = migrate_fd_get_status;
     88     s->mig_state.release = migrate_fd_release;
     89 
     90     s->state = MIG_STATE_ACTIVE;
     91     s->mon_resume = NULL;
     92     s->bandwidth_limit = bandwidth_limit;
     93 
     94     if (!detach)
     95         migrate_fd_monitor_suspend(s);
     96 
     97     migrate_fd_connect(s);
     98     return &s->mig_state;
     99 
    100 err_after_open:
    101     pclose(f);
    102 err_after_alloc:
    103     qemu_free(s);
    104     return NULL;
    105 }
    106 
    107 static void exec_accept_incoming_migration(void *opaque)
    108 {
    109     QEMUFile *f = opaque;
    110     int ret;
    111 
    112     vm_stop(0); /* just in case */
    113     ret = qemu_loadvm_state(f);
    114     if (ret < 0) {
    115         fprintf(stderr, "load of migration failed\n");
    116         goto err;
    117     }
    118     qemu_announce_self();
    119     dprintf("successfully loaded vm state\n");
    120     /* we've successfully migrated, close the fd */
    121     qemu_set_fd_handler2(qemu_popen_fd(f), NULL, NULL, NULL, NULL);
    122     vm_start();
    123 
    124 err:
    125     qemu_fclose(f);
    126 }
    127 
    128 int exec_start_incoming_migration(const char *command)
    129 {
    130     QEMUFile *f;
    131 
    132     dprintf("Attempting to start an incoming migration\n");
    133     f = qemu_popen_cmd(command, "r");
    134     if(f == NULL) {
    135         dprintf("Unable to apply qemu wrapper to popen file\n");
    136         return -errno;
    137     }
    138 
    139     qemu_set_fd_handler2(qemu_popen_fd(f), NULL,
    140 			 exec_accept_incoming_migration, NULL,
    141 			 (void *)(unsigned long)f);
    142 
    143     return 0;
    144 }
    145