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