xref: /spdk/test/unit/lib/blobfs/blobfs_async_ut/blobfs_async_ut.c (revision 712a3f69d32632bf6c862f00200f7f437d3f7529)
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 struct spdk_trace_histories *g_trace_histories;
53 DEFINE_STUB_V(spdk_trace_add_register_fn, (struct spdk_trace_register_fn *reg_fn));
54 DEFINE_STUB_V(spdk_trace_register_description, (const char *name,
55 		uint16_t tpoint_id, uint8_t owner_type,
56 		uint8_t object_type, uint8_t new_object,
57 		uint8_t arg1_is_ptr, const char *arg1_name));
58 DEFINE_STUB_V(_spdk_trace_record, (uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id,
59 				   uint32_t size, uint64_t object_id, uint64_t arg1));
60 
61 /* Return NULL to test hardcoded defaults. */
62 struct spdk_conf_section *
63 spdk_conf_find_section(struct spdk_conf *cp, const char *name)
64 {
65 	return NULL;
66 }
67 
68 /* Return -1 to test hardcoded defaults. */
69 int
70 spdk_conf_section_get_intval(struct spdk_conf_section *sp, const char *key)
71 {
72 	return -1;
73 }
74 
75 static void
76 fs_op_complete(void *ctx, int fserrno)
77 {
78 	g_fserrno = fserrno;
79 }
80 
81 static void
82 fs_op_with_handle_complete(void *ctx, struct spdk_filesystem *fs, int fserrno)
83 {
84 	g_fs = fs;
85 	g_fserrno = fserrno;
86 }
87 
88 static void
89 fs_init(void)
90 {
91 	struct spdk_filesystem *fs;
92 	struct spdk_bs_dev *dev;
93 
94 	dev = init_dev();
95 
96 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
97 	poll_threads();
98 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
99 	CU_ASSERT(g_fserrno == 0);
100 	fs = g_fs;
101 	SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev);
102 
103 	g_fserrno = 1;
104 	spdk_fs_unload(fs, fs_op_complete, NULL);
105 	poll_threads();
106 	CU_ASSERT(g_fserrno == 0);
107 }
108 
109 static void
110 create_cb(void *ctx, int fserrno)
111 {
112 	g_fserrno = fserrno;
113 }
114 
115 static void
116 open_cb(void *ctx, struct spdk_file *f, int fserrno)
117 {
118 	g_fserrno = fserrno;
119 	g_file = f;
120 }
121 
122 static void
123 delete_cb(void *ctx, int fserrno)
124 {
125 	g_fserrno = fserrno;
126 }
127 
128 static void
129 fs_open(void)
130 {
131 	struct spdk_filesystem *fs;
132 	spdk_fs_iter iter;
133 	struct spdk_bs_dev *dev;
134 	struct spdk_file *file;
135 	char name[257] = {'\0'};
136 
137 	dev = init_dev();
138 	memset(name, 'a', sizeof(name) - 1);
139 
140 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
141 	poll_threads();
142 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
143 	CU_ASSERT(g_fserrno == 0);
144 	fs = g_fs;
145 	SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev);
146 
147 	g_fserrno = 0;
148 	/* Open should fail, because the file name is too long. */
149 	spdk_fs_open_file_async(fs, name, SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
150 	poll_threads();
151 	CU_ASSERT(g_fserrno == -ENAMETOOLONG);
152 
153 	g_fserrno = 0;
154 	spdk_fs_open_file_async(fs, "file1", 0, open_cb, NULL);
155 	poll_threads();
156 	CU_ASSERT(g_fserrno == -ENOENT);
157 
158 	g_file = NULL;
159 	g_fserrno = 1;
160 	spdk_fs_open_file_async(fs, "file1", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
161 	poll_threads();
162 	CU_ASSERT(g_fserrno == 0);
163 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
164 	CU_ASSERT(!strcmp("file1", g_file->name));
165 	CU_ASSERT(g_file->ref_count == 1);
166 
167 	iter = spdk_fs_iter_first(fs);
168 	CU_ASSERT(iter != NULL);
169 	file = spdk_fs_iter_get_file(iter);
170 	SPDK_CU_ASSERT_FATAL(file != NULL);
171 	CU_ASSERT(!strcmp("file1", file->name));
172 	iter = spdk_fs_iter_next(iter);
173 	CU_ASSERT(iter == NULL);
174 
175 	g_fserrno = 0;
176 	/* Delete should successful, we will mark the file as deleted. */
177 	spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
178 	poll_threads();
179 	CU_ASSERT(g_fserrno == 0);
180 	CU_ASSERT(!TAILQ_EMPTY(&fs->files));
181 
182 	g_fserrno = 1;
183 	spdk_file_close_async(g_file, fs_op_complete, NULL);
184 	poll_threads();
185 	CU_ASSERT(g_fserrno == 0);
186 	CU_ASSERT(TAILQ_EMPTY(&fs->files));
187 
188 	g_fserrno = 1;
189 	spdk_fs_unload(fs, fs_op_complete, NULL);
190 	poll_threads();
191 	CU_ASSERT(g_fserrno == 0);
192 }
193 
194 static void
195 fs_create(void)
196 {
197 	struct spdk_filesystem *fs;
198 	struct spdk_bs_dev *dev;
199 	char name[257] = {'\0'};
200 
201 	dev = init_dev();
202 	memset(name, 'a', sizeof(name) - 1);
203 
204 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
205 	poll_threads();
206 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
207 	CU_ASSERT(g_fserrno == 0);
208 	fs = g_fs;
209 	SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev);
210 
211 	g_fserrno = 0;
212 	/* Create should fail, because the file name is too long. */
213 	spdk_fs_create_file_async(fs, name, create_cb, NULL);
214 	poll_threads();
215 	CU_ASSERT(g_fserrno == -ENAMETOOLONG);
216 
217 	g_fserrno = 1;
218 	spdk_fs_create_file_async(fs, "file1", create_cb, NULL);
219 	poll_threads();
220 	CU_ASSERT(g_fserrno == 0);
221 
222 	g_fserrno = 1;
223 	spdk_fs_create_file_async(fs, "file1", create_cb, NULL);
224 	poll_threads();
225 	CU_ASSERT(g_fserrno == -EEXIST);
226 
227 	g_fserrno = 1;
228 	spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
229 	poll_threads();
230 	CU_ASSERT(g_fserrno == 0);
231 	CU_ASSERT(TAILQ_EMPTY(&fs->files));
232 
233 	g_fserrno = 1;
234 	spdk_fs_unload(fs, fs_op_complete, NULL);
235 	poll_threads();
236 	CU_ASSERT(g_fserrno == 0);
237 }
238 
239 static void
240 fs_truncate(void)
241 {
242 	struct spdk_filesystem *fs;
243 	struct spdk_bs_dev *dev;
244 
245 	dev = init_dev();
246 
247 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
248 	poll_threads();
249 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
250 	CU_ASSERT(g_fserrno == 0);
251 	fs = g_fs;
252 	SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev);
253 
254 	g_file = NULL;
255 	g_fserrno = 1;
256 	spdk_fs_open_file_async(fs, "file1", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
257 	poll_threads();
258 	CU_ASSERT(g_fserrno == 0);
259 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
260 
261 	g_fserrno = 1;
262 	spdk_file_truncate_async(g_file, 18 * 1024 * 1024 + 1, fs_op_complete, NULL);
263 	poll_threads();
264 	CU_ASSERT(g_fserrno == 0);
265 	CU_ASSERT(g_file->length == 18 * 1024 * 1024 + 1);
266 
267 	g_fserrno = 1;
268 	spdk_file_truncate_async(g_file, 1, fs_op_complete, NULL);
269 	poll_threads();
270 	CU_ASSERT(g_fserrno == 0);
271 	CU_ASSERT(g_file->length == 1);
272 
273 	g_fserrno = 1;
274 	spdk_file_truncate_async(g_file, 18 * 1024 * 1024 + 1, fs_op_complete, NULL);
275 	poll_threads();
276 	CU_ASSERT(g_fserrno == 0);
277 	CU_ASSERT(g_file->length == 18 * 1024 * 1024 + 1);
278 
279 	g_fserrno = 1;
280 	spdk_file_close_async(g_file, fs_op_complete, NULL);
281 	poll_threads();
282 	CU_ASSERT(g_fserrno == 0);
283 	CU_ASSERT(g_file->ref_count == 0);
284 
285 	g_fserrno = 1;
286 	spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
287 	poll_threads();
288 	CU_ASSERT(g_fserrno == 0);
289 	CU_ASSERT(TAILQ_EMPTY(&fs->files));
290 
291 	g_fserrno = 1;
292 	spdk_fs_unload(fs, fs_op_complete, NULL);
293 	poll_threads();
294 	CU_ASSERT(g_fserrno == 0);
295 }
296 
297 static void
298 fs_rename(void)
299 {
300 	struct spdk_filesystem *fs;
301 	struct spdk_file *file, *file2, *file_iter;
302 	struct spdk_bs_dev *dev;
303 
304 	dev = init_dev();
305 
306 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
307 	poll_threads();
308 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
309 	CU_ASSERT(g_fserrno == 0);
310 	fs = g_fs;
311 	SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev);
312 
313 	g_fserrno = 1;
314 	spdk_fs_create_file_async(fs, "file1", create_cb, NULL);
315 	poll_threads();
316 	CU_ASSERT(g_fserrno == 0);
317 
318 	g_file = NULL;
319 	g_fserrno = 1;
320 	spdk_fs_open_file_async(fs, "file1", 0, open_cb, NULL);
321 	poll_threads();
322 	CU_ASSERT(g_fserrno == 0);
323 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
324 	CU_ASSERT(g_file->ref_count == 1);
325 
326 	file = g_file;
327 	g_file = NULL;
328 	g_fserrno = 1;
329 	spdk_file_close_async(file, fs_op_complete, NULL);
330 	poll_threads();
331 	CU_ASSERT(g_fserrno == 0);
332 	SPDK_CU_ASSERT_FATAL(file->ref_count == 0);
333 
334 	g_file = NULL;
335 	g_fserrno = 1;
336 	spdk_fs_open_file_async(fs, "file2", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
337 	poll_threads();
338 	CU_ASSERT(g_fserrno == 0);
339 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
340 	CU_ASSERT(g_file->ref_count == 1);
341 
342 	file2 = g_file;
343 	g_file = NULL;
344 	g_fserrno = 1;
345 	spdk_file_close_async(file2, fs_op_complete, NULL);
346 	poll_threads();
347 	CU_ASSERT(g_fserrno == 0);
348 	SPDK_CU_ASSERT_FATAL(file2->ref_count == 0);
349 
350 	/*
351 	 * Do a 3-way rename.  This should delete the old "file2", then rename
352 	 *  "file1" to "file2".
353 	 */
354 	g_fserrno = 1;
355 	spdk_fs_rename_file_async(fs, "file1", "file2", fs_op_complete, NULL);
356 	poll_threads();
357 	CU_ASSERT(g_fserrno == 0);
358 	CU_ASSERT(file->ref_count == 0);
359 	CU_ASSERT(!strcmp(file->name, "file2"));
360 	CU_ASSERT(TAILQ_FIRST(&fs->files) == file);
361 	CU_ASSERT(TAILQ_NEXT(file, tailq) == NULL);
362 
363 	g_fserrno = 0;
364 	spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
365 	poll_threads();
366 	CU_ASSERT(g_fserrno == -ENOENT);
367 	CU_ASSERT(!TAILQ_EMPTY(&fs->files));
368 	TAILQ_FOREACH(file_iter, &fs->files, tailq) {
369 		if (file_iter == NULL) {
370 			SPDK_CU_ASSERT_FATAL(false);
371 		}
372 	}
373 
374 	g_fserrno = 1;
375 	spdk_fs_delete_file_async(fs, "file2", delete_cb, NULL);
376 	poll_threads();
377 	CU_ASSERT(g_fserrno == 0);
378 	CU_ASSERT(TAILQ_EMPTY(&fs->files));
379 
380 	g_fserrno = 1;
381 	spdk_fs_unload(fs, fs_op_complete, NULL);
382 	poll_threads();
383 	CU_ASSERT(g_fserrno == 0);
384 }
385 
386 static void
387 fs_rw_async(void)
388 {
389 	struct spdk_filesystem *fs;
390 	struct spdk_bs_dev *dev;
391 	uint8_t w_buf[4096];
392 	uint8_t r_buf[4096];
393 
394 	dev = init_dev();
395 
396 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
397 	poll_threads();
398 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
399 	CU_ASSERT(g_fserrno == 0);
400 	fs = g_fs;
401 	SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev);
402 
403 	g_file = NULL;
404 	g_fserrno = 1;
405 	spdk_fs_open_file_async(fs, "file1", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
406 	poll_threads();
407 	CU_ASSERT(g_fserrno == 0);
408 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
409 
410 	/* Write file */
411 	CU_ASSERT(g_file->length == 0);
412 	g_fserrno = 1;
413 	memset(w_buf, 0x5a, sizeof(w_buf));
414 	spdk_file_write_async(g_file, fs->sync_target.sync_io_channel, w_buf, 0, 4096,
415 			      fs_op_complete, NULL);
416 	poll_threads();
417 	CU_ASSERT(g_fserrno == 0);
418 	CU_ASSERT(g_file->length == 4096);
419 
420 	/* Read file */
421 	g_fserrno = 1;
422 	memset(r_buf, 0x0, sizeof(r_buf));
423 	spdk_file_read_async(g_file, fs->sync_target.sync_io_channel, r_buf, 0, 4096,
424 			     fs_op_complete, NULL);
425 	poll_threads();
426 	CU_ASSERT(g_fserrno == 0);
427 	CU_ASSERT(memcmp(r_buf, w_buf, sizeof(r_buf)) == 0);
428 
429 	g_fserrno = 1;
430 	spdk_file_close_async(g_file, fs_op_complete, NULL);
431 	poll_threads();
432 	CU_ASSERT(g_fserrno == 0);
433 
434 	g_fserrno = 1;
435 	spdk_fs_unload(fs, fs_op_complete, NULL);
436 	poll_threads();
437 	CU_ASSERT(g_fserrno == 0);
438 }
439 
440 static void
441 fs_writev_readv_async(void)
442 {
443 	struct spdk_filesystem *fs;
444 	struct spdk_bs_dev *dev;
445 	struct iovec w_iov[2];
446 	struct iovec r_iov[2];
447 	uint8_t w_buf[4096];
448 	uint8_t r_buf[4096];
449 
450 	dev = init_dev();
451 
452 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
453 	poll_threads();
454 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
455 	CU_ASSERT(g_fserrno == 0);
456 	fs = g_fs;
457 	SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev);
458 
459 	g_file = NULL;
460 	g_fserrno = 1;
461 	spdk_fs_open_file_async(fs, "file1", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
462 	poll_threads();
463 	CU_ASSERT(g_fserrno == 0);
464 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
465 
466 	/* Write file */
467 	CU_ASSERT(g_file->length == 0);
468 	g_fserrno = 1;
469 	memset(w_buf, 0x5a, sizeof(w_buf));
470 	w_iov[0].iov_base = w_buf;
471 	w_iov[0].iov_len = 2048;
472 	w_iov[1].iov_base = w_buf + 2048;
473 	w_iov[1].iov_len = 2048;
474 	spdk_file_writev_async(g_file, fs->sync_target.sync_io_channel,
475 			       w_iov, 2, 0, 4096, fs_op_complete, NULL);
476 	poll_threads();
477 	CU_ASSERT(g_fserrno == 0);
478 	CU_ASSERT(g_file->length == 4096);
479 
480 	/* Read file */
481 	g_fserrno = 1;
482 	memset(r_buf, 0x0, sizeof(r_buf));
483 	r_iov[0].iov_base = r_buf;
484 	r_iov[0].iov_len = 2048;
485 	r_iov[1].iov_base = r_buf + 2048;
486 	r_iov[1].iov_len = 2048;
487 	spdk_file_readv_async(g_file, fs->sync_target.sync_io_channel,
488 			      r_iov, 2, 0, 4096, fs_op_complete, NULL);
489 	poll_threads();
490 	CU_ASSERT(g_fserrno == 0);
491 	CU_ASSERT(memcmp(r_buf, w_buf, sizeof(r_buf)) == 0);
492 
493 	/* Overwrite file with block aligned */
494 	g_fserrno = 1;
495 	memset(w_buf, 0x6a, sizeof(w_buf));
496 	w_iov[0].iov_base = w_buf;
497 	w_iov[0].iov_len = 2048;
498 	w_iov[1].iov_base = w_buf + 2048;
499 	w_iov[1].iov_len = 2048;
500 	spdk_file_writev_async(g_file, fs->sync_target.sync_io_channel,
501 			       w_iov, 2, 0, 4096, fs_op_complete, NULL);
502 	poll_threads();
503 	CU_ASSERT(g_fserrno == 0);
504 	CU_ASSERT(g_file->length == 4096);
505 
506 	/* Read file to verify the overwritten data */
507 	g_fserrno = 1;
508 	memset(r_buf, 0x0, sizeof(r_buf));
509 	r_iov[0].iov_base = r_buf;
510 	r_iov[0].iov_len = 2048;
511 	r_iov[1].iov_base = r_buf + 2048;
512 	r_iov[1].iov_len = 2048;
513 	spdk_file_readv_async(g_file, fs->sync_target.sync_io_channel,
514 			      r_iov, 2, 0, 4096, fs_op_complete, NULL);
515 	poll_threads();
516 	CU_ASSERT(g_fserrno == 0);
517 	CU_ASSERT(memcmp(r_buf, w_buf, sizeof(r_buf)) == 0);
518 
519 	g_fserrno = 1;
520 	spdk_file_close_async(g_file, fs_op_complete, NULL);
521 	poll_threads();
522 	CU_ASSERT(g_fserrno == 0);
523 
524 	g_fserrno = 1;
525 	spdk_fs_unload(fs, fs_op_complete, NULL);
526 	poll_threads();
527 	CU_ASSERT(g_fserrno == 0);
528 }
529 
530 static void
531 tree_find_buffer_ut(void)
532 {
533 	struct cache_tree *root;
534 	struct cache_tree *level1_0;
535 	struct cache_tree *level0_0_0;
536 	struct cache_tree *level0_0_12;
537 	struct cache_buffer *leaf_0_0_4;
538 	struct cache_buffer *leaf_0_12_8;
539 	struct cache_buffer *leaf_9_23_15;
540 	struct cache_buffer *buffer;
541 
542 	level1_0 = calloc(1, sizeof(struct cache_tree));
543 	SPDK_CU_ASSERT_FATAL(level1_0 != NULL);
544 	level0_0_0 = calloc(1, sizeof(struct cache_tree));
545 	SPDK_CU_ASSERT_FATAL(level0_0_0 != NULL);
546 	level0_0_12 = calloc(1, sizeof(struct cache_tree));
547 	SPDK_CU_ASSERT_FATAL(level0_0_12 != NULL);
548 	leaf_0_0_4 = calloc(1, sizeof(struct cache_buffer));
549 	SPDK_CU_ASSERT_FATAL(leaf_0_0_4 != NULL);
550 	leaf_0_12_8 = calloc(1, sizeof(struct cache_buffer));
551 	SPDK_CU_ASSERT_FATAL(leaf_0_12_8 != NULL);
552 	leaf_9_23_15 = calloc(1, sizeof(struct cache_buffer));
553 	SPDK_CU_ASSERT_FATAL(leaf_9_23_15 != NULL);
554 
555 	level1_0->level = 1;
556 	level0_0_0->level = 0;
557 	level0_0_12->level = 0;
558 
559 	leaf_0_0_4->offset = CACHE_BUFFER_SIZE * 4;
560 	level0_0_0->u.buffer[4] = leaf_0_0_4;
561 	level0_0_0->present_mask |= (1ULL << 4);
562 
563 	leaf_0_12_8->offset = CACHE_TREE_LEVEL_SIZE(1) * 12 + CACHE_BUFFER_SIZE * 8;
564 	level0_0_12->u.buffer[8] = leaf_0_12_8;
565 	level0_0_12->present_mask |= (1ULL << 8);
566 
567 	level1_0->u.tree[0] = level0_0_0;
568 	level1_0->present_mask |= (1ULL << 0);
569 	level1_0->u.tree[12] = level0_0_12;
570 	level1_0->present_mask |= (1ULL << 12);
571 
572 	buffer = spdk_tree_find_buffer(NULL, 0);
573 	CU_ASSERT(buffer == NULL);
574 
575 	buffer = spdk_tree_find_buffer(level0_0_0, 0);
576 	CU_ASSERT(buffer == NULL);
577 
578 	buffer = spdk_tree_find_buffer(level0_0_0, CACHE_TREE_LEVEL_SIZE(0) + 1);
579 	CU_ASSERT(buffer == NULL);
580 
581 	buffer = spdk_tree_find_buffer(level0_0_0, leaf_0_0_4->offset);
582 	CU_ASSERT(buffer == leaf_0_0_4);
583 
584 	buffer = spdk_tree_find_buffer(level1_0, leaf_0_0_4->offset);
585 	CU_ASSERT(buffer == leaf_0_0_4);
586 
587 	buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset);
588 	CU_ASSERT(buffer == leaf_0_12_8);
589 
590 	buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset + CACHE_BUFFER_SIZE - 1);
591 	CU_ASSERT(buffer == leaf_0_12_8);
592 
593 	buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset - 1);
594 	CU_ASSERT(buffer == NULL);
595 
596 	leaf_9_23_15->offset = CACHE_TREE_LEVEL_SIZE(2) * 9 +
597 			       CACHE_TREE_LEVEL_SIZE(1) * 23 +
598 			       CACHE_BUFFER_SIZE * 15;
599 	root = spdk_tree_insert_buffer(level1_0, leaf_9_23_15);
600 	CU_ASSERT(root != level1_0);
601 	buffer = spdk_tree_find_buffer(root, leaf_9_23_15->offset);
602 	CU_ASSERT(buffer == leaf_9_23_15);
603 	spdk_tree_free_buffers(root);
604 	free(root);
605 }
606 
607 static void
608 channel_ops(void)
609 {
610 	struct spdk_filesystem *fs;
611 	struct spdk_bs_dev *dev;
612 	struct spdk_io_channel *channel;
613 
614 	dev = init_dev();
615 
616 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
617 	poll_threads();
618 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
619 	CU_ASSERT(g_fserrno == 0);
620 	fs = g_fs;
621 	SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev);
622 
623 	channel =  spdk_fs_alloc_io_channel(fs);
624 	CU_ASSERT(channel != NULL);
625 
626 	spdk_fs_free_io_channel(channel);
627 
628 	g_fserrno = 1;
629 	spdk_fs_unload(fs, fs_op_complete, NULL);
630 	poll_threads();
631 	CU_ASSERT(g_fserrno == 0);
632 	g_fs = NULL;
633 }
634 
635 static void
636 channel_ops_sync(void)
637 {
638 	struct spdk_filesystem *fs;
639 	struct spdk_bs_dev *dev;
640 	struct spdk_fs_thread_ctx *channel;
641 
642 	dev = init_dev();
643 
644 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
645 	poll_threads();
646 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
647 	CU_ASSERT(g_fserrno == 0);
648 	fs = g_fs;
649 	SPDK_CU_ASSERT_FATAL(fs->bs->dev == dev);
650 
651 	channel =  spdk_fs_alloc_thread_ctx(fs);
652 	CU_ASSERT(channel != NULL);
653 
654 	spdk_fs_free_thread_ctx(channel);
655 
656 	g_fserrno = 1;
657 	spdk_fs_unload(fs, fs_op_complete, NULL);
658 	poll_threads();
659 	CU_ASSERT(g_fserrno == 0);
660 	g_fs = NULL;
661 }
662 
663 int main(int argc, char **argv)
664 {
665 	CU_pSuite	suite = NULL;
666 	unsigned int	num_failures;
667 
668 	if (CU_initialize_registry() != CUE_SUCCESS) {
669 		return CU_get_error();
670 	}
671 
672 	suite = CU_add_suite("blobfs_async_ut", NULL, NULL);
673 	if (suite == NULL) {
674 		CU_cleanup_registry();
675 		return CU_get_error();
676 	}
677 
678 	if (
679 		CU_add_test(suite, "fs_init", fs_init) == NULL ||
680 		CU_add_test(suite, "fs_open", fs_open) == NULL ||
681 		CU_add_test(suite, "fs_create", fs_create) == NULL ||
682 		CU_add_test(suite, "fs_truncate", fs_truncate) == NULL ||
683 		CU_add_test(suite, "fs_rename", fs_rename) == NULL ||
684 		CU_add_test(suite, "fs_rw_async", fs_rw_async) == NULL ||
685 		CU_add_test(suite, "fs_writev_readv_async", fs_writev_readv_async) == NULL ||
686 		CU_add_test(suite, "tree_find_buffer", tree_find_buffer_ut) == NULL ||
687 		CU_add_test(suite, "channel_ops", channel_ops) == NULL ||
688 		CU_add_test(suite, "channel_ops_sync", channel_ops_sync) == NULL
689 	) {
690 		CU_cleanup_registry();
691 		return CU_get_error();
692 	}
693 
694 	allocate_threads(1);
695 	set_thread(0);
696 
697 	g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
698 	CU_basic_set_mode(CU_BRM_VERBOSE);
699 	CU_basic_run_tests();
700 	num_failures = CU_get_number_of_failures();
701 	CU_cleanup_registry();
702 	free(g_dev_buffer);
703 
704 	free_threads();
705 
706 	return num_failures;
707 }
708