xref: /spdk/test/unit/lib/blobfs/blobfs_sync_ut/blobfs_sync_ut.c (revision ea941caeaf896fdf2aef7685f86f37023060faed)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2017 Intel Corporation.
312e840b9SSeth Howell  *   All rights reserved.
412e840b9SSeth Howell  */
512e840b9SSeth Howell 
612e840b9SSeth Howell #include "spdk/stdinc.h"
712e840b9SSeth Howell 
812e840b9SSeth Howell #include "spdk/blobfs.h"
912e840b9SSeth Howell #include "spdk/env.h"
1012e840b9SSeth Howell #include "spdk/log.h"
1112e840b9SSeth Howell #include "spdk/barrier.h"
125fc0475cSJiewei Ke #include "thread/thread_internal.h"
1312e840b9SSeth Howell 
14ae431e31SKonrad Sztyber #include "spdk_internal/cunit.h"
1512e840b9SSeth Howell #include "unit/lib/blob/bs_dev_common.c"
16c9fb57a2SSeth Howell #include "common/lib/test_env.c"
1712e840b9SSeth Howell #include "blobfs/blobfs.c"
1812e840b9SSeth Howell #include "blobfs/tree.c"
1912e840b9SSeth Howell 
2012e840b9SSeth Howell struct spdk_filesystem *g_fs;
2112e840b9SSeth Howell struct spdk_file *g_file;
2212e840b9SSeth Howell int g_fserrno;
23088c5e04SBen Walker struct spdk_thread *g_dispatch_thread = NULL;
2412e840b9SSeth Howell 
2512e840b9SSeth Howell struct ut_request {
2612e840b9SSeth Howell 	fs_request_fn fn;
2712e840b9SSeth Howell 	void *arg;
2812e840b9SSeth Howell 	volatile int done;
2912e840b9SSeth Howell };
3012e840b9SSeth Howell 
31ba8f1a9eSAlexey Marchuk DEFINE_STUB(spdk_memory_domain_memzero, int, (struct spdk_memory_domain *src_domain,
32ba8f1a9eSAlexey Marchuk 		void *src_domain_ctx, struct iovec *iov, uint32_t iovcnt, void (*cpl_cb)(void *, int),
33ba8f1a9eSAlexey Marchuk 		void *cpl_cb_arg), 0);
34475b86aaSKonrad Sztyber DEFINE_STUB(spdk_mempool_lookup, struct spdk_mempool *, (const char *name), NULL);
35ba8f1a9eSAlexey Marchuk 
3612e840b9SSeth Howell static void
send_request(fs_request_fn fn,void * arg)3712e840b9SSeth Howell send_request(fs_request_fn fn, void *arg)
3812e840b9SSeth Howell {
39088c5e04SBen Walker 	spdk_thread_send_msg(g_dispatch_thread, (spdk_msg_fn)fn, arg);
40088c5e04SBen Walker }
4112e840b9SSeth Howell 
42088c5e04SBen Walker static void
ut_call_fn(void * arg)43088c5e04SBen Walker ut_call_fn(void *arg)
44088c5e04SBen Walker {
45088c5e04SBen Walker 	struct ut_request *req = arg;
4612e840b9SSeth Howell 
47088c5e04SBen Walker 	req->fn(req->arg);
48088c5e04SBen Walker 	req->done = 1;
4912e840b9SSeth Howell }
5012e840b9SSeth Howell 
5112e840b9SSeth Howell static void
ut_send_request(fs_request_fn fn,void * arg)5212e840b9SSeth Howell ut_send_request(fs_request_fn fn, void *arg)
5312e840b9SSeth Howell {
5412e840b9SSeth Howell 	struct ut_request req;
5512e840b9SSeth Howell 
5612e840b9SSeth Howell 	req.fn = fn;
5712e840b9SSeth Howell 	req.arg = arg;
5812e840b9SSeth Howell 	req.done = 0;
5912e840b9SSeth Howell 
60088c5e04SBen Walker 	spdk_thread_send_msg(g_dispatch_thread, ut_call_fn, &req);
6112e840b9SSeth Howell 
62088c5e04SBen Walker 	/* Wait for this to finish */
63088c5e04SBen Walker 	while (req.done == 0) {	}
6412e840b9SSeth Howell }
6512e840b9SSeth Howell 
6612e840b9SSeth Howell static void
fs_op_complete(void * ctx,int fserrno)6712e840b9SSeth Howell fs_op_complete(void *ctx, int fserrno)
6812e840b9SSeth Howell {
6912e840b9SSeth Howell 	g_fserrno = fserrno;
7012e840b9SSeth Howell }
7112e840b9SSeth Howell 
7212e840b9SSeth Howell static void
fs_op_with_handle_complete(void * ctx,struct spdk_filesystem * fs,int fserrno)7312e840b9SSeth Howell fs_op_with_handle_complete(void *ctx, struct spdk_filesystem *fs, int fserrno)
7412e840b9SSeth Howell {
7512e840b9SSeth Howell 	g_fs = fs;
7612e840b9SSeth Howell 	g_fserrno = fserrno;
7712e840b9SSeth Howell }
7812e840b9SSeth Howell 
7912e840b9SSeth Howell static void
fs_thread_poll(void)80c41c4c2bSChangpeng Liu fs_thread_poll(void)
8112e840b9SSeth Howell {
8211654a60SBen Walker 	struct spdk_thread *thread;
83c41c4c2bSChangpeng Liu 
84c41c4c2bSChangpeng Liu 	thread = spdk_get_thread();
85c41c4c2bSChangpeng Liu 	while (spdk_thread_poll(thread, 0, 0) > 0) {}
86c41c4c2bSChangpeng Liu 	while (spdk_thread_poll(g_cache_pool_thread, 0, 0) > 0) {}
87c41c4c2bSChangpeng Liu }
88c41c4c2bSChangpeng Liu 
89c41c4c2bSChangpeng Liu static void
_fs_init(void * arg)90c41c4c2bSChangpeng Liu _fs_init(void *arg)
91c41c4c2bSChangpeng Liu {
9212e840b9SSeth Howell 	struct spdk_bs_dev *dev;
9312e840b9SSeth Howell 
9412e840b9SSeth Howell 	g_fs = NULL;
9512e840b9SSeth Howell 	g_fserrno = -1;
9612e840b9SSeth Howell 	dev = init_dev();
9712e840b9SSeth Howell 	spdk_fs_init(dev, NULL, send_request, fs_op_with_handle_complete, NULL);
98c41c4c2bSChangpeng Liu 
99c41c4c2bSChangpeng Liu 	fs_thread_poll();
10011654a60SBen Walker 
10112e840b9SSeth Howell 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
10211654a60SBen Walker 	SPDK_CU_ASSERT_FATAL(g_fs->bdev == dev);
10312e840b9SSeth Howell 	CU_ASSERT(g_fserrno == 0);
10412e840b9SSeth Howell }
10512e840b9SSeth Howell 
10612e840b9SSeth Howell static void
_fs_load(void * arg)107e967dcd2SJim Harris _fs_load(void *arg)
108e967dcd2SJim Harris {
109e967dcd2SJim Harris 	struct spdk_bs_dev *dev;
110e967dcd2SJim Harris 
111e967dcd2SJim Harris 	g_fs = NULL;
112e967dcd2SJim Harris 	g_fserrno = -1;
113e967dcd2SJim Harris 	dev = init_dev();
114e967dcd2SJim Harris 	spdk_fs_load(dev, send_request, fs_op_with_handle_complete, NULL);
115c41c4c2bSChangpeng Liu 
116c41c4c2bSChangpeng Liu 	fs_thread_poll();
117e967dcd2SJim Harris 
118e967dcd2SJim Harris 	SPDK_CU_ASSERT_FATAL(g_fs != NULL);
119e967dcd2SJim Harris 	SPDK_CU_ASSERT_FATAL(g_fs->bdev == dev);
120e967dcd2SJim Harris 	CU_ASSERT(g_fserrno == 0);
121e967dcd2SJim Harris }
122e967dcd2SJim Harris 
123e967dcd2SJim Harris static void
_fs_unload(void * arg)12412e840b9SSeth Howell _fs_unload(void *arg)
12512e840b9SSeth Howell {
12612e840b9SSeth Howell 	g_fserrno = -1;
12712e840b9SSeth Howell 	spdk_fs_unload(g_fs, fs_op_complete, NULL);
128c41c4c2bSChangpeng Liu 
129c41c4c2bSChangpeng Liu 	fs_thread_poll();
130c41c4c2bSChangpeng Liu 
13112e840b9SSeth Howell 	CU_ASSERT(g_fserrno == 0);
13212e840b9SSeth Howell 	g_fs = NULL;
13312e840b9SSeth Howell }
13412e840b9SSeth Howell 
13512e840b9SSeth Howell static void
_nop(void * arg)136cdd089a8SJim Harris _nop(void *arg)
137cdd089a8SJim Harris {
138cdd089a8SJim Harris }
139cdd089a8SJim Harris 
140cdd089a8SJim Harris static void
cache_read_after_write(void)1416ff6a270SChangpeng Liu cache_read_after_write(void)
14212e840b9SSeth Howell {
14312e840b9SSeth Howell 	uint64_t length;
14412e840b9SSeth Howell 	int rc;
1456ff6a270SChangpeng Liu 	char w_buf[100], r_buf[100];
146e9d400d5SBen Walker 	struct spdk_fs_thread_ctx *channel;
1476ff6a270SChangpeng Liu 	struct spdk_file_stat stat = {0};
14812e840b9SSeth Howell 
14912e840b9SSeth Howell 	ut_send_request(_fs_init, NULL);
15012e840b9SSeth Howell 
151e9d400d5SBen Walker 	channel = spdk_fs_alloc_thread_ctx(g_fs);
15212e840b9SSeth Howell 
15312e840b9SSeth Howell 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
15412e840b9SSeth Howell 	CU_ASSERT(rc == 0);
15512e840b9SSeth Howell 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
15612e840b9SSeth Howell 
15712e840b9SSeth Howell 	length = (4 * 1024 * 1024);
158703d1f80SZiye Yang 	rc = spdk_file_truncate(g_file, channel, length);
159703d1f80SZiye Yang 	CU_ASSERT(rc == 0);
16012e840b9SSeth Howell 
1616ff6a270SChangpeng Liu 	memset(w_buf, 0x5a, sizeof(w_buf));
1626ff6a270SChangpeng Liu 	spdk_file_write(g_file, channel, w_buf, 0, sizeof(w_buf));
16312e840b9SSeth Howell 
16412e840b9SSeth Howell 	CU_ASSERT(spdk_file_get_length(g_file) == length);
16512e840b9SSeth Howell 
1666ff6a270SChangpeng Liu 	rc = spdk_file_truncate(g_file, channel, sizeof(w_buf));
167703d1f80SZiye Yang 	CU_ASSERT(rc == 0);
16812e840b9SSeth Howell 
16912e840b9SSeth Howell 	spdk_file_close(g_file, channel);
1706ff6a270SChangpeng Liu 
171c41c4c2bSChangpeng Liu 	fs_thread_poll();
172c41c4c2bSChangpeng Liu 
1736ff6a270SChangpeng Liu 	rc = spdk_fs_file_stat(g_fs, channel, "testfile", &stat);
1746ff6a270SChangpeng Liu 	CU_ASSERT(rc == 0);
1756ff6a270SChangpeng Liu 	CU_ASSERT(sizeof(w_buf) == stat.size);
1766ff6a270SChangpeng Liu 
1776ff6a270SChangpeng Liu 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &g_file);
1786ff6a270SChangpeng Liu 	CU_ASSERT(rc == 0);
1796ff6a270SChangpeng Liu 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
1806ff6a270SChangpeng Liu 
1816ff6a270SChangpeng Liu 	memset(r_buf, 0, sizeof(r_buf));
1826ff6a270SChangpeng Liu 	spdk_file_read(g_file, channel, r_buf, 0, sizeof(r_buf));
1836ff6a270SChangpeng Liu 	CU_ASSERT(memcmp(w_buf, r_buf, sizeof(r_buf)) == 0);
1846ff6a270SChangpeng Liu 
1856ff6a270SChangpeng Liu 	spdk_file_close(g_file, channel);
186c41c4c2bSChangpeng Liu 
187c41c4c2bSChangpeng Liu 	fs_thread_poll();
188c41c4c2bSChangpeng Liu 
18912e840b9SSeth Howell 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
19012e840b9SSeth Howell 	CU_ASSERT(rc == 0);
19112e840b9SSeth Howell 
19212e840b9SSeth Howell 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
19312e840b9SSeth Howell 	CU_ASSERT(rc == -ENOENT);
19412e840b9SSeth Howell 
195e9d400d5SBen Walker 	spdk_fs_free_thread_ctx(channel);
19612e840b9SSeth Howell 
19712e840b9SSeth Howell 	ut_send_request(_fs_unload, NULL);
19812e840b9SSeth Howell }
19912e840b9SSeth Howell 
20012e840b9SSeth Howell static void
file_length(void)201e967dcd2SJim Harris file_length(void)
202e967dcd2SJim Harris {
203e967dcd2SJim Harris 	int rc;
204e967dcd2SJim Harris 	char *buf;
205e967dcd2SJim Harris 	uint64_t buf_length;
2069c48768aSZiye Yang 	volatile uint64_t *length_flushed;
207e967dcd2SJim Harris 	struct spdk_fs_thread_ctx *channel;
208e967dcd2SJim Harris 	struct spdk_file_stat stat = {0};
209e967dcd2SJim Harris 
210e967dcd2SJim Harris 	ut_send_request(_fs_init, NULL);
211e967dcd2SJim Harris 
212e967dcd2SJim Harris 	channel = spdk_fs_alloc_thread_ctx(g_fs);
213e967dcd2SJim Harris 
214e967dcd2SJim Harris 	g_file = NULL;
215e967dcd2SJim Harris 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
216e967dcd2SJim Harris 	CU_ASSERT(rc == 0);
217e967dcd2SJim Harris 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
218e967dcd2SJim Harris 
219cdd089a8SJim Harris 	/* Write one CACHE_BUFFER.  Filling at least one cache buffer triggers
220cdd089a8SJim Harris 	 * a flush to disk.
221e967dcd2SJim Harris 	 */
222cdd089a8SJim Harris 	buf_length = CACHE_BUFFER_SIZE;
223e967dcd2SJim Harris 	buf = calloc(1, buf_length);
224e967dcd2SJim Harris 	spdk_file_write(g_file, channel, buf, 0, buf_length);
225e967dcd2SJim Harris 	free(buf);
226e967dcd2SJim Harris 
227e967dcd2SJim Harris 	/* Spin until all of the data has been flushed to the SSD.  There's been no
228e967dcd2SJim Harris 	 * sync operation yet, so the xattr on the file is still 0.
2299c48768aSZiye Yang 	 *
2309c48768aSZiye Yang 	 * length_flushed: This variable is modified by a different thread in this unit
2319c48768aSZiye Yang 	 * test. So we need to dereference it as a volatile to ensure the value is always
2329c48768aSZiye Yang 	 * re-read.
233e967dcd2SJim Harris 	 */
2349c48768aSZiye Yang 	length_flushed = &g_file->length_flushed;
2359c48768aSZiye Yang 	while (*length_flushed != buf_length) {}
236e967dcd2SJim Harris 
237e967dcd2SJim Harris 	/* Close the file.  This causes an implicit sync which should write the
238e967dcd2SJim Harris 	 * length_flushed value as the "length" xattr on the file.
239e967dcd2SJim Harris 	 */
240e967dcd2SJim Harris 	spdk_file_close(g_file, channel);
241e967dcd2SJim Harris 
242c41c4c2bSChangpeng Liu 	fs_thread_poll();
243c41c4c2bSChangpeng Liu 
244e967dcd2SJim Harris 	rc = spdk_fs_file_stat(g_fs, channel, "testfile", &stat);
245e967dcd2SJim Harris 	CU_ASSERT(rc == 0);
246e967dcd2SJim Harris 	CU_ASSERT(buf_length == stat.size);
247e967dcd2SJim Harris 
248e967dcd2SJim Harris 	spdk_fs_free_thread_ctx(channel);
249e967dcd2SJim Harris 
250e967dcd2SJim Harris 	/* Unload and reload the filesystem.  The file length will be
251e967dcd2SJim Harris 	 * read during load from the length xattr.  We want to make sure
252e967dcd2SJim Harris 	 * it matches what was written when the file was originally
253e967dcd2SJim Harris 	 * written and closed.
254e967dcd2SJim Harris 	 */
255e967dcd2SJim Harris 	ut_send_request(_fs_unload, NULL);
256e967dcd2SJim Harris 
257e967dcd2SJim Harris 	ut_send_request(_fs_load, NULL);
258e967dcd2SJim Harris 
259e967dcd2SJim Harris 	channel = spdk_fs_alloc_thread_ctx(g_fs);
260e967dcd2SJim Harris 
261e967dcd2SJim Harris 	rc = spdk_fs_file_stat(g_fs, channel, "testfile", &stat);
262e967dcd2SJim Harris 	CU_ASSERT(rc == 0);
263e967dcd2SJim Harris 	CU_ASSERT(buf_length == stat.size);
264e967dcd2SJim Harris 
265e967dcd2SJim Harris 	g_file = NULL;
266e967dcd2SJim Harris 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &g_file);
267e967dcd2SJim Harris 	CU_ASSERT(rc == 0);
268e967dcd2SJim Harris 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
269e967dcd2SJim Harris 
270e967dcd2SJim Harris 	spdk_file_close(g_file, channel);
271e967dcd2SJim Harris 
272c41c4c2bSChangpeng Liu 	fs_thread_poll();
273c41c4c2bSChangpeng Liu 
274e967dcd2SJim Harris 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
275e967dcd2SJim Harris 	CU_ASSERT(rc == 0);
276e967dcd2SJim Harris 
277e967dcd2SJim Harris 	spdk_fs_free_thread_ctx(channel);
278e967dcd2SJim Harris 
279e967dcd2SJim Harris 	ut_send_request(_fs_unload, NULL);
280e967dcd2SJim Harris }
281e967dcd2SJim Harris 
282e967dcd2SJim Harris static void
append_write_to_extend_blob(void)283678c0261SChangpeng Liu append_write_to_extend_blob(void)
284678c0261SChangpeng Liu {
285678c0261SChangpeng Liu 	uint64_t blob_size, buf_length;
286678c0261SChangpeng Liu 	char *buf, append_buf[64];
287678c0261SChangpeng Liu 	int rc;
288678c0261SChangpeng Liu 	struct spdk_fs_thread_ctx *channel;
289678c0261SChangpeng Liu 
290678c0261SChangpeng Liu 	ut_send_request(_fs_init, NULL);
291678c0261SChangpeng Liu 
292678c0261SChangpeng Liu 	channel = spdk_fs_alloc_thread_ctx(g_fs);
293678c0261SChangpeng Liu 
294678c0261SChangpeng Liu 	/* create a file and write the file with blob_size - 1 data length */
295678c0261SChangpeng Liu 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
296678c0261SChangpeng Liu 	CU_ASSERT(rc == 0);
297678c0261SChangpeng Liu 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
298678c0261SChangpeng Liu 
299678c0261SChangpeng Liu 	blob_size = __file_get_blob_size(g_file);
300678c0261SChangpeng Liu 
301678c0261SChangpeng Liu 	buf_length = blob_size - 1;
302678c0261SChangpeng Liu 	buf = calloc(1, buf_length);
303678c0261SChangpeng Liu 	rc = spdk_file_write(g_file, channel, buf, 0, buf_length);
304678c0261SChangpeng Liu 	CU_ASSERT(rc == 0);
305678c0261SChangpeng Liu 	free(buf);
306678c0261SChangpeng Liu 
307678c0261SChangpeng Liu 	spdk_file_close(g_file, channel);
308c41c4c2bSChangpeng Liu 	fs_thread_poll();
309678c0261SChangpeng Liu 	spdk_fs_free_thread_ctx(channel);
310678c0261SChangpeng Liu 	ut_send_request(_fs_unload, NULL);
311678c0261SChangpeng Liu 
312678c0261SChangpeng Liu 	/* load existing file and write extra 2 bytes to cross blob boundary */
313678c0261SChangpeng Liu 	ut_send_request(_fs_load, NULL);
314678c0261SChangpeng Liu 
315678c0261SChangpeng Liu 	channel = spdk_fs_alloc_thread_ctx(g_fs);
316678c0261SChangpeng Liu 	g_file = NULL;
317678c0261SChangpeng Liu 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &g_file);
318678c0261SChangpeng Liu 	CU_ASSERT(rc == 0);
319678c0261SChangpeng Liu 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
320678c0261SChangpeng Liu 
321678c0261SChangpeng Liu 	CU_ASSERT(g_file->length == buf_length);
322678c0261SChangpeng Liu 	CU_ASSERT(g_file->last == NULL);
323678c0261SChangpeng Liu 	CU_ASSERT(g_file->append_pos == buf_length);
324678c0261SChangpeng Liu 
325678c0261SChangpeng Liu 	rc = spdk_file_write(g_file, channel, append_buf, buf_length, 2);
326678c0261SChangpeng Liu 	CU_ASSERT(rc == 0);
327678c0261SChangpeng Liu 	CU_ASSERT(2 * blob_size == __file_get_blob_size(g_file));
328678c0261SChangpeng Liu 	spdk_file_close(g_file, channel);
329c41c4c2bSChangpeng Liu 	fs_thread_poll();
330678c0261SChangpeng Liu 	CU_ASSERT(g_file->length == buf_length + 2);
331678c0261SChangpeng Liu 
332678c0261SChangpeng Liu 	spdk_fs_free_thread_ctx(channel);
333678c0261SChangpeng Liu 	ut_send_request(_fs_unload, NULL);
334678c0261SChangpeng Liu }
335678c0261SChangpeng Liu 
336678c0261SChangpeng Liu static void
partial_buffer(void)337cdd089a8SJim Harris partial_buffer(void)
338cdd089a8SJim Harris {
339cdd089a8SJim Harris 	int rc;
340cdd089a8SJim Harris 	char *buf;
341cdd089a8SJim Harris 	uint64_t buf_length;
342cdd089a8SJim Harris 	struct spdk_fs_thread_ctx *channel;
343cdd089a8SJim Harris 	struct spdk_file_stat stat = {0};
344cdd089a8SJim Harris 
345cdd089a8SJim Harris 	ut_send_request(_fs_init, NULL);
346cdd089a8SJim Harris 
347cdd089a8SJim Harris 	channel = spdk_fs_alloc_thread_ctx(g_fs);
348cdd089a8SJim Harris 
349cdd089a8SJim Harris 	g_file = NULL;
350cdd089a8SJim Harris 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
351cdd089a8SJim Harris 	CU_ASSERT(rc == 0);
352cdd089a8SJim Harris 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
353cdd089a8SJim Harris 
354cdd089a8SJim Harris 	/* Write one CACHE_BUFFER plus one byte.  Filling at least one cache buffer triggers
355cdd089a8SJim Harris 	 * a flush to disk.  We want to make sure the extra byte is not implicitly flushed.
356cdd089a8SJim Harris 	 * It should only get flushed once we sync or close the file.
357cdd089a8SJim Harris 	 */
358cdd089a8SJim Harris 	buf_length = CACHE_BUFFER_SIZE + 1;
359cdd089a8SJim Harris 	buf = calloc(1, buf_length);
360cdd089a8SJim Harris 	spdk_file_write(g_file, channel, buf, 0, buf_length);
361cdd089a8SJim Harris 	free(buf);
362cdd089a8SJim Harris 
363cdd089a8SJim Harris 	/* Send some nop messages to the dispatch thread.  This will ensure any of the
364cdd089a8SJim Harris 	 * pending write operations are completed.  A well-functioning blobfs should only
365cdd089a8SJim Harris 	 * issue one write for the filled CACHE_BUFFER - a buggy one might try to write
366cdd089a8SJim Harris 	 * the extra byte.  So do a bunch of _nops to make sure all of them (even the buggy
367cdd089a8SJim Harris 	 * ones) get a chance to run.  Note that we can't just send a message to the
368cdd089a8SJim Harris 	 * dispatch thread to call spdk_thread_poll() because the messages are themselves
369cdd089a8SJim Harris 	 * run in the context of spdk_thread_poll().
370cdd089a8SJim Harris 	 */
371cdd089a8SJim Harris 	ut_send_request(_nop, NULL);
372cdd089a8SJim Harris 	ut_send_request(_nop, NULL);
373cdd089a8SJim Harris 	ut_send_request(_nop, NULL);
374cdd089a8SJim Harris 	ut_send_request(_nop, NULL);
375cdd089a8SJim Harris 	ut_send_request(_nop, NULL);
376cdd089a8SJim Harris 	ut_send_request(_nop, NULL);
377cdd089a8SJim Harris 
378cdd089a8SJim Harris 	CU_ASSERT(g_file->length_flushed == CACHE_BUFFER_SIZE);
379cdd089a8SJim Harris 
380cdd089a8SJim Harris 	/* Close the file.  This causes an implicit sync which should write the
381cdd089a8SJim Harris 	 * length_flushed value as the "length" xattr on the file.
382cdd089a8SJim Harris 	 */
383cdd089a8SJim Harris 	spdk_file_close(g_file, channel);
384cdd089a8SJim Harris 
385c41c4c2bSChangpeng Liu 	fs_thread_poll();
386c41c4c2bSChangpeng Liu 
387cdd089a8SJim Harris 	rc = spdk_fs_file_stat(g_fs, channel, "testfile", &stat);
388cdd089a8SJim Harris 	CU_ASSERT(rc == 0);
389cdd089a8SJim Harris 	CU_ASSERT(buf_length == stat.size);
390cdd089a8SJim Harris 
391cdd089a8SJim Harris 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
392cdd089a8SJim Harris 	CU_ASSERT(rc == 0);
393cdd089a8SJim Harris 
394cdd089a8SJim Harris 	spdk_fs_free_thread_ctx(channel);
395cdd089a8SJim Harris 
396cdd089a8SJim Harris 	ut_send_request(_fs_unload, NULL);
397cdd089a8SJim Harris }
398cdd089a8SJim Harris 
399cdd089a8SJim Harris static void
cache_write_null_buffer(void)40012e840b9SSeth Howell cache_write_null_buffer(void)
40112e840b9SSeth Howell {
40212e840b9SSeth Howell 	uint64_t length;
40312e840b9SSeth Howell 	int rc;
404e9d400d5SBen Walker 	struct spdk_fs_thread_ctx *channel;
40511654a60SBen Walker 	struct spdk_thread *thread;
40612e840b9SSeth Howell 
40712e840b9SSeth Howell 	ut_send_request(_fs_init, NULL);
40812e840b9SSeth Howell 
409e9d400d5SBen Walker 	channel = spdk_fs_alloc_thread_ctx(g_fs);
41012e840b9SSeth Howell 
41112e840b9SSeth Howell 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
41212e840b9SSeth Howell 	CU_ASSERT(rc == 0);
41312e840b9SSeth Howell 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
41412e840b9SSeth Howell 
41512e840b9SSeth Howell 	length = 0;
416703d1f80SZiye Yang 	rc = spdk_file_truncate(g_file, channel, length);
417703d1f80SZiye Yang 	CU_ASSERT(rc == 0);
41812e840b9SSeth Howell 
41912e840b9SSeth Howell 	rc = spdk_file_write(g_file, channel, NULL, 0, 0);
42012e840b9SSeth Howell 	CU_ASSERT(rc == 0);
42112e840b9SSeth Howell 
42212e840b9SSeth Howell 	spdk_file_close(g_file, channel);
423c41c4c2bSChangpeng Liu 
424c41c4c2bSChangpeng Liu 	fs_thread_poll();
425c41c4c2bSChangpeng Liu 
42612e840b9SSeth Howell 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
42712e840b9SSeth Howell 	CU_ASSERT(rc == 0);
42812e840b9SSeth Howell 
429e9d400d5SBen Walker 	spdk_fs_free_thread_ctx(channel);
43012e840b9SSeth Howell 
43111654a60SBen Walker 	thread = spdk_get_thread();
4328abfb06eSBen Walker 	while (spdk_thread_poll(thread, 0, 0) > 0) {}
43311654a60SBen Walker 
43412e840b9SSeth Howell 	ut_send_request(_fs_unload, NULL);
43512e840b9SSeth Howell }
43612e840b9SSeth Howell 
43712e840b9SSeth Howell static void
fs_create_sync(void)43812e840b9SSeth Howell fs_create_sync(void)
43912e840b9SSeth Howell {
44012e840b9SSeth Howell 	int rc;
441e9d400d5SBen Walker 	struct spdk_fs_thread_ctx *channel;
44212e840b9SSeth Howell 
44312e840b9SSeth Howell 	ut_send_request(_fs_init, NULL);
44412e840b9SSeth Howell 
445e9d400d5SBen Walker 	channel = spdk_fs_alloc_thread_ctx(g_fs);
44612e840b9SSeth Howell 	CU_ASSERT(channel != NULL);
44712e840b9SSeth Howell 
44812e840b9SSeth Howell 	rc = spdk_fs_create_file(g_fs, channel, "testfile");
44912e840b9SSeth Howell 	CU_ASSERT(rc == 0);
45012e840b9SSeth Howell 
45112e840b9SSeth Howell 	/* Create should fail, because the file already exists. */
45212e840b9SSeth Howell 	rc = spdk_fs_create_file(g_fs, channel, "testfile");
45312e840b9SSeth Howell 	CU_ASSERT(rc != 0);
45412e840b9SSeth Howell 
45512e840b9SSeth Howell 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
45612e840b9SSeth Howell 	CU_ASSERT(rc == 0);
45712e840b9SSeth Howell 
458e9d400d5SBen Walker 	spdk_fs_free_thread_ctx(channel);
45912e840b9SSeth Howell 
460c41c4c2bSChangpeng Liu 	fs_thread_poll();
46111654a60SBen Walker 
46212e840b9SSeth Howell 	ut_send_request(_fs_unload, NULL);
46312e840b9SSeth Howell }
46412e840b9SSeth Howell 
46512e840b9SSeth Howell static void
fs_rename_sync(void)46698ef63aaSChangpeng Liu fs_rename_sync(void)
46798ef63aaSChangpeng Liu {
46898ef63aaSChangpeng Liu 	int rc;
46998ef63aaSChangpeng Liu 	struct spdk_fs_thread_ctx *channel;
47098ef63aaSChangpeng Liu 
47198ef63aaSChangpeng Liu 	ut_send_request(_fs_init, NULL);
47298ef63aaSChangpeng Liu 
47398ef63aaSChangpeng Liu 	channel = spdk_fs_alloc_thread_ctx(g_fs);
47498ef63aaSChangpeng Liu 	CU_ASSERT(channel != NULL);
47598ef63aaSChangpeng Liu 
47698ef63aaSChangpeng Liu 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
47798ef63aaSChangpeng Liu 	CU_ASSERT(rc == 0);
47898ef63aaSChangpeng Liu 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
47998ef63aaSChangpeng Liu 
48098ef63aaSChangpeng Liu 	CU_ASSERT(strcmp(spdk_file_get_name(g_file), "testfile") == 0);
48198ef63aaSChangpeng Liu 
48298ef63aaSChangpeng Liu 	rc = spdk_fs_rename_file(g_fs, channel, "testfile", "newtestfile");
48398ef63aaSChangpeng Liu 	CU_ASSERT(rc == 0);
48498ef63aaSChangpeng Liu 	CU_ASSERT(strcmp(spdk_file_get_name(g_file), "newtestfile") == 0);
48598ef63aaSChangpeng Liu 
48698ef63aaSChangpeng Liu 	spdk_file_close(g_file, channel);
48798ef63aaSChangpeng Liu 
488c41c4c2bSChangpeng Liu 	fs_thread_poll();
489c41c4c2bSChangpeng Liu 
490c41c4c2bSChangpeng Liu 	spdk_fs_free_thread_ctx(channel);
49198ef63aaSChangpeng Liu 
49298ef63aaSChangpeng Liu 	ut_send_request(_fs_unload, NULL);
49398ef63aaSChangpeng Liu }
49498ef63aaSChangpeng Liu 
49598ef63aaSChangpeng Liu static void
cache_append_no_cache(void)49612e840b9SSeth Howell cache_append_no_cache(void)
49712e840b9SSeth Howell {
49812e840b9SSeth Howell 	int rc;
49912e840b9SSeth Howell 	char buf[100];
500e9d400d5SBen Walker 	struct spdk_fs_thread_ctx *channel;
50112e840b9SSeth Howell 
50212e840b9SSeth Howell 	ut_send_request(_fs_init, NULL);
50312e840b9SSeth Howell 
504e9d400d5SBen Walker 	channel = spdk_fs_alloc_thread_ctx(g_fs);
50512e840b9SSeth Howell 
50612e840b9SSeth Howell 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
50712e840b9SSeth Howell 	CU_ASSERT(rc == 0);
50812e840b9SSeth Howell 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
50912e840b9SSeth Howell 
51012e840b9SSeth Howell 	spdk_file_write(g_file, channel, buf, 0 * sizeof(buf), sizeof(buf));
51112e840b9SSeth Howell 	CU_ASSERT(spdk_file_get_length(g_file) == 1 * sizeof(buf));
51212e840b9SSeth Howell 	spdk_file_write(g_file, channel, buf, 1 * sizeof(buf), sizeof(buf));
51312e840b9SSeth Howell 	CU_ASSERT(spdk_file_get_length(g_file) == 2 * sizeof(buf));
51412e840b9SSeth Howell 	spdk_file_sync(g_file, channel);
515c41c4c2bSChangpeng Liu 
516c41c4c2bSChangpeng Liu 	fs_thread_poll();
517c41c4c2bSChangpeng Liu 
51812e840b9SSeth Howell 	spdk_file_write(g_file, channel, buf, 2 * sizeof(buf), sizeof(buf));
51912e840b9SSeth Howell 	CU_ASSERT(spdk_file_get_length(g_file) == 3 * sizeof(buf));
52012e840b9SSeth Howell 	spdk_file_write(g_file, channel, buf, 3 * sizeof(buf), sizeof(buf));
52112e840b9SSeth Howell 	CU_ASSERT(spdk_file_get_length(g_file) == 4 * sizeof(buf));
52212e840b9SSeth Howell 	spdk_file_write(g_file, channel, buf, 4 * sizeof(buf), sizeof(buf));
52312e840b9SSeth Howell 	CU_ASSERT(spdk_file_get_length(g_file) == 5 * sizeof(buf));
52412e840b9SSeth Howell 
52512e840b9SSeth Howell 	spdk_file_close(g_file, channel);
526c41c4c2bSChangpeng Liu 
527c41c4c2bSChangpeng Liu 	fs_thread_poll();
528c41c4c2bSChangpeng Liu 
52912e840b9SSeth Howell 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
53012e840b9SSeth Howell 	CU_ASSERT(rc == 0);
53112e840b9SSeth Howell 
532e9d400d5SBen Walker 	spdk_fs_free_thread_ctx(channel);
53312e840b9SSeth Howell 
53412e840b9SSeth Howell 	ut_send_request(_fs_unload, NULL);
53512e840b9SSeth Howell }
53612e840b9SSeth Howell 
53712e840b9SSeth Howell static void
fs_delete_file_without_close(void)53812e840b9SSeth Howell fs_delete_file_without_close(void)
53912e840b9SSeth Howell {
54012e840b9SSeth Howell 	int rc;
541e9d400d5SBen Walker 	struct spdk_fs_thread_ctx *channel;
54212e840b9SSeth Howell 	struct spdk_file *file;
54312e840b9SSeth Howell 
54412e840b9SSeth Howell 	ut_send_request(_fs_init, NULL);
545e9d400d5SBen Walker 	channel = spdk_fs_alloc_thread_ctx(g_fs);
54612e840b9SSeth Howell 	CU_ASSERT(channel != NULL);
54712e840b9SSeth Howell 
54812e840b9SSeth Howell 	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
54912e840b9SSeth Howell 	CU_ASSERT(rc == 0);
550438b71d1SSeth Howell 	SPDK_CU_ASSERT_FATAL(g_file != NULL);
55112e840b9SSeth Howell 
55212e840b9SSeth Howell 	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
55312e840b9SSeth Howell 	CU_ASSERT(rc == 0);
55412e840b9SSeth Howell 	CU_ASSERT(g_file->ref_count != 0);
55512e840b9SSeth Howell 	CU_ASSERT(g_file->is_deleted == true);
55612e840b9SSeth Howell 
55712e840b9SSeth Howell 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file);
55812e840b9SSeth Howell 	CU_ASSERT(rc != 0);
55912e840b9SSeth Howell 
56012e840b9SSeth Howell 	spdk_file_close(g_file, channel);
56112e840b9SSeth Howell 
562c41c4c2bSChangpeng Liu 	fs_thread_poll();
563c41c4c2bSChangpeng Liu 
56412e840b9SSeth Howell 	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file);
56512e840b9SSeth Howell 	CU_ASSERT(rc != 0);
56612e840b9SSeth Howell 
567e9d400d5SBen Walker 	spdk_fs_free_thread_ctx(channel);
56812e840b9SSeth Howell 
56912e840b9SSeth Howell 	ut_send_request(_fs_unload, NULL);
57012e840b9SSeth Howell 
57112e840b9SSeth Howell }
57212e840b9SSeth Howell 
573088c5e04SBen Walker static bool g_thread_exit = false;
574088c5e04SBen Walker 
57512e840b9SSeth Howell static void
terminate_spdk_thread(void * arg)57612e840b9SSeth Howell terminate_spdk_thread(void *arg)
57712e840b9SSeth Howell {
578088c5e04SBen Walker 	g_thread_exit = true;
57912e840b9SSeth Howell }
58012e840b9SSeth Howell 
58112e840b9SSeth Howell static void *
spdk_thread(void * arg)58212e840b9SSeth Howell spdk_thread(void *arg)
58312e840b9SSeth Howell {
584088c5e04SBen Walker 	struct spdk_thread *thread = arg;
58512e840b9SSeth Howell 
586605e530aSBen Walker 	spdk_set_thread(thread);
58712e840b9SSeth Howell 
588088c5e04SBen Walker 	while (!g_thread_exit) {
5898abfb06eSBen Walker 		spdk_thread_poll(thread, 0, 0);
59012e840b9SSeth Howell 	}
59112e840b9SSeth Howell 
59212e840b9SSeth Howell 	return NULL;
59312e840b9SSeth Howell }
59412e840b9SSeth Howell 
5958dd1cd21SBen Walker int
main(int argc,char ** argv)5968dd1cd21SBen Walker main(int argc, char **argv)
59712e840b9SSeth Howell {
598605e530aSBen Walker 	struct spdk_thread *thread;
59912e840b9SSeth Howell 	CU_pSuite	suite = NULL;
60012e840b9SSeth Howell 	pthread_t	spdk_tid;
60112e840b9SSeth Howell 	unsigned int	num_failures;
60212e840b9SSeth Howell 
60378b696bcSVitaliy Mysak 	CU_initialize_registry();
60412e840b9SSeth Howell 
60512e840b9SSeth Howell 	suite = CU_add_suite("blobfs_sync_ut", NULL, NULL);
60612e840b9SSeth Howell 
607dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, cache_read_after_write);
608dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, file_length);
609dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, append_write_to_extend_blob);
610dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, partial_buffer);
611dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, cache_write_null_buffer);
612dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, fs_create_sync);
613dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, fs_rename_sync);
614dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, cache_append_no_cache);
615dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, fs_delete_file_without_close);
61612e840b9SSeth Howell 
617088c5e04SBen Walker 	spdk_thread_lib_init(NULL, 0);
618088c5e04SBen Walker 
6195d0b5e2cSBen Walker 	thread = spdk_thread_create("test_thread", NULL);
620605e530aSBen Walker 	spdk_set_thread(thread);
6217f6068f0SBen Walker 
6225d0b5e2cSBen Walker 	g_dispatch_thread = spdk_thread_create("dispatch_thread", NULL);
623088c5e04SBen Walker 	pthread_create(&spdk_tid, NULL, spdk_thread, g_dispatch_thread);
624088c5e04SBen Walker 
62512e840b9SSeth Howell 	g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
626088c5e04SBen Walker 
627*ea941caeSKonrad Sztyber 	num_failures = spdk_ut_run_tests(argc, argv, NULL);
62812e840b9SSeth Howell 	CU_cleanup_registry();
629088c5e04SBen Walker 
63012e840b9SSeth Howell 	free(g_dev_buffer);
631088c5e04SBen Walker 
632088c5e04SBen Walker 	ut_send_request(terminate_spdk_thread, NULL);
63312e840b9SSeth Howell 	pthread_join(spdk_tid, NULL);
634088c5e04SBen Walker 
635088c5e04SBen Walker 	while (spdk_thread_poll(g_dispatch_thread, 0, 0) > 0) {}
636088c5e04SBen Walker 	while (spdk_thread_poll(thread, 0, 0) > 0) {}
637088c5e04SBen Walker 
638e036215fSBen Walker 	spdk_set_thread(thread);
6399cba82b9SBen Walker 	spdk_thread_exit(thread);
640e7ead00bSShuhei Matsumoto 	while (!spdk_thread_is_exited(thread)) {
641e7ead00bSShuhei Matsumoto 		spdk_thread_poll(thread, 0, 0);
642e7ead00bSShuhei Matsumoto 	}
643e036215fSBen Walker 	spdk_thread_destroy(thread);
644e036215fSBen Walker 
645e036215fSBen Walker 	spdk_set_thread(g_dispatch_thread);
646088c5e04SBen Walker 	spdk_thread_exit(g_dispatch_thread);
647e7ead00bSShuhei Matsumoto 	while (!spdk_thread_is_exited(g_dispatch_thread)) {
648e7ead00bSShuhei Matsumoto 		spdk_thread_poll(g_dispatch_thread, 0, 0);
649e7ead00bSShuhei Matsumoto 	}
650e036215fSBen Walker 	spdk_thread_destroy(g_dispatch_thread);
651088c5e04SBen Walker 
652088c5e04SBen Walker 	spdk_thread_lib_fini();
653088c5e04SBen Walker 
65412e840b9SSeth Howell 	return num_failures;
65512e840b9SSeth Howell }
656