xref: /spdk/test/unit/lib/blobfs/blobfs_sync_ut/blobfs_sync_ut.c (revision c4d9daeb7bf491bc0eb6e8d417b75d44773cb009)
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 "spdk/blobfs.h"
37 #include "spdk/env.h"
38 #include "spdk/log.h"
39 #include "spdk/thread.h"
40 #include "spdk/barrier.h"
41 #include "spdk_internal/thread.h"
42 
43 #include "spdk_cunit.h"
44 #include "unit/lib/blob/bs_dev_common.c"
45 #include "common/lib/test_env.c"
46 #include "blobfs/blobfs.c"
47 #include "blobfs/tree.c"
48 
49 struct spdk_filesystem *g_fs;
50 struct spdk_file *g_file;
51 int g_fserrno;
52 struct spdk_thread *g_dispatch_thread = NULL;
53 struct spdk_trace_histories *g_trace_histories;
54 DEFINE_STUB_V(spdk_trace_add_register_fn, (struct spdk_trace_register_fn *reg_fn));
55 DEFINE_STUB_V(spdk_trace_register_description, (const char *name,
56 		uint16_t tpoint_id, uint8_t owner_type,
57 		uint8_t object_type, uint8_t new_object,
58 		uint8_t arg1_is_ptr, const char *arg1_name));
59 DEFINE_STUB_V(_spdk_trace_record, (uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id,
60 				   uint32_t size, uint64_t object_id, uint64_t arg1));
61 
62 /* Return NULL to test hardcoded defaults. */
63 struct spdk_conf_section *
64 spdk_conf_find_section(struct spdk_conf *cp, const char *name)
65 {
66 	return NULL;
67 }
68 
69 /* Return -1 to test hardcoded defaults. */
70 int
71 spdk_conf_section_get_intval(struct spdk_conf_section *sp, const char *key)
72 {
73 	return -1;
74 }
75 
76 struct ut_request {
77 	fs_request_fn fn;
78 	void *arg;
79 	volatile int done;
80 };
81 
82 static void
83 send_request(fs_request_fn fn, void *arg)
84 {
85 	spdk_thread_send_msg(g_dispatch_thread, (spdk_msg_fn)fn, arg);
86 }
87 
88 static void
89 ut_call_fn(void *arg)
90 {
91 	struct ut_request *req = arg;
92 
93 	req->fn(req->arg);
94 	req->done = 1;
95 }
96 
97 static void
98 ut_send_request(fs_request_fn fn, void *arg)
99 {
100 	struct ut_request req;
101 
102 	req.fn = fn;
103 	req.arg = arg;
104 	req.done = 0;
105 
106 	spdk_thread_send_msg(g_dispatch_thread, ut_call_fn, &req);
107 
108 	/* Wait for this to finish */
109 	while (req.done == 0) {	}
110 }
111 
112 static void
113 fs_op_complete(void *ctx, int fserrno)
114 {
115 	g_fserrno = fserrno;
116 }
117 
118 static void
119 fs_op_with_handle_complete(void *ctx, struct spdk_filesystem *fs, int fserrno)
120 {
121 	g_fs = fs;
122 	g_fserrno = fserrno;
123 }
124 
125 static void
126 _fs_init(void *arg)
127 {
128 	struct spdk_thread *thread;
129 	struct spdk_bs_dev *dev;
130 
131 	g_fs = NULL;
132 	g_fserrno = -1;
133 	dev = init_dev();
134 	spdk_fs_init(dev, NULL, send_request, fs_op_with_handle_complete, NULL);
135 	thread = spdk_get_thread();
136 	while (spdk_thread_poll(thread, 0, 0) > 0) {}
137 
138 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
139 	SPDK_CU_ASSERT_FATAL(g_fs->bdev == dev);
140 	CU_ASSERT(g_fserrno == 0);
141 }
142 
143 static void
144 _fs_unload(void *arg)
145 {
146 	struct spdk_thread *thread;
147 
148 	g_fserrno = -1;
149 	spdk_fs_unload(g_fs, fs_op_complete, NULL);
150 	thread = spdk_get_thread();
151 	while (spdk_thread_poll(thread, 0, 0) > 0) {}
152 	CU_ASSERT(g_fserrno == 0);
153 	g_fs = NULL;
154 }
155 
156 static void
157 cache_write(void)
158 {
159 	uint64_t length;
160 	int rc;
161 	char buf[100];
162 	struct spdk_fs_thread_ctx *channel;
163 
164 	ut_send_request(_fs_init, NULL);
165 
166 	channel = spdk_fs_alloc_thread_ctx(g_fs);
167 
168 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
169 	CU_ASSERT(rc == 0);
170 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
171 
172 	length = (4 * 1024 * 1024);
173 	rc = spdk_file_truncate(g_file, channel, length);
174 	CU_ASSERT(rc == 0);
175 
176 	spdk_file_write(g_file, channel, buf, 0, sizeof(buf));
177 
178 	CU_ASSERT(spdk_file_get_length(g_file) == length);
179 
180 	rc = spdk_file_truncate(g_file, channel, sizeof(buf));
181 	CU_ASSERT(rc == 0);
182 
183 	spdk_file_close(g_file, channel);
184 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
185 	CU_ASSERT(rc == 0);
186 
187 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
188 	CU_ASSERT(rc == -ENOENT);
189 
190 	spdk_fs_free_thread_ctx(channel);
191 
192 	ut_send_request(_fs_unload, NULL);
193 }
194 
195 static void
196 cache_write_null_buffer(void)
197 {
198 	uint64_t length;
199 	int rc;
200 	struct spdk_fs_thread_ctx *channel;
201 	struct spdk_thread *thread;
202 
203 	ut_send_request(_fs_init, NULL);
204 
205 	channel = spdk_fs_alloc_thread_ctx(g_fs);
206 
207 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
208 	CU_ASSERT(rc == 0);
209 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
210 
211 	length = 0;
212 	rc = spdk_file_truncate(g_file, channel, length);
213 	CU_ASSERT(rc == 0);
214 
215 	rc = spdk_file_write(g_file, channel, NULL, 0, 0);
216 	CU_ASSERT(rc == 0);
217 
218 	spdk_file_close(g_file, channel);
219 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
220 	CU_ASSERT(rc == 0);
221 
222 	spdk_fs_free_thread_ctx(channel);
223 
224 	thread = spdk_get_thread();
225 	while (spdk_thread_poll(thread, 0, 0) > 0) {}
226 
227 	ut_send_request(_fs_unload, NULL);
228 }
229 
230 static void
231 fs_create_sync(void)
232 {
233 	int rc;
234 	struct spdk_fs_thread_ctx *channel;
235 	struct spdk_thread *thread;
236 
237 	ut_send_request(_fs_init, NULL);
238 
239 	channel = spdk_fs_alloc_thread_ctx(g_fs);
240 	CU_ASSERT(channel != NULL);
241 
242 	rc = spdk_fs_create_file(g_fs, channel, "testfile");
243 	CU_ASSERT(rc == 0);
244 
245 	/* Create should fail, because the file already exists. */
246 	rc = spdk_fs_create_file(g_fs, channel, "testfile");
247 	CU_ASSERT(rc != 0);
248 
249 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
250 	CU_ASSERT(rc == 0);
251 
252 	spdk_fs_free_thread_ctx(channel);
253 
254 	thread = spdk_get_thread();
255 	while (spdk_thread_poll(thread, 0, 0) > 0) {}
256 
257 	ut_send_request(_fs_unload, NULL);
258 }
259 
260 static void
261 cache_append_no_cache(void)
262 {
263 	int rc;
264 	char buf[100];
265 	struct spdk_fs_thread_ctx *channel;
266 	struct spdk_thread *thread;
267 
268 	ut_send_request(_fs_init, NULL);
269 
270 	channel = spdk_fs_alloc_thread_ctx(g_fs);
271 
272 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
273 	CU_ASSERT(rc == 0);
274 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
275 
276 	spdk_file_write(g_file, channel, buf, 0 * sizeof(buf), sizeof(buf));
277 	CU_ASSERT(spdk_file_get_length(g_file) == 1 * sizeof(buf));
278 	spdk_file_write(g_file, channel, buf, 1 * sizeof(buf), sizeof(buf));
279 	CU_ASSERT(spdk_file_get_length(g_file) == 2 * sizeof(buf));
280 	spdk_file_sync(g_file, channel);
281 	cache_free_buffers(g_file);
282 	spdk_file_write(g_file, channel, buf, 2 * sizeof(buf), sizeof(buf));
283 	CU_ASSERT(spdk_file_get_length(g_file) == 3 * sizeof(buf));
284 	spdk_file_write(g_file, channel, buf, 3 * sizeof(buf), sizeof(buf));
285 	CU_ASSERT(spdk_file_get_length(g_file) == 4 * sizeof(buf));
286 	spdk_file_write(g_file, channel, buf, 4 * sizeof(buf), sizeof(buf));
287 	CU_ASSERT(spdk_file_get_length(g_file) == 5 * sizeof(buf));
288 
289 	spdk_file_close(g_file, channel);
290 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
291 	CU_ASSERT(rc == 0);
292 
293 	spdk_fs_free_thread_ctx(channel);
294 
295 	thread = spdk_get_thread();
296 	while (spdk_thread_poll(thread, 0, 0) > 0) {}
297 
298 	ut_send_request(_fs_unload, NULL);
299 }
300 
301 static void
302 fs_delete_file_without_close(void)
303 {
304 	int rc;
305 	struct spdk_fs_thread_ctx *channel;
306 	struct spdk_file *file;
307 	struct spdk_thread *thread;
308 
309 	ut_send_request(_fs_init, NULL);
310 	channel = spdk_fs_alloc_thread_ctx(g_fs);
311 	CU_ASSERT(channel != NULL);
312 
313 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
314 	CU_ASSERT(rc == 0);
315 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
316 
317 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
318 	CU_ASSERT(rc == 0);
319 	CU_ASSERT(g_file->ref_count != 0);
320 	CU_ASSERT(g_file->is_deleted == true);
321 
322 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file);
323 	CU_ASSERT(rc != 0);
324 
325 	spdk_file_close(g_file, channel);
326 
327 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file);
328 	CU_ASSERT(rc != 0);
329 
330 	spdk_fs_free_thread_ctx(channel);
331 
332 	thread = spdk_get_thread();
333 	while (spdk_thread_poll(thread, 0, 0) > 0) {}
334 
335 	ut_send_request(_fs_unload, NULL);
336 
337 }
338 
339 static bool g_thread_exit = false;
340 
341 static void
342 terminate_spdk_thread(void *arg)
343 {
344 	g_thread_exit = true;
345 }
346 
347 static void *
348 spdk_thread(void *arg)
349 {
350 	struct spdk_thread *thread = arg;
351 
352 	spdk_set_thread(thread);
353 
354 	while (!g_thread_exit) {
355 		spdk_thread_poll(thread, 0, 0);
356 	}
357 
358 	return NULL;
359 }
360 
361 int main(int argc, char **argv)
362 {
363 	struct spdk_thread *thread;
364 	CU_pSuite	suite = NULL;
365 	pthread_t	spdk_tid;
366 	unsigned int	num_failures;
367 
368 	if (CU_initialize_registry() != CUE_SUCCESS) {
369 		return CU_get_error();
370 	}
371 
372 	suite = CU_add_suite("blobfs_sync_ut", NULL, NULL);
373 	if (suite == NULL) {
374 		CU_cleanup_registry();
375 		return CU_get_error();
376 	}
377 
378 	if (
379 		CU_add_test(suite, "write", cache_write) == NULL ||
380 		CU_add_test(suite, "write_null_buffer", cache_write_null_buffer) == NULL ||
381 		CU_add_test(suite, "create_sync", fs_create_sync) == NULL ||
382 		CU_add_test(suite, "append_no_cache", cache_append_no_cache) == NULL ||
383 		CU_add_test(suite, "delete_file_without_close", fs_delete_file_without_close) == NULL
384 	) {
385 		CU_cleanup_registry();
386 		return CU_get_error();
387 	}
388 
389 	spdk_thread_lib_init(NULL, 0);
390 
391 	thread = spdk_thread_create("test_thread", NULL);
392 	spdk_set_thread(thread);
393 
394 	g_dispatch_thread = spdk_thread_create("dispatch_thread", NULL);
395 	pthread_create(&spdk_tid, NULL, spdk_thread, g_dispatch_thread);
396 
397 	g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
398 
399 	CU_basic_set_mode(CU_BRM_VERBOSE);
400 	CU_basic_run_tests();
401 	num_failures = CU_get_number_of_failures();
402 	CU_cleanup_registry();
403 
404 	free(g_dev_buffer);
405 
406 	ut_send_request(terminate_spdk_thread, NULL);
407 	pthread_join(spdk_tid, NULL);
408 
409 	while (spdk_thread_poll(g_dispatch_thread, 0, 0) > 0) {}
410 	while (spdk_thread_poll(thread, 0, 0) > 0) {}
411 
412 	spdk_thread_exit(thread);
413 	spdk_thread_exit(g_dispatch_thread);
414 
415 	spdk_thread_lib_fini();
416 
417 	return num_failures;
418 }
419