提交 b7382e9e 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/juanquintela/tags/pull-migration-pull-request' into staging

Migration pull request

# gpg: Signature made Wed 29 Jan 2020 10:57:23 GMT
# gpg:                using RSA key 1899FF8EDEBF58CCEE034B82F487EF185872D723
# gpg: Good signature from "Juan Quintela <quintela@redhat.com>" [full]
# gpg:                 aka "Juan Quintela <quintela@trasno.org>" [full]
# Primary key fingerprint: 1899 FF8E DEBF 58CC EE03  4B82 F487 EF18 5872 D723

* remotes/juanquintela/tags/pull-migration-pull-request:
  migration/compress: compress QEMUFile is not writable
  migration: Simplify get_qlist
  multifd: Split multifd code into its own file
  multifd: Make multifd_load_setup() get an Error parameter
  multifd: Make multifd_save_setup() get an Error parameter
  migration: Make checkpatch happy with comments
  multifd: Use qemu_target_page_size()
  multifd: multifd_send_sync_main only needs the qemufile
  multifd: multifd_queue_page only needs the qemufile
  multifd: multifd_send_pages only needs the qemufile
  ram_addr: Split RAMBlock definition
  migration/multifd: fix nullptr access in multifd_send_terminate_threads
  migration: Create migration_is_running()
  migration-test: Make sure that multifd and cancel works
  migration: Don't send data if we have stopped
  qemu-file: Don't do IO after shutdown
  multifd: Make sure that we don't do any IO after an error
  migration-test: Use g_free() instead of free()
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
......@@ -1975,6 +1975,7 @@ F: ioport.c
F: include/exec/memop.h
F: include/exec/memory.h
F: include/exec/ram_addr.h
F: include/exec/ramblock.h
F: memory.c
F: include/exec/memory-internal.h
F: exec.c
......
......@@ -24,45 +24,7 @@
#include "hw/xen/xen.h"
#include "sysemu/tcg.h"
#include "exec/ramlist.h"
struct RAMBlock {
struct rcu_head rcu;
struct MemoryRegion *mr;
uint8_t *host;
uint8_t *colo_cache; /* For colo, VM's ram cache */
ram_addr_t offset;
ram_addr_t used_length;
ram_addr_t max_length;
void (*resized)(const char*, uint64_t length, void *host);
uint32_t flags;
/* Protected by iothread lock. */
char idstr[256];
/* RCU-enabled, writes protected by the ramlist lock */
QLIST_ENTRY(RAMBlock) next;
QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
int fd;
size_t page_size;
/* dirty bitmap used during migration */
unsigned long *bmap;
/* bitmap of already received pages in postcopy */
unsigned long *receivedmap;
/*
* bitmap to track already cleared dirty bitmap. When the bit is
* set, it means the corresponding memory chunk needs a log-clear.
* Set this up to non-NULL to enable the capability to postpone
* and split clearing of dirty bitmap on the remote node (e.g.,
* KVM). The bitmap will be set only when doing global sync.
*
* NOTE: this bitmap is different comparing to the other bitmaps
* in that one bit can represent multiple guest pages (which is
* decided by the `clear_bmap_shift' variable below). On
* destination side, this should always be NULL, and the variable
* `clear_bmap_shift' is meaningless.
*/
unsigned long *clear_bmap;
uint8_t clear_bmap_shift;
};
#include "exec/ramblock.h"
/**
* clear_bmap_size: calculate clear bitmap size
......
/*
* Declarations for cpu physical memory functions
*
* Copyright 2011 Red Hat, Inc. and/or its affiliates
*
* Authors:
* Avi Kivity <avi@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* later. See the COPYING file in the top-level directory.
*
*/
/*
* This header is for use by exec.c and memory.c ONLY. Do not include it.
* The functions declared here will be removed soon.
*/
#ifndef QEMU_EXEC_RAMBLOCK_H
#define QEMU_EXEC_RAMBLOCK_H
#ifndef CONFIG_USER_ONLY
#include "cpu-common.h"
struct RAMBlock {
struct rcu_head rcu;
struct MemoryRegion *mr;
uint8_t *host;
uint8_t *colo_cache; /* For colo, VM's ram cache */
ram_addr_t offset;
ram_addr_t used_length;
ram_addr_t max_length;
void (*resized)(const char*, uint64_t length, void *host);
uint32_t flags;
/* Protected by iothread lock. */
char idstr[256];
/* RCU-enabled, writes protected by the ramlist lock */
QLIST_ENTRY(RAMBlock) next;
QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
int fd;
size_t page_size;
/* dirty bitmap used during migration */
unsigned long *bmap;
/* bitmap of already received pages in postcopy */
unsigned long *receivedmap;
/*
* bitmap to track already cleared dirty bitmap. When the bit is
* set, it means the corresponding memory chunk needs a log-clear.
* Set this up to non-NULL to enable the capability to postpone
* and split clearing of dirty bitmap on the remote node (e.g.,
* KVM). The bitmap will be set only when doing global sync.
*
* NOTE: this bitmap is different comparing to the other bitmaps
* in that one bit can represent multiple guest pages (which is
* decided by the `clear_bmap_shift' variable below). On
* destination side, this should always be NULL, and the variable
* `clear_bmap_shift' is meaningless.
*/
unsigned long *clear_bmap;
uint8_t clear_bmap_shift;
};
#endif
#endif
......@@ -515,6 +515,12 @@ union { \
(elm); \
(elm) = *QLIST_RAW_NEXT(elm, entry))
#define QLIST_RAW_INSERT_AFTER(head, prev, elem, entry) do { \
*QLIST_RAW_NEXT(prev, entry) = elem; \
*QLIST_RAW_PREVIOUS(elem, entry) = QLIST_RAW_NEXT(prev, entry); \
*QLIST_RAW_NEXT(elem, entry) = NULL; \
} while (0)
#define QLIST_RAW_INSERT_HEAD(head, elm, entry) do { \
void *first = *QLIST_RAW_FIRST(head); \
*QLIST_RAW_FIRST(head) = elm; \
......@@ -527,17 +533,4 @@ union { \
} \
} while (0)
#define QLIST_RAW_REVERSE(head, elm, entry) do { \
void *iter = *QLIST_RAW_FIRST(head), *prev = NULL, *next; \
while (iter) { \
next = *QLIST_RAW_NEXT(iter, entry); \
*QLIST_RAW_PREVIOUS(iter, entry) = QLIST_RAW_NEXT(next, entry); \
*QLIST_RAW_NEXT(iter, entry) = prev; \
prev = iter; \
iter = next; \
} \
*QLIST_RAW_FIRST(head) = prev; \
*QLIST_RAW_PREVIOUS(prev, entry) = QLIST_RAW_FIRST(head); \
} while (0)
#endif /* QEMU_SYS_QUEUE_H */
......@@ -7,6 +7,7 @@ common-obj-y += qemu-file-channel.o
common-obj-y += xbzrle.o postcopy-ram.o
common-obj-y += qjson.o
common-obj-y += block-dirty-bitmap.o
common-obj-y += multifd.o
common-obj-$(CONFIG_RDMA) += rdma.o
......
......@@ -53,6 +53,7 @@
#include "monitor/monitor.h"
#include "net/announce.h"
#include "qemu/queue.h"
#include "multifd.h"
#define MAX_THROTTLE (32 << 20) /* Migration transfer speed throttling */
......@@ -518,13 +519,23 @@ fail:
exit(EXIT_FAILURE);
}
static void migration_incoming_setup(QEMUFile *f)
/**
* @migration_incoming_setup: Setup incoming migration
*
* Returns 0 for no error or 1 for error
*
* @f: file for main migration channel
* @errp: where to put errors
*/
static int migration_incoming_setup(QEMUFile *f, Error **errp)
{
MigrationIncomingState *mis = migration_incoming_get_current();
Error *local_err = NULL;
if (multifd_load_setup() != 0) {
if (multifd_load_setup(&local_err) != 0) {
/* We haven't been able to create multifd threads
nothing better to do */
error_report_err(local_err);
exit(EXIT_FAILURE);
}
......@@ -532,6 +543,7 @@ static void migration_incoming_setup(QEMUFile *f)
mis->from_src_file = f;
}
qemu_file_set_blocking(f, false);
return 0;
}
void migration_incoming_process(void)
......@@ -572,19 +584,27 @@ static bool postcopy_try_recover(QEMUFile *f)
return false;
}
void migration_fd_process_incoming(QEMUFile *f)
void migration_fd_process_incoming(QEMUFile *f, Error **errp)
{
Error *local_err = NULL;
if (postcopy_try_recover(f)) {
return;
}
migration_incoming_setup(f);
if (migration_incoming_setup(f, &local_err)) {
if (local_err) {
error_propagate(errp, local_err);
}
return;
}
migration_incoming_process();
}
void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
{
MigrationIncomingState *mis = migration_incoming_get_current();
Error *local_err = NULL;
bool start_migration;
if (!mis->from_src_file) {
......@@ -596,7 +616,12 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
return;
}
migration_incoming_setup(f);
if (migration_incoming_setup(f, &local_err)) {
if (local_err) {
error_propagate(errp, local_err);
}
return;
}
/*
* Common migration only needs one channel, so we can start
......@@ -604,7 +629,6 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
*/
start_migration = !migrate_use_multifd();
} else {
Error *local_err = NULL;
/* Multiple connections */
assert(migrate_use_multifd());
start_migration = multifd_recv_new_channel(ioc, &local_err);
......@@ -829,6 +853,27 @@ bool migration_is_setup_or_active(int state)
}
}
bool migration_is_running(int state)
{
switch (state) {
case MIGRATION_STATUS_ACTIVE:
case MIGRATION_STATUS_POSTCOPY_ACTIVE:
case MIGRATION_STATUS_POSTCOPY_PAUSED:
case MIGRATION_STATUS_POSTCOPY_RECOVER:
case MIGRATION_STATUS_SETUP:
case MIGRATION_STATUS_PRE_SWITCHOVER:
case MIGRATION_STATUS_DEVICE:
case MIGRATION_STATUS_WAIT_UNPLUG:
case MIGRATION_STATUS_CANCELLING:
case MIGRATION_STATUS_COLO:
return true;
default:
return false;
}
}
static void populate_time_info(MigrationInfo *info, MigrationState *s)
{
info->has_status = true;
......@@ -1077,7 +1122,7 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
MigrationCapabilityStatusList *cap;
bool cap_list[MIGRATION_CAPABILITY__MAX];
if (migration_is_setup_or_active(s->state)) {
if (migration_is_running(s->state)) {
error_setg(errp, QERR_MIGRATION_ACTIVE);
return;
}
......@@ -1590,7 +1635,7 @@ static void migrate_fd_cancel(MigrationState *s)
do {
old_state = s->state;
if (!migration_is_setup_or_active(old_state)) {
if (!migration_is_running(old_state)) {
break;
}
/* If the migration is paused, kick it out of the pause */
......@@ -1888,9 +1933,7 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,
return true;
}
if (migration_is_setup_or_active(s->state) ||
s->state == MIGRATION_STATUS_CANCELLING ||
s->state == MIGRATION_STATUS_COLO) {
if (migration_is_running(s->state)) {
error_setg(errp, QERR_MIGRATION_ACTIVE);
return false;
}
......@@ -3348,6 +3391,7 @@ static void *migration_thread(void *opaque)
void migrate_fd_connect(MigrationState *s, Error *error_in)
{
Error *local_err = NULL;
int64_t rate_limit;
bool resume = s->state == MIGRATION_STATUS_POSTCOPY_PAUSED;
......@@ -3396,7 +3440,8 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
return;
}
if (multifd_save_setup() != 0) {
if (multifd_save_setup(&local_err) != 0) {
error_report_err(local_err);
migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_FAILED);
migrate_fd_cleanup(s);
......
......@@ -265,7 +265,7 @@ struct MigrationState
void migrate_set_state(int *state, int old_state, int new_state);
void migration_fd_process_incoming(QEMUFile *f);
void migration_fd_process_incoming(QEMUFile *f, Error **errp);
void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp);
void migration_incoming_process(void);
......@@ -279,6 +279,7 @@ void migrate_fd_error(MigrationState *s, const Error *error);
void migrate_fd_connect(MigrationState *s, Error *error_in);
bool migration_is_setup_or_active(int state);
bool migration_is_running(int state);
void migrate_init(MigrationState *s);
bool migration_is_blocked(Error **errp);
......
此差异已折叠。
/*
* Multifd common functions
*
* Copyright (c) 2019-2020 Red Hat Inc
*
* Authors:
* Juan Quintela <quintela@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef QEMU_MIGRATION_MULTIFD_H
#define QEMU_MIGRATION_MULTIFD_H
int multifd_save_setup(Error **errp);
void multifd_save_cleanup(void);
int multifd_load_setup(Error **errp);
int multifd_load_cleanup(Error **errp);
bool multifd_recv_all_channels_created(void);
bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp);
void multifd_recv_sync_main(void);
void multifd_send_sync_main(QEMUFile *f);
int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset);
#define MULTIFD_FLAG_SYNC (1 << 0)
/* This value needs to be a multiple of qemu_target_page_size() */
#define MULTIFD_PACKET_SIZE (512 * 1024)
typedef struct {
uint32_t magic;
uint32_t version;
uint32_t flags;
/* maximum number of allocated pages */
uint32_t pages_alloc;
uint32_t pages_used;
/* size of the next packet that contains pages */
uint32_t next_packet_size;
uint64_t packet_num;
uint64_t unused[4]; /* Reserved for future use */
char ramblock[256];
uint64_t offset[];
} __attribute__((packed)) MultiFDPacket_t;
typedef struct {
/* number of used pages */
uint32_t used;
/* number of allocated pages */
uint32_t allocated;
/* global number of generated multifd packets */
uint64_t packet_num;
/* offset of each page */
ram_addr_t *offset;
/* pointer to each page */
struct iovec *iov;
RAMBlock *block;
} MultiFDPages_t;
typedef struct {
/* this fields are not changed once the thread is created */
/* channel number */
uint8_t id;
/* channel thread name */
char *name;
/* channel thread id */
QemuThread thread;
/* communication channel */
QIOChannel *c;
/* sem where to wait for more work */
QemuSemaphore sem;
/* this mutex protects the following parameters */
QemuMutex mutex;
/* is this channel thread running */
bool running;
/* should this thread finish */
bool quit;
/* thread has work to do */
int pending_job;
/* array of pages to sent */
MultiFDPages_t *pages;
/* packet allocated len */
uint32_t packet_len;
/* pointer to the packet */
MultiFDPacket_t *packet;
/* multifd flags for each packet */
uint32_t flags;
/* size of the next packet that contains pages */
uint32_t next_packet_size;
/* global number of generated multifd packets */
uint64_t packet_num;
/* thread local variables */
/* packets sent through this channel */
uint64_t num_packets;
/* pages sent through this channel */
uint64_t num_pages;
/* syncs main thread and channels */
QemuSemaphore sem_sync;
} MultiFDSendParams;
typedef struct {
/* this fields are not changed once the thread is created */
/* channel number */
uint8_t id;
/* channel thread name */
char *name;
/* channel thread id */
QemuThread thread;
/* communication channel */
QIOChannel *c;
/* this mutex protects the following parameters */
QemuMutex mutex;
/* is this channel thread running */
bool running;
/* should this thread finish */
bool quit;
/* array of pages to receive */
MultiFDPages_t *pages;
/* packet allocated len */
uint32_t packet_len;
/* pointer to the packet */
MultiFDPacket_t *packet;
/* multifd flags for each packet */
uint32_t flags;
/* global number of generated multifd packets */
uint64_t packet_num;
/* thread local variables */
/* size of the next packet that contains pages */
uint32_t next_packet_size;
/* packets sent through this channel */
uint64_t num_packets;
/* pages sent through this channel */
uint64_t num_pages;
/* syncs main thread and channels */
QemuSemaphore sem_sync;
} MultiFDRecvParams;
#endif
......@@ -53,6 +53,8 @@ struct QEMUFile {
int last_error;
Error *last_error_obj;
/* has the file has been shutdown */
bool shutdown;
};
/*
......@@ -61,10 +63,18 @@ struct QEMUFile {
*/
int qemu_file_shutdown(QEMUFile *f)
{
int ret;
f->shutdown = true;
if (!f->ops->shut_down) {
return -ENOSYS;
}
return f->ops->shut_down(f->opaque, true, true, NULL);
ret = f->ops->shut_down(f->opaque, true, true, NULL);
if (!f->last_error) {
qemu_file_set_error(f, -EIO);
}
return ret;
}
/*
......@@ -214,6 +224,9 @@ void qemu_fflush(QEMUFile *f)
return;
}
if (f->shutdown) {
return;
}
if (f->iovcnt > 0) {
expect = iov_size(f->iov, f->iovcnt);
ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos,
......@@ -328,6 +341,10 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
f->buf_index = 0;
f->buf_size = pending;
if (f->shutdown) {
return 0;
}
len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
IO_BUF_SIZE - pending, &local_error);
if (len > 0) {
......@@ -642,6 +659,9 @@ int64_t qemu_ftell(QEMUFile *f)
int qemu_file_rate_limit(QEMUFile *f)
{
if (f->shutdown) {
return 1;
}
if (qemu_file_get_error(f)) {
return 1;
}
......@@ -744,11 +764,8 @@ static int qemu_compress_data(z_stream *stream, uint8_t *dest, size_t dest_len,
/* Compress size bytes of data start at p and store the compressed
* data to the buffer of f.
*
* When f is not writable, return -1 if f has no space to save the
* compressed data.
* When f is wirtable and it has no space to save the compressed data,
* do fflush first, if f still has no space to save the compressed
* data, return -1.
* Since the file is dummy file with empty_ops, return -1 if f has no space to
* save the compressed data.
*/
ssize_t qemu_put_compression_data(QEMUFile *f, z_stream *stream,
const uint8_t *p, size_t size)
......@@ -756,14 +773,7 @@ ssize_t qemu_put_compression_data(QEMUFile *f, z_stream *stream,
ssize_t blen = IO_BUF_SIZE - f->buf_index - sizeof(int32_t);
if (blen < compressBound(size)) {
if (!qemu_file_is_writable(f)) {
return -1;
}
qemu_fflush(f);
blen = IO_BUF_SIZE - sizeof(int32_t);
if (blen < compressBound(size)) {
return -1;
}
return -1;
}
blen = qemu_compress_data(stream, f->buf + f->buf_index + sizeof(int32_t),
......
此差异已折叠。
......@@ -41,13 +41,6 @@ int xbzrle_cache_resize(int64_t new_size, Error **errp);
uint64_t ram_bytes_remaining(void);
uint64_t ram_bytes_total(void);
int multifd_save_setup(void);
void multifd_save_cleanup(void);
int multifd_load_setup(void);
int multifd_load_cleanup(Error **errp);
bool multifd_recv_all_channels_created(void);
bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp);
uint64_t ram_pagesize_summary(void);
int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len);
void acct_update_position(QEMUFile *f, size_t size, bool zero);
......
......@@ -4004,7 +4004,7 @@ static void rdma_accept_incoming_migration(void *opaque)
}
rdma->migration_started_on_destination = 1;
migration_fd_process_incoming(f);
migration_fd_process_incoming(f, errp);
}
void rdma_start_incoming_migration(const char *host_port, Error **errp)
......
......@@ -1531,9 +1531,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
MigrationState *ms = migrate_get_current();
MigrationStatus status;
if (migration_is_setup_or_active(ms->state) ||
ms->state == MIGRATION_STATUS_CANCELLING ||
ms->state == MIGRATION_STATUS_COLO) {
if (migration_is_running(ms->state)) {
error_setg(errp, QERR_MIGRATION_ACTIVE);
return -EINVAL;
}
......
......@@ -879,7 +879,7 @@ static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
/* offset of the QLIST entry in a QLIST element */
size_t entry_offset = field->start;
int version_id = field->version_id;
void *elm;
void *elm, *prev = NULL;
trace_get_qlist(field->name, vmsd->name, vmsd->version_id);
if (version_id > vmsd->version_id) {
......@@ -900,9 +900,13 @@ static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
g_free(elm);
return ret;
}
QLIST_RAW_INSERT_HEAD(pv, elm, entry_offset);
if (!prev) {
QLIST_RAW_INSERT_HEAD(pv, elm, entry_offset);
} else {
QLIST_RAW_INSERT_AFTER(pv, prev, elm, entry_offset);
}
prev = elm;
}
QLIST_RAW_REVERSE(pv, elm, entry_offset);
trace_get_qlist_end(field->name, vmsd->name);
return ret;
......
......@@ -424,6 +424,14 @@ static void migrate_recover(QTestState *who, const char *uri)
qobject_unref(rsp);
}
static void migrate_cancel(QTestState *who)
{
QDict *rsp;
rsp = wait_command(who, "{ 'execute': 'migrate_cancel' }");
qobject_unref(rsp);
}
static void migrate_set_capability(QTestState *who, const char *capability,
bool value)
{
......@@ -456,6 +464,8 @@ static void migrate_postcopy_start(QTestState *from, QTestState *to)
typedef struct {
bool hide_stderr;
bool use_shmem;
/* only launch the target process */
bool only_target;
char *opts_source;
char *opts_target;
} MigrateStart;
......@@ -571,7 +581,9 @@ static int test_migrate_start(QTestState **from, QTestState **to,
arch_source, shmem_opts, args->opts_source,
ignore_stderr);
g_free(arch_source);
*from = qtest_init(cmd_source);
if (!args->only_target) {
*from = qtest_init(cmd_source);
}
g_free(cmd_source);
cmd_target = g_strdup_printf("-accel kvm -accel tcg%s%s "
......@@ -1291,7 +1303,104 @@ static void test_multifd_tcp(void)
wait_for_serial("dest_serial");
wait_for_migration_complete(from);
test_migrate_end(from, to, true);
free(uri);
g_free(uri);
}
/*
* This test does:
* source target
* migrate_incoming
* migrate
* migrate_cancel
* launch another target
* migrate
*
* And see that it works
*/
static void test_multifd_tcp_cancel(void)
{
MigrateStart *args = migrate_start_new();
QTestState *from, *to, *to2;
QDict *rsp;
char *uri;
args->hide_stderr = true;
if (test_migrate_start(&from, &to, "defer", args)) {
return;
}
/*
* We want to pick a speed slow enough that the test completes
* quickly, but that it doesn't complete precopy even on a slow
* machine, so also set the downtime.
*/
/* 1 ms should make it not converge*/
migrate_set_parameter_int(from, "downtime-limit", 1);
/* 300MB/s */
migrate_set_parameter_int(from, "max-bandwidth", 30000000);
migrate_set_parameter_int(from, "multifd-channels", 16);
migrate_set_parameter_int(to, "multifd-channels", 16);
migrate_set_capability(from, "multifd", "true");
migrate_set_capability(to, "multifd", "true");
/* Start incoming migration from the 1st socket */
rsp = wait_command(to, "{ 'execute': 'migrate-incoming',"
" 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}");
qobject_unref(rsp);
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
uri = migrate_get_socket_address(to, "socket-address");
migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from);
migrate_cancel(from);
args = migrate_start_new();
args->only_target = true;
if (test_migrate_start(&from, &to2, "defer", args)) {
return;
}
migrate_set_parameter_int(to2, "multifd-channels", 16);
migrate_set_capability(to2, "multifd", "true");
/* Start incoming migration from the 1st socket */
rsp = wait_command(to2, "{ 'execute': 'migrate-incoming',"
" 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}");
qobject_unref(rsp);
uri = migrate_get_socket_address(to2, "socket-address");
wait_for_migration_status(from, "cancelled", NULL);
/* 300ms it should converge */
migrate_set_parameter_int(from, "downtime-limit", 300);
/* 1GB/s */
migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from);
if (!got_stop) {
qtest_qmp_eventwait(from, "STOP");
}
qtest_qmp_eventwait(to2, "RESUME");
wait_for_serial("dest_serial");
wait_for_migration_complete(from);
test_migrate_end(from, to2, true);
g_free(uri);
}
int main(int argc, char **argv)
......@@ -1359,6 +1468,7 @@ int main(int argc, char **argv)
qtest_add_func("/migration/auto_converge", test_migrate_auto_converge);
qtest_add_func("/migration/multifd/tcp", test_multifd_tcp);
qtest_add_func("/migration/multifd/tcp/cancel", test_multifd_tcp_cancel);
ret = g_test_run();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册