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