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