qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at jcs-vmm 650 lines 17 kB view raw
1/* 2 * Block replication tests 3 * 4 * Copyright (c) 2016 FUJITSU LIMITED 5 * Author: Changlong Xie <xiecl.fnst@cn.fujitsu.com> 6 * 7 * This work is licensed under the terms of the GNU GPL, version 2 or 8 * later. See the COPYING file in the top-level directory. 9 */ 10 11#include "qemu/osdep.h" 12 13#include "qapi/error.h" 14#include "qapi/qmp/qdict.h" 15#include "qemu/option.h" 16#include "qemu/main-loop.h" 17#include "replication.h" 18#include "block/block_int.h" 19#include "block/qdict.h" 20#include "sysemu/block-backend.h" 21 22#define IMG_SIZE (64 * 1024 * 1024) 23 24/* primary */ 25#define P_ID "primary-id" 26static char p_local_disk[] = "/tmp/p_local_disk.XXXXXX"; 27 28/* secondary */ 29#define S_ID "secondary-id" 30#define S_LOCAL_DISK_ID "secondary-local-disk-id" 31static char s_local_disk[] = "/tmp/s_local_disk.XXXXXX"; 32static char s_active_disk[] = "/tmp/s_active_disk.XXXXXX"; 33static char s_hidden_disk[] = "/tmp/s_hidden_disk.XXXXXX"; 34 35/* FIXME: steal from blockdev.c */ 36QemuOptsList qemu_drive_opts = { 37 .name = "drive", 38 .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head), 39 .desc = { 40 { /* end of list */ } 41 }, 42}; 43 44#define NOT_DONE 0x7fffffff 45 46static void blk_rw_done(void *opaque, int ret) 47{ 48 *(int *)opaque = ret; 49} 50 51static void test_blk_read(BlockBackend *blk, long pattern, 52 int64_t pattern_offset, int64_t pattern_count, 53 int64_t offset, int64_t count, 54 bool expect_failed) 55{ 56 void *pattern_buf = NULL; 57 QEMUIOVector qiov; 58 void *cmp_buf = NULL; 59 int async_ret = NOT_DONE; 60 61 if (pattern) { 62 cmp_buf = g_malloc(pattern_count); 63 memset(cmp_buf, pattern, pattern_count); 64 } 65 66 pattern_buf = g_malloc(count); 67 if (pattern) { 68 memset(pattern_buf, pattern, count); 69 } else { 70 memset(pattern_buf, 0x00, count); 71 } 72 73 qemu_iovec_init(&qiov, 1); 74 qemu_iovec_add(&qiov, pattern_buf, count); 75 76 blk_aio_preadv(blk, offset, &qiov, 0, blk_rw_done, &async_ret); 77 while (async_ret == NOT_DONE) { 78 main_loop_wait(false); 79 } 80 81 if (expect_failed) { 82 g_assert(async_ret != 0); 83 } else { 84 g_assert(async_ret == 0); 85 if (pattern) { 86 g_assert(memcmp(pattern_buf + pattern_offset, 87 cmp_buf, pattern_count) <= 0); 88 } 89 } 90 91 g_free(pattern_buf); 92 g_free(cmp_buf); 93 qemu_iovec_destroy(&qiov); 94} 95 96static void test_blk_write(BlockBackend *blk, long pattern, int64_t offset, 97 int64_t count, bool expect_failed) 98{ 99 void *pattern_buf = NULL; 100 QEMUIOVector qiov; 101 int async_ret = NOT_DONE; 102 103 pattern_buf = g_malloc(count); 104 if (pattern) { 105 memset(pattern_buf, pattern, count); 106 } else { 107 memset(pattern_buf, 0x00, count); 108 } 109 110 qemu_iovec_init(&qiov, 1); 111 qemu_iovec_add(&qiov, pattern_buf, count); 112 113 blk_aio_pwritev(blk, offset, &qiov, 0, blk_rw_done, &async_ret); 114 while (async_ret == NOT_DONE) { 115 main_loop_wait(false); 116 } 117 118 if (expect_failed) { 119 g_assert(async_ret != 0); 120 } else { 121 g_assert(async_ret == 0); 122 } 123 124 g_free(pattern_buf); 125 qemu_iovec_destroy(&qiov); 126} 127 128/* 129 * Create a uniquely-named empty temporary file. 130 */ 131static void make_temp(char *template) 132{ 133 int fd; 134 135 fd = mkstemp(template); 136 g_assert(fd >= 0); 137 close(fd); 138} 139 140static void prepare_imgs(void) 141{ 142 Error *local_err = NULL; 143 144 make_temp(p_local_disk); 145 make_temp(s_local_disk); 146 make_temp(s_active_disk); 147 make_temp(s_hidden_disk); 148 149 /* Primary */ 150 bdrv_img_create(p_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, 151 BDRV_O_RDWR, true, &local_err); 152 g_assert(!local_err); 153 154 /* Secondary */ 155 bdrv_img_create(s_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, 156 BDRV_O_RDWR, true, &local_err); 157 g_assert(!local_err); 158 bdrv_img_create(s_active_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, 159 BDRV_O_RDWR, true, &local_err); 160 g_assert(!local_err); 161 bdrv_img_create(s_hidden_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, 162 BDRV_O_RDWR, true, &local_err); 163 g_assert(!local_err); 164} 165 166static void cleanup_imgs(void) 167{ 168 /* Primary */ 169 unlink(p_local_disk); 170 171 /* Secondary */ 172 unlink(s_local_disk); 173 unlink(s_active_disk); 174 unlink(s_hidden_disk); 175} 176 177static BlockBackend *start_primary(void) 178{ 179 BlockBackend *blk; 180 QemuOpts *opts; 181 QDict *qdict; 182 Error *local_err = NULL; 183 char *cmdline; 184 185 cmdline = g_strdup_printf("driver=replication,mode=primary,node-name=xxx," 186 "file.driver=qcow2,file.file.filename=%s," 187 "file.file.locking=off" 188 , p_local_disk); 189 opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false); 190 g_free(cmdline); 191 192 qdict = qemu_opts_to_qdict(opts, NULL); 193 qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); 194 qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); 195 196 blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err); 197 g_assert(blk); 198 g_assert(!local_err); 199 200 monitor_add_blk(blk, P_ID, &local_err); 201 g_assert(!local_err); 202 203 qemu_opts_del(opts); 204 205 return blk; 206} 207 208static void teardown_primary(void) 209{ 210 BlockBackend *blk; 211 AioContext *ctx; 212 213 /* remove P_ID */ 214 blk = blk_by_name(P_ID); 215 assert(blk); 216 217 ctx = blk_get_aio_context(blk); 218 aio_context_acquire(ctx); 219 monitor_remove_blk(blk); 220 blk_unref(blk); 221 aio_context_release(ctx); 222} 223 224static void test_primary_read(void) 225{ 226 BlockBackend *blk; 227 228 blk = start_primary(); 229 230 /* read from 0 to IMG_SIZE */ 231 test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true); 232 233 teardown_primary(); 234} 235 236static void test_primary_write(void) 237{ 238 BlockBackend *blk; 239 240 blk = start_primary(); 241 242 /* write from 0 to IMG_SIZE */ 243 test_blk_write(blk, 0, 0, IMG_SIZE, true); 244 245 teardown_primary(); 246} 247 248static void test_primary_start(void) 249{ 250 BlockBackend *blk = NULL; 251 Error *local_err = NULL; 252 253 blk = start_primary(); 254 255 replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); 256 g_assert(!local_err); 257 258 /* read from 0 to IMG_SIZE */ 259 test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true); 260 261 /* write 0x22 from 0 to IMG_SIZE */ 262 test_blk_write(blk, 0x22, 0, IMG_SIZE, false); 263 264 teardown_primary(); 265} 266 267static void test_primary_stop(void) 268{ 269 Error *local_err = NULL; 270 bool failover = true; 271 272 start_primary(); 273 274 replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); 275 g_assert(!local_err); 276 277 replication_stop_all(failover, &local_err); 278 g_assert(!local_err); 279 280 teardown_primary(); 281} 282 283static void test_primary_do_checkpoint(void) 284{ 285 Error *local_err = NULL; 286 287 start_primary(); 288 289 replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); 290 g_assert(!local_err); 291 292 replication_do_checkpoint_all(&local_err); 293 g_assert(!local_err); 294 295 teardown_primary(); 296} 297 298static void test_primary_get_error_all(void) 299{ 300 Error *local_err = NULL; 301 302 start_primary(); 303 304 replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); 305 g_assert(!local_err); 306 307 replication_get_error_all(&local_err); 308 g_assert(!local_err); 309 310 teardown_primary(); 311} 312 313static BlockBackend *start_secondary(void) 314{ 315 QemuOpts *opts; 316 QDict *qdict; 317 BlockBackend *blk; 318 char *cmdline; 319 Error *local_err = NULL; 320 321 /* add s_local_disk and forge S_LOCAL_DISK_ID */ 322 cmdline = g_strdup_printf("file.filename=%s,driver=qcow2," 323 "file.locking=off", 324 s_local_disk); 325 opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false); 326 g_free(cmdline); 327 328 qdict = qemu_opts_to_qdict(opts, NULL); 329 qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); 330 qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); 331 332 blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err); 333 assert(blk); 334 monitor_add_blk(blk, S_LOCAL_DISK_ID, &local_err); 335 g_assert(!local_err); 336 337 /* format s_local_disk with pattern "0x11" */ 338 test_blk_write(blk, 0x11, 0, IMG_SIZE, false); 339 340 qemu_opts_del(opts); 341 342 /* add S_(ACTIVE/HIDDEN)_DISK and forge S_ID */ 343 cmdline = g_strdup_printf("driver=replication,mode=secondary,top-id=%s," 344 "file.driver=qcow2,file.file.filename=%s," 345 "file.file.locking=off," 346 "file.backing.driver=qcow2," 347 "file.backing.file.filename=%s," 348 "file.backing.file.locking=off," 349 "file.backing.backing=%s" 350 , S_ID, s_active_disk, s_hidden_disk 351 , S_LOCAL_DISK_ID); 352 opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false); 353 g_free(cmdline); 354 355 qdict = qemu_opts_to_qdict(opts, NULL); 356 qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); 357 qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); 358 359 blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err); 360 assert(blk); 361 monitor_add_blk(blk, S_ID, &local_err); 362 g_assert(!local_err); 363 364 qemu_opts_del(opts); 365 366 return blk; 367} 368 369static void teardown_secondary(void) 370{ 371 /* only need to destroy two BBs */ 372 BlockBackend *blk; 373 AioContext *ctx; 374 375 /* remove S_LOCAL_DISK_ID */ 376 blk = blk_by_name(S_LOCAL_DISK_ID); 377 assert(blk); 378 379 ctx = blk_get_aio_context(blk); 380 aio_context_acquire(ctx); 381 monitor_remove_blk(blk); 382 blk_unref(blk); 383 aio_context_release(ctx); 384 385 /* remove S_ID */ 386 blk = blk_by_name(S_ID); 387 assert(blk); 388 389 ctx = blk_get_aio_context(blk); 390 aio_context_acquire(ctx); 391 monitor_remove_blk(blk); 392 blk_unref(blk); 393 aio_context_release(ctx); 394} 395 396static void test_secondary_read(void) 397{ 398 BlockBackend *blk; 399 400 blk = start_secondary(); 401 402 /* read from 0 to IMG_SIZE */ 403 test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true); 404 405 teardown_secondary(); 406} 407 408static void test_secondary_write(void) 409{ 410 BlockBackend *blk; 411 412 blk = start_secondary(); 413 414 /* write from 0 to IMG_SIZE */ 415 test_blk_write(blk, 0, 0, IMG_SIZE, true); 416 417 teardown_secondary(); 418} 419 420static void test_secondary_start(void) 421{ 422 BlockBackend *top_blk, *local_blk; 423 Error *local_err = NULL; 424 bool failover = true; 425 426 top_blk = start_secondary(); 427 replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); 428 g_assert(!local_err); 429 430 /* read from s_local_disk (0, IMG_SIZE) */ 431 test_blk_read(top_blk, 0x11, 0, IMG_SIZE, 0, IMG_SIZE, false); 432 433 /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 434 local_blk = blk_by_name(S_LOCAL_DISK_ID); 435 test_blk_write(local_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, false); 436 437 /* replication will backup s_local_disk to s_hidden_disk */ 438 test_blk_read(top_blk, 0x11, IMG_SIZE / 2, 439 IMG_SIZE / 2, 0, IMG_SIZE, false); 440 441 /* write 0x33 to s_active_disk (0, IMG_SIZE / 2) */ 442 test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false); 443 444 /* read from s_active_disk (0, IMG_SIZE/2) */ 445 test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2, 446 0, IMG_SIZE / 2, false); 447 448 /* unblock top_bs */ 449 replication_stop_all(failover, &local_err); 450 g_assert(!local_err); 451 452 teardown_secondary(); 453} 454 455 456static void test_secondary_stop(void) 457{ 458 BlockBackend *top_blk, *local_blk; 459 Error *local_err = NULL; 460 bool failover = true; 461 462 top_blk = start_secondary(); 463 replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); 464 g_assert(!local_err); 465 466 /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 467 local_blk = blk_by_name(S_LOCAL_DISK_ID); 468 test_blk_write(local_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, false); 469 470 /* replication will backup s_local_disk to s_hidden_disk */ 471 test_blk_read(top_blk, 0x11, IMG_SIZE / 2, 472 IMG_SIZE / 2, 0, IMG_SIZE, false); 473 474 /* write 0x33 to s_active_disk (0, IMG_SIZE / 2) */ 475 test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false); 476 477 /* do active commit */ 478 replication_stop_all(failover, &local_err); 479 g_assert(!local_err); 480 481 /* read from s_local_disk (0, IMG_SIZE / 2) */ 482 test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2, 483 0, IMG_SIZE / 2, false); 484 485 486 /* read from s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 487 test_blk_read(top_blk, 0x22, IMG_SIZE / 2, 488 IMG_SIZE / 2, 0, IMG_SIZE, false); 489 490 teardown_secondary(); 491} 492 493static void test_secondary_continuous_replication(void) 494{ 495 BlockBackend *top_blk, *local_blk; 496 Error *local_err = NULL; 497 498 top_blk = start_secondary(); 499 replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); 500 g_assert(!local_err); 501 502 /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 503 local_blk = blk_by_name(S_LOCAL_DISK_ID); 504 test_blk_write(local_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, false); 505 506 /* replication will backup s_local_disk to s_hidden_disk */ 507 test_blk_read(top_blk, 0x11, IMG_SIZE / 2, 508 IMG_SIZE / 2, 0, IMG_SIZE, false); 509 510 /* write 0x33 to s_active_disk (0, IMG_SIZE / 2) */ 511 test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false); 512 513 /* do failover (active commit) */ 514 replication_stop_all(true, &local_err); 515 g_assert(!local_err); 516 517 /* it should ignore all requests from now on */ 518 519 /* start after failover */ 520 replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); 521 g_assert(!local_err); 522 523 /* checkpoint */ 524 replication_do_checkpoint_all(&local_err); 525 g_assert(!local_err); 526 527 /* stop */ 528 replication_stop_all(true, &local_err); 529 g_assert(!local_err); 530 531 /* read from s_local_disk (0, IMG_SIZE / 2) */ 532 test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2, 533 0, IMG_SIZE / 2, false); 534 535 536 /* read from s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 537 test_blk_read(top_blk, 0x22, IMG_SIZE / 2, 538 IMG_SIZE / 2, 0, IMG_SIZE, false); 539 540 teardown_secondary(); 541} 542 543static void test_secondary_do_checkpoint(void) 544{ 545 BlockBackend *top_blk, *local_blk; 546 Error *local_err = NULL; 547 bool failover = true; 548 549 top_blk = start_secondary(); 550 replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); 551 g_assert(!local_err); 552 553 /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 554 local_blk = blk_by_name(S_LOCAL_DISK_ID); 555 test_blk_write(local_blk, 0x22, IMG_SIZE / 2, 556 IMG_SIZE / 2, false); 557 558 /* replication will backup s_local_disk to s_hidden_disk */ 559 test_blk_read(top_blk, 0x11, IMG_SIZE / 2, 560 IMG_SIZE / 2, 0, IMG_SIZE, false); 561 562 replication_do_checkpoint_all(&local_err); 563 g_assert(!local_err); 564 565 /* after checkpoint, read pattern 0x22 from s_local_disk */ 566 test_blk_read(top_blk, 0x22, IMG_SIZE / 2, 567 IMG_SIZE / 2, 0, IMG_SIZE, false); 568 569 /* unblock top_bs */ 570 replication_stop_all(failover, &local_err); 571 g_assert(!local_err); 572 573 teardown_secondary(); 574} 575 576static void test_secondary_get_error_all(void) 577{ 578 Error *local_err = NULL; 579 bool failover = true; 580 581 start_secondary(); 582 replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); 583 g_assert(!local_err); 584 585 replication_get_error_all(&local_err); 586 g_assert(!local_err); 587 588 /* unblock top_bs */ 589 replication_stop_all(failover, &local_err); 590 g_assert(!local_err); 591 592 teardown_secondary(); 593} 594 595static void sigabrt_handler(int signo) 596{ 597 cleanup_imgs(); 598} 599 600static void setup_sigabrt_handler(void) 601{ 602 struct sigaction sigact; 603 604 sigact = (struct sigaction) { 605 .sa_handler = sigabrt_handler, 606 .sa_flags = SA_RESETHAND, 607 }; 608 sigemptyset(&sigact.sa_mask); 609 sigaction(SIGABRT, &sigact, NULL); 610} 611 612int main(int argc, char **argv) 613{ 614 int ret; 615 qemu_init_main_loop(&error_fatal); 616 bdrv_init(); 617 618 g_test_init(&argc, &argv, NULL); 619 setup_sigabrt_handler(); 620 621 prepare_imgs(); 622 623 /* Primary */ 624 g_test_add_func("/replication/primary/read", test_primary_read); 625 g_test_add_func("/replication/primary/write", test_primary_write); 626 g_test_add_func("/replication/primary/start", test_primary_start); 627 g_test_add_func("/replication/primary/stop", test_primary_stop); 628 g_test_add_func("/replication/primary/do_checkpoint", 629 test_primary_do_checkpoint); 630 g_test_add_func("/replication/primary/get_error_all", 631 test_primary_get_error_all); 632 633 /* Secondary */ 634 g_test_add_func("/replication/secondary/read", test_secondary_read); 635 g_test_add_func("/replication/secondary/write", test_secondary_write); 636 g_test_add_func("/replication/secondary/start", test_secondary_start); 637 g_test_add_func("/replication/secondary/stop", test_secondary_stop); 638 g_test_add_func("/replication/secondary/continuous_replication", 639 test_secondary_continuous_replication); 640 g_test_add_func("/replication/secondary/do_checkpoint", 641 test_secondary_do_checkpoint); 642 g_test_add_func("/replication/secondary/get_error_all", 643 test_secondary_get_error_all); 644 645 ret = g_test_run(); 646 647 cleanup_imgs(); 648 649 return ret; 650}