xref: /spdk/test/unit/lib/blobfs/blobfs_sync_ut/blobfs_sync_ut.c (revision c94020001adcc0d8fae89ff7902e2e0f2243e25d)
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 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
321 
322 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
323 	CU_ASSERT(rc == 0);
324 	CU_ASSERT(g_file->ref_count != 0);
325 	CU_ASSERT(g_file->is_deleted == true);
326 
327 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file);
328 	CU_ASSERT(rc != 0);
329 
330 	spdk_file_close(g_file, channel);
331 
332 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file);
333 	CU_ASSERT(rc != 0);
334 
335 	spdk_fs_free_io_channel(channel);
336 	spdk_free_thread();
337 
338 	ut_send_request(_fs_unload, NULL);
339 
340 }
341 
342 static void
343 terminate_spdk_thread(void *arg)
344 {
345 	spdk_free_thread();
346 	pthread_exit(NULL);
347 }
348 
349 static void *
350 spdk_thread(void *arg)
351 {
352 	struct ut_request *req;
353 
354 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
355 
356 	while (1) {
357 		pthread_mutex_lock(&g_mutex);
358 		if (g_req != NULL) {
359 			req = g_req;
360 			req->fn(req->arg);
361 			req->done = 1;
362 			if (!req->from_ut) {
363 				free(req);
364 			}
365 			g_req = NULL;
366 		}
367 		pthread_mutex_unlock(&g_mutex);
368 	}
369 
370 	return NULL;
371 }
372 
373 int main(int argc, char **argv)
374 {
375 	CU_pSuite	suite = NULL;
376 	pthread_t	spdk_tid;
377 	unsigned int	num_failures;
378 
379 	if (CU_initialize_registry() != CUE_SUCCESS) {
380 		return CU_get_error();
381 	}
382 
383 	suite = CU_add_suite("blobfs_sync_ut", NULL, NULL);
384 	if (suite == NULL) {
385 		CU_cleanup_registry();
386 		return CU_get_error();
387 	}
388 
389 	if (
390 		CU_add_test(suite, "write", cache_write) == NULL ||
391 		CU_add_test(suite, "write_null_buffer", cache_write_null_buffer) == NULL ||
392 		CU_add_test(suite, "create_sync", fs_create_sync) == NULL ||
393 		CU_add_test(suite, "append_no_cache", cache_append_no_cache) == NULL ||
394 		CU_add_test(suite, "delete_file_without_close", fs_delete_file_without_close) == NULL
395 	) {
396 		CU_cleanup_registry();
397 		return CU_get_error();
398 	}
399 
400 	pthread_create(&spdk_tid, NULL, spdk_thread, NULL);
401 	g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
402 	CU_basic_set_mode(CU_BRM_VERBOSE);
403 	CU_basic_run_tests();
404 	num_failures = CU_get_number_of_failures();
405 	CU_cleanup_registry();
406 	free(g_dev_buffer);
407 	send_request(terminate_spdk_thread, NULL);
408 	pthread_join(spdk_tid, NULL);
409 	return num_failures;
410 }
411