migration/next for 20161014

-----BEGIN PGP SIGNATURE-----
 
 iQIcBAABCAAGBQJYAPidAAoJEPSH7xhYctcjgakP/0M4gXnf5HpEPrF2y5fWOrds
 9/65UEdkg466tyshu8gY2YWjNNLh65psNiD1eDwwUbOBydapAai8dJiaqlO4/vvz
 le0ctBMv34FUQ4bTYMpf9ZaKK3gplNQWZp70DXZ7d4LKNNPPbqiCK1vaMwZkT2bM
 3cal8IsWaDVcUnN3C85FlgGuS43IDNmbzMd7/WZKNZX/u9dcn/Fg1LMMmpIMl1IM
 o+i9jJv4MAyBqTQ4FMcvGJZ6uFVHz/GftYVCshCG6acU1Qoeq3KsInk41Ev0N8wO
 RRWOelbcSlug1HshQbKiJcEFajZT/2zIdMMA+xAmwTnCRufH8OMeQAAByRjArQLZ
 bfuZZpdRSQdhQwEt5Tad7t+oPDFXYWkiNiZo8CQFnXRSwMiKP0XCW7clphCUNeCV
 tyG5njvHuM1WqsXG0qhSVXUWvshSk4XBlNgiCn7Et1sM0mZNEnNaKGl6TCJwWaO3
 pbm021zxyY7jJl3FDptnRdqhUJHqLqnmj5A0kIVMzsTTz1LCliyhjSmtVBfpi3bu
 dTPYheUvsvOrWgcFwEBlcFMjXWHRB6UqEHeRm4eKnoB3ewkMPfW2sl5W+gCwAoGj
 aINiBIHPm0plfnWnv+D7AKzWolHsyM5aHdLUjrnFfDqahqZc+zGib63c7A1Kn4Fv
 2+OTc+a9ckGC7VahqS0E
 =Gd97
 -----END PGP SIGNATURE-----

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

migration/next for 20161014

# gpg: Signature made Fri 14 Oct 2016 16:24:13 BST
# gpg:                using RSA key 0xF487EF185872D723
# gpg: Good signature from "Juan Quintela <quintela@redhat.com>"
# gpg:                 aka "Juan Quintela <quintela@trasno.org>"
# Primary key fingerprint: 1899 FF8E DEBF 58CC EE03  4B82 F487 EF18 5872 D723

* remotes/juanquintela/tags/migration/20161014:
  docs/xbzrle: correction
  migrate: move max-bandwidth and downtime-limit to migrate_set_parameter
  migration: Fix seg with missing port
  migration/postcopy: Explicitly disallow huge pages
  RAMBlocks: Store page size
  Postcopy vs xbzrle: Don't send xbzrle pages once in postcopy [for 2.8]
  migrate: Fix bounds check for migration parameters in migration.c
  migrate: Use boxed qapi for migrate-set-parameters
  migrate: Share common MigrationParameters struct
  migrate: Fix cpu-throttle-increment regression in HMP
  migration/rdma: Don't flag an error when we've been told about one
  migration: Make failed migration load set file error
  migration/rdma: Pass qemu_file errors across link
  migration: Report values for comparisons
  migration: report an error giving the failed field

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-10-17 10:31:10 +01:00
commit 4378caf59e
15 changed files with 282 additions and 183 deletions

View File

@ -2910,7 +2910,9 @@ Set migration parameters
throttled for auto-converge (json-int)
- "cpu-throttle-increment": set throttle increasing percentage for
auto-converge (json-int)
- "max-bandwidth": set maximum speed for migrations (in bytes/sec) (json-int)
- "downtime-limit": set maximum tolerated downtime (in milliseconds) for
migrations (json-int)
Arguments:
Example:
@ -2931,7 +2933,10 @@ Query current migration parameters
throttled (json-int)
- "cpu-throttle-increment" : throttle increasing percentage for
auto-converge (json-int)
- "max-bandwidth" : maximium migration speed in bytes per second
(json-int)
- "downtime-limit" : maximum tolerated downtime of migration in
milliseconds (json-int)
Arguments:
Example:
@ -2943,7 +2948,9 @@ Example:
"cpu-throttle-increment": 10,
"compress-threads": 8,
"compress-level": 1,
"cpu-throttle-initial": 20
"cpu-throttle-initial": 20,
"max-bandwidth": 33554432,
"downtime-limit": 300
}
}

View File

@ -42,7 +42,7 @@ nzrun = length byte...
length = uleb128 encoded integer
On the sender side XBZRLE is used as a compact delta encoding of page updates,
retrieving the old page content from the cache (default size of 512 MB). The
retrieving the old page content from the cache (default size of 64MB). The
receiving side uses the existing page's content and XBZRLE to decode the new
page's content.
@ -73,7 +73,7 @@ e9 07 0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 03 01 67 01 01 69
Cache update strategy
=====================
Keeping the hot pages in the cache is effective for decreased cache
Keeping the hot pages in the cache is effective for decreasing cache
misses. XBZRLE uses a counter as the age of each page. The counter will
increase after each ram dirty bitmap sync. When a cache conflict is
detected, XBZRLE will only evict pages in the cache that are older than

19
exec.c
View File

@ -1199,7 +1199,6 @@ static void *file_ram_alloc(RAMBlock *block,
char *c;
void *area = MAP_FAILED;
int fd = -1;
int64_t page_size;
if (kvm_enabled() && !kvm_has_sync_mmu()) {
error_setg(errp,
@ -1254,17 +1253,17 @@ static void *file_ram_alloc(RAMBlock *block,
*/
}
page_size = qemu_fd_getpagesize(fd);
block->mr->align = MAX(page_size, QEMU_VMALLOC_ALIGN);
block->page_size = qemu_fd_getpagesize(fd);
block->mr->align = MAX(block->page_size, QEMU_VMALLOC_ALIGN);
if (memory < page_size) {
if (memory < block->page_size) {
error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
"or larger than page size 0x%" PRIx64,
memory, page_size);
"or larger than page size 0x%zx",
memory, block->page_size);
goto error;
}
memory = ROUND_UP(memory, page_size);
memory = ROUND_UP(memory, block->page_size);
/*
* ftruncate is not supported by hugetlbfs in older
@ -1419,6 +1418,11 @@ void qemu_ram_unset_idstr(RAMBlock *block)
}
}
size_t qemu_ram_pagesize(RAMBlock *rb)
{
return rb->page_size;
}
static int memory_try_enable_merging(void *addr, size_t len)
{
if (!machine_mem_merge(current_machine)) {
@ -1658,6 +1662,7 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
new_block->max_length = max_size;
assert(max_size >= size);
new_block->fd = -1;
new_block->page_size = getpagesize();
new_block->host = host;
if (host) {
new_block->flags |= RAM_PREALLOC;

77
hmp.c
View File

@ -284,27 +284,40 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
if (params) {
monitor_printf(mon, "parameters:");
assert(params->has_compress_level);
monitor_printf(mon, " %s: %" PRId64,
MigrationParameter_lookup[MIGRATION_PARAMETER_COMPRESS_LEVEL],
params->compress_level);
assert(params->has_compress_threads);
monitor_printf(mon, " %s: %" PRId64,
MigrationParameter_lookup[MIGRATION_PARAMETER_COMPRESS_THREADS],
params->compress_threads);
assert(params->has_decompress_threads);
monitor_printf(mon, " %s: %" PRId64,
MigrationParameter_lookup[MIGRATION_PARAMETER_DECOMPRESS_THREADS],
params->decompress_threads);
assert(params->has_cpu_throttle_initial);
monitor_printf(mon, " %s: %" PRId64,
MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL],
params->cpu_throttle_initial);
assert(params->has_cpu_throttle_increment);
monitor_printf(mon, " %s: %" PRId64,
MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT],
params->cpu_throttle_increment);
monitor_printf(mon, " %s: '%s'",
MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_CREDS],
params->tls_creds ? : "");
params->has_tls_creds ? params->tls_creds : "");
monitor_printf(mon, " %s: '%s'",
MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_HOSTNAME],
params->tls_hostname ? : "");
params->has_tls_hostname ? params->tls_hostname : "");
assert(params->has_max_bandwidth);
monitor_printf(mon, " %s: %" PRId64 " bytes/second",
MigrationParameter_lookup[MIGRATION_PARAMETER_MAX_BANDWIDTH],
params->max_bandwidth);
assert(params->has_downtime_limit);
monitor_printf(mon, " %s: %" PRId64 " milliseconds",
MigrationParameter_lookup[MIGRATION_PARAMETER_DOWNTIME_LIMIT],
params->downtime_limit);
monitor_printf(mon, "\n");
}
@ -1260,6 +1273,7 @@ void hmp_migrate_incoming(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &err);
}
/* Kept for backwards compatibility */
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict)
{
double value = qdict_get_double(qdict, "value");
@ -1278,6 +1292,7 @@ void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict)
}
}
/* Kept for backwards compatibility */
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
{
int64_t value = qdict_get_int(qdict, "value");
@ -1318,45 +1333,58 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
{
const char *param = qdict_get_str(qdict, "parameter");
const char *valuestr = qdict_get_str(qdict, "value");
int64_t valuebw = 0;
long valueint = 0;
char *endp;
Error *err = NULL;
bool has_compress_level = false;
bool has_compress_threads = false;
bool has_decompress_threads = false;
bool has_cpu_throttle_initial = false;
bool has_cpu_throttle_increment = false;
bool has_tls_creds = false;
bool has_tls_hostname = false;
bool use_int_value = false;
int i;
for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
if (strcmp(param, MigrationParameter_lookup[i]) == 0) {
MigrationParameters p = { 0 };
switch (i) {
case MIGRATION_PARAMETER_COMPRESS_LEVEL:
has_compress_level = true;
p.has_compress_level = true;
use_int_value = true;
break;
case MIGRATION_PARAMETER_COMPRESS_THREADS:
has_compress_threads = true;
p.has_compress_threads = true;
use_int_value = true;
break;
case MIGRATION_PARAMETER_DECOMPRESS_THREADS:
has_decompress_threads = true;
p.has_decompress_threads = true;
use_int_value = true;
break;
case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL:
has_cpu_throttle_initial = true;
p.has_cpu_throttle_initial = true;
use_int_value = true;
break;
case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT:
has_cpu_throttle_increment = true;
p.has_cpu_throttle_increment = true;
use_int_value = true;
break;
case MIGRATION_PARAMETER_TLS_CREDS:
has_tls_creds = true;
p.has_tls_creds = true;
p.tls_creds = (char *) valuestr;
break;
case MIGRATION_PARAMETER_TLS_HOSTNAME:
has_tls_hostname = true;
p.has_tls_hostname = true;
p.tls_hostname = (char *) valuestr;
break;
case MIGRATION_PARAMETER_MAX_BANDWIDTH:
p.has_max_bandwidth = true;
valuebw = qemu_strtosz(valuestr, &endp);
if (valuebw < 0 || (size_t)valuebw != valuebw
|| *endp != '\0') {
error_setg(&err, "Invalid size %s", valuestr);
goto cleanup;
}
p.max_bandwidth = valuebw;
break;
case MIGRATION_PARAMETER_DOWNTIME_LIMIT:
p.has_downtime_limit = true;
use_int_value = true;
break;
}
@ -1366,16 +1394,17 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
valuestr);
goto cleanup;
}
/* Set all integers; only one has_FOO will be set, and
* the code ignores the remaining values */
p.compress_level = valueint;
p.compress_threads = valueint;
p.decompress_threads = valueint;
p.cpu_throttle_initial = valueint;
p.cpu_throttle_increment = valueint;
p.downtime_limit = valueint;
}
qmp_migrate_set_parameters(has_compress_level, valueint,
has_compress_threads, valueint,
has_decompress_threads, valueint,
has_cpu_throttle_initial, valueint,
has_cpu_throttle_increment, valueint,
has_tls_creds, valuestr,
has_tls_hostname, valuestr,
&err);
qmp_migrate_set_parameters(&p, &err);
break;
}
}

View File

@ -63,6 +63,7 @@ RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset,
void qemu_ram_set_idstr(RAMBlock *block, const char *name, DeviceState *dev);
void qemu_ram_unset_idstr(RAMBlock *block);
const char *qemu_ram_get_idstr(RAMBlock *rb);
size_t qemu_ram_pagesize(RAMBlock *block);
void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
int len, int is_write);

View File

@ -36,6 +36,7 @@ struct RAMBlock {
/* RCU-enabled, writes protected by the ramlist lock */
QLIST_ENTRY(RAMBlock) next;
int fd;
size_t page_size;
};
static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset)

View File

@ -129,7 +129,6 @@ struct MigrationSrcPageRequest {
struct MigrationState
{
int64_t bandwidth_limit;
size_t bytes_xfer;
size_t xfer_limit;
QemuThread thread;

View File

@ -44,6 +44,10 @@
#define BUFFER_DELAY 100
#define XFER_LIMIT_RATIO (1000 / BUFFER_DELAY)
/* Time in milliseconds we are allowed to stop the source,
* for sending the last part */
#define DEFAULT_MIGRATE_SET_DOWNTIME 300
/* Default compression thread count */
#define DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT 8
/* Default decompression thread count, usually decompression is at
@ -80,7 +84,6 @@ MigrationState *migrate_get_current(void)
static bool once;
static MigrationState current_migration = {
.state = MIGRATION_STATUS_NONE,
.bandwidth_limit = MAX_THROTTLE,
.xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE,
.mbps = -1,
.parameters = {
@ -89,6 +92,8 @@ MigrationState *migrate_get_current(void)
.decompress_threads = DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT,
.cpu_throttle_initial = DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL,
.cpu_throttle_increment = DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT,
.max_bandwidth = MAX_THROTTLE,
.downtime_limit = DEFAULT_MIGRATE_SET_DOWNTIME,
},
};
@ -517,17 +522,6 @@ void migrate_send_rp_pong(MigrationIncomingState *mis,
migrate_send_rp_message(mis, MIG_RP_MSG_PONG, sizeof(buf), &buf);
}
/* 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 = 300000000;
uint64_t migrate_max_downtime(void)
{
return max_downtime;
}
MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
{
MigrationCapabilityStatusList *head = NULL;
@ -559,13 +553,24 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
MigrationState *s = migrate_get_current();
params = g_malloc0(sizeof(*params));
params->has_compress_level = true;
params->compress_level = s->parameters.compress_level;
params->has_compress_threads = true;
params->compress_threads = s->parameters.compress_threads;
params->has_decompress_threads = true;
params->decompress_threads = s->parameters.decompress_threads;
params->has_cpu_throttle_initial = true;
params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
params->has_cpu_throttle_increment = true;
params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
params->has_tls_creds = !!s->parameters.tls_creds;
params->tls_creds = g_strdup(s->parameters.tls_creds);
params->has_tls_hostname = !!s->parameters.tls_hostname;
params->tls_hostname = g_strdup(s->parameters.tls_hostname);
params->has_max_bandwidth = true;
params->max_bandwidth = s->parameters.max_bandwidth;
params->has_downtime_limit = true;
params->downtime_limit = s->parameters.downtime_limit;
return params;
}
@ -759,78 +764,92 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
}
}
void qmp_migrate_set_parameters(bool has_compress_level,
int64_t compress_level,
bool has_compress_threads,
int64_t compress_threads,
bool has_decompress_threads,
int64_t decompress_threads,
bool has_cpu_throttle_initial,
int64_t cpu_throttle_initial,
bool has_cpu_throttle_increment,
int64_t cpu_throttle_increment,
bool has_tls_creds,
const char *tls_creds,
bool has_tls_hostname,
const char *tls_hostname,
Error **errp)
void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
{
MigrationState *s = migrate_get_current();
if (has_compress_level && (compress_level < 0 || compress_level > 9)) {
if (params->has_compress_level &&
(params->compress_level < 0 || params->compress_level > 9)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level",
"is invalid, it should be in the range of 0 to 9");
return;
}
if (has_compress_threads &&
(compress_threads < 1 || compress_threads > 255)) {
if (params->has_compress_threads &&
(params->compress_threads < 1 || params->compress_threads > 255)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"compress_threads",
"is invalid, it should be in the range of 1 to 255");
return;
}
if (has_decompress_threads &&
(decompress_threads < 1 || decompress_threads > 255)) {
if (params->has_decompress_threads &&
(params->decompress_threads < 1 || params->decompress_threads > 255)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"decompress_threads",
"is invalid, it should be in the range of 1 to 255");
return;
}
if (has_cpu_throttle_initial &&
(cpu_throttle_initial < 1 || cpu_throttle_initial > 99)) {
if (params->has_cpu_throttle_initial &&
(params->cpu_throttle_initial < 1 ||
params->cpu_throttle_initial > 99)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"cpu_throttle_initial",
"an integer in the range of 1 to 99");
return;
}
if (has_cpu_throttle_increment &&
(cpu_throttle_increment < 1 || cpu_throttle_increment > 99)) {
if (params->has_cpu_throttle_increment &&
(params->cpu_throttle_increment < 1 ||
params->cpu_throttle_increment > 99)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"cpu_throttle_increment",
"an integer in the range of 1 to 99");
return;
}
if (params->has_max_bandwidth &&
(params->max_bandwidth < 0 || params->max_bandwidth > SIZE_MAX)) {
error_setg(errp, "Parameter 'max_bandwidth' expects an integer in the"
" range of 0 to %zu bytes/second", SIZE_MAX);
return;
}
if (params->has_downtime_limit &&
(params->downtime_limit < 0 || params->downtime_limit > 2000000)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"downtime_limit",
"an integer in the range of 0 to 2000000 milliseconds");
return;
}
if (has_compress_level) {
s->parameters.compress_level = compress_level;
if (params->has_compress_level) {
s->parameters.compress_level = params->compress_level;
}
if (has_compress_threads) {
s->parameters.compress_threads = compress_threads;
if (params->has_compress_threads) {
s->parameters.compress_threads = params->compress_threads;
}
if (has_decompress_threads) {
s->parameters.decompress_threads = decompress_threads;
if (params->has_decompress_threads) {
s->parameters.decompress_threads = params->decompress_threads;
}
if (has_cpu_throttle_initial) {
s->parameters.cpu_throttle_initial = cpu_throttle_initial;
if (params->has_cpu_throttle_initial) {
s->parameters.cpu_throttle_initial = params->cpu_throttle_initial;
}
if (has_cpu_throttle_increment) {
s->parameters.cpu_throttle_increment = cpu_throttle_increment;
if (params->has_cpu_throttle_increment) {
s->parameters.cpu_throttle_increment = params->cpu_throttle_increment;
}
if (has_tls_creds) {
if (params->has_tls_creds) {
g_free(s->parameters.tls_creds);
s->parameters.tls_creds = g_strdup(tls_creds);
s->parameters.tls_creds = g_strdup(params->tls_creds);
}
if (has_tls_hostname) {
if (params->has_tls_hostname) {
g_free(s->parameters.tls_hostname);
s->parameters.tls_hostname = g_strdup(tls_hostname);
s->parameters.tls_hostname = g_strdup(params->tls_hostname);
}
if (params->has_max_bandwidth) {
s->parameters.max_bandwidth = params->max_bandwidth;
if (s->to_dst_file) {
qemu_file_set_rate_limit(s->to_dst_file,
s->parameters.max_bandwidth / XFER_LIMIT_RATIO);
}
}
if (params->has_downtime_limit) {
s->parameters.downtime_limit = params->downtime_limit;
}
}
@ -1165,28 +1184,25 @@ int64_t qmp_query_migrate_cache_size(Error **errp)
void qmp_migrate_set_speed(int64_t value, Error **errp)
{
MigrationState *s;
MigrationParameters p = {
.has_max_bandwidth = true,
.max_bandwidth = value,
};
if (value < 0) {
value = 0;
}
if (value > SIZE_MAX) {
value = SIZE_MAX;
}
s = migrate_get_current();
s->bandwidth_limit = value;
if (s->to_dst_file) {
qemu_file_set_rate_limit(s->to_dst_file,
s->bandwidth_limit / XFER_LIMIT_RATIO);
}
qmp_migrate_set_parameters(&p, errp);
}
void qmp_migrate_set_downtime(double value, Error **errp)
{
value *= 1e9;
value = MAX(0, MIN(UINT64_MAX, value));
max_downtime = (uint64_t)value;
value *= 1000; /* Convert to milliseconds */
value = MAX(0, MIN(INT64_MAX, value));
MigrationParameters p = {
.has_downtime_limit = true,
.downtime_limit = value,
};
qmp_migrate_set_parameters(&p, errp);
}
bool migrate_postcopy_ram(void)
@ -1793,7 +1809,7 @@ static void *migration_thread(void *opaque)
initial_bytes;
uint64_t time_spent = current_time - initial_time;
double bandwidth = (double)transferred_bytes / time_spent;
max_size = bandwidth * migrate_max_downtime() / 1000000;
max_size = bandwidth * s->parameters.downtime_limit;
s->mbps = (((double) transferred_bytes * 8.0) /
((double) time_spent / 1000.0)) / 1000.0 / 1000.0;
@ -1852,13 +1868,12 @@ static void *migration_thread(void *opaque)
void migrate_fd_connect(MigrationState *s)
{
/* This is a best 1st approximation. ns to ms */
s->expected_downtime = max_downtime/1000000;
s->expected_downtime = s->parameters.downtime_limit;
s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
qemu_file_set_blocking(s->to_dst_file, true);
qemu_file_set_rate_limit(s->to_dst_file,
s->bandwidth_limit / XFER_LIMIT_RATIO);
s->parameters.max_bandwidth / XFER_LIMIT_RATIO);
/* Notify before starting migration thread */
notifier_list_notify(&migration_state_notifiers, s);

View File

@ -84,6 +84,24 @@ static bool ufd_version_check(int ufd)
return true;
}
/*
* Check for things that postcopy won't support; returns 0 if the block
* is fine.
*/
static int check_range(const char *block_name, void *host_addr,
ram_addr_t offset, ram_addr_t length, void *opaque)
{
RAMBlock *rb = qemu_ram_block_by_name(block_name);
if (qemu_ram_pagesize(rb) > getpagesize()) {
error_report("Postcopy doesn't support large page sizes yet (%s)",
block_name);
return -E2BIG;
}
return 0;
}
/*
* Note: This has the side effect of munlock'ing all of RAM, that's
* normally fine since if the postcopy succeeds it gets turned back on at the
@ -104,6 +122,12 @@ bool postcopy_ram_supported_by_host(void)
goto out;
}
/* Check for anything about the RAMBlocks we don't support */
if (qemu_ram_foreach_block(check_range, NULL)) {
/* check_range will have printed its own error */
goto out;
}
ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
if (ufd == -1) {
error_report("%s: userfaultfd not available: %s", __func__,

View File

@ -771,7 +771,9 @@ static int ram_save_page(QEMUFile *f, PageSearchStatus *pss,
* page would be stale
*/
xbzrle_cache_zero_page(current_addr);
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
} else if (!ram_bulk_stage &&
!migration_in_postcopy(migrate_get_current()) &&
migrate_use_xbzrle()) {
pages = save_xbzrle_page(f, &p, current_addr, block,
offset, last_stage, bytes_transferred);
if (!last_stage) {

View File

@ -350,6 +350,7 @@ typedef struct RDMAContext {
*/
int error_state;
int error_reported;
int received_error;
/*
* Description of ram blocks used throughout the code.
@ -1676,6 +1677,9 @@ static int qemu_rdma_exchange_get_response(RDMAContext *rdma,
", but got: %s (%d), length: %d",
control_desc[expecting], expecting,
control_desc[head->type], head->type, head->len);
if (head->type == RDMA_CONTROL_ERROR) {
rdma->received_error = true;
}
return -EIO;
}
if (head->len > RDMA_CONTROL_MAX_BUFFER - sizeof(*head)) {
@ -2202,7 +2206,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma)
int ret, idx;
if (rdma->cm_id && rdma->connected) {
if (rdma->error_state) {
if (rdma->error_state && !rdma->received_error) {
RDMAControlHeader head = { .len = 0,
.type = RDMA_CONTROL_ERROR,
.repeat = 1,
@ -2804,6 +2808,9 @@ static int qio_channel_rdma_close(QIOChannel *ioc,
QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
trace_qemu_rdma_close();
if (rioc->rdma) {
if (!rioc->rdma->error_state) {
rioc->rdma->error_state = qemu_file_get_error(rioc->file);
}
qemu_rdma_cleanup(rioc->rdma);
g_free(rioc->rdma);
rioc->rdma = NULL;

View File

@ -1828,40 +1828,45 @@ qemu_loadvm_section_part_end(QEMUFile *f, MigrationIncomingState *mis)
static int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis)
{
uint8_t section_type;
int ret;
int ret = 0;
while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
ret = 0;
trace_qemu_loadvm_state_section(section_type);
switch (section_type) {
case QEMU_VM_SECTION_START:
case QEMU_VM_SECTION_FULL:
ret = qemu_loadvm_section_start_full(f, mis);
if (ret < 0) {
return ret;
goto out;
}
break;
case QEMU_VM_SECTION_PART:
case QEMU_VM_SECTION_END:
ret = qemu_loadvm_section_part_end(f, mis);
if (ret < 0) {
return ret;
goto out;
}
break;
case QEMU_VM_COMMAND:
ret = loadvm_process_command(f);
trace_qemu_loadvm_state_section_command(ret);
if ((ret < 0) || (ret & LOADVM_QUIT)) {
return ret;
goto out;
}
break;
default:
error_report("Unknown savevm section type %d", section_type);
return -EINVAL;
ret = -EINVAL;
goto out;
}
}
return 0;
out:
if (ret < 0) {
qemu_file_set_error(f, ret);
}
return ret;
}
int qemu_loadvm_state(QEMUFile *f)

View File

@ -112,8 +112,12 @@ void tcp_start_outgoing_migration(MigrationState *s,
const char *host_port,
Error **errp)
{
SocketAddress *saddr = tcp_build_address(host_port, errp);
socket_start_outgoing_migration(s, saddr, errp);
Error *err = NULL;
SocketAddress *saddr = tcp_build_address(host_port, &err);
if (!err) {
socket_start_outgoing_migration(s, saddr, &err);
}
error_propagate(errp, err);
}
void unix_start_outgoing_migration(MigrationState *s,
@ -174,8 +178,12 @@ static void socket_start_incoming_migration(SocketAddress *saddr,
void tcp_start_incoming_migration(const char *host_port, Error **errp)
{
SocketAddress *saddr = tcp_build_address(host_port, errp);
socket_start_incoming_migration(saddr, errp);
Error *err = NULL;
SocketAddress *saddr = tcp_build_address(host_port, &err);
if (!err) {
socket_start_incoming_migration(saddr, &err);
}
error_propagate(errp, err);
}
void unix_start_incoming_migration(const char *path, Error **errp)

View File

@ -130,6 +130,8 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
}
if (ret < 0) {
qemu_file_set_error(f, ret);
error_report("Failed to load %s:%s", vmsd->name,
field->name);
trace_vmstate_load_field_error(field->name, ret);
return ret;
}
@ -555,6 +557,7 @@ static int get_int32_equal(QEMUFile *f, void *pv, size_t size)
if (*v == v2) {
return 0;
}
error_report("%" PRIx32 " != %" PRIx32, *v, v2);
return -EINVAL;
}
@ -578,6 +581,9 @@ static int get_int32_le(QEMUFile *f, void *pv, size_t size)
*cur = loaded;
return 0;
}
error_report("Invalid value %" PRId32
" expecting positive value <= %" PRId32,
loaded, *cur);
return -EINVAL;
}
@ -683,6 +689,7 @@ static int get_uint32_equal(QEMUFile *f, void *pv, size_t size)
if (*v == v2) {
return 0;
}
error_report("%" PRIx32 " != %" PRIx32, *v, v2);
return -EINVAL;
}
@ -725,6 +732,7 @@ static int get_uint64_equal(QEMUFile *f, void *pv, size_t size)
if (*v == v2) {
return 0;
}
error_report("%" PRIx64 " != %" PRIx64, *v, v2);
return -EINVAL;
}
@ -746,6 +754,7 @@ static int get_uint8_equal(QEMUFile *f, void *pv, size_t size)
if (*v == v2) {
return 0;
}
error_report("%x != %x", *v, v2);
return -EINVAL;
}
@ -767,6 +776,7 @@ static int get_uint16_equal(QEMUFile *f, void *pv, size_t size)
if (*v == v2) {
return 0;
}
error_report("%x != %x", *v, v2);
return -EINVAL;
}

View File

@ -658,101 +658,85 @@
# hostname must be provided so that the server's x509
# certificate identity can be validated. (Since 2.7)
#
# @max-bandwidth: to set maximum speed for migration. maximum speed in
# bytes per second. (Since 2.8)
#
# @downtime-limit: set maximum tolerated downtime for migration. maximum
# downtime in milliseconds (Since 2.8)
#
# Since: 2.4
##
{ 'enum': 'MigrationParameter',
'data': ['compress-level', 'compress-threads', 'decompress-threads',
'cpu-throttle-initial', 'cpu-throttle-increment',
'tls-creds', 'tls-hostname'] }
'tls-creds', 'tls-hostname', 'max-bandwidth',
'downtime-limit'] }
#
# @migrate-set-parameters
#
# Set the following migration parameters
# Set various migration parameters. See MigrationParameters for details.
#
# @compress-level: compression level
# Since: 2.4
##
{ 'command': 'migrate-set-parameters', 'boxed': true,
'data': 'MigrationParameters' }
#
# @compress-threads: compression thread count
# @MigrationParameters
#
# @decompress-threads: decompression thread count
# Optional members can be omitted on input ('migrate-set-parameters')
# but most members will always be present on output
# ('query-migrate-parameters'), with the exception of tls-creds and
# tls-hostname.
#
# @cpu-throttle-initial: Initial percentage of time guest cpus are throttled
# when migration auto-converge is activated. The
# default value is 20. (Since 2.7)
# @compress-level: #optional compression level
#
# @cpu-throttle-increment: throttle percentage increase each time
# @compress-threads: #optional compression thread count
#
# @decompress-threads: #optional decompression thread count
#
# @cpu-throttle-initial: #optional Initial percentage of time guest cpus are
# throttledwhen migration auto-converge is activated.
# The default value is 20. (Since 2.7)
#
# @cpu-throttle-increment: #optional throttle percentage increase each time
# auto-converge detects that migration is not making
# progress. The default value is 10. (Since 2.7)
#
# @tls-creds: ID of the 'tls-creds' object that provides credentials for
# establishing a TLS connection over the migration data channel.
# On the outgoing side of the migration, the credentials must
# be for a 'client' endpoint, while for the incoming side the
# @tls-creds: #optional ID of the 'tls-creds' object that provides credentials
# for establishing a TLS connection over the migration data
# channel. On the outgoing side of the migration, the credentials
# must be for a 'client' endpoint, while for the incoming side the
# credentials must be for a 'server' endpoint. Setting this
# will enable TLS for all migrations. The default is unset,
# resulting in unsecured migration at the QEMU level. (Since 2.7)
#
# @tls-hostname: hostname of the target host for the migration. This is
# required when using x509 based TLS credentials and the
# @tls-hostname: #optional hostname of the target host for the migration. This
# is required when using x509 based TLS credentials and the
# migration URI does not already include a hostname. For
# example if using fd: or exec: based migration, the
# hostname must be provided so that the server's x509
# certificate identity can be validated. (Since 2.7)
#
# @max-bandwidth: to set maximum speed for migration. maximum speed in
# bytes per second. (Since 2.8)
#
# @downtime-limit: set maximum tolerated downtime for migration. maximum
# downtime in milliseconds (Since 2.8)
#
# Since: 2.4
##
{ 'command': 'migrate-set-parameters',
{ 'struct': 'MigrationParameters',
'data': { '*compress-level': 'int',
'*compress-threads': 'int',
'*decompress-threads': 'int',
'*cpu-throttle-initial': 'int',
'*cpu-throttle-increment': 'int',
'*tls-creds': 'str',
'*tls-hostname': 'str'} }
#
# @MigrationParameters
#
# @compress-level: compression level
#
# @compress-threads: compression thread count
#
# @decompress-threads: decompression thread count
#
# @cpu-throttle-initial: Initial percentage of time guest cpus are throttled
# when migration auto-converge is activated. The
# default value is 20. (Since 2.7)
#
# @cpu-throttle-increment: throttle percentage increase each time
# auto-converge detects that migration is not making
# progress. The default value is 10. (Since 2.7)
#
# @tls-creds: ID of the 'tls-creds' object that provides credentials for
# establishing a TLS connection over the migration data channel.
# On the outgoing side of the migration, the credentials must
# be for a 'client' endpoint, while for the incoming side the
# credentials must be for a 'server' endpoint. Setting this
# will enable TLS for all migrations. The default is unset,
# resulting in unsecured migration at the QEMU level. (Since 2.7)
#
# @tls-hostname: hostname of the target host for the migration. This is
# required when using x509 based TLS credentials and the
# migration URI does not already include a hostname. For
# example if using fd: or exec: based migration, the
# hostname must be provided so that the server's x509
# certificate identity can be validated. (Since 2.7)
#
# Since: 2.4
##
{ 'struct': 'MigrationParameters',
'data': { 'compress-level': 'int',
'compress-threads': 'int',
'decompress-threads': 'int',
'cpu-throttle-initial': 'int',
'cpu-throttle-increment': 'int',
'tls-creds': 'str',
'tls-hostname': 'str'} }
'*tls-hostname': 'str',
'*max-bandwidth': 'int',
'*downtime-limit': 'int'} }
##
# @query-migrate-parameters
#
@ -1834,6 +1818,8 @@
#
# Returns: nothing on success
#
# Notes: This command is deprecated in favor of 'migrate-set-parameters'
#
# Since: 0.14.0
##
{ 'command': 'migrate_set_downtime', 'data': {'value': 'number'} }
@ -1847,7 +1833,7 @@
#
# Returns: nothing on success
#
# Notes: A value lesser than zero will be automatically round up to zero.
# Notes: This command is deprecated in favor of 'migrate-set-parameters'
#
# Since: 0.14.0
##