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 "CUnit/Basic.h" 37 38 #include "common/lib/ut_multithread.c" 39 40 #include "spdk_cunit.h" 41 #include "blobfs/blobfs.c" 42 #include "blobfs/tree.c" 43 #include "blob/blobstore.h" 44 45 #include "spdk_internal/thread.h" 46 47 #include "unit/lib/blob/bs_dev_common.c" 48 49 struct spdk_filesystem *g_fs; 50 struct spdk_file *g_file; 51 int g_fserrno; 52 53 /* Return NULL to test hardcoded defaults. */ 54 struct spdk_conf_section * 55 spdk_conf_find_section(struct spdk_conf *cp, const char *name) 56 { 57 return NULL; 58 } 59 60 /* Return -1 to test hardcoded defaults. */ 61 int 62 spdk_conf_section_get_intval(struct spdk_conf_section *sp, const char *key) 63 { 64 return -1; 65 } 66 67 static void 68 fs_op_complete(void *ctx, int fserrno) 69 { 70 g_fserrno = fserrno; 71 } 72 73 static void 74 fs_op_with_handle_complete(void *ctx, struct spdk_filesystem *fs, int fserrno) 75 { 76 g_fs = fs; 77 g_fserrno = fserrno; 78 } 79 80 static void 81 fs_init(void) 82 { 83 struct spdk_filesystem *fs; 84 struct spdk_bs_dev *dev; 85 86 dev = init_dev(); 87 88 spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL); 89 poll_threads(); 90 SPDK_CU_ASSERT_FATAL(g_fs != NULL); 91 CU_ASSERT(g_fserrno == 0); 92 fs = g_fs; 93 SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev); 94 95 g_fserrno = 1; 96 spdk_fs_unload(fs, fs_op_complete, NULL); 97 poll_threads(); 98 CU_ASSERT(g_fserrno == 0); 99 } 100 101 static void 102 create_cb(void *ctx, int fserrno) 103 { 104 g_fserrno = fserrno; 105 } 106 107 static void 108 open_cb(void *ctx, struct spdk_file *f, int fserrno) 109 { 110 g_fserrno = fserrno; 111 g_file = f; 112 } 113 114 static void 115 delete_cb(void *ctx, int fserrno) 116 { 117 g_fserrno = fserrno; 118 } 119 120 static void 121 fs_open(void) 122 { 123 struct spdk_filesystem *fs; 124 spdk_fs_iter iter; 125 struct spdk_bs_dev *dev; 126 struct spdk_file *file; 127 char name[257] = {'\0'}; 128 129 dev = init_dev(); 130 memset(name, 'a', sizeof(name) - 1); 131 132 spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL); 133 poll_threads(); 134 SPDK_CU_ASSERT_FATAL(g_fs != NULL); 135 CU_ASSERT(g_fserrno == 0); 136 fs = g_fs; 137 SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev); 138 139 g_fserrno = 0; 140 /* Open should fail, because the file name is too long. */ 141 spdk_fs_open_file_async(fs, name, SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL); 142 poll_threads(); 143 CU_ASSERT(g_fserrno == -ENAMETOOLONG); 144 145 g_fserrno = 0; 146 spdk_fs_open_file_async(fs, "file1", 0, open_cb, NULL); 147 poll_threads(); 148 CU_ASSERT(g_fserrno == -ENOENT); 149 150 g_file = NULL; 151 g_fserrno = 1; 152 spdk_fs_open_file_async(fs, "file1", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL); 153 poll_threads(); 154 CU_ASSERT(g_fserrno == 0); 155 SPDK_CU_ASSERT_FATAL(g_file != NULL); 156 CU_ASSERT(!strcmp("file1", g_file->name)); 157 CU_ASSERT(g_file->ref_count == 1); 158 159 iter = spdk_fs_iter_first(fs); 160 CU_ASSERT(iter != NULL); 161 file = spdk_fs_iter_get_file(iter); 162 SPDK_CU_ASSERT_FATAL(file != NULL); 163 CU_ASSERT(!strcmp("file1", file->name)); 164 iter = spdk_fs_iter_next(iter); 165 CU_ASSERT(iter == NULL); 166 167 g_fserrno = 0; 168 /* Delete should successful, we will mark the file as deleted. */ 169 spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL); 170 poll_threads(); 171 CU_ASSERT(g_fserrno == 0); 172 CU_ASSERT(!TAILQ_EMPTY(&fs->files)); 173 174 g_fserrno = 1; 175 spdk_file_close_async(g_file, fs_op_complete, NULL); 176 poll_threads(); 177 CU_ASSERT(g_fserrno == 0); 178 CU_ASSERT(TAILQ_EMPTY(&fs->files)); 179 180 g_fserrno = 1; 181 spdk_fs_unload(fs, fs_op_complete, NULL); 182 poll_threads(); 183 CU_ASSERT(g_fserrno == 0); 184 } 185 186 static void 187 fs_create(void) 188 { 189 struct spdk_filesystem *fs; 190 struct spdk_bs_dev *dev; 191 char name[257] = {'\0'}; 192 193 dev = init_dev(); 194 memset(name, 'a', sizeof(name) - 1); 195 196 spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL); 197 poll_threads(); 198 SPDK_CU_ASSERT_FATAL(g_fs != NULL); 199 CU_ASSERT(g_fserrno == 0); 200 fs = g_fs; 201 SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev); 202 203 g_fserrno = 0; 204 /* Create should fail, because the file name is too long. */ 205 spdk_fs_create_file_async(fs, name, create_cb, NULL); 206 poll_threads(); 207 CU_ASSERT(g_fserrno == -ENAMETOOLONG); 208 209 g_fserrno = 1; 210 spdk_fs_create_file_async(fs, "file1", create_cb, NULL); 211 poll_threads(); 212 CU_ASSERT(g_fserrno == 0); 213 214 g_fserrno = 1; 215 spdk_fs_create_file_async(fs, "file1", create_cb, NULL); 216 poll_threads(); 217 CU_ASSERT(g_fserrno == -EEXIST); 218 219 g_fserrno = 1; 220 spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL); 221 poll_threads(); 222 CU_ASSERT(g_fserrno == 0); 223 CU_ASSERT(TAILQ_EMPTY(&fs->files)); 224 225 g_fserrno = 1; 226 spdk_fs_unload(fs, fs_op_complete, NULL); 227 poll_threads(); 228 CU_ASSERT(g_fserrno == 0); 229 } 230 231 static void 232 fs_truncate(void) 233 { 234 struct spdk_filesystem *fs; 235 struct spdk_bs_dev *dev; 236 237 dev = init_dev(); 238 239 spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL); 240 poll_threads(); 241 SPDK_CU_ASSERT_FATAL(g_fs != NULL); 242 CU_ASSERT(g_fserrno == 0); 243 fs = g_fs; 244 SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev); 245 246 g_file = NULL; 247 g_fserrno = 1; 248 spdk_fs_open_file_async(fs, "file1", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL); 249 poll_threads(); 250 CU_ASSERT(g_fserrno == 0); 251 SPDK_CU_ASSERT_FATAL(g_file != NULL); 252 253 g_fserrno = 1; 254 spdk_file_truncate_async(g_file, 18 * 1024 * 1024 + 1, fs_op_complete, NULL); 255 poll_threads(); 256 CU_ASSERT(g_fserrno == 0); 257 CU_ASSERT(g_file->length == 18 * 1024 * 1024 + 1); 258 259 g_fserrno = 1; 260 spdk_file_truncate_async(g_file, 1, fs_op_complete, NULL); 261 poll_threads(); 262 CU_ASSERT(g_fserrno == 0); 263 CU_ASSERT(g_file->length == 1); 264 265 g_fserrno = 1; 266 spdk_file_truncate_async(g_file, 18 * 1024 * 1024 + 1, fs_op_complete, NULL); 267 poll_threads(); 268 CU_ASSERT(g_fserrno == 0); 269 CU_ASSERT(g_file->length == 18 * 1024 * 1024 + 1); 270 271 g_fserrno = 1; 272 spdk_file_close_async(g_file, fs_op_complete, NULL); 273 poll_threads(); 274 CU_ASSERT(g_fserrno == 0); 275 CU_ASSERT(g_file->ref_count == 0); 276 277 g_fserrno = 1; 278 spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL); 279 poll_threads(); 280 CU_ASSERT(g_fserrno == 0); 281 CU_ASSERT(TAILQ_EMPTY(&fs->files)); 282 283 g_fserrno = 1; 284 spdk_fs_unload(fs, fs_op_complete, NULL); 285 poll_threads(); 286 CU_ASSERT(g_fserrno == 0); 287 } 288 289 static void 290 fs_rename(void) 291 { 292 struct spdk_filesystem *fs; 293 struct spdk_file *file, *file2, *file_iter; 294 struct spdk_bs_dev *dev; 295 296 dev = init_dev(); 297 298 spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL); 299 poll_threads(); 300 SPDK_CU_ASSERT_FATAL(g_fs != NULL); 301 CU_ASSERT(g_fserrno == 0); 302 fs = g_fs; 303 SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev); 304 305 g_fserrno = 1; 306 spdk_fs_create_file_async(fs, "file1", create_cb, NULL); 307 poll_threads(); 308 CU_ASSERT(g_fserrno == 0); 309 310 g_file = NULL; 311 g_fserrno = 1; 312 spdk_fs_open_file_async(fs, "file1", 0, open_cb, NULL); 313 poll_threads(); 314 CU_ASSERT(g_fserrno == 0); 315 SPDK_CU_ASSERT_FATAL(g_file != NULL); 316 CU_ASSERT(g_file->ref_count == 1); 317 318 file = g_file; 319 g_file = NULL; 320 g_fserrno = 1; 321 spdk_file_close_async(file, fs_op_complete, NULL); 322 poll_threads(); 323 CU_ASSERT(g_fserrno == 0); 324 SPDK_CU_ASSERT_FATAL(file->ref_count == 0); 325 326 g_file = NULL; 327 g_fserrno = 1; 328 spdk_fs_open_file_async(fs, "file2", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL); 329 poll_threads(); 330 CU_ASSERT(g_fserrno == 0); 331 SPDK_CU_ASSERT_FATAL(g_file != NULL); 332 CU_ASSERT(g_file->ref_count == 1); 333 334 file2 = g_file; 335 g_file = NULL; 336 g_fserrno = 1; 337 spdk_file_close_async(file2, fs_op_complete, NULL); 338 poll_threads(); 339 CU_ASSERT(g_fserrno == 0); 340 SPDK_CU_ASSERT_FATAL(file2->ref_count == 0); 341 342 /* 343 * Do a 3-way rename. This should delete the old "file2", then rename 344 * "file1" to "file2". 345 */ 346 g_fserrno = 1; 347 spdk_fs_rename_file_async(fs, "file1", "file2", fs_op_complete, NULL); 348 poll_threads(); 349 CU_ASSERT(g_fserrno == 0); 350 CU_ASSERT(file->ref_count == 0); 351 CU_ASSERT(!strcmp(file->name, "file2")); 352 CU_ASSERT(TAILQ_FIRST(&fs->files) == file); 353 CU_ASSERT(TAILQ_NEXT(file, tailq) == NULL); 354 355 g_fserrno = 0; 356 spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL); 357 poll_threads(); 358 CU_ASSERT(g_fserrno == -ENOENT); 359 CU_ASSERT(!TAILQ_EMPTY(&fs->files)); 360 TAILQ_FOREACH(file_iter, &fs->files, tailq) { 361 if (file_iter == NULL) { 362 SPDK_CU_ASSERT_FATAL(false); 363 } 364 } 365 366 g_fserrno = 1; 367 spdk_fs_delete_file_async(fs, "file2", delete_cb, NULL); 368 poll_threads(); 369 CU_ASSERT(g_fserrno == 0); 370 CU_ASSERT(TAILQ_EMPTY(&fs->files)); 371 372 g_fserrno = 1; 373 spdk_fs_unload(fs, fs_op_complete, NULL); 374 poll_threads(); 375 CU_ASSERT(g_fserrno == 0); 376 } 377 378 static void 379 tree_find_buffer_ut(void) 380 { 381 struct cache_tree *root; 382 struct cache_tree *level1_0; 383 struct cache_tree *level0_0_0; 384 struct cache_tree *level0_0_12; 385 struct cache_buffer *leaf_0_0_4; 386 struct cache_buffer *leaf_0_12_8; 387 struct cache_buffer *leaf_9_23_15; 388 struct cache_buffer *buffer; 389 390 level1_0 = calloc(1, sizeof(struct cache_tree)); 391 SPDK_CU_ASSERT_FATAL(level1_0 != NULL); 392 level0_0_0 = calloc(1, sizeof(struct cache_tree)); 393 SPDK_CU_ASSERT_FATAL(level0_0_0 != NULL); 394 level0_0_12 = calloc(1, sizeof(struct cache_tree)); 395 SPDK_CU_ASSERT_FATAL(level0_0_12 != NULL); 396 leaf_0_0_4 = calloc(1, sizeof(struct cache_buffer)); 397 SPDK_CU_ASSERT_FATAL(leaf_0_0_4 != NULL); 398 leaf_0_12_8 = calloc(1, sizeof(struct cache_buffer)); 399 SPDK_CU_ASSERT_FATAL(leaf_0_12_8 != NULL); 400 leaf_9_23_15 = calloc(1, sizeof(struct cache_buffer)); 401 SPDK_CU_ASSERT_FATAL(leaf_9_23_15 != NULL); 402 403 level1_0->level = 1; 404 level0_0_0->level = 0; 405 level0_0_12->level = 0; 406 407 leaf_0_0_4->offset = CACHE_BUFFER_SIZE * 4; 408 level0_0_0->u.buffer[4] = leaf_0_0_4; 409 level0_0_0->present_mask |= (1ULL << 4); 410 411 leaf_0_12_8->offset = CACHE_TREE_LEVEL_SIZE(1) * 12 + CACHE_BUFFER_SIZE * 8; 412 level0_0_12->u.buffer[8] = leaf_0_12_8; 413 level0_0_12->present_mask |= (1ULL << 8); 414 415 level1_0->u.tree[0] = level0_0_0; 416 level1_0->present_mask |= (1ULL << 0); 417 level1_0->u.tree[12] = level0_0_12; 418 level1_0->present_mask |= (1ULL << 12); 419 420 buffer = spdk_tree_find_buffer(NULL, 0); 421 CU_ASSERT(buffer == NULL); 422 423 buffer = spdk_tree_find_buffer(level0_0_0, 0); 424 CU_ASSERT(buffer == NULL); 425 426 buffer = spdk_tree_find_buffer(level0_0_0, CACHE_TREE_LEVEL_SIZE(0) + 1); 427 CU_ASSERT(buffer == NULL); 428 429 buffer = spdk_tree_find_buffer(level0_0_0, leaf_0_0_4->offset); 430 CU_ASSERT(buffer == leaf_0_0_4); 431 432 buffer = spdk_tree_find_buffer(level1_0, leaf_0_0_4->offset); 433 CU_ASSERT(buffer == leaf_0_0_4); 434 435 buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset); 436 CU_ASSERT(buffer == leaf_0_12_8); 437 438 buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset + CACHE_BUFFER_SIZE - 1); 439 CU_ASSERT(buffer == leaf_0_12_8); 440 441 buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset - 1); 442 CU_ASSERT(buffer == NULL); 443 444 leaf_9_23_15->offset = CACHE_TREE_LEVEL_SIZE(2) * 9 + 445 CACHE_TREE_LEVEL_SIZE(1) * 23 + 446 CACHE_BUFFER_SIZE * 15; 447 root = spdk_tree_insert_buffer(level1_0, leaf_9_23_15); 448 CU_ASSERT(root != level1_0); 449 buffer = spdk_tree_find_buffer(root, leaf_9_23_15->offset); 450 CU_ASSERT(buffer == leaf_9_23_15); 451 spdk_tree_free_buffers(root); 452 free(root); 453 } 454 455 static void 456 channel_ops(void) 457 { 458 struct spdk_filesystem *fs; 459 struct spdk_bs_dev *dev; 460 struct spdk_io_channel *channel; 461 462 dev = init_dev(); 463 464 spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL); 465 poll_threads(); 466 SPDK_CU_ASSERT_FATAL(g_fs != NULL); 467 CU_ASSERT(g_fserrno == 0); 468 fs = g_fs; 469 SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev); 470 471 channel = spdk_fs_alloc_io_channel(fs); 472 CU_ASSERT(channel != NULL); 473 474 spdk_fs_free_io_channel(channel); 475 476 g_fserrno = 1; 477 spdk_fs_unload(fs, fs_op_complete, NULL); 478 poll_threads(); 479 CU_ASSERT(g_fserrno == 0); 480 g_fs = NULL; 481 } 482 483 static void 484 channel_ops_sync(void) 485 { 486 struct spdk_filesystem *fs; 487 struct spdk_bs_dev *dev; 488 struct spdk_fs_thread_ctx *channel; 489 490 dev = init_dev(); 491 492 spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL); 493 poll_threads(); 494 SPDK_CU_ASSERT_FATAL(g_fs != NULL); 495 CU_ASSERT(g_fserrno == 0); 496 fs = g_fs; 497 SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev); 498 499 channel = spdk_fs_alloc_thread_ctx(fs); 500 CU_ASSERT(channel != NULL); 501 502 spdk_fs_free_thread_ctx(channel); 503 504 g_fserrno = 1; 505 spdk_fs_unload(fs, fs_op_complete, NULL); 506 poll_threads(); 507 CU_ASSERT(g_fserrno == 0); 508 g_fs = NULL; 509 } 510 511 int main(int argc, char **argv) 512 { 513 CU_pSuite suite = NULL; 514 unsigned int num_failures; 515 516 if (CU_initialize_registry() != CUE_SUCCESS) { 517 return CU_get_error(); 518 } 519 520 suite = CU_add_suite("blobfs_async_ut", NULL, NULL); 521 if (suite == NULL) { 522 CU_cleanup_registry(); 523 return CU_get_error(); 524 } 525 526 if ( 527 CU_add_test(suite, "fs_init", fs_init) == NULL || 528 CU_add_test(suite, "fs_open", fs_open) == NULL || 529 CU_add_test(suite, "fs_create", fs_create) == NULL || 530 CU_add_test(suite, "fs_truncate", fs_truncate) == NULL || 531 CU_add_test(suite, "fs_rename", fs_rename) == NULL || 532 CU_add_test(suite, "tree_find_buffer", tree_find_buffer_ut) == NULL || 533 CU_add_test(suite, "channel_ops", channel_ops) == NULL || 534 CU_add_test(suite, "channel_ops_sync", channel_ops_sync) == NULL 535 ) { 536 CU_cleanup_registry(); 537 return CU_get_error(); 538 } 539 540 allocate_threads(1); 541 set_thread(0); 542 543 g_dev_buffer = calloc(1, DEV_BUFFER_SIZE); 544 CU_basic_set_mode(CU_BRM_VERBOSE); 545 CU_basic_run_tests(); 546 num_failures = CU_get_number_of_failures(); 547 CU_cleanup_registry(); 548 free(g_dev_buffer); 549 550 free_threads(); 551 552 return num_failures; 553 } 554