Migration pull 2018-02-06
This is based off Juan's last pull with a few extras, but also removing: Add migration xbzrle test Add migration precopy test As well as my normal test boxes, I also gave it a test on a 32 bit ARM box and it seems happy (a Calxeda highbank) and a big-endian power box. Dave -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJaecrLAAoJEAUWMx68W/3nXMcQAKc/XyllcmwVGQ5NiEKQRcar 7bJLgu7t4EaJkOhMN2/jeyEjX9p1GjZw6x2PCp7ipZyhLmu5mUWxKC/l+dD7XFLW aTRZmP7gnIUFnTc1sWYdGy59HRjQ8KeVuZILPbgWaJIkC5Pc5I0Wxvhqm0GBCKpI T2tCEV/PHJWyHovs1ZITKgD8NWPZpgc9ZRefomvyb4eJeplf7Eq/hZzgzIP7aoTU fsF/wCTg2lhILl8BvWIxp+Tlhz/hOBay5+5FEEy6x7/tfgJk76Dh/Ri2uPcGPcgG ReUaM9JCn+Toe75z96V43WHuPj0Ea4+7al85H6gXsQeeDBtiewBjUUwQ1mv/zZCn wQyWdX4OoU7gvQEF/3m/8Pb3QuXLxzs6febqcWGj8mFg+IVOEhxHYJ/UdMeq2ASI KG6iHGzUw33R7AE8HoQBV9C/uJ7BzzZEjuJbtzFWXK5QWC2zWOpaFu9R4VGEsAzL ktS96pGtUxHJXZJq8I+rmHr/4KHO6UK4B+/VGKEKzooedkHgYjdTeWyvMDzrJTaq pLpXJxaljuDCNZClX2F5A5GjcrFmDXyz1GGoTAqacqD0OENbqS7CcZVHaEf58/lR fWld/Ya1KjyEjGEsdTD2XAzEO4wMj6GYrk9lcmzIFKwtyIgDJDAWDPXzR/bx1MY8 h0YzqwP6L8HI9nGzzEyz =ntXb -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgilbert/tags/pull-migration-20180206a' into staging Migration pull 2018-02-06 This is based off Juan's last pull with a few extras, but also removing: Add migration xbzrle test Add migration precopy test As well as my normal test boxes, I also gave it a test on a 32 bit ARM box and it seems happy (a Calxeda highbank) and a big-endian power box. Dave # gpg: Signature made Tue 06 Feb 2018 15:33:31 GMT # gpg: using RSA key 0516331EBC5BFDE7 # gpg: Good signature from "Dr. David Alan Gilbert (RH2) <dgilbert@redhat.com>" # Primary key fingerprint: 45F5 C71B 4A0C B7FB 977A 9FA9 0516 331E BC5B FDE7 * remotes/dgilbert/tags/pull-migration-20180206a: migration: incoming postcopy advise sanity checks migration: Don't leak IO channels migration: Recover block devices if failure in device state tests: Adjust sleeps for migration test tests: Create migrate-start-postcopy command tests: Add deprecated commands migration test tests: Use consistent names for migration tests: Consolidate accelerators declaration tests: Remove deprecated migration tests commands migration: Drop current address parameter from save_zero_page() migration: use s->threshold_size inside migration_update_counters migration/savevm.c: set MAX_VM_CMD_PACKAGED_SIZE to 1ul << 32 migration: Route errors down through migration_channel_connect migration: Allow migrate_fd_connect to take an Error * Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
0833df03f4
|
@ -55,29 +55,29 @@ void migration_channel_process_incoming(QIOChannel *ioc)
|
||||||
* @s: Current migration state
|
* @s: Current migration state
|
||||||
* @ioc: Channel to which we are connecting
|
* @ioc: Channel to which we are connecting
|
||||||
* @hostname: Where we want to connect
|
* @hostname: Where we want to connect
|
||||||
|
* @error: Error indicating failure to connect, free'd here
|
||||||
*/
|
*/
|
||||||
void migration_channel_connect(MigrationState *s,
|
void migration_channel_connect(MigrationState *s,
|
||||||
QIOChannel *ioc,
|
QIOChannel *ioc,
|
||||||
const char *hostname)
|
const char *hostname,
|
||||||
|
Error *error)
|
||||||
{
|
{
|
||||||
trace_migration_set_outgoing_channel(
|
trace_migration_set_outgoing_channel(
|
||||||
ioc, object_get_typename(OBJECT(ioc)), hostname);
|
ioc, object_get_typename(OBJECT(ioc)), hostname, error);
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
if (s->parameters.tls_creds &&
|
||||||
|
*s->parameters.tls_creds &&
|
||||||
|
!object_dynamic_cast(OBJECT(ioc),
|
||||||
|
TYPE_QIO_CHANNEL_TLS)) {
|
||||||
|
migration_tls_channel_connect(s, ioc, hostname, &error);
|
||||||
|
} else {
|
||||||
|
QEMUFile *f = qemu_fopen_channel_output(ioc);
|
||||||
|
|
||||||
|
s->to_dst_file = f;
|
||||||
|
|
||||||
if (s->parameters.tls_creds &&
|
|
||||||
*s->parameters.tls_creds &&
|
|
||||||
!object_dynamic_cast(OBJECT(ioc),
|
|
||||||
TYPE_QIO_CHANNEL_TLS)) {
|
|
||||||
Error *local_err = NULL;
|
|
||||||
migration_tls_channel_connect(s, ioc, hostname, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
migrate_fd_error(s, local_err);
|
|
||||||
error_free(local_err);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
QEMUFile *f = qemu_fopen_channel_output(ioc);
|
|
||||||
|
|
||||||
s->to_dst_file = f;
|
|
||||||
|
|
||||||
migrate_fd_connect(s);
|
|
||||||
}
|
}
|
||||||
|
migrate_fd_connect(s, error);
|
||||||
|
error_free(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,5 +22,6 @@ void migration_channel_process_incoming(QIOChannel *ioc);
|
||||||
|
|
||||||
void migration_channel_connect(MigrationState *s,
|
void migration_channel_connect(MigrationState *s,
|
||||||
QIOChannel *ioc,
|
QIOChannel *ioc,
|
||||||
const char *hostname);
|
const char *hostname,
|
||||||
|
Error *error_in);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -39,7 +39,7 @@ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error
|
||||||
}
|
}
|
||||||
|
|
||||||
qio_channel_set_name(ioc, "migration-exec-outgoing");
|
qio_channel_set_name(ioc, "migration-exec-outgoing");
|
||||||
migration_channel_connect(s, ioc, NULL);
|
migration_channel_connect(s, ioc, NULL, NULL);
|
||||||
object_unref(OBJECT(ioc));
|
object_unref(OBJECT(ioc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **
|
||||||
}
|
}
|
||||||
|
|
||||||
qio_channel_set_name(QIO_CHANNEL(ioc), "migration-fd-outgoing");
|
qio_channel_set_name(QIO_CHANNEL(ioc), "migration-fd-outgoing");
|
||||||
migration_channel_connect(s, ioc, NULL);
|
migration_channel_connect(s, ioc, NULL, NULL);
|
||||||
object_unref(OBJECT(ioc));
|
object_unref(OBJECT(ioc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2122,7 +2122,8 @@ fail_invalidate:
|
||||||
/* If not doing postcopy, vm_start() will be called: let's regain
|
/* If not doing postcopy, vm_start() will be called: let's regain
|
||||||
* control on images.
|
* control on images.
|
||||||
*/
|
*/
|
||||||
if (s->state == MIGRATION_STATUS_ACTIVE) {
|
if (s->state == MIGRATION_STATUS_ACTIVE ||
|
||||||
|
s->state == MIGRATION_STATUS_DEVICE) {
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
|
@ -2169,7 +2170,6 @@ static void migration_update_counters(MigrationState *s,
|
||||||
int64_t current_time)
|
int64_t current_time)
|
||||||
{
|
{
|
||||||
uint64_t transferred, time_spent;
|
uint64_t transferred, time_spent;
|
||||||
int64_t threshold_size;
|
|
||||||
double bandwidth;
|
double bandwidth;
|
||||||
|
|
||||||
if (current_time < s->iteration_start_time + BUFFER_DELAY) {
|
if (current_time < s->iteration_start_time + BUFFER_DELAY) {
|
||||||
|
@ -2179,7 +2179,7 @@ static void migration_update_counters(MigrationState *s,
|
||||||
transferred = qemu_ftell(s->to_dst_file) - s->iteration_initial_bytes;
|
transferred = qemu_ftell(s->to_dst_file) - s->iteration_initial_bytes;
|
||||||
time_spent = current_time - s->iteration_start_time;
|
time_spent = current_time - s->iteration_start_time;
|
||||||
bandwidth = (double)transferred / time_spent;
|
bandwidth = (double)transferred / time_spent;
|
||||||
threshold_size = bandwidth * s->parameters.downtime_limit;
|
s->threshold_size = bandwidth * s->parameters.downtime_limit;
|
||||||
|
|
||||||
s->mbps = (((double) transferred * 8.0) /
|
s->mbps = (((double) transferred * 8.0) /
|
||||||
((double) time_spent / 1000.0)) / 1000.0 / 1000.0;
|
((double) time_spent / 1000.0)) / 1000.0 / 1000.0;
|
||||||
|
@ -2199,7 +2199,7 @@ static void migration_update_counters(MigrationState *s,
|
||||||
s->iteration_initial_bytes = qemu_ftell(s->to_dst_file);
|
s->iteration_initial_bytes = qemu_ftell(s->to_dst_file);
|
||||||
|
|
||||||
trace_migrate_transferred(transferred, time_spent,
|
trace_migrate_transferred(transferred, time_spent,
|
||||||
bandwidth, threshold_size);
|
bandwidth, s->threshold_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Migration thread iteration status */
|
/* Migration thread iteration status */
|
||||||
|
@ -2378,10 +2378,15 @@ static void *migration_thread(void *opaque)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void migrate_fd_connect(MigrationState *s)
|
void migrate_fd_connect(MigrationState *s, Error *error_in)
|
||||||
{
|
{
|
||||||
s->expected_downtime = s->parameters.downtime_limit;
|
s->expected_downtime = s->parameters.downtime_limit;
|
||||||
s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
|
s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
|
||||||
|
if (error_in) {
|
||||||
|
migrate_fd_error(s, error_in);
|
||||||
|
migrate_fd_cleanup(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qemu_file_set_blocking(s->to_dst_file, true);
|
qemu_file_set_blocking(s->to_dst_file, true);
|
||||||
qemu_file_set_rate_limit(s->to_dst_file,
|
qemu_file_set_rate_limit(s->to_dst_file,
|
||||||
|
|
|
@ -190,7 +190,7 @@ uint64_t migrate_max_downtime(void);
|
||||||
void migrate_set_error(MigrationState *s, const Error *error);
|
void migrate_set_error(MigrationState *s, const Error *error);
|
||||||
void migrate_fd_error(MigrationState *s, const Error *error);
|
void migrate_fd_error(MigrationState *s, const Error *error);
|
||||||
|
|
||||||
void migrate_fd_connect(MigrationState *s);
|
void migrate_fd_connect(MigrationState *s, Error *error_in);
|
||||||
|
|
||||||
MigrationState *migrate_init(void);
|
MigrationState *migrate_init(void);
|
||||||
bool migration_is_blocked(Error **errp);
|
bool migration_is_blocked(Error **errp);
|
||||||
|
|
|
@ -907,11 +907,10 @@ static void migration_bitmap_sync(RAMState *rs)
|
||||||
* @rs: current RAM state
|
* @rs: current RAM state
|
||||||
* @block: block that contains the page we want to send
|
* @block: block that contains the page we want to send
|
||||||
* @offset: offset inside the block for the page
|
* @offset: offset inside the block for the page
|
||||||
* @p: pointer to the page
|
|
||||||
*/
|
*/
|
||||||
static int save_zero_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
|
static int save_zero_page(RAMState *rs, RAMBlock *block, ram_addr_t offset)
|
||||||
uint8_t *p)
|
|
||||||
{
|
{
|
||||||
|
uint8_t *p = block->host + offset;
|
||||||
int pages = -1;
|
int pages = -1;
|
||||||
|
|
||||||
if (is_zero_range(p, TARGET_PAGE_SIZE)) {
|
if (is_zero_range(p, TARGET_PAGE_SIZE)) {
|
||||||
|
@ -984,7 +983,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pages = save_zero_page(rs, block, offset, p);
|
pages = save_zero_page(rs, block, offset);
|
||||||
if (pages > 0) {
|
if (pages > 0) {
|
||||||
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
|
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
|
||||||
* page would be stale
|
* page would be stale
|
||||||
|
@ -1160,7 +1159,7 @@ static int ram_save_compressed_page(RAMState *rs, PageSearchStatus *pss,
|
||||||
*/
|
*/
|
||||||
if (block != rs->last_sent_block) {
|
if (block != rs->last_sent_block) {
|
||||||
flush_compressed_data(rs);
|
flush_compressed_data(rs);
|
||||||
pages = save_zero_page(rs, block, offset, p);
|
pages = save_zero_page(rs, block, offset);
|
||||||
if (pages == -1) {
|
if (pages == -1) {
|
||||||
/* Make sure the first page is sent out before other pages */
|
/* Make sure the first page is sent out before other pages */
|
||||||
bytes_xmit = save_page_header(rs, rs->f, block, offset |
|
bytes_xmit = save_page_header(rs, rs->f, block, offset |
|
||||||
|
@ -1180,7 +1179,7 @@ static int ram_save_compressed_page(RAMState *rs, PageSearchStatus *pss,
|
||||||
ram_release_pages(block->idstr, offset, pages);
|
ram_release_pages(block->idstr, offset, pages);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pages = save_zero_page(rs, block, offset, p);
|
pages = save_zero_page(rs, block, offset);
|
||||||
if (pages == -1) {
|
if (pages == -1) {
|
||||||
pages = compress_page_with_multi_thread(rs, block, offset);
|
pages = compress_page_with_multi_thread(rs, block, offset);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3758,7 +3758,7 @@ void rdma_start_outgoing_migration(void *opaque,
|
||||||
trace_rdma_start_outgoing_migration_after_rdma_connect();
|
trace_rdma_start_outgoing_migration_after_rdma_connect();
|
||||||
|
|
||||||
s->to_dst_file = qemu_fopen_rdma(rdma, "wb");
|
s->to_dst_file = qemu_fopen_rdma(rdma, "wb");
|
||||||
migrate_fd_connect(s);
|
migrate_fd_connect(s, NULL);
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
g_free(rdma);
|
g_free(rdma);
|
||||||
|
|
|
@ -81,7 +81,7 @@ enum qemu_vm_cmd {
|
||||||
MIG_CMD_MAX
|
MIG_CMD_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24)
|
#define MAX_VM_CMD_PACKAGED_SIZE UINT32_MAX
|
||||||
static struct mig_cmd_args {
|
static struct mig_cmd_args {
|
||||||
ssize_t len; /* -1 = variable */
|
ssize_t len; /* -1 = variable */
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -1376,7 +1376,8 @@ static int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis);
|
||||||
* *might* happen - it might be skipped if precopy transferred everything
|
* *might* happen - it might be skipped if precopy transferred everything
|
||||||
* quickly.
|
* quickly.
|
||||||
*/
|
*/
|
||||||
static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis)
|
static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
|
||||||
|
uint16_t len)
|
||||||
{
|
{
|
||||||
PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE);
|
PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE);
|
||||||
uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps;
|
uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps;
|
||||||
|
@ -1387,8 +1388,22 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!migrate_postcopy_ram()) {
|
switch (len) {
|
||||||
|
case 0:
|
||||||
|
if (migrate_postcopy_ram()) {
|
||||||
|
error_report("RAM postcopy is enabled but have 0 byte advise");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
case 8 + 8:
|
||||||
|
if (!migrate_postcopy_ram()) {
|
||||||
|
error_report("RAM postcopy is disabled but have 16 byte advise");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_report("CMD_POSTCOPY_ADVISE invalid length (%d)", len);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!postcopy_ram_supported_by_host(mis)) {
|
if (!postcopy_ram_supported_by_host(mis)) {
|
||||||
|
@ -1807,7 +1822,7 @@ static int loadvm_process_command(QEMUFile *f)
|
||||||
return loadvm_handle_cmd_packaged(mis);
|
return loadvm_handle_cmd_packaged(mis);
|
||||||
|
|
||||||
case MIG_CMD_POSTCOPY_ADVISE:
|
case MIG_CMD_POSTCOPY_ADVISE:
|
||||||
return loadvm_postcopy_handle_advise(mis);
|
return loadvm_postcopy_handle_advise(mis, len);
|
||||||
|
|
||||||
case MIG_CMD_POSTCOPY_LISTEN:
|
case MIG_CMD_POSTCOPY_LISTEN:
|
||||||
return loadvm_postcopy_handle_listen(mis);
|
return loadvm_postcopy_handle_listen(mis);
|
||||||
|
@ -2266,6 +2281,7 @@ void qmp_xen_save_devices_state(const char *filename, bool has_live, bool live,
|
||||||
}
|
}
|
||||||
qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-save-state");
|
qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-save-state");
|
||||||
f = qemu_fopen_channel_output(QIO_CHANNEL(ioc));
|
f = qemu_fopen_channel_output(QIO_CHANNEL(ioc));
|
||||||
|
object_unref(OBJECT(ioc));
|
||||||
ret = qemu_save_device_state(f);
|
ret = qemu_save_device_state(f);
|
||||||
qemu_fclose(f);
|
qemu_fclose(f);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -2313,6 +2329,7 @@ void qmp_xen_load_devices_state(const char *filename, Error **errp)
|
||||||
}
|
}
|
||||||
qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-load-state");
|
qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-load-state");
|
||||||
f = qemu_fopen_channel_input(QIO_CHANNEL(ioc));
|
f = qemu_fopen_channel_input(QIO_CHANNEL(ioc));
|
||||||
|
object_unref(OBJECT(ioc));
|
||||||
|
|
||||||
ret = qemu_loadvm_state(f);
|
ret = qemu_loadvm_state(f);
|
||||||
qemu_fclose(f);
|
qemu_fclose(f);
|
||||||
|
|
|
@ -79,12 +79,10 @@ static void socket_outgoing_migration(QIOTask *task,
|
||||||
|
|
||||||
if (qio_task_propagate_error(task, &err)) {
|
if (qio_task_propagate_error(task, &err)) {
|
||||||
trace_migration_socket_outgoing_error(error_get_pretty(err));
|
trace_migration_socket_outgoing_error(error_get_pretty(err));
|
||||||
migrate_fd_error(data->s, err);
|
|
||||||
error_free(err);
|
|
||||||
} else {
|
} else {
|
||||||
trace_migration_socket_outgoing_connected(data->hostname);
|
trace_migration_socket_outgoing_connected(data->hostname);
|
||||||
migration_channel_connect(data->s, sioc, data->hostname);
|
|
||||||
}
|
}
|
||||||
|
migration_channel_connect(data->s, sioc, data->hostname, err);
|
||||||
object_unref(OBJECT(sioc));
|
object_unref(OBJECT(sioc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,11 +118,10 @@ static void migration_tls_outgoing_handshake(QIOTask *task,
|
||||||
|
|
||||||
if (qio_task_propagate_error(task, &err)) {
|
if (qio_task_propagate_error(task, &err)) {
|
||||||
trace_migration_tls_outgoing_handshake_error(error_get_pretty(err));
|
trace_migration_tls_outgoing_handshake_error(error_get_pretty(err));
|
||||||
migrate_fd_error(s, err);
|
|
||||||
} else {
|
} else {
|
||||||
trace_migration_tls_outgoing_handshake_complete();
|
trace_migration_tls_outgoing_handshake_complete();
|
||||||
migration_channel_connect(s, ioc, NULL);
|
|
||||||
}
|
}
|
||||||
|
migration_channel_connect(s, ioc, NULL, err);
|
||||||
object_unref(OBJECT(ioc));
|
object_unref(OBJECT(ioc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ migrate_transferred(uint64_t tranferred, uint64_t time_spent, double bandwidth,
|
||||||
process_incoming_migration_co_end(int ret, int ps) "ret=%d postcopy-state=%d"
|
process_incoming_migration_co_end(int ret, int ps) "ret=%d postcopy-state=%d"
|
||||||
process_incoming_migration_co_postcopy_end_main(void) ""
|
process_incoming_migration_co_postcopy_end_main(void) ""
|
||||||
migration_set_incoming_channel(void *ioc, const char *ioctype) "ioc=%p ioctype=%s"
|
migration_set_incoming_channel(void *ioc, const char *ioctype) "ioc=%p ioctype=%s"
|
||||||
migration_set_outgoing_channel(void *ioc, const char *ioctype, const char *hostname) "ioc=%p ioctype=%s hostname=%s"
|
migration_set_outgoing_channel(void *ioc, const char *ioctype, const char *hostname, void *err) "ioc=%p ioctype=%s hostname=%s err=%p"
|
||||||
|
|
||||||
# migration/rdma.c
|
# migration/rdma.c
|
||||||
qemu_rdma_accept_incoming_migration(void) ""
|
qemu_rdma_accept_incoming_migration(void) ""
|
||||||
|
|
|
@ -268,10 +268,9 @@ static uint64_t get_migration_pass(QTestState *who)
|
||||||
|
|
||||||
static void wait_for_migration_complete(QTestState *who)
|
static void wait_for_migration_complete(QTestState *who)
|
||||||
{
|
{
|
||||||
QDict *rsp, *rsp_return;
|
while (true) {
|
||||||
bool completed;
|
QDict *rsp, *rsp_return;
|
||||||
|
bool completed;
|
||||||
do {
|
|
||||||
const char *status;
|
const char *status;
|
||||||
|
|
||||||
rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
|
rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
|
||||||
|
@ -280,8 +279,11 @@ static void wait_for_migration_complete(QTestState *who)
|
||||||
completed = strcmp(status, "completed") == 0;
|
completed = strcmp(status, "completed") == 0;
|
||||||
g_assert_cmpstr(status, !=, "failed");
|
g_assert_cmpstr(status, !=, "failed");
|
||||||
QDECREF(rsp);
|
QDECREF(rsp);
|
||||||
usleep(1000 * 100);
|
if (completed) {
|
||||||
} while (!completed);
|
return;
|
||||||
|
}
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_for_migration_pass(QTestState *who)
|
static void wait_for_migration_pass(QTestState *who)
|
||||||
|
@ -290,16 +292,13 @@ static void wait_for_migration_pass(QTestState *who)
|
||||||
uint64_t pass;
|
uint64_t pass;
|
||||||
|
|
||||||
/* Wait for the 1st sync */
|
/* Wait for the 1st sync */
|
||||||
do {
|
while (!got_stop && !initial_pass) {
|
||||||
|
usleep(1000);
|
||||||
initial_pass = get_migration_pass(who);
|
initial_pass = get_migration_pass(who);
|
||||||
if (got_stop || initial_pass) {
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
usleep(1000 * 100);
|
|
||||||
} while (true);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
usleep(1000 * 100);
|
usleep(1000);
|
||||||
pass = get_migration_pass(who);
|
pass = get_migration_pass(who);
|
||||||
} while (pass == initial_pass && !got_stop);
|
} while (pass == initial_pass && !got_stop);
|
||||||
}
|
}
|
||||||
|
@ -369,37 +368,20 @@ static void migrate_check_parameter(QTestState *who, const char *parameter,
|
||||||
QDECREF(rsp);
|
QDECREF(rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void migrate_set_downtime(QTestState *who, const double value)
|
static void migrate_set_parameter(QTestState *who, const char *parameter,
|
||||||
{
|
const char *value)
|
||||||
QDict *rsp;
|
|
||||||
gchar *cmd;
|
|
||||||
char *expected;
|
|
||||||
int64_t result_int;
|
|
||||||
|
|
||||||
cmd = g_strdup_printf("{ 'execute': 'migrate_set_downtime',"
|
|
||||||
"'arguments': { 'value': %g } }", value);
|
|
||||||
rsp = qtest_qmp(who, cmd);
|
|
||||||
g_free(cmd);
|
|
||||||
g_assert(qdict_haskey(rsp, "return"));
|
|
||||||
QDECREF(rsp);
|
|
||||||
result_int = value * 1000L;
|
|
||||||
expected = g_strdup_printf("%" PRId64, result_int);
|
|
||||||
migrate_check_parameter(who, "downtime-limit", expected);
|
|
||||||
g_free(expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void migrate_set_speed(QTestState *who, const char *value)
|
|
||||||
{
|
{
|
||||||
QDict *rsp;
|
QDict *rsp;
|
||||||
gchar *cmd;
|
gchar *cmd;
|
||||||
|
|
||||||
cmd = g_strdup_printf("{ 'execute': 'migrate_set_speed',"
|
cmd = g_strdup_printf("{ 'execute': 'migrate-set-parameters',"
|
||||||
"'arguments': { 'value': %s } }", value);
|
"'arguments': { '%s': %s } }",
|
||||||
|
parameter, value);
|
||||||
rsp = qtest_qmp(who, cmd);
|
rsp = qtest_qmp(who, cmd);
|
||||||
g_free(cmd);
|
g_free(cmd);
|
||||||
g_assert(qdict_haskey(rsp, "return"));
|
g_assert(qdict_haskey(rsp, "return"));
|
||||||
QDECREF(rsp);
|
QDECREF(rsp);
|
||||||
migrate_check_parameter(who, "max-bandwidth", value);
|
migrate_check_parameter(who, parameter, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void migrate_set_capability(QTestState *who, const char *capability,
|
static void migrate_set_capability(QTestState *who, const char *capability,
|
||||||
|
@ -433,41 +415,52 @@ static void migrate(QTestState *who, const char *uri)
|
||||||
QDECREF(rsp);
|
QDECREF(rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void migrate_start_postcopy(QTestState *who)
|
||||||
|
{
|
||||||
|
QDict *rsp;
|
||||||
|
|
||||||
|
rsp = wait_command(who, "{ 'execute': 'migrate-start-postcopy' }");
|
||||||
|
g_assert(qdict_haskey(rsp, "return"));
|
||||||
|
QDECREF(rsp);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_migrate_start(QTestState **from, QTestState **to,
|
static void test_migrate_start(QTestState **from, QTestState **to,
|
||||||
const char *uri)
|
const char *uri)
|
||||||
{
|
{
|
||||||
gchar *cmd_src, *cmd_dst;
|
gchar *cmd_src, *cmd_dst;
|
||||||
char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
|
char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
|
||||||
const char *arch = qtest_get_arch();
|
const char *arch = qtest_get_arch();
|
||||||
|
const char *accel = "kvm:tcg";
|
||||||
|
|
||||||
got_stop = false;
|
got_stop = false;
|
||||||
|
|
||||||
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
|
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
|
||||||
init_bootfile_x86(bootpath);
|
init_bootfile_x86(bootpath);
|
||||||
cmd_src = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
|
cmd_src = g_strdup_printf("-machine accel=%s -m 150M"
|
||||||
" -name pcsource,debug-threads=on"
|
" -name source,debug-threads=on"
|
||||||
" -serial file:%s/src_serial"
|
" -serial file:%s/src_serial"
|
||||||
" -drive file=%s,format=raw",
|
" -drive file=%s,format=raw",
|
||||||
tmpfs, bootpath);
|
accel, tmpfs, bootpath);
|
||||||
cmd_dst = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
|
cmd_dst = g_strdup_printf("-machine accel=%s -m 150M"
|
||||||
" -name pcdest,debug-threads=on"
|
" -name target,debug-threads=on"
|
||||||
" -serial file:%s/dest_serial"
|
" -serial file:%s/dest_serial"
|
||||||
" -drive file=%s,format=raw"
|
" -drive file=%s,format=raw"
|
||||||
" -incoming %s",
|
" -incoming %s",
|
||||||
tmpfs, bootpath, uri);
|
accel, tmpfs, bootpath, uri);
|
||||||
} else if (strcmp(arch, "ppc64") == 0) {
|
} else if (strcmp(arch, "ppc64") == 0) {
|
||||||
const char *accel;
|
|
||||||
|
|
||||||
/* On ppc64, the test only works with kvm-hv, but not with kvm-pr */
|
/* On ppc64, the test only works with kvm-hv, but not with kvm-pr */
|
||||||
accel = access("/sys/module/kvm_hv", F_OK) ? "tcg" : "kvm:tcg";
|
if (access("/sys/module/kvm_hv", F_OK)) {
|
||||||
|
accel = "tcg";
|
||||||
|
}
|
||||||
init_bootfile_ppc(bootpath);
|
init_bootfile_ppc(bootpath);
|
||||||
cmd_src = g_strdup_printf("-machine accel=%s -m 256M"
|
cmd_src = g_strdup_printf("-machine accel=%s -m 256M"
|
||||||
" -name pcsource,debug-threads=on"
|
" -name source,debug-threads=on"
|
||||||
" -serial file:%s/src_serial"
|
" -serial file:%s/src_serial"
|
||||||
" -drive file=%s,if=pflash,format=raw",
|
" -drive file=%s,if=pflash,format=raw",
|
||||||
accel, tmpfs, bootpath);
|
accel, tmpfs, bootpath);
|
||||||
cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
|
cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
|
||||||
" -name pcdest,debug-threads=on"
|
" -name target,debug-threads=on"
|
||||||
" -serial file:%s/dest_serial"
|
" -serial file:%s/dest_serial"
|
||||||
" -incoming %s",
|
" -incoming %s",
|
||||||
accel, tmpfs, uri);
|
accel, tmpfs, uri);
|
||||||
|
@ -495,13 +488,13 @@ static void test_migrate_end(QTestState *from, QTestState *to)
|
||||||
/* Destination still running, wait for a byte to change */
|
/* Destination still running, wait for a byte to change */
|
||||||
do {
|
do {
|
||||||
qtest_memread(to, start_address, &dest_byte_b, 1);
|
qtest_memread(to, start_address, &dest_byte_b, 1);
|
||||||
usleep(10 * 1000);
|
usleep(1000 * 10);
|
||||||
} while (dest_byte_a == dest_byte_b);
|
} while (dest_byte_a == dest_byte_b);
|
||||||
|
|
||||||
qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
|
qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
|
||||||
/* With it stopped, check nothing changes */
|
/* With it stopped, check nothing changes */
|
||||||
qtest_memread(to, start_address, &dest_byte_c, 1);
|
qtest_memread(to, start_address, &dest_byte_c, 1);
|
||||||
sleep(1);
|
usleep(1000 * 200);
|
||||||
qtest_memread(to, start_address, &dest_byte_d, 1);
|
qtest_memread(to, start_address, &dest_byte_d, 1);
|
||||||
g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
|
g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
|
||||||
|
|
||||||
|
@ -515,11 +508,55 @@ static void test_migrate_end(QTestState *from, QTestState *to)
|
||||||
cleanup("dest_serial");
|
cleanup("dest_serial");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void deprecated_set_downtime(QTestState *who, const double value)
|
||||||
|
{
|
||||||
|
QDict *rsp;
|
||||||
|
gchar *cmd;
|
||||||
|
char *expected;
|
||||||
|
int64_t result_int;
|
||||||
|
|
||||||
|
cmd = g_strdup_printf("{ 'execute': 'migrate_set_downtime',"
|
||||||
|
"'arguments': { 'value': %g } }", value);
|
||||||
|
rsp = qtest_qmp(who, cmd);
|
||||||
|
g_free(cmd);
|
||||||
|
g_assert(qdict_haskey(rsp, "return"));
|
||||||
|
QDECREF(rsp);
|
||||||
|
result_int = value * 1000L;
|
||||||
|
expected = g_strdup_printf("%" PRId64, result_int);
|
||||||
|
migrate_check_parameter(who, "downtime-limit", expected);
|
||||||
|
g_free(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deprecated_set_speed(QTestState *who, const char *value)
|
||||||
|
{
|
||||||
|
QDict *rsp;
|
||||||
|
gchar *cmd;
|
||||||
|
|
||||||
|
cmd = g_strdup_printf("{ 'execute': 'migrate_set_speed',"
|
||||||
|
"'arguments': { 'value': %s } }", value);
|
||||||
|
rsp = qtest_qmp(who, cmd);
|
||||||
|
g_free(cmd);
|
||||||
|
g_assert(qdict_haskey(rsp, "return"));
|
||||||
|
QDECREF(rsp);
|
||||||
|
migrate_check_parameter(who, "max-bandwidth", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_deprecated(void)
|
||||||
|
{
|
||||||
|
QTestState *from;
|
||||||
|
|
||||||
|
from = qtest_start("");
|
||||||
|
|
||||||
|
deprecated_set_downtime(from, 0.12345);
|
||||||
|
deprecated_set_speed(from, "12345");
|
||||||
|
|
||||||
|
qtest_quit(from);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_migrate(void)
|
static void test_migrate(void)
|
||||||
{
|
{
|
||||||
char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
|
char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
|
||||||
QTestState *from, *to;
|
QTestState *from, *to;
|
||||||
QDict *rsp;
|
|
||||||
|
|
||||||
test_migrate_start(&from, &to, uri);
|
test_migrate_start(&from, &to, uri);
|
||||||
|
|
||||||
|
@ -530,8 +567,8 @@ static void test_migrate(void)
|
||||||
* quickly, but that it doesn't complete precopy even on a slow
|
* quickly, but that it doesn't complete precopy even on a slow
|
||||||
* machine, so also set the downtime.
|
* machine, so also set the downtime.
|
||||||
*/
|
*/
|
||||||
migrate_set_speed(from, "100000000");
|
migrate_set_parameter(from, "max-bandwidth", "100000000");
|
||||||
migrate_set_downtime(from, 0.001);
|
migrate_set_parameter(from, "downtime-limit", "1");
|
||||||
|
|
||||||
/* Wait for the first serial output from the source */
|
/* Wait for the first serial output from the source */
|
||||||
wait_for_serial("src_serial");
|
wait_for_serial("src_serial");
|
||||||
|
@ -540,9 +577,7 @@ static void test_migrate(void)
|
||||||
|
|
||||||
wait_for_migration_pass(from);
|
wait_for_migration_pass(from);
|
||||||
|
|
||||||
rsp = wait_command(from, "{ 'execute': 'migrate-start-postcopy' }");
|
migrate_start_postcopy(from);
|
||||||
g_assert(qdict_haskey(rsp, "return"));
|
|
||||||
QDECREF(rsp);
|
|
||||||
|
|
||||||
if (!got_stop) {
|
if (!got_stop) {
|
||||||
qtest_qmp_eventwait(from, "STOP");
|
qtest_qmp_eventwait(from, "STOP");
|
||||||
|
@ -578,6 +613,7 @@ int main(int argc, char **argv)
|
||||||
module_call_init(MODULE_INIT_QOM);
|
module_call_init(MODULE_INIT_QOM);
|
||||||
|
|
||||||
qtest_add_func("/migration/postcopy/unix", test_migrate);
|
qtest_add_func("/migration/postcopy/unix", test_migrate);
|
||||||
|
qtest_add_func("/migration/deprecated", test_deprecated);
|
||||||
|
|
||||||
ret = g_test_run();
|
ret = g_test_run();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue