qemu/migration-unix.c
<<
>>
Prefs
   1/*
   2 * QEMU live migration via Unix Domain Sockets
   3 *
   4 * Copyright Red Hat, Inc. 2009
   5 *
   6 * Authors:
   7 *  Chris Lalancette <clalance@redhat.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2.  See
  10 * the COPYING file in the top-level directory.
  11 *
  12 */
  13
  14#include "qemu-common.h"
  15#include "qemu_socket.h"
  16#include "migration.h"
  17#include "qemu-char.h"
  18#include "buffered_file.h"
  19#include "block.h"
  20
  21//#define DEBUG_MIGRATION_UNIX
  22
  23#ifdef DEBUG_MIGRATION_UNIX
  24#define DPRINTF(fmt, ...) \
  25    do { printf("migration-unix: " fmt, ## __VA_ARGS__); } while (0)
  26#else
  27#define DPRINTF(fmt, ...) \
  28    do { } while (0)
  29#endif
  30
  31static int unix_errno(FdMigrationState *s)
  32{
  33    return errno;
  34}
  35
  36static int unix_write(FdMigrationState *s, const void * buf, size_t size)
  37{
  38    return write(s->fd, buf, size);
  39}
  40
  41static int unix_close(FdMigrationState *s)
  42{
  43    DPRINTF("unix_close\n");
  44    if (s->fd != -1) {
  45        close(s->fd);
  46        s->fd = -1;
  47    }
  48    return 0;
  49}
  50
  51static void unix_wait_for_connect(void *opaque)
  52{
  53    FdMigrationState *s = opaque;
  54    int val, ret;
  55    socklen_t valsize = sizeof(val);
  56
  57    DPRINTF("connect completed\n");
  58    do {
  59        ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
  60    } while (ret == -1 && (s->get_error(s)) == EINTR);
  61
  62    if (ret < 0) {
  63        migrate_fd_error(s);
  64        return;
  65    }
  66
  67    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
  68
  69    if (val == 0)
  70        migrate_fd_connect(s);
  71    else {
  72        DPRINTF("error connecting %d\n", val);
  73        migrate_fd_error(s);
  74    }
  75}
  76
  77MigrationState *unix_start_outgoing_migration(Monitor *mon,
  78                                              const char *path,
  79                                              int64_t bandwidth_limit,
  80                                              int detach,
  81                                              int blk,
  82                                              int inc)
  83{
  84    FdMigrationState *s;
  85    struct sockaddr_un addr;
  86    int ret;
  87
  88    addr.sun_family = AF_UNIX;
  89    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
  90
  91    s = qemu_mallocz(sizeof(*s));
  92
  93    s->get_error = unix_errno;
  94    s->write = unix_write;
  95    s->close = unix_close;
  96    s->mig_state.cancel = migrate_fd_cancel;
  97    s->mig_state.get_status = migrate_fd_get_status;
  98    s->mig_state.release = migrate_fd_release;
  99
 100    s->mig_state.blk = blk;
 101    s->mig_state.shared = inc;
 102
 103    s->state = MIG_STATE_ACTIVE;
 104    s->mon = NULL;
 105    s->bandwidth_limit = bandwidth_limit;
 106    s->fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
 107    if (s->fd < 0) {
 108        DPRINTF("Unable to open socket");
 109        goto err_after_alloc;
 110    }
 111
 112    socket_set_nonblock(s->fd);
 113
 114    do {
 115        ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
 116        if (ret == -1)
 117            ret = -(s->get_error(s));
 118
 119        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
 120            qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s);
 121    } while (ret == -EINTR);
 122
 123    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
 124        DPRINTF("connect failed\n");
 125        goto err_after_open;
 126    }
 127
 128    if (!detach) {
 129        migrate_fd_monitor_suspend(s, mon);
 130    }
 131
 132    if (ret >= 0)
 133        migrate_fd_connect(s);
 134
 135    return &s->mig_state;
 136
 137err_after_open:
 138    close(s->fd);
 139
 140err_after_alloc:
 141    qemu_free(s);
 142    return NULL;
 143}
 144
 145static void unix_accept_incoming_migration(void *opaque)
 146{
 147    struct sockaddr_un addr;
 148    socklen_t addrlen = sizeof(addr);
 149    int s = (intptr_t)opaque;
 150    QEMUFile *f;
 151    int c;
 152
 153    do {
 154        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
 155    } while (c == -1 && socket_error() == EINTR);
 156
 157    DPRINTF("accepted migration\n");
 158
 159    if (c == -1) {
 160        fprintf(stderr, "could not accept migration connection\n");
 161        return;
 162    }
 163
 164    f = qemu_fopen_socket(c);
 165    if (f == NULL) {
 166        fprintf(stderr, "could not qemu_fopen socket\n");
 167        goto out;
 168    }
 169
 170    process_incoming_migration(f);
 171    qemu_fclose(f);
 172out:
 173    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
 174    close(s);
 175    close(c);
 176}
 177
 178int unix_start_incoming_migration(const char *path)
 179{
 180    struct sockaddr_un un;
 181    int sock;
 182
 183    DPRINTF("Attempting to start an incoming migration\n");
 184
 185    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
 186    if (sock < 0) {
 187        fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno));
 188        return -EINVAL;
 189    }
 190
 191    memset(&un, 0, sizeof(un));
 192    un.sun_family = AF_UNIX;
 193    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
 194
 195    unlink(un.sun_path);
 196    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
 197        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
 198        goto err;
 199    }
 200    if (listen(sock, 1) < 0) {
 201        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
 202        goto err;
 203    }
 204
 205    qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL,
 206                         (void *)(intptr_t)sock);
 207
 208    return 0;
 209
 210err:
 211    close(sock);
 212
 213    return -EINVAL;
 214}
 215