1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "spdk/blobfs.h" 37 #include "spdk/env.h" 38 #include "spdk/log.h" 39 #include "spdk/thread.h" 40 #include "spdk/barrier.h" 41 #include "spdk_internal/thread.h" 42 43 #include "spdk_cunit.h" 44 #include "unit/lib/blob/bs_dev_common.c" 45 #include "common/lib/test_env.c" 46 #include "blobfs/blobfs.c" 47 #include "blobfs/tree.c" 48 49 struct spdk_filesystem *g_fs; 50 struct spdk_file *g_file; 51 int g_fserrno; 52 struct spdk_thread *g_dispatch_thread = NULL; 53 struct spdk_trace_histories *g_trace_histories; 54 DEFINE_STUB_V(spdk_trace_add_register_fn, (struct spdk_trace_register_fn *reg_fn)); 55 DEFINE_STUB_V(spdk_trace_register_description, (const char *name, 56 uint16_t tpoint_id, uint8_t owner_type, 57 uint8_t object_type, uint8_t new_object, 58 uint8_t arg1_is_ptr, const char *arg1_name)); 59 DEFINE_STUB_V(_spdk_trace_record, (uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id, 60 uint32_t size, uint64_t object_id, uint64_t arg1)); 61 62 /* Return NULL to test hardcoded defaults. */ 63 struct spdk_conf_section * 64 spdk_conf_find_section(struct spdk_conf *cp, const char *name) 65 { 66 return NULL; 67 } 68 69 /* Return -1 to test hardcoded defaults. */ 70 int 71 spdk_conf_section_get_intval(struct spdk_conf_section *sp, const char *key) 72 { 73 return -1; 74 } 75 76 struct ut_request { 77 fs_request_fn fn; 78 void *arg; 79 volatile int done; 80 }; 81 82 static void 83 send_request(fs_request_fn fn, void *arg) 84 { 85 spdk_thread_send_msg(g_dispatch_thread, (spdk_msg_fn)fn, arg); 86 } 87 88 static void 89 ut_call_fn(void *arg) 90 { 91 struct ut_request *req = arg; 92 93 req->fn(req->arg); 94 req->done = 1; 95 } 96 97 static void 98 ut_send_request(fs_request_fn fn, void *arg) 99 { 100 struct ut_request req; 101 102 req.fn = fn; 103 req.arg = arg; 104 req.done = 0; 105 106 spdk_thread_send_msg(g_dispatch_thread, ut_call_fn, &req); 107 108 /* Wait for this to finish */ 109 while (req.done == 0) { } 110 } 111 112 static void 113 fs_op_complete(void *ctx, int fserrno) 114 { 115 g_fserrno = fserrno; 116 } 117 118 static void 119 fs_op_with_handle_complete(void *ctx, struct spdk_filesystem *fs, int fserrno) 120 { 121 g_fs = fs; 122 g_fserrno = fserrno; 123 } 124 125 static void 126 _fs_init(void *arg) 127 { 128 struct spdk_thread *thread; 129 struct spdk_bs_dev *dev; 130 131 g_fs = NULL; 132 g_fserrno = -1; 133 dev = init_dev(); 134 spdk_fs_init(dev, NULL, send_request, fs_op_with_handle_complete, NULL); 135 thread = spdk_get_thread(); 136 while (spdk_thread_poll(thread, 0, 0) > 0) {} 137 138 SPDK_CU_ASSERT_FATAL(g_fs != NULL); 139 SPDK_CU_ASSERT_FATAL(g_fs->bdev == dev); 140 CU_ASSERT(g_fserrno == 0); 141 } 142 143 static void 144 _fs_load(void *arg) 145 { 146 struct spdk_thread *thread; 147 struct spdk_bs_dev *dev; 148 149 g_fs = NULL; 150 g_fserrno = -1; 151 dev = init_dev(); 152 spdk_fs_load(dev, send_request, fs_op_with_handle_complete, NULL); 153 thread = spdk_get_thread(); 154 while (spdk_thread_poll(thread, 0, 0) > 0) {} 155 156 SPDK_CU_ASSERT_FATAL(g_fs != NULL); 157 SPDK_CU_ASSERT_FATAL(g_fs->bdev == dev); 158 CU_ASSERT(g_fserrno == 0); 159 } 160 161 static void 162 _fs_unload(void *arg) 163 { 164 struct spdk_thread *thread; 165 166 g_fserrno = -1; 167 spdk_fs_unload(g_fs, fs_op_complete, NULL); 168 thread = spdk_get_thread(); 169 while (spdk_thread_poll(thread, 0, 0) > 0) {} 170 CU_ASSERT(g_fserrno == 0); 171 g_fs = NULL; 172 } 173 174 static void 175 _nop(void *arg) 176 { 177 } 178 179 static void 180 cache_read_after_write(void) 181 { 182 uint64_t length; 183 int rc; 184 char w_buf[100], r_buf[100]; 185 struct spdk_fs_thread_ctx *channel; 186 struct spdk_file_stat stat = {0}; 187 188 ut_send_request(_fs_init, NULL); 189 190 channel = spdk_fs_alloc_thread_ctx(g_fs); 191 192 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 193 CU_ASSERT(rc == 0); 194 SPDK_CU_ASSERT_FATAL(g_file != NULL); 195 196 length = (4 * 1024 * 1024); 197 rc = spdk_file_truncate(g_file, channel, length); 198 CU_ASSERT(rc == 0); 199 200 memset(w_buf, 0x5a, sizeof(w_buf)); 201 spdk_file_write(g_file, channel, w_buf, 0, sizeof(w_buf)); 202 203 CU_ASSERT(spdk_file_get_length(g_file) == length); 204 205 rc = spdk_file_truncate(g_file, channel, sizeof(w_buf)); 206 CU_ASSERT(rc == 0); 207 208 spdk_file_close(g_file, channel); 209 210 rc = spdk_fs_file_stat(g_fs, channel, "testfile", &stat); 211 CU_ASSERT(rc == 0); 212 CU_ASSERT(sizeof(w_buf) == stat.size); 213 214 rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &g_file); 215 CU_ASSERT(rc == 0); 216 SPDK_CU_ASSERT_FATAL(g_file != NULL); 217 218 memset(r_buf, 0, sizeof(r_buf)); 219 spdk_file_read(g_file, channel, r_buf, 0, sizeof(r_buf)); 220 CU_ASSERT(memcmp(w_buf, r_buf, sizeof(r_buf)) == 0); 221 222 spdk_file_close(g_file, channel); 223 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 224 CU_ASSERT(rc == 0); 225 226 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 227 CU_ASSERT(rc == -ENOENT); 228 229 spdk_fs_free_thread_ctx(channel); 230 231 ut_send_request(_fs_unload, NULL); 232 } 233 234 static void 235 file_length(void) 236 { 237 int rc; 238 char *buf; 239 uint64_t buf_length; 240 volatile uint64_t *length_flushed; 241 struct spdk_fs_thread_ctx *channel; 242 struct spdk_file_stat stat = {0}; 243 244 ut_send_request(_fs_init, NULL); 245 246 channel = spdk_fs_alloc_thread_ctx(g_fs); 247 248 g_file = NULL; 249 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 250 CU_ASSERT(rc == 0); 251 SPDK_CU_ASSERT_FATAL(g_file != NULL); 252 253 /* Write one CACHE_BUFFER. Filling at least one cache buffer triggers 254 * a flush to disk. 255 */ 256 buf_length = CACHE_BUFFER_SIZE; 257 buf = calloc(1, buf_length); 258 spdk_file_write(g_file, channel, buf, 0, buf_length); 259 free(buf); 260 261 /* Spin until all of the data has been flushed to the SSD. There's been no 262 * sync operation yet, so the xattr on the file is still 0. 263 * 264 * length_flushed: This variable is modified by a different thread in this unit 265 * test. So we need to dereference it as a volatile to ensure the value is always 266 * re-read. 267 */ 268 length_flushed = &g_file->length_flushed; 269 while (*length_flushed != buf_length) {} 270 271 /* Close the file. This causes an implicit sync which should write the 272 * length_flushed value as the "length" xattr on the file. 273 */ 274 spdk_file_close(g_file, channel); 275 276 rc = spdk_fs_file_stat(g_fs, channel, "testfile", &stat); 277 CU_ASSERT(rc == 0); 278 CU_ASSERT(buf_length == stat.size); 279 280 spdk_fs_free_thread_ctx(channel); 281 282 /* Unload and reload the filesystem. The file length will be 283 * read during load from the length xattr. We want to make sure 284 * it matches what was written when the file was originally 285 * written and closed. 286 */ 287 ut_send_request(_fs_unload, NULL); 288 289 ut_send_request(_fs_load, NULL); 290 291 channel = spdk_fs_alloc_thread_ctx(g_fs); 292 293 rc = spdk_fs_file_stat(g_fs, channel, "testfile", &stat); 294 CU_ASSERT(rc == 0); 295 CU_ASSERT(buf_length == stat.size); 296 297 g_file = NULL; 298 rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &g_file); 299 CU_ASSERT(rc == 0); 300 SPDK_CU_ASSERT_FATAL(g_file != NULL); 301 302 spdk_file_close(g_file, channel); 303 304 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 305 CU_ASSERT(rc == 0); 306 307 spdk_fs_free_thread_ctx(channel); 308 309 ut_send_request(_fs_unload, NULL); 310 } 311 312 static void 313 partial_buffer(void) 314 { 315 int rc; 316 char *buf; 317 uint64_t buf_length; 318 struct spdk_fs_thread_ctx *channel; 319 struct spdk_file_stat stat = {0}; 320 321 ut_send_request(_fs_init, NULL); 322 323 channel = spdk_fs_alloc_thread_ctx(g_fs); 324 325 g_file = NULL; 326 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 327 CU_ASSERT(rc == 0); 328 SPDK_CU_ASSERT_FATAL(g_file != NULL); 329 330 /* Write one CACHE_BUFFER plus one byte. Filling at least one cache buffer triggers 331 * a flush to disk. We want to make sure the extra byte is not implicitly flushed. 332 * It should only get flushed once we sync or close the file. 333 */ 334 buf_length = CACHE_BUFFER_SIZE + 1; 335 buf = calloc(1, buf_length); 336 spdk_file_write(g_file, channel, buf, 0, buf_length); 337 free(buf); 338 339 /* Send some nop messages to the dispatch thread. This will ensure any of the 340 * pending write operations are completed. A well-functioning blobfs should only 341 * issue one write for the filled CACHE_BUFFER - a buggy one might try to write 342 * the extra byte. So do a bunch of _nops to make sure all of them (even the buggy 343 * ones) get a chance to run. Note that we can't just send a message to the 344 * dispatch thread to call spdk_thread_poll() because the messages are themselves 345 * run in the context of spdk_thread_poll(). 346 */ 347 ut_send_request(_nop, NULL); 348 ut_send_request(_nop, NULL); 349 ut_send_request(_nop, NULL); 350 ut_send_request(_nop, NULL); 351 ut_send_request(_nop, NULL); 352 ut_send_request(_nop, NULL); 353 354 CU_ASSERT(g_file->length_flushed == CACHE_BUFFER_SIZE); 355 356 /* Close the file. This causes an implicit sync which should write the 357 * length_flushed value as the "length" xattr on the file. 358 */ 359 spdk_file_close(g_file, channel); 360 361 rc = spdk_fs_file_stat(g_fs, channel, "testfile", &stat); 362 CU_ASSERT(rc == 0); 363 CU_ASSERT(buf_length == stat.size); 364 365 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 366 CU_ASSERT(rc == 0); 367 368 spdk_fs_free_thread_ctx(channel); 369 370 ut_send_request(_fs_unload, NULL); 371 } 372 373 static void 374 cache_write_null_buffer(void) 375 { 376 uint64_t length; 377 int rc; 378 struct spdk_fs_thread_ctx *channel; 379 struct spdk_thread *thread; 380 381 ut_send_request(_fs_init, NULL); 382 383 channel = spdk_fs_alloc_thread_ctx(g_fs); 384 385 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 386 CU_ASSERT(rc == 0); 387 SPDK_CU_ASSERT_FATAL(g_file != NULL); 388 389 length = 0; 390 rc = spdk_file_truncate(g_file, channel, length); 391 CU_ASSERT(rc == 0); 392 393 rc = spdk_file_write(g_file, channel, NULL, 0, 0); 394 CU_ASSERT(rc == 0); 395 396 spdk_file_close(g_file, channel); 397 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 398 CU_ASSERT(rc == 0); 399 400 spdk_fs_free_thread_ctx(channel); 401 402 thread = spdk_get_thread(); 403 while (spdk_thread_poll(thread, 0, 0) > 0) {} 404 405 ut_send_request(_fs_unload, NULL); 406 } 407 408 static void 409 fs_create_sync(void) 410 { 411 int rc; 412 struct spdk_fs_thread_ctx *channel; 413 struct spdk_thread *thread; 414 415 ut_send_request(_fs_init, NULL); 416 417 channel = spdk_fs_alloc_thread_ctx(g_fs); 418 CU_ASSERT(channel != NULL); 419 420 rc = spdk_fs_create_file(g_fs, channel, "testfile"); 421 CU_ASSERT(rc == 0); 422 423 /* Create should fail, because the file already exists. */ 424 rc = spdk_fs_create_file(g_fs, channel, "testfile"); 425 CU_ASSERT(rc != 0); 426 427 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 428 CU_ASSERT(rc == 0); 429 430 spdk_fs_free_thread_ctx(channel); 431 432 thread = spdk_get_thread(); 433 while (spdk_thread_poll(thread, 0, 0) > 0) {} 434 435 ut_send_request(_fs_unload, NULL); 436 } 437 438 static void 439 fs_rename_sync(void) 440 { 441 int rc; 442 struct spdk_fs_thread_ctx *channel; 443 struct spdk_thread *thread; 444 445 ut_send_request(_fs_init, NULL); 446 447 channel = spdk_fs_alloc_thread_ctx(g_fs); 448 CU_ASSERT(channel != NULL); 449 450 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 451 CU_ASSERT(rc == 0); 452 SPDK_CU_ASSERT_FATAL(g_file != NULL); 453 454 CU_ASSERT(strcmp(spdk_file_get_name(g_file), "testfile") == 0); 455 456 rc = spdk_fs_rename_file(g_fs, channel, "testfile", "newtestfile"); 457 CU_ASSERT(rc == 0); 458 CU_ASSERT(strcmp(spdk_file_get_name(g_file), "newtestfile") == 0); 459 460 spdk_file_close(g_file, channel); 461 spdk_fs_free_thread_ctx(channel); 462 463 thread = spdk_get_thread(); 464 while (spdk_thread_poll(thread, 0, 0) > 0) {} 465 466 ut_send_request(_fs_unload, NULL); 467 } 468 469 static void 470 cache_append_no_cache(void) 471 { 472 int rc; 473 char buf[100]; 474 struct spdk_fs_thread_ctx *channel; 475 struct spdk_thread *thread; 476 477 ut_send_request(_fs_init, NULL); 478 479 channel = spdk_fs_alloc_thread_ctx(g_fs); 480 481 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 482 CU_ASSERT(rc == 0); 483 SPDK_CU_ASSERT_FATAL(g_file != NULL); 484 485 spdk_file_write(g_file, channel, buf, 0 * sizeof(buf), sizeof(buf)); 486 CU_ASSERT(spdk_file_get_length(g_file) == 1 * sizeof(buf)); 487 spdk_file_write(g_file, channel, buf, 1 * sizeof(buf), sizeof(buf)); 488 CU_ASSERT(spdk_file_get_length(g_file) == 2 * sizeof(buf)); 489 spdk_file_sync(g_file, channel); 490 cache_free_buffers(g_file); 491 spdk_file_write(g_file, channel, buf, 2 * sizeof(buf), sizeof(buf)); 492 CU_ASSERT(spdk_file_get_length(g_file) == 3 * sizeof(buf)); 493 spdk_file_write(g_file, channel, buf, 3 * sizeof(buf), sizeof(buf)); 494 CU_ASSERT(spdk_file_get_length(g_file) == 4 * sizeof(buf)); 495 spdk_file_write(g_file, channel, buf, 4 * sizeof(buf), sizeof(buf)); 496 CU_ASSERT(spdk_file_get_length(g_file) == 5 * sizeof(buf)); 497 498 spdk_file_close(g_file, channel); 499 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 500 CU_ASSERT(rc == 0); 501 502 spdk_fs_free_thread_ctx(channel); 503 504 thread = spdk_get_thread(); 505 while (spdk_thread_poll(thread, 0, 0) > 0) {} 506 507 ut_send_request(_fs_unload, NULL); 508 } 509 510 static void 511 fs_delete_file_without_close(void) 512 { 513 int rc; 514 struct spdk_fs_thread_ctx *channel; 515 struct spdk_file *file; 516 struct spdk_thread *thread; 517 518 ut_send_request(_fs_init, NULL); 519 channel = spdk_fs_alloc_thread_ctx(g_fs); 520 CU_ASSERT(channel != NULL); 521 522 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 523 CU_ASSERT(rc == 0); 524 SPDK_CU_ASSERT_FATAL(g_file != NULL); 525 526 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 527 CU_ASSERT(rc == 0); 528 CU_ASSERT(g_file->ref_count != 0); 529 CU_ASSERT(g_file->is_deleted == true); 530 531 rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file); 532 CU_ASSERT(rc != 0); 533 534 spdk_file_close(g_file, channel); 535 536 rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file); 537 CU_ASSERT(rc != 0); 538 539 spdk_fs_free_thread_ctx(channel); 540 541 thread = spdk_get_thread(); 542 while (spdk_thread_poll(thread, 0, 0) > 0) {} 543 544 ut_send_request(_fs_unload, NULL); 545 546 } 547 548 static bool g_thread_exit = false; 549 550 static void 551 terminate_spdk_thread(void *arg) 552 { 553 g_thread_exit = true; 554 } 555 556 static void * 557 spdk_thread(void *arg) 558 { 559 struct spdk_thread *thread = arg; 560 561 spdk_set_thread(thread); 562 563 while (!g_thread_exit) { 564 spdk_thread_poll(thread, 0, 0); 565 } 566 567 return NULL; 568 } 569 570 int main(int argc, char **argv) 571 { 572 struct spdk_thread *thread; 573 CU_pSuite suite = NULL; 574 pthread_t spdk_tid; 575 unsigned int num_failures; 576 577 if (CU_initialize_registry() != CUE_SUCCESS) { 578 return CU_get_error(); 579 } 580 581 suite = CU_add_suite("blobfs_sync_ut", NULL, NULL); 582 if (suite == NULL) { 583 CU_cleanup_registry(); 584 return CU_get_error(); 585 } 586 587 if ( 588 CU_add_test(suite, "cache read after write", cache_read_after_write) == NULL || 589 CU_add_test(suite, "file length", file_length) == NULL || 590 CU_add_test(suite, "partial buffer", partial_buffer) == NULL || 591 CU_add_test(suite, "write_null_buffer", cache_write_null_buffer) == NULL || 592 CU_add_test(suite, "create_sync", fs_create_sync) == NULL || 593 CU_add_test(suite, "rename_sync", fs_rename_sync) == NULL || 594 CU_add_test(suite, "append_no_cache", cache_append_no_cache) == NULL || 595 CU_add_test(suite, "delete_file_without_close", fs_delete_file_without_close) == NULL 596 ) { 597 CU_cleanup_registry(); 598 return CU_get_error(); 599 } 600 601 spdk_thread_lib_init(NULL, 0); 602 603 thread = spdk_thread_create("test_thread", NULL); 604 spdk_set_thread(thread); 605 606 g_dispatch_thread = spdk_thread_create("dispatch_thread", NULL); 607 pthread_create(&spdk_tid, NULL, spdk_thread, g_dispatch_thread); 608 609 g_dev_buffer = calloc(1, DEV_BUFFER_SIZE); 610 611 CU_basic_set_mode(CU_BRM_VERBOSE); 612 CU_basic_run_tests(); 613 num_failures = CU_get_number_of_failures(); 614 CU_cleanup_registry(); 615 616 free(g_dev_buffer); 617 618 ut_send_request(terminate_spdk_thread, NULL); 619 pthread_join(spdk_tid, NULL); 620 621 while (spdk_thread_poll(g_dispatch_thread, 0, 0) > 0) {} 622 while (spdk_thread_poll(thread, 0, 0) > 0) {} 623 624 spdk_set_thread(thread); 625 spdk_thread_exit(thread); 626 spdk_thread_destroy(thread); 627 628 spdk_set_thread(g_dispatch_thread); 629 spdk_thread_exit(g_dispatch_thread); 630 spdk_thread_destroy(g_dispatch_thread); 631 632 spdk_thread_lib_fini(); 633 634 return num_failures; 635 } 636