xref: /spdk/test/unit/lib/blobfs/blobfs_sync_ut/blobfs_sync_ut.c (revision 22898a91b9b6f289933db19b0175821cfb7e7820)
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/io_channel.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 	spdk_file_truncate(g_file, channel, length);
184 
185 	spdk_file_write(g_file, channel, buf, 0, sizeof(buf));
186 
187 	CU_ASSERT(spdk_file_get_length(g_file) == length);
188 
189 	spdk_file_truncate(g_file, channel, sizeof(buf));
190 
191 	spdk_file_close(g_file, channel);
192 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
193 	CU_ASSERT(rc == 0);
194 
195 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
196 	CU_ASSERT(rc == -ENOENT);
197 
198 	spdk_fs_free_io_channel(channel);
199 	spdk_free_thread();
200 
201 	ut_send_request(_fs_unload, NULL);
202 }
203 
204 static void
205 cache_write_null_buffer(void)
206 {
207 	uint64_t length;
208 	int rc;
209 	struct spdk_io_channel *channel;
210 
211 	ut_send_request(_fs_init, NULL);
212 
213 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
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 	spdk_file_truncate(g_file, channel, length);
222 
223 	rc = spdk_file_write(g_file, channel, NULL, 0, 0);
224 	CU_ASSERT(rc == 0);
225 
226 	spdk_file_close(g_file, channel);
227 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
228 	CU_ASSERT(rc == 0);
229 
230 	spdk_fs_free_io_channel(channel);
231 	spdk_free_thread();
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 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
245 	channel = spdk_fs_alloc_io_channel_sync(g_fs);
246 	CU_ASSERT(channel != NULL);
247 
248 	rc = spdk_fs_create_file(g_fs, channel, "testfile");
249 	CU_ASSERT(rc == 0);
250 
251 	/* Create should fail, because the file already exists. */
252 	rc = spdk_fs_create_file(g_fs, channel, "testfile");
253 	CU_ASSERT(rc != 0);
254 
255 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
256 	CU_ASSERT(rc == 0);
257 
258 	spdk_fs_free_io_channel(channel);
259 	spdk_free_thread();
260 
261 	ut_send_request(_fs_unload, NULL);
262 }
263 
264 static void
265 cache_append_no_cache(void)
266 {
267 	int rc;
268 	char buf[100];
269 	struct spdk_io_channel *channel;
270 
271 	ut_send_request(_fs_init, NULL);
272 
273 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
274 	channel = spdk_fs_alloc_io_channel_sync(g_fs);
275 
276 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
277 	CU_ASSERT(rc == 0);
278 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
279 
280 	spdk_file_write(g_file, channel, buf, 0 * sizeof(buf), sizeof(buf));
281 	CU_ASSERT(spdk_file_get_length(g_file) == 1 * sizeof(buf));
282 	spdk_file_write(g_file, channel, buf, 1 * sizeof(buf), sizeof(buf));
283 	CU_ASSERT(spdk_file_get_length(g_file) == 2 * sizeof(buf));
284 	spdk_file_sync(g_file, channel);
285 	cache_free_buffers(g_file);
286 	spdk_file_write(g_file, channel, buf, 2 * sizeof(buf), sizeof(buf));
287 	CU_ASSERT(spdk_file_get_length(g_file) == 3 * sizeof(buf));
288 	spdk_file_write(g_file, channel, buf, 3 * sizeof(buf), sizeof(buf));
289 	CU_ASSERT(spdk_file_get_length(g_file) == 4 * sizeof(buf));
290 	spdk_file_write(g_file, channel, buf, 4 * sizeof(buf), sizeof(buf));
291 	CU_ASSERT(spdk_file_get_length(g_file) == 5 * sizeof(buf));
292 
293 	spdk_file_close(g_file, channel);
294 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
295 	CU_ASSERT(rc == 0);
296 
297 	spdk_fs_free_io_channel(channel);
298 	spdk_free_thread();
299 
300 	ut_send_request(_fs_unload, NULL);
301 }
302 
303 static void
304 fs_delete_file_without_close(void)
305 {
306 	int rc;
307 	struct spdk_io_channel *channel;
308 	struct spdk_file *file;
309 
310 	ut_send_request(_fs_init, NULL);
311 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
312 	channel = spdk_fs_alloc_io_channel_sync(g_fs);
313 	CU_ASSERT(channel != NULL);
314 
315 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
316 	CU_ASSERT(rc == 0);
317 
318 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
319 	CU_ASSERT(rc == 0);
320 	CU_ASSERT(g_file->ref_count != 0);
321 	CU_ASSERT(g_file->is_deleted == true);
322 
323 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file);
324 	CU_ASSERT(rc != 0);
325 
326 	spdk_file_close(g_file, channel);
327 
328 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file);
329 	CU_ASSERT(rc != 0);
330 
331 	spdk_fs_free_io_channel(channel);
332 	spdk_free_thread();
333 
334 	ut_send_request(_fs_unload, NULL);
335 
336 }
337 
338 static void
339 terminate_spdk_thread(void *arg)
340 {
341 	spdk_free_thread();
342 	pthread_exit(NULL);
343 }
344 
345 static void *
346 spdk_thread(void *arg)
347 {
348 	struct ut_request *req;
349 
350 	spdk_allocate_thread(_fs_send_msg, NULL, NULL, NULL, "thread0");
351 
352 	while (1) {
353 		pthread_mutex_lock(&g_mutex);
354 		if (g_req != NULL) {
355 			req = g_req;
356 			req->fn(req->arg);
357 			req->done = 1;
358 			if (!req->from_ut) {
359 				free(req);
360 			}
361 			g_req = NULL;
362 		}
363 		pthread_mutex_unlock(&g_mutex);
364 	}
365 
366 	return NULL;
367 }
368 
369 int main(int argc, char **argv)
370 {
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 	pthread_create(&spdk_tid, NULL, spdk_thread, NULL);
397 	g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
398 	CU_basic_set_mode(CU_BRM_VERBOSE);
399 	CU_basic_run_tests();
400 	num_failures = CU_get_number_of_failures();
401 	CU_cleanup_registry();
402 	free(g_dev_buffer);
403 	send_request(terminate_spdk_thread, NULL);
404 	pthread_join(spdk_tid, NULL);
405 	return num_failures;
406 }
407