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