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