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 54 /* Return NULL to test hardcoded defaults. */ 55 struct spdk_conf_section * 56 spdk_conf_find_section(struct spdk_conf *cp, const char *name) 57 { 58 return NULL; 59 } 60 61 /* Return -1 to test hardcoded defaults. */ 62 int 63 spdk_conf_section_get_intval(struct spdk_conf_section *sp, const char *key) 64 { 65 return -1; 66 } 67 68 struct ut_request { 69 fs_request_fn fn; 70 void *arg; 71 volatile int done; 72 }; 73 74 static void 75 send_request(fs_request_fn fn, void *arg) 76 { 77 spdk_thread_send_msg(g_dispatch_thread, (spdk_msg_fn)fn, arg); 78 } 79 80 static void 81 ut_call_fn(void *arg) 82 { 83 struct ut_request *req = arg; 84 85 req->fn(req->arg); 86 req->done = 1; 87 } 88 89 static void 90 ut_send_request(fs_request_fn fn, void *arg) 91 { 92 struct ut_request req; 93 94 req.fn = fn; 95 req.arg = arg; 96 req.done = 0; 97 98 spdk_thread_send_msg(g_dispatch_thread, ut_call_fn, &req); 99 100 /* Wait for this to finish */ 101 while (req.done == 0) { } 102 } 103 104 static void 105 fs_op_complete(void *ctx, int fserrno) 106 { 107 g_fserrno = fserrno; 108 } 109 110 static void 111 fs_op_with_handle_complete(void *ctx, struct spdk_filesystem *fs, int fserrno) 112 { 113 g_fs = fs; 114 g_fserrno = fserrno; 115 } 116 117 static void 118 _fs_init(void *arg) 119 { 120 struct spdk_thread *thread; 121 struct spdk_bs_dev *dev; 122 123 g_fs = NULL; 124 g_fserrno = -1; 125 dev = init_dev(); 126 spdk_fs_init(dev, NULL, send_request, fs_op_with_handle_complete, NULL); 127 thread = spdk_get_thread(); 128 while (spdk_thread_poll(thread, 0, 0) > 0) {} 129 130 SPDK_CU_ASSERT_FATAL(g_fs != NULL); 131 SPDK_CU_ASSERT_FATAL(g_fs->bdev == dev); 132 CU_ASSERT(g_fserrno == 0); 133 } 134 135 static void 136 _fs_unload(void *arg) 137 { 138 struct spdk_thread *thread; 139 140 g_fserrno = -1; 141 spdk_fs_unload(g_fs, fs_op_complete, NULL); 142 thread = spdk_get_thread(); 143 while (spdk_thread_poll(thread, 0, 0) > 0) {} 144 CU_ASSERT(g_fserrno == 0); 145 g_fs = NULL; 146 } 147 148 static void 149 cache_write(void) 150 { 151 uint64_t length; 152 int rc; 153 char buf[100]; 154 struct spdk_fs_thread_ctx *channel; 155 156 ut_send_request(_fs_init, NULL); 157 158 channel = spdk_fs_alloc_thread_ctx(g_fs); 159 160 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 161 CU_ASSERT(rc == 0); 162 SPDK_CU_ASSERT_FATAL(g_file != NULL); 163 164 length = (4 * 1024 * 1024); 165 rc = spdk_file_truncate(g_file, channel, length); 166 CU_ASSERT(rc == 0); 167 168 spdk_file_write(g_file, channel, buf, 0, sizeof(buf)); 169 170 CU_ASSERT(spdk_file_get_length(g_file) == length); 171 172 rc = spdk_file_truncate(g_file, channel, sizeof(buf)); 173 CU_ASSERT(rc == 0); 174 175 spdk_file_close(g_file, channel); 176 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 177 CU_ASSERT(rc == 0); 178 179 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 180 CU_ASSERT(rc == -ENOENT); 181 182 spdk_fs_free_thread_ctx(channel); 183 184 ut_send_request(_fs_unload, NULL); 185 } 186 187 static void 188 cache_write_null_buffer(void) 189 { 190 uint64_t length; 191 int rc; 192 struct spdk_fs_thread_ctx *channel; 193 struct spdk_thread *thread; 194 195 ut_send_request(_fs_init, NULL); 196 197 channel = spdk_fs_alloc_thread_ctx(g_fs); 198 199 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 200 CU_ASSERT(rc == 0); 201 SPDK_CU_ASSERT_FATAL(g_file != NULL); 202 203 length = 0; 204 rc = spdk_file_truncate(g_file, channel, length); 205 CU_ASSERT(rc == 0); 206 207 rc = spdk_file_write(g_file, channel, NULL, 0, 0); 208 CU_ASSERT(rc == 0); 209 210 spdk_file_close(g_file, channel); 211 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 212 CU_ASSERT(rc == 0); 213 214 spdk_fs_free_thread_ctx(channel); 215 216 thread = spdk_get_thread(); 217 while (spdk_thread_poll(thread, 0, 0) > 0) {} 218 219 ut_send_request(_fs_unload, NULL); 220 } 221 222 static void 223 fs_create_sync(void) 224 { 225 int rc; 226 struct spdk_fs_thread_ctx *channel; 227 struct spdk_thread *thread; 228 229 ut_send_request(_fs_init, NULL); 230 231 channel = spdk_fs_alloc_thread_ctx(g_fs); 232 CU_ASSERT(channel != NULL); 233 234 rc = spdk_fs_create_file(g_fs, channel, "testfile"); 235 CU_ASSERT(rc == 0); 236 237 /* Create should fail, because the file already exists. */ 238 rc = spdk_fs_create_file(g_fs, channel, "testfile"); 239 CU_ASSERT(rc != 0); 240 241 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 242 CU_ASSERT(rc == 0); 243 244 spdk_fs_free_thread_ctx(channel); 245 246 thread = spdk_get_thread(); 247 while (spdk_thread_poll(thread, 0, 0) > 0) {} 248 249 ut_send_request(_fs_unload, NULL); 250 } 251 252 static void 253 cache_append_no_cache(void) 254 { 255 int rc; 256 char buf[100]; 257 struct spdk_fs_thread_ctx *channel; 258 struct spdk_thread *thread; 259 260 ut_send_request(_fs_init, NULL); 261 262 channel = spdk_fs_alloc_thread_ctx(g_fs); 263 264 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 265 CU_ASSERT(rc == 0); 266 SPDK_CU_ASSERT_FATAL(g_file != NULL); 267 268 spdk_file_write(g_file, channel, buf, 0 * sizeof(buf), sizeof(buf)); 269 CU_ASSERT(spdk_file_get_length(g_file) == 1 * sizeof(buf)); 270 spdk_file_write(g_file, channel, buf, 1 * sizeof(buf), sizeof(buf)); 271 CU_ASSERT(spdk_file_get_length(g_file) == 2 * sizeof(buf)); 272 spdk_file_sync(g_file, channel); 273 cache_free_buffers(g_file); 274 spdk_file_write(g_file, channel, buf, 2 * sizeof(buf), sizeof(buf)); 275 CU_ASSERT(spdk_file_get_length(g_file) == 3 * sizeof(buf)); 276 spdk_file_write(g_file, channel, buf, 3 * sizeof(buf), sizeof(buf)); 277 CU_ASSERT(spdk_file_get_length(g_file) == 4 * sizeof(buf)); 278 spdk_file_write(g_file, channel, buf, 4 * sizeof(buf), sizeof(buf)); 279 CU_ASSERT(spdk_file_get_length(g_file) == 5 * sizeof(buf)); 280 281 spdk_file_close(g_file, channel); 282 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 283 CU_ASSERT(rc == 0); 284 285 spdk_fs_free_thread_ctx(channel); 286 287 thread = spdk_get_thread(); 288 while (spdk_thread_poll(thread, 0, 0) > 0) {} 289 290 ut_send_request(_fs_unload, NULL); 291 } 292 293 static void 294 fs_delete_file_without_close(void) 295 { 296 int rc; 297 struct spdk_fs_thread_ctx *channel; 298 struct spdk_file *file; 299 struct spdk_thread *thread; 300 301 ut_send_request(_fs_init, NULL); 302 channel = spdk_fs_alloc_thread_ctx(g_fs); 303 CU_ASSERT(channel != NULL); 304 305 rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file); 306 CU_ASSERT(rc == 0); 307 SPDK_CU_ASSERT_FATAL(g_file != NULL); 308 309 rc = spdk_fs_delete_file(g_fs, channel, "testfile"); 310 CU_ASSERT(rc == 0); 311 CU_ASSERT(g_file->ref_count != 0); 312 CU_ASSERT(g_file->is_deleted == true); 313 314 rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file); 315 CU_ASSERT(rc != 0); 316 317 spdk_file_close(g_file, channel); 318 319 rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file); 320 CU_ASSERT(rc != 0); 321 322 spdk_fs_free_thread_ctx(channel); 323 324 thread = spdk_get_thread(); 325 while (spdk_thread_poll(thread, 0, 0) > 0) {} 326 327 ut_send_request(_fs_unload, NULL); 328 329 } 330 331 static bool g_thread_exit = false; 332 333 static void 334 terminate_spdk_thread(void *arg) 335 { 336 g_thread_exit = true; 337 } 338 339 static void * 340 spdk_thread(void *arg) 341 { 342 struct spdk_thread *thread = arg; 343 344 spdk_set_thread(thread); 345 346 while (!g_thread_exit) { 347 spdk_thread_poll(thread, 0, 0); 348 } 349 350 return NULL; 351 } 352 353 int main(int argc, char **argv) 354 { 355 struct spdk_thread *thread; 356 CU_pSuite suite = NULL; 357 pthread_t spdk_tid; 358 unsigned int num_failures; 359 360 if (CU_initialize_registry() != CUE_SUCCESS) { 361 return CU_get_error(); 362 } 363 364 suite = CU_add_suite("blobfs_sync_ut", NULL, NULL); 365 if (suite == NULL) { 366 CU_cleanup_registry(); 367 return CU_get_error(); 368 } 369 370 if ( 371 CU_add_test(suite, "write", cache_write) == NULL || 372 CU_add_test(suite, "write_null_buffer", cache_write_null_buffer) == NULL || 373 CU_add_test(suite, "create_sync", fs_create_sync) == NULL || 374 CU_add_test(suite, "append_no_cache", cache_append_no_cache) == NULL || 375 CU_add_test(suite, "delete_file_without_close", fs_delete_file_without_close) == NULL 376 ) { 377 CU_cleanup_registry(); 378 return CU_get_error(); 379 } 380 381 spdk_thread_lib_init(NULL, 0); 382 383 thread = spdk_thread_create("test_thread"); 384 spdk_set_thread(thread); 385 386 g_dispatch_thread = spdk_thread_create("dispatch_thread"); 387 pthread_create(&spdk_tid, NULL, spdk_thread, g_dispatch_thread); 388 389 g_dev_buffer = calloc(1, DEV_BUFFER_SIZE); 390 391 CU_basic_set_mode(CU_BRM_VERBOSE); 392 CU_basic_run_tests(); 393 num_failures = CU_get_number_of_failures(); 394 CU_cleanup_registry(); 395 396 free(g_dev_buffer); 397 398 ut_send_request(terminate_spdk_thread, NULL); 399 pthread_join(spdk_tid, NULL); 400 401 while (spdk_thread_poll(g_dispatch_thread, 0, 0) > 0) {} 402 while (spdk_thread_poll(thread, 0, 0) > 0) {} 403 404 spdk_thread_exit(thread); 405 spdk_thread_exit(g_dispatch_thread); 406 407 spdk_thread_lib_fini(); 408 409 return num_failures; 410 } 411