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