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