1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 5 */ 6 7 #include "spdk/stdinc.h" 8 9 #include "spdk/bdev.h" 10 #include "spdk/accel.h" 11 #include "spdk/env.h" 12 #include "spdk/log.h" 13 #include "spdk/thread.h" 14 #include "spdk/event.h" 15 #include "spdk/rpc.h" 16 #include "spdk/util.h" 17 #include "spdk/string.h" 18 19 #include "bdev_internal.h" 20 #include "CUnit/Basic.h" 21 22 #define BUFFER_IOVS 1024 23 #define BUFFER_SIZE 260 * 1024 24 #define BDEV_TASK_ARRAY_SIZE 2048 25 26 pthread_mutex_t g_test_mutex; 27 pthread_cond_t g_test_cond; 28 29 static struct spdk_thread *g_thread_init; 30 static struct spdk_thread *g_thread_ut; 31 static struct spdk_thread *g_thread_io; 32 static bool g_wait_for_tests = false; 33 static int g_num_failures = 0; 34 static bool g_shutdown = false; 35 36 struct io_target { 37 struct spdk_bdev *bdev; 38 struct spdk_bdev_desc *bdev_desc; 39 struct spdk_io_channel *ch; 40 struct io_target *next; 41 }; 42 43 struct bdevio_request { 44 char *buf; 45 char *fused_buf; 46 int data_len; 47 uint64_t offset; 48 struct iovec iov[BUFFER_IOVS]; 49 int iovcnt; 50 struct iovec fused_iov[BUFFER_IOVS]; 51 int fused_iovcnt; 52 struct io_target *target; 53 uint64_t src_offset; 54 }; 55 56 struct io_target *g_io_targets = NULL; 57 struct io_target *g_current_io_target = NULL; 58 static void rpc_perform_tests_cb(unsigned num_failures, struct spdk_jsonrpc_request *request); 59 60 static void 61 execute_spdk_function(spdk_msg_fn fn, void *arg) 62 { 63 pthread_mutex_lock(&g_test_mutex); 64 spdk_thread_send_msg(g_thread_io, fn, arg); 65 pthread_cond_wait(&g_test_cond, &g_test_mutex); 66 pthread_mutex_unlock(&g_test_mutex); 67 } 68 69 static void 70 wake_ut_thread(void) 71 { 72 pthread_mutex_lock(&g_test_mutex); 73 pthread_cond_signal(&g_test_cond); 74 pthread_mutex_unlock(&g_test_mutex); 75 } 76 77 static void 78 __get_io_channel(void *arg) 79 { 80 struct io_target *target = arg; 81 82 target->ch = spdk_bdev_get_io_channel(target->bdev_desc); 83 assert(target->ch); 84 wake_ut_thread(); 85 } 86 87 static void 88 bdevio_construct_target_open_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 89 void *event_ctx) 90 { 91 } 92 93 static int 94 bdevio_construct_target(struct spdk_bdev *bdev) 95 { 96 struct io_target *target; 97 int rc; 98 uint64_t num_blocks = spdk_bdev_get_num_blocks(bdev); 99 uint32_t block_size = spdk_bdev_get_block_size(bdev); 100 101 target = malloc(sizeof(struct io_target)); 102 if (target == NULL) { 103 return -ENOMEM; 104 } 105 106 rc = spdk_bdev_open_ext(spdk_bdev_get_name(bdev), true, bdevio_construct_target_open_cb, NULL, 107 &target->bdev_desc); 108 if (rc != 0) { 109 free(target); 110 SPDK_ERRLOG("Could not open leaf bdev %s, error=%d\n", spdk_bdev_get_name(bdev), rc); 111 return rc; 112 } 113 114 printf(" %s: %" PRIu64 " blocks of %" PRIu32 " bytes (%" PRIu64 " MiB)\n", 115 spdk_bdev_get_name(bdev), 116 num_blocks, block_size, 117 (num_blocks * block_size + 1024 * 1024 - 1) / (1024 * 1024)); 118 119 target->bdev = bdev; 120 target->next = g_io_targets; 121 execute_spdk_function(__get_io_channel, target); 122 g_io_targets = target; 123 124 return 0; 125 } 126 127 static int 128 bdevio_construct_targets(void) 129 { 130 struct spdk_bdev *bdev; 131 int rc; 132 133 printf("I/O targets:\n"); 134 135 bdev = spdk_bdev_first_leaf(); 136 while (bdev != NULL) { 137 rc = bdevio_construct_target(bdev); 138 if (rc < 0) { 139 SPDK_ERRLOG("Could not construct bdev %s, error=%d\n", spdk_bdev_get_name(bdev), rc); 140 return rc; 141 } 142 bdev = spdk_bdev_next_leaf(bdev); 143 } 144 145 if (g_io_targets == NULL) { 146 SPDK_ERRLOG("No bdevs to perform tests on\n"); 147 return -1; 148 } 149 150 return 0; 151 } 152 153 static void 154 __put_io_channel(void *arg) 155 { 156 struct io_target *target = arg; 157 158 spdk_put_io_channel(target->ch); 159 wake_ut_thread(); 160 } 161 162 static void 163 bdevio_cleanup_targets(void) 164 { 165 struct io_target *target; 166 167 target = g_io_targets; 168 while (target != NULL) { 169 execute_spdk_function(__put_io_channel, target); 170 spdk_bdev_close(target->bdev_desc); 171 g_io_targets = target->next; 172 free(target); 173 target = g_io_targets; 174 } 175 } 176 177 static bool g_completion_success; 178 179 static void 180 initialize_buffer(char **buf, int pattern, int size) 181 { 182 *buf = spdk_zmalloc(size, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 183 memset(*buf, pattern, size); 184 } 185 186 static void 187 quick_test_complete(struct spdk_bdev_io *bdev_io, bool success, void *arg) 188 { 189 g_completion_success = success; 190 spdk_bdev_free_io(bdev_io); 191 wake_ut_thread(); 192 } 193 194 static uint64_t 195 bdev_bytes_to_blocks(struct spdk_bdev *bdev, uint64_t bytes) 196 { 197 uint32_t block_size = spdk_bdev_get_block_size(bdev); 198 199 CU_ASSERT(bytes % block_size == 0); 200 return bytes / block_size; 201 } 202 203 static void 204 __blockdev_write(void *arg) 205 { 206 struct bdevio_request *req = arg; 207 struct io_target *target = req->target; 208 int rc; 209 210 if (req->iovcnt) { 211 rc = spdk_bdev_writev(target->bdev_desc, target->ch, req->iov, req->iovcnt, req->offset, 212 req->data_len, quick_test_complete, NULL); 213 } else { 214 rc = spdk_bdev_write(target->bdev_desc, target->ch, req->buf, req->offset, 215 req->data_len, quick_test_complete, NULL); 216 } 217 218 if (rc) { 219 g_completion_success = false; 220 wake_ut_thread(); 221 } 222 } 223 224 static void 225 __blockdev_write_zeroes(void *arg) 226 { 227 struct bdevio_request *req = arg; 228 struct io_target *target = req->target; 229 int rc; 230 231 rc = spdk_bdev_write_zeroes(target->bdev_desc, target->ch, req->offset, 232 req->data_len, quick_test_complete, NULL); 233 if (rc) { 234 g_completion_success = false; 235 wake_ut_thread(); 236 } 237 } 238 239 static void 240 __blockdev_compare_and_write(void *arg) 241 { 242 struct bdevio_request *req = arg; 243 struct io_target *target = req->target; 244 struct spdk_bdev *bdev = target->bdev; 245 int rc; 246 247 rc = spdk_bdev_comparev_and_writev_blocks(target->bdev_desc, target->ch, req->iov, req->iovcnt, 248 req->fused_iov, req->fused_iovcnt, bdev_bytes_to_blocks(bdev, req->offset), 249 bdev_bytes_to_blocks(bdev, req->data_len), quick_test_complete, NULL); 250 251 if (rc) { 252 g_completion_success = false; 253 wake_ut_thread(); 254 } 255 } 256 257 static void 258 sgl_chop_buffer(struct bdevio_request *req, int iov_len) 259 { 260 int data_len = req->data_len; 261 char *buf = req->buf; 262 263 req->iovcnt = 0; 264 if (!iov_len) { 265 return; 266 } 267 268 for (; data_len > 0 && req->iovcnt < BUFFER_IOVS; req->iovcnt++) { 269 if (data_len < iov_len) { 270 iov_len = data_len; 271 } 272 273 req->iov[req->iovcnt].iov_base = buf; 274 req->iov[req->iovcnt].iov_len = iov_len; 275 276 buf += iov_len; 277 data_len -= iov_len; 278 } 279 280 CU_ASSERT_EQUAL_FATAL(data_len, 0); 281 } 282 283 static void 284 sgl_chop_fused_buffer(struct bdevio_request *req, int iov_len) 285 { 286 int data_len = req->data_len; 287 char *buf = req->fused_buf; 288 289 req->fused_iovcnt = 0; 290 if (!iov_len) { 291 return; 292 } 293 294 for (; data_len > 0 && req->fused_iovcnt < BUFFER_IOVS; req->fused_iovcnt++) { 295 if (data_len < iov_len) { 296 iov_len = data_len; 297 } 298 299 req->fused_iov[req->fused_iovcnt].iov_base = buf; 300 req->fused_iov[req->fused_iovcnt].iov_len = iov_len; 301 302 buf += iov_len; 303 data_len -= iov_len; 304 } 305 306 CU_ASSERT_EQUAL_FATAL(data_len, 0); 307 } 308 309 static void 310 blockdev_write(struct io_target *target, char *tx_buf, 311 uint64_t offset, int data_len, int iov_len) 312 { 313 struct bdevio_request req; 314 315 req.target = target; 316 req.buf = tx_buf; 317 req.data_len = data_len; 318 req.offset = offset; 319 sgl_chop_buffer(&req, iov_len); 320 321 g_completion_success = false; 322 323 execute_spdk_function(__blockdev_write, &req); 324 } 325 326 static void 327 _blockdev_compare_and_write(struct io_target *target, char *cmp_buf, char *write_buf, 328 uint64_t offset, int data_len, int iov_len) 329 { 330 struct bdevio_request req; 331 332 req.target = target; 333 req.buf = cmp_buf; 334 req.fused_buf = write_buf; 335 req.data_len = data_len; 336 req.offset = offset; 337 sgl_chop_buffer(&req, iov_len); 338 sgl_chop_fused_buffer(&req, iov_len); 339 340 g_completion_success = false; 341 342 execute_spdk_function(__blockdev_compare_and_write, &req); 343 } 344 345 static void 346 blockdev_write_zeroes(struct io_target *target, char *tx_buf, 347 uint64_t offset, int data_len) 348 { 349 struct bdevio_request req; 350 351 req.target = target; 352 req.buf = tx_buf; 353 req.data_len = data_len; 354 req.offset = offset; 355 356 g_completion_success = false; 357 358 execute_spdk_function(__blockdev_write_zeroes, &req); 359 } 360 361 static void 362 __blockdev_read(void *arg) 363 { 364 struct bdevio_request *req = arg; 365 struct io_target *target = req->target; 366 int rc; 367 368 if (req->iovcnt) { 369 rc = spdk_bdev_readv(target->bdev_desc, target->ch, req->iov, req->iovcnt, req->offset, 370 req->data_len, quick_test_complete, NULL); 371 } else { 372 rc = spdk_bdev_read(target->bdev_desc, target->ch, req->buf, req->offset, 373 req->data_len, quick_test_complete, NULL); 374 } 375 376 if (rc) { 377 g_completion_success = false; 378 wake_ut_thread(); 379 } 380 } 381 382 static void 383 blockdev_read(struct io_target *target, char *rx_buf, 384 uint64_t offset, int data_len, int iov_len) 385 { 386 struct bdevio_request req; 387 388 req.target = target; 389 req.buf = rx_buf; 390 req.data_len = data_len; 391 req.offset = offset; 392 req.iovcnt = 0; 393 sgl_chop_buffer(&req, iov_len); 394 395 g_completion_success = false; 396 397 execute_spdk_function(__blockdev_read, &req); 398 } 399 400 static void 401 _blockdev_copy(void *arg) 402 { 403 struct bdevio_request *req = arg; 404 struct io_target *target = req->target; 405 struct spdk_bdev *bdev = target->bdev; 406 int rc; 407 408 rc = spdk_bdev_copy_blocks(target->bdev_desc, target->ch, 409 bdev_bytes_to_blocks(bdev, req->offset), 410 bdev_bytes_to_blocks(bdev, req->src_offset), 411 bdev_bytes_to_blocks(bdev, req->data_len), 412 quick_test_complete, NULL); 413 414 if (rc) { 415 g_completion_success = false; 416 wake_ut_thread(); 417 } 418 } 419 420 static void 421 blockdev_copy(struct io_target *target, uint64_t dst_offset, uint64_t src_offset, int data_len) 422 { 423 struct bdevio_request req; 424 425 req.target = target; 426 req.data_len = data_len; 427 req.offset = dst_offset; 428 req.src_offset = src_offset; 429 430 g_completion_success = false; 431 432 execute_spdk_function(_blockdev_copy, &req); 433 } 434 435 static int 436 blockdev_write_read_data_match(char *rx_buf, char *tx_buf, int data_length) 437 { 438 return memcmp(rx_buf, tx_buf, data_length); 439 } 440 441 static void 442 blockdev_write_read(uint32_t data_length, uint32_t iov_len, int pattern, uint64_t offset, 443 int expected_rc, bool write_zeroes) 444 { 445 struct io_target *target; 446 char *tx_buf = NULL; 447 char *rx_buf = NULL; 448 int rc; 449 uint64_t write_offset = offset; 450 uint32_t write_data_len = data_length; 451 452 target = g_current_io_target; 453 454 if (spdk_bdev_get_write_unit_size(target->bdev) > 1 && expected_rc == 0) { 455 uint32_t write_unit_bytes; 456 457 write_unit_bytes = spdk_bdev_get_write_unit_size(target->bdev) * 458 spdk_bdev_get_block_size(target->bdev); 459 write_offset -= offset % write_unit_bytes; 460 write_data_len += (offset - write_offset); 461 462 if (write_data_len % write_unit_bytes) { 463 write_data_len += write_unit_bytes - write_data_len % write_unit_bytes; 464 } 465 } 466 467 if (!write_zeroes) { 468 initialize_buffer(&tx_buf, pattern, write_data_len); 469 initialize_buffer(&rx_buf, 0, data_length); 470 471 blockdev_write(target, tx_buf, write_offset, write_data_len, iov_len); 472 } else { 473 initialize_buffer(&tx_buf, 0, write_data_len); 474 initialize_buffer(&rx_buf, pattern, data_length); 475 476 blockdev_write_zeroes(target, tx_buf, write_offset, write_data_len); 477 } 478 479 480 if (expected_rc == 0) { 481 CU_ASSERT_EQUAL(g_completion_success, true); 482 } else { 483 CU_ASSERT_EQUAL(g_completion_success, false); 484 } 485 blockdev_read(target, rx_buf, offset, data_length, iov_len); 486 487 if (expected_rc == 0) { 488 CU_ASSERT_EQUAL(g_completion_success, true); 489 } else { 490 CU_ASSERT_EQUAL(g_completion_success, false); 491 } 492 493 if (g_completion_success) { 494 rc = blockdev_write_read_data_match(rx_buf, tx_buf + (offset - write_offset), data_length); 495 /* Assert the write by comparing it with values read 496 * from each blockdev */ 497 CU_ASSERT_EQUAL(rc, 0); 498 } 499 500 spdk_free(rx_buf); 501 spdk_free(tx_buf); 502 } 503 504 static void 505 blockdev_compare_and_write(uint32_t data_length, uint32_t iov_len, uint64_t offset) 506 { 507 struct io_target *target; 508 char *tx_buf = NULL; 509 char *write_buf = NULL; 510 char *rx_buf = NULL; 511 int rc; 512 513 target = g_current_io_target; 514 515 initialize_buffer(&tx_buf, 0xAA, data_length); 516 initialize_buffer(&rx_buf, 0, data_length); 517 initialize_buffer(&write_buf, 0xBB, data_length); 518 519 blockdev_write(target, tx_buf, offset, data_length, iov_len); 520 CU_ASSERT_EQUAL(g_completion_success, true); 521 522 _blockdev_compare_and_write(target, tx_buf, write_buf, offset, data_length, iov_len); 523 CU_ASSERT_EQUAL(g_completion_success, true); 524 525 _blockdev_compare_and_write(target, tx_buf, write_buf, offset, data_length, iov_len); 526 CU_ASSERT_EQUAL(g_completion_success, false); 527 528 blockdev_read(target, rx_buf, offset, data_length, iov_len); 529 CU_ASSERT_EQUAL(g_completion_success, true); 530 rc = blockdev_write_read_data_match(rx_buf, write_buf, data_length); 531 /* Assert the write by comparing it with values read 532 * from each blockdev */ 533 CU_ASSERT_EQUAL(rc, 0); 534 535 spdk_free(rx_buf); 536 spdk_free(tx_buf); 537 spdk_free(write_buf); 538 } 539 540 static void 541 blockdev_write_read_block(void) 542 { 543 uint32_t data_length; 544 uint64_t offset; 545 int pattern; 546 int expected_rc; 547 struct io_target *target = g_current_io_target; 548 struct spdk_bdev *bdev = target->bdev; 549 550 /* Data size = 1 block */ 551 data_length = spdk_bdev_get_block_size(bdev); 552 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 553 offset = 0; 554 pattern = 0xA3; 555 /* Params are valid, hence the expected return value 556 * of write and read for all blockdevs is 0. */ 557 expected_rc = 0; 558 559 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0); 560 } 561 562 static void 563 blockdev_write_zeroes_read_block(void) 564 { 565 uint32_t data_length; 566 uint64_t offset; 567 int pattern; 568 int expected_rc; 569 struct io_target *target = g_current_io_target; 570 struct spdk_bdev *bdev = target->bdev; 571 572 /* Data size = 1 block */ 573 data_length = spdk_bdev_get_block_size(bdev); 574 offset = 0; 575 pattern = 0xA3; 576 /* Params are valid, hence the expected return value 577 * of write_zeroes and read for all blockdevs is 0. */ 578 expected_rc = 0; 579 580 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 1); 581 } 582 583 /* 584 * This i/o will not have to split at the bdev layer. 585 */ 586 static void 587 blockdev_write_zeroes_read_no_split(void) 588 { 589 uint32_t data_length; 590 uint64_t offset; 591 int pattern; 592 int expected_rc; 593 struct io_target *target = g_current_io_target; 594 struct spdk_bdev *bdev = target->bdev; 595 596 /* Data size = block size aligned ZERO_BUFFER_SIZE */ 597 data_length = ZERO_BUFFER_SIZE; /* from bdev_internal.h */ 598 data_length -= ZERO_BUFFER_SIZE % spdk_bdev_get_block_size(bdev); 599 offset = 0; 600 pattern = 0xA3; 601 /* Params are valid, hence the expected return value 602 * of write_zeroes and read for all blockdevs is 0. */ 603 expected_rc = 0; 604 605 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 1); 606 } 607 608 /* 609 * This i/o will have to split at the bdev layer if 610 * write-zeroes is not supported by the bdev. 611 */ 612 static void 613 blockdev_write_zeroes_read_split(void) 614 { 615 uint32_t data_length; 616 uint64_t offset; 617 int pattern; 618 int expected_rc; 619 struct io_target *target = g_current_io_target; 620 struct spdk_bdev *bdev = target->bdev; 621 622 /* Data size = block size aligned 3 * ZERO_BUFFER_SIZE */ 623 data_length = 3 * ZERO_BUFFER_SIZE; /* from bdev_internal.h */ 624 data_length -= data_length % spdk_bdev_get_block_size(bdev); 625 offset = 0; 626 pattern = 0xA3; 627 /* Params are valid, hence the expected return value 628 * of write_zeroes and read for all blockdevs is 0. */ 629 expected_rc = 0; 630 631 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 1); 632 } 633 634 /* 635 * This i/o will have to split at the bdev layer if 636 * write-zeroes is not supported by the bdev. It also 637 * tests a write size that is not an even multiple of 638 * the bdev layer zero buffer size. 639 */ 640 static void 641 blockdev_write_zeroes_read_split_partial(void) 642 { 643 uint32_t data_length; 644 uint64_t offset; 645 int pattern; 646 int expected_rc; 647 struct io_target *target = g_current_io_target; 648 struct spdk_bdev *bdev = target->bdev; 649 uint32_t block_size = spdk_bdev_get_block_size(bdev); 650 651 /* Data size = block size aligned 7 * ZERO_BUFFER_SIZE / 2 */ 652 data_length = ZERO_BUFFER_SIZE * 7 / 2; 653 data_length -= data_length % block_size; 654 offset = 0; 655 pattern = 0xA3; 656 /* Params are valid, hence the expected return value 657 * of write_zeroes and read for all blockdevs is 0. */ 658 expected_rc = 0; 659 660 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 1); 661 } 662 663 static void 664 blockdev_writev_readv_block(void) 665 { 666 uint32_t data_length, iov_len; 667 uint64_t offset; 668 int pattern; 669 int expected_rc; 670 struct io_target *target = g_current_io_target; 671 struct spdk_bdev *bdev = target->bdev; 672 673 /* Data size = 1 block */ 674 data_length = spdk_bdev_get_block_size(bdev); 675 iov_len = data_length; 676 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 677 offset = 0; 678 pattern = 0xA3; 679 /* Params are valid, hence the expected return value 680 * of write and read for all blockdevs is 0. */ 681 expected_rc = 0; 682 683 blockdev_write_read(data_length, iov_len, pattern, offset, expected_rc, 0); 684 } 685 686 static void 687 blockdev_comparev_and_writev(void) 688 { 689 uint32_t data_length, iov_len; 690 uint64_t offset; 691 struct io_target *target = g_current_io_target; 692 struct spdk_bdev *bdev = target->bdev; 693 694 if (spdk_bdev_is_md_separate(bdev)) { 695 /* TODO: remove this check once bdev layer properly supports 696 * compare and write for bdevs with separate md. 697 */ 698 SPDK_ERRLOG("skipping comparev_and_writev on bdev %s since it has\n" 699 "separate metadata which is not supported yet.\n", 700 spdk_bdev_get_name(bdev)); 701 return; 702 } 703 704 /* Data size = acwu size */ 705 data_length = spdk_bdev_get_block_size(bdev) * spdk_bdev_get_acwu(bdev); 706 iov_len = data_length; 707 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 708 offset = 0; 709 710 blockdev_compare_and_write(data_length, iov_len, offset); 711 } 712 713 static void 714 blockdev_writev_readv_30x1block(void) 715 { 716 uint32_t data_length, iov_len; 717 uint64_t offset; 718 int pattern; 719 int expected_rc; 720 struct io_target *target = g_current_io_target; 721 struct spdk_bdev *bdev = target->bdev; 722 uint32_t block_size = spdk_bdev_get_block_size(bdev); 723 724 /* Data size = 30 * block size */ 725 data_length = block_size * 30; 726 iov_len = block_size; 727 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 728 offset = 0; 729 pattern = 0xA3; 730 /* Params are valid, hence the expected return value 731 * of write and read for all blockdevs is 0. */ 732 expected_rc = 0; 733 734 blockdev_write_read(data_length, iov_len, pattern, offset, expected_rc, 0); 735 } 736 737 static void 738 blockdev_write_read_8blocks(void) 739 { 740 uint32_t data_length; 741 uint64_t offset; 742 int pattern; 743 int expected_rc; 744 struct io_target *target = g_current_io_target; 745 struct spdk_bdev *bdev = target->bdev; 746 747 /* Data size = 8 * block size */ 748 data_length = spdk_bdev_get_block_size(bdev) * 8; 749 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 750 offset = data_length; 751 pattern = 0xA3; 752 /* Params are valid, hence the expected return value 753 * of write and read for all blockdevs is 0. */ 754 expected_rc = 0; 755 756 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0); 757 } 758 759 static void 760 blockdev_writev_readv_8blocks(void) 761 { 762 uint32_t data_length, iov_len; 763 uint64_t offset; 764 int pattern; 765 int expected_rc; 766 struct io_target *target = g_current_io_target; 767 struct spdk_bdev *bdev = target->bdev; 768 769 /* Data size = 8 * block size */ 770 data_length = spdk_bdev_get_block_size(bdev) * 8; 771 iov_len = data_length; 772 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 773 offset = data_length; 774 pattern = 0xA3; 775 /* Params are valid, hence the expected return value 776 * of write and read for all blockdevs is 0. */ 777 expected_rc = 0; 778 779 blockdev_write_read(data_length, iov_len, pattern, offset, expected_rc, 0); 780 } 781 782 static void 783 blockdev_write_read_size_gt_128k(void) 784 { 785 uint32_t data_length; 786 uint64_t offset; 787 int pattern; 788 int expected_rc; 789 struct io_target *target = g_current_io_target; 790 struct spdk_bdev *bdev = target->bdev; 791 uint32_t block_size = spdk_bdev_get_block_size(bdev); 792 793 /* Data size = block size aligned 128K + 1 block */ 794 data_length = 128 * 1024; 795 data_length -= data_length % block_size; 796 data_length += block_size; 797 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 798 offset = block_size * 2; 799 pattern = 0xA3; 800 /* Params are valid, hence the expected return value 801 * of write and read for all blockdevs is 0. */ 802 expected_rc = 0; 803 804 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0); 805 } 806 807 static void 808 blockdev_writev_readv_size_gt_128k(void) 809 { 810 uint32_t data_length, iov_len; 811 uint64_t offset; 812 int pattern; 813 int expected_rc; 814 struct io_target *target = g_current_io_target; 815 struct spdk_bdev *bdev = target->bdev; 816 uint32_t block_size = spdk_bdev_get_block_size(bdev); 817 818 /* Data size = block size aligned 128K + 1 block */ 819 data_length = 128 * 1024; 820 data_length -= data_length % block_size; 821 data_length += block_size; 822 iov_len = data_length; 823 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 824 offset = block_size * 2; 825 pattern = 0xA3; 826 /* Params are valid, hence the expected return value 827 * of write and read for all blockdevs is 0. */ 828 expected_rc = 0; 829 830 blockdev_write_read(data_length, iov_len, pattern, offset, expected_rc, 0); 831 } 832 833 static void 834 blockdev_writev_readv_size_gt_128k_two_iov(void) 835 { 836 uint32_t data_length, iov_len; 837 uint64_t offset; 838 int pattern; 839 int expected_rc; 840 struct io_target *target = g_current_io_target; 841 struct spdk_bdev *bdev = target->bdev; 842 uint32_t block_size = spdk_bdev_get_block_size(bdev); 843 844 /* Data size = block size aligned 128K + 1 block */ 845 data_length = 128 * 1024; 846 data_length -= data_length % block_size; 847 iov_len = data_length; 848 data_length += block_size; 849 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 850 offset = block_size * 2; 851 pattern = 0xA3; 852 /* Params are valid, hence the expected return value 853 * of write and read for all blockdevs is 0. */ 854 expected_rc = 0; 855 856 blockdev_write_read(data_length, iov_len, pattern, offset, expected_rc, 0); 857 } 858 859 static void 860 blockdev_write_read_invalid_size(void) 861 { 862 uint32_t data_length; 863 uint64_t offset; 864 int pattern; 865 int expected_rc; 866 struct io_target *target = g_current_io_target; 867 struct spdk_bdev *bdev = target->bdev; 868 uint32_t block_size = spdk_bdev_get_block_size(bdev); 869 870 /* Data size is not a multiple of the block size */ 871 data_length = block_size - 1; 872 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 873 offset = block_size * 2; 874 pattern = 0xA3; 875 /* Params are invalid, hence the expected return value 876 * of write and read for all blockdevs is < 0 */ 877 expected_rc = -1; 878 879 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0); 880 } 881 882 static void 883 blockdev_write_read_offset_plus_nbytes_equals_bdev_size(void) 884 { 885 uint32_t data_length; 886 uint64_t offset; 887 int pattern; 888 int expected_rc; 889 struct io_target *target = g_current_io_target; 890 struct spdk_bdev *bdev = target->bdev; 891 uint32_t block_size = spdk_bdev_get_block_size(bdev); 892 893 data_length = block_size; 894 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 895 /* The start offset has been set to a marginal value 896 * such that offset + nbytes == Total size of 897 * blockdev. */ 898 offset = ((spdk_bdev_get_num_blocks(bdev) - 1) * block_size); 899 pattern = 0xA3; 900 /* Params are valid, hence the expected return value 901 * of write and read for all blockdevs is 0. */ 902 expected_rc = 0; 903 904 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0); 905 } 906 907 static void 908 blockdev_write_read_offset_plus_nbytes_gt_bdev_size(void) 909 { 910 uint32_t data_length; 911 uint64_t offset; 912 int pattern; 913 int expected_rc; 914 struct io_target *target = g_current_io_target; 915 struct spdk_bdev *bdev = target->bdev; 916 uint32_t block_size = spdk_bdev_get_block_size(bdev); 917 918 /* Tests the overflow condition of the blockdevs. */ 919 data_length = block_size * 2; 920 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 921 pattern = 0xA3; 922 923 /* The start offset has been set to a valid value 924 * but offset + nbytes is greater than the Total size 925 * of the blockdev. The test should fail. */ 926 offset = (spdk_bdev_get_num_blocks(bdev) - 1) * block_size; 927 /* Params are invalid, hence the expected return value 928 * of write and read for all blockdevs is < 0 */ 929 expected_rc = -1; 930 931 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0); 932 } 933 934 static void 935 blockdev_write_read_max_offset(void) 936 { 937 int data_length; 938 uint64_t offset; 939 int pattern; 940 int expected_rc; 941 struct io_target *target = g_current_io_target; 942 struct spdk_bdev *bdev = target->bdev; 943 944 data_length = spdk_bdev_get_block_size(bdev); 945 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 946 /* The start offset has been set to UINT64_MAX such that 947 * adding nbytes wraps around and points to an invalid address. */ 948 offset = UINT64_MAX; 949 pattern = 0xA3; 950 /* Params are invalid, hence the expected return value 951 * of write and read for all blockdevs is < 0 */ 952 expected_rc = -1; 953 954 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0); 955 } 956 957 static void 958 blockdev_overlapped_write_read_2blocks(void) 959 { 960 int data_length; 961 uint64_t offset; 962 int pattern; 963 int expected_rc; 964 struct io_target *target = g_current_io_target; 965 struct spdk_bdev *bdev = target->bdev; 966 967 /* Data size = 2 blocks */ 968 data_length = spdk_bdev_get_block_size(bdev) * 2; 969 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 970 offset = 0; 971 pattern = 0xA3; 972 /* Params are valid, hence the expected return value 973 * of write and read for all blockdevs is 0. */ 974 expected_rc = 0; 975 /* Assert the write by comparing it with values read 976 * from the same offset for each blockdev */ 977 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0); 978 979 /* Overwrite the pattern 0xbb of size 2*block size on an address offset 980 * overlapping with the address written above and assert the new value in 981 * the overlapped address range */ 982 /* Populate 2*block size with value 0xBB */ 983 pattern = 0xBB; 984 /* Offset = 1 block; Overlap offset addresses and write value 0xbb */ 985 offset = spdk_bdev_get_block_size(bdev); 986 /* Assert the write by comparing it with values read 987 * from the overlapped offset for each blockdev */ 988 blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0); 989 } 990 991 static void 992 __blockdev_reset(void *arg) 993 { 994 struct bdevio_request *req = arg; 995 struct io_target *target = req->target; 996 int rc; 997 998 rc = spdk_bdev_reset(target->bdev_desc, target->ch, quick_test_complete, NULL); 999 if (rc < 0) { 1000 g_completion_success = false; 1001 wake_ut_thread(); 1002 } 1003 } 1004 1005 static void 1006 blockdev_test_reset(void) 1007 { 1008 struct bdevio_request req; 1009 struct io_target *target; 1010 bool reset_supported; 1011 1012 target = g_current_io_target; 1013 req.target = target; 1014 1015 reset_supported = spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_RESET); 1016 g_completion_success = false; 1017 1018 execute_spdk_function(__blockdev_reset, &req); 1019 1020 CU_ASSERT_EQUAL(g_completion_success, reset_supported); 1021 } 1022 1023 struct bdevio_passthrough_request { 1024 struct spdk_nvme_cmd cmd; 1025 void *buf; 1026 uint32_t len; 1027 struct io_target *target; 1028 int sct; 1029 int sc; 1030 uint32_t cdw0; 1031 }; 1032 1033 static void 1034 nvme_pt_test_complete(struct spdk_bdev_io *bdev_io, bool success, void *arg) 1035 { 1036 struct bdevio_passthrough_request *pt_req = arg; 1037 1038 spdk_bdev_io_get_nvme_status(bdev_io, &pt_req->cdw0, &pt_req->sct, &pt_req->sc); 1039 spdk_bdev_free_io(bdev_io); 1040 wake_ut_thread(); 1041 } 1042 1043 static void 1044 __blockdev_nvme_passthru(void *arg) 1045 { 1046 struct bdevio_passthrough_request *pt_req = arg; 1047 struct io_target *target = pt_req->target; 1048 int rc; 1049 1050 rc = spdk_bdev_nvme_io_passthru(target->bdev_desc, target->ch, 1051 &pt_req->cmd, pt_req->buf, pt_req->len, 1052 nvme_pt_test_complete, pt_req); 1053 if (rc) { 1054 wake_ut_thread(); 1055 } 1056 } 1057 1058 static void 1059 blockdev_test_nvme_passthru_rw(void) 1060 { 1061 struct bdevio_passthrough_request pt_req; 1062 void *write_buf, *read_buf; 1063 struct io_target *target; 1064 1065 target = g_current_io_target; 1066 1067 if (!spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_NVME_IO)) { 1068 return; 1069 } 1070 1071 memset(&pt_req, 0, sizeof(pt_req)); 1072 pt_req.target = target; 1073 pt_req.cmd.opc = SPDK_NVME_OPC_WRITE; 1074 pt_req.cmd.nsid = 1; 1075 *(uint64_t *)&pt_req.cmd.cdw10 = 4; 1076 pt_req.cmd.cdw12 = 0; 1077 1078 pt_req.len = spdk_bdev_get_block_size(target->bdev); 1079 write_buf = spdk_malloc(pt_req.len, 0, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 1080 memset(write_buf, 0xA5, pt_req.len); 1081 pt_req.buf = write_buf; 1082 1083 pt_req.sct = SPDK_NVME_SCT_VENDOR_SPECIFIC; 1084 pt_req.sc = SPDK_NVME_SC_INVALID_FIELD; 1085 execute_spdk_function(__blockdev_nvme_passthru, &pt_req); 1086 CU_ASSERT(pt_req.sct == SPDK_NVME_SCT_GENERIC); 1087 CU_ASSERT(pt_req.sc == SPDK_NVME_SC_SUCCESS); 1088 1089 pt_req.cmd.opc = SPDK_NVME_OPC_READ; 1090 read_buf = spdk_zmalloc(pt_req.len, 0, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 1091 pt_req.buf = read_buf; 1092 1093 pt_req.sct = SPDK_NVME_SCT_VENDOR_SPECIFIC; 1094 pt_req.sc = SPDK_NVME_SC_INVALID_FIELD; 1095 execute_spdk_function(__blockdev_nvme_passthru, &pt_req); 1096 CU_ASSERT(pt_req.sct == SPDK_NVME_SCT_GENERIC); 1097 CU_ASSERT(pt_req.sc == SPDK_NVME_SC_SUCCESS); 1098 1099 CU_ASSERT(!memcmp(read_buf, write_buf, pt_req.len)); 1100 spdk_free(read_buf); 1101 spdk_free(write_buf); 1102 } 1103 1104 static void 1105 blockdev_test_nvme_passthru_vendor_specific(void) 1106 { 1107 struct bdevio_passthrough_request pt_req; 1108 struct io_target *target; 1109 1110 target = g_current_io_target; 1111 1112 if (!spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_NVME_IO)) { 1113 return; 1114 } 1115 1116 memset(&pt_req, 0, sizeof(pt_req)); 1117 pt_req.target = target; 1118 pt_req.cmd.opc = 0x7F; /* choose known invalid opcode */ 1119 pt_req.cmd.nsid = 1; 1120 1121 pt_req.sct = SPDK_NVME_SCT_VENDOR_SPECIFIC; 1122 pt_req.sc = SPDK_NVME_SC_SUCCESS; 1123 pt_req.cdw0 = 0xbeef; 1124 execute_spdk_function(__blockdev_nvme_passthru, &pt_req); 1125 CU_ASSERT(pt_req.sct == SPDK_NVME_SCT_GENERIC); 1126 CU_ASSERT(pt_req.sc == SPDK_NVME_SC_INVALID_OPCODE); 1127 CU_ASSERT(pt_req.cdw0 == 0x0); 1128 } 1129 1130 static void 1131 __blockdev_nvme_admin_passthru(void *arg) 1132 { 1133 struct bdevio_passthrough_request *pt_req = arg; 1134 struct io_target *target = pt_req->target; 1135 int rc; 1136 1137 rc = spdk_bdev_nvme_admin_passthru(target->bdev_desc, target->ch, 1138 &pt_req->cmd, pt_req->buf, pt_req->len, 1139 nvme_pt_test_complete, pt_req); 1140 if (rc) { 1141 wake_ut_thread(); 1142 } 1143 } 1144 1145 static void 1146 blockdev_test_nvme_admin_passthru(void) 1147 { 1148 struct io_target *target; 1149 struct bdevio_passthrough_request pt_req; 1150 1151 target = g_current_io_target; 1152 1153 if (!spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_NVME_ADMIN)) { 1154 return; 1155 } 1156 1157 memset(&pt_req, 0, sizeof(pt_req)); 1158 pt_req.target = target; 1159 pt_req.cmd.opc = SPDK_NVME_OPC_IDENTIFY; 1160 pt_req.cmd.nsid = 0; 1161 *(uint64_t *)&pt_req.cmd.cdw10 = SPDK_NVME_IDENTIFY_CTRLR; 1162 1163 pt_req.len = sizeof(struct spdk_nvme_ctrlr_data); 1164 pt_req.buf = spdk_malloc(pt_req.len, 0, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 1165 1166 pt_req.sct = SPDK_NVME_SCT_GENERIC; 1167 pt_req.sc = SPDK_NVME_SC_SUCCESS; 1168 execute_spdk_function(__blockdev_nvme_admin_passthru, &pt_req); 1169 CU_ASSERT(pt_req.sct == SPDK_NVME_SCT_GENERIC); 1170 CU_ASSERT(pt_req.sc == SPDK_NVME_SC_SUCCESS); 1171 } 1172 1173 static void 1174 blockdev_test_copy(void) 1175 { 1176 uint32_t data_length; 1177 uint64_t src_offset, dst_offset; 1178 struct io_target *target = g_current_io_target; 1179 struct spdk_bdev *bdev = target->bdev; 1180 char *tx_buf = NULL; 1181 char *rx_buf = NULL; 1182 int rc; 1183 1184 if (!spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_COPY)) { 1185 return; 1186 } 1187 1188 data_length = spdk_bdev_get_block_size(bdev); 1189 CU_ASSERT_TRUE(data_length < BUFFER_SIZE); 1190 src_offset = 0; 1191 dst_offset = spdk_bdev_get_block_size(bdev); 1192 1193 initialize_buffer(&tx_buf, 0xAA, data_length); 1194 initialize_buffer(&rx_buf, 0, data_length); 1195 1196 blockdev_write(target, tx_buf, src_offset, data_length, data_length); 1197 CU_ASSERT_EQUAL(g_completion_success, true); 1198 1199 blockdev_copy(target, dst_offset, src_offset, data_length); 1200 CU_ASSERT_EQUAL(g_completion_success, true); 1201 1202 blockdev_read(target, rx_buf, dst_offset, data_length, data_length); 1203 CU_ASSERT_EQUAL(g_completion_success, true); 1204 1205 rc = blockdev_write_read_data_match(rx_buf, tx_buf, data_length); 1206 CU_ASSERT_EQUAL(rc, 0); 1207 } 1208 1209 static void 1210 __stop_init_thread(void *arg) 1211 { 1212 unsigned num_failures = g_num_failures; 1213 struct spdk_jsonrpc_request *request = arg; 1214 1215 g_num_failures = 0; 1216 1217 bdevio_cleanup_targets(); 1218 if (g_wait_for_tests && !g_shutdown) { 1219 /* Do not stop the app yet, wait for another RPC */ 1220 rpc_perform_tests_cb(num_failures, request); 1221 return; 1222 } 1223 spdk_app_stop(num_failures); 1224 } 1225 1226 static void 1227 stop_init_thread(unsigned num_failures, struct spdk_jsonrpc_request *request) 1228 { 1229 g_num_failures = num_failures; 1230 1231 spdk_thread_send_msg(g_thread_init, __stop_init_thread, request); 1232 } 1233 1234 static int 1235 suite_init(void) 1236 { 1237 if (g_current_io_target == NULL) { 1238 g_current_io_target = g_io_targets; 1239 } 1240 return 0; 1241 } 1242 1243 static int 1244 suite_fini(void) 1245 { 1246 g_current_io_target = g_current_io_target->next; 1247 return 0; 1248 } 1249 1250 #define SUITE_NAME_MAX 64 1251 1252 static int 1253 __setup_ut_on_single_target(struct io_target *target) 1254 { 1255 unsigned rc = 0; 1256 CU_pSuite suite = NULL; 1257 char name[SUITE_NAME_MAX]; 1258 1259 snprintf(name, sizeof(name), "bdevio tests on: %s", spdk_bdev_get_name(target->bdev)); 1260 suite = CU_add_suite(name, suite_init, suite_fini); 1261 if (suite == NULL) { 1262 CU_cleanup_registry(); 1263 rc = CU_get_error(); 1264 return -rc; 1265 } 1266 1267 if ( 1268 CU_add_test(suite, "blockdev write read block", 1269 blockdev_write_read_block) == NULL 1270 || CU_add_test(suite, "blockdev write zeroes read block", 1271 blockdev_write_zeroes_read_block) == NULL 1272 || CU_add_test(suite, "blockdev write zeroes read no split", 1273 blockdev_write_zeroes_read_no_split) == NULL 1274 || CU_add_test(suite, "blockdev write zeroes read split", 1275 blockdev_write_zeroes_read_split) == NULL 1276 || CU_add_test(suite, "blockdev write zeroes read split partial", 1277 blockdev_write_zeroes_read_split_partial) == NULL 1278 || CU_add_test(suite, "blockdev reset", 1279 blockdev_test_reset) == NULL 1280 || CU_add_test(suite, "blockdev write read 8 blocks", 1281 blockdev_write_read_8blocks) == NULL 1282 || CU_add_test(suite, "blockdev write read size > 128k", 1283 blockdev_write_read_size_gt_128k) == NULL 1284 || CU_add_test(suite, "blockdev write read invalid size", 1285 blockdev_write_read_invalid_size) == NULL 1286 || CU_add_test(suite, "blockdev write read offset + nbytes == size of blockdev", 1287 blockdev_write_read_offset_plus_nbytes_equals_bdev_size) == NULL 1288 || CU_add_test(suite, "blockdev write read offset + nbytes > size of blockdev", 1289 blockdev_write_read_offset_plus_nbytes_gt_bdev_size) == NULL 1290 || CU_add_test(suite, "blockdev write read max offset", 1291 blockdev_write_read_max_offset) == NULL 1292 || CU_add_test(suite, "blockdev write read 2 blocks on overlapped address offset", 1293 blockdev_overlapped_write_read_2blocks) == NULL 1294 || CU_add_test(suite, "blockdev writev readv 8 blocks", 1295 blockdev_writev_readv_8blocks) == NULL 1296 || CU_add_test(suite, "blockdev writev readv 30 x 1block", 1297 blockdev_writev_readv_30x1block) == NULL 1298 || CU_add_test(suite, "blockdev writev readv block", 1299 blockdev_writev_readv_block) == NULL 1300 || CU_add_test(suite, "blockdev writev readv size > 128k", 1301 blockdev_writev_readv_size_gt_128k) == NULL 1302 || CU_add_test(suite, "blockdev writev readv size > 128k in two iovs", 1303 blockdev_writev_readv_size_gt_128k_two_iov) == NULL 1304 || CU_add_test(suite, "blockdev comparev and writev", 1305 blockdev_comparev_and_writev) == NULL 1306 || CU_add_test(suite, "blockdev nvme passthru rw", 1307 blockdev_test_nvme_passthru_rw) == NULL 1308 || CU_add_test(suite, "blockdev nvme passthru vendor specific", 1309 blockdev_test_nvme_passthru_vendor_specific) == NULL 1310 || CU_add_test(suite, "blockdev nvme admin passthru", 1311 blockdev_test_nvme_admin_passthru) == NULL 1312 || CU_add_test(suite, "blockdev copy", 1313 blockdev_test_copy) == NULL 1314 ) { 1315 CU_cleanup_registry(); 1316 rc = CU_get_error(); 1317 return -rc; 1318 } 1319 return 0; 1320 } 1321 1322 static void 1323 __run_ut_thread(void *arg) 1324 { 1325 struct spdk_jsonrpc_request *request = arg; 1326 int rc = 0; 1327 struct io_target *target; 1328 unsigned num_failures; 1329 1330 if (CU_initialize_registry() != CUE_SUCCESS) { 1331 /* CUnit error, probably won't recover */ 1332 rc = CU_get_error(); 1333 stop_init_thread(-rc, request); 1334 } 1335 1336 target = g_io_targets; 1337 while (target != NULL) { 1338 rc = __setup_ut_on_single_target(target); 1339 if (rc < 0) { 1340 /* CUnit error, probably won't recover */ 1341 stop_init_thread(-rc, request); 1342 } 1343 target = target->next; 1344 } 1345 CU_basic_set_mode(CU_BRM_VERBOSE); 1346 CU_basic_run_tests(); 1347 num_failures = CU_get_number_of_failures(); 1348 CU_cleanup_registry(); 1349 1350 stop_init_thread(num_failures, request); 1351 } 1352 1353 static void 1354 __construct_targets(void *arg) 1355 { 1356 if (bdevio_construct_targets() < 0) { 1357 spdk_app_stop(-1); 1358 return; 1359 } 1360 1361 spdk_thread_send_msg(g_thread_ut, __run_ut_thread, NULL); 1362 } 1363 1364 static void 1365 test_main(void *arg1) 1366 { 1367 struct spdk_cpuset tmpmask = {}; 1368 uint32_t i; 1369 1370 pthread_mutex_init(&g_test_mutex, NULL); 1371 pthread_cond_init(&g_test_cond, NULL); 1372 1373 /* This test runs specifically on at least three cores. 1374 * g_thread_init is the app_thread on main core from event framework. 1375 * Next two are only for the tests and should always be on separate CPU cores. */ 1376 if (spdk_env_get_core_count() < 3) { 1377 spdk_app_stop(-1); 1378 return; 1379 } 1380 1381 SPDK_ENV_FOREACH_CORE(i) { 1382 if (i == spdk_env_get_current_core()) { 1383 g_thread_init = spdk_get_thread(); 1384 continue; 1385 } 1386 spdk_cpuset_zero(&tmpmask); 1387 spdk_cpuset_set_cpu(&tmpmask, i, true); 1388 if (g_thread_ut == NULL) { 1389 g_thread_ut = spdk_thread_create("ut_thread", &tmpmask); 1390 } else if (g_thread_io == NULL) { 1391 g_thread_io = spdk_thread_create("io_thread", &tmpmask); 1392 } 1393 1394 } 1395 1396 if (g_wait_for_tests) { 1397 /* Do not perform any tests until RPC is received */ 1398 return; 1399 } 1400 1401 spdk_thread_send_msg(g_thread_init, __construct_targets, NULL); 1402 } 1403 1404 static void 1405 bdevio_usage(void) 1406 { 1407 printf(" -w start bdevio app and wait for RPC to start the tests\n"); 1408 } 1409 1410 static int 1411 bdevio_parse_arg(int ch, char *arg) 1412 { 1413 switch (ch) { 1414 case 'w': 1415 g_wait_for_tests = true; 1416 break; 1417 default: 1418 return -EINVAL; 1419 } 1420 return 0; 1421 } 1422 1423 struct rpc_perform_tests { 1424 char *name; 1425 }; 1426 1427 static void 1428 free_rpc_perform_tests(struct rpc_perform_tests *r) 1429 { 1430 free(r->name); 1431 } 1432 1433 static const struct spdk_json_object_decoder rpc_perform_tests_decoders[] = { 1434 {"name", offsetof(struct rpc_perform_tests, name), spdk_json_decode_string, true}, 1435 }; 1436 1437 static void 1438 rpc_perform_tests_cb(unsigned num_failures, struct spdk_jsonrpc_request *request) 1439 { 1440 struct spdk_json_write_ctx *w; 1441 1442 if (num_failures == 0) { 1443 w = spdk_jsonrpc_begin_result(request); 1444 spdk_json_write_uint32(w, num_failures); 1445 spdk_jsonrpc_end_result(request, w); 1446 } else { 1447 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1448 "%d test cases failed", num_failures); 1449 } 1450 } 1451 1452 static void 1453 rpc_perform_tests(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) 1454 { 1455 struct rpc_perform_tests req = {NULL}; 1456 struct spdk_bdev *bdev; 1457 int rc; 1458 1459 if (params && spdk_json_decode_object(params, rpc_perform_tests_decoders, 1460 SPDK_COUNTOF(rpc_perform_tests_decoders), 1461 &req)) { 1462 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1463 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1464 goto invalid; 1465 } 1466 1467 if (req.name) { 1468 bdev = spdk_bdev_get_by_name(req.name); 1469 if (bdev == NULL) { 1470 SPDK_ERRLOG("Bdev '%s' does not exist\n", req.name); 1471 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1472 "Bdev '%s' does not exist: %s", 1473 req.name, spdk_strerror(ENODEV)); 1474 goto invalid; 1475 } 1476 rc = bdevio_construct_target(bdev); 1477 if (rc < 0) { 1478 SPDK_ERRLOG("Could not construct target for bdev '%s'\n", spdk_bdev_get_name(bdev)); 1479 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1480 "Could not construct target for bdev '%s': %s", 1481 spdk_bdev_get_name(bdev), spdk_strerror(-rc)); 1482 goto invalid; 1483 } 1484 } else { 1485 rc = bdevio_construct_targets(); 1486 if (rc < 0) { 1487 SPDK_ERRLOG("Could not construct targets for all bdevs\n"); 1488 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1489 "Could not construct targets for all bdevs: %s", 1490 spdk_strerror(-rc)); 1491 goto invalid; 1492 } 1493 } 1494 free_rpc_perform_tests(&req); 1495 1496 spdk_thread_send_msg(g_thread_ut, __run_ut_thread, request); 1497 1498 return; 1499 1500 invalid: 1501 free_rpc_perform_tests(&req); 1502 } 1503 SPDK_RPC_REGISTER("perform_tests", rpc_perform_tests, SPDK_RPC_RUNTIME) 1504 1505 static void 1506 spdk_bdevio_shutdown_cb(void) 1507 { 1508 g_shutdown = true; 1509 spdk_thread_send_msg(g_thread_init, __stop_init_thread, NULL); 1510 } 1511 1512 int 1513 main(int argc, char **argv) 1514 { 1515 int rc; 1516 struct spdk_app_opts opts = {}; 1517 1518 spdk_app_opts_init(&opts, sizeof(opts)); 1519 opts.name = "bdevio"; 1520 opts.reactor_mask = "0x7"; 1521 opts.shutdown_cb = spdk_bdevio_shutdown_cb; 1522 1523 if ((rc = spdk_app_parse_args(argc, argv, &opts, "w", NULL, 1524 bdevio_parse_arg, bdevio_usage)) != 1525 SPDK_APP_PARSE_ARGS_SUCCESS) { 1526 return rc; 1527 } 1528 1529 rc = spdk_app_start(&opts, test_main, NULL); 1530 spdk_app_fini(); 1531 1532 return rc; 1533 } 1534