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:
commit
4378caf59e
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
19
exec.c
@ -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
77
hmp.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -129,7 +129,6 @@ struct MigrationSrcPageRequest {
|
||||
|
||||
struct MigrationState
|
||||
{
|
||||
int64_t bandwidth_limit;
|
||||
size_t bytes_xfer;
|
||||
size_t xfer_limit;
|
||||
QemuThread thread;
|
||||
|
@ -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);
|
||||
|
@ -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__,
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
110
qapi-schema.json
110
qapi-schema.json
@ -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
|
||||
##
|
||||
|
Loading…
Reference in New Issue
Block a user