qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 605 lines 16 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 make_temp(p_local_disk); 143 make_temp(s_local_disk); 144 make_temp(s_active_disk); 145 make_temp(s_hidden_disk); 146 147 /* Primary */ 148 bdrv_img_create(p_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, 149 BDRV_O_RDWR, true, &error_abort); 150 151 /* Secondary */ 152 bdrv_img_create(s_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, 153 BDRV_O_RDWR, true, &error_abort); 154 bdrv_img_create(s_active_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, 155 BDRV_O_RDWR, true, &error_abort); 156 bdrv_img_create(s_hidden_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE, 157 BDRV_O_RDWR, true, &error_abort); 158} 159 160static void cleanup_imgs(void) 161{ 162 /* Primary */ 163 unlink(p_local_disk); 164 165 /* Secondary */ 166 unlink(s_local_disk); 167 unlink(s_active_disk); 168 unlink(s_hidden_disk); 169} 170 171static BlockBackend *start_primary(void) 172{ 173 BlockBackend *blk; 174 QemuOpts *opts; 175 QDict *qdict; 176 char *cmdline; 177 178 cmdline = g_strdup_printf("driver=replication,mode=primary,node-name=xxx," 179 "file.driver=qcow2,file.file.filename=%s," 180 "file.file.locking=off" 181 , p_local_disk); 182 opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false); 183 g_free(cmdline); 184 185 qdict = qemu_opts_to_qdict(opts, NULL); 186 qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); 187 qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); 188 189 blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &error_abort); 190 g_assert(blk); 191 192 monitor_add_blk(blk, P_ID, &error_abort); 193 194 qemu_opts_del(opts); 195 196 return blk; 197} 198 199static void teardown_primary(void) 200{ 201 BlockBackend *blk; 202 AioContext *ctx; 203 204 /* remove P_ID */ 205 blk = blk_by_name(P_ID); 206 assert(blk); 207 208 ctx = blk_get_aio_context(blk); 209 aio_context_acquire(ctx); 210 monitor_remove_blk(blk); 211 blk_unref(blk); 212 aio_context_release(ctx); 213} 214 215static void test_primary_read(void) 216{ 217 BlockBackend *blk; 218 219 blk = start_primary(); 220 221 /* read from 0 to IMG_SIZE */ 222 test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true); 223 224 teardown_primary(); 225} 226 227static void test_primary_write(void) 228{ 229 BlockBackend *blk; 230 231 blk = start_primary(); 232 233 /* write from 0 to IMG_SIZE */ 234 test_blk_write(blk, 0, 0, IMG_SIZE, true); 235 236 teardown_primary(); 237} 238 239static void test_primary_start(void) 240{ 241 BlockBackend *blk = NULL; 242 243 blk = start_primary(); 244 245 replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort); 246 247 /* read from 0 to IMG_SIZE */ 248 test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true); 249 250 /* write 0x22 from 0 to IMG_SIZE */ 251 test_blk_write(blk, 0x22, 0, IMG_SIZE, false); 252 253 teardown_primary(); 254} 255 256static void test_primary_stop(void) 257{ 258 bool failover = true; 259 260 start_primary(); 261 262 replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort); 263 264 replication_stop_all(failover, &error_abort); 265 266 teardown_primary(); 267} 268 269static void test_primary_do_checkpoint(void) 270{ 271 start_primary(); 272 273 replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort); 274 275 replication_do_checkpoint_all(&error_abort); 276 277 teardown_primary(); 278} 279 280static void test_primary_get_error_all(void) 281{ 282 start_primary(); 283 284 replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort); 285 286 replication_get_error_all(&error_abort); 287 288 teardown_primary(); 289} 290 291static BlockBackend *start_secondary(void) 292{ 293 QemuOpts *opts; 294 QDict *qdict; 295 BlockBackend *blk; 296 char *cmdline; 297 298 /* add s_local_disk and forge S_LOCAL_DISK_ID */ 299 cmdline = g_strdup_printf("file.filename=%s,driver=qcow2," 300 "file.locking=off", 301 s_local_disk); 302 opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false); 303 g_free(cmdline); 304 305 qdict = qemu_opts_to_qdict(opts, NULL); 306 qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); 307 qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); 308 309 blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &error_abort); 310 assert(blk); 311 monitor_add_blk(blk, S_LOCAL_DISK_ID, &error_abort); 312 313 /* format s_local_disk with pattern "0x11" */ 314 test_blk_write(blk, 0x11, 0, IMG_SIZE, false); 315 316 qemu_opts_del(opts); 317 318 /* add S_(ACTIVE/HIDDEN)_DISK and forge S_ID */ 319 cmdline = g_strdup_printf("driver=replication,mode=secondary,top-id=%s," 320 "file.driver=qcow2,file.file.filename=%s," 321 "file.file.locking=off," 322 "file.backing.driver=qcow2," 323 "file.backing.file.filename=%s," 324 "file.backing.file.locking=off," 325 "file.backing.backing=%s" 326 , S_ID, s_active_disk, s_hidden_disk 327 , S_LOCAL_DISK_ID); 328 opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false); 329 g_free(cmdline); 330 331 qdict = qemu_opts_to_qdict(opts, NULL); 332 qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); 333 qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); 334 335 blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &error_abort); 336 assert(blk); 337 monitor_add_blk(blk, S_ID, &error_abort); 338 339 qemu_opts_del(opts); 340 341 return blk; 342} 343 344static void teardown_secondary(void) 345{ 346 /* only need to destroy two BBs */ 347 BlockBackend *blk; 348 AioContext *ctx; 349 350 /* remove S_LOCAL_DISK_ID */ 351 blk = blk_by_name(S_LOCAL_DISK_ID); 352 assert(blk); 353 354 ctx = blk_get_aio_context(blk); 355 aio_context_acquire(ctx); 356 monitor_remove_blk(blk); 357 blk_unref(blk); 358 aio_context_release(ctx); 359 360 /* remove S_ID */ 361 blk = blk_by_name(S_ID); 362 assert(blk); 363 364 ctx = blk_get_aio_context(blk); 365 aio_context_acquire(ctx); 366 monitor_remove_blk(blk); 367 blk_unref(blk); 368 aio_context_release(ctx); 369} 370 371static void test_secondary_read(void) 372{ 373 BlockBackend *blk; 374 375 blk = start_secondary(); 376 377 /* read from 0 to IMG_SIZE */ 378 test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true); 379 380 teardown_secondary(); 381} 382 383static void test_secondary_write(void) 384{ 385 BlockBackend *blk; 386 387 blk = start_secondary(); 388 389 /* write from 0 to IMG_SIZE */ 390 test_blk_write(blk, 0, 0, IMG_SIZE, true); 391 392 teardown_secondary(); 393} 394 395static void test_secondary_start(void) 396{ 397 BlockBackend *top_blk, *local_blk; 398 bool failover = true; 399 400 top_blk = start_secondary(); 401 replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort); 402 403 /* read from s_local_disk (0, IMG_SIZE) */ 404 test_blk_read(top_blk, 0x11, 0, IMG_SIZE, 0, IMG_SIZE, false); 405 406 /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 407 local_blk = blk_by_name(S_LOCAL_DISK_ID); 408 test_blk_write(local_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, false); 409 410 /* replication will backup s_local_disk to s_hidden_disk */ 411 test_blk_read(top_blk, 0x11, IMG_SIZE / 2, 412 IMG_SIZE / 2, 0, IMG_SIZE, false); 413 414 /* write 0x33 to s_active_disk (0, IMG_SIZE / 2) */ 415 test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false); 416 417 /* read from s_active_disk (0, IMG_SIZE/2) */ 418 test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2, 419 0, IMG_SIZE / 2, false); 420 421 /* unblock top_bs */ 422 replication_stop_all(failover, &error_abort); 423 424 teardown_secondary(); 425} 426 427 428static void test_secondary_stop(void) 429{ 430 BlockBackend *top_blk, *local_blk; 431 bool failover = true; 432 433 top_blk = start_secondary(); 434 replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort); 435 436 /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 437 local_blk = blk_by_name(S_LOCAL_DISK_ID); 438 test_blk_write(local_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, false); 439 440 /* replication will backup s_local_disk to s_hidden_disk */ 441 test_blk_read(top_blk, 0x11, IMG_SIZE / 2, 442 IMG_SIZE / 2, 0, IMG_SIZE, false); 443 444 /* write 0x33 to s_active_disk (0, IMG_SIZE / 2) */ 445 test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false); 446 447 /* do active commit */ 448 replication_stop_all(failover, &error_abort); 449 450 /* read from s_local_disk (0, IMG_SIZE / 2) */ 451 test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2, 452 0, IMG_SIZE / 2, false); 453 454 455 /* read from s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 456 test_blk_read(top_blk, 0x22, IMG_SIZE / 2, 457 IMG_SIZE / 2, 0, IMG_SIZE, false); 458 459 teardown_secondary(); 460} 461 462static void test_secondary_continuous_replication(void) 463{ 464 BlockBackend *top_blk, *local_blk; 465 466 top_blk = start_secondary(); 467 replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort); 468 469 /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 470 local_blk = blk_by_name(S_LOCAL_DISK_ID); 471 test_blk_write(local_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, false); 472 473 /* replication will backup s_local_disk to s_hidden_disk */ 474 test_blk_read(top_blk, 0x11, IMG_SIZE / 2, 475 IMG_SIZE / 2, 0, IMG_SIZE, false); 476 477 /* write 0x33 to s_active_disk (0, IMG_SIZE / 2) */ 478 test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false); 479 480 /* do failover (active commit) */ 481 replication_stop_all(true, &error_abort); 482 483 /* it should ignore all requests from now on */ 484 485 /* start after failover */ 486 replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort); 487 488 /* checkpoint */ 489 replication_do_checkpoint_all(&error_abort); 490 491 /* stop */ 492 replication_stop_all(true, &error_abort); 493 494 /* read from s_local_disk (0, IMG_SIZE / 2) */ 495 test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2, 496 0, IMG_SIZE / 2, false); 497 498 499 /* read from s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 500 test_blk_read(top_blk, 0x22, IMG_SIZE / 2, 501 IMG_SIZE / 2, 0, IMG_SIZE, false); 502 503 teardown_secondary(); 504} 505 506static void test_secondary_do_checkpoint(void) 507{ 508 BlockBackend *top_blk, *local_blk; 509 bool failover = true; 510 511 top_blk = start_secondary(); 512 replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort); 513 514 /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */ 515 local_blk = blk_by_name(S_LOCAL_DISK_ID); 516 test_blk_write(local_blk, 0x22, IMG_SIZE / 2, 517 IMG_SIZE / 2, false); 518 519 /* replication will backup s_local_disk to s_hidden_disk */ 520 test_blk_read(top_blk, 0x11, IMG_SIZE / 2, 521 IMG_SIZE / 2, 0, IMG_SIZE, false); 522 523 replication_do_checkpoint_all(&error_abort); 524 525 /* after checkpoint, read pattern 0x22 from s_local_disk */ 526 test_blk_read(top_blk, 0x22, IMG_SIZE / 2, 527 IMG_SIZE / 2, 0, IMG_SIZE, false); 528 529 /* unblock top_bs */ 530 replication_stop_all(failover, &error_abort); 531 532 teardown_secondary(); 533} 534 535static void test_secondary_get_error_all(void) 536{ 537 bool failover = true; 538 539 start_secondary(); 540 replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort); 541 542 replication_get_error_all(&error_abort); 543 544 /* unblock top_bs */ 545 replication_stop_all(failover, &error_abort); 546 547 teardown_secondary(); 548} 549 550static void sigabrt_handler(int signo) 551{ 552 cleanup_imgs(); 553} 554 555static void setup_sigabrt_handler(void) 556{ 557 struct sigaction sigact; 558 559 sigact = (struct sigaction) { 560 .sa_handler = sigabrt_handler, 561 .sa_flags = SA_RESETHAND, 562 }; 563 sigemptyset(&sigact.sa_mask); 564 sigaction(SIGABRT, &sigact, NULL); 565} 566 567int main(int argc, char **argv) 568{ 569 int ret; 570 qemu_init_main_loop(&error_fatal); 571 bdrv_init(); 572 573 g_test_init(&argc, &argv, NULL); 574 setup_sigabrt_handler(); 575 576 prepare_imgs(); 577 578 /* Primary */ 579 g_test_add_func("/replication/primary/read", test_primary_read); 580 g_test_add_func("/replication/primary/write", test_primary_write); 581 g_test_add_func("/replication/primary/start", test_primary_start); 582 g_test_add_func("/replication/primary/stop", test_primary_stop); 583 g_test_add_func("/replication/primary/do_checkpoint", 584 test_primary_do_checkpoint); 585 g_test_add_func("/replication/primary/get_error_all", 586 test_primary_get_error_all); 587 588 /* Secondary */ 589 g_test_add_func("/replication/secondary/read", test_secondary_read); 590 g_test_add_func("/replication/secondary/write", test_secondary_write); 591 g_test_add_func("/replication/secondary/start", test_secondary_start); 592 g_test_add_func("/replication/secondary/stop", test_secondary_stop); 593 g_test_add_func("/replication/secondary/continuous_replication", 594 test_secondary_continuous_replication); 595 g_test_add_func("/replication/secondary/do_checkpoint", 596 test_secondary_do_checkpoint); 597 g_test_add_func("/replication/secondary/get_error_all", 598 test_secondary_get_error_all); 599 600 ret = g_test_run(); 601 602 cleanup_imgs(); 603 604 return ret; 605}