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