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