qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

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>

+151 -96
+16 -16
migration/channel.c
··· 55 55 * @s: Current migration state 56 56 * @ioc: Channel to which we are connecting 57 57 * @hostname: Where we want to connect 58 + * @error: Error indicating failure to connect, free'd here 58 59 */ 59 60 void migration_channel_connect(MigrationState *s, 60 61 QIOChannel *ioc, 61 - const char *hostname) 62 + const char *hostname, 63 + Error *error) 62 64 { 63 65 trace_migration_set_outgoing_channel( 64 - ioc, object_get_typename(OBJECT(ioc)), hostname); 66 + ioc, object_get_typename(OBJECT(ioc)), hostname, error); 65 67 66 - if (s->parameters.tls_creds && 67 - *s->parameters.tls_creds && 68 - !object_dynamic_cast(OBJECT(ioc), 69 - TYPE_QIO_CHANNEL_TLS)) { 70 - Error *local_err = NULL; 71 - migration_tls_channel_connect(s, ioc, hostname, &local_err); 72 - if (local_err) { 73 - migrate_fd_error(s, local_err); 74 - error_free(local_err); 75 - } 76 - } else { 77 - QEMUFile *f = qemu_fopen_channel_output(ioc); 68 + if (!error) { 69 + if (s->parameters.tls_creds && 70 + *s->parameters.tls_creds && 71 + !object_dynamic_cast(OBJECT(ioc), 72 + TYPE_QIO_CHANNEL_TLS)) { 73 + migration_tls_channel_connect(s, ioc, hostname, &error); 74 + } else { 75 + QEMUFile *f = qemu_fopen_channel_output(ioc); 78 76 79 - s->to_dst_file = f; 77 + s->to_dst_file = f; 80 78 81 - migrate_fd_connect(s); 79 + } 82 80 } 81 + migrate_fd_connect(s, error); 82 + error_free(error); 83 83 }
+2 -1
migration/channel.h
··· 22 22 23 23 void migration_channel_connect(MigrationState *s, 24 24 QIOChannel *ioc, 25 - const char *hostname); 25 + const char *hostname, 26 + Error *error_in); 26 27 #endif
+1 -1
migration/exec.c
··· 39 39 } 40 40 41 41 qio_channel_set_name(ioc, "migration-exec-outgoing"); 42 - migration_channel_connect(s, ioc, NULL); 42 + migration_channel_connect(s, ioc, NULL, NULL); 43 43 object_unref(OBJECT(ioc)); 44 44 } 45 45
+1 -1
migration/fd.c
··· 39 39 } 40 40 41 41 qio_channel_set_name(QIO_CHANNEL(ioc), "migration-fd-outgoing"); 42 - migration_channel_connect(s, ioc, NULL); 42 + migration_channel_connect(s, ioc, NULL, NULL); 43 43 object_unref(OBJECT(ioc)); 44 44 } 45 45
+10 -5
migration/migration.c
··· 2122 2122 /* If not doing postcopy, vm_start() will be called: let's regain 2123 2123 * control on images. 2124 2124 */ 2125 - if (s->state == MIGRATION_STATUS_ACTIVE) { 2125 + if (s->state == MIGRATION_STATUS_ACTIVE || 2126 + s->state == MIGRATION_STATUS_DEVICE) { 2126 2127 Error *local_err = NULL; 2127 2128 2128 2129 qemu_mutex_lock_iothread(); ··· 2169 2170 int64_t current_time) 2170 2171 { 2171 2172 uint64_t transferred, time_spent; 2172 - int64_t threshold_size; 2173 2173 double bandwidth; 2174 2174 2175 2175 if (current_time < s->iteration_start_time + BUFFER_DELAY) { ··· 2179 2179 transferred = qemu_ftell(s->to_dst_file) - s->iteration_initial_bytes; 2180 2180 time_spent = current_time - s->iteration_start_time; 2181 2181 bandwidth = (double)transferred / time_spent; 2182 - threshold_size = bandwidth * s->parameters.downtime_limit; 2182 + s->threshold_size = bandwidth * s->parameters.downtime_limit; 2183 2183 2184 2184 s->mbps = (((double) transferred * 8.0) / 2185 2185 ((double) time_spent / 1000.0)) / 1000.0 / 1000.0; ··· 2199 2199 s->iteration_initial_bytes = qemu_ftell(s->to_dst_file); 2200 2200 2201 2201 trace_migrate_transferred(transferred, time_spent, 2202 - bandwidth, threshold_size); 2202 + bandwidth, s->threshold_size); 2203 2203 } 2204 2204 2205 2205 /* Migration thread iteration status */ ··· 2378 2378 return NULL; 2379 2379 } 2380 2380 2381 - void migrate_fd_connect(MigrationState *s) 2381 + void migrate_fd_connect(MigrationState *s, Error *error_in) 2382 2382 { 2383 2383 s->expected_downtime = s->parameters.downtime_limit; 2384 2384 s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s); 2385 + if (error_in) { 2386 + migrate_fd_error(s, error_in); 2387 + migrate_fd_cleanup(s); 2388 + return; 2389 + } 2385 2390 2386 2391 qemu_file_set_blocking(s->to_dst_file, true); 2387 2392 qemu_file_set_rate_limit(s->to_dst_file,
+1 -1
migration/migration.h
··· 190 190 void migrate_set_error(MigrationState *s, const Error *error); 191 191 void migrate_fd_error(MigrationState *s, const Error *error); 192 192 193 - void migrate_fd_connect(MigrationState *s); 193 + void migrate_fd_connect(MigrationState *s, Error *error_in); 194 194 195 195 MigrationState *migrate_init(void); 196 196 bool migration_is_blocked(Error **errp);
+5 -6
migration/ram.c
··· 907 907 * @rs: current RAM state 908 908 * @block: block that contains the page we want to send 909 909 * @offset: offset inside the block for the page 910 - * @p: pointer to the page 911 910 */ 912 - static int save_zero_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, 913 - uint8_t *p) 911 + static int save_zero_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) 914 912 { 913 + uint8_t *p = block->host + offset; 915 914 int pages = -1; 916 915 917 916 if (is_zero_range(p, TARGET_PAGE_SIZE)) { ··· 984 983 } 985 984 } 986 985 } else { 987 - pages = save_zero_page(rs, block, offset, p); 986 + pages = save_zero_page(rs, block, offset); 988 987 if (pages > 0) { 989 988 /* Must let xbzrle know, otherwise a previous (now 0'd) cached 990 989 * page would be stale ··· 1160 1159 */ 1161 1160 if (block != rs->last_sent_block) { 1162 1161 flush_compressed_data(rs); 1163 - pages = save_zero_page(rs, block, offset, p); 1162 + pages = save_zero_page(rs, block, offset); 1164 1163 if (pages == -1) { 1165 1164 /* Make sure the first page is sent out before other pages */ 1166 1165 bytes_xmit = save_page_header(rs, rs->f, block, offset | ··· 1180 1179 ram_release_pages(block->idstr, offset, pages); 1181 1180 } 1182 1181 } else { 1183 - pages = save_zero_page(rs, block, offset, p); 1182 + pages = save_zero_page(rs, block, offset); 1184 1183 if (pages == -1) { 1185 1184 pages = compress_page_with_multi_thread(rs, block, offset); 1186 1185 } else {
+1 -1
migration/rdma.c
··· 3758 3758 trace_rdma_start_outgoing_migration_after_rdma_connect(); 3759 3759 3760 3760 s->to_dst_file = qemu_fopen_rdma(rdma, "wb"); 3761 - migrate_fd_connect(s); 3761 + migrate_fd_connect(s, NULL); 3762 3762 return; 3763 3763 err: 3764 3764 g_free(rdma);
+21 -4
migration/savevm.c
··· 81 81 MIG_CMD_MAX 82 82 }; 83 83 84 - #define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24) 84 + #define MAX_VM_CMD_PACKAGED_SIZE UINT32_MAX 85 85 static struct mig_cmd_args { 86 86 ssize_t len; /* -1 = variable */ 87 87 const char *name; ··· 1376 1376 * *might* happen - it might be skipped if precopy transferred everything 1377 1377 * quickly. 1378 1378 */ 1379 - static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis) 1379 + static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis, 1380 + uint16_t len) 1380 1381 { 1381 1382 PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE); 1382 1383 uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps; ··· 1387 1388 return -1; 1388 1389 } 1389 1390 1390 - if (!migrate_postcopy_ram()) { 1391 + switch (len) { 1392 + case 0: 1393 + if (migrate_postcopy_ram()) { 1394 + error_report("RAM postcopy is enabled but have 0 byte advise"); 1395 + return -EINVAL; 1396 + } 1391 1397 return 0; 1398 + case 8 + 8: 1399 + if (!migrate_postcopy_ram()) { 1400 + error_report("RAM postcopy is disabled but have 16 byte advise"); 1401 + return -EINVAL; 1402 + } 1403 + break; 1404 + default: 1405 + error_report("CMD_POSTCOPY_ADVISE invalid length (%d)", len); 1406 + return -EINVAL; 1392 1407 } 1393 1408 1394 1409 if (!postcopy_ram_supported_by_host(mis)) { ··· 1807 1822 return loadvm_handle_cmd_packaged(mis); 1808 1823 1809 1824 case MIG_CMD_POSTCOPY_ADVISE: 1810 - return loadvm_postcopy_handle_advise(mis); 1825 + return loadvm_postcopy_handle_advise(mis, len); 1811 1826 1812 1827 case MIG_CMD_POSTCOPY_LISTEN: 1813 1828 return loadvm_postcopy_handle_listen(mis); ··· 2266 2281 } 2267 2282 qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-save-state"); 2268 2283 f = qemu_fopen_channel_output(QIO_CHANNEL(ioc)); 2284 + object_unref(OBJECT(ioc)); 2269 2285 ret = qemu_save_device_state(f); 2270 2286 qemu_fclose(f); 2271 2287 if (ret < 0) { ··· 2313 2329 } 2314 2330 qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-load-state"); 2315 2331 f = qemu_fopen_channel_input(QIO_CHANNEL(ioc)); 2332 + object_unref(OBJECT(ioc)); 2316 2333 2317 2334 ret = qemu_loadvm_state(f); 2318 2335 qemu_fclose(f);
+1 -3
migration/socket.c
··· 79 79 80 80 if (qio_task_propagate_error(task, &err)) { 81 81 trace_migration_socket_outgoing_error(error_get_pretty(err)); 82 - migrate_fd_error(data->s, err); 83 - error_free(err); 84 82 } else { 85 83 trace_migration_socket_outgoing_connected(data->hostname); 86 - migration_channel_connect(data->s, sioc, data->hostname); 87 84 } 85 + migration_channel_connect(data->s, sioc, data->hostname, err); 88 86 object_unref(OBJECT(sioc)); 89 87 } 90 88
+1 -2
migration/tls.c
··· 118 118 119 119 if (qio_task_propagate_error(task, &err)) { 120 120 trace_migration_tls_outgoing_handshake_error(error_get_pretty(err)); 121 - migrate_fd_error(s, err); 122 121 } else { 123 122 trace_migration_tls_outgoing_handshake_complete(); 124 - migration_channel_connect(s, ioc, NULL); 125 123 } 124 + migration_channel_connect(s, ioc, NULL, err); 126 125 object_unref(OBJECT(ioc)); 127 126 } 128 127
+1 -1
migration/trace-events
··· 114 114 process_incoming_migration_co_end(int ret, int ps) "ret=%d postcopy-state=%d" 115 115 process_incoming_migration_co_postcopy_end_main(void) "" 116 116 migration_set_incoming_channel(void *ioc, const char *ioctype) "ioc=%p ioctype=%s" 117 - migration_set_outgoing_channel(void *ioc, const char *ioctype, const char *hostname) "ioc=%p ioctype=%s hostname=%s" 117 + migration_set_outgoing_channel(void *ioc, const char *ioctype, const char *hostname, void *err) "ioc=%p ioctype=%s hostname=%s err=%p" 118 118 119 119 # migration/rdma.c 120 120 qemu_rdma_accept_incoming_migration(void) ""
+90 -54
tests/migration-test.c
··· 268 268 269 269 static void wait_for_migration_complete(QTestState *who) 270 270 { 271 - QDict *rsp, *rsp_return; 272 - bool completed; 273 - 274 - do { 271 + while (true) { 272 + QDict *rsp, *rsp_return; 273 + bool completed; 275 274 const char *status; 276 275 277 276 rsp = wait_command(who, "{ 'execute': 'query-migrate' }"); ··· 280 279 completed = strcmp(status, "completed") == 0; 281 280 g_assert_cmpstr(status, !=, "failed"); 282 281 QDECREF(rsp); 283 - usleep(1000 * 100); 284 - } while (!completed); 282 + if (completed) { 283 + return; 284 + } 285 + usleep(1000); 286 + } 285 287 } 286 288 287 289 static void wait_for_migration_pass(QTestState *who) ··· 290 292 uint64_t pass; 291 293 292 294 /* Wait for the 1st sync */ 293 - do { 295 + while (!got_stop && !initial_pass) { 296 + usleep(1000); 294 297 initial_pass = get_migration_pass(who); 295 - if (got_stop || initial_pass) { 296 - break; 297 - } 298 - usleep(1000 * 100); 299 - } while (true); 298 + } 300 299 301 300 do { 302 - usleep(1000 * 100); 301 + usleep(1000); 303 302 pass = get_migration_pass(who); 304 303 } while (pass == initial_pass && !got_stop); 305 304 } ··· 369 368 QDECREF(rsp); 370 369 } 371 370 372 - static void migrate_set_downtime(QTestState *who, const double value) 373 - { 374 - QDict *rsp; 375 - gchar *cmd; 376 - char *expected; 377 - int64_t result_int; 378 - 379 - cmd = g_strdup_printf("{ 'execute': 'migrate_set_downtime'," 380 - "'arguments': { 'value': %g } }", value); 381 - rsp = qtest_qmp(who, cmd); 382 - g_free(cmd); 383 - g_assert(qdict_haskey(rsp, "return")); 384 - QDECREF(rsp); 385 - result_int = value * 1000L; 386 - expected = g_strdup_printf("%" PRId64, result_int); 387 - migrate_check_parameter(who, "downtime-limit", expected); 388 - g_free(expected); 389 - } 390 - 391 - static void migrate_set_speed(QTestState *who, const char *value) 371 + static void migrate_set_parameter(QTestState *who, const char *parameter, 372 + const char *value) 392 373 { 393 374 QDict *rsp; 394 375 gchar *cmd; 395 376 396 - cmd = g_strdup_printf("{ 'execute': 'migrate_set_speed'," 397 - "'arguments': { 'value': %s } }", value); 377 + cmd = g_strdup_printf("{ 'execute': 'migrate-set-parameters'," 378 + "'arguments': { '%s': %s } }", 379 + parameter, value); 398 380 rsp = qtest_qmp(who, cmd); 399 381 g_free(cmd); 400 382 g_assert(qdict_haskey(rsp, "return")); 401 383 QDECREF(rsp); 402 - migrate_check_parameter(who, "max-bandwidth", value); 384 + migrate_check_parameter(who, parameter, value); 403 385 } 404 386 405 387 static void migrate_set_capability(QTestState *who, const char *capability, ··· 433 415 QDECREF(rsp); 434 416 } 435 417 418 + static void migrate_start_postcopy(QTestState *who) 419 + { 420 + QDict *rsp; 421 + 422 + rsp = wait_command(who, "{ 'execute': 'migrate-start-postcopy' }"); 423 + g_assert(qdict_haskey(rsp, "return")); 424 + QDECREF(rsp); 425 + } 426 + 436 427 static void test_migrate_start(QTestState **from, QTestState **to, 437 428 const char *uri) 438 429 { 439 430 gchar *cmd_src, *cmd_dst; 440 431 char *bootpath = g_strdup_printf("%s/bootsect", tmpfs); 441 432 const char *arch = qtest_get_arch(); 433 + const char *accel = "kvm:tcg"; 442 434 443 435 got_stop = false; 444 436 445 437 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 446 438 init_bootfile_x86(bootpath); 447 - cmd_src = g_strdup_printf("-machine accel=kvm:tcg -m 150M" 448 - " -name pcsource,debug-threads=on" 439 + cmd_src = g_strdup_printf("-machine accel=%s -m 150M" 440 + " -name source,debug-threads=on" 449 441 " -serial file:%s/src_serial" 450 442 " -drive file=%s,format=raw", 451 - tmpfs, bootpath); 452 - cmd_dst = g_strdup_printf("-machine accel=kvm:tcg -m 150M" 453 - " -name pcdest,debug-threads=on" 443 + accel, tmpfs, bootpath); 444 + cmd_dst = g_strdup_printf("-machine accel=%s -m 150M" 445 + " -name target,debug-threads=on" 454 446 " -serial file:%s/dest_serial" 455 447 " -drive file=%s,format=raw" 456 448 " -incoming %s", 457 - tmpfs, bootpath, uri); 449 + accel, tmpfs, bootpath, uri); 458 450 } else if (strcmp(arch, "ppc64") == 0) { 459 - const char *accel; 460 451 461 452 /* On ppc64, the test only works with kvm-hv, but not with kvm-pr */ 462 - accel = access("/sys/module/kvm_hv", F_OK) ? "tcg" : "kvm:tcg"; 453 + if (access("/sys/module/kvm_hv", F_OK)) { 454 + accel = "tcg"; 455 + } 463 456 init_bootfile_ppc(bootpath); 464 457 cmd_src = g_strdup_printf("-machine accel=%s -m 256M" 465 - " -name pcsource,debug-threads=on" 458 + " -name source,debug-threads=on" 466 459 " -serial file:%s/src_serial" 467 460 " -drive file=%s,if=pflash,format=raw", 468 461 accel, tmpfs, bootpath); 469 462 cmd_dst = g_strdup_printf("-machine accel=%s -m 256M" 470 - " -name pcdest,debug-threads=on" 463 + " -name target,debug-threads=on" 471 464 " -serial file:%s/dest_serial" 472 465 " -incoming %s", 473 466 accel, tmpfs, uri); ··· 495 488 /* Destination still running, wait for a byte to change */ 496 489 do { 497 490 qtest_memread(to, start_address, &dest_byte_b, 1); 498 - usleep(10 * 1000); 491 + usleep(1000 * 10); 499 492 } while (dest_byte_a == dest_byte_b); 500 493 501 494 qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}"); 502 495 /* With it stopped, check nothing changes */ 503 496 qtest_memread(to, start_address, &dest_byte_c, 1); 504 - sleep(1); 497 + usleep(1000 * 200); 505 498 qtest_memread(to, start_address, &dest_byte_d, 1); 506 499 g_assert_cmpint(dest_byte_c, ==, dest_byte_d); 507 500 ··· 515 508 cleanup("dest_serial"); 516 509 } 517 510 511 + static void deprecated_set_downtime(QTestState *who, const double value) 512 + { 513 + QDict *rsp; 514 + gchar *cmd; 515 + char *expected; 516 + int64_t result_int; 517 + 518 + cmd = g_strdup_printf("{ 'execute': 'migrate_set_downtime'," 519 + "'arguments': { 'value': %g } }", value); 520 + rsp = qtest_qmp(who, cmd); 521 + g_free(cmd); 522 + g_assert(qdict_haskey(rsp, "return")); 523 + QDECREF(rsp); 524 + result_int = value * 1000L; 525 + expected = g_strdup_printf("%" PRId64, result_int); 526 + migrate_check_parameter(who, "downtime-limit", expected); 527 + g_free(expected); 528 + } 529 + 530 + static void deprecated_set_speed(QTestState *who, const char *value) 531 + { 532 + QDict *rsp; 533 + gchar *cmd; 534 + 535 + cmd = g_strdup_printf("{ 'execute': 'migrate_set_speed'," 536 + "'arguments': { 'value': %s } }", value); 537 + rsp = qtest_qmp(who, cmd); 538 + g_free(cmd); 539 + g_assert(qdict_haskey(rsp, "return")); 540 + QDECREF(rsp); 541 + migrate_check_parameter(who, "max-bandwidth", value); 542 + } 543 + 544 + static void test_deprecated(void) 545 + { 546 + QTestState *from; 547 + 548 + from = qtest_start(""); 549 + 550 + deprecated_set_downtime(from, 0.12345); 551 + deprecated_set_speed(from, "12345"); 552 + 553 + qtest_quit(from); 554 + } 555 + 518 556 static void test_migrate(void) 519 557 { 520 558 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 521 559 QTestState *from, *to; 522 - QDict *rsp; 523 560 524 561 test_migrate_start(&from, &to, uri); 525 562 ··· 530 567 * quickly, but that it doesn't complete precopy even on a slow 531 568 * machine, so also set the downtime. 532 569 */ 533 - migrate_set_speed(from, "100000000"); 534 - migrate_set_downtime(from, 0.001); 570 + migrate_set_parameter(from, "max-bandwidth", "100000000"); 571 + migrate_set_parameter(from, "downtime-limit", "1"); 535 572 536 573 /* Wait for the first serial output from the source */ 537 574 wait_for_serial("src_serial"); ··· 540 577 541 578 wait_for_migration_pass(from); 542 579 543 - rsp = wait_command(from, "{ 'execute': 'migrate-start-postcopy' }"); 544 - g_assert(qdict_haskey(rsp, "return")); 545 - QDECREF(rsp); 580 + migrate_start_postcopy(from); 546 581 547 582 if (!got_stop) { 548 583 qtest_qmp_eventwait(from, "STOP"); ··· 578 613 module_call_init(MODULE_INIT_QOM); 579 614 580 615 qtest_add_func("/migration/postcopy/unix", test_migrate); 616 + qtest_add_func("/migration/deprecated", test_deprecated); 581 617 582 618 ret = g_test_run(); 583 619