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_unload(void *arg) 145 { 146 struct spdk_thread *thread; 147 148 g_fserrno = -1; 149 spdk_fs_unload(g_fs, fs_op_complete, NULL); 150 thread = spdk_get_thread(); 151 while (spdk_thread_poll(thread, 0, 0) > 0) {} 152 CU_ASSERT(g_fserrno == 0); 153 g_fs = NULL; 154 } 155 156 static void 157 cache_write(void) 158 { 159 uint64_t length; 160 int rc; 161 char buf[100]; 162 struct spdk_fs_thread_ctx *channel; 163 164 ut_send_request(_fs_init, NULL); 165 166 channel = spdk_fs_alloc_thread_ctx(g_fs); 167 168 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 169 CU_ASSERT(rc == 0); 170 SPDK_CU_ASSERT_FATAL(g_file != NULL); 171 172 length = (4 * 1024 * 1024); 173 rc = spdk_file_truncate(g_file, channel, length); 174 CU_ASSERT(rc == 0); 175 176 spdk_file_write(g_file, channel, buf, 0, sizeof(buf)); 177 178 CU_ASSERT(spdk_file_get_length(g_file) == length); 179 180 rc = spdk_file_truncate(g_file, channel, sizeof(buf)); 181 CU_ASSERT(rc == 0); 182 183 spdk_file_close(g_file, channel); 184 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 185 CU_ASSERT(rc == 0); 186 187 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 188 CU_ASSERT(rc == -ENOENT); 189 190 spdk_fs_free_thread_ctx(channel); 191 192 ut_send_request(_fs_unload, NULL); 193 } 194 195 static void 196 cache_write_null_buffer(void) 197 { 198 uint64_t length; 199 int rc; 200 struct spdk_fs_thread_ctx *channel; 201 struct spdk_thread *thread; 202 203 ut_send_request(_fs_init, NULL); 204 205 channel = spdk_fs_alloc_thread_ctx(g_fs); 206 207 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 208 CU_ASSERT(rc == 0); 209 SPDK_CU_ASSERT_FATAL(g_file != NULL); 210 211 length = 0; 212 rc = spdk_file_truncate(g_file, channel, length); 213 CU_ASSERT(rc == 0); 214 215 rc = spdk_file_write(g_file, channel, NULL, 0, 0); 216 CU_ASSERT(rc == 0); 217 218 spdk_file_close(g_file, channel); 219 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 220 CU_ASSERT(rc == 0); 221 222 spdk_fs_free_thread_ctx(channel); 223 224 thread = spdk_get_thread(); 225 while (spdk_thread_poll(thread, 0, 0) > 0) {} 226 227 ut_send_request(_fs_unload, NULL); 228 } 229 230 static void 231 fs_create_sync(void) 232 { 233 int rc; 234 struct spdk_fs_thread_ctx *channel; 235 struct spdk_thread *thread; 236 237 ut_send_request(_fs_init, NULL); 238 239 channel = spdk_fs_alloc_thread_ctx(g_fs); 240 CU_ASSERT(channel != NULL); 241 242 rc = spdk_fs_create_file(g_fs, channel, "testfile"); 243 CU_ASSERT(rc == 0); 244 245 /* Create should fail, because the file already exists. */ 246 rc = spdk_fs_create_file(g_fs, channel, "testfile"); 247 CU_ASSERT(rc != 0); 248 249 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 250 CU_ASSERT(rc == 0); 251 252 spdk_fs_free_thread_ctx(channel); 253 254 thread = spdk_get_thread(); 255 while (spdk_thread_poll(thread, 0, 0) > 0) {} 256 257 ut_send_request(_fs_unload, NULL); 258 } 259 260 static void 261 cache_append_no_cache(void) 262 { 263 int rc; 264 char buf[100]; 265 struct spdk_fs_thread_ctx *channel; 266 struct spdk_thread *thread; 267 268 ut_send_request(_fs_init, NULL); 269 270 channel = spdk_fs_alloc_thread_ctx(g_fs); 271 272 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 273 CU_ASSERT(rc == 0); 274 SPDK_CU_ASSERT_FATAL(g_file != NULL); 275 276 spdk_file_write(g_file, channel, buf, 0 * sizeof(buf), sizeof(buf)); 277 CU_ASSERT(spdk_file_get_length(g_file) == 1 * sizeof(buf)); 278 spdk_file_write(g_file, channel, buf, 1 * sizeof(buf), sizeof(buf)); 279 CU_ASSERT(spdk_file_get_length(g_file) == 2 * sizeof(buf)); 280 spdk_file_sync(g_file, channel); 281 cache_free_buffers(g_file); 282 spdk_file_write(g_file, channel, buf, 2 * sizeof(buf), sizeof(buf)); 283 CU_ASSERT(spdk_file_get_length(g_file) == 3 * sizeof(buf)); 284 spdk_file_write(g_file, channel, buf, 3 * sizeof(buf), sizeof(buf)); 285 CU_ASSERT(spdk_file_get_length(g_file) == 4 * sizeof(buf)); 286 spdk_file_write(g_file, channel, buf, 4 * sizeof(buf), sizeof(buf)); 287 CU_ASSERT(spdk_file_get_length(g_file) == 5 * sizeof(buf)); 288 289 spdk_file_close(g_file, channel); 290 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 291 CU_ASSERT(rc == 0); 292 293 spdk_fs_free_thread_ctx(channel); 294 295 thread = spdk_get_thread(); 296 while (spdk_thread_poll(thread, 0, 0) > 0) {} 297 298 ut_send_request(_fs_unload, NULL); 299 } 300 301 static void 302 fs_delete_file_without_close(void) 303 { 304 int rc; 305 struct spdk_fs_thread_ctx *channel; 306 struct spdk_file *file; 307 struct spdk_thread *thread; 308 309 ut_send_request(_fs_init, NULL); 310 channel = spdk_fs_alloc_thread_ctx(g_fs); 311 CU_ASSERT(channel != NULL); 312 313 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 314 CU_ASSERT(rc == 0); 315 SPDK_CU_ASSERT_FATAL(g_file != NULL); 316 317 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 318 CU_ASSERT(rc == 0); 319 CU_ASSERT(g_file->ref_count != 0); 320 CU_ASSERT(g_file->is_deleted == true); 321 322 rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file); 323 CU_ASSERT(rc != 0); 324 325 spdk_file_close(g_file, channel); 326 327 rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file); 328 CU_ASSERT(rc != 0); 329 330 spdk_fs_free_thread_ctx(channel); 331 332 thread = spdk_get_thread(); 333 while (spdk_thread_poll(thread, 0, 0) > 0) {} 334 335 ut_send_request(_fs_unload, NULL); 336 337 } 338 339 static bool g_thread_exit = false; 340 341 static void 342 terminate_spdk_thread(void *arg) 343 { 344 g_thread_exit = true; 345 } 346 347 static void * 348 spdk_thread(void *arg) 349 { 350 struct spdk_thread *thread = arg; 351 352 spdk_set_thread(thread); 353 354 while (!g_thread_exit) { 355 spdk_thread_poll(thread, 0, 0); 356 } 357 358 return NULL; 359 } 360 361 int main(int argc, char **argv) 362 { 363 struct spdk_thread *thread; 364 CU_pSuite suite = NULL; 365 pthread_t spdk_tid; 366 unsigned int num_failures; 367 368 if (CU_initialize_registry() != CUE_SUCCESS) { 369 return CU_get_error(); 370 } 371 372 suite = CU_add_suite("blobfs_sync_ut", NULL, NULL); 373 if (suite == NULL) { 374 CU_cleanup_registry(); 375 return CU_get_error(); 376 } 377 378 if ( 379 CU_add_test(suite, "write", cache_write) == NULL || 380 CU_add_test(suite, "write_null_buffer", cache_write_null_buffer) == NULL || 381 CU_add_test(suite, "create_sync", fs_create_sync) == NULL || 382 CU_add_test(suite, "append_no_cache", cache_append_no_cache) == NULL || 383 CU_add_test(suite, "delete_file_without_close", fs_delete_file_without_close) == NULL 384 ) { 385 CU_cleanup_registry(); 386 return CU_get_error(); 387 } 388 389 spdk_thread_lib_init(NULL, 0); 390 391 thread = spdk_thread_create("test_thread", NULL); 392 spdk_set_thread(thread); 393 394 g_dispatch_thread = spdk_thread_create("dispatch_thread", NULL); 395 pthread_create(&spdk_tid, NULL, spdk_thread, g_dispatch_thread); 396 397 g_dev_buffer = calloc(1, DEV_BUFFER_SIZE); 398 399 CU_basic_set_mode(CU_BRM_VERBOSE); 400 CU_basic_run_tests(); 401 num_failures = CU_get_number_of_failures(); 402 CU_cleanup_registry(); 403 404 free(g_dev_buffer); 405 406 ut_send_request(terminate_spdk_thread, NULL); 407 pthread_join(spdk_tid, NULL); 408 409 while (spdk_thread_poll(g_dispatch_thread, 0, 0) > 0) {} 410 while (spdk_thread_poll(thread, 0, 0) > 0) {} 411 412 spdk_thread_exit(thread); 413 spdk_thread_exit(g_dispatch_thread); 414 415 spdk_thread_lib_fini(); 416 417 return num_failures; 418 } 419