migration.c 12.1 KB
Newer Older
A
aliguori 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * QEMU live migration
 *
 * Copyright IBM, Corp. 2008
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 * the COPYING file in the top-level directory.
 *
 */

#include "qemu-common.h"
#include "migration.h"
A
aliguori 已提交
16
#include "monitor.h"
17 18 19 20
#include "buffered_file.h"
#include "sysemu.h"
#include "block.h"
#include "qemu_socket.h"
21
#include "block-migration.h"
22
#include "qemu-objects.h"
23 24 25 26 27 28 29 30 31 32

//#define DEBUG_MIGRATION

#ifdef DEBUG_MIGRATION
#define dprintf(fmt, ...) \
    do { printf("migration: " fmt, ## __VA_ARGS__); } while (0)
#else
#define dprintf(fmt, ...) \
    do { } while (0)
#endif
A
aliguori 已提交
33 34 35 36 37 38 39 40

/* Migration speed throttling */
static uint32_t max_throttle = (32 << 20);

static MigrationState *current_migration;

void qemu_start_incoming_migration(const char *uri)
{
A
aliguori 已提交
41 42 43 44
    const char *p;

    if (strstart(uri, "tcp:", &p))
        tcp_start_incoming_migration(p);
45 46 47
#if !defined(WIN32)
    else if (strstart(uri, "exec:", &p))
        exec_start_incoming_migration(p);
C
Chris Lalancette 已提交
48 49
    else if (strstart(uri, "unix:", &p))
        unix_start_incoming_migration(p);
P
Paolo Bonzini 已提交
50 51
    else if (strstart(uri, "fd:", &p))
        fd_start_incoming_migration(p);
52
#endif
A
aliguori 已提交
53 54
    else
        fprintf(stderr, "unknown migration protocol: %s\n", uri);
A
aliguori 已提交
55 56
}

57
void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
A
aliguori 已提交
58
{
A
aliguori 已提交
59 60
    MigrationState *s = NULL;
    const char *p;
61 62
    int detach = qdict_get_int(qdict, "detach");
    const char *uri = qdict_get_str(qdict, "uri");
63 64 65 66 67 68 69

    if (current_migration &&
        current_migration->get_status(current_migration) == MIG_STATE_ACTIVE) {
        monitor_printf(mon, "migration already in progress\n");
        return;
    }

A
aliguori 已提交
70
    if (strstart(uri, "tcp:", &p))
71
        s = tcp_start_outgoing_migration(mon, p, max_throttle, detach,
L
lirans@il.ibm.com 已提交
72 73
                                         (int)qdict_get_int(qdict, "blk"), 
                                         (int)qdict_get_int(qdict, "inc"));
74 75
#if !defined(WIN32)
    else if (strstart(uri, "exec:", &p))
76
        s = exec_start_outgoing_migration(mon, p, max_throttle, detach,
L
lirans@il.ibm.com 已提交
77 78
                                          (int)qdict_get_int(qdict, "blk"), 
                                          (int)qdict_get_int(qdict, "inc"));
C
Chris Lalancette 已提交
79
    else if (strstart(uri, "unix:", &p))
80
        s = unix_start_outgoing_migration(mon, p, max_throttle, detach,
L
lirans@il.ibm.com 已提交
81 82
					  (int)qdict_get_int(qdict, "blk"), 
                                          (int)qdict_get_int(qdict, "inc"));
P
Paolo Bonzini 已提交
83
    else if (strstart(uri, "fd:", &p))
L
lirans@il.ibm.com 已提交
84 85 86
        s = fd_start_outgoing_migration(mon, p, max_throttle, detach, 
                                        (int)qdict_get_int(qdict, "blk"), 
                                        (int)qdict_get_int(qdict, "inc"));
87
#endif
A
aliguori 已提交
88
    else
A
aliguori 已提交
89
        monitor_printf(mon, "unknown migration protocol: %s\n", uri);
A
aliguori 已提交
90 91

    if (s == NULL)
A
aliguori 已提交
92
        monitor_printf(mon, "migration failed\n");
A
aliguori 已提交
93
    else {
A
aliguori 已提交
94 95
        if (current_migration)
            current_migration->release(current_migration);
A
aliguori 已提交
96

A
aliguori 已提交
97
        current_migration = s;
A
aliguori 已提交
98
    }
A
aliguori 已提交
99 100
}

101
void do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
A
aliguori 已提交
102 103 104 105
{
    MigrationState *s = current_migration;

    if (s)
A
aliguori 已提交
106
        s->cancel(s);
A
aliguori 已提交
107 108
}

109
void do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
A
aliguori 已提交
110 111
{
    double d;
112
    FdMigrationState *s;
A
aliguori 已提交
113

114 115 116
    d = qdict_get_double(qdict, "value");
    d = MAX(0, MIN(UINT32_MAX, d));
    max_throttle = d;
117

118 119
    s = migrate_to_fms(current_migration);
    if (s && s->file) {
120 121
        qemu_file_set_rate_limit(s->file, max_throttle);
    }
A
aliguori 已提交
122 123
}

124 125 126 127 128 129 130 131 132 133 134
/* amount of nanoseconds we are willing to wait for migration to be down.
 * the choice of nanoseconds is because it is the maximum resolution that
 * get_clock() can achieve. It is an internal measure. All user-visible
 * units must be in seconds */
static uint64_t max_downtime = 30000000;

uint64_t migrate_max_downtime(void)
{
    return max_downtime;
}

135 136
void do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
                             QObject **ret_data)
G
Glauber Costa 已提交
137 138 139
{
    double d;

140 141
    d = qdict_get_double(qdict, "value") * 1e9;
    d = MAX(0, MIN(UINT64_MAX, d));
G
Glauber Costa 已提交
142 143 144
    max_downtime = (uint64_t)d;
}

145 146
static void migrate_print_status(Monitor *mon, const char *name,
                                 const QDict *status_dict)
A
aliguori 已提交
147
{
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
    QDict *qdict;

    qdict = qobject_to_qdict(qdict_get(status_dict, name));

    monitor_printf(mon, "transferred %s: %" PRIu64 " kbytes\n", name,
                        qdict_get_int(qdict, "transferred") >> 10);
    monitor_printf(mon, "remaining %s: %" PRIu64 " kbytes\n", name,
                        qdict_get_int(qdict, "remaining") >> 10);
    monitor_printf(mon, "total %s: %" PRIu64 " kbytes\n", name,
                        qdict_get_int(qdict, "total") >> 10);
}

void do_info_migrate_print(Monitor *mon, const QObject *data)
{
    QDict *qdict;

    qdict = qobject_to_qdict(data);

    monitor_printf(mon, "Migration status: %s\n",
                   qdict_get_str(qdict, "status"));

    if (qdict_haskey(qdict, "ram")) {
        migrate_print_status(mon, "ram", qdict);
    }

    if (qdict_haskey(qdict, "disk")) {
        migrate_print_status(mon, "disk", qdict);
    }
}

static void migrate_put_status(QDict *qdict, const char *name,
                               uint64_t trans, uint64_t rem, uint64_t total)
{
    QObject *obj;

    obj = qobject_from_jsonf("{ 'transferred': %" PRId64 ", "
                               "'remaining': %" PRId64 ", "
                               "'total': %" PRId64 " }", trans, rem, total);
    assert(obj != NULL);

    qdict_put_obj(qdict, name, obj);
}

/**
 * do_info_migrate(): Migration status
 *
 * Return a QDict. If migration is active there will be another
 * QDict with RAM migration status and if block migration is active
 * another one with block migration status.
 *
 * The main QDict contains the following:
 *
 * - "status": migration status
 * - "ram": only present if "status" is "active", it is a QDict with the
 *   following RAM information (in bytes):
 *          - "transferred": amount transferred
 *          - "remaining": amount remaining
 *          - "total": total
 * - "disk": only present if "status" is "active" and it is a block migration,
 *   it is a QDict with the following disk information (in bytes):
 *          - "transferred": amount transferred
 *          - "remaining": amount remaining
 *          - "total": total
 *
 * Examples:
 *
 * 1. Migration is "completed":
 *
 * { "status": "completed" }
 *
 * 2. Migration is "active" and it is not a block migration:
 *
 * { "status": "active",
 *            "ram": { "transferred": 123, "remaining": 123, "total": 246 } }
 *
 * 3. Migration is "active" and it is a block migration:
 *
 * { "status": "active",
 *   "ram": { "total": 1057024, "remaining": 1053304, "transferred": 3720 },
 *   "disk": { "total": 20971520, "remaining": 20880384, "transferred": 91136 }}
 */
void do_info_migrate(Monitor *mon, QObject **ret_data)
{
    QDict *qdict;
A
aliguori 已提交
232
    MigrationState *s = current_migration;
A
aliguori 已提交
233

A
aliguori 已提交
234
    if (s) {
A
aliguori 已提交
235 236
        switch (s->get_status(s)) {
        case MIG_STATE_ACTIVE:
237 238 239 240 241 242
            qdict = qdict_new();
            qdict_put(qdict, "status", qstring_from_str("active"));

            migrate_put_status(qdict, "ram", ram_bytes_transferred(),
                               ram_bytes_remaining(), ram_bytes_total());

243
            if (blk_mig_active()) {
244 245 246
                migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
                                   blk_mig_bytes_remaining(),
                                   blk_mig_bytes_total());
247
            }
248 249

            *ret_data = QOBJECT(qdict);
A
aliguori 已提交
250 251
            break;
        case MIG_STATE_COMPLETED:
252
            *ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
A
aliguori 已提交
253 254
            break;
        case MIG_STATE_ERROR:
255
            *ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
A
aliguori 已提交
256 257
            break;
        case MIG_STATE_CANCELLED:
258
            *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
A
aliguori 已提交
259 260
            break;
        }
261
        assert(*ret_data != NULL);
A
aliguori 已提交
262 263 264
    }
}

265 266
/* shared migration helpers */

267
void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon)
268
{
269 270
    s->mon = mon;
    if (monitor_suspend(mon) == 0) {
271
        dprintf("suspending monitor\n");
272 273
    } else {
        monitor_printf(mon, "terminal does not allow synchronous "
274
                       "migration, continuing detached\n");
275
    }
276 277
}

278 279 280 281 282 283 284 285 286 287 288 289 290 291
void migrate_fd_error(FdMigrationState *s)
{
    dprintf("setting error state\n");
    s->state = MIG_STATE_ERROR;
    migrate_fd_cleanup(s);
}

void migrate_fd_cleanup(FdMigrationState *s)
{
    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);

    if (s->file) {
        dprintf("closing file\n");
        qemu_fclose(s->file);
292
        s->file = NULL;
293 294 295 296 297 298
    }

    if (s->fd != -1)
        close(s->fd);

    /* Don't resume monitor until we've flushed all of the buffers */
299 300 301
    if (s->mon) {
        monitor_resume(s->mon);
    }
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320

    s->fd = -1;
}

void migrate_fd_put_notify(void *opaque)
{
    FdMigrationState *s = opaque;

    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
    qemu_file_put_notify(s->file);
}

ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
{
    FdMigrationState *s = opaque;
    ssize_t ret;

    do {
        ret = s->write(s, data, size);
321
    } while (ret == -1 && ((s->get_error(s)) == EINTR));
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343

    if (ret == -1)
        ret = -(s->get_error(s));

    if (ret == -EAGAIN)
        qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s);

    return ret;
}

void migrate_fd_connect(FdMigrationState *s)
{
    int ret;

    s->file = qemu_fopen_ops_buffered(s,
                                      s->bandwidth_limit,
                                      migrate_fd_put_buffer,
                                      migrate_fd_put_ready,
                                      migrate_fd_wait_for_unfreeze,
                                      migrate_fd_close);

    dprintf("beginning savevm\n");
344
    ret = qemu_savevm_state_begin(s->mon, s->file, s->mig_state.blk,
L
lirans@il.ibm.com 已提交
345
                                  s->mig_state.shared);
346 347 348 349 350
    if (ret < 0) {
        dprintf("failed, %d\n", ret);
        migrate_fd_error(s);
        return;
    }
L
lirans@il.ibm.com 已提交
351
    
352 353 354 355 356 357 358 359 360 361 362 363 364
    migrate_fd_put_ready(s);
}

void migrate_fd_put_ready(void *opaque)
{
    FdMigrationState *s = opaque;

    if (s->state != MIG_STATE_ACTIVE) {
        dprintf("put_ready returning because of non-active state\n");
        return;
    }

    dprintf("iterate\n");
365
    if (qemu_savevm_state_iterate(s->mon, s->file) == 1) {
366
        int state;
367 368
        int old_vm_running = vm_running;

369 370 371
        dprintf("done iterating\n");
        vm_stop(0);

G
Glauber Costa 已提交
372
        qemu_aio_flush();
373
        bdrv_flush_all();
374
        if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) {
375 376 377
            if (old_vm_running) {
                vm_start();
            }
378 379 380 381
            state = MIG_STATE_ERROR;
        } else {
            state = MIG_STATE_COMPLETED;
        }
382
        migrate_fd_cleanup(s);
383
        s->state = state;
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
    }
}

int migrate_fd_get_status(MigrationState *mig_state)
{
    FdMigrationState *s = migrate_to_fms(mig_state);
    return s->state;
}

void migrate_fd_cancel(MigrationState *mig_state)
{
    FdMigrationState *s = migrate_to_fms(mig_state);

    if (s->state != MIG_STATE_ACTIVE)
        return;

    dprintf("cancelling migration\n");

    s->state = MIG_STATE_CANCELLED;
403
    qemu_savevm_state_cancel(s->mon, s->file);
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442

    migrate_fd_cleanup(s);
}

void migrate_fd_release(MigrationState *mig_state)
{
    FdMigrationState *s = migrate_to_fms(mig_state);

    dprintf("releasing state\n");
   
    if (s->state == MIG_STATE_ACTIVE) {
        s->state = MIG_STATE_CANCELLED;
        migrate_fd_cleanup(s);
    }
    free(s);
}

void migrate_fd_wait_for_unfreeze(void *opaque)
{
    FdMigrationState *s = opaque;
    int ret;

    dprintf("wait for unfreeze\n");
    if (s->state != MIG_STATE_ACTIVE)
        return;

    do {
        fd_set wfds;

        FD_ZERO(&wfds);
        FD_SET(s->fd, &wfds);

        ret = select(s->fd + 1, NULL, &wfds, NULL, NULL);
    } while (ret == -1 && (s->get_error(s)) == EINTR);
}

int migrate_fd_close(void *opaque)
{
    FdMigrationState *s = opaque;
443 444

    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
445 446
    return s->close(s);
}