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