xref: /spdk/lib/blobfs/blobfs.c (revision 0eae01067000f31cb6c9dbdf792411c1957754f3)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2017 Intel Corporation.
31edd9bf3SJim Harris  *   All rights reserved.
41edd9bf3SJim Harris  */
51edd9bf3SJim Harris 
6b961d9ccSBen Walker #include "spdk/stdinc.h"
71edd9bf3SJim Harris 
81edd9bf3SJim Harris #include "spdk/blobfs.h"
9e70dc52fSJim Harris #include "cache_tree.h"
101edd9bf3SJim Harris 
111edd9bf3SJim Harris #include "spdk/queue.h"
12a83f91c2SBen Walker #include "spdk/thread.h"
131edd9bf3SJim Harris #include "spdk/assert.h"
141edd9bf3SJim Harris #include "spdk/env.h"
153b683c18SBen Walker #include "spdk/util.h"
164e8e97c8STomasz Zawadzki #include "spdk/log.h"
17f71fed21SJim Harris #include "spdk/trace.h"
181edd9bf3SJim Harris 
19c37e776eSKrzysztof Karas #include "spdk_internal/trace_defs.h"
20c37e776eSKrzysztof Karas 
211edd9bf3SJim Harris #define BLOBFS_TRACE(file, str, args...) \
222172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s " str, file->name, ##args)
231edd9bf3SJim Harris 
241edd9bf3SJim Harris #define BLOBFS_TRACE_RW(file, str, args...) \
252172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs_rw, "file=%s " str, file->name, ##args)
261edd9bf3SJim Harris 
27f6c5e40aSZiye Yang #define BLOBFS_DEFAULT_CACHE_SIZE (4ULL * 1024 * 1024 * 1024)
28f6c5e40aSZiye Yang #define SPDK_BLOBFS_DEFAULT_OPTS_CLUSTER_SZ (1024 * 1024)
291edd9bf3SJim Harris 
3062202ddaSChangpeng Liu #define SPDK_BLOBFS_SIGNATURE	"BLOBFS"
3162202ddaSChangpeng Liu 
32f6c5e40aSZiye Yang static uint64_t g_fs_cache_size = BLOBFS_DEFAULT_CACHE_SIZE;
331edd9bf3SJim Harris static struct spdk_mempool *g_cache_pool;
3455478de6Syidong0635 static TAILQ_HEAD(, spdk_file) g_caches = TAILQ_HEAD_INITIALIZER(g_caches);
351914de09SChangpeng Liu static struct spdk_poller *g_cache_pool_mgmt_poller;
361914de09SChangpeng Liu static struct spdk_thread *g_cache_pool_thread;
371914de09SChangpeng Liu #define BLOBFS_CACHE_POOL_POLL_PERIOD_IN_US 1000ULL
38e045a02cSJim Harris static int g_fs_count = 0;
39e045a02cSJim Harris static pthread_mutex_t g_cache_init_lock = PTHREAD_MUTEX_INITIALIZER;
401edd9bf3SJim Harris 
41*0eae0106SJim Harris static void
42*0eae0106SJim Harris blobfs_trace(void)
43f71fed21SJim Harris {
443e158bd5SKonrad Sztyber 	struct spdk_trace_tpoint_opts opts[] = {
453e158bd5SKonrad Sztyber 		{
463e158bd5SKonrad Sztyber 			"BLOBFS_XATTR_START", TRACE_BLOBFS_XATTR_START,
4726d44a12SJim Harris 			OWNER_TYPE_NONE, OBJECT_NONE, 0,
483e158bd5SKonrad Sztyber 			{{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
493e158bd5SKonrad Sztyber 		},
503e158bd5SKonrad Sztyber 		{
513e158bd5SKonrad Sztyber 			"BLOBFS_XATTR_END", TRACE_BLOBFS_XATTR_END,
5226d44a12SJim Harris 			OWNER_TYPE_NONE, OBJECT_NONE, 0,
533e158bd5SKonrad Sztyber 			{{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
543e158bd5SKonrad Sztyber 		},
553e158bd5SKonrad Sztyber 		{
563e158bd5SKonrad Sztyber 			"BLOBFS_OPEN", TRACE_BLOBFS_OPEN,
5726d44a12SJim Harris 			OWNER_TYPE_NONE, OBJECT_NONE, 0,
583e158bd5SKonrad Sztyber 			{{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
593e158bd5SKonrad Sztyber 		},
603e158bd5SKonrad Sztyber 		{
613e158bd5SKonrad Sztyber 			"BLOBFS_CLOSE", TRACE_BLOBFS_CLOSE,
6226d44a12SJim Harris 			OWNER_TYPE_NONE, OBJECT_NONE, 0,
633e158bd5SKonrad Sztyber 			{{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
643e158bd5SKonrad Sztyber 		},
653e158bd5SKonrad Sztyber 		{
663e158bd5SKonrad Sztyber 			"BLOBFS_DELETE_START", TRACE_BLOBFS_DELETE_START,
6726d44a12SJim Harris 			OWNER_TYPE_NONE, OBJECT_NONE, 0,
683e158bd5SKonrad Sztyber 			{{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
693e158bd5SKonrad Sztyber 		},
703e158bd5SKonrad Sztyber 		{
713e158bd5SKonrad Sztyber 			"BLOBFS_DELETE_DONE", TRACE_BLOBFS_DELETE_DONE,
7226d44a12SJim Harris 			OWNER_TYPE_NONE, OBJECT_NONE, 0,
733e158bd5SKonrad Sztyber 			{{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
743e158bd5SKonrad Sztyber 		}
753e158bd5SKonrad Sztyber 	};
763e158bd5SKonrad Sztyber 
773e158bd5SKonrad Sztyber 	spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts));
78f71fed21SJim Harris }
79*0eae0106SJim Harris SPDK_TRACE_REGISTER_FN(blobfs_trace, "blobfs", TRACE_GROUP_BLOBFS)
80f71fed21SJim Harris 
811edd9bf3SJim Harris void
82bc0180f6SSeth Howell cache_buffer_free(struct cache_buffer *cache_buffer)
831edd9bf3SJim Harris {
841edd9bf3SJim Harris 	spdk_mempool_put(g_cache_pool, cache_buffer->buf);
851edd9bf3SJim Harris 	free(cache_buffer);
861edd9bf3SJim Harris }
871edd9bf3SJim Harris 
881edd9bf3SJim Harris #define CACHE_READAHEAD_THRESHOLD	(128 * 1024)
891edd9bf3SJim Harris 
901edd9bf3SJim Harris struct spdk_file {
911edd9bf3SJim Harris 	struct spdk_filesystem	*fs;
921edd9bf3SJim Harris 	struct spdk_blob	*blob;
931edd9bf3SJim Harris 	char			*name;
941edd9bf3SJim Harris 	uint64_t		length;
952d18887fSCunyin Chang 	bool                    is_deleted;
961edd9bf3SJim Harris 	bool			open_for_writing;
971edd9bf3SJim Harris 	uint64_t		length_flushed;
98e967dcd2SJim Harris 	uint64_t		length_xattr;
991edd9bf3SJim Harris 	uint64_t		append_pos;
1001edd9bf3SJim Harris 	uint64_t		seq_byte_count;
1011edd9bf3SJim Harris 	uint64_t		next_seq_offset;
1021edd9bf3SJim Harris 	uint32_t		priority;
1031edd9bf3SJim Harris 	TAILQ_ENTRY(spdk_file)	tailq;
1041edd9bf3SJim Harris 	spdk_blob_id		blobid;
1051edd9bf3SJim Harris 	uint32_t		ref_count;
1061edd9bf3SJim Harris 	pthread_spinlock_t	lock;
1071edd9bf3SJim Harris 	struct cache_buffer	*last;
1081edd9bf3SJim Harris 	struct cache_tree	*tree;
1091edd9bf3SJim Harris 	TAILQ_HEAD(open_requests_head, spdk_fs_request) open_requests;
1101edd9bf3SJim Harris 	TAILQ_HEAD(sync_requests_head, spdk_fs_request) sync_requests;
1111edd9bf3SJim Harris 	TAILQ_ENTRY(spdk_file)	cache_tailq;
1121edd9bf3SJim Harris };
1131edd9bf3SJim Harris 
1142d18887fSCunyin Chang struct spdk_deleted_file {
1152d18887fSCunyin Chang 	spdk_blob_id	id;
1162d18887fSCunyin Chang 	TAILQ_ENTRY(spdk_deleted_file)	tailq;
1172d18887fSCunyin Chang };
1182d18887fSCunyin Chang 
1191edd9bf3SJim Harris struct spdk_filesystem {
1201edd9bf3SJim Harris 	struct spdk_blob_store	*bs;
1211edd9bf3SJim Harris 	TAILQ_HEAD(, spdk_file)	files;
1221edd9bf3SJim Harris 	struct spdk_bs_opts	bs_opts;
1231edd9bf3SJim Harris 	struct spdk_bs_dev	*bdev;
1241edd9bf3SJim Harris 	fs_send_request_fn	send_request;
1253b683c18SBen Walker 
1263b683c18SBen Walker 	struct {
1273b683c18SBen Walker 		uint32_t		max_ops;
128a3ab7610SBen Walker 		struct spdk_io_channel	*sync_io_channel;
129a3ab7610SBen Walker 		struct spdk_fs_channel	*sync_fs_channel;
130a3ab7610SBen Walker 	} sync_target;
131a3ab7610SBen Walker 
132a3ab7610SBen Walker 	struct {
133a3ab7610SBen Walker 		uint32_t		max_ops;
134267a4e1eSBen Walker 		struct spdk_io_channel	*md_io_channel;
135267a4e1eSBen Walker 		struct spdk_fs_channel	*md_fs_channel;
136267a4e1eSBen Walker 	} md_target;
137267a4e1eSBen Walker 
138267a4e1eSBen Walker 	struct {
139267a4e1eSBen Walker 		uint32_t		max_ops;
1403b683c18SBen Walker 	} io_target;
1411edd9bf3SJim Harris };
1421edd9bf3SJim Harris 
1431edd9bf3SJim Harris struct spdk_fs_cb_args {
1441edd9bf3SJim Harris 	union {
1451edd9bf3SJim Harris 		spdk_fs_op_with_handle_complete		fs_op_with_handle;
1461edd9bf3SJim Harris 		spdk_fs_op_complete			fs_op;
1471edd9bf3SJim Harris 		spdk_file_op_with_handle_complete	file_op_with_handle;
1481edd9bf3SJim Harris 		spdk_file_op_complete			file_op;
1491edd9bf3SJim Harris 		spdk_file_stat_op_complete		stat_op;
1501edd9bf3SJim Harris 	} fn;
1511edd9bf3SJim Harris 	void *arg;
1521edd9bf3SJim Harris 	sem_t *sem;
1531edd9bf3SJim Harris 	struct spdk_filesystem *fs;
1541edd9bf3SJim Harris 	struct spdk_file *file;
1551edd9bf3SJim Harris 	int rc;
156944a480eSJimboLuCN 	int *rwerrno;
157ceb6ef89SChangpeng Liu 	struct iovec *iovs;
158ceb6ef89SChangpeng Liu 	uint32_t iovcnt;
159ceb6ef89SChangpeng Liu 	struct iovec iov;
1601edd9bf3SJim Harris 	union {
1611edd9bf3SJim Harris 		struct {
1622d18887fSCunyin Chang 			TAILQ_HEAD(, spdk_deleted_file)	deleted_files;
1632d18887fSCunyin Chang 		} fs_load;
1642d18887fSCunyin Chang 		struct {
1651edd9bf3SJim Harris 			uint64_t	length;
1661edd9bf3SJim Harris 		} truncate;
1671edd9bf3SJim Harris 		struct {
1681edd9bf3SJim Harris 			struct spdk_io_channel	*channel;
1691edd9bf3SJim Harris 			void		*pin_buf;
1701edd9bf3SJim Harris 			int		is_read;
1711edd9bf3SJim Harris 			off_t		offset;
1721edd9bf3SJim Harris 			size_t		length;
173be2d2c76SPiotr Pelplinski 			uint64_t	start_lba;
174be2d2c76SPiotr Pelplinski 			uint64_t	num_lba;
1751edd9bf3SJim Harris 			uint32_t	blocklen;
1761edd9bf3SJim Harris 		} rw;
1771edd9bf3SJim Harris 		struct {
1781edd9bf3SJim Harris 			const char	*old_name;
1791edd9bf3SJim Harris 			const char	*new_name;
1801edd9bf3SJim Harris 		} rename;
1811edd9bf3SJim Harris 		struct {
1821edd9bf3SJim Harris 			struct cache_buffer	*cache_buffer;
1831edd9bf3SJim Harris 			uint64_t		length;
1841edd9bf3SJim Harris 		} flush;
1851edd9bf3SJim Harris 		struct {
1861edd9bf3SJim Harris 			struct cache_buffer	*cache_buffer;
1871edd9bf3SJim Harris 			uint64_t		length;
1881edd9bf3SJim Harris 			uint64_t		offset;
1891edd9bf3SJim Harris 		} readahead;
1901edd9bf3SJim Harris 		struct {
191e967dcd2SJim Harris 			/* offset of the file when the sync request was made */
1921edd9bf3SJim Harris 			uint64_t			offset;
1931edd9bf3SJim Harris 			TAILQ_ENTRY(spdk_fs_request)	tailq;
194a6014eb2SJim Harris 			bool				xattr_in_progress;
195e967dcd2SJim Harris 			/* length written to the xattr for this file - this should
196e967dcd2SJim Harris 			 * always be the same as the offset if only one thread is
197e967dcd2SJim Harris 			 * writing to the file, but could differ if multiple threads
198e967dcd2SJim Harris 			 * are appending
199e967dcd2SJim Harris 			 */
200e967dcd2SJim Harris 			uint64_t			length;
2011edd9bf3SJim Harris 		} sync;
2021edd9bf3SJim Harris 		struct {
2031edd9bf3SJim Harris 			uint32_t			num_clusters;
2041edd9bf3SJim Harris 		} resize;
2051edd9bf3SJim Harris 		struct {
2061edd9bf3SJim Harris 			const char	*name;
2071edd9bf3SJim Harris 			uint32_t	flags;
2081edd9bf3SJim Harris 			TAILQ_ENTRY(spdk_fs_request)	tailq;
2091edd9bf3SJim Harris 		} open;
2101edd9bf3SJim Harris 		struct {
2111edd9bf3SJim Harris 			const char		*name;
212463925ffSJim Harris 			struct spdk_blob	*blob;
2131edd9bf3SJim Harris 		} create;
2141edd9bf3SJim Harris 		struct {
2151edd9bf3SJim Harris 			const char	*name;
2161edd9bf3SJim Harris 		} delete;
2171edd9bf3SJim Harris 		struct {
2181edd9bf3SJim Harris 			const char	*name;
2191edd9bf3SJim Harris 		} stat;
2201edd9bf3SJim Harris 	} op;
2211edd9bf3SJim Harris };
2221edd9bf3SJim Harris 
22387d5d832SChangpeng Liu static void file_free(struct spdk_file *file);
224bc0180f6SSeth Howell static void fs_io_device_unregister(struct spdk_filesystem *fs);
225bc0180f6SSeth Howell static void fs_free_io_channels(struct spdk_filesystem *fs);
2261edd9bf3SJim Harris 
2276951b979SCunyin Chang void
2286951b979SCunyin Chang spdk_fs_opts_init(struct spdk_blobfs_opts *opts)
2296951b979SCunyin Chang {
230f6c5e40aSZiye Yang 	opts->cluster_sz = SPDK_BLOBFS_DEFAULT_OPTS_CLUSTER_SZ;
2316951b979SCunyin Chang }
2326951b979SCunyin Chang 
2331914de09SChangpeng Liu static int _blobfs_cache_pool_reclaim(void *arg);
2341914de09SChangpeng Liu 
2351914de09SChangpeng Liu static bool
2361914de09SChangpeng Liu blobfs_cache_pool_need_reclaim(void)
2371914de09SChangpeng Liu {
2381914de09SChangpeng Liu 	size_t count;
2391914de09SChangpeng Liu 
2401914de09SChangpeng Liu 	count = spdk_mempool_count(g_cache_pool);
2411914de09SChangpeng Liu 	/* We define a aggressive policy here as the requirements from db_bench are batched, so start the poller
2421914de09SChangpeng Liu 	 *  when the number of available cache buffer is less than 1/5 of total buffers.
2431914de09SChangpeng Liu 	 */
2441914de09SChangpeng Liu 	if (count > (size_t)g_fs_cache_size / CACHE_BUFFER_SIZE / 5) {
2451914de09SChangpeng Liu 		return false;
2461914de09SChangpeng Liu 	}
2471914de09SChangpeng Liu 
2481914de09SChangpeng Liu 	return true;
2491914de09SChangpeng Liu }
2501914de09SChangpeng Liu 
2511edd9bf3SJim Harris static void
2521914de09SChangpeng Liu __start_cache_pool_mgmt(void *ctx)
2531edd9bf3SJim Harris {
2541914de09SChangpeng Liu 	assert(g_cache_pool_mgmt_poller == NULL);
255ab0bc5c2SShuhei Matsumoto 	g_cache_pool_mgmt_poller = SPDK_POLLER_REGISTER(_blobfs_cache_pool_reclaim, NULL,
2561914de09SChangpeng Liu 				   BLOBFS_CACHE_POOL_POLL_PERIOD_IN_US);
2571914de09SChangpeng Liu }
2581914de09SChangpeng Liu 
2591914de09SChangpeng Liu static void
2601914de09SChangpeng Liu __stop_cache_pool_mgmt(void *ctx)
2611914de09SChangpeng Liu {
2621914de09SChangpeng Liu 	spdk_poller_unregister(&g_cache_pool_mgmt_poller);
2631914de09SChangpeng Liu 
2641914de09SChangpeng Liu 	assert(g_cache_pool != NULL);
2651914de09SChangpeng Liu 	assert(spdk_mempool_count(g_cache_pool) == g_fs_cache_size / CACHE_BUFFER_SIZE);
2661914de09SChangpeng Liu 	spdk_mempool_free(g_cache_pool);
2671914de09SChangpeng Liu 	g_cache_pool = NULL;
2681914de09SChangpeng Liu 
2691914de09SChangpeng Liu 	spdk_thread_exit(g_cache_pool_thread);
2701914de09SChangpeng Liu }
2711914de09SChangpeng Liu 
2721914de09SChangpeng Liu static void
27384532e3dSJim Harris allocate_cache_pool(void)
27484532e3dSJim Harris {
27584532e3dSJim Harris 	assert(g_cache_pool == NULL);
27684532e3dSJim Harris 	g_cache_pool = spdk_mempool_create("spdk_fs_cache",
27784532e3dSJim Harris 					   g_fs_cache_size / CACHE_BUFFER_SIZE,
27884532e3dSJim Harris 					   CACHE_BUFFER_SIZE,
27984532e3dSJim Harris 					   SPDK_MEMPOOL_DEFAULT_CACHE_SIZE,
280186b109dSJim Harris 					   SPDK_ENV_NUMA_ID_ANY);
28184532e3dSJim Harris 	if (!g_cache_pool) {
28284532e3dSJim Harris 		if (spdk_mempool_lookup("spdk_fs_cache") != NULL) {
28384532e3dSJim Harris 			SPDK_ERRLOG("Unable to allocate mempool: already exists\n");
28484532e3dSJim Harris 			SPDK_ERRLOG("Probably running in multiprocess environment, which is "
28584532e3dSJim Harris 				    "unsupported by the blobfs library\n");
28684532e3dSJim Harris 		} else {
28784532e3dSJim Harris 			SPDK_ERRLOG("Create mempool failed, you may "
28884532e3dSJim Harris 				    "increase the memory and try again\n");
28984532e3dSJim Harris 		}
29084532e3dSJim Harris 		assert(false);
29184532e3dSJim Harris 	}
29284532e3dSJim Harris }
29384532e3dSJim Harris 
29484532e3dSJim Harris static void
2950841addaSChangpeng Liu initialize_global_cache(void)
2961914de09SChangpeng Liu {
2970841addaSChangpeng Liu 	pthread_mutex_lock(&g_cache_init_lock);
2980841addaSChangpeng Liu 	if (g_fs_count == 0) {
29984532e3dSJim Harris 		allocate_cache_pool();
3001914de09SChangpeng Liu 		g_cache_pool_thread = spdk_thread_create("cache_pool_mgmt", NULL);
3011914de09SChangpeng Liu 		assert(g_cache_pool_thread != NULL);
3021914de09SChangpeng Liu 		spdk_thread_send_msg(g_cache_pool_thread, __start_cache_pool_mgmt, NULL);
3031edd9bf3SJim Harris 	}
3040841addaSChangpeng Liu 	g_fs_count++;
3050841addaSChangpeng Liu 	pthread_mutex_unlock(&g_cache_init_lock);
3060841addaSChangpeng Liu }
3071edd9bf3SJim Harris 
308e045a02cSJim Harris static void
3090841addaSChangpeng Liu free_global_cache(void)
310e045a02cSJim Harris {
3110841addaSChangpeng Liu 	pthread_mutex_lock(&g_cache_init_lock);
3120841addaSChangpeng Liu 	g_fs_count--;
3130841addaSChangpeng Liu 	if (g_fs_count == 0) {
3141914de09SChangpeng Liu 		spdk_thread_send_msg(g_cache_pool_thread, __stop_cache_pool_mgmt, NULL);
315e045a02cSJim Harris 	}
3160841addaSChangpeng Liu 	pthread_mutex_unlock(&g_cache_init_lock);
3170841addaSChangpeng Liu }
318e045a02cSJim Harris 
3191edd9bf3SJim Harris static uint64_t
3201edd9bf3SJim Harris __file_get_blob_size(struct spdk_file *file)
3211edd9bf3SJim Harris {
3221edd9bf3SJim Harris 	uint64_t cluster_sz;
3231edd9bf3SJim Harris 
3241edd9bf3SJim Harris 	cluster_sz = file->fs->bs_opts.cluster_sz;
3251edd9bf3SJim Harris 	return cluster_sz * spdk_blob_get_num_clusters(file->blob);
3261edd9bf3SJim Harris }
3271edd9bf3SJim Harris 
3281edd9bf3SJim Harris struct spdk_fs_request {
3291edd9bf3SJim Harris 	struct spdk_fs_cb_args		args;
3301edd9bf3SJim Harris 	TAILQ_ENTRY(spdk_fs_request)	link;
3311edd9bf3SJim Harris 	struct spdk_fs_channel		*channel;
3321edd9bf3SJim Harris };
3331edd9bf3SJim Harris 
3341edd9bf3SJim Harris struct spdk_fs_channel {
3351edd9bf3SJim Harris 	struct spdk_fs_request		*req_mem;
3361edd9bf3SJim Harris 	TAILQ_HEAD(, spdk_fs_request)	reqs;
3371edd9bf3SJim Harris 	sem_t				sem;
3381edd9bf3SJim Harris 	struct spdk_filesystem		*fs;
3391edd9bf3SJim Harris 	struct spdk_io_channel		*bs_channel;
3401edd9bf3SJim Harris 	fs_send_request_fn		send_request;
34159ed2aa9SJim Harris 	bool				sync;
342b282c927SJim Harris 	uint32_t			outstanding_reqs;
34359ed2aa9SJim Harris 	pthread_spinlock_t		lock;
3441edd9bf3SJim Harris };
3451edd9bf3SJim Harris 
346e9d400d5SBen Walker /* For now, this is effectively an alias. But eventually we'll shift
347e9d400d5SBen Walker  * some data members over. */
348e9d400d5SBen Walker struct spdk_fs_thread_ctx {
349e9d400d5SBen Walker 	struct spdk_fs_channel	ch;
350e9d400d5SBen Walker };
351e9d400d5SBen Walker 
3521edd9bf3SJim Harris static struct spdk_fs_request *
353ceb6ef89SChangpeng Liu alloc_fs_request_with_iov(struct spdk_fs_channel *channel, uint32_t iovcnt)
3541edd9bf3SJim Harris {
3551edd9bf3SJim Harris 	struct spdk_fs_request *req;
356ceb6ef89SChangpeng Liu 	struct iovec *iovs = NULL;
357ceb6ef89SChangpeng Liu 
358ceb6ef89SChangpeng Liu 	if (iovcnt > 1) {
359ceb6ef89SChangpeng Liu 		iovs = calloc(iovcnt, sizeof(struct iovec));
360ceb6ef89SChangpeng Liu 		if (!iovs) {
361ceb6ef89SChangpeng Liu 			return NULL;
362ceb6ef89SChangpeng Liu 		}
363ceb6ef89SChangpeng Liu 	}
3641edd9bf3SJim Harris 
36559ed2aa9SJim Harris 	if (channel->sync) {
36659ed2aa9SJim Harris 		pthread_spin_lock(&channel->lock);
36759ed2aa9SJim Harris 	}
36859ed2aa9SJim Harris 
3691edd9bf3SJim Harris 	req = TAILQ_FIRST(&channel->reqs);
37059ed2aa9SJim Harris 	if (req) {
371b282c927SJim Harris 		channel->outstanding_reqs++;
37259ed2aa9SJim Harris 		TAILQ_REMOVE(&channel->reqs, req, link);
37359ed2aa9SJim Harris 	}
37459ed2aa9SJim Harris 
37559ed2aa9SJim Harris 	if (channel->sync) {
37659ed2aa9SJim Harris 		pthread_spin_unlock(&channel->lock);
37759ed2aa9SJim Harris 	}
37859ed2aa9SJim Harris 
37959ed2aa9SJim Harris 	if (req == NULL) {
380bdb1d571SZiye Yang 		SPDK_ERRLOG("Cannot allocate req on spdk_fs_channel =%p\n", channel);
381ceb6ef89SChangpeng Liu 		free(iovs);
3821edd9bf3SJim Harris 		return NULL;
3831edd9bf3SJim Harris 	}
3841edd9bf3SJim Harris 	memset(req, 0, sizeof(*req));
3851edd9bf3SJim Harris 	req->channel = channel;
386ceb6ef89SChangpeng Liu 	if (iovcnt > 1) {
387ceb6ef89SChangpeng Liu 		req->args.iovs = iovs;
388ceb6ef89SChangpeng Liu 	} else {
389ceb6ef89SChangpeng Liu 		req->args.iovs = &req->args.iov;
390ceb6ef89SChangpeng Liu 	}
391ceb6ef89SChangpeng Liu 	req->args.iovcnt = iovcnt;
3921edd9bf3SJim Harris 
3931edd9bf3SJim Harris 	return req;
3941edd9bf3SJim Harris }
3951edd9bf3SJim Harris 
396ceb6ef89SChangpeng Liu static struct spdk_fs_request *
397ceb6ef89SChangpeng Liu alloc_fs_request(struct spdk_fs_channel *channel)
398ceb6ef89SChangpeng Liu {
399ceb6ef89SChangpeng Liu 	return alloc_fs_request_with_iov(channel, 0);
400ceb6ef89SChangpeng Liu }
401ceb6ef89SChangpeng Liu 
4021edd9bf3SJim Harris static void
4031edd9bf3SJim Harris free_fs_request(struct spdk_fs_request *req)
4041edd9bf3SJim Harris {
40559ed2aa9SJim Harris 	struct spdk_fs_channel *channel = req->channel;
40659ed2aa9SJim Harris 
407ceb6ef89SChangpeng Liu 	if (req->args.iovcnt > 1) {
408ceb6ef89SChangpeng Liu 		free(req->args.iovs);
409ceb6ef89SChangpeng Liu 	}
410ceb6ef89SChangpeng Liu 
41159ed2aa9SJim Harris 	if (channel->sync) {
41259ed2aa9SJim Harris 		pthread_spin_lock(&channel->lock);
41359ed2aa9SJim Harris 	}
41459ed2aa9SJim Harris 
4151edd9bf3SJim Harris 	TAILQ_INSERT_HEAD(&req->channel->reqs, req, link);
416b282c927SJim Harris 	channel->outstanding_reqs--;
41759ed2aa9SJim Harris 
41859ed2aa9SJim Harris 	if (channel->sync) {
41959ed2aa9SJim Harris 		pthread_spin_unlock(&channel->lock);
42059ed2aa9SJim Harris 	}
4211edd9bf3SJim Harris }
4221edd9bf3SJim Harris 
4231edd9bf3SJim Harris static int
424bc0180f6SSeth Howell fs_channel_create(struct spdk_filesystem *fs, struct spdk_fs_channel *channel,
4253b683c18SBen Walker 		  uint32_t max_ops)
4261edd9bf3SJim Harris {
4271edd9bf3SJim Harris 	uint32_t i;
4281edd9bf3SJim Harris 
4291edd9bf3SJim Harris 	channel->req_mem = calloc(max_ops, sizeof(struct spdk_fs_request));
4301edd9bf3SJim Harris 	if (!channel->req_mem) {
4311edd9bf3SJim Harris 		return -1;
4321edd9bf3SJim Harris 	}
4331edd9bf3SJim Harris 
434b282c927SJim Harris 	channel->outstanding_reqs = 0;
4351edd9bf3SJim Harris 	TAILQ_INIT(&channel->reqs);
4361edd9bf3SJim Harris 	sem_init(&channel->sem, 0, 0);
4371edd9bf3SJim Harris 
4381edd9bf3SJim Harris 	for (i = 0; i < max_ops; i++) {
4391edd9bf3SJim Harris 		TAILQ_INSERT_TAIL(&channel->reqs, &channel->req_mem[i], link);
4401edd9bf3SJim Harris 	}
4411edd9bf3SJim Harris 
4421edd9bf3SJim Harris 	channel->fs = fs;
4431edd9bf3SJim Harris 
4441edd9bf3SJim Harris 	return 0;
4451edd9bf3SJim Harris }
4461edd9bf3SJim Harris 
4473b683c18SBen Walker static int
448bc0180f6SSeth Howell fs_md_channel_create(void *io_device, void *ctx_buf)
4493b683c18SBen Walker {
450267a4e1eSBen Walker 	struct spdk_filesystem		*fs;
451267a4e1eSBen Walker 	struct spdk_fs_channel		*channel = ctx_buf;
452267a4e1eSBen Walker 
453267a4e1eSBen Walker 	fs = SPDK_CONTAINEROF(io_device, struct spdk_filesystem, md_target);
454267a4e1eSBen Walker 
455bc0180f6SSeth Howell 	return fs_channel_create(fs, channel, fs->md_target.max_ops);
4563b683c18SBen Walker }
4573b683c18SBen Walker 
4583b683c18SBen Walker static int
459bc0180f6SSeth Howell fs_sync_channel_create(void *io_device, void *ctx_buf)
460a3ab7610SBen Walker {
461a3ab7610SBen Walker 	struct spdk_filesystem		*fs;
462a3ab7610SBen Walker 	struct spdk_fs_channel		*channel = ctx_buf;
463a3ab7610SBen Walker 
464a3ab7610SBen Walker 	fs = SPDK_CONTAINEROF(io_device, struct spdk_filesystem, sync_target);
465a3ab7610SBen Walker 
466bc0180f6SSeth Howell 	return fs_channel_create(fs, channel, fs->sync_target.max_ops);
467a3ab7610SBen Walker }
468a3ab7610SBen Walker 
469a3ab7610SBen Walker static int
470bc0180f6SSeth Howell fs_io_channel_create(void *io_device, void *ctx_buf)
4713b683c18SBen Walker {
4723b683c18SBen Walker 	struct spdk_filesystem		*fs;
4733b683c18SBen Walker 	struct spdk_fs_channel		*channel = ctx_buf;
4743b683c18SBen Walker 
4753b683c18SBen Walker 	fs = SPDK_CONTAINEROF(io_device, struct spdk_filesystem, io_target);
4763b683c18SBen Walker 
477bc0180f6SSeth Howell 	return fs_channel_create(fs, channel, fs->io_target.max_ops);
4783b683c18SBen Walker }
4793b683c18SBen Walker 
4801edd9bf3SJim Harris static void
481bc0180f6SSeth Howell fs_channel_destroy(void *io_device, void *ctx_buf)
4821edd9bf3SJim Harris {
4831edd9bf3SJim Harris 	struct spdk_fs_channel *channel = ctx_buf;
4841edd9bf3SJim Harris 
485b282c927SJim Harris 	if (channel->outstanding_reqs > 0) {
486b282c927SJim Harris 		SPDK_ERRLOG("channel freed with %" PRIu32 " outstanding requests!\n",
487b282c927SJim Harris 			    channel->outstanding_reqs);
488b282c927SJim Harris 	}
489b282c927SJim Harris 
4901edd9bf3SJim Harris 	free(channel->req_mem);
4911edd9bf3SJim Harris 	if (channel->bs_channel != NULL) {
4921edd9bf3SJim Harris 		spdk_bs_free_io_channel(channel->bs_channel);
4931edd9bf3SJim Harris 	}
4941edd9bf3SJim Harris }
4951edd9bf3SJim Harris 
4961edd9bf3SJim Harris static void
4971edd9bf3SJim Harris __send_request_direct(fs_request_fn fn, void *arg)
4981edd9bf3SJim Harris {
4991edd9bf3SJim Harris 	fn(arg);
5001edd9bf3SJim Harris }
5011edd9bf3SJim Harris 
5021edd9bf3SJim Harris static void
5031edd9bf3SJim Harris common_fs_bs_init(struct spdk_filesystem *fs, struct spdk_blob_store *bs)
5041edd9bf3SJim Harris {
5051edd9bf3SJim Harris 	fs->bs = bs;
5061edd9bf3SJim Harris 	fs->bs_opts.cluster_sz = spdk_bs_get_cluster_size(bs);
507d969ac44SBen Walker 	fs->md_target.md_fs_channel->bs_channel = spdk_bs_alloc_io_channel(fs->bs);
508267a4e1eSBen Walker 	fs->md_target.md_fs_channel->send_request = __send_request_direct;
509d969ac44SBen Walker 	fs->sync_target.sync_fs_channel->bs_channel = spdk_bs_alloc_io_channel(fs->bs);
510a3ab7610SBen Walker 	fs->sync_target.sync_fs_channel->send_request = __send_request_direct;
511e045a02cSJim Harris 
5120841addaSChangpeng Liu 	initialize_global_cache();
5131edd9bf3SJim Harris }
5141edd9bf3SJim Harris 
5151edd9bf3SJim Harris static void
5161edd9bf3SJim Harris init_cb(void *ctx, struct spdk_blob_store *bs, int bserrno)
5171edd9bf3SJim Harris {
5181edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
5191edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
5201edd9bf3SJim Harris 	struct spdk_filesystem *fs = args->fs;
5211edd9bf3SJim Harris 
5221edd9bf3SJim Harris 	if (bserrno == 0) {
5231edd9bf3SJim Harris 		common_fs_bs_init(fs, bs);
5241edd9bf3SJim Harris 	} else {
5251edd9bf3SJim Harris 		free(fs);
526f2e4d641SJim Harris 		fs = NULL;
5271edd9bf3SJim Harris 	}
5281edd9bf3SJim Harris 
5291edd9bf3SJim Harris 	args->fn.fs_op_with_handle(args->arg, fs, bserrno);
5301edd9bf3SJim Harris 	free_fs_request(req);
5311edd9bf3SJim Harris }
5321edd9bf3SJim Harris 
5331edd9bf3SJim Harris static struct spdk_filesystem *
5341edd9bf3SJim Harris fs_alloc(struct spdk_bs_dev *dev, fs_send_request_fn send_request_fn)
5351edd9bf3SJim Harris {
5361edd9bf3SJim Harris 	struct spdk_filesystem *fs;
5371edd9bf3SJim Harris 
5381edd9bf3SJim Harris 	fs = calloc(1, sizeof(*fs));
5391edd9bf3SJim Harris 	if (fs == NULL) {
5401edd9bf3SJim Harris 		return NULL;
5411edd9bf3SJim Harris 	}
5421edd9bf3SJim Harris 
5431edd9bf3SJim Harris 	fs->bdev = dev;
5441edd9bf3SJim Harris 	fs->send_request = send_request_fn;
5451edd9bf3SJim Harris 	TAILQ_INIT(&fs->files);
5461edd9bf3SJim Harris 
547267a4e1eSBen Walker 	fs->md_target.max_ops = 512;
548bc0180f6SSeth Howell 	spdk_io_device_register(&fs->md_target, fs_md_channel_create, fs_channel_destroy,
549c9402000SBen Walker 				sizeof(struct spdk_fs_channel), "blobfs_md");
550d969ac44SBen Walker 	fs->md_target.md_io_channel = spdk_get_io_channel(&fs->md_target);
551267a4e1eSBen Walker 	fs->md_target.md_fs_channel = spdk_io_channel_get_ctx(fs->md_target.md_io_channel);
5521edd9bf3SJim Harris 
553a3ab7610SBen Walker 	fs->sync_target.max_ops = 512;
554bc0180f6SSeth Howell 	spdk_io_device_register(&fs->sync_target, fs_sync_channel_create, fs_channel_destroy,
555c9402000SBen Walker 				sizeof(struct spdk_fs_channel), "blobfs_sync");
556d969ac44SBen Walker 	fs->sync_target.sync_io_channel = spdk_get_io_channel(&fs->sync_target);
557a3ab7610SBen Walker 	fs->sync_target.sync_fs_channel = spdk_io_channel_get_ctx(fs->sync_target.sync_io_channel);
5581edd9bf3SJim Harris 
5593b683c18SBen Walker 	fs->io_target.max_ops = 512;
560bc0180f6SSeth Howell 	spdk_io_device_register(&fs->io_target, fs_io_channel_create, fs_channel_destroy,
561c9402000SBen Walker 				sizeof(struct spdk_fs_channel), "blobfs_io");
5623b683c18SBen Walker 
5631edd9bf3SJim Harris 	return fs;
5641edd9bf3SJim Harris }
5651edd9bf3SJim Harris 
566f1e14ef4SChangpeng Liu static void
567f1e14ef4SChangpeng Liu __wake_caller(void *arg, int fserrno)
568f1e14ef4SChangpeng Liu {
569f1e14ef4SChangpeng Liu 	struct spdk_fs_cb_args *args = arg;
570f1e14ef4SChangpeng Liu 
571944a480eSJimboLuCN 	if ((args->rwerrno != NULL) && (*(args->rwerrno) == 0) && fserrno) {
572944a480eSJimboLuCN 		*(args->rwerrno) = fserrno;
573944a480eSJimboLuCN 	}
574f1e14ef4SChangpeng Liu 	args->rc = fserrno;
575f1e14ef4SChangpeng Liu 	sem_post(args->sem);
576f1e14ef4SChangpeng Liu }
577f1e14ef4SChangpeng Liu 
5781edd9bf3SJim Harris void
5796951b979SCunyin Chang spdk_fs_init(struct spdk_bs_dev *dev, struct spdk_blobfs_opts *opt,
5806951b979SCunyin Chang 	     fs_send_request_fn send_request_fn,
5811edd9bf3SJim Harris 	     spdk_fs_op_with_handle_complete cb_fn, void *cb_arg)
5821edd9bf3SJim Harris {
5831edd9bf3SJim Harris 	struct spdk_filesystem *fs;
5841edd9bf3SJim Harris 	struct spdk_fs_request *req;
5851edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
586eb8b1e20SMaciej Szwed 	struct spdk_bs_opts opts = {};
5871edd9bf3SJim Harris 
5881edd9bf3SJim Harris 	fs = fs_alloc(dev, send_request_fn);
5891edd9bf3SJim Harris 	if (fs == NULL) {
5901edd9bf3SJim Harris 		cb_fn(cb_arg, NULL, -ENOMEM);
5911edd9bf3SJim Harris 		return;
5921edd9bf3SJim Harris 	}
5931edd9bf3SJim Harris 
594267a4e1eSBen Walker 	req = alloc_fs_request(fs->md_target.md_fs_channel);
5951edd9bf3SJim Harris 	if (req == NULL) {
596bc0180f6SSeth Howell 		fs_free_io_channels(fs);
597bc0180f6SSeth Howell 		fs_io_device_unregister(fs);
5981edd9bf3SJim Harris 		cb_fn(cb_arg, NULL, -ENOMEM);
5991edd9bf3SJim Harris 		return;
6001edd9bf3SJim Harris 	}
6011edd9bf3SJim Harris 
6021edd9bf3SJim Harris 	args = &req->args;
6031edd9bf3SJim Harris 	args->fn.fs_op_with_handle = cb_fn;
6041edd9bf3SJim Harris 	args->arg = cb_arg;
6051edd9bf3SJim Harris 	args->fs = fs;
6061edd9bf3SJim Harris 
6073de9887dSZiye Yang 	spdk_bs_opts_init(&opts, sizeof(opts));
60862202ddaSChangpeng Liu 	snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), SPDK_BLOBFS_SIGNATURE);
6096951b979SCunyin Chang 	if (opt) {
6106951b979SCunyin Chang 		opts.cluster_sz = opt->cluster_sz;
6116951b979SCunyin Chang 	}
612eb8b1e20SMaciej Szwed 	spdk_bs_init(dev, &opts, init_cb, req);
6131edd9bf3SJim Harris }
6141edd9bf3SJim Harris 
6151edd9bf3SJim Harris static struct spdk_file *
6161edd9bf3SJim Harris file_alloc(struct spdk_filesystem *fs)
6171edd9bf3SJim Harris {
6181edd9bf3SJim Harris 	struct spdk_file *file;
6191edd9bf3SJim Harris 
6201edd9bf3SJim Harris 	file = calloc(1, sizeof(*file));
6211edd9bf3SJim Harris 	if (file == NULL) {
6221edd9bf3SJim Harris 		return NULL;
6231edd9bf3SJim Harris 	}
6241edd9bf3SJim Harris 
625402288acSZiye Yang 	file->tree = calloc(1, sizeof(*file->tree));
626402288acSZiye Yang 	if (file->tree == NULL) {
627402288acSZiye Yang 		free(file);
628402288acSZiye Yang 		return NULL;
629402288acSZiye Yang 	}
630402288acSZiye Yang 
6317192849eSSeth Howell 	if (pthread_spin_init(&file->lock, 0)) {
6327192849eSSeth Howell 		free(file->tree);
6337192849eSSeth Howell 		free(file);
6347192849eSSeth Howell 		return NULL;
6357192849eSSeth Howell 	}
6367192849eSSeth Howell 
6371edd9bf3SJim Harris 	file->fs = fs;
6381edd9bf3SJim Harris 	TAILQ_INIT(&file->open_requests);
6391edd9bf3SJim Harris 	TAILQ_INIT(&file->sync_requests);
6401edd9bf3SJim Harris 	TAILQ_INSERT_TAIL(&fs->files, file, tailq);
6411edd9bf3SJim Harris 	file->priority = SPDK_FILE_PRIORITY_LOW;
6421edd9bf3SJim Harris 	return file;
6431edd9bf3SJim Harris }
6441edd9bf3SJim Harris 
64598160717SJim Harris static void fs_load_done(void *ctx, int bserrno);
6462d18887fSCunyin Chang 
6472d18887fSCunyin Chang static int
6482d18887fSCunyin Chang _handle_deleted_files(struct spdk_fs_request *req)
6492d18887fSCunyin Chang {
6502d18887fSCunyin Chang 	struct spdk_fs_cb_args *args = &req->args;
6512d18887fSCunyin Chang 	struct spdk_filesystem *fs = args->fs;
6522d18887fSCunyin Chang 
6532d18887fSCunyin Chang 	if (!TAILQ_EMPTY(&args->op.fs_load.deleted_files)) {
6542d18887fSCunyin Chang 		struct spdk_deleted_file *deleted_file;
6552d18887fSCunyin Chang 
6562d18887fSCunyin Chang 		deleted_file = TAILQ_FIRST(&args->op.fs_load.deleted_files);
6572d18887fSCunyin Chang 		TAILQ_REMOVE(&args->op.fs_load.deleted_files, deleted_file, tailq);
65898160717SJim Harris 		spdk_bs_delete_blob(fs->bs, deleted_file->id, fs_load_done, req);
6592d18887fSCunyin Chang 		free(deleted_file);
6602d18887fSCunyin Chang 		return 0;
6612d18887fSCunyin Chang 	}
6622d18887fSCunyin Chang 
6632d18887fSCunyin Chang 	return 1;
6642d18887fSCunyin Chang }
6652d18887fSCunyin Chang 
6662d18887fSCunyin Chang static void
66798160717SJim Harris fs_load_done(void *ctx, int bserrno)
6682d18887fSCunyin Chang {
6692d18887fSCunyin Chang 	struct spdk_fs_request *req = ctx;
6702d18887fSCunyin Chang 	struct spdk_fs_cb_args *args = &req->args;
6712d18887fSCunyin Chang 	struct spdk_filesystem *fs = args->fs;
6722d18887fSCunyin Chang 
67398160717SJim Harris 	/* The filesystem has been loaded.  Now check if there are any files that
67498160717SJim Harris 	 *  were marked for deletion before last unload.  Do not complete the
67598160717SJim Harris 	 *  fs_load callback until all of them have been deleted on disk.
67698160717SJim Harris 	 */
67759970a89SDaniel Verkamp 	if (_handle_deleted_files(req) == 0) {
67898160717SJim Harris 		/* We found a file that's been marked for deleting but not actually
67998160717SJim Harris 		 *  deleted yet.  This function will get called again once the delete
68098160717SJim Harris 		 *  operation is completed.
68198160717SJim Harris 		 */
6822d18887fSCunyin Chang 		return;
68359970a89SDaniel Verkamp 	}
6842d18887fSCunyin Chang 
6852d18887fSCunyin Chang 	args->fn.fs_op_with_handle(args->arg, fs, 0);
6862d18887fSCunyin Chang 	free_fs_request(req);
6872d18887fSCunyin Chang 
6882d18887fSCunyin Chang }
6892d18887fSCunyin Chang 
6901edd9bf3SJim Harris static void
6911edd9bf3SJim Harris iter_cb(void *ctx, struct spdk_blob *blob, int rc)
6921edd9bf3SJim Harris {
6931edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
6941edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
6951edd9bf3SJim Harris 	struct spdk_filesystem *fs = args->fs;
6961edd9bf3SJim Harris 	uint64_t *length;
6971edd9bf3SJim Harris 	const char *name;
6982d18887fSCunyin Chang 	uint32_t *is_deleted;
6991edd9bf3SJim Harris 	size_t value_len;
7001edd9bf3SJim Harris 
701d1165a65SJim Harris 	if (rc < 0) {
7021edd9bf3SJim Harris 		args->fn.fs_op_with_handle(args->arg, fs, rc);
7031edd9bf3SJim Harris 		free_fs_request(req);
7041edd9bf3SJim Harris 		return;
7051edd9bf3SJim Harris 	}
7061edd9bf3SJim Harris 
7072c3591f1SJim Harris 	rc = spdk_blob_get_xattr_value(blob, "name", (const void **)&name, &value_len);
7081edd9bf3SJim Harris 	if (rc < 0) {
7091edd9bf3SJim Harris 		args->fn.fs_op_with_handle(args->arg, fs, rc);
7101edd9bf3SJim Harris 		free_fs_request(req);
7111edd9bf3SJim Harris 		return;
7121edd9bf3SJim Harris 	}
7131edd9bf3SJim Harris 
7142c3591f1SJim Harris 	rc = spdk_blob_get_xattr_value(blob, "length", (const void **)&length, &value_len);
7151edd9bf3SJim Harris 	if (rc < 0) {
7161edd9bf3SJim Harris 		args->fn.fs_op_with_handle(args->arg, fs, rc);
7171edd9bf3SJim Harris 		free_fs_request(req);
7181edd9bf3SJim Harris 		return;
7191edd9bf3SJim Harris 	}
7202d18887fSCunyin Chang 
7211edd9bf3SJim Harris 	assert(value_len == 8);
7221edd9bf3SJim Harris 
7232d18887fSCunyin Chang 	/* This file could be deleted last time without close it, then app crashed, so we delete it now */
7242c3591f1SJim Harris 	rc = spdk_blob_get_xattr_value(blob, "is_deleted", (const void **)&is_deleted, &value_len);
7252d18887fSCunyin Chang 	if (rc < 0) {
7262d18887fSCunyin Chang 		struct spdk_file *f;
7272d18887fSCunyin Chang 
7281edd9bf3SJim Harris 		f = file_alloc(fs);
7291edd9bf3SJim Harris 		if (f == NULL) {
730a7317317SZiye Yang 			SPDK_ERRLOG("Cannot allocate file to handle deleted file on disk\n");
7311edd9bf3SJim Harris 			args->fn.fs_op_with_handle(args->arg, fs, -ENOMEM);
7321edd9bf3SJim Harris 			free_fs_request(req);
7331edd9bf3SJim Harris 			return;
7341edd9bf3SJim Harris 		}
7351edd9bf3SJim Harris 
7361edd9bf3SJim Harris 		f->name = strdup(name);
73757eee182Syidong0635 		if (!f->name) {
73857eee182Syidong0635 			SPDK_ERRLOG("Cannot allocate memory for file name\n");
73957eee182Syidong0635 			args->fn.fs_op_with_handle(args->arg, fs, -ENOMEM);
74057eee182Syidong0635 			free_fs_request(req);
74157eee182Syidong0635 			file_free(f);
74257eee182Syidong0635 			return;
74357eee182Syidong0635 		}
74457eee182Syidong0635 
7451edd9bf3SJim Harris 		f->blobid = spdk_blob_get_id(blob);
7461edd9bf3SJim Harris 		f->length = *length;
7471edd9bf3SJim Harris 		f->length_flushed = *length;
748e967dcd2SJim Harris 		f->length_xattr = *length;
7491edd9bf3SJim Harris 		f->append_pos = *length;
7502172c432STomasz Zawadzki 		SPDK_DEBUGLOG(blobfs, "added file %s length=%ju\n", f->name, f->length);
7512d18887fSCunyin Chang 	} else {
7522d18887fSCunyin Chang 		struct spdk_deleted_file *deleted_file;
7532d18887fSCunyin Chang 
7542d18887fSCunyin Chang 		deleted_file = calloc(1, sizeof(*deleted_file));
7552d18887fSCunyin Chang 		if (deleted_file == NULL) {
7562d18887fSCunyin Chang 			args->fn.fs_op_with_handle(args->arg, fs, -ENOMEM);
7572d18887fSCunyin Chang 			free_fs_request(req);
7582d18887fSCunyin Chang 			return;
7592d18887fSCunyin Chang 		}
7602d18887fSCunyin Chang 		deleted_file->id = spdk_blob_get_id(blob);
7612d18887fSCunyin Chang 		TAILQ_INSERT_TAIL(&args->op.fs_load.deleted_files, deleted_file, tailq);
7622d18887fSCunyin Chang 	}
7631edd9bf3SJim Harris }
7641edd9bf3SJim Harris 
7651edd9bf3SJim Harris static void
7661edd9bf3SJim Harris load_cb(void *ctx, struct spdk_blob_store *bs, int bserrno)
7671edd9bf3SJim Harris {
7681edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
7691edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
7701edd9bf3SJim Harris 	struct spdk_filesystem *fs = args->fs;
771eb8b1e20SMaciej Szwed 	struct spdk_bs_type bstype;
77262202ddaSChangpeng Liu 	static const struct spdk_bs_type blobfs_type = {SPDK_BLOBFS_SIGNATURE};
773450e2b88SDaniel Verkamp 	static const struct spdk_bs_type zeros;
7741edd9bf3SJim Harris 
7751edd9bf3SJim Harris 	if (bserrno != 0) {
7761edd9bf3SJim Harris 		args->fn.fs_op_with_handle(args->arg, NULL, bserrno);
7771edd9bf3SJim Harris 		free_fs_request(req);
778bc0180f6SSeth Howell 		fs_free_io_channels(fs);
779bc0180f6SSeth Howell 		fs_io_device_unregister(fs);
7801edd9bf3SJim Harris 		return;
7811edd9bf3SJim Harris 	}
7821edd9bf3SJim Harris 
783eb8b1e20SMaciej Szwed 	bstype = spdk_bs_get_bstype(bs);
784eb8b1e20SMaciej Szwed 
785450e2b88SDaniel Verkamp 	if (!memcmp(&bstype, &zeros, sizeof(bstype))) {
7862172c432STomasz Zawadzki 		SPDK_DEBUGLOG(blobfs, "assigning bstype\n");
787450e2b88SDaniel Verkamp 		spdk_bs_set_bstype(bs, blobfs_type);
788450e2b88SDaniel Verkamp 	} else if (memcmp(&bstype, &blobfs_type, sizeof(bstype))) {
7895adac19aSChangpeng Liu 		SPDK_ERRLOG("not blobfs\n");
7902172c432STomasz Zawadzki 		SPDK_LOGDUMP(blobfs, "bstype", &bstype, sizeof(bstype));
7915adac19aSChangpeng Liu 		args->fn.fs_op_with_handle(args->arg, NULL, -EINVAL);
792eb8b1e20SMaciej Szwed 		free_fs_request(req);
793bc0180f6SSeth Howell 		fs_free_io_channels(fs);
794bc0180f6SSeth Howell 		fs_io_device_unregister(fs);
795eb8b1e20SMaciej Szwed 		return;
796eb8b1e20SMaciej Szwed 	}
797eb8b1e20SMaciej Szwed 
7981edd9bf3SJim Harris 	common_fs_bs_init(fs, bs);
79998160717SJim Harris 	fs_load_done(req, 0);
8001edd9bf3SJim Harris }
8011edd9bf3SJim Harris 
802d0b13460SZiye Yang static void
803bc0180f6SSeth Howell fs_io_device_unregister(struct spdk_filesystem *fs)
804d0b13460SZiye Yang {
805d0b13460SZiye Yang 	assert(fs != NULL);
806d0b13460SZiye Yang 	spdk_io_device_unregister(&fs->md_target, NULL);
807d0b13460SZiye Yang 	spdk_io_device_unregister(&fs->sync_target, NULL);
808d0b13460SZiye Yang 	spdk_io_device_unregister(&fs->io_target, NULL);
809d0b13460SZiye Yang 	free(fs);
810d0b13460SZiye Yang }
811d0b13460SZiye Yang 
812d0b13460SZiye Yang static void
813bc0180f6SSeth Howell fs_free_io_channels(struct spdk_filesystem *fs)
814d0b13460SZiye Yang {
815d0b13460SZiye Yang 	assert(fs != NULL);
816d0b13460SZiye Yang 	spdk_fs_free_io_channel(fs->md_target.md_io_channel);
817d0b13460SZiye Yang 	spdk_fs_free_io_channel(fs->sync_target.sync_io_channel);
818d0b13460SZiye Yang }
819d0b13460SZiye Yang 
8201edd9bf3SJim Harris void
8211edd9bf3SJim Harris spdk_fs_load(struct spdk_bs_dev *dev, fs_send_request_fn send_request_fn,
8221edd9bf3SJim Harris 	     spdk_fs_op_with_handle_complete cb_fn, void *cb_arg)
8231edd9bf3SJim Harris {
8241edd9bf3SJim Harris 	struct spdk_filesystem *fs;
8251edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
8261edd9bf3SJim Harris 	struct spdk_fs_request *req;
827d1165a65SJim Harris 	struct spdk_bs_opts	bs_opts;
8281edd9bf3SJim Harris 
8291edd9bf3SJim Harris 	fs = fs_alloc(dev, send_request_fn);
8301edd9bf3SJim Harris 	if (fs == NULL) {
8311edd9bf3SJim Harris 		cb_fn(cb_arg, NULL, -ENOMEM);
8321edd9bf3SJim Harris 		return;
8331edd9bf3SJim Harris 	}
8341edd9bf3SJim Harris 
835267a4e1eSBen Walker 	req = alloc_fs_request(fs->md_target.md_fs_channel);
8361edd9bf3SJim Harris 	if (req == NULL) {
837bc0180f6SSeth Howell 		fs_free_io_channels(fs);
838bc0180f6SSeth Howell 		fs_io_device_unregister(fs);
8391edd9bf3SJim Harris 		cb_fn(cb_arg, NULL, -ENOMEM);
8401edd9bf3SJim Harris 		return;
8411edd9bf3SJim Harris 	}
8421edd9bf3SJim Harris 
8431edd9bf3SJim Harris 	args = &req->args;
8441edd9bf3SJim Harris 	args->fn.fs_op_with_handle = cb_fn;
8451edd9bf3SJim Harris 	args->arg = cb_arg;
8461edd9bf3SJim Harris 	args->fs = fs;
8472d18887fSCunyin Chang 	TAILQ_INIT(&args->op.fs_load.deleted_files);
8483de9887dSZiye Yang 	spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
849d1165a65SJim Harris 	bs_opts.iter_cb_fn = iter_cb;
850d1165a65SJim Harris 	bs_opts.iter_cb_arg = req;
851d1165a65SJim Harris 	spdk_bs_load(dev, &bs_opts, load_cb, req);
8521edd9bf3SJim Harris }
8531edd9bf3SJim Harris 
8541edd9bf3SJim Harris static void
8551edd9bf3SJim Harris unload_cb(void *ctx, int bserrno)
8561edd9bf3SJim Harris {
8571edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
8581edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
8591edd9bf3SJim Harris 	struct spdk_filesystem *fs = args->fs;
860546d8ab2SChangpeng Liu 	struct spdk_file *file, *tmp;
861546d8ab2SChangpeng Liu 
862546d8ab2SChangpeng Liu 	TAILQ_FOREACH_SAFE(file, &fs->files, tailq, tmp) {
863546d8ab2SChangpeng Liu 		TAILQ_REMOVE(&fs->files, file, tailq);
86487d5d832SChangpeng Liu 		file_free(file);
865546d8ab2SChangpeng Liu 	}
8661edd9bf3SJim Harris 
8670841addaSChangpeng Liu 	free_global_cache();
868e045a02cSJim Harris 
8691edd9bf3SJim Harris 	args->fn.fs_op(args->arg, bserrno);
8701edd9bf3SJim Harris 	free(req);
871267a4e1eSBen Walker 
872bc0180f6SSeth Howell 	fs_io_device_unregister(fs);
8731edd9bf3SJim Harris }
8741edd9bf3SJim Harris 
8751edd9bf3SJim Harris void
8761edd9bf3SJim Harris spdk_fs_unload(struct spdk_filesystem *fs, spdk_fs_op_complete cb_fn, void *cb_arg)
8771edd9bf3SJim Harris {
8781edd9bf3SJim Harris 	struct spdk_fs_request *req;
8791edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
8801edd9bf3SJim Harris 
8811edd9bf3SJim Harris 	/*
8821edd9bf3SJim Harris 	 * We must free the md_channel before unloading the blobstore, so just
8831edd9bf3SJim Harris 	 *  allocate this request from the general heap.
8841edd9bf3SJim Harris 	 */
8851edd9bf3SJim Harris 	req = calloc(1, sizeof(*req));
8861edd9bf3SJim Harris 	if (req == NULL) {
8871edd9bf3SJim Harris 		cb_fn(cb_arg, -ENOMEM);
8881edd9bf3SJim Harris 		return;
8891edd9bf3SJim Harris 	}
8901edd9bf3SJim Harris 
8911edd9bf3SJim Harris 	args = &req->args;
8921edd9bf3SJim Harris 	args->fn.fs_op = cb_fn;
8931edd9bf3SJim Harris 	args->arg = cb_arg;
8941edd9bf3SJim Harris 	args->fs = fs;
8951edd9bf3SJim Harris 
896bc0180f6SSeth Howell 	fs_free_io_channels(fs);
8971edd9bf3SJim Harris 	spdk_bs_unload(fs->bs, unload_cb, req);
8981edd9bf3SJim Harris }
8991edd9bf3SJim Harris 
9001edd9bf3SJim Harris static struct spdk_file *
9011edd9bf3SJim Harris fs_find_file(struct spdk_filesystem *fs, const char *name)
9021edd9bf3SJim Harris {
9031edd9bf3SJim Harris 	struct spdk_file *file;
9041edd9bf3SJim Harris 
9051edd9bf3SJim Harris 	TAILQ_FOREACH(file, &fs->files, tailq) {
9061edd9bf3SJim Harris 		if (!strncmp(name, file->name, SPDK_FILE_NAME_MAX)) {
9071edd9bf3SJim Harris 			return file;
9081edd9bf3SJim Harris 		}
9091edd9bf3SJim Harris 	}
9101edd9bf3SJim Harris 
9111edd9bf3SJim Harris 	return NULL;
9121edd9bf3SJim Harris }
9131edd9bf3SJim Harris 
9141edd9bf3SJim Harris void
9151edd9bf3SJim Harris spdk_fs_file_stat_async(struct spdk_filesystem *fs, const char *name,
9161edd9bf3SJim Harris 			spdk_file_stat_op_complete cb_fn, void *cb_arg)
9171edd9bf3SJim Harris {
9181edd9bf3SJim Harris 	struct spdk_file_stat stat;
9191edd9bf3SJim Harris 	struct spdk_file *f = NULL;
9201edd9bf3SJim Harris 
9211edd9bf3SJim Harris 	if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) {
9221edd9bf3SJim Harris 		cb_fn(cb_arg, NULL, -ENAMETOOLONG);
9231edd9bf3SJim Harris 		return;
9241edd9bf3SJim Harris 	}
9251edd9bf3SJim Harris 
9261edd9bf3SJim Harris 	f = fs_find_file(fs, name);
9271edd9bf3SJim Harris 	if (f != NULL) {
9281edd9bf3SJim Harris 		stat.blobid = f->blobid;
9290e48ef40SCunyin Chang 		stat.size = f->append_pos >= f->length ? f->append_pos : f->length;
9301edd9bf3SJim Harris 		cb_fn(cb_arg, &stat, 0);
9311edd9bf3SJim Harris 		return;
9321edd9bf3SJim Harris 	}
9331edd9bf3SJim Harris 
9341edd9bf3SJim Harris 	cb_fn(cb_arg, NULL, -ENOENT);
9351edd9bf3SJim Harris }
9361edd9bf3SJim Harris 
9371edd9bf3SJim Harris static void
9381edd9bf3SJim Harris __copy_stat(void *arg, struct spdk_file_stat *stat, int fserrno)
9391edd9bf3SJim Harris {
9401edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
9411edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
9421edd9bf3SJim Harris 
9431edd9bf3SJim Harris 	args->rc = fserrno;
9441edd9bf3SJim Harris 	if (fserrno == 0) {
9451edd9bf3SJim Harris 		memcpy(args->arg, stat, sizeof(*stat));
9461edd9bf3SJim Harris 	}
9471edd9bf3SJim Harris 	sem_post(args->sem);
9481edd9bf3SJim Harris }
9491edd9bf3SJim Harris 
9501edd9bf3SJim Harris static void
9511edd9bf3SJim Harris __file_stat(void *arg)
9521edd9bf3SJim Harris {
9531edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
9541edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
9551edd9bf3SJim Harris 
9561edd9bf3SJim Harris 	spdk_fs_file_stat_async(args->fs, args->op.stat.name,
9571edd9bf3SJim Harris 				args->fn.stat_op, req);
9581edd9bf3SJim Harris }
9591edd9bf3SJim Harris 
9601edd9bf3SJim Harris int
961e9d400d5SBen Walker spdk_fs_file_stat(struct spdk_filesystem *fs, struct spdk_fs_thread_ctx *ctx,
9621edd9bf3SJim Harris 		  const char *name, struct spdk_file_stat *stat)
9631edd9bf3SJim Harris {
964e9d400d5SBen Walker 	struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
9651edd9bf3SJim Harris 	struct spdk_fs_request *req;
9661edd9bf3SJim Harris 	int rc;
9671edd9bf3SJim Harris 
9681edd9bf3SJim Harris 	req = alloc_fs_request(channel);
9690de89b36SZiye Yang 	if (req == NULL) {
970a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate stat req on file=%s\n", name);
9710de89b36SZiye Yang 		return -ENOMEM;
9720de89b36SZiye Yang 	}
9731edd9bf3SJim Harris 
9741edd9bf3SJim Harris 	req->args.fs = fs;
9751edd9bf3SJim Harris 	req->args.op.stat.name = name;
9761edd9bf3SJim Harris 	req->args.fn.stat_op = __copy_stat;
9771edd9bf3SJim Harris 	req->args.arg = stat;
9781edd9bf3SJim Harris 	req->args.sem = &channel->sem;
9791edd9bf3SJim Harris 	channel->send_request(__file_stat, req);
9801edd9bf3SJim Harris 	sem_wait(&channel->sem);
9811edd9bf3SJim Harris 
9821edd9bf3SJim Harris 	rc = req->args.rc;
9831edd9bf3SJim Harris 	free_fs_request(req);
9841edd9bf3SJim Harris 
9851edd9bf3SJim Harris 	return rc;
9861edd9bf3SJim Harris }
9871edd9bf3SJim Harris 
9881edd9bf3SJim Harris static void
9891edd9bf3SJim Harris fs_create_blob_close_cb(void *ctx, int bserrno)
9901edd9bf3SJim Harris {
991f1e14ef4SChangpeng Liu 	int rc;
9921edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
9931edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
9941edd9bf3SJim Harris 
995f1e14ef4SChangpeng Liu 	rc = args->rc ? args->rc : bserrno;
996f1e14ef4SChangpeng Liu 	args->fn.file_op(args->arg, rc);
9971edd9bf3SJim Harris 	free_fs_request(req);
9981edd9bf3SJim Harris }
9991edd9bf3SJim Harris 
10001edd9bf3SJim Harris static void
1001463925ffSJim Harris fs_create_blob_resize_cb(void *ctx, int bserrno)
10021edd9bf3SJim Harris {
10031edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
10041edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
10051edd9bf3SJim Harris 	struct spdk_file *f = args->file;
1006463925ffSJim Harris 	struct spdk_blob *blob = args->op.create.blob;
10071edd9bf3SJim Harris 	uint64_t length = 0;
10081edd9bf3SJim Harris 
1009f1e14ef4SChangpeng Liu 	args->rc = bserrno;
1010f1e14ef4SChangpeng Liu 	if (bserrno) {
1011f1e14ef4SChangpeng Liu 		spdk_blob_close(blob, fs_create_blob_close_cb, args);
1012f1e14ef4SChangpeng Liu 		return;
1013f1e14ef4SChangpeng Liu 	}
1014f1e14ef4SChangpeng Liu 
10152c3591f1SJim Harris 	spdk_blob_set_xattr(blob, "name", f->name, strlen(f->name) + 1);
10162c3591f1SJim Harris 	spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
10171edd9bf3SJim Harris 
1018e734bb9fSJim Harris 	spdk_blob_close(blob, fs_create_blob_close_cb, args);
10191edd9bf3SJim Harris }
10201edd9bf3SJim Harris 
10211edd9bf3SJim Harris static void
1022463925ffSJim Harris fs_create_blob_open_cb(void *ctx, struct spdk_blob *blob, int bserrno)
1023463925ffSJim Harris {
1024463925ffSJim Harris 	struct spdk_fs_request *req = ctx;
1025463925ffSJim Harris 	struct spdk_fs_cb_args *args = &req->args;
1026463925ffSJim Harris 
1027f1e14ef4SChangpeng Liu 	if (bserrno) {
1028f1e14ef4SChangpeng Liu 		args->fn.file_op(args->arg, bserrno);
1029f1e14ef4SChangpeng Liu 		free_fs_request(req);
1030f1e14ef4SChangpeng Liu 		return;
1031f1e14ef4SChangpeng Liu 	}
1032f1e14ef4SChangpeng Liu 
1033463925ffSJim Harris 	args->op.create.blob = blob;
1034463925ffSJim Harris 	spdk_blob_resize(blob, 1, fs_create_blob_resize_cb, req);
1035463925ffSJim Harris }
1036463925ffSJim Harris 
1037463925ffSJim Harris static void
10381edd9bf3SJim Harris fs_create_blob_create_cb(void *ctx, spdk_blob_id blobid, int bserrno)
10391edd9bf3SJim Harris {
10401edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
10411edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
10421edd9bf3SJim Harris 	struct spdk_file *f = args->file;
10431edd9bf3SJim Harris 
1044f1e14ef4SChangpeng Liu 	if (bserrno) {
1045f1e14ef4SChangpeng Liu 		args->fn.file_op(args->arg, bserrno);
1046f1e14ef4SChangpeng Liu 		free_fs_request(req);
1047f1e14ef4SChangpeng Liu 		return;
1048f1e14ef4SChangpeng Liu 	}
1049f1e14ef4SChangpeng Liu 
10501edd9bf3SJim Harris 	f->blobid = blobid;
1051d52dbda2SJim Harris 	spdk_bs_open_blob(f->fs->bs, blobid, fs_create_blob_open_cb, req);
10521edd9bf3SJim Harris }
10531edd9bf3SJim Harris 
10541edd9bf3SJim Harris void
10551edd9bf3SJim Harris spdk_fs_create_file_async(struct spdk_filesystem *fs, const char *name,
10561edd9bf3SJim Harris 			  spdk_file_op_complete cb_fn, void *cb_arg)
10571edd9bf3SJim Harris {
10581edd9bf3SJim Harris 	struct spdk_file *file;
10591edd9bf3SJim Harris 	struct spdk_fs_request *req;
10601edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
10611edd9bf3SJim Harris 
10621edd9bf3SJim Harris 	if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) {
10631edd9bf3SJim Harris 		cb_fn(cb_arg, -ENAMETOOLONG);
10641edd9bf3SJim Harris 		return;
10651edd9bf3SJim Harris 	}
10661edd9bf3SJim Harris 
10671edd9bf3SJim Harris 	file = fs_find_file(fs, name);
10681edd9bf3SJim Harris 	if (file != NULL) {
10691edd9bf3SJim Harris 		cb_fn(cb_arg, -EEXIST);
10701edd9bf3SJim Harris 		return;
10711edd9bf3SJim Harris 	}
10721edd9bf3SJim Harris 
10731edd9bf3SJim Harris 	file = file_alloc(fs);
10741edd9bf3SJim Harris 	if (file == NULL) {
1075a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate new file for creation\n");
10761edd9bf3SJim Harris 		cb_fn(cb_arg, -ENOMEM);
10771edd9bf3SJim Harris 		return;
10781edd9bf3SJim Harris 	}
10791edd9bf3SJim Harris 
1080267a4e1eSBen Walker 	req = alloc_fs_request(fs->md_target.md_fs_channel);
10811edd9bf3SJim Harris 	if (req == NULL) {
1082a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate create async req for file=%s\n", name);
10832ef4855eSZhiqiang Liu 		TAILQ_REMOVE(&fs->files, file, tailq);
10842ef4855eSZhiqiang Liu 		file_free(file);
10851edd9bf3SJim Harris 		cb_fn(cb_arg, -ENOMEM);
10861edd9bf3SJim Harris 		return;
10871edd9bf3SJim Harris 	}
10881edd9bf3SJim Harris 
10891edd9bf3SJim Harris 	args = &req->args;
10901edd9bf3SJim Harris 	args->file = file;
10911edd9bf3SJim Harris 	args->fn.file_op = cb_fn;
10921edd9bf3SJim Harris 	args->arg = cb_arg;
10931edd9bf3SJim Harris 
10941edd9bf3SJim Harris 	file->name = strdup(name);
10952ef4855eSZhiqiang Liu 	if (!file->name) {
10962ef4855eSZhiqiang Liu 		SPDK_ERRLOG("Cannot allocate file->name for file=%s\n", name);
10972ef4855eSZhiqiang Liu 		free_fs_request(req);
10982ef4855eSZhiqiang Liu 		TAILQ_REMOVE(&fs->files, file, tailq);
10992ef4855eSZhiqiang Liu 		file_free(file);
11002ef4855eSZhiqiang Liu 		cb_fn(cb_arg, -ENOMEM);
11012ef4855eSZhiqiang Liu 		return;
11022ef4855eSZhiqiang Liu 	}
1103d52dbda2SJim Harris 	spdk_bs_create_blob(fs->bs, fs_create_blob_create_cb, args);
11041edd9bf3SJim Harris }
11051edd9bf3SJim Harris 
11061edd9bf3SJim Harris static void
11071edd9bf3SJim Harris __fs_create_file_done(void *arg, int fserrno)
11081edd9bf3SJim Harris {
11091edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
11101edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
11111edd9bf3SJim Harris 
11122172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s\n", args->op.create.name);
111377a523e4Shgy 	__wake_caller(args, fserrno);
11141edd9bf3SJim Harris }
11151edd9bf3SJim Harris 
11161edd9bf3SJim Harris static void
11171edd9bf3SJim Harris __fs_create_file(void *arg)
11181edd9bf3SJim Harris {
11191edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
11201edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
11211edd9bf3SJim Harris 
11222172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s\n", args->op.create.name);
11231edd9bf3SJim Harris 	spdk_fs_create_file_async(args->fs, args->op.create.name, __fs_create_file_done, req);
11241edd9bf3SJim Harris }
11251edd9bf3SJim Harris 
11261edd9bf3SJim Harris int
1127e9d400d5SBen Walker spdk_fs_create_file(struct spdk_filesystem *fs, struct spdk_fs_thread_ctx *ctx, const char *name)
11281edd9bf3SJim Harris {
1129e9d400d5SBen Walker 	struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
11301edd9bf3SJim Harris 	struct spdk_fs_request *req;
11311edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
11321edd9bf3SJim Harris 	int rc;
11331edd9bf3SJim Harris 
11342172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s\n", name);
11351edd9bf3SJim Harris 
11361edd9bf3SJim Harris 	req = alloc_fs_request(channel);
11370de89b36SZiye Yang 	if (req == NULL) {
1138a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate req to create file=%s\n", name);
11390de89b36SZiye Yang 		return -ENOMEM;
11400de89b36SZiye Yang 	}
11411edd9bf3SJim Harris 
11421edd9bf3SJim Harris 	args = &req->args;
11431edd9bf3SJim Harris 	args->fs = fs;
11441edd9bf3SJim Harris 	args->op.create.name = name;
11451edd9bf3SJim Harris 	args->sem = &channel->sem;
11461edd9bf3SJim Harris 	fs->send_request(__fs_create_file, req);
11471edd9bf3SJim Harris 	sem_wait(&channel->sem);
11481edd9bf3SJim Harris 	rc = args->rc;
11491edd9bf3SJim Harris 	free_fs_request(req);
11501edd9bf3SJim Harris 
11511edd9bf3SJim Harris 	return rc;
11521edd9bf3SJim Harris }
11531edd9bf3SJim Harris 
11541edd9bf3SJim Harris static void
11551edd9bf3SJim Harris fs_open_blob_done(void *ctx, struct spdk_blob *blob, int bserrno)
11561edd9bf3SJim Harris {
11571edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
11581edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
11591edd9bf3SJim Harris 	struct spdk_file *f = args->file;
11601edd9bf3SJim Harris 
11611edd9bf3SJim Harris 	f->blob = blob;
11621edd9bf3SJim Harris 	while (!TAILQ_EMPTY(&f->open_requests)) {
11631edd9bf3SJim Harris 		req = TAILQ_FIRST(&f->open_requests);
11641edd9bf3SJim Harris 		args = &req->args;
11651edd9bf3SJim Harris 		TAILQ_REMOVE(&f->open_requests, req, args.op.open.tailq);
11663e158bd5SKonrad Sztyber 		spdk_trace_record(TRACE_BLOBFS_OPEN, 0, 0, 0, f->name);
11671edd9bf3SJim Harris 		args->fn.file_op_with_handle(args->arg, f, bserrno);
11681edd9bf3SJim Harris 		free_fs_request(req);
11691edd9bf3SJim Harris 	}
11701edd9bf3SJim Harris }
11711edd9bf3SJim Harris 
11721edd9bf3SJim Harris static void
11731edd9bf3SJim Harris fs_open_blob_create_cb(void *ctx, int bserrno)
11741edd9bf3SJim Harris {
11751edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
11761edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
11771edd9bf3SJim Harris 	struct spdk_file *file = args->file;
11781edd9bf3SJim Harris 	struct spdk_filesystem *fs = args->fs;
11791edd9bf3SJim Harris 
11801edd9bf3SJim Harris 	if (file == NULL) {
11817079a18fSJim Harris 		/*
11827079a18fSJim Harris 		 * This is from an open with CREATE flag - the file
11837079a18fSJim Harris 		 *  is now created so look it up in the file list for this
11847079a18fSJim Harris 		 *  filesystem.
11857079a18fSJim Harris 		 */
11861edd9bf3SJim Harris 		file = fs_find_file(fs, args->op.open.name);
11877079a18fSJim Harris 		assert(file != NULL);
11881edd9bf3SJim Harris 		args->file = file;
11891edd9bf3SJim Harris 	}
11901edd9bf3SJim Harris 
11911edd9bf3SJim Harris 	file->ref_count++;
11921edd9bf3SJim Harris 	TAILQ_INSERT_TAIL(&file->open_requests, req, args.op.open.tailq);
11931edd9bf3SJim Harris 	if (file->ref_count == 1) {
11941edd9bf3SJim Harris 		assert(file->blob == NULL);
1195d52dbda2SJim Harris 		spdk_bs_open_blob(fs->bs, file->blobid, fs_open_blob_done, req);
11961edd9bf3SJim Harris 	} else if (file->blob != NULL) {
11971edd9bf3SJim Harris 		fs_open_blob_done(req, file->blob, 0);
11981edd9bf3SJim Harris 	} else {
11991edd9bf3SJim Harris 		/*
12001edd9bf3SJim Harris 		 * The blob open for this file is in progress due to a previous
12011edd9bf3SJim Harris 		 *  open request.  When that open completes, it will invoke the
12021edd9bf3SJim Harris 		 *  open callback for this request.
12031edd9bf3SJim Harris 		 */
12041edd9bf3SJim Harris 	}
12051edd9bf3SJim Harris }
12061edd9bf3SJim Harris 
12071edd9bf3SJim Harris void
12081edd9bf3SJim Harris spdk_fs_open_file_async(struct spdk_filesystem *fs, const char *name, uint32_t flags,
12091edd9bf3SJim Harris 			spdk_file_op_with_handle_complete cb_fn, void *cb_arg)
12101edd9bf3SJim Harris {
12111edd9bf3SJim Harris 	struct spdk_file *f = NULL;
12121edd9bf3SJim Harris 	struct spdk_fs_request *req;
12131edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
12141edd9bf3SJim Harris 
12151edd9bf3SJim Harris 	if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) {
12161edd9bf3SJim Harris 		cb_fn(cb_arg, NULL, -ENAMETOOLONG);
12171edd9bf3SJim Harris 		return;
12181edd9bf3SJim Harris 	}
12191edd9bf3SJim Harris 
12201edd9bf3SJim Harris 	f = fs_find_file(fs, name);
12211edd9bf3SJim Harris 	if (f == NULL && !(flags & SPDK_BLOBFS_OPEN_CREATE)) {
12221edd9bf3SJim Harris 		cb_fn(cb_arg, NULL, -ENOENT);
12231edd9bf3SJim Harris 		return;
12241edd9bf3SJim Harris 	}
12251edd9bf3SJim Harris 
12262d18887fSCunyin Chang 	if (f != NULL && f->is_deleted == true) {
12272d18887fSCunyin Chang 		cb_fn(cb_arg, NULL, -ENOENT);
12282d18887fSCunyin Chang 		return;
12292d18887fSCunyin Chang 	}
12302d18887fSCunyin Chang 
1231267a4e1eSBen Walker 	req = alloc_fs_request(fs->md_target.md_fs_channel);
12321edd9bf3SJim Harris 	if (req == NULL) {
1233a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate async open req for file=%s\n", name);
12341edd9bf3SJim Harris 		cb_fn(cb_arg, NULL, -ENOMEM);
12351edd9bf3SJim Harris 		return;
12361edd9bf3SJim Harris 	}
12371edd9bf3SJim Harris 
12381edd9bf3SJim Harris 	args = &req->args;
12391edd9bf3SJim Harris 	args->fn.file_op_with_handle = cb_fn;
12401edd9bf3SJim Harris 	args->arg = cb_arg;
12411edd9bf3SJim Harris 	args->file = f;
12421edd9bf3SJim Harris 	args->fs = fs;
12431edd9bf3SJim Harris 	args->op.open.name = name;
12441edd9bf3SJim Harris 
12451edd9bf3SJim Harris 	if (f == NULL) {
12461edd9bf3SJim Harris 		spdk_fs_create_file_async(fs, name, fs_open_blob_create_cb, req);
12471edd9bf3SJim Harris 	} else {
12481edd9bf3SJim Harris 		fs_open_blob_create_cb(req, 0);
12491edd9bf3SJim Harris 	}
12501edd9bf3SJim Harris }
12511edd9bf3SJim Harris 
12521edd9bf3SJim Harris static void
12531edd9bf3SJim Harris __fs_open_file_done(void *arg, struct spdk_file *file, int bserrno)
12541edd9bf3SJim Harris {
12551edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
12561edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
12571edd9bf3SJim Harris 
12581edd9bf3SJim Harris 	args->file = file;
12592172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s\n", args->op.open.name);
126077a523e4Shgy 	__wake_caller(args, bserrno);
12611edd9bf3SJim Harris }
12621edd9bf3SJim Harris 
12631edd9bf3SJim Harris static void
12641edd9bf3SJim Harris __fs_open_file(void *arg)
12651edd9bf3SJim Harris {
12661edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
12671edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
12681edd9bf3SJim Harris 
12692172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s\n", args->op.open.name);
12701edd9bf3SJim Harris 	spdk_fs_open_file_async(args->fs, args->op.open.name, args->op.open.flags,
12711edd9bf3SJim Harris 				__fs_open_file_done, req);
12721edd9bf3SJim Harris }
12731edd9bf3SJim Harris 
12741edd9bf3SJim Harris int
1275e9d400d5SBen Walker spdk_fs_open_file(struct spdk_filesystem *fs, struct spdk_fs_thread_ctx *ctx,
12761edd9bf3SJim Harris 		  const char *name, uint32_t flags, struct spdk_file **file)
12771edd9bf3SJim Harris {
1278e9d400d5SBen Walker 	struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
12791edd9bf3SJim Harris 	struct spdk_fs_request *req;
12801edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
12811edd9bf3SJim Harris 	int rc;
12821edd9bf3SJim Harris 
12832172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s\n", name);
12841edd9bf3SJim Harris 
12851edd9bf3SJim Harris 	req = alloc_fs_request(channel);
12860de89b36SZiye Yang 	if (req == NULL) {
1287a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate req for opening file=%s\n", name);
12880de89b36SZiye Yang 		return -ENOMEM;
12890de89b36SZiye Yang 	}
12901edd9bf3SJim Harris 
12911edd9bf3SJim Harris 	args = &req->args;
12921edd9bf3SJim Harris 	args->fs = fs;
12931edd9bf3SJim Harris 	args->op.open.name = name;
12941edd9bf3SJim Harris 	args->op.open.flags = flags;
12951edd9bf3SJim Harris 	args->sem = &channel->sem;
12961edd9bf3SJim Harris 	fs->send_request(__fs_open_file, req);
12971edd9bf3SJim Harris 	sem_wait(&channel->sem);
12981edd9bf3SJim Harris 	rc = args->rc;
12991edd9bf3SJim Harris 	if (rc == 0) {
13001edd9bf3SJim Harris 		*file = args->file;
13011edd9bf3SJim Harris 	} else {
13021edd9bf3SJim Harris 		*file = NULL;
13031edd9bf3SJim Harris 	}
13041edd9bf3SJim Harris 	free_fs_request(req);
13051edd9bf3SJim Harris 
13061edd9bf3SJim Harris 	return rc;
13071edd9bf3SJim Harris }
13081edd9bf3SJim Harris 
13091edd9bf3SJim Harris static void
13101edd9bf3SJim Harris fs_rename_blob_close_cb(void *ctx, int bserrno)
13111edd9bf3SJim Harris {
13121edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
13131edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
13141edd9bf3SJim Harris 
13151edd9bf3SJim Harris 	args->fn.fs_op(args->arg, bserrno);
13161edd9bf3SJim Harris 	free_fs_request(req);
13171edd9bf3SJim Harris }
13181edd9bf3SJim Harris 
13191edd9bf3SJim Harris static void
13201edd9bf3SJim Harris fs_rename_blob_open_cb(void *ctx, struct spdk_blob *blob, int bserrno)
13211edd9bf3SJim Harris {
13221edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
13231edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
13241edd9bf3SJim Harris 	const char *new_name = args->op.rename.new_name;
13251edd9bf3SJim Harris 
13262c3591f1SJim Harris 	spdk_blob_set_xattr(blob, "name", new_name, strlen(new_name) + 1);
1327e734bb9fSJim Harris 	spdk_blob_close(blob, fs_rename_blob_close_cb, req);
13281edd9bf3SJim Harris }
13291edd9bf3SJim Harris 
13301edd9bf3SJim Harris static void
1331bc0180f6SSeth Howell _fs_md_rename_file(struct spdk_fs_request *req)
13321edd9bf3SJim Harris {
13331edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
13341edd9bf3SJim Harris 	struct spdk_file *f;
13351edd9bf3SJim Harris 
13361edd9bf3SJim Harris 	f = fs_find_file(args->fs, args->op.rename.old_name);
13371edd9bf3SJim Harris 	if (f == NULL) {
13381edd9bf3SJim Harris 		args->fn.fs_op(args->arg, -ENOENT);
13391edd9bf3SJim Harris 		free_fs_request(req);
13401edd9bf3SJim Harris 		return;
13411edd9bf3SJim Harris 	}
13421edd9bf3SJim Harris 
13431edd9bf3SJim Harris 	free(f->name);
13441edd9bf3SJim Harris 	f->name = strdup(args->op.rename.new_name);
134557eee182Syidong0635 	if (!f->name) {
134657eee182Syidong0635 		SPDK_ERRLOG("Cannot allocate memory for file name\n");
134757eee182Syidong0635 		args->fn.fs_op(args->arg, -ENOMEM);
134857eee182Syidong0635 		free_fs_request(req);
134957eee182Syidong0635 		return;
135057eee182Syidong0635 	}
135157eee182Syidong0635 
13521edd9bf3SJim Harris 	args->file = f;
1353d52dbda2SJim Harris 	spdk_bs_open_blob(args->fs->bs, f->blobid, fs_rename_blob_open_cb, req);
13541edd9bf3SJim Harris }
13551edd9bf3SJim Harris 
13561edd9bf3SJim Harris static void
13571edd9bf3SJim Harris fs_rename_delete_done(void *arg, int fserrno)
13581edd9bf3SJim Harris {
1359bc0180f6SSeth Howell 	_fs_md_rename_file(arg);
13601edd9bf3SJim Harris }
13611edd9bf3SJim Harris 
13621edd9bf3SJim Harris void
13631edd9bf3SJim Harris spdk_fs_rename_file_async(struct spdk_filesystem *fs,
13641edd9bf3SJim Harris 			  const char *old_name, const char *new_name,
13651edd9bf3SJim Harris 			  spdk_file_op_complete cb_fn, void *cb_arg)
13661edd9bf3SJim Harris {
13671edd9bf3SJim Harris 	struct spdk_file *f;
13681edd9bf3SJim Harris 	struct spdk_fs_request *req;
13691edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
13701edd9bf3SJim Harris 
13712172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "old=%s new=%s\n", old_name, new_name);
13721edd9bf3SJim Harris 	if (strnlen(new_name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) {
13731edd9bf3SJim Harris 		cb_fn(cb_arg, -ENAMETOOLONG);
13741edd9bf3SJim Harris 		return;
13751edd9bf3SJim Harris 	}
13761edd9bf3SJim Harris 
1377267a4e1eSBen Walker 	req = alloc_fs_request(fs->md_target.md_fs_channel);
13781edd9bf3SJim Harris 	if (req == NULL) {
1379a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate rename async req for renaming file from %s to %s\n", old_name,
1380a7317317SZiye Yang 			    new_name);
13811edd9bf3SJim Harris 		cb_fn(cb_arg, -ENOMEM);
13821edd9bf3SJim Harris 		return;
13831edd9bf3SJim Harris 	}
13841edd9bf3SJim Harris 
13851edd9bf3SJim Harris 	args = &req->args;
13861edd9bf3SJim Harris 	args->fn.fs_op = cb_fn;
13871edd9bf3SJim Harris 	args->fs = fs;
13881edd9bf3SJim Harris 	args->arg = cb_arg;
13891edd9bf3SJim Harris 	args->op.rename.old_name = old_name;
13901edd9bf3SJim Harris 	args->op.rename.new_name = new_name;
13911edd9bf3SJim Harris 
13921edd9bf3SJim Harris 	f = fs_find_file(fs, new_name);
13931edd9bf3SJim Harris 	if (f == NULL) {
1394bc0180f6SSeth Howell 		_fs_md_rename_file(req);
13951edd9bf3SJim Harris 		return;
13961edd9bf3SJim Harris 	}
13971edd9bf3SJim Harris 
13981edd9bf3SJim Harris 	/*
13991edd9bf3SJim Harris 	 * The rename overwrites an existing file.  So delete the existing file, then
14001edd9bf3SJim Harris 	 *  do the actual rename.
14011edd9bf3SJim Harris 	 */
14021edd9bf3SJim Harris 	spdk_fs_delete_file_async(fs, new_name, fs_rename_delete_done, req);
14031edd9bf3SJim Harris }
14041edd9bf3SJim Harris 
14051edd9bf3SJim Harris static void
14061edd9bf3SJim Harris __fs_rename_file_done(void *arg, int fserrno)
14071edd9bf3SJim Harris {
14081edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
14091edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
14101edd9bf3SJim Harris 
1411f1e14ef4SChangpeng Liu 	__wake_caller(args, fserrno);
14121edd9bf3SJim Harris }
14131edd9bf3SJim Harris 
14141edd9bf3SJim Harris static void
14151edd9bf3SJim Harris __fs_rename_file(void *arg)
14161edd9bf3SJim Harris {
14171edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
14181edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
14191edd9bf3SJim Harris 
14201edd9bf3SJim Harris 	spdk_fs_rename_file_async(args->fs, args->op.rename.old_name, args->op.rename.new_name,
14211edd9bf3SJim Harris 				  __fs_rename_file_done, req);
14221edd9bf3SJim Harris }
14231edd9bf3SJim Harris 
14241edd9bf3SJim Harris int
1425e9d400d5SBen Walker spdk_fs_rename_file(struct spdk_filesystem *fs, struct spdk_fs_thread_ctx *ctx,
14261edd9bf3SJim Harris 		    const char *old_name, const char *new_name)
14271edd9bf3SJim Harris {
1428e9d400d5SBen Walker 	struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
14291edd9bf3SJim Harris 	struct spdk_fs_request *req;
14301edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
14311edd9bf3SJim Harris 	int rc;
14321edd9bf3SJim Harris 
14331edd9bf3SJim Harris 	req = alloc_fs_request(channel);
14340de89b36SZiye Yang 	if (req == NULL) {
1435a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate rename req for file=%s\n", old_name);
14360de89b36SZiye Yang 		return -ENOMEM;
14370de89b36SZiye Yang 	}
14381edd9bf3SJim Harris 
14391edd9bf3SJim Harris 	args = &req->args;
14401edd9bf3SJim Harris 
14411edd9bf3SJim Harris 	args->fs = fs;
14421edd9bf3SJim Harris 	args->op.rename.old_name = old_name;
14431edd9bf3SJim Harris 	args->op.rename.new_name = new_name;
14441edd9bf3SJim Harris 	args->sem = &channel->sem;
14451edd9bf3SJim Harris 	fs->send_request(__fs_rename_file, req);
14461edd9bf3SJim Harris 	sem_wait(&channel->sem);
14471edd9bf3SJim Harris 	rc = args->rc;
14481edd9bf3SJim Harris 	free_fs_request(req);
14491edd9bf3SJim Harris 	return rc;
14501edd9bf3SJim Harris }
14511edd9bf3SJim Harris 
14521edd9bf3SJim Harris static void
14531edd9bf3SJim Harris blob_delete_cb(void *ctx, int bserrno)
14541edd9bf3SJim Harris {
14551edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
14561edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
14571edd9bf3SJim Harris 
14581edd9bf3SJim Harris 	args->fn.file_op(args->arg, bserrno);
14591edd9bf3SJim Harris 	free_fs_request(req);
14601edd9bf3SJim Harris }
14611edd9bf3SJim Harris 
14621edd9bf3SJim Harris void
14631edd9bf3SJim Harris spdk_fs_delete_file_async(struct spdk_filesystem *fs, const char *name,
14641edd9bf3SJim Harris 			  spdk_file_op_complete cb_fn, void *cb_arg)
14651edd9bf3SJim Harris {
14661edd9bf3SJim Harris 	struct spdk_file *f;
14671edd9bf3SJim Harris 	spdk_blob_id blobid;
14681edd9bf3SJim Harris 	struct spdk_fs_request *req;
14691edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
14701edd9bf3SJim Harris 
14712172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s\n", name);
14721edd9bf3SJim Harris 
14731edd9bf3SJim Harris 	if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) {
14741edd9bf3SJim Harris 		cb_fn(cb_arg, -ENAMETOOLONG);
14751edd9bf3SJim Harris 		return;
14761edd9bf3SJim Harris 	}
14771edd9bf3SJim Harris 
14781edd9bf3SJim Harris 	f = fs_find_file(fs, name);
14791edd9bf3SJim Harris 	if (f == NULL) {
1480a7317317SZiye Yang 		SPDK_ERRLOG("Cannot find the file=%s to deleted\n", name);
14811edd9bf3SJim Harris 		cb_fn(cb_arg, -ENOENT);
14821edd9bf3SJim Harris 		return;
14831edd9bf3SJim Harris 	}
14841edd9bf3SJim Harris 
1485267a4e1eSBen Walker 	req = alloc_fs_request(fs->md_target.md_fs_channel);
14861edd9bf3SJim Harris 	if (req == NULL) {
1487a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate the req for the file=%s to deleted\n", name);
14881edd9bf3SJim Harris 		cb_fn(cb_arg, -ENOMEM);
14891edd9bf3SJim Harris 		return;
14901edd9bf3SJim Harris 	}
14911edd9bf3SJim Harris 
14922d18887fSCunyin Chang 	args = &req->args;
14932d18887fSCunyin Chang 	args->fn.file_op = cb_fn;
14942d18887fSCunyin Chang 	args->arg = cb_arg;
14952d18887fSCunyin Chang 
14962d18887fSCunyin Chang 	if (f->ref_count > 0) {
14972d18887fSCunyin Chang 		/* If the ref > 0, we mark the file as deleted and delete it when we close it. */
14982d18887fSCunyin Chang 		f->is_deleted = true;
14992c3591f1SJim Harris 		spdk_blob_set_xattr(f->blob, "is_deleted", &f->is_deleted, sizeof(bool));
15001bc959f2SChangpeng Liu 		spdk_blob_sync_md(f->blob, blob_delete_cb, req);
15012d18887fSCunyin Chang 		return;
15022d18887fSCunyin Chang 	}
15032d18887fSCunyin Chang 
150487d5d832SChangpeng Liu 	blobid = f->blobid;
15051edd9bf3SJim Harris 	TAILQ_REMOVE(&fs->files, f, tailq);
15061edd9bf3SJim Harris 
150787d5d832SChangpeng Liu 	file_free(f);
15081edd9bf3SJim Harris 
1509d52dbda2SJim Harris 	spdk_bs_delete_blob(fs->bs, blobid, blob_delete_cb, req);
15101edd9bf3SJim Harris }
15111edd9bf3SJim Harris 
15121edd9bf3SJim Harris static void
15131edd9bf3SJim Harris __fs_delete_file_done(void *arg, int fserrno)
15141edd9bf3SJim Harris {
15151edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
15161edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
15171edd9bf3SJim Harris 
15183e158bd5SKonrad Sztyber 	spdk_trace_record(TRACE_BLOBFS_DELETE_DONE, 0, 0, 0, args->op.delete.name);
1519f1e14ef4SChangpeng Liu 	__wake_caller(args, fserrno);
15201edd9bf3SJim Harris }
15211edd9bf3SJim Harris 
15221edd9bf3SJim Harris static void
15231edd9bf3SJim Harris __fs_delete_file(void *arg)
15241edd9bf3SJim Harris {
15251edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
15261edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
15271edd9bf3SJim Harris 
15283e158bd5SKonrad Sztyber 	spdk_trace_record(TRACE_BLOBFS_DELETE_START, 0, 0, 0, args->op.delete.name);
15291edd9bf3SJim Harris 	spdk_fs_delete_file_async(args->fs, args->op.delete.name, __fs_delete_file_done, req);
15301edd9bf3SJim Harris }
15311edd9bf3SJim Harris 
15321edd9bf3SJim Harris int
1533e9d400d5SBen Walker spdk_fs_delete_file(struct spdk_filesystem *fs, struct spdk_fs_thread_ctx *ctx,
15341edd9bf3SJim Harris 		    const char *name)
15351edd9bf3SJim Harris {
1536e9d400d5SBen Walker 	struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
15371edd9bf3SJim Harris 	struct spdk_fs_request *req;
15381edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
15391edd9bf3SJim Harris 	int rc;
15401edd9bf3SJim Harris 
15411edd9bf3SJim Harris 	req = alloc_fs_request(channel);
15420de89b36SZiye Yang 	if (req == NULL) {
15432172c432STomasz Zawadzki 		SPDK_DEBUGLOG(blobfs, "Cannot allocate req to delete file=%s\n", name);
15440de89b36SZiye Yang 		return -ENOMEM;
15450de89b36SZiye Yang 	}
15461edd9bf3SJim Harris 
15471edd9bf3SJim Harris 	args = &req->args;
15481edd9bf3SJim Harris 	args->fs = fs;
15491edd9bf3SJim Harris 	args->op.delete.name = name;
15501edd9bf3SJim Harris 	args->sem = &channel->sem;
15511edd9bf3SJim Harris 	fs->send_request(__fs_delete_file, req);
15521edd9bf3SJim Harris 	sem_wait(&channel->sem);
15531edd9bf3SJim Harris 	rc = args->rc;
15541edd9bf3SJim Harris 	free_fs_request(req);
15551edd9bf3SJim Harris 
15561edd9bf3SJim Harris 	return rc;
15571edd9bf3SJim Harris }
15581edd9bf3SJim Harris 
15591edd9bf3SJim Harris spdk_fs_iter
15601edd9bf3SJim Harris spdk_fs_iter_first(struct spdk_filesystem *fs)
15611edd9bf3SJim Harris {
15621edd9bf3SJim Harris 	struct spdk_file *f;
15631edd9bf3SJim Harris 
15641edd9bf3SJim Harris 	f = TAILQ_FIRST(&fs->files);
15651edd9bf3SJim Harris 	return f;
15661edd9bf3SJim Harris }
15671edd9bf3SJim Harris 
15681edd9bf3SJim Harris spdk_fs_iter
15691edd9bf3SJim Harris spdk_fs_iter_next(spdk_fs_iter iter)
15701edd9bf3SJim Harris {
15711edd9bf3SJim Harris 	struct spdk_file *f = iter;
15721edd9bf3SJim Harris 
15731edd9bf3SJim Harris 	if (f == NULL) {
15741edd9bf3SJim Harris 		return NULL;
15751edd9bf3SJim Harris 	}
15761edd9bf3SJim Harris 
15771edd9bf3SJim Harris 	f = TAILQ_NEXT(f, tailq);
15781edd9bf3SJim Harris 	return f;
15791edd9bf3SJim Harris }
15801edd9bf3SJim Harris 
15811edd9bf3SJim Harris const char *
15821edd9bf3SJim Harris spdk_file_get_name(struct spdk_file *file)
15831edd9bf3SJim Harris {
15841edd9bf3SJim Harris 	return file->name;
15851edd9bf3SJim Harris }
15861edd9bf3SJim Harris 
15871edd9bf3SJim Harris uint64_t
15881edd9bf3SJim Harris spdk_file_get_length(struct spdk_file *file)
15891edd9bf3SJim Harris {
159013a58c41SZiye Yang 	uint64_t length;
159113a58c41SZiye Yang 
15921edd9bf3SJim Harris 	assert(file != NULL);
159313a58c41SZiye Yang 
159413a58c41SZiye Yang 	length = file->append_pos >= file->length ? file->append_pos : file->length;
15952172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s length=0x%jx\n", file->name, length);
159613a58c41SZiye Yang 	return length;
15971edd9bf3SJim Harris }
15981edd9bf3SJim Harris 
15991edd9bf3SJim Harris static void
16001edd9bf3SJim Harris fs_truncate_complete_cb(void *ctx, int bserrno)
16011edd9bf3SJim Harris {
16021edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
16031edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
16041edd9bf3SJim Harris 
16051edd9bf3SJim Harris 	args->fn.file_op(args->arg, bserrno);
16061edd9bf3SJim Harris 	free_fs_request(req);
16071edd9bf3SJim Harris }
16081edd9bf3SJim Harris 
1609463925ffSJim Harris static void
1610463925ffSJim Harris fs_truncate_resize_cb(void *ctx, int bserrno)
1611463925ffSJim Harris {
1612463925ffSJim Harris 	struct spdk_fs_request *req = ctx;
1613463925ffSJim Harris 	struct spdk_fs_cb_args *args = &req->args;
1614463925ffSJim Harris 	struct spdk_file *file = args->file;
1615463925ffSJim Harris 	uint64_t *length = &args->op.truncate.length;
1616463925ffSJim Harris 
1617f1e14ef4SChangpeng Liu 	if (bserrno) {
1618f1e14ef4SChangpeng Liu 		args->fn.file_op(args->arg, bserrno);
1619f1e14ef4SChangpeng Liu 		free_fs_request(req);
1620f1e14ef4SChangpeng Liu 		return;
1621f1e14ef4SChangpeng Liu 	}
1622f1e14ef4SChangpeng Liu 
1623463925ffSJim Harris 	spdk_blob_set_xattr(file->blob, "length", length, sizeof(*length));
1624463925ffSJim Harris 
1625463925ffSJim Harris 	file->length = *length;
1626463925ffSJim Harris 	if (file->append_pos > file->length) {
1627463925ffSJim Harris 		file->append_pos = file->length;
1628463925ffSJim Harris 	}
1629463925ffSJim Harris 
16302db73782SChangpeng Liu 	spdk_blob_sync_md(file->blob, fs_truncate_complete_cb, req);
1631463925ffSJim Harris }
1632463925ffSJim Harris 
16331edd9bf3SJim Harris static uint64_t
16341edd9bf3SJim Harris __bytes_to_clusters(uint64_t length, uint64_t cluster_sz)
16351edd9bf3SJim Harris {
16361edd9bf3SJim Harris 	return (length + cluster_sz - 1) / cluster_sz;
16371edd9bf3SJim Harris }
16381edd9bf3SJim Harris 
16391edd9bf3SJim Harris void
16401edd9bf3SJim Harris spdk_file_truncate_async(struct spdk_file *file, uint64_t length,
16411edd9bf3SJim Harris 			 spdk_file_op_complete cb_fn, void *cb_arg)
16421edd9bf3SJim Harris {
16431edd9bf3SJim Harris 	struct spdk_filesystem *fs;
16441edd9bf3SJim Harris 	size_t num_clusters;
16451edd9bf3SJim Harris 	struct spdk_fs_request *req;
16461edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
16471edd9bf3SJim Harris 
16482172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s old=0x%jx new=0x%jx\n", file->name, file->length, length);
16491edd9bf3SJim Harris 	if (length == file->length) {
16501edd9bf3SJim Harris 		cb_fn(cb_arg, 0);
16511edd9bf3SJim Harris 		return;
16521edd9bf3SJim Harris 	}
16531edd9bf3SJim Harris 
1654267a4e1eSBen Walker 	req = alloc_fs_request(file->fs->md_target.md_fs_channel);
16551edd9bf3SJim Harris 	if (req == NULL) {
16561edd9bf3SJim Harris 		cb_fn(cb_arg, -ENOMEM);
16571edd9bf3SJim Harris 		return;
16581edd9bf3SJim Harris 	}
16591edd9bf3SJim Harris 
16601edd9bf3SJim Harris 	args = &req->args;
16611edd9bf3SJim Harris 	args->fn.file_op = cb_fn;
16621edd9bf3SJim Harris 	args->arg = cb_arg;
16631edd9bf3SJim Harris 	args->file = file;
1664463925ffSJim Harris 	args->op.truncate.length = length;
16651edd9bf3SJim Harris 	fs = file->fs;
16661edd9bf3SJim Harris 
16671edd9bf3SJim Harris 	num_clusters = __bytes_to_clusters(length, fs->bs_opts.cluster_sz);
16681edd9bf3SJim Harris 
1669463925ffSJim Harris 	spdk_blob_resize(file->blob, num_clusters, fs_truncate_resize_cb, req);
16701edd9bf3SJim Harris }
16711edd9bf3SJim Harris 
16721edd9bf3SJim Harris static void
16731edd9bf3SJim Harris __truncate(void *arg)
16741edd9bf3SJim Harris {
16751edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
16761edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
16771edd9bf3SJim Harris 
16781edd9bf3SJim Harris 	spdk_file_truncate_async(args->file, args->op.truncate.length,
1679f1e14ef4SChangpeng Liu 				 args->fn.file_op, args);
16801edd9bf3SJim Harris }
16811edd9bf3SJim Harris 
1682703d1f80SZiye Yang int
1683e9d400d5SBen Walker spdk_file_truncate(struct spdk_file *file, struct spdk_fs_thread_ctx *ctx,
16841edd9bf3SJim Harris 		   uint64_t length)
16851edd9bf3SJim Harris {
1686e9d400d5SBen Walker 	struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
16871edd9bf3SJim Harris 	struct spdk_fs_request *req;
16881edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
1689f1e14ef4SChangpeng Liu 	int rc;
16901edd9bf3SJim Harris 
16911edd9bf3SJim Harris 	req = alloc_fs_request(channel);
1692703d1f80SZiye Yang 	if (req == NULL) {
1693703d1f80SZiye Yang 		return -ENOMEM;
1694703d1f80SZiye Yang 	}
16951edd9bf3SJim Harris 
16961edd9bf3SJim Harris 	args = &req->args;
16971edd9bf3SJim Harris 
16981edd9bf3SJim Harris 	args->file = file;
16991edd9bf3SJim Harris 	args->op.truncate.length = length;
1700f1e14ef4SChangpeng Liu 	args->fn.file_op = __wake_caller;
1701f1e14ef4SChangpeng Liu 	args->sem = &channel->sem;
17021edd9bf3SJim Harris 
17031edd9bf3SJim Harris 	channel->send_request(__truncate, req);
17041edd9bf3SJim Harris 	sem_wait(&channel->sem);
1705f1e14ef4SChangpeng Liu 	rc = args->rc;
17061edd9bf3SJim Harris 	free_fs_request(req);
1707703d1f80SZiye Yang 
1708f1e14ef4SChangpeng Liu 	return rc;
17091edd9bf3SJim Harris }
17101edd9bf3SJim Harris 
17111edd9bf3SJim Harris static void
17121edd9bf3SJim Harris __rw_done(void *ctx, int bserrno)
17131edd9bf3SJim Harris {
17141edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
17151edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
17161edd9bf3SJim Harris 
171727a23a33SDarek Stojaczyk 	spdk_free(args->op.rw.pin_buf);
17181edd9bf3SJim Harris 	args->fn.file_op(args->arg, bserrno);
17191edd9bf3SJim Harris 	free_fs_request(req);
17201edd9bf3SJim Harris }
17211edd9bf3SJim Harris 
17221edd9bf3SJim Harris static void
17231edd9bf3SJim Harris __read_done(void *ctx, int bserrno)
17241edd9bf3SJim Harris {
17251edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
17261edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
17271966f1eeSChangpeng Liu 	void *buf;
17281edd9bf3SJim Harris 
17295d1fa299Shgy 	if (bserrno) {
17305d1fa299Shgy 		__rw_done(req, bserrno);
17315d1fa299Shgy 		return;
17325d1fa299Shgy 	}
17335d1fa299Shgy 
17340de89b36SZiye Yang 	assert(req != NULL);
17351966f1eeSChangpeng Liu 	buf = (void *)((uintptr_t)args->op.rw.pin_buf + (args->op.rw.offset & (args->op.rw.blocklen - 1)));
17361edd9bf3SJim Harris 	if (args->op.rw.is_read) {
1737dabca256Syidong0635 		spdk_copy_buf_to_iovs(args->iovs, args->iovcnt, buf, args->op.rw.length);
17381edd9bf3SJim Harris 		__rw_done(req, 0);
17391edd9bf3SJim Harris 	} else {
1740dabca256Syidong0635 		spdk_copy_iovs_to_buf(buf, args->op.rw.length, args->iovs, args->iovcnt);
174166fc591fSJim Harris 		spdk_blob_io_write(args->file->blob, args->op.rw.channel,
17421edd9bf3SJim Harris 				   args->op.rw.pin_buf,
1743be2d2c76SPiotr Pelplinski 				   args->op.rw.start_lba, args->op.rw.num_lba,
17441edd9bf3SJim Harris 				   __rw_done, req);
17451edd9bf3SJim Harris 	}
17461edd9bf3SJim Harris }
17471edd9bf3SJim Harris 
17481edd9bf3SJim Harris static void
17491edd9bf3SJim Harris __do_blob_read(void *ctx, int fserrno)
17501edd9bf3SJim Harris {
17511edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
17521edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
17531edd9bf3SJim Harris 
1754f4ba32fcSZiye Yang 	if (fserrno) {
1755f4ba32fcSZiye Yang 		__rw_done(req, fserrno);
1756f4ba32fcSZiye Yang 		return;
1757f4ba32fcSZiye Yang 	}
175866fc591fSJim Harris 	spdk_blob_io_read(args->file->blob, args->op.rw.channel,
17591edd9bf3SJim Harris 			  args->op.rw.pin_buf,
1760be2d2c76SPiotr Pelplinski 			  args->op.rw.start_lba, args->op.rw.num_lba,
17611edd9bf3SJim Harris 			  __read_done, req);
17621edd9bf3SJim Harris }
17631edd9bf3SJim Harris 
17641edd9bf3SJim Harris static void
17651edd9bf3SJim Harris __get_page_parameters(struct spdk_file *file, uint64_t offset, uint64_t length,
1766be2d2c76SPiotr Pelplinski 		      uint64_t *start_lba, uint32_t *lba_size, uint64_t *num_lba)
17671edd9bf3SJim Harris {
1768be2d2c76SPiotr Pelplinski 	uint64_t end_lba;
17691edd9bf3SJim Harris 
1770be2d2c76SPiotr Pelplinski 	*lba_size = spdk_bs_get_io_unit_size(file->fs->bs);
1771be2d2c76SPiotr Pelplinski 	*start_lba = offset / *lba_size;
1772be2d2c76SPiotr Pelplinski 	end_lba = (offset + length - 1) / *lba_size;
1773be2d2c76SPiotr Pelplinski 	*num_lba = (end_lba - *start_lba + 1);
17741edd9bf3SJim Harris }
17751edd9bf3SJim Harris 
1776be4a5602SGangCao static bool
1777be4a5602SGangCao __is_lba_aligned(struct spdk_file *file, uint64_t offset, uint64_t length)
1778be4a5602SGangCao {
1779be4a5602SGangCao 	uint32_t lba_size = spdk_bs_get_io_unit_size(file->fs->bs);
1780be4a5602SGangCao 
1781be4a5602SGangCao 	if ((offset % lba_size == 0) && (length % lba_size == 0)) {
1782be4a5602SGangCao 		return true;
1783be4a5602SGangCao 	}
1784be4a5602SGangCao 
1785be4a5602SGangCao 	return false;
1786be4a5602SGangCao }
1787be4a5602SGangCao 
17881edd9bf3SJim Harris static void
17891966f1eeSChangpeng Liu _fs_request_setup_iovs(struct spdk_fs_request *req, struct iovec *iovs, uint32_t iovcnt)
17901966f1eeSChangpeng Liu {
17911966f1eeSChangpeng Liu 	uint32_t i;
17921966f1eeSChangpeng Liu 
17931966f1eeSChangpeng Liu 	for (i = 0; i < iovcnt; i++) {
17941966f1eeSChangpeng Liu 		req->args.iovs[i].iov_base = iovs[i].iov_base;
17951966f1eeSChangpeng Liu 		req->args.iovs[i].iov_len = iovs[i].iov_len;
17961966f1eeSChangpeng Liu 	}
17971966f1eeSChangpeng Liu }
17981966f1eeSChangpeng Liu 
17991966f1eeSChangpeng Liu static void
18001966f1eeSChangpeng Liu __readvwritev(struct spdk_file *file, struct spdk_io_channel *_channel,
18011966f1eeSChangpeng Liu 	      struct iovec *iovs, uint32_t iovcnt, uint64_t offset, uint64_t length,
18021edd9bf3SJim Harris 	      spdk_file_op_complete cb_fn, void *cb_arg, int is_read)
18031edd9bf3SJim Harris {
18041edd9bf3SJim Harris 	struct spdk_fs_request *req;
18051edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
18061edd9bf3SJim Harris 	struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel);
1807be2d2c76SPiotr Pelplinski 	uint64_t start_lba, num_lba, pin_buf_length;
1808be2d2c76SPiotr Pelplinski 	uint32_t lba_size;
18091edd9bf3SJim Harris 
18101edd9bf3SJim Harris 	if (is_read && offset + length > file->length) {
18111edd9bf3SJim Harris 		cb_fn(cb_arg, -EINVAL);
18121edd9bf3SJim Harris 		return;
18131edd9bf3SJim Harris 	}
18141edd9bf3SJim Harris 
18151966f1eeSChangpeng Liu 	req = alloc_fs_request_with_iov(channel, iovcnt);
18161edd9bf3SJim Harris 	if (req == NULL) {
18171edd9bf3SJim Harris 		cb_fn(cb_arg, -ENOMEM);
18181edd9bf3SJim Harris 		return;
18191edd9bf3SJim Harris 	}
18201edd9bf3SJim Harris 
1821be2d2c76SPiotr Pelplinski 	__get_page_parameters(file, offset, length, &start_lba, &lba_size, &num_lba);
1822be2d2c76SPiotr Pelplinski 
18231edd9bf3SJim Harris 	args = &req->args;
18241edd9bf3SJim Harris 	args->fn.file_op = cb_fn;
18251edd9bf3SJim Harris 	args->arg = cb_arg;
18261edd9bf3SJim Harris 	args->file = file;
18271edd9bf3SJim Harris 	args->op.rw.channel = channel->bs_channel;
18281966f1eeSChangpeng Liu 	_fs_request_setup_iovs(req, iovs, iovcnt);
18291edd9bf3SJim Harris 	args->op.rw.is_read = is_read;
18301edd9bf3SJim Harris 	args->op.rw.offset = offset;
1831be2d2c76SPiotr Pelplinski 	args->op.rw.blocklen = lba_size;
18321edd9bf3SJim Harris 
1833be2d2c76SPiotr Pelplinski 	pin_buf_length = num_lba * lba_size;
18341966f1eeSChangpeng Liu 	args->op.rw.length = pin_buf_length;
183527a23a33SDarek Stojaczyk 	args->op.rw.pin_buf = spdk_malloc(pin_buf_length, lba_size, NULL,
1836186b109dSJim Harris 					  SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_DMA);
1837e152aa8eSZiye Yang 	if (args->op.rw.pin_buf == NULL) {
18382172c432STomasz Zawadzki 		SPDK_DEBUGLOG(blobfs, "Failed to allocate buf for: file=%s offset=%jx length=%jx\n",
1839e152aa8eSZiye Yang 			      file->name, offset, length);
1840e152aa8eSZiye Yang 		free_fs_request(req);
1841e152aa8eSZiye Yang 		cb_fn(cb_arg, -ENOMEM);
1842e152aa8eSZiye Yang 		return;
1843e152aa8eSZiye Yang 	}
18441edd9bf3SJim Harris 
1845be2d2c76SPiotr Pelplinski 	args->op.rw.start_lba = start_lba;
1846be2d2c76SPiotr Pelplinski 	args->op.rw.num_lba = num_lba;
18471edd9bf3SJim Harris 
18481edd9bf3SJim Harris 	if (!is_read && file->length < offset + length) {
18491edd9bf3SJim Harris 		spdk_file_truncate_async(file, offset + length, __do_blob_read, req);
1850be4a5602SGangCao 	} else if (!is_read && __is_lba_aligned(file, offset, length)) {
1851dabca256Syidong0635 		spdk_copy_iovs_to_buf(args->op.rw.pin_buf, args->op.rw.length, args->iovs, args->iovcnt);
1852be4a5602SGangCao 		spdk_blob_io_write(args->file->blob, args->op.rw.channel,
1853be4a5602SGangCao 				   args->op.rw.pin_buf,
1854be4a5602SGangCao 				   args->op.rw.start_lba, args->op.rw.num_lba,
1855be4a5602SGangCao 				   __rw_done, req);
18561edd9bf3SJim Harris 	} else {
18571edd9bf3SJim Harris 		__do_blob_read(req, 0);
18581edd9bf3SJim Harris 	}
18591edd9bf3SJim Harris }
18601edd9bf3SJim Harris 
18611966f1eeSChangpeng Liu static void
18621966f1eeSChangpeng Liu __readwrite(struct spdk_file *file, struct spdk_io_channel *channel,
18631966f1eeSChangpeng Liu 	    void *payload, uint64_t offset, uint64_t length,
18641966f1eeSChangpeng Liu 	    spdk_file_op_complete cb_fn, void *cb_arg, int is_read)
18651966f1eeSChangpeng Liu {
18661966f1eeSChangpeng Liu 	struct iovec iov;
18671966f1eeSChangpeng Liu 
18681966f1eeSChangpeng Liu 	iov.iov_base = payload;
18691966f1eeSChangpeng Liu 	iov.iov_len = (size_t)length;
18701966f1eeSChangpeng Liu 
18711966f1eeSChangpeng Liu 	__readvwritev(file, channel, &iov, 1, offset, length, cb_fn, cb_arg, is_read);
18721966f1eeSChangpeng Liu }
18731966f1eeSChangpeng Liu 
18741edd9bf3SJim Harris void
18751edd9bf3SJim Harris spdk_file_write_async(struct spdk_file *file, struct spdk_io_channel *channel,
18761edd9bf3SJim Harris 		      void *payload, uint64_t offset, uint64_t length,
18771edd9bf3SJim Harris 		      spdk_file_op_complete cb_fn, void *cb_arg)
18781edd9bf3SJim Harris {
18791edd9bf3SJim Harris 	__readwrite(file, channel, payload, offset, length, cb_fn, cb_arg, 0);
18801edd9bf3SJim Harris }
18811edd9bf3SJim Harris 
18821edd9bf3SJim Harris void
18831966f1eeSChangpeng Liu spdk_file_writev_async(struct spdk_file *file, struct spdk_io_channel *channel,
18841966f1eeSChangpeng Liu 		       struct iovec *iovs, uint32_t iovcnt, uint64_t offset, uint64_t length,
18851966f1eeSChangpeng Liu 		       spdk_file_op_complete cb_fn, void *cb_arg)
18861966f1eeSChangpeng Liu {
18872172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s offset=%jx length=%jx\n",
18881966f1eeSChangpeng Liu 		      file->name, offset, length);
18891966f1eeSChangpeng Liu 
18901966f1eeSChangpeng Liu 	__readvwritev(file, channel, iovs, iovcnt, offset, length, cb_fn, cb_arg, 0);
18911966f1eeSChangpeng Liu }
18921966f1eeSChangpeng Liu 
18931966f1eeSChangpeng Liu void
18941edd9bf3SJim Harris spdk_file_read_async(struct spdk_file *file, struct spdk_io_channel *channel,
18951edd9bf3SJim Harris 		     void *payload, uint64_t offset, uint64_t length,
18961edd9bf3SJim Harris 		     spdk_file_op_complete cb_fn, void *cb_arg)
18971edd9bf3SJim Harris {
18982172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s offset=%jx length=%jx\n",
18991edd9bf3SJim Harris 		      file->name, offset, length);
190077a523e4Shgy 
19011edd9bf3SJim Harris 	__readwrite(file, channel, payload, offset, length, cb_fn, cb_arg, 1);
19021edd9bf3SJim Harris }
19031edd9bf3SJim Harris 
19041966f1eeSChangpeng Liu void
19051966f1eeSChangpeng Liu spdk_file_readv_async(struct spdk_file *file, struct spdk_io_channel *channel,
19061966f1eeSChangpeng Liu 		      struct iovec *iovs, uint32_t iovcnt, uint64_t offset, uint64_t length,
19071966f1eeSChangpeng Liu 		      spdk_file_op_complete cb_fn, void *cb_arg)
19081966f1eeSChangpeng Liu {
19092172c432STomasz Zawadzki 	SPDK_DEBUGLOG(blobfs, "file=%s offset=%jx length=%jx\n",
19101966f1eeSChangpeng Liu 		      file->name, offset, length);
19111966f1eeSChangpeng Liu 
19121966f1eeSChangpeng Liu 	__readvwritev(file, channel, iovs, iovcnt, offset, length, cb_fn, cb_arg, 1);
19131966f1eeSChangpeng Liu }
19141966f1eeSChangpeng Liu 
19151edd9bf3SJim Harris struct spdk_io_channel *
1916d969ac44SBen Walker spdk_fs_alloc_io_channel(struct spdk_filesystem *fs)
19171edd9bf3SJim Harris {
19181edd9bf3SJim Harris 	struct spdk_io_channel *io_channel;
19191edd9bf3SJim Harris 	struct spdk_fs_channel *fs_channel;
19201edd9bf3SJim Harris 
1921d969ac44SBen Walker 	io_channel = spdk_get_io_channel(&fs->io_target);
19221edd9bf3SJim Harris 	fs_channel = spdk_io_channel_get_ctx(io_channel);
1923d969ac44SBen Walker 	fs_channel->bs_channel = spdk_bs_alloc_io_channel(fs->bs);
19241edd9bf3SJim Harris 	fs_channel->send_request = __send_request_direct;
19251edd9bf3SJim Harris 
19261edd9bf3SJim Harris 	return io_channel;
19271edd9bf3SJim Harris }
19281edd9bf3SJim Harris 
1929e9d400d5SBen Walker void
1930e9d400d5SBen Walker spdk_fs_free_io_channel(struct spdk_io_channel *channel)
1931e9d400d5SBen Walker {
1932e9d400d5SBen Walker 	spdk_put_io_channel(channel);
1933e9d400d5SBen Walker }
1934e9d400d5SBen Walker 
1935e9d400d5SBen Walker struct spdk_fs_thread_ctx *
1936e9d400d5SBen Walker spdk_fs_alloc_thread_ctx(struct spdk_filesystem *fs)
19371edd9bf3SJim Harris {
1938b71bebe8SBen Walker 	struct spdk_fs_thread_ctx *ctx;
19391edd9bf3SJim Harris 
1940b71bebe8SBen Walker 	ctx = calloc(1, sizeof(*ctx));
1941b71bebe8SBen Walker 	if (!ctx) {
1942b71bebe8SBen Walker 		return NULL;
1943b71bebe8SBen Walker 	}
19441edd9bf3SJim Harris 
19457192849eSSeth Howell 	if (pthread_spin_init(&ctx->ch.lock, 0)) {
19467192849eSSeth Howell 		free(ctx);
19477192849eSSeth Howell 		return NULL;
19487192849eSSeth Howell 	}
19497192849eSSeth Howell 
1950bc0180f6SSeth Howell 	fs_channel_create(fs, &ctx->ch, 512);
1951b71bebe8SBen Walker 
1952b71bebe8SBen Walker 	ctx->ch.send_request = fs->send_request;
1953b71bebe8SBen Walker 	ctx->ch.sync = 1;
1954b71bebe8SBen Walker 
1955b71bebe8SBen Walker 	return ctx;
19561edd9bf3SJim Harris }
19571edd9bf3SJim Harris 
1958e9d400d5SBen Walker 
19591edd9bf3SJim Harris void
1960e9d400d5SBen Walker spdk_fs_free_thread_ctx(struct spdk_fs_thread_ctx *ctx)
19611edd9bf3SJim Harris {
1962b282c927SJim Harris 	assert(ctx->ch.sync == 1);
1963b282c927SJim Harris 
1964b282c927SJim Harris 	while (true) {
1965b282c927SJim Harris 		pthread_spin_lock(&ctx->ch.lock);
1966b282c927SJim Harris 		if (ctx->ch.outstanding_reqs == 0) {
1967b282c927SJim Harris 			pthread_spin_unlock(&ctx->ch.lock);
1968b282c927SJim Harris 			break;
1969b282c927SJim Harris 		}
1970b282c927SJim Harris 		pthread_spin_unlock(&ctx->ch.lock);
1971b282c927SJim Harris 		usleep(1000);
1972b282c927SJim Harris 	}
1973b282c927SJim Harris 
1974bc0180f6SSeth Howell 	fs_channel_destroy(NULL, &ctx->ch);
1975b71bebe8SBen Walker 	free(ctx);
19761edd9bf3SJim Harris }
19771edd9bf3SJim Harris 
19782f249aceSXiaodong Liu int
19791edd9bf3SJim Harris spdk_fs_set_cache_size(uint64_t size_in_mb)
19801edd9bf3SJim Harris {
19812f249aceSXiaodong Liu 	/* setting g_fs_cache_size is only permitted if cache pool
19822f249aceSXiaodong Liu 	 * is already freed or hasn't been initialized
19832f249aceSXiaodong Liu 	 */
19842f249aceSXiaodong Liu 	if (g_cache_pool != NULL) {
19852f249aceSXiaodong Liu 		return -EPERM;
19862f249aceSXiaodong Liu 	}
19872f249aceSXiaodong Liu 
19881edd9bf3SJim Harris 	g_fs_cache_size = size_in_mb * 1024 * 1024;
19892f249aceSXiaodong Liu 
19902f249aceSXiaodong Liu 	return 0;
19911edd9bf3SJim Harris }
19921edd9bf3SJim Harris 
19931edd9bf3SJim Harris uint64_t
19941edd9bf3SJim Harris spdk_fs_get_cache_size(void)
19951edd9bf3SJim Harris {
19961edd9bf3SJim Harris 	return g_fs_cache_size / (1024 * 1024);
19971edd9bf3SJim Harris }
19981edd9bf3SJim Harris 
1999125797e0SChangpeng Liu static void __file_flush(void *ctx);
20001edd9bf3SJim Harris 
2001ac257bd4SChangpeng Liu /* Try to free some cache buffers from this file.
200272b9af55SChangpeng Liu  */
2003beaf6961SChangpeng Liu static int
200472b9af55SChangpeng Liu reclaim_cache_buffers(struct spdk_file *file)
200572b9af55SChangpeng Liu {
200672b9af55SChangpeng Liu 	int rc;
200772b9af55SChangpeng Liu 
200872b9af55SChangpeng Liu 	BLOBFS_TRACE(file, "free=%s\n", file->name);
200972b9af55SChangpeng Liu 
201072b9af55SChangpeng Liu 	/* The function is safe to be called with any threads, while the file
201172b9af55SChangpeng Liu 	 * lock maybe locked by other thread for now, so try to get the file
201272b9af55SChangpeng Liu 	 * lock here.
201372b9af55SChangpeng Liu 	 */
201472b9af55SChangpeng Liu 	rc = pthread_spin_trylock(&file->lock);
201572b9af55SChangpeng Liu 	if (rc != 0) {
2016beaf6961SChangpeng Liu 		return -1;
201772b9af55SChangpeng Liu 	}
201872b9af55SChangpeng Liu 
201972b9af55SChangpeng Liu 	if (file->tree->present_mask == 0) {
202072b9af55SChangpeng Liu 		pthread_spin_unlock(&file->lock);
2021beaf6961SChangpeng Liu 		return -1;
202272b9af55SChangpeng Liu 	}
2023bc0180f6SSeth Howell 	tree_free_buffers(file->tree);
202472b9af55SChangpeng Liu 
202572b9af55SChangpeng Liu 	TAILQ_REMOVE(&g_caches, file, cache_tailq);
202672b9af55SChangpeng Liu 	/* If not freed, put it in the end of the queue */
202772b9af55SChangpeng Liu 	if (file->tree->present_mask != 0) {
202872b9af55SChangpeng Liu 		TAILQ_INSERT_TAIL(&g_caches, file, cache_tailq);
202952939f25SLiYankun 	}
203052939f25SLiYankun 
203152939f25SLiYankun 	/* tree_free_buffers() may have freed the buffer pointed to by file->last.
203252939f25SLiYankun 	 * So check if current append_pos is still in the cache, and if not, clear
203352939f25SLiYankun 	 * file->last.
203452939f25SLiYankun 	 */
203552939f25SLiYankun 	if (tree_find_buffer(file->tree, file->append_pos) == NULL) {
203672b9af55SChangpeng Liu 		file->last = NULL;
203772b9af55SChangpeng Liu 	}
203852939f25SLiYankun 
203972b9af55SChangpeng Liu 	pthread_spin_unlock(&file->lock);
2040beaf6961SChangpeng Liu 
2041beaf6961SChangpeng Liu 	return 0;
204272b9af55SChangpeng Liu }
204372b9af55SChangpeng Liu 
20441914de09SChangpeng Liu static int
20451914de09SChangpeng Liu _blobfs_cache_pool_reclaim(void *arg)
20461edd9bf3SJim Harris {
204772b9af55SChangpeng Liu 	struct spdk_file *file, *tmp;
2048beaf6961SChangpeng Liu 	int rc;
20491edd9bf3SJim Harris 
20501914de09SChangpeng Liu 	if (!blobfs_cache_pool_need_reclaim()) {
2051eb05cbd6SMaciej Szwed 		return SPDK_POLLER_IDLE;
20521edd9bf3SJim Harris 	}
20531edd9bf3SJim Harris 
205472b9af55SChangpeng Liu 	TAILQ_FOREACH_SAFE(file, &g_caches, cache_tailq, tmp) {
20551edd9bf3SJim Harris 		if (!file->open_for_writing &&
20561914de09SChangpeng Liu 		    file->priority == SPDK_FILE_PRIORITY_LOW) {
2057beaf6961SChangpeng Liu 			rc = reclaim_cache_buffers(file);
2058beaf6961SChangpeng Liu 			if (rc < 0) {
2059beaf6961SChangpeng Liu 				continue;
20601edd9bf3SJim Harris 			}
20611914de09SChangpeng Liu 			if (!blobfs_cache_pool_need_reclaim()) {
2062eb05cbd6SMaciej Szwed 				return SPDK_POLLER_BUSY;
20631edd9bf3SJim Harris 			}
20641edd9bf3SJim Harris 			break;
20651edd9bf3SJim Harris 		}
2066beaf6961SChangpeng Liu 	}
206772b9af55SChangpeng Liu 
206872b9af55SChangpeng Liu 	TAILQ_FOREACH_SAFE(file, &g_caches, cache_tailq, tmp) {
20691914de09SChangpeng Liu 		if (!file->open_for_writing) {
2070beaf6961SChangpeng Liu 			rc = reclaim_cache_buffers(file);
2071beaf6961SChangpeng Liu 			if (rc < 0) {
2072beaf6961SChangpeng Liu 				continue;
20731edd9bf3SJim Harris 			}
20741914de09SChangpeng Liu 			if (!blobfs_cache_pool_need_reclaim()) {
2075eb05cbd6SMaciej Szwed 				return SPDK_POLLER_BUSY;
20761edd9bf3SJim Harris 			}
207772b9af55SChangpeng Liu 			break;
20781edd9bf3SJim Harris 		}
2079beaf6961SChangpeng Liu 	}
20801edd9bf3SJim Harris 
208172b9af55SChangpeng Liu 	TAILQ_FOREACH_SAFE(file, &g_caches, cache_tailq, tmp) {
2082beaf6961SChangpeng Liu 		rc = reclaim_cache_buffers(file);
2083beaf6961SChangpeng Liu 		if (rc < 0) {
2084beaf6961SChangpeng Liu 			continue;
20851edd9bf3SJim Harris 		}
208672b9af55SChangpeng Liu 		break;
20871edd9bf3SJim Harris 	}
20881edd9bf3SJim Harris 
2089eb05cbd6SMaciej Szwed 	return SPDK_POLLER_BUSY;
20901edd9bf3SJim Harris }
20911edd9bf3SJim Harris 
2092c41c4c2bSChangpeng Liu static void
2093c41c4c2bSChangpeng Liu _add_file_to_cache_pool(void *ctx)
2094c41c4c2bSChangpeng Liu {
2095c41c4c2bSChangpeng Liu 	struct spdk_file *file = ctx;
2096c41c4c2bSChangpeng Liu 
2097c41c4c2bSChangpeng Liu 	TAILQ_INSERT_TAIL(&g_caches, file, cache_tailq);
2098c41c4c2bSChangpeng Liu }
2099c41c4c2bSChangpeng Liu 
210076d23f6fSChangpeng Liu static void
210176d23f6fSChangpeng Liu _remove_file_from_cache_pool(void *ctx)
210276d23f6fSChangpeng Liu {
210376d23f6fSChangpeng Liu 	struct spdk_file *file = ctx;
210476d23f6fSChangpeng Liu 
210576d23f6fSChangpeng Liu 	TAILQ_REMOVE(&g_caches, file, cache_tailq);
210676d23f6fSChangpeng Liu }
210776d23f6fSChangpeng Liu 
21081edd9bf3SJim Harris static struct cache_buffer *
21091edd9bf3SJim Harris cache_insert_buffer(struct spdk_file *file, uint64_t offset)
21101edd9bf3SJim Harris {
21111edd9bf3SJim Harris 	struct cache_buffer *buf;
21121edd9bf3SJim Harris 	int count = 0;
2113c41c4c2bSChangpeng Liu 	bool need_update = false;
21141edd9bf3SJim Harris 
21151edd9bf3SJim Harris 	buf = calloc(1, sizeof(*buf));
21161edd9bf3SJim Harris 	if (buf == NULL) {
21172172c432STomasz Zawadzki 		SPDK_DEBUGLOG(blobfs, "calloc failed\n");
21181edd9bf3SJim Harris 		return NULL;
21191edd9bf3SJim Harris 	}
21201edd9bf3SJim Harris 
21211914de09SChangpeng Liu 	do {
21221914de09SChangpeng Liu 		buf->buf = spdk_mempool_get(g_cache_pool);
21231914de09SChangpeng Liu 		if (buf->buf) {
21241914de09SChangpeng Liu 			break;
21251914de09SChangpeng Liu 		}
212638f91be5SJim Harris 		if (count++ == 100) {
2127fa2d95b3SZiye Yang 			SPDK_ERRLOG("Could not allocate cache buffer for file=%p on offset=%jx\n",
2128fa2d95b3SZiye Yang 				    file, offset);
212938f91be5SJim Harris 			free(buf);
21301edd9bf3SJim Harris 			return NULL;
21311edd9bf3SJim Harris 		}
21321914de09SChangpeng Liu 		usleep(BLOBFS_CACHE_POOL_POLL_PERIOD_IN_US);
21331914de09SChangpeng Liu 	} while (true);
21341edd9bf3SJim Harris 
21351edd9bf3SJim Harris 	buf->buf_size = CACHE_BUFFER_SIZE;
21361edd9bf3SJim Harris 	buf->offset = offset;
21371edd9bf3SJim Harris 
21381edd9bf3SJim Harris 	if (file->tree->present_mask == 0) {
2139c41c4c2bSChangpeng Liu 		need_update = true;
21401edd9bf3SJim Harris 	}
2141bc0180f6SSeth Howell 	file->tree = tree_insert_buffer(file->tree, buf);
2142c41c4c2bSChangpeng Liu 
2143c41c4c2bSChangpeng Liu 	if (need_update) {
2144c41c4c2bSChangpeng Liu 		spdk_thread_send_msg(g_cache_pool_thread, _add_file_to_cache_pool, file);
2145c41c4c2bSChangpeng Liu 	}
21461edd9bf3SJim Harris 
21471edd9bf3SJim Harris 	return buf;
21481edd9bf3SJim Harris }
21491edd9bf3SJim Harris 
21501edd9bf3SJim Harris static struct cache_buffer *
21511edd9bf3SJim Harris cache_append_buffer(struct spdk_file *file)
21521edd9bf3SJim Harris {
21531edd9bf3SJim Harris 	struct cache_buffer *last;
21541edd9bf3SJim Harris 
21551edd9bf3SJim Harris 	assert(file->last == NULL || file->last->bytes_filled == file->last->buf_size);
21561edd9bf3SJim Harris 	assert((file->append_pos % CACHE_BUFFER_SIZE) == 0);
21571edd9bf3SJim Harris 
21581edd9bf3SJim Harris 	last = cache_insert_buffer(file, file->append_pos);
21591edd9bf3SJim Harris 	if (last == NULL) {
21602172c432STomasz Zawadzki 		SPDK_DEBUGLOG(blobfs, "cache_insert_buffer failed\n");
21611edd9bf3SJim Harris 		return NULL;
21621edd9bf3SJim Harris 	}
21631edd9bf3SJim Harris 
21641edd9bf3SJim Harris 	file->last = last;
21651edd9bf3SJim Harris 
21661edd9bf3SJim Harris 	return last;
21671edd9bf3SJim Harris }
21681edd9bf3SJim Harris 
2169a6014eb2SJim Harris static void __check_sync_reqs(struct spdk_file *file);
2170a6014eb2SJim Harris 
21711edd9bf3SJim Harris static void
2172f1e14ef4SChangpeng Liu __file_cache_finish_sync(void *ctx, int bserrno)
21731edd9bf3SJim Harris {
21749602ade7SZiye Yang 	struct spdk_file *file;
21759602ade7SZiye Yang 	struct spdk_fs_request *sync_req = ctx;
21761edd9bf3SJim Harris 	struct spdk_fs_cb_args *sync_args;
21771edd9bf3SJim Harris 
21781edd9bf3SJim Harris 	sync_args = &sync_req->args;
21799602ade7SZiye Yang 	file = sync_args->file;
21809602ade7SZiye Yang 	pthread_spin_lock(&file->lock);
2181e967dcd2SJim Harris 	file->length_xattr = sync_args->op.sync.length;
2182a6014eb2SJim Harris 	assert(sync_args->op.sync.offset <= file->length_flushed);
2183f71fed21SJim Harris 	spdk_trace_record(TRACE_BLOBFS_XATTR_END, 0, sync_args->op.sync.offset,
21843e158bd5SKonrad Sztyber 			  0, file->name);
21851edd9bf3SJim Harris 	BLOBFS_TRACE(file, "sync done offset=%jx\n", sync_args->op.sync.offset);
21861edd9bf3SJim Harris 	TAILQ_REMOVE(&file->sync_requests, sync_req, args.op.sync.tailq);
21871edd9bf3SJim Harris 	pthread_spin_unlock(&file->lock);
2188a6014eb2SJim Harris 
2189f1e14ef4SChangpeng Liu 	sync_args->fn.file_op(sync_args->arg, bserrno);
21909602ade7SZiye Yang 
21911fd159beSChangpeng Liu 	free_fs_request(sync_req);
21929602ade7SZiye Yang 	__check_sync_reqs(file);
21931edd9bf3SJim Harris }
21941edd9bf3SJim Harris 
21951edd9bf3SJim Harris static void
2196a6014eb2SJim Harris __check_sync_reqs(struct spdk_file *file)
2197a6014eb2SJim Harris {
2198a6014eb2SJim Harris 	struct spdk_fs_request *sync_req;
2199a6014eb2SJim Harris 
2200a6014eb2SJim Harris 	pthread_spin_lock(&file->lock);
2201a6014eb2SJim Harris 
2202a6014eb2SJim Harris 	TAILQ_FOREACH(sync_req, &file->sync_requests, args.op.sync.tailq) {
2203a6014eb2SJim Harris 		if (sync_req->args.op.sync.offset <= file->length_flushed) {
2204a6014eb2SJim Harris 			break;
2205a6014eb2SJim Harris 		}
2206a6014eb2SJim Harris 	}
2207a6014eb2SJim Harris 
2208a6014eb2SJim Harris 	if (sync_req != NULL && !sync_req->args.op.sync.xattr_in_progress) {
2209a6014eb2SJim Harris 		BLOBFS_TRACE(file, "set xattr length 0x%jx\n", file->length_flushed);
2210a6014eb2SJim Harris 		sync_req->args.op.sync.xattr_in_progress = true;
2211e967dcd2SJim Harris 		sync_req->args.op.sync.length = file->length_flushed;
22122c3591f1SJim Harris 		spdk_blob_set_xattr(file->blob, "length", &file->length_flushed,
2213a6014eb2SJim Harris 				    sizeof(file->length_flushed));
2214a6014eb2SJim Harris 
2215a6014eb2SJim Harris 		pthread_spin_unlock(&file->lock);
2216f71fed21SJim Harris 		spdk_trace_record(TRACE_BLOBFS_XATTR_START, 0, file->length_flushed,
22173e158bd5SKonrad Sztyber 				  0, file->name);
22189602ade7SZiye Yang 		spdk_blob_sync_md(file->blob, __file_cache_finish_sync, sync_req);
2219a6014eb2SJim Harris 	} else {
2220a6014eb2SJim Harris 		pthread_spin_unlock(&file->lock);
2221a6014eb2SJim Harris 	}
2222a6014eb2SJim Harris }
2223a6014eb2SJim Harris 
2224a6014eb2SJim Harris static void
2225125797e0SChangpeng Liu __file_flush_done(void *ctx, int bserrno)
22261edd9bf3SJim Harris {
2227125797e0SChangpeng Liu 	struct spdk_fs_request *req = ctx;
2228125797e0SChangpeng Liu 	struct spdk_fs_cb_args *args = &req->args;
22291edd9bf3SJim Harris 	struct spdk_file *file = args->file;
22301edd9bf3SJim Harris 	struct cache_buffer *next = args->op.flush.cache_buffer;
22311edd9bf3SJim Harris 
22321edd9bf3SJim Harris 	BLOBFS_TRACE(file, "length=%jx\n", args->op.flush.length);
22331edd9bf3SJim Harris 
22341edd9bf3SJim Harris 	pthread_spin_lock(&file->lock);
22351edd9bf3SJim Harris 	next->in_progress = false;
22361edd9bf3SJim Harris 	next->bytes_flushed += args->op.flush.length;
22371edd9bf3SJim Harris 	file->length_flushed += args->op.flush.length;
22381edd9bf3SJim Harris 	if (file->length_flushed > file->length) {
22391edd9bf3SJim Harris 		file->length = file->length_flushed;
22401edd9bf3SJim Harris 	}
22411edd9bf3SJim Harris 	if (next->bytes_flushed == next->buf_size) {
22421edd9bf3SJim Harris 		BLOBFS_TRACE(file, "write buffer fully flushed 0x%jx\n", file->length_flushed);
2243bc0180f6SSeth Howell 		next = tree_find_buffer(file->tree, file->length_flushed);
22441edd9bf3SJim Harris 	}
22451edd9bf3SJim Harris 
224664467825SZiye Yang 	/*
224764467825SZiye Yang 	 * Assert that there is no cached data that extends past the end of the underlying
224864467825SZiye Yang 	 *  blob.
224964467825SZiye Yang 	 */
225064467825SZiye Yang 	assert(next == NULL || next->offset < __file_get_blob_size(file) ||
225164467825SZiye Yang 	       next->bytes_filled == 0);
225264467825SZiye Yang 
2253a6014eb2SJim Harris 	pthread_spin_unlock(&file->lock);
22541edd9bf3SJim Harris 
2255a6014eb2SJim Harris 	__check_sync_reqs(file);
22561edd9bf3SJim Harris 
2257125797e0SChangpeng Liu 	__file_flush(req);
22581edd9bf3SJim Harris }
22591edd9bf3SJim Harris 
22601edd9bf3SJim Harris static void
2261125797e0SChangpeng Liu __file_flush(void *ctx)
22621edd9bf3SJim Harris {
2263125797e0SChangpeng Liu 	struct spdk_fs_request *req = ctx;
2264125797e0SChangpeng Liu 	struct spdk_fs_cb_args *args = &req->args;
22651edd9bf3SJim Harris 	struct spdk_file *file = args->file;
22661edd9bf3SJim Harris 	struct cache_buffer *next;
2267be2d2c76SPiotr Pelplinski 	uint64_t offset, length, start_lba, num_lba;
2268be2d2c76SPiotr Pelplinski 	uint32_t lba_size;
22691edd9bf3SJim Harris 
22701edd9bf3SJim Harris 	pthread_spin_lock(&file->lock);
2271bc0180f6SSeth Howell 	next = tree_find_buffer(file->tree, file->length_flushed);
2272cdd089a8SJim Harris 	if (next == NULL || next->in_progress ||
2273cdd089a8SJim Harris 	    ((next->bytes_filled < next->buf_size) && TAILQ_EMPTY(&file->sync_requests))) {
22741edd9bf3SJim Harris 		/*
2275cdd089a8SJim Harris 		 * There is either no data to flush, a flush I/O is already in
2276cdd089a8SJim Harris 		 *  progress, or the next buffer is partially filled but there's no
2277cdd089a8SJim Harris 		 *  outstanding request to sync it.
2278cdd089a8SJim Harris 		 * So return immediately - if a flush I/O is in progress we will flush
2279cdd089a8SJim Harris 		 *  more data after that is completed, or a partial buffer will get flushed
2280cdd089a8SJim Harris 		 *  when it is either filled or the file is synced.
22811edd9bf3SJim Harris 		 */
2282125797e0SChangpeng Liu 		free_fs_request(req);
22831831b086SJim Harris 		if (next == NULL) {
22841831b086SJim Harris 			/*
22851831b086SJim Harris 			 * For cases where a file's cache was evicted, and then the
22861831b086SJim Harris 			 *  file was later appended, we will write the data directly
22871831b086SJim Harris 			 *  to disk and bypass cache.  So just update length_flushed
22881831b086SJim Harris 			 *  here to reflect that all data was already written to disk.
22891831b086SJim Harris 			 */
22901831b086SJim Harris 			file->length_flushed = file->append_pos;
22911831b086SJim Harris 		}
22921edd9bf3SJim Harris 		pthread_spin_unlock(&file->lock);
22931831b086SJim Harris 		if (next == NULL) {
22941831b086SJim Harris 			/*
22951831b086SJim Harris 			 * There is no data to flush, but we still need to check for any
22961831b086SJim Harris 			 *  outstanding sync requests to make sure metadata gets updated.
22971831b086SJim Harris 			 */
22981831b086SJim Harris 			__check_sync_reqs(file);
22991831b086SJim Harris 		}
23001edd9bf3SJim Harris 		return;
23011edd9bf3SJim Harris 	}
23021edd9bf3SJim Harris 
23031edd9bf3SJim Harris 	offset = next->offset + next->bytes_flushed;
23041edd9bf3SJim Harris 	length = next->bytes_filled - next->bytes_flushed;
23051edd9bf3SJim Harris 	if (length == 0) {
2306125797e0SChangpeng Liu 		free_fs_request(req);
23071edd9bf3SJim Harris 		pthread_spin_unlock(&file->lock);
2308e967dcd2SJim Harris 		/*
2309e967dcd2SJim Harris 		 * There is no data to flush, but we still need to check for any
2310e967dcd2SJim Harris 		 *  outstanding sync requests to make sure metadata gets updated.
2311e967dcd2SJim Harris 		 */
2312e967dcd2SJim Harris 		__check_sync_reqs(file);
23131edd9bf3SJim Harris 		return;
23141edd9bf3SJim Harris 	}
23151edd9bf3SJim Harris 	args->op.flush.length = length;
23161edd9bf3SJim Harris 	args->op.flush.cache_buffer = next;
23171edd9bf3SJim Harris 
2318be2d2c76SPiotr Pelplinski 	__get_page_parameters(file, offset, length, &start_lba, &lba_size, &num_lba);
23191edd9bf3SJim Harris 
23201edd9bf3SJim Harris 	next->in_progress = true;
2321391dd1c2SGangCao 	BLOBFS_TRACE(file, "offset=0x%jx length=0x%jx page start=0x%jx num=0x%jx\n",
2322be2d2c76SPiotr Pelplinski 		     offset, length, start_lba, num_lba);
23231edd9bf3SJim Harris 	pthread_spin_unlock(&file->lock);
232466fc591fSJim Harris 	spdk_blob_io_write(file->blob, file->fs->sync_target.sync_fs_channel->bs_channel,
2325be2d2c76SPiotr Pelplinski 			   next->buf + (start_lba * lba_size) - next->offset,
2326125797e0SChangpeng Liu 			   start_lba, num_lba, __file_flush_done, req);
23271edd9bf3SJim Harris }
23281edd9bf3SJim Harris 
23291edd9bf3SJim Harris static void
23301edd9bf3SJim Harris __file_extend_done(void *arg, int bserrno)
23311edd9bf3SJim Harris {
23321edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = arg;
23331edd9bf3SJim Harris 
2334f1e14ef4SChangpeng Liu 	__wake_caller(args, bserrno);
23351edd9bf3SJim Harris }
23361edd9bf3SJim Harris 
23371edd9bf3SJim Harris static void
2338463925ffSJim Harris __file_extend_resize_cb(void *_args, int bserrno)
2339463925ffSJim Harris {
2340463925ffSJim Harris 	struct spdk_fs_cb_args *args = _args;
2341463925ffSJim Harris 	struct spdk_file *file = args->file;
2342463925ffSJim Harris 
2343f1e14ef4SChangpeng Liu 	if (bserrno) {
2344f1e14ef4SChangpeng Liu 		__wake_caller(args, bserrno);
2345f1e14ef4SChangpeng Liu 		return;
2346f1e14ef4SChangpeng Liu 	}
2347f1e14ef4SChangpeng Liu 
2348463925ffSJim Harris 	spdk_blob_sync_md(file->blob, __file_extend_done, args);
2349463925ffSJim Harris }
2350463925ffSJim Harris 
2351463925ffSJim Harris static void
23521edd9bf3SJim Harris __file_extend_blob(void *_args)
23531edd9bf3SJim Harris {
23541edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = _args;
23551edd9bf3SJim Harris 	struct spdk_file *file = args->file;
23561edd9bf3SJim Harris 
2357463925ffSJim Harris 	spdk_blob_resize(file->blob, args->op.resize.num_clusters, __file_extend_resize_cb, args);
23581edd9bf3SJim Harris }
23591edd9bf3SJim Harris 
23601edd9bf3SJim Harris static void
23610d4735eaSChangpeng Liu __rw_from_file_done(void *ctx, int bserrno)
23621edd9bf3SJim Harris {
23630d4735eaSChangpeng Liu 	struct spdk_fs_request *req = ctx;
23641edd9bf3SJim Harris 
23650d4735eaSChangpeng Liu 	__wake_caller(&req->args, bserrno);
23660d4735eaSChangpeng Liu 	free_fs_request(req);
23671edd9bf3SJim Harris }
23681edd9bf3SJim Harris 
23691edd9bf3SJim Harris static void
23700d4735eaSChangpeng Liu __rw_from_file(void *ctx)
23711edd9bf3SJim Harris {
23720d4735eaSChangpeng Liu 	struct spdk_fs_request *req = ctx;
23730d4735eaSChangpeng Liu 	struct spdk_fs_cb_args *args = &req->args;
23741edd9bf3SJim Harris 	struct spdk_file *file = args->file;
23751edd9bf3SJim Harris 
23761edd9bf3SJim Harris 	if (args->op.rw.is_read) {
2377ceb6ef89SChangpeng Liu 		spdk_file_read_async(file, file->fs->sync_target.sync_io_channel, args->iovs[0].iov_base,
2378ceb6ef89SChangpeng Liu 				     args->op.rw.offset, (uint64_t)args->iovs[0].iov_len,
23790d4735eaSChangpeng Liu 				     __rw_from_file_done, req);
23801edd9bf3SJim Harris 	} else {
2381ceb6ef89SChangpeng Liu 		spdk_file_write_async(file, file->fs->sync_target.sync_io_channel, args->iovs[0].iov_base,
2382ceb6ef89SChangpeng Liu 				      args->op.rw.offset, (uint64_t)args->iovs[0].iov_len,
23830d4735eaSChangpeng Liu 				      __rw_from_file_done, req);
23841edd9bf3SJim Harris 	}
23851edd9bf3SJim Harris }
23861edd9bf3SJim Harris 
2387944a480eSJimboLuCN struct rw_from_file_arg {
2388944a480eSJimboLuCN 	struct spdk_fs_channel *channel;
2389944a480eSJimboLuCN 	int rwerrno;
2390944a480eSJimboLuCN };
2391944a480eSJimboLuCN 
23921edd9bf3SJim Harris static int
23930d4735eaSChangpeng Liu __send_rw_from_file(struct spdk_file *file, void *payload,
23940d4735eaSChangpeng Liu 		    uint64_t offset, uint64_t length, bool is_read,
2395944a480eSJimboLuCN 		    struct rw_from_file_arg *arg)
23961edd9bf3SJim Harris {
23970d4735eaSChangpeng Liu 	struct spdk_fs_request *req;
23981edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
23991edd9bf3SJim Harris 
2400944a480eSJimboLuCN 	req = alloc_fs_request_with_iov(arg->channel, 1);
24010d4735eaSChangpeng Liu 	if (req == NULL) {
2402944a480eSJimboLuCN 		sem_post(&arg->channel->sem);
24031edd9bf3SJim Harris 		return -ENOMEM;
24041edd9bf3SJim Harris 	}
24051edd9bf3SJim Harris 
24060d4735eaSChangpeng Liu 	args = &req->args;
24071edd9bf3SJim Harris 	args->file = file;
2408944a480eSJimboLuCN 	args->sem = &arg->channel->sem;
2409ceb6ef89SChangpeng Liu 	args->iovs[0].iov_base = payload;
2410ceb6ef89SChangpeng Liu 	args->iovs[0].iov_len = (size_t)length;
24111edd9bf3SJim Harris 	args->op.rw.offset = offset;
24121edd9bf3SJim Harris 	args->op.rw.is_read = is_read;
2413944a480eSJimboLuCN 	args->rwerrno = &arg->rwerrno;
24140d4735eaSChangpeng Liu 	file->fs->send_request(__rw_from_file, req);
24151edd9bf3SJim Harris 	return 0;
24161edd9bf3SJim Harris }
24171edd9bf3SJim Harris 
24181edd9bf3SJim Harris int
2419e9d400d5SBen Walker spdk_file_write(struct spdk_file *file, struct spdk_fs_thread_ctx *ctx,
24201edd9bf3SJim Harris 		void *payload, uint64_t offset, uint64_t length)
24211edd9bf3SJim Harris {
2422e9d400d5SBen Walker 	struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
2423125797e0SChangpeng Liu 	struct spdk_fs_request *flush_req;
24241edd9bf3SJim Harris 	uint64_t rem_length, copy, blob_size, cluster_sz;
24251edd9bf3SJim Harris 	uint32_t cache_buffers_filled = 0;
24261edd9bf3SJim Harris 	uint8_t *cur_payload;
24271edd9bf3SJim Harris 	struct cache_buffer *last;
24281edd9bf3SJim Harris 
24291edd9bf3SJim Harris 	BLOBFS_TRACE_RW(file, "offset=%jx length=%jx\n", offset, length);
24301edd9bf3SJim Harris 
24311edd9bf3SJim Harris 	if (length == 0) {
24321edd9bf3SJim Harris 		return 0;
24331edd9bf3SJim Harris 	}
24341edd9bf3SJim Harris 
24351edd9bf3SJim Harris 	if (offset != file->append_pos) {
24361edd9bf3SJim Harris 		BLOBFS_TRACE(file, " error offset=%jx append_pos=%jx\n", offset, file->append_pos);
24371edd9bf3SJim Harris 		return -EINVAL;
24381edd9bf3SJim Harris 	}
24391edd9bf3SJim Harris 
24401edd9bf3SJim Harris 	pthread_spin_lock(&file->lock);
24411edd9bf3SJim Harris 	file->open_for_writing = true;
24421edd9bf3SJim Harris 
244352939f25SLiYankun 	do {
2444b151999fSZiye Yang 		if ((file->last == NULL) && (file->append_pos % CACHE_BUFFER_SIZE == 0)) {
24451edd9bf3SJim Harris 			cache_append_buffer(file);
2446b151999fSZiye Yang 		}
2447b151999fSZiye Yang 
2448b151999fSZiye Yang 		if (file->last == NULL) {
2449944a480eSJimboLuCN 			struct rw_from_file_arg arg = {};
24501edd9bf3SJim Harris 			int rc;
24511edd9bf3SJim Harris 
2452944a480eSJimboLuCN 			arg.channel = channel;
2453944a480eSJimboLuCN 			arg.rwerrno = 0;
24541edd9bf3SJim Harris 			file->append_pos += length;
24551285f823SJim Harris 			pthread_spin_unlock(&file->lock);
2456944a480eSJimboLuCN 			rc = __send_rw_from_file(file, payload, offset, length, false, &arg);
2457944a480eSJimboLuCN 			if (rc != 0) {
24581edd9bf3SJim Harris 				return rc;
24591edd9bf3SJim Harris 			}
2460944a480eSJimboLuCN 			sem_wait(&channel->sem);
2461944a480eSJimboLuCN 			return arg.rwerrno;
2462944a480eSJimboLuCN 		}
24631edd9bf3SJim Harris 
24641edd9bf3SJim Harris 		blob_size = __file_get_blob_size(file);
24651edd9bf3SJim Harris 
24661edd9bf3SJim Harris 		if ((offset + length) > blob_size) {
24671edd9bf3SJim Harris 			struct spdk_fs_cb_args extend_args = {};
24681edd9bf3SJim Harris 
24691edd9bf3SJim Harris 			cluster_sz = file->fs->bs_opts.cluster_sz;
24701edd9bf3SJim Harris 			extend_args.sem = &channel->sem;
24711edd9bf3SJim Harris 			extend_args.op.resize.num_clusters = __bytes_to_clusters((offset + length), cluster_sz);
24721edd9bf3SJim Harris 			extend_args.file = file;
24731edd9bf3SJim Harris 			BLOBFS_TRACE(file, "start resize to %u clusters\n", extend_args.op.resize.num_clusters);
24741edd9bf3SJim Harris 			pthread_spin_unlock(&file->lock);
24751edd9bf3SJim Harris 			file->fs->send_request(__file_extend_blob, &extend_args);
24761edd9bf3SJim Harris 			sem_wait(&channel->sem);
2477f1e14ef4SChangpeng Liu 			if (extend_args.rc) {
2478f1e14ef4SChangpeng Liu 				return extend_args.rc;
2479f1e14ef4SChangpeng Liu 			}
2480bf94bb78SGangCao 			pthread_spin_lock(&file->lock);
24811edd9bf3SJim Harris 		}
248252939f25SLiYankun 	} while (file->last == NULL);
24831edd9bf3SJim Harris 
2484125797e0SChangpeng Liu 	flush_req = alloc_fs_request(channel);
2485125797e0SChangpeng Liu 	if (flush_req == NULL) {
24863732429cSChangpeng Liu 		pthread_spin_unlock(&file->lock);
24873732429cSChangpeng Liu 		return -ENOMEM;
24883732429cSChangpeng Liu 	}
24893732429cSChangpeng Liu 
24901edd9bf3SJim Harris 	last = file->last;
24911edd9bf3SJim Harris 	rem_length = length;
24921edd9bf3SJim Harris 	cur_payload = payload;
24931edd9bf3SJim Harris 	while (rem_length > 0) {
24941edd9bf3SJim Harris 		copy = last->buf_size - last->bytes_filled;
24951edd9bf3SJim Harris 		if (copy > rem_length) {
24961edd9bf3SJim Harris 			copy = rem_length;
24971edd9bf3SJim Harris 		}
24981edd9bf3SJim Harris 		BLOBFS_TRACE_RW(file, "  fill offset=%jx length=%jx\n", file->append_pos, copy);
24991edd9bf3SJim Harris 		memcpy(&last->buf[last->bytes_filled], cur_payload, copy);
25001edd9bf3SJim Harris 		file->append_pos += copy;
25011edd9bf3SJim Harris 		if (file->length < file->append_pos) {
25021edd9bf3SJim Harris 			file->length = file->append_pos;
25031edd9bf3SJim Harris 		}
25041edd9bf3SJim Harris 		cur_payload += copy;
25051edd9bf3SJim Harris 		last->bytes_filled += copy;
25061edd9bf3SJim Harris 		rem_length -= copy;
25071edd9bf3SJim Harris 		if (last->bytes_filled == last->buf_size) {
25081edd9bf3SJim Harris 			cache_buffers_filled++;
25091edd9bf3SJim Harris 			last = cache_append_buffer(file);
25101edd9bf3SJim Harris 			if (last == NULL) {
25111edd9bf3SJim Harris 				BLOBFS_TRACE(file, "nomem\n");
2512125797e0SChangpeng Liu 				free_fs_request(flush_req);
25131edd9bf3SJim Harris 				pthread_spin_unlock(&file->lock);
25141edd9bf3SJim Harris 				return -ENOMEM;
25151edd9bf3SJim Harris 			}
25161edd9bf3SJim Harris 		}
25171edd9bf3SJim Harris 	}
25181edd9bf3SJim Harris 
25191edd9bf3SJim Harris 	pthread_spin_unlock(&file->lock);
2520edc5610fSCunyin Chang 
2521edc5610fSCunyin Chang 	if (cache_buffers_filled == 0) {
2522125797e0SChangpeng Liu 		free_fs_request(flush_req);
25231edd9bf3SJim Harris 		return 0;
25241edd9bf3SJim Harris 	}
25251edd9bf3SJim Harris 
2526125797e0SChangpeng Liu 	flush_req->args.file = file;
2527125797e0SChangpeng Liu 	file->fs->send_request(__file_flush, flush_req);
25281edd9bf3SJim Harris 	return 0;
25291edd9bf3SJim Harris }
25301edd9bf3SJim Harris 
25311edd9bf3SJim Harris static void
2532824cda20SChangpeng Liu __readahead_done(void *ctx, int bserrno)
25331edd9bf3SJim Harris {
2534824cda20SChangpeng Liu 	struct spdk_fs_request *req = ctx;
2535824cda20SChangpeng Liu 	struct spdk_fs_cb_args *args = &req->args;
25361edd9bf3SJim Harris 	struct cache_buffer *cache_buffer = args->op.readahead.cache_buffer;
25371edd9bf3SJim Harris 	struct spdk_file *file = args->file;
25381edd9bf3SJim Harris 
25391edd9bf3SJim Harris 	BLOBFS_TRACE(file, "offset=%jx\n", cache_buffer->offset);
25401edd9bf3SJim Harris 
25411edd9bf3SJim Harris 	pthread_spin_lock(&file->lock);
25421edd9bf3SJim Harris 	cache_buffer->bytes_filled = args->op.readahead.length;
25431edd9bf3SJim Harris 	cache_buffer->bytes_flushed = args->op.readahead.length;
25441edd9bf3SJim Harris 	cache_buffer->in_progress = false;
25451edd9bf3SJim Harris 	pthread_spin_unlock(&file->lock);
25461edd9bf3SJim Harris 
2547824cda20SChangpeng Liu 	free_fs_request(req);
25481edd9bf3SJim Harris }
25491edd9bf3SJim Harris 
25501edd9bf3SJim Harris static void
2551824cda20SChangpeng Liu __readahead(void *ctx)
25521edd9bf3SJim Harris {
2553824cda20SChangpeng Liu 	struct spdk_fs_request *req = ctx;
2554824cda20SChangpeng Liu 	struct spdk_fs_cb_args *args = &req->args;
25551edd9bf3SJim Harris 	struct spdk_file *file = args->file;
2556be2d2c76SPiotr Pelplinski 	uint64_t offset, length, start_lba, num_lba;
2557be2d2c76SPiotr Pelplinski 	uint32_t lba_size;
25581edd9bf3SJim Harris 
25591edd9bf3SJim Harris 	offset = args->op.readahead.offset;
25601edd9bf3SJim Harris 	length = args->op.readahead.length;
25611edd9bf3SJim Harris 	assert(length > 0);
25621edd9bf3SJim Harris 
2563be2d2c76SPiotr Pelplinski 	__get_page_parameters(file, offset, length, &start_lba, &lba_size, &num_lba);
25641edd9bf3SJim Harris 
25651edd9bf3SJim Harris 	BLOBFS_TRACE(file, "offset=%jx length=%jx page start=%jx num=%jx\n",
2566be2d2c76SPiotr Pelplinski 		     offset, length, start_lba, num_lba);
256766fc591fSJim Harris 	spdk_blob_io_read(file->blob, file->fs->sync_target.sync_fs_channel->bs_channel,
25681edd9bf3SJim Harris 			  args->op.readahead.cache_buffer->buf,
2569824cda20SChangpeng Liu 			  start_lba, num_lba, __readahead_done, req);
25701edd9bf3SJim Harris }
25711edd9bf3SJim Harris 
25721edd9bf3SJim Harris static uint64_t
25731edd9bf3SJim Harris __next_cache_buffer_offset(uint64_t offset)
25741edd9bf3SJim Harris {
25751edd9bf3SJim Harris 	return (offset + CACHE_BUFFER_SIZE) & ~(CACHE_TREE_LEVEL_MASK(0));
25761edd9bf3SJim Harris }
25771edd9bf3SJim Harris 
25781edd9bf3SJim Harris static void
2579824cda20SChangpeng Liu check_readahead(struct spdk_file *file, uint64_t offset,
2580824cda20SChangpeng Liu 		struct spdk_fs_channel *channel)
25811edd9bf3SJim Harris {
2582824cda20SChangpeng Liu 	struct spdk_fs_request *req;
25831edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
25841edd9bf3SJim Harris 
25851edd9bf3SJim Harris 	offset = __next_cache_buffer_offset(offset);
2586bc0180f6SSeth Howell 	if (tree_find_buffer(file->tree, offset) != NULL || file->length <= offset) {
25871edd9bf3SJim Harris 		return;
25881edd9bf3SJim Harris 	}
25891edd9bf3SJim Harris 
2590824cda20SChangpeng Liu 	req = alloc_fs_request(channel);
2591824cda20SChangpeng Liu 	if (req == NULL) {
259257986fb8SGangCao 		return;
259357986fb8SGangCao 	}
2594824cda20SChangpeng Liu 	args = &req->args;
259557986fb8SGangCao 
259657986fb8SGangCao 	BLOBFS_TRACE(file, "offset=%jx\n", offset);
259757986fb8SGangCao 
25981edd9bf3SJim Harris 	args->file = file;
25991edd9bf3SJim Harris 	args->op.readahead.offset = offset;
26001edd9bf3SJim Harris 	args->op.readahead.cache_buffer = cache_insert_buffer(file, offset);
2601db6e1105SZiye Yang 	if (!args->op.readahead.cache_buffer) {
2602db6e1105SZiye Yang 		BLOBFS_TRACE(file, "Cannot allocate buf for offset=%jx\n", offset);
2603824cda20SChangpeng Liu 		free_fs_request(req);
2604db6e1105SZiye Yang 		return;
2605db6e1105SZiye Yang 	}
2606db6e1105SZiye Yang 
26071edd9bf3SJim Harris 	args->op.readahead.cache_buffer->in_progress = true;
26081edd9bf3SJim Harris 	if (file->length < (offset + CACHE_BUFFER_SIZE)) {
26091edd9bf3SJim Harris 		args->op.readahead.length = file->length & (CACHE_BUFFER_SIZE - 1);
26101edd9bf3SJim Harris 	} else {
26111edd9bf3SJim Harris 		args->op.readahead.length = CACHE_BUFFER_SIZE;
26121edd9bf3SJim Harris 	}
2613824cda20SChangpeng Liu 	file->fs->send_request(__readahead, req);
26141edd9bf3SJim Harris }
26151edd9bf3SJim Harris 
26161edd9bf3SJim Harris int64_t
2617e9d400d5SBen Walker spdk_file_read(struct spdk_file *file, struct spdk_fs_thread_ctx *ctx,
26181edd9bf3SJim Harris 	       void *payload, uint64_t offset, uint64_t length)
26191edd9bf3SJim Harris {
2620e9d400d5SBen Walker 	struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
26211edd9bf3SJim Harris 	uint64_t final_offset, final_length;
26221edd9bf3SJim Harris 	uint32_t sub_reads = 0;
26232505b938SChangpeng Liu 	struct cache_buffer *buf;
26242505b938SChangpeng Liu 	uint64_t read_len;
2625944a480eSJimboLuCN 	struct rw_from_file_arg arg = {};
26261edd9bf3SJim Harris 
26271edd9bf3SJim Harris 	pthread_spin_lock(&file->lock);
26281edd9bf3SJim Harris 
26291edd9bf3SJim Harris 	BLOBFS_TRACE_RW(file, "offset=%ju length=%ju\n", offset, length);
26301edd9bf3SJim Harris 
26311edd9bf3SJim Harris 	file->open_for_writing = false;
26321edd9bf3SJim Harris 
263345f7571aSBen Walker 	if (length == 0 || offset >= file->append_pos) {
26341edd9bf3SJim Harris 		pthread_spin_unlock(&file->lock);
26351edd9bf3SJim Harris 		return 0;
26361edd9bf3SJim Harris 	}
26371edd9bf3SJim Harris 
263845f7571aSBen Walker 	if (offset + length > file->append_pos) {
263945f7571aSBen Walker 		length = file->append_pos - offset;
26401edd9bf3SJim Harris 	}
26411edd9bf3SJim Harris 
26421edd9bf3SJim Harris 	if (offset != file->next_seq_offset) {
26431edd9bf3SJim Harris 		file->seq_byte_count = 0;
26441edd9bf3SJim Harris 	}
26451edd9bf3SJim Harris 	file->seq_byte_count += length;
26461edd9bf3SJim Harris 	file->next_seq_offset = offset + length;
26471edd9bf3SJim Harris 	if (file->seq_byte_count >= CACHE_READAHEAD_THRESHOLD) {
2648824cda20SChangpeng Liu 		check_readahead(file, offset, channel);
2649824cda20SChangpeng Liu 		check_readahead(file, offset + CACHE_BUFFER_SIZE, channel);
26501edd9bf3SJim Harris 	}
26511edd9bf3SJim Harris 
2652944a480eSJimboLuCN 	arg.channel = channel;
2653944a480eSJimboLuCN 	arg.rwerrno = 0;
26541edd9bf3SJim Harris 	final_length = 0;
26551edd9bf3SJim Harris 	final_offset = offset + length;
26561edd9bf3SJim Harris 	while (offset < final_offset) {
2657944a480eSJimboLuCN 		int ret = 0;
26581edd9bf3SJim Harris 		length = NEXT_CACHE_BUFFER_OFFSET(offset) - offset;
26591edd9bf3SJim Harris 		if (length > (final_offset - offset)) {
26601edd9bf3SJim Harris 			length = final_offset - offset;
26611edd9bf3SJim Harris 		}
2662bc1495b0SZiye Yang 
2663bc0180f6SSeth Howell 		buf = tree_find_filled_buffer(file->tree, offset);
26642505b938SChangpeng Liu 		if (buf == NULL) {
26652505b938SChangpeng Liu 			pthread_spin_unlock(&file->lock);
2666944a480eSJimboLuCN 			ret = __send_rw_from_file(file, payload, offset, length, true, &arg);
26672505b938SChangpeng Liu 			pthread_spin_lock(&file->lock);
2668944a480eSJimboLuCN 			if (ret == 0) {
2669bc1495b0SZiye Yang 				sub_reads++;
26702505b938SChangpeng Liu 			}
26712505b938SChangpeng Liu 		} else {
26722505b938SChangpeng Liu 			read_len = length;
26732505b938SChangpeng Liu 			if ((offset + length) > (buf->offset + buf->bytes_filled)) {
26742505b938SChangpeng Liu 				read_len = buf->offset + buf->bytes_filled - offset;
26752505b938SChangpeng Liu 			}
26762505b938SChangpeng Liu 			BLOBFS_TRACE(file, "read %p offset=%ju length=%ju\n", payload, offset, read_len);
26772505b938SChangpeng Liu 			memcpy(payload, &buf->buf[offset - buf->offset], read_len);
26782505b938SChangpeng Liu 			if ((offset + read_len) % CACHE_BUFFER_SIZE == 0) {
2679bc0180f6SSeth Howell 				tree_remove_buffer(file->tree, buf);
26802505b938SChangpeng Liu 				if (file->tree->present_mask == 0) {
268176d23f6fSChangpeng Liu 					spdk_thread_send_msg(g_cache_pool_thread, _remove_file_from_cache_pool, file);
26822505b938SChangpeng Liu 				}
26832505b938SChangpeng Liu 			}
26842505b938SChangpeng Liu 		}
26852505b938SChangpeng Liu 
2686944a480eSJimboLuCN 		if (ret == 0) {
26871edd9bf3SJim Harris 			final_length += length;
26881edd9bf3SJim Harris 		} else {
2689944a480eSJimboLuCN 			arg.rwerrno = ret;
26901edd9bf3SJim Harris 			break;
26911edd9bf3SJim Harris 		}
26921edd9bf3SJim Harris 		payload += length;
26931edd9bf3SJim Harris 		offset += length;
26941edd9bf3SJim Harris 	}
26951edd9bf3SJim Harris 	pthread_spin_unlock(&file->lock);
26962505b938SChangpeng Liu 	while (sub_reads > 0) {
26971edd9bf3SJim Harris 		sem_wait(&channel->sem);
26982505b938SChangpeng Liu 		sub_reads--;
26991edd9bf3SJim Harris 	}
2700944a480eSJimboLuCN 	if (arg.rwerrno == 0) {
27011edd9bf3SJim Harris 		return final_length;
27021edd9bf3SJim Harris 	} else {
2703944a480eSJimboLuCN 		return arg.rwerrno;
27041edd9bf3SJim Harris 	}
27051edd9bf3SJim Harris }
27061edd9bf3SJim Harris 
27071edd9bf3SJim Harris static void
27081edd9bf3SJim Harris _file_sync(struct spdk_file *file, struct spdk_fs_channel *channel,
27091edd9bf3SJim Harris 	   spdk_file_op_complete cb_fn, void *cb_arg)
27101edd9bf3SJim Harris {
27111edd9bf3SJim Harris 	struct spdk_fs_request *sync_req;
27121edd9bf3SJim Harris 	struct spdk_fs_request *flush_req;
27131edd9bf3SJim Harris 	struct spdk_fs_cb_args *sync_args;
27141edd9bf3SJim Harris 	struct spdk_fs_cb_args *flush_args;
27151edd9bf3SJim Harris 
27161edd9bf3SJim Harris 	BLOBFS_TRACE(file, "offset=%jx\n", file->append_pos);
27171edd9bf3SJim Harris 
27181edd9bf3SJim Harris 	pthread_spin_lock(&file->lock);
2719e967dcd2SJim Harris 	if (file->append_pos <= file->length_xattr) {
2720e967dcd2SJim Harris 		BLOBFS_TRACE(file, "done - file already synced\n");
27211edd9bf3SJim Harris 		pthread_spin_unlock(&file->lock);
27221edd9bf3SJim Harris 		cb_fn(cb_arg, 0);
27231edd9bf3SJim Harris 		return;
27241edd9bf3SJim Harris 	}
27251edd9bf3SJim Harris 
27261edd9bf3SJim Harris 	sync_req = alloc_fs_request(channel);
27270de89b36SZiye Yang 	if (!sync_req) {
2728a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate sync req for file=%s\n", file->name);
27290de89b36SZiye Yang 		pthread_spin_unlock(&file->lock);
27300de89b36SZiye Yang 		cb_fn(cb_arg, -ENOMEM);
27310de89b36SZiye Yang 		return;
27320de89b36SZiye Yang 	}
27331edd9bf3SJim Harris 	sync_args = &sync_req->args;
27341edd9bf3SJim Harris 
27351edd9bf3SJim Harris 	flush_req = alloc_fs_request(channel);
27360de89b36SZiye Yang 	if (!flush_req) {
2737a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate flush req for file=%s\n", file->name);
2738ea1132a9SChangpeng Liu 		free_fs_request(sync_req);
27390de89b36SZiye Yang 		pthread_spin_unlock(&file->lock);
27400de89b36SZiye Yang 		cb_fn(cb_arg, -ENOMEM);
27410de89b36SZiye Yang 		return;
27420de89b36SZiye Yang 	}
27431edd9bf3SJim Harris 	flush_args = &flush_req->args;
27441edd9bf3SJim Harris 
27451edd9bf3SJim Harris 	sync_args->file = file;
27461edd9bf3SJim Harris 	sync_args->fn.file_op = cb_fn;
27471edd9bf3SJim Harris 	sync_args->arg = cb_arg;
27481edd9bf3SJim Harris 	sync_args->op.sync.offset = file->append_pos;
2749a6014eb2SJim Harris 	sync_args->op.sync.xattr_in_progress = false;
27501edd9bf3SJim Harris 	TAILQ_INSERT_TAIL(&file->sync_requests, sync_req, args.op.sync.tailq);
27511edd9bf3SJim Harris 	pthread_spin_unlock(&file->lock);
27521edd9bf3SJim Harris 
27531edd9bf3SJim Harris 	flush_args->file = file;
2754125797e0SChangpeng Liu 	channel->send_request(__file_flush, flush_req);
27551edd9bf3SJim Harris }
27561edd9bf3SJim Harris 
27571edd9bf3SJim Harris int
2758e9d400d5SBen Walker spdk_file_sync(struct spdk_file *file, struct spdk_fs_thread_ctx *ctx)
27591edd9bf3SJim Harris {
2760e9d400d5SBen Walker 	struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
2761f1e14ef4SChangpeng Liu 	struct spdk_fs_cb_args args = {};
27621edd9bf3SJim Harris 
2763f1e14ef4SChangpeng Liu 	args.sem = &channel->sem;
2764f1e14ef4SChangpeng Liu 	_file_sync(file, channel, __wake_caller, &args);
27651edd9bf3SJim Harris 	sem_wait(&channel->sem);
27661edd9bf3SJim Harris 
2767f1e14ef4SChangpeng Liu 	return args.rc;
27681edd9bf3SJim Harris }
27691edd9bf3SJim Harris 
27701edd9bf3SJim Harris void
27711edd9bf3SJim Harris spdk_file_sync_async(struct spdk_file *file, struct spdk_io_channel *_channel,
27721edd9bf3SJim Harris 		     spdk_file_op_complete cb_fn, void *cb_arg)
27731edd9bf3SJim Harris {
27741edd9bf3SJim Harris 	struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel);
27751edd9bf3SJim Harris 
27761edd9bf3SJim Harris 	_file_sync(file, channel, cb_fn, cb_arg);
27771edd9bf3SJim Harris }
27781edd9bf3SJim Harris 
27791edd9bf3SJim Harris void
27801edd9bf3SJim Harris spdk_file_set_priority(struct spdk_file *file, uint32_t priority)
27811edd9bf3SJim Harris {
27821edd9bf3SJim Harris 	BLOBFS_TRACE(file, "priority=%u\n", priority);
27831edd9bf3SJim Harris 	file->priority = priority;
27841edd9bf3SJim Harris 
27851edd9bf3SJim Harris }
27861edd9bf3SJim Harris 
27871edd9bf3SJim Harris /*
27881edd9bf3SJim Harris  * Close routines
27891edd9bf3SJim Harris  */
27901edd9bf3SJim Harris 
27911edd9bf3SJim Harris static void
27921edd9bf3SJim Harris __file_close_async_done(void *ctx, int bserrno)
27931edd9bf3SJim Harris {
27941edd9bf3SJim Harris 	struct spdk_fs_request *req = ctx;
27951edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
27962d18887fSCunyin Chang 	struct spdk_file *file = args->file;
27971edd9bf3SJim Harris 
27983e158bd5SKonrad Sztyber 	spdk_trace_record(TRACE_BLOBFS_CLOSE, 0, 0, 0, file->name);
2799f71fed21SJim Harris 
28002d18887fSCunyin Chang 	if (file->is_deleted) {
28012d18887fSCunyin Chang 		spdk_fs_delete_file_async(file->fs, file->name, blob_delete_cb, ctx);
28022d18887fSCunyin Chang 		return;
28032d18887fSCunyin Chang 	}
2804cacfeef3SCunyin Chang 
28051edd9bf3SJim Harris 	args->fn.file_op(args->arg, bserrno);
28061edd9bf3SJim Harris 	free_fs_request(req);
28071edd9bf3SJim Harris }
28081edd9bf3SJim Harris 
28091edd9bf3SJim Harris static void
28101edd9bf3SJim Harris __file_close_async(struct spdk_file *file, struct spdk_fs_request *req)
28111edd9bf3SJim Harris {
2812e734bb9fSJim Harris 	struct spdk_blob *blob;
2813e734bb9fSJim Harris 
28141edd9bf3SJim Harris 	pthread_spin_lock(&file->lock);
28151edd9bf3SJim Harris 	if (file->ref_count == 0) {
28161edd9bf3SJim Harris 		pthread_spin_unlock(&file->lock);
28171edd9bf3SJim Harris 		__file_close_async_done(req, -EBADF);
28181edd9bf3SJim Harris 		return;
28191edd9bf3SJim Harris 	}
28201edd9bf3SJim Harris 
28211edd9bf3SJim Harris 	file->ref_count--;
28221edd9bf3SJim Harris 	if (file->ref_count > 0) {
28231edd9bf3SJim Harris 		pthread_spin_unlock(&file->lock);
2824cacfeef3SCunyin Chang 		req->args.fn.file_op(req->args.arg, 0);
2825cacfeef3SCunyin Chang 		free_fs_request(req);
28261edd9bf3SJim Harris 		return;
28271edd9bf3SJim Harris 	}
28281edd9bf3SJim Harris 
28291edd9bf3SJim Harris 	pthread_spin_unlock(&file->lock);
28301edd9bf3SJim Harris 
2831e734bb9fSJim Harris 	blob = file->blob;
2832e734bb9fSJim Harris 	file->blob = NULL;
2833e734bb9fSJim Harris 	spdk_blob_close(blob, __file_close_async_done, req);
28341edd9bf3SJim Harris }
28351edd9bf3SJim Harris 
28361edd9bf3SJim Harris static void
28371edd9bf3SJim Harris __file_close_async__sync_done(void *arg, int fserrno)
28381edd9bf3SJim Harris {
28391edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
28401edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
28411edd9bf3SJim Harris 
28421edd9bf3SJim Harris 	__file_close_async(args->file, req);
28431edd9bf3SJim Harris }
28441edd9bf3SJim Harris 
28451edd9bf3SJim Harris void
28461edd9bf3SJim Harris spdk_file_close_async(struct spdk_file *file, spdk_file_op_complete cb_fn, void *cb_arg)
28471edd9bf3SJim Harris {
28481edd9bf3SJim Harris 	struct spdk_fs_request *req;
28491edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
28501edd9bf3SJim Harris 
2851267a4e1eSBen Walker 	req = alloc_fs_request(file->fs->md_target.md_fs_channel);
28521edd9bf3SJim Harris 	if (req == NULL) {
2853a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate close async req for file=%s\n", file->name);
28541edd9bf3SJim Harris 		cb_fn(cb_arg, -ENOMEM);
28551edd9bf3SJim Harris 		return;
28561edd9bf3SJim Harris 	}
28571edd9bf3SJim Harris 
28581edd9bf3SJim Harris 	args = &req->args;
28591edd9bf3SJim Harris 	args->file = file;
28601edd9bf3SJim Harris 	args->fn.file_op = cb_fn;
28611edd9bf3SJim Harris 	args->arg = cb_arg;
28621edd9bf3SJim Harris 
2863267a4e1eSBen Walker 	spdk_file_sync_async(file, file->fs->md_target.md_io_channel, __file_close_async__sync_done, req);
28641edd9bf3SJim Harris }
28651edd9bf3SJim Harris 
28661edd9bf3SJim Harris static void
28671edd9bf3SJim Harris __file_close(void *arg)
28681edd9bf3SJim Harris {
28691edd9bf3SJim Harris 	struct spdk_fs_request *req = arg;
28701edd9bf3SJim Harris 	struct spdk_fs_cb_args *args = &req->args;
28711edd9bf3SJim Harris 	struct spdk_file *file = args->file;
28721edd9bf3SJim Harris 
28731edd9bf3SJim Harris 	__file_close_async(file, req);
28741edd9bf3SJim Harris }
28751edd9bf3SJim Harris 
28761edd9bf3SJim Harris int
2877e9d400d5SBen Walker spdk_file_close(struct spdk_file *file, struct spdk_fs_thread_ctx *ctx)
28781edd9bf3SJim Harris {
2879e9d400d5SBen Walker 	struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
28801edd9bf3SJim Harris 	struct spdk_fs_request *req;
28811edd9bf3SJim Harris 	struct spdk_fs_cb_args *args;
28821edd9bf3SJim Harris 
28831edd9bf3SJim Harris 	req = alloc_fs_request(channel);
28840de89b36SZiye Yang 	if (req == NULL) {
2885a7317317SZiye Yang 		SPDK_ERRLOG("Cannot allocate close req for file=%s\n", file->name);
28860de89b36SZiye Yang 		return -ENOMEM;
28870de89b36SZiye Yang 	}
28881edd9bf3SJim Harris 
28891edd9bf3SJim Harris 	args = &req->args;
28901edd9bf3SJim Harris 
2891e9d400d5SBen Walker 	spdk_file_sync(file, ctx);
28921edd9bf3SJim Harris 	BLOBFS_TRACE(file, "name=%s\n", file->name);
28931edd9bf3SJim Harris 	args->file = file;
28941edd9bf3SJim Harris 	args->sem = &channel->sem;
2895b1430065SChangpeng Liu 	args->fn.file_op = __wake_caller;
2896dfbbcc74SZiye Yang 	args->arg = args;
28971edd9bf3SJim Harris 	channel->send_request(__file_close, req);
28981edd9bf3SJim Harris 	sem_wait(&channel->sem);
28991edd9bf3SJim Harris 
29001edd9bf3SJim Harris 	return args->rc;
29011edd9bf3SJim Harris }
29021edd9bf3SJim Harris 
290318261f84SChangpeng Liu int
290418261f84SChangpeng Liu spdk_file_get_id(struct spdk_file *file, void *id, size_t size)
290518261f84SChangpeng Liu {
290618261f84SChangpeng Liu 	if (size < sizeof(spdk_blob_id)) {
290718261f84SChangpeng Liu 		return -EINVAL;
290818261f84SChangpeng Liu 	}
290918261f84SChangpeng Liu 
291018261f84SChangpeng Liu 	memcpy(id, &file->blobid, sizeof(spdk_blob_id));
291118261f84SChangpeng Liu 
291218261f84SChangpeng Liu 	return sizeof(spdk_blob_id);
291318261f84SChangpeng Liu }
291418261f84SChangpeng Liu 
29151edd9bf3SJim Harris static void
291687d5d832SChangpeng Liu _file_free(void *ctx)
291787d5d832SChangpeng Liu {
291887d5d832SChangpeng Liu 	struct spdk_file *file = ctx;
291987d5d832SChangpeng Liu 
292087d5d832SChangpeng Liu 	TAILQ_REMOVE(&g_caches, file, cache_tailq);
292187d5d832SChangpeng Liu 
292287d5d832SChangpeng Liu 	free(file->name);
292387d5d832SChangpeng Liu 	free(file->tree);
292487d5d832SChangpeng Liu 	free(file);
292587d5d832SChangpeng Liu }
292687d5d832SChangpeng Liu 
292787d5d832SChangpeng Liu static void
292887d5d832SChangpeng Liu file_free(struct spdk_file *file)
29291edd9bf3SJim Harris {
29301edd9bf3SJim Harris 	BLOBFS_TRACE(file, "free=%s\n", file->name);
29311edd9bf3SJim Harris 	pthread_spin_lock(&file->lock);
29321edd9bf3SJim Harris 	if (file->tree->present_mask == 0) {
29331edd9bf3SJim Harris 		pthread_spin_unlock(&file->lock);
293487d5d832SChangpeng Liu 		free(file->name);
293587d5d832SChangpeng Liu 		free(file->tree);
293687d5d832SChangpeng Liu 		free(file);
29371edd9bf3SJim Harris 		return;
29381edd9bf3SJim Harris 	}
293995399c11SZiye Yang 
294087d5d832SChangpeng Liu 	tree_free_buffers(file->tree);
294172b9af55SChangpeng Liu 	assert(file->tree->present_mask == 0);
294287d5d832SChangpeng Liu 	spdk_thread_send_msg(g_cache_pool_thread, _file_free, file);
29431edd9bf3SJim Harris 	pthread_spin_unlock(&file->lock);
29441edd9bf3SJim Harris }
29451edd9bf3SJim Harris 
29462172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(blobfs)
29472172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(blobfs_rw)
2948