xref: /spdk/test/unit/lib/blobfs/blobfs_async_ut/blobfs_async_ut.c (revision 22898a91b9b6f289933db19b0175821cfb7e7820)
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/test_env.c"
39 
40 #include "spdk_cunit.h"
41 #include "blobfs/blobfs.c"
42 #include "blobfs/tree.c"
43 
44 #include "unit/lib/blob/bs_dev_common.c"
45 
46 struct spdk_filesystem *g_fs;
47 struct spdk_file *g_file;
48 int g_fserrno;
49 
50 /* Return NULL to test hardcoded defaults. */
51 struct spdk_conf_section *
52 spdk_conf_find_section(struct spdk_conf *cp, const char *name)
53 {
54 	return NULL;
55 }
56 
57 /* Return -1 to test hardcoded defaults. */
58 int
59 spdk_conf_section_get_intval(struct spdk_conf_section *sp, const char *key)
60 {
61 	return -1;
62 }
63 
64 static void
65 _fs_send_msg(spdk_thread_fn fn, void *ctx, void *thread_ctx)
66 {
67 	fn(ctx);
68 }
69 
70 static void
71 fs_op_complete(void *ctx, int fserrno)
72 {
73 	g_fserrno = fserrno;
74 }
75 
76 static void
77 fs_op_with_handle_complete(void *ctx, struct spdk_filesystem *fs, int fserrno)
78 {
79 	g_fs = fs;
80 	g_fserrno = fserrno;
81 }
82 
83 static void
84 fs_init(void)
85 {
86 	struct spdk_filesystem *fs;
87 	struct spdk_bs_dev *dev;
88 
89 	dev = init_dev();
90 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
91 
92 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
93 	CU_ASSERT(g_fs != NULL);
94 	CU_ASSERT(g_fserrno == 0);
95 	fs = g_fs;
96 
97 	g_fserrno = 1;
98 	spdk_fs_unload(fs, fs_op_complete, NULL);
99 	CU_ASSERT(g_fserrno == 0);
100 
101 	spdk_free_thread();
102 }
103 
104 static void
105 create_cb(void *ctx, int fserrno)
106 {
107 	g_fserrno = fserrno;
108 }
109 
110 static void
111 open_cb(void *ctx, struct spdk_file *f, int fserrno)
112 {
113 	g_fserrno = fserrno;
114 	g_file = f;
115 }
116 
117 static void
118 delete_cb(void *ctx, int fserrno)
119 {
120 	g_fserrno = fserrno;
121 }
122 
123 static void
124 fs_open(void)
125 {
126 	struct spdk_filesystem *fs;
127 	spdk_fs_iter iter;
128 	struct spdk_bs_dev *dev;
129 	struct spdk_file *file;
130 	char name[257] = {'\0'};
131 
132 	dev = init_dev();
133 	memset(name, 'a', sizeof(name) - 1);
134 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
135 
136 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
137 	CU_ASSERT(g_fs != NULL);
138 	CU_ASSERT(g_fserrno == 0);
139 	fs = g_fs;
140 
141 	g_fserrno = 0;
142 	/* Open should fail, because the file name is too long. */
143 	spdk_fs_open_file_async(fs, name, SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
144 	CU_ASSERT(g_fserrno == -ENAMETOOLONG);
145 
146 	g_fserrno = 0;
147 	spdk_fs_open_file_async(fs, "file1", 0, open_cb, NULL);
148 	CU_ASSERT(g_fserrno == -ENOENT);
149 
150 	g_file = NULL;
151 	g_fserrno = 1;
152 	spdk_fs_open_file_async(fs, "file1", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
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 	CU_ASSERT(g_fserrno == 0);
170 	CU_ASSERT(!TAILQ_EMPTY(&fs->files));
171 
172 	g_fserrno = 1;
173 	spdk_file_close_async(g_file, fs_op_complete, NULL);
174 	CU_ASSERT(g_fserrno == 0);
175 	CU_ASSERT(TAILQ_EMPTY(&fs->files));
176 
177 	g_fserrno = 1;
178 	spdk_fs_unload(fs, fs_op_complete, NULL);
179 	CU_ASSERT(g_fserrno == 0);
180 
181 	spdk_free_thread();
182 }
183 
184 static void
185 fs_create(void)
186 {
187 	struct spdk_filesystem *fs;
188 	struct spdk_bs_dev *dev;
189 	char name[257] = {'\0'};
190 
191 	dev = init_dev();
192 	memset(name, 'a', sizeof(name) - 1);
193 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
194 
195 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
196 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
197 	CU_ASSERT(g_fserrno == 0);
198 	fs = g_fs;
199 
200 	g_fserrno = 0;
201 	/* Create should fail, because the file name is too long. */
202 	spdk_fs_create_file_async(fs, name, create_cb, NULL);
203 	CU_ASSERT(g_fserrno == -ENAMETOOLONG);
204 
205 	g_fserrno = 1;
206 	spdk_fs_create_file_async(fs, "file1", create_cb, NULL);
207 	CU_ASSERT(g_fserrno == 0);
208 
209 	g_fserrno = 1;
210 	spdk_fs_create_file_async(fs, "file1", create_cb, NULL);
211 	CU_ASSERT(g_fserrno == -EEXIST);
212 
213 	g_fserrno = 1;
214 	spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
215 	CU_ASSERT(g_fserrno == 0);
216 	CU_ASSERT(TAILQ_EMPTY(&fs->files));
217 
218 	g_fserrno = 1;
219 	spdk_fs_unload(fs, fs_op_complete, NULL);
220 	CU_ASSERT(g_fserrno == 0);
221 
222 	spdk_free_thread();
223 }
224 
225 static void
226 fs_truncate(void)
227 {
228 	struct spdk_filesystem *fs;
229 	struct spdk_bs_dev *dev;
230 
231 	dev = init_dev();
232 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
233 
234 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
235 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
236 	CU_ASSERT(g_fserrno == 0);
237 	fs = g_fs;
238 
239 	g_file = NULL;
240 	g_fserrno = 1;
241 	spdk_fs_open_file_async(fs, "file1", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
242 	CU_ASSERT(g_fserrno == 0);
243 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
244 
245 	g_fserrno = 1;
246 	spdk_file_truncate_async(g_file, 18 * 1024 * 1024 + 1, fs_op_complete, NULL);
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 	CU_ASSERT(g_fserrno == 0);
253 	CU_ASSERT(g_file->length == 1);
254 
255 	g_fserrno = 1;
256 	spdk_file_truncate_async(g_file, 18 * 1024 * 1024 + 1, fs_op_complete, NULL);
257 	CU_ASSERT(g_fserrno == 0);
258 	CU_ASSERT(g_file->length == 18 * 1024 * 1024 + 1);
259 
260 	g_fserrno = 1;
261 	spdk_file_close_async(g_file, fs_op_complete, NULL);
262 	CU_ASSERT(g_fserrno == 0);
263 	CU_ASSERT(g_file->ref_count == 0);
264 
265 	g_fserrno = 1;
266 	spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
267 	CU_ASSERT(g_fserrno == 0);
268 	CU_ASSERT(TAILQ_EMPTY(&fs->files));
269 
270 	g_fserrno = 1;
271 	spdk_fs_unload(fs, fs_op_complete, NULL);
272 	CU_ASSERT(g_fserrno == 0);
273 
274 	spdk_free_thread();
275 }
276 
277 static void
278 fs_rename(void)
279 {
280 	struct spdk_filesystem *fs;
281 	struct spdk_file *file, *file2;
282 	struct spdk_bs_dev *dev;
283 
284 	dev = init_dev();
285 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
286 
287 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
288 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
289 	CU_ASSERT(g_fserrno == 0);
290 	fs = g_fs;
291 
292 	g_fserrno = 1;
293 	spdk_fs_create_file_async(fs, "file1", create_cb, NULL);
294 	CU_ASSERT(g_fserrno == 0);
295 
296 	g_file = NULL;
297 	g_fserrno = 1;
298 	spdk_fs_open_file_async(fs, "file1", 0, open_cb, NULL);
299 	CU_ASSERT(g_fserrno == 0);
300 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
301 	CU_ASSERT(g_file->ref_count == 1);
302 
303 	file = g_file;
304 	g_file = NULL;
305 	g_fserrno = 1;
306 	spdk_file_close_async(file, fs_op_complete, NULL);
307 	CU_ASSERT(g_fserrno == 0);
308 	SPDK_CU_ASSERT_FATAL(file->ref_count == 0);
309 
310 	g_file = NULL;
311 	g_fserrno = 1;
312 	spdk_fs_open_file_async(fs, "file2", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
313 	CU_ASSERT(g_fserrno == 0);
314 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
315 	CU_ASSERT(g_file->ref_count == 1);
316 
317 	file2 = g_file;
318 	g_file = NULL;
319 	g_fserrno = 1;
320 	spdk_file_close_async(file2, fs_op_complete, NULL);
321 	CU_ASSERT(g_fserrno == 0);
322 	SPDK_CU_ASSERT_FATAL(file2->ref_count == 0);
323 
324 	/*
325 	 * Do a 3-way rename.  This should delete the old "file2", then rename
326 	 *  "file1" to "file2".
327 	 */
328 	g_fserrno = 1;
329 	spdk_fs_rename_file_async(fs, "file1", "file2", fs_op_complete, NULL);
330 	CU_ASSERT(g_fserrno == 0);
331 	CU_ASSERT(file->ref_count == 0);
332 	CU_ASSERT(!strcmp(file->name, "file2"));
333 	CU_ASSERT(TAILQ_FIRST(&fs->files) == file);
334 	CU_ASSERT(TAILQ_NEXT(file, tailq) == NULL);
335 
336 	g_fserrno = 0;
337 	spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
338 	CU_ASSERT(g_fserrno == -ENOENT);
339 	CU_ASSERT(!TAILQ_EMPTY(&fs->files));
340 
341 	g_fserrno = 1;
342 	spdk_fs_delete_file_async(fs, "file2", delete_cb, NULL);
343 	CU_ASSERT(g_fserrno == 0);
344 	CU_ASSERT(TAILQ_EMPTY(&fs->files));
345 
346 	g_fserrno = 1;
347 	spdk_fs_unload(fs, fs_op_complete, NULL);
348 	CU_ASSERT(g_fserrno == 0);
349 
350 	spdk_free_thread();
351 }
352 
353 static void
354 tree_find_buffer_ut(void)
355 {
356 	struct cache_tree *root;
357 	struct cache_tree *level1_0;
358 	struct cache_tree *level0_0_0;
359 	struct cache_tree *level0_0_12;
360 	struct cache_buffer *leaf_0_0_4;
361 	struct cache_buffer *leaf_0_12_8;
362 	struct cache_buffer *leaf_9_23_15;
363 	struct cache_buffer *buffer;
364 
365 	level1_0 = calloc(1, sizeof(struct cache_tree));
366 	SPDK_CU_ASSERT_FATAL(level1_0 != NULL);
367 	level0_0_0 = calloc(1, sizeof(struct cache_tree));
368 	SPDK_CU_ASSERT_FATAL(level0_0_0 != NULL);
369 	level0_0_12 = calloc(1, sizeof(struct cache_tree));
370 	SPDK_CU_ASSERT_FATAL(level0_0_12 != NULL);
371 	leaf_0_0_4 = calloc(1, sizeof(struct cache_buffer));
372 	SPDK_CU_ASSERT_FATAL(leaf_0_0_4 != NULL);
373 	leaf_0_12_8 = calloc(1, sizeof(struct cache_buffer));
374 	SPDK_CU_ASSERT_FATAL(leaf_0_12_8 != NULL);
375 	leaf_9_23_15 = calloc(1, sizeof(struct cache_buffer));
376 	SPDK_CU_ASSERT_FATAL(leaf_9_23_15 != NULL);
377 
378 	level1_0->level = 1;
379 	level0_0_0->level = 0;
380 	level0_0_12->level = 0;
381 
382 	leaf_0_0_4->offset = CACHE_BUFFER_SIZE * 4;
383 	level0_0_0->u.buffer[4] = leaf_0_0_4;
384 	level0_0_0->present_mask |= (1ULL << 4);
385 
386 	leaf_0_12_8->offset = CACHE_TREE_LEVEL_SIZE(1) * 12 + CACHE_BUFFER_SIZE * 8;
387 	level0_0_12->u.buffer[8] = leaf_0_12_8;
388 	level0_0_12->present_mask |= (1ULL << 8);
389 
390 	level1_0->u.tree[0] = level0_0_0;
391 	level1_0->present_mask |= (1ULL << 0);
392 	level1_0->u.tree[12] = level0_0_12;
393 	level1_0->present_mask |= (1ULL << 12);
394 
395 	buffer = spdk_tree_find_buffer(NULL, 0);
396 	CU_ASSERT(buffer == NULL);
397 
398 	buffer = spdk_tree_find_buffer(level0_0_0, 0);
399 	CU_ASSERT(buffer == NULL);
400 
401 	buffer = spdk_tree_find_buffer(level0_0_0, CACHE_TREE_LEVEL_SIZE(0) + 1);
402 	CU_ASSERT(buffer == NULL);
403 
404 	buffer = spdk_tree_find_buffer(level0_0_0, leaf_0_0_4->offset);
405 	CU_ASSERT(buffer == leaf_0_0_4);
406 
407 	buffer = spdk_tree_find_buffer(level1_0, leaf_0_0_4->offset);
408 	CU_ASSERT(buffer == leaf_0_0_4);
409 
410 	buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset);
411 	CU_ASSERT(buffer == leaf_0_12_8);
412 
413 	buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset + CACHE_BUFFER_SIZE - 1);
414 	CU_ASSERT(buffer == leaf_0_12_8);
415 
416 	buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset - 1);
417 	CU_ASSERT(buffer == NULL);
418 
419 	leaf_9_23_15->offset = CACHE_TREE_LEVEL_SIZE(2) * 9 +
420 			       CACHE_TREE_LEVEL_SIZE(1) * 23 +
421 			       CACHE_BUFFER_SIZE * 15;
422 	root = spdk_tree_insert_buffer(level1_0, leaf_9_23_15);
423 	CU_ASSERT(root != level1_0);
424 	buffer = spdk_tree_find_buffer(root, leaf_9_23_15->offset);
425 	CU_ASSERT(buffer == leaf_9_23_15);
426 	spdk_tree_free_buffers(root);
427 	free(root);
428 }
429 
430 static void
431 channel_ops(void)
432 {
433 	struct spdk_filesystem *fs;
434 	struct spdk_bs_dev *dev;
435 	struct spdk_io_channel *channel;
436 
437 	dev = init_dev();
438 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
439 
440 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
441 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
442 	CU_ASSERT(g_fserrno == 0);
443 	fs = g_fs;
444 
445 	channel =  spdk_fs_alloc_io_channel(fs);
446 	CU_ASSERT(channel != NULL);
447 
448 	spdk_fs_free_io_channel(channel);
449 
450 	g_fserrno = 1;
451 	spdk_fs_unload(fs, fs_op_complete, NULL);
452 	CU_ASSERT(g_fserrno == 0);
453 	g_fs = NULL;
454 
455 	spdk_free_thread();
456 }
457 
458 static void
459 channel_ops_sync(void)
460 {
461 	struct spdk_filesystem *fs;
462 	struct spdk_bs_dev *dev;
463 	struct spdk_io_channel *channel;
464 
465 	dev = init_dev();
466 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
467 
468 	spdk_fs_init(dev, NULL, NULL, fs_op_with_handle_complete, NULL);
469 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
470 	CU_ASSERT(g_fserrno == 0);
471 	fs = g_fs;
472 
473 	channel =  spdk_fs_alloc_io_channel_sync(fs);
474 	CU_ASSERT(channel != NULL);
475 
476 	spdk_fs_free_io_channel(channel);
477 
478 	g_fserrno = 1;
479 	spdk_fs_unload(fs, fs_op_complete, NULL);
480 	CU_ASSERT(g_fserrno == 0);
481 	g_fs = NULL;
482 
483 	spdk_free_thread();
484 }
485 
486 int main(int argc, char **argv)
487 {
488 	CU_pSuite	suite = NULL;
489 	unsigned int	num_failures;
490 
491 	if (CU_initialize_registry() != CUE_SUCCESS) {
492 		return CU_get_error();
493 	}
494 
495 	suite = CU_add_suite("blobfs_async_ut", NULL, NULL);
496 	if (suite == NULL) {
497 		CU_cleanup_registry();
498 		return CU_get_error();
499 	}
500 
501 	if (
502 		CU_add_test(suite, "fs_init", fs_init) == NULL ||
503 		CU_add_test(suite, "fs_open", fs_open) == NULL ||
504 		CU_add_test(suite, "fs_create", fs_create) == NULL ||
505 		CU_add_test(suite, "fs_truncate", fs_truncate) == NULL ||
506 		CU_add_test(suite, "fs_rename", fs_rename) == NULL ||
507 		CU_add_test(suite, "tree_find_buffer", tree_find_buffer_ut) == NULL ||
508 		CU_add_test(suite, "channel_ops", channel_ops) == NULL ||
509 		CU_add_test(suite, "channel_ops_sync", channel_ops_sync) == NULL
510 	) {
511 		CU_cleanup_registry();
512 		return CU_get_error();
513 	}
514 
515 	g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
516 	CU_basic_set_mode(CU_BRM_VERBOSE);
517 	CU_basic_run_tests();
518 	num_failures = CU_get_number_of_failures();
519 	CU_cleanup_registry();
520 	free(g_dev_buffer);
521 	return num_failures;
522 }
523