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