Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/blobfs.h"
9 : : #include "cache_tree.h"
10 : :
11 : : #include "spdk/queue.h"
12 : : #include "spdk/thread.h"
13 : : #include "spdk/assert.h"
14 : : #include "spdk/env.h"
15 : : #include "spdk/util.h"
16 : : #include "spdk/log.h"
17 : : #include "spdk/trace.h"
18 : :
19 : : #include "spdk_internal/trace_defs.h"
20 : :
21 : : #define BLOBFS_TRACE(file, str, args...) \
22 : : SPDK_DEBUGLOG(blobfs, "file=%s " str, file->name, ##args)
23 : :
24 : : #define BLOBFS_TRACE_RW(file, str, args...) \
25 : : SPDK_DEBUGLOG(blobfs_rw, "file=%s " str, file->name, ##args)
26 : :
27 : : #define BLOBFS_DEFAULT_CACHE_SIZE (4ULL * 1024 * 1024 * 1024)
28 : : #define SPDK_BLOBFS_DEFAULT_OPTS_CLUSTER_SZ (1024 * 1024)
29 : :
30 : : #define SPDK_BLOBFS_SIGNATURE "BLOBFS"
31 : :
32 : : static uint64_t g_fs_cache_size = BLOBFS_DEFAULT_CACHE_SIZE;
33 : : static struct spdk_mempool *g_cache_pool;
34 : : static TAILQ_HEAD(, spdk_file) g_caches = TAILQ_HEAD_INITIALIZER(g_caches);
35 : : static struct spdk_poller *g_cache_pool_mgmt_poller;
36 : : static struct spdk_thread *g_cache_pool_thread;
37 : : #define BLOBFS_CACHE_POOL_POLL_PERIOD_IN_US 1000ULL
38 : : static int g_fs_count = 0;
39 : : static pthread_mutex_t g_cache_init_lock = PTHREAD_MUTEX_INITIALIZER;
40 : :
41 : : static void
42 : 1873 : blobfs_trace(void)
43 : : {
44 : 1873 : struct spdk_trace_tpoint_opts opts[] = {
45 : : {
46 : : "BLOBFS_XATTR_START", TRACE_BLOBFS_XATTR_START,
47 : : OWNER_NONE, OBJECT_NONE, 0,
48 : : {{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
49 : : },
50 : : {
51 : : "BLOBFS_XATTR_END", TRACE_BLOBFS_XATTR_END,
52 : : OWNER_NONE, OBJECT_NONE, 0,
53 : : {{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
54 : : },
55 : : {
56 : : "BLOBFS_OPEN", TRACE_BLOBFS_OPEN,
57 : : OWNER_NONE, OBJECT_NONE, 0,
58 : : {{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
59 : : },
60 : : {
61 : : "BLOBFS_CLOSE", TRACE_BLOBFS_CLOSE,
62 : : OWNER_NONE, OBJECT_NONE, 0,
63 : : {{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
64 : : },
65 : : {
66 : : "BLOBFS_DELETE_START", TRACE_BLOBFS_DELETE_START,
67 : : OWNER_NONE, OBJECT_NONE, 0,
68 : : {{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
69 : : },
70 : : {
71 : : "BLOBFS_DELETE_DONE", TRACE_BLOBFS_DELETE_DONE,
72 : : OWNER_NONE, OBJECT_NONE, 0,
73 : : {{ "file", SPDK_TRACE_ARG_TYPE_STR, 40 }},
74 : : }
75 : : };
76 : :
77 : 1873 : spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts));
78 : 1873 : }
79 : 2017 : SPDK_TRACE_REGISTER_FN(blobfs_trace, "blobfs", TRACE_GROUP_BLOBFS)
80 : :
81 : : void
82 : 1047997 : cache_buffer_free(struct cache_buffer *cache_buffer)
83 : : {
84 [ # # # # ]: 1047997 : spdk_mempool_put(g_cache_pool, cache_buffer->buf);
85 : 1047997 : free(cache_buffer);
86 : 1047997 : }
87 : :
88 : : #define CACHE_READAHEAD_THRESHOLD (128 * 1024)
89 : :
90 : : struct spdk_file {
91 : : struct spdk_filesystem *fs;
92 : : struct spdk_blob *blob;
93 : : char *name;
94 : : uint64_t length;
95 : : bool is_deleted;
96 : : bool open_for_writing;
97 : : uint64_t length_flushed;
98 : : uint64_t length_xattr;
99 : : uint64_t append_pos;
100 : : uint64_t seq_byte_count;
101 : : uint64_t next_seq_offset;
102 : : uint32_t priority;
103 : : TAILQ_ENTRY(spdk_file) tailq;
104 : : spdk_blob_id blobid;
105 : : uint32_t ref_count;
106 : : pthread_spinlock_t lock;
107 : : struct cache_buffer *last;
108 : : struct cache_tree *tree;
109 : : TAILQ_HEAD(open_requests_head, spdk_fs_request) open_requests;
110 : : TAILQ_HEAD(sync_requests_head, spdk_fs_request) sync_requests;
111 : : TAILQ_ENTRY(spdk_file) cache_tailq;
112 : : };
113 : :
114 : : struct spdk_deleted_file {
115 : : spdk_blob_id id;
116 : : TAILQ_ENTRY(spdk_deleted_file) tailq;
117 : : };
118 : :
119 : : struct spdk_filesystem {
120 : : struct spdk_blob_store *bs;
121 : : TAILQ_HEAD(, spdk_file) files;
122 : : struct spdk_bs_opts bs_opts;
123 : : struct spdk_bs_dev *bdev;
124 : : fs_send_request_fn send_request;
125 : :
126 : : struct {
127 : : uint32_t max_ops;
128 : : struct spdk_io_channel *sync_io_channel;
129 : : struct spdk_fs_channel *sync_fs_channel;
130 : : } sync_target;
131 : :
132 : : struct {
133 : : uint32_t max_ops;
134 : : struct spdk_io_channel *md_io_channel;
135 : : struct spdk_fs_channel *md_fs_channel;
136 : : } md_target;
137 : :
138 : : struct {
139 : : uint32_t max_ops;
140 : : } io_target;
141 : : };
142 : :
143 : : struct spdk_fs_cb_args {
144 : : union {
145 : : spdk_fs_op_with_handle_complete fs_op_with_handle;
146 : : spdk_fs_op_complete fs_op;
147 : : spdk_file_op_with_handle_complete file_op_with_handle;
148 : : spdk_file_op_complete file_op;
149 : : spdk_file_stat_op_complete stat_op;
150 : : } fn;
151 : : void *arg;
152 : : sem_t *sem;
153 : : struct spdk_filesystem *fs;
154 : : struct spdk_file *file;
155 : : int rc;
156 : : int *rwerrno;
157 : : struct iovec *iovs;
158 : : uint32_t iovcnt;
159 : : struct iovec iov;
160 : : union {
161 : : struct {
162 : : TAILQ_HEAD(, spdk_deleted_file) deleted_files;
163 : : } fs_load;
164 : : struct {
165 : : uint64_t length;
166 : : } truncate;
167 : : struct {
168 : : struct spdk_io_channel *channel;
169 : : void *pin_buf;
170 : : int is_read;
171 : : off_t offset;
172 : : size_t length;
173 : : uint64_t start_lba;
174 : : uint64_t num_lba;
175 : : uint32_t blocklen;
176 : : } rw;
177 : : struct {
178 : : const char *old_name;
179 : : const char *new_name;
180 : : } rename;
181 : : struct {
182 : : struct cache_buffer *cache_buffer;
183 : : uint64_t length;
184 : : } flush;
185 : : struct {
186 : : struct cache_buffer *cache_buffer;
187 : : uint64_t length;
188 : : uint64_t offset;
189 : : } readahead;
190 : : struct {
191 : : /* offset of the file when the sync request was made */
192 : : uint64_t offset;
193 : : TAILQ_ENTRY(spdk_fs_request) tailq;
194 : : bool xattr_in_progress;
195 : : /* length written to the xattr for this file - this should
196 : : * always be the same as the offset if only one thread is
197 : : * writing to the file, but could differ if multiple threads
198 : : * are appending
199 : : */
200 : : uint64_t length;
201 : : } sync;
202 : : struct {
203 : : uint32_t num_clusters;
204 : : } resize;
205 : : struct {
206 : : const char *name;
207 : : uint32_t flags;
208 : : TAILQ_ENTRY(spdk_fs_request) tailq;
209 : : } open;
210 : : struct {
211 : : const char *name;
212 : : struct spdk_blob *blob;
213 : : } create;
214 : : struct {
215 : : const char *name;
216 : : } delete;
217 : : struct {
218 : : const char *name;
219 : : } stat;
220 : : } op;
221 : : };
222 : :
223 : : static void file_free(struct spdk_file *file);
224 : : static void fs_io_device_unregister(struct spdk_filesystem *fs);
225 : : static void fs_free_io_channels(struct spdk_filesystem *fs);
226 : :
227 : : void
228 : 3 : spdk_fs_opts_init(struct spdk_blobfs_opts *opts)
229 : : {
230 [ # # # # ]: 3 : opts->cluster_sz = SPDK_BLOBFS_DEFAULT_OPTS_CLUSTER_SZ;
231 : 3 : }
232 : :
233 : : static int _blobfs_cache_pool_reclaim(void *arg);
234 : :
235 : : static bool
236 : 508928 : blobfs_cache_pool_need_reclaim(void)
237 : : {
238 : : size_t count;
239 : :
240 : 508928 : count = spdk_mempool_count(g_cache_pool);
241 : : /* We define a aggressive policy here as the requirements from db_bench are batched, so start the poller
242 : : * when the number of available cache buffer is less than 1/5 of total buffers.
243 : : */
244 [ + + # # : 508928 : if (count > (size_t)g_fs_cache_size / CACHE_BUFFER_SIZE / 5) {
# # # # ]
245 : 502271 : return false;
246 : : }
247 : :
248 : 6657 : return true;
249 : 0 : }
250 : :
251 : : static void
252 : 72 : __start_cache_pool_mgmt(void *ctx)
253 : : {
254 [ - + # # ]: 72 : assert(g_cache_pool == NULL);
255 : :
256 : 72 : g_cache_pool = spdk_mempool_create("spdk_fs_cache",
257 [ # # # # ]: 0 : g_fs_cache_size / CACHE_BUFFER_SIZE,
258 [ # # ]: 0 : CACHE_BUFFER_SIZE,
259 : : SPDK_MEMPOOL_DEFAULT_CACHE_SIZE,
260 : : SPDK_ENV_SOCKET_ID_ANY);
261 [ - + ]: 72 : if (!g_cache_pool) {
262 [ # # ]: 0 : if (spdk_mempool_lookup("spdk_fs_cache") != NULL) {
263 : 0 : SPDK_ERRLOG("Unable to allocate mempool: already exists\n");
264 : 0 : SPDK_ERRLOG("Probably running in multiprocess environment, which is "
265 : : "unsupported by the blobfs library\n");
266 : 0 : } else {
267 : 0 : SPDK_ERRLOG("Create mempool failed, you may "
268 : : "increase the memory and try again\n");
269 : : }
270 [ # # ]: 0 : assert(false);
271 : : }
272 : :
273 [ - + # # ]: 72 : assert(g_cache_pool_mgmt_poller == NULL);
274 : 72 : g_cache_pool_mgmt_poller = SPDK_POLLER_REGISTER(_blobfs_cache_pool_reclaim, NULL,
275 : : BLOBFS_CACHE_POOL_POLL_PERIOD_IN_US);
276 : 72 : }
277 : :
278 : : static void
279 : 72 : __stop_cache_pool_mgmt(void *ctx)
280 : : {
281 : 72 : spdk_poller_unregister(&g_cache_pool_mgmt_poller);
282 : :
283 [ - + # # ]: 72 : assert(g_cache_pool != NULL);
284 [ - + # # : 72 : assert(spdk_mempool_count(g_cache_pool) == g_fs_cache_size / CACHE_BUFFER_SIZE);
# # # # ]
285 : 72 : spdk_mempool_free(g_cache_pool);
286 : 72 : g_cache_pool = NULL;
287 : :
288 : 72 : spdk_thread_exit(g_cache_pool_thread);
289 : 72 : }
290 : :
291 : : static void
292 : 72 : initialize_global_cache(void)
293 : : {
294 [ - + ]: 72 : pthread_mutex_lock(&g_cache_init_lock);
295 [ + - ]: 72 : if (g_fs_count == 0) {
296 : 72 : g_cache_pool_thread = spdk_thread_create("cache_pool_mgmt", NULL);
297 [ - + # # ]: 72 : assert(g_cache_pool_thread != NULL);
298 : 72 : spdk_thread_send_msg(g_cache_pool_thread, __start_cache_pool_mgmt, NULL);
299 : 0 : }
300 [ # # ]: 72 : g_fs_count++;
301 [ - + ]: 72 : pthread_mutex_unlock(&g_cache_init_lock);
302 : 72 : }
303 : :
304 : : static void
305 : 72 : free_global_cache(void)
306 : : {
307 [ - + ]: 72 : pthread_mutex_lock(&g_cache_init_lock);
308 [ # # ]: 72 : g_fs_count--;
309 [ + - ]: 72 : if (g_fs_count == 0) {
310 : 72 : spdk_thread_send_msg(g_cache_pool_thread, __stop_cache_pool_mgmt, NULL);
311 : 0 : }
312 [ - + ]: 72 : pthread_mutex_unlock(&g_cache_init_lock);
313 : 72 : }
314 : :
315 : : static uint64_t
316 : 1540280 : __file_get_blob_size(struct spdk_file *file)
317 : : {
318 : : uint64_t cluster_sz;
319 : :
320 [ # # # # : 1540280 : cluster_sz = file->fs->bs_opts.cluster_sz;
# # # # #
# ]
321 [ # # # # ]: 1540280 : return cluster_sz * spdk_blob_get_num_clusters(file->blob);
322 : : }
323 : :
324 : : struct spdk_fs_request {
325 : : struct spdk_fs_cb_args args;
326 : : TAILQ_ENTRY(spdk_fs_request) link;
327 : : struct spdk_fs_channel *channel;
328 : : };
329 : :
330 : : struct spdk_fs_channel {
331 : : struct spdk_fs_request *req_mem;
332 : : TAILQ_HEAD(, spdk_fs_request) reqs;
333 : : sem_t sem;
334 : : struct spdk_filesystem *fs;
335 : : struct spdk_io_channel *bs_channel;
336 : : fs_send_request_fn send_request;
337 : : bool sync;
338 : : uint32_t outstanding_reqs;
339 : : pthread_spinlock_t lock;
340 : : };
341 : :
342 : : /* For now, this is effectively an alias. But eventually we'll shift
343 : : * some data members over. */
344 : : struct spdk_fs_thread_ctx {
345 : : struct spdk_fs_channel ch;
346 : : };
347 : :
348 : : static struct spdk_fs_request *
349 : 8337813 : alloc_fs_request_with_iov(struct spdk_fs_channel *channel, uint32_t iovcnt)
350 : : {
351 : : struct spdk_fs_request *req;
352 : 8337813 : struct iovec *iovs = NULL;
353 : :
354 [ + + ]: 8337813 : if (iovcnt > 1) {
355 : 12 : iovs = calloc(iovcnt, sizeof(struct iovec));
356 [ - + ]: 12 : if (!iovs) {
357 : 0 : return NULL;
358 : : }
359 : 0 : }
360 : :
361 [ + + + + : 8337813 : if (channel->sync) {
# # # # ]
362 [ - + # # ]: 4845641 : pthread_spin_lock(&channel->lock);
363 : 0 : }
364 : :
365 [ # # # # : 8337813 : req = TAILQ_FIRST(&channel->reqs);
# # ]
366 [ + - ]: 8337813 : if (req) {
367 [ # # ]: 8337813 : channel->outstanding_reqs++;
368 [ + - # # : 8337813 : TAILQ_REMOVE(&channel->reqs, req, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
369 : 0 : }
370 : :
371 [ + + + + : 8337813 : if (channel->sync) {
# # # # ]
372 [ - + # # ]: 4845641 : pthread_spin_unlock(&channel->lock);
373 : 0 : }
374 : :
375 [ - + ]: 8337813 : if (req == NULL) {
376 : 0 : SPDK_ERRLOG("Cannot allocate req on spdk_fs_channel =%p\n", channel);
377 : 0 : free(iovs);
378 : 0 : return NULL;
379 : : }
380 [ - + ]: 8337813 : memset(req, 0, sizeof(*req));
381 [ # # # # ]: 8337813 : req->channel = channel;
382 [ + + ]: 8337813 : if (iovcnt > 1) {
383 [ # # # # : 12 : req->args.iovs = iovs;
# # ]
384 : 0 : } else {
385 [ # # # # : 8337801 : req->args.iovs = &req->args.iov;
# # # # #
# ]
386 : : }
387 [ # # # # : 8337813 : req->args.iovcnt = iovcnt;
# # ]
388 : :
389 : 8337813 : return req;
390 : 0 : }
391 : :
392 : : static struct spdk_fs_request *
393 : 1382325 : alloc_fs_request(struct spdk_fs_channel *channel)
394 : : {
395 : 1382325 : return alloc_fs_request_with_iov(channel, 0);
396 : : }
397 : :
398 : : static void
399 : 8337813 : free_fs_request(struct spdk_fs_request *req)
400 : : {
401 [ # # # # ]: 8337813 : struct spdk_fs_channel *channel = req->channel;
402 : :
403 [ + + # # : 8337813 : if (req->args.iovcnt > 1) {
# # # # ]
404 [ # # # # : 12 : free(req->args.iovs);
# # ]
405 : 0 : }
406 : :
407 [ + + + + : 8337813 : if (channel->sync) {
# # # # ]
408 [ - + # # ]: 4845641 : pthread_spin_lock(&channel->lock);
409 : 0 : }
410 : :
411 [ + - # # : 8337813 : TAILQ_INSERT_HEAD(&req->channel->reqs, req, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
412 [ # # ]: 8337813 : channel->outstanding_reqs--;
413 : :
414 [ + + + + : 8337813 : if (channel->sync) {
# # # # ]
415 [ - + # # ]: 4845641 : pthread_spin_unlock(&channel->lock);
416 : 0 : }
417 : 8337813 : }
418 : :
419 : : static int
420 : 388 : fs_channel_create(struct spdk_filesystem *fs, struct spdk_fs_channel *channel,
421 : : uint32_t max_ops)
422 : : {
423 : : uint32_t i;
424 : :
425 [ # # # # ]: 388 : channel->req_mem = calloc(max_ops, sizeof(struct spdk_fs_request));
426 [ - + # # : 388 : if (!channel->req_mem) {
# # ]
427 : 0 : return -1;
428 : : }
429 : :
430 [ # # # # ]: 388 : channel->outstanding_reqs = 0;
431 [ # # # # : 388 : TAILQ_INIT(&channel->reqs);
# # # # #
# # # # #
# # ]
432 [ - + # # ]: 388 : sem_init(&channel->sem, 0, 0);
433 : :
434 [ + + ]: 199044 : for (i = 0; i < max_ops; i++) {
435 [ # # # # : 198656 : TAILQ_INSERT_TAIL(&channel->reqs, &channel->req_mem[i], link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
436 : 0 : }
437 : :
438 [ # # # # ]: 388 : channel->fs = fs;
439 : :
440 : 388 : return 0;
441 : 0 : }
442 : :
443 : : static int
444 : 73 : fs_md_channel_create(void *io_device, void *ctx_buf)
445 : : {
446 : : struct spdk_filesystem *fs;
447 : 73 : struct spdk_fs_channel *channel = ctx_buf;
448 : :
449 : 73 : fs = SPDK_CONTAINEROF(io_device, struct spdk_filesystem, md_target);
450 : :
451 [ # # # # : 73 : return fs_channel_create(fs, channel, fs->md_target.max_ops);
# # ]
452 : : }
453 : :
454 : : static int
455 : 73 : fs_sync_channel_create(void *io_device, void *ctx_buf)
456 : : {
457 : : struct spdk_filesystem *fs;
458 : 73 : struct spdk_fs_channel *channel = ctx_buf;
459 : :
460 : 73 : fs = SPDK_CONTAINEROF(io_device, struct spdk_filesystem, sync_target);
461 : :
462 [ # # # # : 73 : return fs_channel_create(fs, channel, fs->sync_target.max_ops);
# # ]
463 : : }
464 : :
465 : : static int
466 : 3 : fs_io_channel_create(void *io_device, void *ctx_buf)
467 : : {
468 : : struct spdk_filesystem *fs;
469 : 3 : struct spdk_fs_channel *channel = ctx_buf;
470 : :
471 : 3 : fs = SPDK_CONTAINEROF(io_device, struct spdk_filesystem, io_target);
472 : :
473 [ # # # # : 3 : return fs_channel_create(fs, channel, fs->io_target.max_ops);
# # ]
474 : : }
475 : :
476 : : static void
477 : 388 : fs_channel_destroy(void *io_device, void *ctx_buf)
478 : : {
479 : 388 : struct spdk_fs_channel *channel = ctx_buf;
480 : :
481 [ - + # # : 388 : if (channel->outstanding_reqs > 0) {
# # ]
482 [ # # # # ]: 0 : SPDK_ERRLOG("channel freed with %" PRIu32 " outstanding requests!\n",
483 : : channel->outstanding_reqs);
484 : 0 : }
485 : :
486 [ # # # # ]: 388 : free(channel->req_mem);
487 [ + + # # : 388 : if (channel->bs_channel != NULL) {
# # ]
488 [ # # # # ]: 147 : spdk_bs_free_io_channel(channel->bs_channel);
489 : 0 : }
490 : 388 : }
491 : :
492 : : static void
493 : 0 : __send_request_direct(fs_request_fn fn, void *arg)
494 : : {
495 [ # # # # ]: 0 : fn(arg);
496 : 0 : }
497 : :
498 : : static void
499 : 72 : common_fs_bs_init(struct spdk_filesystem *fs, struct spdk_blob_store *bs)
500 : : {
501 [ # # # # ]: 72 : fs->bs = bs;
502 [ # # # # : 72 : fs->bs_opts.cluster_sz = spdk_bs_get_cluster_size(bs);
# # ]
503 [ # # # # : 72 : fs->md_target.md_fs_channel->bs_channel = spdk_bs_alloc_io_channel(fs->bs);
# # # # #
# # # #
# ]
504 [ # # # # : 72 : fs->md_target.md_fs_channel->send_request = __send_request_direct;
# # # # #
# ]
505 [ # # # # : 72 : fs->sync_target.sync_fs_channel->bs_channel = spdk_bs_alloc_io_channel(fs->bs);
# # # # #
# # # #
# ]
506 [ # # # # : 72 : fs->sync_target.sync_fs_channel->send_request = __send_request_direct;
# # # # #
# ]
507 : :
508 : 72 : initialize_global_cache();
509 : 72 : }
510 : :
511 : : static void
512 : 57 : init_cb(void *ctx, struct spdk_blob_store *bs, int bserrno)
513 : : {
514 : 57 : struct spdk_fs_request *req = ctx;
515 [ # # ]: 57 : struct spdk_fs_cb_args *args = &req->args;
516 [ # # # # ]: 57 : struct spdk_filesystem *fs = args->fs;
517 : :
518 [ + - ]: 57 : if (bserrno == 0) {
519 : 57 : common_fs_bs_init(fs, bs);
520 : 0 : } else {
521 : 0 : free(fs);
522 : 0 : fs = NULL;
523 : : }
524 : :
525 [ # # # # : 57 : args->fn.fs_op_with_handle(args->arg, fs, bserrno);
# # # # #
# # # #
# ]
526 : 57 : free_fs_request(req);
527 : 57 : }
528 : :
529 : : static struct spdk_filesystem *
530 : 73 : fs_alloc(struct spdk_bs_dev *dev, fs_send_request_fn send_request_fn)
531 : : {
532 : : struct spdk_filesystem *fs;
533 : :
534 : 73 : fs = calloc(1, sizeof(*fs));
535 [ - + ]: 73 : if (fs == NULL) {
536 : 0 : return NULL;
537 : : }
538 : :
539 [ # # # # ]: 73 : fs->bdev = dev;
540 [ # # # # ]: 73 : fs->send_request = send_request_fn;
541 [ # # # # : 73 : TAILQ_INIT(&fs->files);
# # # # #
# # # # #
# # ]
542 : :
543 [ # # # # : 73 : fs->md_target.max_ops = 512;
# # ]
544 [ # # ]: 73 : spdk_io_device_register(&fs->md_target, fs_md_channel_create, fs_channel_destroy,
545 : : sizeof(struct spdk_fs_channel), "blobfs_md");
546 [ # # # # : 73 : fs->md_target.md_io_channel = spdk_get_io_channel(&fs->md_target);
# # # # ]
547 [ # # # # : 73 : fs->md_target.md_fs_channel = spdk_io_channel_get_ctx(fs->md_target.md_io_channel);
# # # # #
# # # ]
548 : :
549 [ # # # # : 73 : fs->sync_target.max_ops = 512;
# # ]
550 [ # # ]: 73 : spdk_io_device_register(&fs->sync_target, fs_sync_channel_create, fs_channel_destroy,
551 : : sizeof(struct spdk_fs_channel), "blobfs_sync");
552 [ # # # # : 73 : fs->sync_target.sync_io_channel = spdk_get_io_channel(&fs->sync_target);
# # # # ]
553 [ # # # # : 73 : fs->sync_target.sync_fs_channel = spdk_io_channel_get_ctx(fs->sync_target.sync_io_channel);
# # # # #
# # # ]
554 : :
555 [ # # # # : 73 : fs->io_target.max_ops = 512;
# # ]
556 [ # # ]: 73 : spdk_io_device_register(&fs->io_target, fs_io_channel_create, fs_channel_destroy,
557 : : sizeof(struct spdk_fs_channel), "blobfs_io");
558 : :
559 : 73 : return fs;
560 : 0 : }
561 : :
562 : : static void
563 : 3935580 : __wake_caller(void *arg, int fserrno)
564 : : {
565 : 3935580 : struct spdk_fs_cb_args *args = arg;
566 : :
567 [ + + + - : 3935580 : if ((args->rwerrno != NULL) && (*(args->rwerrno) == 0) && fserrno) {
- + # # #
# # # # #
# # ]
568 [ # # # # : 0 : *(args->rwerrno) = fserrno;
# # ]
569 : 0 : }
570 [ # # # # ]: 3935580 : args->rc = fserrno;
571 [ - + # # : 3935580 : sem_post(args->sem);
# # ]
572 : 3935580 : }
573 : :
574 : : void
575 : 57 : spdk_fs_init(struct spdk_bs_dev *dev, struct spdk_blobfs_opts *opt,
576 : : fs_send_request_fn send_request_fn,
577 : : spdk_fs_op_with_handle_complete cb_fn, void *cb_arg)
578 : : {
579 : : struct spdk_filesystem *fs;
580 : : struct spdk_fs_request *req;
581 : : struct spdk_fs_cb_args *args;
582 : 57 : struct spdk_bs_opts opts = {};
583 : :
584 : 57 : fs = fs_alloc(dev, send_request_fn);
585 [ - + ]: 57 : if (fs == NULL) {
586 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
587 : 0 : return;
588 : : }
589 : :
590 [ # # # # : 57 : req = alloc_fs_request(fs->md_target.md_fs_channel);
# # ]
591 [ - + ]: 57 : if (req == NULL) {
592 : 0 : fs_free_io_channels(fs);
593 : 0 : fs_io_device_unregister(fs);
594 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
595 : 0 : return;
596 : : }
597 : :
598 [ # # ]: 57 : args = &req->args;
599 [ # # # # : 57 : args->fn.fs_op_with_handle = cb_fn;
# # ]
600 [ # # # # ]: 57 : args->arg = cb_arg;
601 [ # # # # ]: 57 : args->fs = fs;
602 : :
603 : 57 : spdk_bs_opts_init(&opts, sizeof(opts));
604 [ - + ]: 57 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), SPDK_BLOBFS_SIGNATURE);
605 [ + + ]: 57 : if (opt) {
606 [ # # # # ]: 3 : opts.cluster_sz = opt->cluster_sz;
607 : 0 : }
608 : 57 : spdk_bs_init(dev, &opts, init_cb, req);
609 : 0 : }
610 : :
611 : : static struct spdk_file *
612 : 8040 : file_alloc(struct spdk_filesystem *fs)
613 : : {
614 : : struct spdk_file *file;
615 : :
616 : 8040 : file = calloc(1, sizeof(*file));
617 [ - + ]: 8040 : if (file == NULL) {
618 : 0 : return NULL;
619 : : }
620 : :
621 [ # # # # ]: 8040 : file->tree = calloc(1, sizeof(*file->tree));
622 [ - + # # : 8040 : if (file->tree == NULL) {
# # ]
623 : 0 : free(file);
624 : 0 : return NULL;
625 : : }
626 : :
627 [ - + - + : 8040 : if (pthread_spin_init(&file->lock, 0)) {
# # ]
628 [ # # # # ]: 0 : free(file->tree);
629 : 0 : free(file);
630 : 0 : return NULL;
631 : : }
632 : :
633 [ # # # # ]: 8040 : file->fs = fs;
634 [ # # # # : 8040 : TAILQ_INIT(&file->open_requests);
# # # # #
# # # # #
# # ]
635 [ # # # # : 8040 : TAILQ_INIT(&file->sync_requests);
# # # # #
# # # # #
# # ]
636 [ # # # # : 8040 : TAILQ_INSERT_TAIL(&fs->files, file, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
637 [ # # # # ]: 8040 : file->priority = SPDK_FILE_PRIORITY_LOW;
638 : 8040 : return file;
639 : 0 : }
640 : :
641 : : static void fs_load_done(void *ctx, int bserrno);
642 : :
643 : : static int
644 : 15 : _handle_deleted_files(struct spdk_fs_request *req)
645 : : {
646 [ # # ]: 15 : struct spdk_fs_cb_args *args = &req->args;
647 [ # # # # ]: 15 : struct spdk_filesystem *fs = args->fs;
648 : :
649 [ - + # # : 15 : if (!TAILQ_EMPTY(&args->op.fs_load.deleted_files)) {
# # # # #
# # # ]
650 : : struct spdk_deleted_file *deleted_file;
651 : :
652 [ # # # # : 0 : deleted_file = TAILQ_FIRST(&args->op.fs_load.deleted_files);
# # # # #
# ]
653 [ # # # # : 0 : TAILQ_REMOVE(&args->op.fs_load.deleted_files, deleted_file, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
654 [ # # # # : 0 : spdk_bs_delete_blob(fs->bs, deleted_file->id, fs_load_done, req);
# # # # ]
655 : 0 : free(deleted_file);
656 : 0 : return 0;
657 : : }
658 : :
659 : 15 : return 1;
660 : 0 : }
661 : :
662 : : static void
663 : 15 : fs_load_done(void *ctx, int bserrno)
664 : : {
665 : 15 : struct spdk_fs_request *req = ctx;
666 [ # # ]: 15 : struct spdk_fs_cb_args *args = &req->args;
667 [ # # # # ]: 15 : struct spdk_filesystem *fs = args->fs;
668 : :
669 : : /* The filesystem has been loaded. Now check if there are any files that
670 : : * were marked for deletion before last unload. Do not complete the
671 : : * fs_load callback until all of them have been deleted on disk.
672 : : */
673 [ - + ]: 15 : if (_handle_deleted_files(req) == 0) {
674 : : /* We found a file that's been marked for deleting but not actually
675 : : * deleted yet. This function will get called again once the delete
676 : : * operation is completed.
677 : : */
678 : 0 : return;
679 : : }
680 : :
681 [ # # # # : 15 : args->fn.fs_op_with_handle(args->arg, fs, 0);
# # # # #
# # # #
# ]
682 : 15 : free_fs_request(req);
683 : :
684 : 0 : }
685 : :
686 : : static void
687 : 5348 : iter_cb(void *ctx, struct spdk_blob *blob, int rc)
688 : : {
689 : 5348 : struct spdk_fs_request *req = ctx;
690 [ # # ]: 5348 : struct spdk_fs_cb_args *args = &req->args;
691 [ # # # # ]: 5348 : struct spdk_filesystem *fs = args->fs;
692 : 5348 : uint64_t *length;
693 : 5348 : const char *name;
694 : 5348 : uint32_t *is_deleted;
695 : 5348 : size_t value_len;
696 : :
697 [ - + ]: 5348 : if (rc < 0) {
698 [ # # # # : 0 : args->fn.fs_op_with_handle(args->arg, fs, rc);
# # # # #
# # # #
# ]
699 : 0 : free_fs_request(req);
700 : 0 : return;
701 : : }
702 : :
703 : 5348 : rc = spdk_blob_get_xattr_value(blob, "name", (const void **)&name, &value_len);
704 [ - + ]: 5348 : if (rc < 0) {
705 [ # # # # : 0 : args->fn.fs_op_with_handle(args->arg, fs, rc);
# # # # #
# # # #
# ]
706 : 0 : free_fs_request(req);
707 : 0 : return;
708 : : }
709 : :
710 : 5348 : rc = spdk_blob_get_xattr_value(blob, "length", (const void **)&length, &value_len);
711 [ - + ]: 5348 : if (rc < 0) {
712 [ # # # # : 0 : args->fn.fs_op_with_handle(args->arg, fs, rc);
# # # # #
# # # #
# ]
713 : 0 : free_fs_request(req);
714 : 0 : return;
715 : : }
716 : :
717 [ - + # # ]: 5348 : assert(value_len == 8);
718 : :
719 : : /* This file could be deleted last time without close it, then app crashed, so we delete it now */
720 : 5348 : rc = spdk_blob_get_xattr_value(blob, "is_deleted", (const void **)&is_deleted, &value_len);
721 [ + - ]: 5348 : if (rc < 0) {
722 : : struct spdk_file *f;
723 : :
724 : 5348 : f = file_alloc(fs);
725 [ - + ]: 5348 : if (f == NULL) {
726 : 0 : SPDK_ERRLOG("Cannot allocate file to handle deleted file on disk\n");
727 [ # # # # : 0 : args->fn.fs_op_with_handle(args->arg, fs, -ENOMEM);
# # # # #
# # # #
# ]
728 : 0 : free_fs_request(req);
729 : 0 : return;
730 : : }
731 : :
732 [ - + # # : 5348 : f->name = strdup(name);
# # ]
733 [ - + # # : 5348 : if (!f->name) {
# # ]
734 : 0 : SPDK_ERRLOG("Cannot allocate memory for file name\n");
735 [ # # # # : 0 : args->fn.fs_op_with_handle(args->arg, fs, -ENOMEM);
# # # # #
# # # #
# ]
736 : 0 : free_fs_request(req);
737 : 0 : file_free(f);
738 : 0 : return;
739 : : }
740 : :
741 [ # # # # ]: 5348 : f->blobid = spdk_blob_get_id(blob);
742 [ # # # # : 5348 : f->length = *length;
# # ]
743 [ # # # # : 5348 : f->length_flushed = *length;
# # ]
744 [ # # # # : 5348 : f->length_xattr = *length;
# # ]
745 [ # # # # : 5348 : f->append_pos = *length;
# # ]
746 [ - + - + : 5348 : SPDK_DEBUGLOG(blobfs, "added file %s length=%ju\n", f->name, f->length);
# # # # #
# # # #
# ]
747 : 0 : } else {
748 : : struct spdk_deleted_file *deleted_file;
749 : :
750 : 0 : deleted_file = calloc(1, sizeof(*deleted_file));
751 [ # # ]: 0 : if (deleted_file == NULL) {
752 [ # # # # : 0 : args->fn.fs_op_with_handle(args->arg, fs, -ENOMEM);
# # # # #
# # # #
# ]
753 : 0 : free_fs_request(req);
754 : 0 : return;
755 : : }
756 [ # # # # ]: 0 : deleted_file->id = spdk_blob_get_id(blob);
757 [ # # # # : 0 : TAILQ_INSERT_TAIL(&args->op.fs_load.deleted_files, deleted_file, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
758 : : }
759 : 0 : }
760 : :
761 : : static void
762 : 16 : load_cb(void *ctx, struct spdk_blob_store *bs, int bserrno)
763 : : {
764 : 16 : struct spdk_fs_request *req = ctx;
765 [ # # ]: 16 : struct spdk_fs_cb_args *args = &req->args;
766 [ # # # # ]: 16 : struct spdk_filesystem *fs = args->fs;
767 : 16 : struct spdk_bs_type bstype;
768 : : static const struct spdk_bs_type blobfs_type = {SPDK_BLOBFS_SIGNATURE};
769 : : static const struct spdk_bs_type zeros;
770 : :
771 [ + + ]: 16 : if (bserrno != 0) {
772 [ # # # # : 1 : args->fn.fs_op_with_handle(args->arg, NULL, bserrno);
# # # # #
# # # #
# ]
773 : 1 : free_fs_request(req);
774 : 1 : fs_free_io_channels(fs);
775 : 1 : fs_io_device_unregister(fs);
776 : 1 : return;
777 : : }
778 : :
779 : 15 : bstype = spdk_bs_get_bstype(bs);
780 : :
781 [ - + # # : 15 : if (!memcmp(&bstype, &zeros, sizeof(bstype))) {
# # ]
782 [ # # # # : 0 : SPDK_DEBUGLOG(blobfs, "assigning bstype\n");
# # ]
783 : 0 : spdk_bs_set_bstype(bs, blobfs_type);
784 [ - + # # : 15 : } else if (memcmp(&bstype, &blobfs_type, sizeof(bstype))) {
# # ]
785 : 0 : SPDK_ERRLOG("not blobfs\n");
786 [ # # # # : 0 : SPDK_LOGDUMP(blobfs, "bstype", &bstype, sizeof(bstype));
# # ]
787 [ # # # # : 0 : args->fn.fs_op_with_handle(args->arg, NULL, -EINVAL);
# # # # #
# # # #
# ]
788 : 0 : free_fs_request(req);
789 : 0 : fs_free_io_channels(fs);
790 : 0 : fs_io_device_unregister(fs);
791 : 0 : return;
792 : : }
793 : :
794 : 15 : common_fs_bs_init(fs, bs);
795 : 15 : fs_load_done(req, 0);
796 : 0 : }
797 : :
798 : : static void
799 : 73 : fs_io_device_unregister(struct spdk_filesystem *fs)
800 : : {
801 [ - + # # ]: 73 : assert(fs != NULL);
802 [ # # ]: 73 : spdk_io_device_unregister(&fs->md_target, NULL);
803 [ # # ]: 73 : spdk_io_device_unregister(&fs->sync_target, NULL);
804 [ # # ]: 73 : spdk_io_device_unregister(&fs->io_target, NULL);
805 : 73 : free(fs);
806 : 73 : }
807 : :
808 : : static void
809 : 73 : fs_free_io_channels(struct spdk_filesystem *fs)
810 : : {
811 [ - + # # ]: 73 : assert(fs != NULL);
812 [ # # # # : 73 : spdk_fs_free_io_channel(fs->md_target.md_io_channel);
# # ]
813 [ # # # # : 73 : spdk_fs_free_io_channel(fs->sync_target.sync_io_channel);
# # ]
814 : 73 : }
815 : :
816 : : void
817 : 16 : spdk_fs_load(struct spdk_bs_dev *dev, fs_send_request_fn send_request_fn,
818 : : spdk_fs_op_with_handle_complete cb_fn, void *cb_arg)
819 : : {
820 : : struct spdk_filesystem *fs;
821 : : struct spdk_fs_cb_args *args;
822 : : struct spdk_fs_request *req;
823 : 16 : struct spdk_bs_opts bs_opts;
824 : :
825 : 16 : fs = fs_alloc(dev, send_request_fn);
826 [ - + ]: 16 : if (fs == NULL) {
827 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
828 : 0 : return;
829 : : }
830 : :
831 [ # # # # : 16 : req = alloc_fs_request(fs->md_target.md_fs_channel);
# # ]
832 [ - + ]: 16 : if (req == NULL) {
833 : 0 : fs_free_io_channels(fs);
834 : 0 : fs_io_device_unregister(fs);
835 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
836 : 0 : return;
837 : : }
838 : :
839 [ # # ]: 16 : args = &req->args;
840 [ # # # # : 16 : args->fn.fs_op_with_handle = cb_fn;
# # ]
841 [ # # # # ]: 16 : args->arg = cb_arg;
842 [ # # # # ]: 16 : args->fs = fs;
843 [ # # # # : 16 : TAILQ_INIT(&args->op.fs_load.deleted_files);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
844 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
845 : 16 : bs_opts.iter_cb_fn = iter_cb;
846 : 16 : bs_opts.iter_cb_arg = req;
847 : 16 : spdk_bs_load(dev, &bs_opts, load_cb, req);
848 : 0 : }
849 : :
850 : : static void
851 : 72 : unload_cb(void *ctx, int bserrno)
852 : : {
853 : 72 : struct spdk_fs_request *req = ctx;
854 [ # # ]: 72 : struct spdk_fs_cb_args *args = &req->args;
855 [ # # # # ]: 72 : struct spdk_filesystem *fs = args->fs;
856 : : struct spdk_file *file, *tmp;
857 : :
858 [ + + # # : 6877 : TAILQ_FOREACH_SAFE(file, &fs->files, tailq, tmp) {
# # # # #
# # # # #
# # ]
859 [ + + # # : 6805 : TAILQ_REMOVE(&fs->files, file, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
860 : 6805 : file_free(file);
861 : 0 : }
862 : :
863 : 72 : free_global_cache();
864 : :
865 [ # # # # : 72 : args->fn.fs_op(args->arg, bserrno);
# # # # #
# # # #
# ]
866 : 72 : free(req);
867 : :
868 : 72 : fs_io_device_unregister(fs);
869 : 72 : }
870 : :
871 : : void
872 : 72 : spdk_fs_unload(struct spdk_filesystem *fs, spdk_fs_op_complete cb_fn, void *cb_arg)
873 : : {
874 : : struct spdk_fs_request *req;
875 : : struct spdk_fs_cb_args *args;
876 : :
877 : : /*
878 : : * We must free the md_channel before unloading the blobstore, so just
879 : : * allocate this request from the general heap.
880 : : */
881 : 72 : req = calloc(1, sizeof(*req));
882 [ - + ]: 72 : if (req == NULL) {
883 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
884 : 0 : return;
885 : : }
886 : :
887 [ # # ]: 72 : args = &req->args;
888 [ # # # # : 72 : args->fn.fs_op = cb_fn;
# # ]
889 [ # # # # ]: 72 : args->arg = cb_arg;
890 [ # # # # ]: 72 : args->fs = fs;
891 : :
892 : 72 : fs_free_io_channels(fs);
893 [ # # # # ]: 72 : spdk_bs_unload(fs->bs, unload_cb, req);
894 : 0 : }
895 : :
896 : : static struct spdk_file *
897 : 23587 : fs_find_file(struct spdk_filesystem *fs, const char *name)
898 : : {
899 : : struct spdk_file *file;
900 : :
901 [ + + # # : 21392627 : TAILQ_FOREACH(file, &fs->files, tailq) {
# # # # #
# # # #
# ]
902 [ + + - + : 21387199 : if (!strncmp(name, file->name, SPDK_FILE_NAME_MAX)) {
+ + # # #
# ]
903 : 18159 : return file;
904 : : }
905 : 0 : }
906 : :
907 : 5428 : return NULL;
908 : 0 : }
909 : :
910 : : void
911 : 7975 : spdk_fs_file_stat_async(struct spdk_filesystem *fs, const char *name,
912 : : spdk_file_stat_op_complete cb_fn, void *cb_arg)
913 : : {
914 : 7975 : struct spdk_file_stat stat;
915 : 7975 : struct spdk_file *f = NULL;
916 : :
917 [ - + - + ]: 7975 : if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) {
918 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENAMETOOLONG);
919 : 0 : return;
920 : : }
921 : :
922 : 7975 : f = fs_find_file(fs, name);
923 [ + + ]: 7975 : if (f != NULL) {
924 [ # # # # ]: 7962 : stat.blobid = f->blobid;
925 [ # # # # : 7962 : stat.size = f->append_pos >= f->length ? f->append_pos : f->length;
# # # # #
# # # # #
# # # # #
# ]
926 [ # # # # ]: 7962 : cb_fn(cb_arg, &stat, 0);
927 : 7962 : return;
928 : : }
929 : :
930 [ # # # # ]: 13 : cb_fn(cb_arg, NULL, -ENOENT);
931 : 0 : }
932 : :
933 : : static void
934 : 7975 : __copy_stat(void *arg, struct spdk_file_stat *stat, int fserrno)
935 : : {
936 : 7975 : struct spdk_fs_request *req = arg;
937 [ # # ]: 7975 : struct spdk_fs_cb_args *args = &req->args;
938 : :
939 [ # # # # ]: 7975 : args->rc = fserrno;
940 [ + + ]: 7975 : if (fserrno == 0) {
941 [ # # # # : 7962 : memcpy(args->arg, stat, sizeof(*stat));
# # # # ]
942 : 0 : }
943 [ - + # # : 7975 : sem_post(args->sem);
# # ]
944 : 7975 : }
945 : :
946 : : static void
947 : 7975 : __file_stat(void *arg)
948 : : {
949 : 7975 : struct spdk_fs_request *req = arg;
950 [ # # ]: 7975 : struct spdk_fs_cb_args *args = &req->args;
951 : :
952 [ # # # # : 7975 : spdk_fs_file_stat_async(args->fs, args->op.stat.name,
# # # # #
# # # ]
953 [ # # # # : 0 : args->fn.stat_op, req);
# # ]
954 : 7975 : }
955 : :
956 : : int
957 : 7975 : spdk_fs_file_stat(struct spdk_filesystem *fs, struct spdk_fs_thread_ctx *ctx,
958 : : const char *name, struct spdk_file_stat *stat)
959 : : {
960 : 7975 : struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
961 : : struct spdk_fs_request *req;
962 : : int rc;
963 : :
964 : 7975 : req = alloc_fs_request(channel);
965 [ - + ]: 7975 : if (req == NULL) {
966 : 0 : SPDK_ERRLOG("Cannot allocate stat req on file=%s\n", name);
967 : 0 : return -ENOMEM;
968 : : }
969 : :
970 [ # # # # : 7975 : req->args.fs = fs;
# # ]
971 [ # # # # : 7975 : req->args.op.stat.name = name;
# # # # #
# ]
972 [ # # # # : 7975 : req->args.fn.stat_op = __copy_stat;
# # # # ]
973 [ # # # # : 7975 : req->args.arg = stat;
# # ]
974 [ # # # # : 7975 : req->args.sem = &channel->sem;
# # # # ]
975 [ # # # # : 7975 : channel->send_request(__file_stat, req);
# # # # ]
976 [ - + # # ]: 7975 : sem_wait(&channel->sem);
977 : :
978 [ # # # # : 7975 : rc = req->args.rc;
# # ]
979 : 7975 : free_fs_request(req);
980 : :
981 : 7975 : return rc;
982 : 0 : }
983 : :
984 : : static void
985 : 2692 : fs_create_blob_close_cb(void *ctx, int bserrno)
986 : : {
987 : : int rc;
988 : 2692 : struct spdk_fs_request *req = ctx;
989 [ # # ]: 2692 : struct spdk_fs_cb_args *args = &req->args;
990 : :
991 [ - + # # : 2692 : rc = args->rc ? args->rc : bserrno;
# # # # #
# ]
992 [ # # # # : 2692 : args->fn.file_op(args->arg, rc);
# # # # #
# # # #
# ]
993 : 2692 : free_fs_request(req);
994 : 2692 : }
995 : :
996 : : static void
997 : 2692 : fs_create_blob_resize_cb(void *ctx, int bserrno)
998 : : {
999 : 2692 : struct spdk_fs_request *req = ctx;
1000 [ # # ]: 2692 : struct spdk_fs_cb_args *args = &req->args;
1001 [ # # # # ]: 2692 : struct spdk_file *f = args->file;
1002 [ # # # # : 2692 : struct spdk_blob *blob = args->op.create.blob;
# # # # ]
1003 : 2692 : uint64_t length = 0;
1004 : :
1005 [ # # # # ]: 2692 : args->rc = bserrno;
1006 [ - + ]: 2692 : if (bserrno) {
1007 : 0 : spdk_blob_close(blob, fs_create_blob_close_cb, args);
1008 : 0 : return;
1009 : : }
1010 : :
1011 [ - + # # : 2692 : spdk_blob_set_xattr(blob, "name", f->name, strlen(f->name) + 1);
# # # # #
# ]
1012 : 2692 : spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
1013 : :
1014 : 2692 : spdk_blob_close(blob, fs_create_blob_close_cb, args);
1015 : 0 : }
1016 : :
1017 : : static void
1018 : 2692 : fs_create_blob_open_cb(void *ctx, struct spdk_blob *blob, int bserrno)
1019 : : {
1020 : 2692 : struct spdk_fs_request *req = ctx;
1021 [ # # ]: 2692 : struct spdk_fs_cb_args *args = &req->args;
1022 : :
1023 [ - + ]: 2692 : if (bserrno) {
1024 [ # # # # : 0 : args->fn.file_op(args->arg, bserrno);
# # # # #
# # # #
# ]
1025 : 0 : free_fs_request(req);
1026 : 0 : return;
1027 : : }
1028 : :
1029 [ # # # # : 2692 : args->op.create.blob = blob;
# # # # ]
1030 : 2692 : spdk_blob_resize(blob, 1, fs_create_blob_resize_cb, req);
1031 : 0 : }
1032 : :
1033 : : static void
1034 : 2692 : fs_create_blob_create_cb(void *ctx, spdk_blob_id blobid, int bserrno)
1035 : : {
1036 : 2692 : struct spdk_fs_request *req = ctx;
1037 [ # # ]: 2692 : struct spdk_fs_cb_args *args = &req->args;
1038 [ # # # # ]: 2692 : struct spdk_file *f = args->file;
1039 : :
1040 [ - + ]: 2692 : if (bserrno) {
1041 [ # # # # : 0 : args->fn.file_op(args->arg, bserrno);
# # # # #
# # # #
# ]
1042 : 0 : free_fs_request(req);
1043 : 0 : return;
1044 : : }
1045 : :
1046 [ # # # # ]: 2692 : f->blobid = blobid;
1047 [ # # # # : 2692 : spdk_bs_open_blob(f->fs->bs, blobid, fs_create_blob_open_cb, req);
# # # # ]
1048 : 0 : }
1049 : :
1050 : : void
1051 : 2701 : spdk_fs_create_file_async(struct spdk_filesystem *fs, const char *name,
1052 : : spdk_file_op_complete cb_fn, void *cb_arg)
1053 : : {
1054 : : struct spdk_file *file;
1055 : : struct spdk_fs_request *req;
1056 : : struct spdk_fs_cb_args *args;
1057 : :
1058 [ + + + + ]: 2701 : if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) {
1059 [ # # # # ]: 3 : cb_fn(cb_arg, -ENAMETOOLONG);
1060 : 3 : return;
1061 : : }
1062 : :
1063 : 2698 : file = fs_find_file(fs, name);
1064 [ + + ]: 2698 : if (file != NULL) {
1065 [ # # # # ]: 6 : cb_fn(cb_arg, -EEXIST);
1066 : 6 : return;
1067 : : }
1068 : :
1069 : 2692 : file = file_alloc(fs);
1070 [ - + ]: 2692 : if (file == NULL) {
1071 : 0 : SPDK_ERRLOG("Cannot allocate new file for creation\n");
1072 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1073 : 0 : return;
1074 : : }
1075 : :
1076 [ # # # # : 2692 : req = alloc_fs_request(fs->md_target.md_fs_channel);
# # ]
1077 [ - + ]: 2692 : if (req == NULL) {
1078 : 0 : SPDK_ERRLOG("Cannot allocate create async req for file=%s\n", name);
1079 [ # # # # : 0 : TAILQ_REMOVE(&fs->files, file, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1080 : 0 : file_free(file);
1081 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1082 : 0 : return;
1083 : : }
1084 : :
1085 [ # # ]: 2692 : args = &req->args;
1086 [ # # # # ]: 2692 : args->file = file;
1087 [ # # # # : 2692 : args->fn.file_op = cb_fn;
# # ]
1088 [ # # # # ]: 2692 : args->arg = cb_arg;
1089 : :
1090 [ - + # # : 2692 : file->name = strdup(name);
# # ]
1091 [ - + # # : 2692 : if (!file->name) {
# # ]
1092 : 0 : SPDK_ERRLOG("Cannot allocate file->name for file=%s\n", name);
1093 : 0 : free_fs_request(req);
1094 [ # # # # : 0 : TAILQ_REMOVE(&fs->files, file, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1095 : 0 : file_free(file);
1096 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1097 : 0 : return;
1098 : : }
1099 [ # # # # ]: 2692 : spdk_bs_create_blob(fs->bs, fs_create_blob_create_cb, args);
1100 : 0 : }
1101 : :
1102 : : static void
1103 : 7 : __fs_create_file_done(void *arg, int fserrno)
1104 : : {
1105 : 7 : struct spdk_fs_request *req = arg;
1106 [ # # ]: 7 : struct spdk_fs_cb_args *args = &req->args;
1107 : :
1108 [ - + - + : 7 : SPDK_DEBUGLOG(blobfs, "file=%s\n", args->op.create.name);
# # # # #
# # # #
# ]
1109 : 7 : __wake_caller(args, fserrno);
1110 : 7 : }
1111 : :
1112 : : static void
1113 : 7 : __fs_create_file(void *arg)
1114 : : {
1115 : 7 : struct spdk_fs_request *req = arg;
1116 [ # # ]: 7 : struct spdk_fs_cb_args *args = &req->args;
1117 : :
1118 [ - + - + : 7 : SPDK_DEBUGLOG(blobfs, "file=%s\n", args->op.create.name);
# # # # #
# # # #
# ]
1119 [ # # # # : 7 : spdk_fs_create_file_async(args->fs, args->op.create.name, __fs_create_file_done, req);
# # # # #
# # # ]
1120 : 7 : }
1121 : :
1122 : : int
1123 : 7 : spdk_fs_create_file(struct spdk_filesystem *fs, struct spdk_fs_thread_ctx *ctx, const char *name)
1124 : : {
1125 : 7 : struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
1126 : : struct spdk_fs_request *req;
1127 : : struct spdk_fs_cb_args *args;
1128 : : int rc;
1129 : :
1130 [ - + - + : 7 : SPDK_DEBUGLOG(blobfs, "file=%s\n", name);
# # ]
1131 : :
1132 : 7 : req = alloc_fs_request(channel);
1133 [ - + ]: 7 : if (req == NULL) {
1134 : 0 : SPDK_ERRLOG("Cannot allocate req to create file=%s\n", name);
1135 : 0 : return -ENOMEM;
1136 : : }
1137 : :
1138 [ # # ]: 7 : args = &req->args;
1139 [ # # # # ]: 7 : args->fs = fs;
1140 [ # # # # : 7 : args->op.create.name = name;
# # # # ]
1141 [ # # # # : 7 : args->sem = &channel->sem;
# # ]
1142 [ # # # # : 7 : fs->send_request(__fs_create_file, req);
# # # # ]
1143 [ - + # # ]: 7 : sem_wait(&channel->sem);
1144 [ # # # # ]: 7 : rc = args->rc;
1145 : 7 : free_fs_request(req);
1146 : :
1147 : 7 : return rc;
1148 : 0 : }
1149 : :
1150 : : static void
1151 : 8916 : fs_open_blob_done(void *ctx, struct spdk_blob *blob, int bserrno)
1152 : : {
1153 : 8916 : struct spdk_fs_request *req = ctx;
1154 [ # # ]: 8916 : struct spdk_fs_cb_args *args = &req->args;
1155 [ # # # # ]: 8916 : struct spdk_file *f = args->file;
1156 : :
1157 [ # # # # ]: 8916 : f->blob = blob;
1158 [ + + # # : 17832 : while (!TAILQ_EMPTY(&f->open_requests)) {
# # # # ]
1159 [ # # # # : 8916 : req = TAILQ_FIRST(&f->open_requests);
# # ]
1160 [ # # ]: 8916 : args = &req->args;
1161 [ - + # # : 8916 : TAILQ_REMOVE(&f->open_requests, req, args.op.open.tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1162 [ + + + + : 8916 : spdk_trace_record(TRACE_BLOBFS_OPEN, 0, 0, 0, f->name);
# # # # #
# # # # #
# # # # #
# # # ]
1163 [ # # # # : 8916 : args->fn.file_op_with_handle(args->arg, f, bserrno);
# # # # #
# # # #
# ]
1164 : 8916 : free_fs_request(req);
1165 : : }
1166 : 8916 : }
1167 : :
1168 : : static void
1169 : 8916 : fs_open_blob_create_cb(void *ctx, int bserrno)
1170 : : {
1171 : 8916 : struct spdk_fs_request *req = ctx;
1172 [ # # ]: 8916 : struct spdk_fs_cb_args *args = &req->args;
1173 [ # # # # ]: 8916 : struct spdk_file *file = args->file;
1174 [ # # # # ]: 8916 : struct spdk_filesystem *fs = args->fs;
1175 : :
1176 [ + + ]: 8916 : if (file == NULL) {
1177 : : /*
1178 : : * This is from an open with CREATE flag - the file
1179 : : * is now created so look it up in the file list for this
1180 : : * filesystem.
1181 : : */
1182 [ # # # # : 2682 : file = fs_find_file(fs, args->op.open.name);
# # # # ]
1183 [ - + # # ]: 2682 : assert(file != NULL);
1184 [ # # # # ]: 2682 : args->file = file;
1185 : 0 : }
1186 : :
1187 [ # # ]: 8916 : file->ref_count++;
1188 [ # # # # : 8916 : TAILQ_INSERT_TAIL(&file->open_requests, req, args.op.open.tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1189 [ + - # # : 8916 : if (file->ref_count == 1) {
# # ]
1190 [ - + # # : 8916 : assert(file->blob == NULL);
# # # # ]
1191 [ # # # # : 8916 : spdk_bs_open_blob(fs->bs, file->blobid, fs_open_blob_done, req);
# # # # ]
1192 [ # # # # : 0 : } else if (file->blob != NULL) {
# # ]
1193 [ # # # # ]: 0 : fs_open_blob_done(req, file->blob, 0);
1194 : 0 : } else {
1195 : : /*
1196 : : * The blob open for this file is in progress due to a previous
1197 : : * open request. When that open completes, it will invoke the
1198 : : * open callback for this request.
1199 : : */
1200 : : }
1201 : 8916 : }
1202 : :
1203 : : void
1204 : 8928 : spdk_fs_open_file_async(struct spdk_filesystem *fs, const char *name, uint32_t flags,
1205 : : spdk_file_op_with_handle_complete cb_fn, void *cb_arg)
1206 : : {
1207 : 8928 : struct spdk_file *f = NULL;
1208 : : struct spdk_fs_request *req;
1209 : : struct spdk_fs_cb_args *args;
1210 : :
1211 [ + + + + ]: 8928 : if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) {
1212 [ # # # # ]: 3 : cb_fn(cb_arg, NULL, -ENAMETOOLONG);
1213 : 3 : return;
1214 : : }
1215 : :
1216 : 8925 : f = fs_find_file(fs, name);
1217 [ + + + + : 8925 : if (f == NULL && !(flags & SPDK_BLOBFS_OPEN_CREATE)) {
# # ]
1218 [ # # # # ]: 6 : cb_fn(cb_arg, NULL, -ENOENT);
1219 : 6 : return;
1220 : : }
1221 : :
1222 [ + + + + : 8919 : if (f != NULL && f->is_deleted == true) {
+ + # # #
# ]
1223 [ # # # # ]: 3 : cb_fn(cb_arg, NULL, -ENOENT);
1224 : 3 : return;
1225 : : }
1226 : :
1227 [ # # # # : 8916 : req = alloc_fs_request(fs->md_target.md_fs_channel);
# # ]
1228 [ - + ]: 8916 : if (req == NULL) {
1229 : 0 : SPDK_ERRLOG("Cannot allocate async open req for file=%s\n", name);
1230 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
1231 : 0 : return;
1232 : : }
1233 : :
1234 [ # # ]: 8916 : args = &req->args;
1235 [ # # # # : 8916 : args->fn.file_op_with_handle = cb_fn;
# # ]
1236 [ # # # # ]: 8916 : args->arg = cb_arg;
1237 [ # # # # ]: 8916 : args->file = f;
1238 [ # # # # ]: 8916 : args->fs = fs;
1239 [ # # # # : 8916 : args->op.open.name = name;
# # # # ]
1240 : :
1241 [ + + ]: 8916 : if (f == NULL) {
1242 : 2682 : spdk_fs_create_file_async(fs, name, fs_open_blob_create_cb, req);
1243 : 0 : } else {
1244 : 6234 : fs_open_blob_create_cb(req, 0);
1245 : : }
1246 : 0 : }
1247 : :
1248 : : static void
1249 : 8904 : __fs_open_file_done(void *arg, struct spdk_file *file, int bserrno)
1250 : : {
1251 : 8904 : struct spdk_fs_request *req = arg;
1252 [ # # ]: 8904 : struct spdk_fs_cb_args *args = &req->args;
1253 : :
1254 [ # # # # ]: 8904 : args->file = file;
1255 [ - + - + : 8904 : SPDK_DEBUGLOG(blobfs, "file=%s\n", args->op.open.name);
# # # # #
# # # #
# ]
1256 : 8904 : __wake_caller(args, bserrno);
1257 : 8904 : }
1258 : :
1259 : : static void
1260 : 8904 : __fs_open_file(void *arg)
1261 : : {
1262 : 8904 : struct spdk_fs_request *req = arg;
1263 [ # # ]: 8904 : struct spdk_fs_cb_args *args = &req->args;
1264 : :
1265 [ - + - + : 8904 : SPDK_DEBUGLOG(blobfs, "file=%s\n", args->op.open.name);
# # # # #
# # # #
# ]
1266 [ # # # # : 8904 : spdk_fs_open_file_async(args->fs, args->op.open.name, args->op.open.flags,
# # # # #
# # # # #
# # # # #
# ]
1267 : 0 : __fs_open_file_done, req);
1268 : 8904 : }
1269 : :
1270 : : int
1271 : 8904 : spdk_fs_open_file(struct spdk_filesystem *fs, struct spdk_fs_thread_ctx *ctx,
1272 : : const char *name, uint32_t flags, struct spdk_file **file)
1273 : : {
1274 : 8904 : struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
1275 : : struct spdk_fs_request *req;
1276 : : struct spdk_fs_cb_args *args;
1277 : : int rc;
1278 : :
1279 [ - + - + : 8904 : SPDK_DEBUGLOG(blobfs, "file=%s\n", name);
# # ]
1280 : :
1281 : 8904 : req = alloc_fs_request(channel);
1282 [ - + ]: 8904 : if (req == NULL) {
1283 : 0 : SPDK_ERRLOG("Cannot allocate req for opening file=%s\n", name);
1284 : 0 : return -ENOMEM;
1285 : : }
1286 : :
1287 [ # # ]: 8904 : args = &req->args;
1288 [ # # # # ]: 8904 : args->fs = fs;
1289 [ # # # # : 8904 : args->op.open.name = name;
# # # # ]
1290 [ # # # # : 8904 : args->op.open.flags = flags;
# # # # ]
1291 [ # # # # : 8904 : args->sem = &channel->sem;
# # ]
1292 [ # # # # : 8904 : fs->send_request(__fs_open_file, req);
# # # # ]
1293 [ - + # # ]: 8904 : sem_wait(&channel->sem);
1294 [ # # # # ]: 8904 : rc = args->rc;
1295 [ + + ]: 8904 : if (rc == 0) {
1296 [ # # # # : 8898 : *file = args->file;
# # ]
1297 : 0 : } else {
1298 [ # # ]: 6 : *file = NULL;
1299 : : }
1300 : 8904 : free_fs_request(req);
1301 : :
1302 : 8904 : return rc;
1303 : 0 : }
1304 : :
1305 : : static void
1306 : 22 : fs_rename_blob_close_cb(void *ctx, int bserrno)
1307 : : {
1308 : 22 : struct spdk_fs_request *req = ctx;
1309 [ # # ]: 22 : struct spdk_fs_cb_args *args = &req->args;
1310 : :
1311 [ # # # # : 22 : args->fn.fs_op(args->arg, bserrno);
# # # # #
# # # #
# ]
1312 : 22 : free_fs_request(req);
1313 : 22 : }
1314 : :
1315 : : static void
1316 : 22 : fs_rename_blob_open_cb(void *ctx, struct spdk_blob *blob, int bserrno)
1317 : : {
1318 : 22 : struct spdk_fs_request *req = ctx;
1319 [ # # ]: 22 : struct spdk_fs_cb_args *args = &req->args;
1320 [ # # # # : 22 : const char *new_name = args->op.rename.new_name;
# # # # ]
1321 : :
1322 [ - + ]: 22 : spdk_blob_set_xattr(blob, "name", new_name, strlen(new_name) + 1);
1323 : 22 : spdk_blob_close(blob, fs_rename_blob_close_cb, req);
1324 : 22 : }
1325 : :
1326 : : static void
1327 : 30 : _fs_md_rename_file(struct spdk_fs_request *req)
1328 : : {
1329 [ # # ]: 30 : struct spdk_fs_cb_args *args = &req->args;
1330 : : struct spdk_file *f;
1331 : :
1332 [ # # # # : 30 : f = fs_find_file(args->fs, args->op.rename.old_name);
# # # # #
# # # ]
1333 [ + + ]: 30 : if (f == NULL) {
1334 [ # # # # : 8 : args->fn.fs_op(args->arg, -ENOENT);
# # # # #
# # # #
# ]
1335 : 8 : free_fs_request(req);
1336 : 8 : return;
1337 : : }
1338 : :
1339 [ # # # # ]: 22 : free(f->name);
1340 [ - + # # : 22 : f->name = strdup(args->op.rename.new_name);
# # # # #
# # # #
# ]
1341 [ - + # # : 22 : if (!f->name) {
# # ]
1342 : 0 : SPDK_ERRLOG("Cannot allocate memory for file name\n");
1343 [ # # # # : 0 : args->fn.fs_op(args->arg, -ENOMEM);
# # # # #
# # # #
# ]
1344 : 0 : free_fs_request(req);
1345 : 0 : return;
1346 : : }
1347 : :
1348 [ # # # # ]: 22 : args->file = f;
1349 [ # # # # : 22 : spdk_bs_open_blob(args->fs->bs, f->blobid, fs_rename_blob_open_cb, req);
# # # # #
# # # ]
1350 : 0 : }
1351 : :
1352 : : static void
1353 : 9 : fs_rename_delete_done(void *arg, int fserrno)
1354 : : {
1355 : 9 : _fs_md_rename_file(arg);
1356 : 9 : }
1357 : :
1358 : : void
1359 : 30 : spdk_fs_rename_file_async(struct spdk_filesystem *fs,
1360 : : const char *old_name, const char *new_name,
1361 : : spdk_file_op_complete cb_fn, void *cb_arg)
1362 : : {
1363 : : struct spdk_file *f;
1364 : : struct spdk_fs_request *req;
1365 : : struct spdk_fs_cb_args *args;
1366 : :
1367 [ - + - + : 30 : SPDK_DEBUGLOG(blobfs, "old=%s new=%s\n", old_name, new_name);
# # ]
1368 [ - + - + ]: 30 : if (strnlen(new_name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) {
1369 [ # # # # ]: 0 : cb_fn(cb_arg, -ENAMETOOLONG);
1370 : 0 : return;
1371 : : }
1372 : :
1373 [ # # # # : 30 : req = alloc_fs_request(fs->md_target.md_fs_channel);
# # ]
1374 [ - + ]: 30 : if (req == NULL) {
1375 : 0 : SPDK_ERRLOG("Cannot allocate rename async req for renaming file from %s to %s\n", old_name,
1376 : : new_name);
1377 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1378 : 0 : return;
1379 : : }
1380 : :
1381 [ # # ]: 30 : args = &req->args;
1382 [ # # # # : 30 : args->fn.fs_op = cb_fn;
# # ]
1383 [ # # # # ]: 30 : args->fs = fs;
1384 [ # # # # ]: 30 : args->arg = cb_arg;
1385 [ # # # # : 30 : args->op.rename.old_name = old_name;
# # # # ]
1386 [ # # # # : 30 : args->op.rename.new_name = new_name;
# # # # ]
1387 : :
1388 : 30 : f = fs_find_file(fs, new_name);
1389 [ + + ]: 30 : if (f == NULL) {
1390 : 21 : _fs_md_rename_file(req);
1391 : 21 : return;
1392 : : }
1393 : :
1394 : : /*
1395 : : * The rename overwrites an existing file. So delete the existing file, then
1396 : : * do the actual rename.
1397 : : */
1398 : 9 : spdk_fs_delete_file_async(fs, new_name, fs_rename_delete_done, req);
1399 : 0 : }
1400 : :
1401 : : static void
1402 : 27 : __fs_rename_file_done(void *arg, int fserrno)
1403 : : {
1404 : 27 : struct spdk_fs_request *req = arg;
1405 [ # # ]: 27 : struct spdk_fs_cb_args *args = &req->args;
1406 : :
1407 : 27 : __wake_caller(args, fserrno);
1408 : 27 : }
1409 : :
1410 : : static void
1411 : 27 : __fs_rename_file(void *arg)
1412 : : {
1413 : 27 : struct spdk_fs_request *req = arg;
1414 [ # # ]: 27 : struct spdk_fs_cb_args *args = &req->args;
1415 : :
1416 [ # # # # : 27 : spdk_fs_rename_file_async(args->fs, args->op.rename.old_name, args->op.rename.new_name,
# # # # #
# # # # #
# # # # #
# ]
1417 : 0 : __fs_rename_file_done, req);
1418 : 27 : }
1419 : :
1420 : : int
1421 : 27 : spdk_fs_rename_file(struct spdk_filesystem *fs, struct spdk_fs_thread_ctx *ctx,
1422 : : const char *old_name, const char *new_name)
1423 : : {
1424 : 27 : struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
1425 : : struct spdk_fs_request *req;
1426 : : struct spdk_fs_cb_args *args;
1427 : : int rc;
1428 : :
1429 : 27 : req = alloc_fs_request(channel);
1430 [ - + ]: 27 : if (req == NULL) {
1431 : 0 : SPDK_ERRLOG("Cannot allocate rename req for file=%s\n", old_name);
1432 : 0 : return -ENOMEM;
1433 : : }
1434 : :
1435 [ # # ]: 27 : args = &req->args;
1436 : :
1437 [ # # # # ]: 27 : args->fs = fs;
1438 [ # # # # : 27 : args->op.rename.old_name = old_name;
# # # # ]
1439 [ # # # # : 27 : args->op.rename.new_name = new_name;
# # # # ]
1440 [ # # # # : 27 : args->sem = &channel->sem;
# # ]
1441 [ # # # # : 27 : fs->send_request(__fs_rename_file, req);
# # # # ]
1442 [ - + # # ]: 27 : sem_wait(&channel->sem);
1443 [ # # # # ]: 27 : rc = args->rc;
1444 : 27 : free_fs_request(req);
1445 : 27 : return rc;
1446 : 0 : }
1447 : :
1448 : : static void
1449 : 1247 : blob_delete_cb(void *ctx, int bserrno)
1450 : : {
1451 : 1247 : struct spdk_fs_request *req = ctx;
1452 [ # # ]: 1247 : struct spdk_fs_cb_args *args = &req->args;
1453 : :
1454 [ # # # # : 1247 : args->fn.file_op(args->arg, bserrno);
# # # # #
# # # #
# ]
1455 : 1247 : free_fs_request(req);
1456 : 1247 : }
1457 : :
1458 : : void
1459 : 1247 : spdk_fs_delete_file_async(struct spdk_filesystem *fs, const char *name,
1460 : : spdk_file_op_complete cb_fn, void *cb_arg)
1461 : : {
1462 : : struct spdk_file *f;
1463 : : spdk_blob_id blobid;
1464 : : struct spdk_fs_request *req;
1465 : : struct spdk_fs_cb_args *args;
1466 : :
1467 [ - + - + : 1247 : SPDK_DEBUGLOG(blobfs, "file=%s\n", name);
# # ]
1468 : :
1469 [ - + - + ]: 1247 : if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) {
1470 [ # # # # ]: 0 : cb_fn(cb_arg, -ENAMETOOLONG);
1471 : 0 : return;
1472 : : }
1473 : :
1474 : 1247 : f = fs_find_file(fs, name);
1475 [ + + ]: 1247 : if (f == NULL) {
1476 : 6 : SPDK_ERRLOG("Cannot find the file=%s to deleted\n", name);
1477 [ # # # # ]: 6 : cb_fn(cb_arg, -ENOENT);
1478 : 6 : return;
1479 : : }
1480 : :
1481 [ # # # # : 1241 : req = alloc_fs_request(fs->md_target.md_fs_channel);
# # ]
1482 [ - + ]: 1241 : if (req == NULL) {
1483 : 0 : SPDK_ERRLOG("Cannot allocate the req for the file=%s to deleted\n", name);
1484 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1485 : 0 : return;
1486 : : }
1487 : :
1488 [ # # ]: 1241 : args = &req->args;
1489 [ # # # # : 1241 : args->fn.file_op = cb_fn;
# # ]
1490 [ # # # # ]: 1241 : args->arg = cb_arg;
1491 : :
1492 [ + + # # : 1241 : if (f->ref_count > 0) {
# # ]
1493 : : /* If the ref > 0, we mark the file as deleted and delete it when we close it. */
1494 [ # # # # ]: 6 : f->is_deleted = true;
1495 [ # # # # : 6 : spdk_blob_set_xattr(f->blob, "is_deleted", &f->is_deleted, sizeof(bool));
# # ]
1496 [ # # # # ]: 6 : spdk_blob_sync_md(f->blob, blob_delete_cb, req);
1497 : 6 : return;
1498 : : }
1499 : :
1500 [ # # # # ]: 1235 : blobid = f->blobid;
1501 [ + + # # : 1235 : TAILQ_REMOVE(&fs->files, f, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1502 : :
1503 : 1235 : file_free(f);
1504 : :
1505 [ # # # # ]: 1235 : spdk_bs_delete_blob(fs->bs, blobid, blob_delete_cb, req);
1506 : 0 : }
1507 : :
1508 : : static void
1509 : 1217 : __fs_delete_file_done(void *arg, int fserrno)
1510 : : {
1511 : 1217 : struct spdk_fs_request *req = arg;
1512 [ # # ]: 1217 : struct spdk_fs_cb_args *args = &req->args;
1513 : :
1514 [ + + + + : 1217 : spdk_trace_record(TRACE_BLOBFS_DELETE_DONE, 0, 0, 0, args->op.delete.name);
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1515 : 1217 : __wake_caller(args, fserrno);
1516 : 1217 : }
1517 : :
1518 : : static void
1519 : 1217 : __fs_delete_file(void *arg)
1520 : : {
1521 : 1217 : struct spdk_fs_request *req = arg;
1522 [ # # ]: 1217 : struct spdk_fs_cb_args *args = &req->args;
1523 : :
1524 [ + + + + : 1217 : spdk_trace_record(TRACE_BLOBFS_DELETE_START, 0, 0, 0, args->op.delete.name);
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1525 [ # # # # : 1217 : spdk_fs_delete_file_async(args->fs, args->op.delete.name, __fs_delete_file_done, req);
# # # # #
# # # ]
1526 : 1217 : }
1527 : :
1528 : : int
1529 : 1217 : spdk_fs_delete_file(struct spdk_filesystem *fs, struct spdk_fs_thread_ctx *ctx,
1530 : : const char *name)
1531 : : {
1532 : 1217 : struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
1533 : : struct spdk_fs_request *req;
1534 : : struct spdk_fs_cb_args *args;
1535 : : int rc;
1536 : :
1537 : 1217 : req = alloc_fs_request(channel);
1538 [ - + ]: 1217 : if (req == NULL) {
1539 [ # # # # : 0 : SPDK_DEBUGLOG(blobfs, "Cannot allocate req to delete file=%s\n", name);
# # ]
1540 : 0 : return -ENOMEM;
1541 : : }
1542 : :
1543 [ # # ]: 1217 : args = &req->args;
1544 [ # # # # ]: 1217 : args->fs = fs;
1545 [ # # # # : 1217 : args->op.delete.name = name;
# # # # ]
1546 [ # # # # : 1217 : args->sem = &channel->sem;
# # ]
1547 [ # # # # : 1217 : fs->send_request(__fs_delete_file, req);
# # # # ]
1548 [ - + # # ]: 1217 : sem_wait(&channel->sem);
1549 [ # # # # ]: 1217 : rc = args->rc;
1550 : 1217 : free_fs_request(req);
1551 : :
1552 : 1217 : return rc;
1553 : 0 : }
1554 : :
1555 : : spdk_fs_iter
1556 : 65 : spdk_fs_iter_first(struct spdk_filesystem *fs)
1557 : : {
1558 : : struct spdk_file *f;
1559 : :
1560 [ # # # # : 65 : f = TAILQ_FIRST(&fs->files);
# # ]
1561 : 65 : return f;
1562 : : }
1563 : :
1564 : : spdk_fs_iter
1565 : 56457 : spdk_fs_iter_next(spdk_fs_iter iter)
1566 : : {
1567 : 56457 : struct spdk_file *f = iter;
1568 : :
1569 [ - + ]: 56457 : if (f == NULL) {
1570 : 0 : return NULL;
1571 : : }
1572 : :
1573 [ # # # # : 56457 : f = TAILQ_NEXT(f, tailq);
# # ]
1574 : 56457 : return f;
1575 : 0 : }
1576 : :
1577 : : const char *
1578 : 49674 : spdk_file_get_name(struct spdk_file *file)
1579 : : {
1580 [ # # # # ]: 49674 : return file->name;
1581 : : }
1582 : :
1583 : : uint64_t
1584 : 18 : spdk_file_get_length(struct spdk_file *file)
1585 : : {
1586 : : uint64_t length;
1587 : :
1588 [ - + # # ]: 18 : assert(file != NULL);
1589 : :
1590 [ # # # # : 18 : length = file->append_pos >= file->length ? file->append_pos : file->length;
# # # # #
# # # # #
# # # # ]
1591 [ - + - + : 18 : SPDK_DEBUGLOG(blobfs, "file=%s length=0x%jx\n", file->name, length);
# # # # #
# ]
1592 : 18 : return length;
1593 : : }
1594 : :
1595 : : static void
1596 : 1449 : fs_truncate_complete_cb(void *ctx, int bserrno)
1597 : : {
1598 : 1449 : struct spdk_fs_request *req = ctx;
1599 [ # # ]: 1449 : struct spdk_fs_cb_args *args = &req->args;
1600 : :
1601 [ # # # # : 1449 : args->fn.file_op(args->arg, bserrno);
# # # # #
# # # #
# ]
1602 : 1449 : free_fs_request(req);
1603 : 1449 : }
1604 : :
1605 : : static void
1606 : 1449 : fs_truncate_resize_cb(void *ctx, int bserrno)
1607 : : {
1608 : 1449 : struct spdk_fs_request *req = ctx;
1609 [ # # ]: 1449 : struct spdk_fs_cb_args *args = &req->args;
1610 [ # # # # ]: 1449 : struct spdk_file *file = args->file;
1611 [ # # # # : 1449 : uint64_t *length = &args->op.truncate.length;
# # ]
1612 : :
1613 [ - + ]: 1449 : if (bserrno) {
1614 [ # # # # : 0 : args->fn.file_op(args->arg, bserrno);
# # # # #
# # # #
# ]
1615 : 0 : free_fs_request(req);
1616 : 0 : return;
1617 : : }
1618 : :
1619 [ # # # # ]: 1449 : spdk_blob_set_xattr(file->blob, "length", length, sizeof(*length));
1620 : :
1621 [ # # # # : 1449 : file->length = *length;
# # ]
1622 [ - + # # : 1449 : if (file->append_pos > file->length) {
# # # # #
# ]
1623 [ # # # # : 0 : file->append_pos = file->length;
# # # # ]
1624 : 0 : }
1625 : :
1626 [ # # # # ]: 1449 : spdk_blob_sync_md(file->blob, fs_truncate_complete_cb, req);
1627 : 0 : }
1628 : :
1629 : : static uint64_t
1630 : 112289 : __bytes_to_clusters(uint64_t length, uint64_t cluster_sz)
1631 : : {
1632 [ - + ]: 112289 : return (length + cluster_sz - 1) / cluster_sz;
1633 : : }
1634 : :
1635 : : void
1636 : 1452 : spdk_file_truncate_async(struct spdk_file *file, uint64_t length,
1637 : : spdk_file_op_complete cb_fn, void *cb_arg)
1638 : : {
1639 : : struct spdk_filesystem *fs;
1640 : : size_t num_clusters;
1641 : : struct spdk_fs_request *req;
1642 : : struct spdk_fs_cb_args *args;
1643 : :
1644 [ - + - + : 1452 : SPDK_DEBUGLOG(blobfs, "file=%s old=0x%jx new=0x%jx\n", file->name, file->length, length);
# # # # #
# # # #
# ]
1645 [ + + # # : 1452 : if (length == file->length) {
# # ]
1646 [ # # # # ]: 3 : cb_fn(cb_arg, 0);
1647 : 3 : return;
1648 : : }
1649 : :
1650 [ # # # # : 1449 : req = alloc_fs_request(file->fs->md_target.md_fs_channel);
# # # # #
# ]
1651 [ - + ]: 1449 : if (req == NULL) {
1652 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1653 : 0 : return;
1654 : : }
1655 : :
1656 [ # # ]: 1449 : args = &req->args;
1657 [ # # # # : 1449 : args->fn.file_op = cb_fn;
# # ]
1658 [ # # # # ]: 1449 : args->arg = cb_arg;
1659 [ # # # # ]: 1449 : args->file = file;
1660 [ # # # # : 1449 : args->op.truncate.length = length;
# # # # ]
1661 [ # # # # ]: 1449 : fs = file->fs;
1662 : :
1663 [ # # # # : 1449 : num_clusters = __bytes_to_clusters(length, fs->bs_opts.cluster_sz);
# # ]
1664 : :
1665 [ # # # # ]: 1449 : spdk_blob_resize(file->blob, num_clusters, fs_truncate_resize_cb, req);
1666 : 0 : }
1667 : :
1668 : : static void
1669 : 1434 : __truncate(void *arg)
1670 : : {
1671 : 1434 : struct spdk_fs_request *req = arg;
1672 [ # # ]: 1434 : struct spdk_fs_cb_args *args = &req->args;
1673 : :
1674 [ # # # # : 1434 : spdk_file_truncate_async(args->file, args->op.truncate.length,
# # # # #
# # # ]
1675 [ # # # # : 0 : args->fn.file_op, args);
# # ]
1676 : 1434 : }
1677 : :
1678 : : int
1679 : 1434 : spdk_file_truncate(struct spdk_file *file, struct spdk_fs_thread_ctx *ctx,
1680 : : uint64_t length)
1681 : : {
1682 : 1434 : struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
1683 : : struct spdk_fs_request *req;
1684 : : struct spdk_fs_cb_args *args;
1685 : : int rc;
1686 : :
1687 : 1434 : req = alloc_fs_request(channel);
1688 [ - + ]: 1434 : if (req == NULL) {
1689 : 0 : return -ENOMEM;
1690 : : }
1691 : :
1692 [ # # ]: 1434 : args = &req->args;
1693 : :
1694 [ # # # # ]: 1434 : args->file = file;
1695 [ # # # # : 1434 : args->op.truncate.length = length;
# # # # ]
1696 [ # # # # : 1434 : args->fn.file_op = __wake_caller;
# # ]
1697 [ # # # # : 1434 : args->sem = &channel->sem;
# # ]
1698 : :
1699 [ # # # # : 1434 : channel->send_request(__truncate, req);
# # # # ]
1700 [ - + # # ]: 1434 : sem_wait(&channel->sem);
1701 [ # # # # ]: 1434 : rc = args->rc;
1702 : 1434 : free_fs_request(req);
1703 : :
1704 : 1434 : return rc;
1705 : 0 : }
1706 : :
1707 : : static void
1708 : 3477753 : __rw_done(void *ctx, int bserrno)
1709 : : {
1710 : 3477753 : struct spdk_fs_request *req = ctx;
1711 [ # # ]: 3477753 : struct spdk_fs_cb_args *args = &req->args;
1712 : :
1713 [ # # # # : 3477753 : spdk_free(args->op.rw.pin_buf);
# # # # ]
1714 [ # # # # : 3477753 : args->fn.file_op(args->arg, bserrno);
# # # # #
# # # #
# ]
1715 : 3477753 : free_fs_request(req);
1716 : 3477753 : }
1717 : :
1718 : : static void
1719 : 3477750 : __read_done(void *ctx, int bserrno)
1720 : : {
1721 : 3477750 : struct spdk_fs_request *req = ctx;
1722 [ # # ]: 3477750 : struct spdk_fs_cb_args *args = &req->args;
1723 : : void *buf;
1724 : :
1725 [ - + ]: 3477750 : if (bserrno) {
1726 : 0 : __rw_done(req, bserrno);
1727 : 0 : return;
1728 : : }
1729 : :
1730 [ - + # # ]: 3477750 : assert(req != NULL);
1731 [ # # # # : 3477750 : buf = (void *)((uintptr_t)args->op.rw.pin_buf + (args->op.rw.offset & (args->op.rw.blocklen - 1)));
# # # # #
# # # # #
# # # # #
# # # #
# ]
1732 [ + + # # : 3477750 : if (args->op.rw.is_read) {
# # # # #
# ]
1733 [ # # # # : 3446600 : spdk_copy_buf_to_iovs(args->iovs, args->iovcnt, buf, args->op.rw.length);
# # # # #
# # # # #
# # ]
1734 : 3446600 : __rw_done(req, 0);
1735 : 0 : } else {
1736 [ # # # # : 31150 : spdk_copy_iovs_to_buf(buf, args->op.rw.length, args->iovs, args->iovcnt);
# # # # #
# # # # #
# # ]
1737 [ # # # # : 31150 : spdk_blob_io_write(args->file->blob, args->op.rw.channel,
# # # # #
# # # # #
# # ]
1738 [ # # # # : 0 : args->op.rw.pin_buf,
# # # # ]
1739 [ # # # # : 0 : args->op.rw.start_lba, args->op.rw.num_lba,
# # # # #
# # # # #
# # ]
1740 : 0 : __rw_done, req);
1741 : : }
1742 : 0 : }
1743 : :
1744 : : static void
1745 : 3477750 : __do_blob_read(void *ctx, int fserrno)
1746 : : {
1747 : 3477750 : struct spdk_fs_request *req = ctx;
1748 [ # # ]: 3477750 : struct spdk_fs_cb_args *args = &req->args;
1749 : :
1750 [ - + ]: 3477750 : if (fserrno) {
1751 : 0 : __rw_done(req, fserrno);
1752 : 0 : return;
1753 : : }
1754 [ # # # # : 3477750 : spdk_blob_io_read(args->file->blob, args->op.rw.channel,
# # # # #
# # # # #
# # ]
1755 [ # # # # : 0 : args->op.rw.pin_buf,
# # # # ]
1756 [ # # # # : 0 : args->op.rw.start_lba, args->op.rw.num_lba,
# # # # #
# # # # #
# # ]
1757 : 0 : __read_done, req);
1758 : 0 : }
1759 : :
1760 : : static void
1761 : 4797361 : __get_page_parameters(struct spdk_file *file, uint64_t offset, uint64_t length,
1762 : : uint64_t *start_lba, uint32_t *lba_size, uint64_t *num_lba)
1763 : : {
1764 : : uint64_t end_lba;
1765 : :
1766 [ # # # # : 4797361 : *lba_size = spdk_bs_get_io_unit_size(file->fs->bs);
# # # # #
# ]
1767 [ - + # # : 4797361 : *start_lba = offset / *lba_size;
# # ]
1768 [ - + # # ]: 4797361 : end_lba = (offset + length - 1) / *lba_size;
1769 [ # # # # ]: 4797361 : *num_lba = (end_lba - *start_lba + 1);
1770 : 4797361 : }
1771 : :
1772 : : static bool
1773 : 31144 : __is_lba_aligned(struct spdk_file *file, uint64_t offset, uint64_t length)
1774 : : {
1775 [ # # # # : 31144 : uint32_t lba_size = spdk_bs_get_io_unit_size(file->fs->bs);
# # # # ]
1776 : :
1777 [ + + + + : 31144 : if ((offset % lba_size == 0) && (length % lba_size == 0)) {
- + + + ]
1778 : 3 : return true;
1779 : : }
1780 : :
1781 : 31141 : return false;
1782 : 0 : }
1783 : :
1784 : : static void
1785 : 3477753 : _fs_request_setup_iovs(struct spdk_fs_request *req, struct iovec *iovs, uint32_t iovcnt)
1786 : : {
1787 : : uint32_t i;
1788 : :
1789 [ + + ]: 6955518 : for (i = 0; i < iovcnt; i++) {
1790 [ # # # # : 3477765 : req->args.iovs[i].iov_base = iovs[i].iov_base;
# # # # #
# # # # #
# # # # ]
1791 [ # # # # : 3477765 : req->args.iovs[i].iov_len = iovs[i].iov_len;
# # # # #
# # # # #
# # # # ]
1792 : 0 : }
1793 : 3477753 : }
1794 : :
1795 : : static void
1796 : 3477753 : __readvwritev(struct spdk_file *file, struct spdk_io_channel *_channel,
1797 : : struct iovec *iovs, uint32_t iovcnt, uint64_t offset, uint64_t length,
1798 : : spdk_file_op_complete cb_fn, void *cb_arg, int is_read)
1799 : : {
1800 : : struct spdk_fs_request *req;
1801 : : struct spdk_fs_cb_args *args;
1802 : 3477753 : struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel);
1803 : 3477753 : uint64_t start_lba, num_lba, pin_buf_length;
1804 : 3477753 : uint32_t lba_size;
1805 : :
1806 [ + + - + : 3477753 : if (is_read && offset + length > file->length) {
# # # # ]
1807 [ # # # # ]: 0 : cb_fn(cb_arg, -EINVAL);
1808 : 0 : return;
1809 : : }
1810 : :
1811 : 3477753 : req = alloc_fs_request_with_iov(channel, iovcnt);
1812 [ - + ]: 3477753 : if (req == NULL) {
1813 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1814 : 0 : return;
1815 : : }
1816 : :
1817 : 3477753 : __get_page_parameters(file, offset, length, &start_lba, &lba_size, &num_lba);
1818 : :
1819 [ # # ]: 3477753 : args = &req->args;
1820 [ # # # # : 3477753 : args->fn.file_op = cb_fn;
# # ]
1821 [ # # # # ]: 3477753 : args->arg = cb_arg;
1822 [ # # # # ]: 3477753 : args->file = file;
1823 [ # # # # : 3477753 : args->op.rw.channel = channel->bs_channel;
# # # # #
# # # ]
1824 : 3477753 : _fs_request_setup_iovs(req, iovs, iovcnt);
1825 [ # # # # : 3477753 : args->op.rw.is_read = is_read;
# # # # ]
1826 [ # # # # : 3477753 : args->op.rw.offset = offset;
# # # # ]
1827 [ # # # # : 3477753 : args->op.rw.blocklen = lba_size;
# # # # ]
1828 : :
1829 : 3477753 : pin_buf_length = num_lba * lba_size;
1830 [ # # # # : 3477753 : args->op.rw.length = pin_buf_length;
# # # # ]
1831 [ # # # # : 3477753 : args->op.rw.pin_buf = spdk_malloc(pin_buf_length, lba_size, NULL,
# # # # ]
1832 : : SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
1833 [ - + # # : 3477753 : if (args->op.rw.pin_buf == NULL) {
# # # # #
# ]
1834 [ # # # # : 0 : SPDK_DEBUGLOG(blobfs, "Failed to allocate buf for: file=%s offset=%jx length=%jx\n",
# # # # #
# ]
1835 : : file->name, offset, length);
1836 : 0 : free_fs_request(req);
1837 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1838 : 0 : return;
1839 : : }
1840 : :
1841 [ # # # # : 3477753 : args->op.rw.start_lba = start_lba;
# # # # ]
1842 [ # # # # : 3477753 : args->op.rw.num_lba = num_lba;
# # # # ]
1843 : :
1844 [ + + + + : 3477753 : if (!is_read && file->length < offset + length) {
# # # # ]
1845 : 9 : spdk_file_truncate_async(file, offset + length, __do_blob_read, req);
1846 [ + + + + ]: 3477744 : } else if (!is_read && __is_lba_aligned(file, offset, length)) {
1847 [ # # # # : 3 : spdk_copy_iovs_to_buf(args->op.rw.pin_buf, args->op.rw.length, args->iovs, args->iovcnt);
# # # # #
# # # # #
# # # # #
# # # #
# ]
1848 [ # # # # : 3 : spdk_blob_io_write(args->file->blob, args->op.rw.channel,
# # # # #
# # # # #
# # ]
1849 [ # # # # : 0 : args->op.rw.pin_buf,
# # # # ]
1850 [ # # # # : 0 : args->op.rw.start_lba, args->op.rw.num_lba,
# # # # #
# # # # #
# # ]
1851 : 0 : __rw_done, req);
1852 : 0 : } else {
1853 : 3477741 : __do_blob_read(req, 0);
1854 : : }
1855 : 0 : }
1856 : :
1857 : : static void
1858 : 3477741 : __readwrite(struct spdk_file *file, struct spdk_io_channel *channel,
1859 : : void *payload, uint64_t offset, uint64_t length,
1860 : : spdk_file_op_complete cb_fn, void *cb_arg, int is_read)
1861 : : {
1862 : 3477741 : struct iovec iov;
1863 : :
1864 : 3477741 : iov.iov_base = payload;
1865 [ # # ]: 3477741 : iov.iov_len = (size_t)length;
1866 : :
1867 : 3477741 : __readvwritev(file, channel, &iov, 1, offset, length, cb_fn, cb_arg, is_read);
1868 : 3477741 : }
1869 : :
1870 : : void
1871 : 31147 : spdk_file_write_async(struct spdk_file *file, struct spdk_io_channel *channel,
1872 : : void *payload, uint64_t offset, uint64_t length,
1873 : : spdk_file_op_complete cb_fn, void *cb_arg)
1874 : : {
1875 : 31147 : __readwrite(file, channel, payload, offset, length, cb_fn, cb_arg, 0);
1876 : 31147 : }
1877 : :
1878 : : void
1879 : 6 : spdk_file_writev_async(struct spdk_file *file, struct spdk_io_channel *channel,
1880 : : struct iovec *iovs, uint32_t iovcnt, uint64_t offset, uint64_t length,
1881 : : spdk_file_op_complete cb_fn, void *cb_arg)
1882 : : {
1883 [ - + - + : 6 : SPDK_DEBUGLOG(blobfs, "file=%s offset=%jx length=%jx\n",
# # # # #
# ]
1884 : : file->name, offset, length);
1885 : :
1886 : 6 : __readvwritev(file, channel, iovs, iovcnt, offset, length, cb_fn, cb_arg, 0);
1887 : 6 : }
1888 : :
1889 : : void
1890 : 3446594 : spdk_file_read_async(struct spdk_file *file, struct spdk_io_channel *channel,
1891 : : void *payload, uint64_t offset, uint64_t length,
1892 : : spdk_file_op_complete cb_fn, void *cb_arg)
1893 : : {
1894 [ - + - + : 3446594 : SPDK_DEBUGLOG(blobfs, "file=%s offset=%jx length=%jx\n",
# # # # #
# ]
1895 : : file->name, offset, length);
1896 : :
1897 : 3446594 : __readwrite(file, channel, payload, offset, length, cb_fn, cb_arg, 1);
1898 : 3446594 : }
1899 : :
1900 : : void
1901 : 6 : spdk_file_readv_async(struct spdk_file *file, struct spdk_io_channel *channel,
1902 : : struct iovec *iovs, uint32_t iovcnt, uint64_t offset, uint64_t length,
1903 : : spdk_file_op_complete cb_fn, void *cb_arg)
1904 : : {
1905 [ - + - + : 6 : SPDK_DEBUGLOG(blobfs, "file=%s offset=%jx length=%jx\n",
# # # # #
# ]
1906 : : file->name, offset, length);
1907 : :
1908 : 6 : __readvwritev(file, channel, iovs, iovcnt, offset, length, cb_fn, cb_arg, 1);
1909 : 6 : }
1910 : :
1911 : : struct spdk_io_channel *
1912 : 3 : spdk_fs_alloc_io_channel(struct spdk_filesystem *fs)
1913 : : {
1914 : : struct spdk_io_channel *io_channel;
1915 : : struct spdk_fs_channel *fs_channel;
1916 : :
1917 [ # # ]: 3 : io_channel = spdk_get_io_channel(&fs->io_target);
1918 : 3 : fs_channel = spdk_io_channel_get_ctx(io_channel);
1919 [ # # # # : 3 : fs_channel->bs_channel = spdk_bs_alloc_io_channel(fs->bs);
# # # # ]
1920 [ # # # # ]: 3 : fs_channel->send_request = __send_request_direct;
1921 : :
1922 : 3 : return io_channel;
1923 : : }
1924 : :
1925 : : void
1926 : 149 : spdk_fs_free_io_channel(struct spdk_io_channel *channel)
1927 : : {
1928 : 149 : spdk_put_io_channel(channel);
1929 : 149 : }
1930 : :
1931 : : struct spdk_fs_thread_ctx *
1932 : 239 : spdk_fs_alloc_thread_ctx(struct spdk_filesystem *fs)
1933 : : {
1934 : : struct spdk_fs_thread_ctx *ctx;
1935 : :
1936 : 239 : ctx = calloc(1, sizeof(*ctx));
1937 [ - + ]: 239 : if (!ctx) {
1938 : 0 : return NULL;
1939 : : }
1940 : :
1941 [ - + - + : 239 : if (pthread_spin_init(&ctx->ch.lock, 0)) {
# # # # ]
1942 : 0 : free(ctx);
1943 : 0 : return NULL;
1944 : : }
1945 : :
1946 [ # # ]: 239 : fs_channel_create(fs, &ctx->ch, 512);
1947 : :
1948 [ # # # # : 239 : ctx->ch.send_request = fs->send_request;
# # # # #
# ]
1949 [ # # # # : 239 : ctx->ch.sync = 1;
# # ]
1950 : :
1951 : 239 : return ctx;
1952 : 0 : }
1953 : :
1954 : :
1955 : : void
1956 : 239 : spdk_fs_free_thread_ctx(struct spdk_fs_thread_ctx *ctx)
1957 : : {
1958 [ - + + + : 239 : assert(ctx->ch.sync == 1);
# # # # #
# # # ]
1959 : :
1960 : 0 : while (true) {
1961 [ - + # # : 239 : pthread_spin_lock(&ctx->ch.lock);
# # ]
1962 [ + - # # : 239 : if (ctx->ch.outstanding_reqs == 0) {
# # # # ]
1963 [ - + # # : 239 : pthread_spin_unlock(&ctx->ch.lock);
# # ]
1964 : 239 : break;
1965 : : }
1966 [ # # # # : 0 : pthread_spin_unlock(&ctx->ch.lock);
# # ]
1967 : 0 : usleep(1000);
1968 : : }
1969 : :
1970 [ # # ]: 239 : fs_channel_destroy(NULL, &ctx->ch);
1971 : 239 : free(ctx);
1972 : 239 : }
1973 : :
1974 : : int
1975 : 12 : spdk_fs_set_cache_size(uint64_t size_in_mb)
1976 : : {
1977 : : /* setting g_fs_cache_size is only permitted if cache pool
1978 : : * is already freed or hasn't been initialized
1979 : : */
1980 [ - + ]: 12 : if (g_cache_pool != NULL) {
1981 : 0 : return -EPERM;
1982 : : }
1983 : :
1984 : 12 : g_fs_cache_size = size_in_mb * 1024 * 1024;
1985 : :
1986 : 12 : return 0;
1987 : 0 : }
1988 : :
1989 : : uint64_t
1990 : 0 : spdk_fs_get_cache_size(void)
1991 : : {
1992 [ # # ]: 0 : return g_fs_cache_size / (1024 * 1024);
1993 : : }
1994 : :
1995 : : static void __file_flush(void *ctx);
1996 : :
1997 : : /* Try to free some cache buffers from this file.
1998 : : */
1999 : : static int
2000 : 6671 : reclaim_cache_buffers(struct spdk_file *file)
2001 : : {
2002 : : int rc;
2003 : :
2004 [ - + - + : 6671 : BLOBFS_TRACE(file, "free=%s\n", file->name);
# # # # #
# # # #
# ]
2005 : :
2006 : : /* The function is safe to be called with any threads, while the file
2007 : : * lock maybe locked by other thread for now, so try to get the file
2008 : : * lock here.
2009 : : */
2010 [ - + # # ]: 6671 : rc = pthread_spin_trylock(&file->lock);
2011 [ + + ]: 6671 : if (rc != 0) {
2012 : 14 : return -1;
2013 : : }
2014 : :
2015 [ - + # # : 6657 : if (file->tree->present_mask == 0) {
# # # # #
# ]
2016 [ # # # # ]: 0 : pthread_spin_unlock(&file->lock);
2017 : 0 : return -1;
2018 : : }
2019 [ # # # # ]: 6657 : tree_free_buffers(file->tree);
2020 : :
2021 [ + - # # : 6657 : TAILQ_REMOVE(&g_caches, file, cache_tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
2022 : : /* If not freed, put it in the end of the queue */
2023 [ + + # # : 6657 : if (file->tree->present_mask != 0) {
# # # # #
# ]
2024 [ # # # # : 12 : TAILQ_INSERT_TAIL(&g_caches, file, cache_tailq);
# # # # #
# # # # #
# # # # #
# # # #
# ]
2025 : 0 : } else {
2026 [ # # # # ]: 6645 : file->last = NULL;
2027 : : }
2028 [ - + # # ]: 6657 : pthread_spin_unlock(&file->lock);
2029 : :
2030 : 6657 : return 0;
2031 : 0 : }
2032 : :
2033 : : static int
2034 : 502845 : _blobfs_cache_pool_reclaim(void *arg)
2035 : : {
2036 : : struct spdk_file *file, *tmp;
2037 : : int rc;
2038 : :
2039 [ + + ]: 502845 : if (!blobfs_cache_pool_need_reclaim()) {
2040 : 498113 : return SPDK_POLLER_IDLE;
2041 : : }
2042 : :
2043 [ + - # # : 31392 : TAILQ_FOREACH_SAFE(file, &g_caches, cache_tailq, tmp) {
# # # # #
# ]
2044 [ - + + + : 31392 : if (!file->open_for_writing &&
# # # # #
# ]
2045 [ + - # # ]: 4744 : file->priority == SPDK_FILE_PRIORITY_LOW) {
2046 : 4744 : rc = reclaim_cache_buffers(file);
2047 [ + + ]: 4744 : if (rc < 0) {
2048 : 12 : continue;
2049 : : }
2050 [ + + ]: 4732 : if (!blobfs_cache_pool_need_reclaim()) {
2051 : 3381 : return SPDK_POLLER_BUSY;
2052 : : }
2053 : 1351 : break;
2054 : : }
2055 : 0 : }
2056 : :
2057 [ + - # # : 7973 : TAILQ_FOREACH_SAFE(file, &g_caches, cache_tailq, tmp) {
# # # # #
# ]
2058 [ - + + + : 7973 : if (!file->open_for_writing) {
# # # # ]
2059 : 1352 : rc = reclaim_cache_buffers(file);
2060 [ + + ]: 1352 : if (rc < 0) {
2061 : 1 : continue;
2062 : : }
2063 [ + + ]: 1351 : if (!blobfs_cache_pool_need_reclaim()) {
2064 : 777 : return SPDK_POLLER_BUSY;
2065 : : }
2066 : 574 : break;
2067 : : }
2068 : 0 : }
2069 : :
2070 [ + - # # : 575 : TAILQ_FOREACH_SAFE(file, &g_caches, cache_tailq, tmp) {
# # # # #
# ]
2071 : 575 : rc = reclaim_cache_buffers(file);
2072 [ + + ]: 575 : if (rc < 0) {
2073 : 1 : continue;
2074 : : }
2075 : 574 : break;
2076 : : }
2077 : :
2078 : 574 : return SPDK_POLLER_BUSY;
2079 : 0 : }
2080 : :
2081 : : static void
2082 : 7683 : _add_file_to_cache_pool(void *ctx)
2083 : : {
2084 : 7683 : struct spdk_file *file = ctx;
2085 : :
2086 [ # # # # : 7683 : TAILQ_INSERT_TAIL(&g_caches, file, cache_tailq);
# # # # #
# # # # #
# # # # #
# # # #
# ]
2087 : 7683 : }
2088 : :
2089 : : static void
2090 : 163 : _remove_file_from_cache_pool(void *ctx)
2091 : : {
2092 : 163 : struct spdk_file *file = ctx;
2093 : :
2094 [ + + # # : 163 : TAILQ_REMOVE(&g_caches, file, cache_tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
2095 : 163 : }
2096 : :
2097 : : static struct cache_buffer *
2098 : 1047988 : cache_insert_buffer(struct spdk_file *file, uint64_t offset)
2099 : : {
2100 : : struct cache_buffer *buf;
2101 : 1047988 : int count = 0;
2102 : 1047988 : bool need_update = false;
2103 : :
2104 : 1047988 : buf = calloc(1, sizeof(*buf));
2105 [ + + ]: 1047988 : if (buf == NULL) {
2106 [ # # # # : 0 : SPDK_DEBUGLOG(blobfs, "calloc failed\n");
# # ]
2107 : 0 : return NULL;
2108 : : }
2109 : :
2110 : 0 : do {
2111 [ # # # # ]: 1047988 : buf->buf = spdk_mempool_get(g_cache_pool);
2112 [ + - # # : 1047988 : if (buf->buf) {
# # ]
2113 : 1047988 : break;
2114 : : }
2115 [ # # # # ]: 0 : if (count++ == 100) {
2116 : 0 : SPDK_ERRLOG("Could not allocate cache buffer for file=%p on offset=%jx\n",
2117 : : file, offset);
2118 : 0 : free(buf);
2119 : 0 : return NULL;
2120 : : }
2121 : 0 : usleep(BLOBFS_CACHE_POOL_POLL_PERIOD_IN_US);
2122 [ # # ]: 0 : } while (true);
2123 : :
2124 [ # # # # : 1047988 : buf->buf_size = CACHE_BUFFER_SIZE;
# # ]
2125 [ # # # # ]: 1047988 : buf->offset = offset;
2126 : :
2127 [ + + # # : 1047988 : if (file->tree->present_mask == 0) {
# # # # #
# ]
2128 : 7683 : need_update = true;
2129 : 0 : }
2130 [ # # # # : 1047988 : file->tree = tree_insert_buffer(file->tree, buf);
# # # # ]
2131 : :
2132 [ + + # # ]: 1047988 : if (need_update) {
2133 : 7683 : spdk_thread_send_msg(g_cache_pool_thread, _add_file_to_cache_pool, file);
2134 : 0 : }
2135 : :
2136 : 1047988 : return buf;
2137 : 0 : }
2138 : :
2139 : : static struct cache_buffer *
2140 : 796079 : cache_append_buffer(struct spdk_file *file)
2141 : : {
2142 : : struct cache_buffer *last;
2143 : :
2144 [ + + - + : 796079 : assert(file->last == NULL || file->last->bytes_filled == file->last->buf_size);
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
2145 [ - + # # : 796079 : assert((file->append_pos % CACHE_BUFFER_SIZE) == 0);
# # # # #
# # # ]
2146 : :
2147 [ # # # # ]: 796079 : last = cache_insert_buffer(file, file->append_pos);
2148 [ - + ]: 796079 : if (last == NULL) {
2149 [ # # # # : 0 : SPDK_DEBUGLOG(blobfs, "cache_insert_buffer failed\n");
# # ]
2150 : 0 : return NULL;
2151 : : }
2152 : :
2153 [ # # # # ]: 796079 : file->last = last;
2154 : :
2155 : 796079 : return last;
2156 : 0 : }
2157 : :
2158 : : static void __check_sync_reqs(struct spdk_file *file);
2159 : :
2160 : : static void
2161 : 304087 : __file_cache_finish_sync(void *ctx, int bserrno)
2162 : : {
2163 : : struct spdk_file *file;
2164 : 304087 : struct spdk_fs_request *sync_req = ctx;
2165 : : struct spdk_fs_cb_args *sync_args;
2166 : :
2167 [ # # ]: 304087 : sync_args = &sync_req->args;
2168 [ # # # # ]: 304087 : file = sync_args->file;
2169 [ - + # # ]: 304087 : pthread_spin_lock(&file->lock);
2170 [ # # # # : 304087 : file->length_xattr = sync_args->op.sync.length;
# # # # #
# # # ]
2171 [ - + # # : 304087 : assert(sync_args->op.sync.offset <= file->length_flushed);
# # # # #
# # # # #
# # ]
2172 [ + + + + : 304087 : spdk_trace_record(TRACE_BLOBFS_XATTR_END, 0, sync_args->op.sync.offset,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
2173 : : 0, file->name);
2174 [ - + - + : 304087 : BLOBFS_TRACE(file, "sync done offset=%jx\n", sync_args->op.sync.offset);
# # # # #
# # # # #
# # # # ]
2175 [ - + # # : 304087 : TAILQ_REMOVE(&file->sync_requests, sync_req, args.op.sync.tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
2176 [ - + # # ]: 304087 : pthread_spin_unlock(&file->lock);
2177 : :
2178 [ # # # # : 304087 : sync_args->fn.file_op(sync_args->arg, bserrno);
# # # # #
# # # #
# ]
2179 : :
2180 : 304087 : free_fs_request(sync_req);
2181 : 304087 : __check_sync_reqs(file);
2182 : 304087 : }
2183 : :
2184 : : static void
2185 : 1675875 : __check_sync_reqs(struct spdk_file *file)
2186 : : {
2187 : : struct spdk_fs_request *sync_req;
2188 : :
2189 [ - + # # ]: 1675875 : pthread_spin_lock(&file->lock);
2190 : :
2191 [ + + # # : 1698257 : TAILQ_FOREACH(sync_req, &file->sync_requests, args.op.sync.tailq) {
# # # # #
# # # # #
# # # # #
# ]
2192 [ + + # # : 600742 : if (sync_req->args.op.sync.offset <= file->length_flushed) {
# # # # #
# # # # #
# # ]
2193 : 578360 : break;
2194 : : }
2195 : 0 : }
2196 : :
2197 [ + + + + : 1675875 : if (sync_req != NULL && !sync_req->args.op.sync.xattr_in_progress) {
+ + # # #
# # # # #
# # ]
2198 [ - + - + : 304087 : BLOBFS_TRACE(file, "set xattr length 0x%jx\n", file->length_flushed);
# # # # #
# # # #
# ]
2199 [ # # # # : 304087 : sync_req->args.op.sync.xattr_in_progress = true;
# # # # #
# ]
2200 [ # # # # : 304087 : sync_req->args.op.sync.length = file->length_flushed;
# # # # #
# # # #
# ]
2201 [ # # # # : 304087 : spdk_blob_set_xattr(file->blob, "length", &file->length_flushed,
# # ]
2202 : : sizeof(file->length_flushed));
2203 : :
2204 [ - + # # ]: 304087 : pthread_spin_unlock(&file->lock);
2205 [ + + + + : 304087 : spdk_trace_record(TRACE_BLOBFS_XATTR_START, 0, file->length_flushed,
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
2206 : : 0, file->name);
2207 [ # # # # ]: 304087 : spdk_blob_sync_md(file->blob, __file_cache_finish_sync, sync_req);
2208 : 0 : } else {
2209 [ - + # # ]: 1371788 : pthread_spin_unlock(&file->lock);
2210 : : }
2211 : 1675875 : }
2212 : :
2213 : : static void
2214 : 1067699 : __file_flush_done(void *ctx, int bserrno)
2215 : : {
2216 : 1067699 : struct spdk_fs_request *req = ctx;
2217 [ # # ]: 1067699 : struct spdk_fs_cb_args *args = &req->args;
2218 [ # # # # ]: 1067699 : struct spdk_file *file = args->file;
2219 [ # # # # : 1067699 : struct cache_buffer *next = args->op.flush.cache_buffer;
# # # # ]
2220 : :
2221 [ - + - + : 1067699 : BLOBFS_TRACE(file, "length=%jx\n", args->op.flush.length);
# # # # #
# # # # #
# # # # ]
2222 : :
2223 [ - + # # ]: 1067699 : pthread_spin_lock(&file->lock);
2224 [ # # # # ]: 1067699 : next->in_progress = false;
2225 [ # # # # : 1067699 : next->bytes_flushed += args->op.flush.length;
# # # # #
# # # ]
2226 [ # # # # : 1067699 : file->length_flushed += args->op.flush.length;
# # # # #
# # # ]
2227 [ - + # # : 1067699 : if (file->length_flushed > file->length) {
# # # # #
# ]
2228 [ # # # # : 0 : file->length = file->length_flushed;
# # # # ]
2229 : 0 : }
2230 [ + + # # : 1067699 : if (next->bytes_flushed == next->buf_size) {
# # # # #
# ]
2231 [ - + - + : 793428 : BLOBFS_TRACE(file, "write buffer fully flushed 0x%jx\n", file->length_flushed);
# # # # #
# # # #
# ]
2232 [ # # # # : 793428 : next = tree_find_buffer(file->tree, file->length_flushed);
# # # # ]
2233 : 0 : }
2234 : :
2235 : : /*
2236 : : * Assert that there is no cached data that extends past the end of the underlying
2237 : : * blob.
2238 : : */
2239 [ + - - + : 1067699 : assert(next == NULL || next->offset < __file_get_blob_size(file) ||
- - # # #
# # # # #
# # ]
2240 : : next->bytes_filled == 0);
2241 : :
2242 [ - + # # ]: 1067699 : pthread_spin_unlock(&file->lock);
2243 : :
2244 : 1067699 : __check_sync_reqs(file);
2245 : :
2246 : 1067699 : __file_flush(req);
2247 : 1067699 : }
2248 : :
2249 : : static void
2250 : 1573554 : __file_flush(void *ctx)
2251 : : {
2252 : 1573554 : struct spdk_fs_request *req = ctx;
2253 [ # # ]: 1573554 : struct spdk_fs_cb_args *args = &req->args;
2254 [ # # # # ]: 1573554 : struct spdk_file *file = args->file;
2255 : : struct cache_buffer *next;
2256 : 1573554 : uint64_t offset, length, start_lba, num_lba;
2257 : 1573554 : uint32_t lba_size;
2258 : :
2259 [ - + # # ]: 1573554 : pthread_spin_lock(&file->lock);
2260 [ # # # # : 1573554 : next = tree_find_buffer(file->tree, file->length_flushed);
# # # # ]
2261 [ + + + + : 1573554 : if (next == NULL || next->in_progress ||
+ + # # #
# # # ]
2262 [ + + + + : 1536573 : ((next->bytes_filled < next->buf_size) && TAILQ_EMPTY(&file->sync_requests))) {
# # # # #
# # # # #
# # ]
2263 : : /*
2264 : : * There is either no data to flush, a flush I/O is already in
2265 : : * progress, or the next buffer is partially filled but there's no
2266 : : * outstanding request to sync it.
2267 : : * So return immediately - if a flush I/O is in progress we will flush
2268 : : * more data after that is completed, or a partial buffer will get flushed
2269 : : * when it is either filled or the file is synced.
2270 : : */
2271 : 231579 : free_fs_request(req);
2272 [ + + ]: 231579 : if (next == NULL) {
2273 : : /*
2274 : : * For cases where a file's cache was evicted, and then the
2275 : : * file was later appended, we will write the data directly
2276 : : * to disk and bypass cache. So just update length_flushed
2277 : : * here to reflect that all data was already written to disk.
2278 : : */
2279 [ # # # # : 29813 : file->length_flushed = file->append_pos;
# # # # ]
2280 : 0 : }
2281 [ - + # # ]: 231579 : pthread_spin_unlock(&file->lock);
2282 [ + + ]: 231579 : if (next == NULL) {
2283 : : /*
2284 : : * There is no data to flush, but we still need to check for any
2285 : : * outstanding sync requests to make sure metadata gets updated.
2286 : : */
2287 : 29813 : __check_sync_reqs(file);
2288 : 0 : }
2289 : 231579 : return;
2290 : : }
2291 : :
2292 [ # # # # : 1341975 : offset = next->offset + next->bytes_flushed;
# # # # ]
2293 [ # # # # : 1341975 : length = next->bytes_filled - next->bytes_flushed;
# # # # ]
2294 [ + + ]: 1341975 : if (length == 0) {
2295 : 274276 : free_fs_request(req);
2296 [ - + # # ]: 274276 : pthread_spin_unlock(&file->lock);
2297 : : /*
2298 : : * There is no data to flush, but we still need to check for any
2299 : : * outstanding sync requests to make sure metadata gets updated.
2300 : : */
2301 : 274276 : __check_sync_reqs(file);
2302 : 274276 : return;
2303 : : }
2304 [ # # # # : 1067699 : args->op.flush.length = length;
# # # # ]
2305 [ # # # # : 1067699 : args->op.flush.cache_buffer = next;
# # # # ]
2306 : :
2307 : 1067699 : __get_page_parameters(file, offset, length, &start_lba, &lba_size, &num_lba);
2308 : :
2309 [ # # # # ]: 1067699 : next->in_progress = true;
2310 [ - + - + : 1067699 : BLOBFS_TRACE(file, "offset=0x%jx length=0x%jx page start=0x%jx num=0x%jx\n",
# # # # #
# ]
2311 : : offset, length, start_lba, num_lba);
2312 [ - + # # ]: 1067699 : pthread_spin_unlock(&file->lock);
2313 [ # # # # : 1067699 : spdk_blob_io_write(file->blob, file->fs->sync_target.sync_fs_channel->bs_channel,
# # # # #
# # # # #
# # # # ]
2314 [ # # # # : 1067699 : next->buf + (start_lba * lba_size) - next->offset,
# # # # #
# # # ]
2315 : 0 : start_lba, num_lba, __file_flush_done, req);
2316 : 0 : }
2317 : :
2318 : : static void
2319 : 110840 : __file_extend_done(void *arg, int bserrno)
2320 : : {
2321 : 110840 : struct spdk_fs_cb_args *args = arg;
2322 : :
2323 : 110840 : __wake_caller(args, bserrno);
2324 : 110840 : }
2325 : :
2326 : : static void
2327 : 110840 : __file_extend_resize_cb(void *_args, int bserrno)
2328 : : {
2329 : 110840 : struct spdk_fs_cb_args *args = _args;
2330 [ # # # # ]: 110840 : struct spdk_file *file = args->file;
2331 : :
2332 [ - + ]: 110840 : if (bserrno) {
2333 : 0 : __wake_caller(args, bserrno);
2334 : 0 : return;
2335 : : }
2336 : :
2337 [ # # # # ]: 110840 : spdk_blob_sync_md(file->blob, __file_extend_done, args);
2338 : 0 : }
2339 : :
2340 : : static void
2341 : 110840 : __file_extend_blob(void *_args)
2342 : : {
2343 : 110840 : struct spdk_fs_cb_args *args = _args;
2344 [ # # # # ]: 110840 : struct spdk_file *file = args->file;
2345 : :
2346 [ # # # # : 110840 : spdk_blob_resize(file->blob, args->op.resize.num_clusters, __file_extend_resize_cb, args);
# # # # #
# # # ]
2347 : 110840 : }
2348 : :
2349 : : static void
2350 : 3477735 : __rw_from_file_done(void *ctx, int bserrno)
2351 : : {
2352 : 3477735 : struct spdk_fs_request *req = ctx;
2353 : :
2354 [ # # ]: 3477735 : __wake_caller(&req->args, bserrno);
2355 : 3477735 : free_fs_request(req);
2356 : 3477735 : }
2357 : :
2358 : : static void
2359 : 3477735 : __rw_from_file(void *ctx)
2360 : : {
2361 : 3477735 : struct spdk_fs_request *req = ctx;
2362 [ # # ]: 3477735 : struct spdk_fs_cb_args *args = &req->args;
2363 [ # # # # ]: 3477735 : struct spdk_file *file = args->file;
2364 : :
2365 [ + + # # : 3477735 : if (args->op.rw.is_read) {
# # # # #
# ]
2366 [ # # # # : 3446591 : spdk_file_read_async(file, file->fs->sync_target.sync_io_channel, args->iovs[0].iov_base,
# # # # #
# # # # #
# # # # #
# ]
2367 [ # # # # : 3446591 : args->op.rw.offset, (uint64_t)args->iovs[0].iov_len,
# # # # #
# # # # #
# # # # ]
2368 : 0 : __rw_from_file_done, req);
2369 : 0 : } else {
2370 [ # # # # : 31144 : spdk_file_write_async(file, file->fs->sync_target.sync_io_channel, args->iovs[0].iov_base,
# # # # #
# # # # #
# # # # #
# ]
2371 [ # # # # : 31144 : args->op.rw.offset, (uint64_t)args->iovs[0].iov_len,
# # # # #
# # # # #
# # # # ]
2372 : 0 : __rw_from_file_done, req);
2373 : : }
2374 : 3477735 : }
2375 : :
2376 : : struct rw_from_file_arg {
2377 : : struct spdk_fs_channel *channel;
2378 : : int rwerrno;
2379 : : };
2380 : :
2381 : : static int
2382 : 3477735 : __send_rw_from_file(struct spdk_file *file, void *payload,
2383 : : uint64_t offset, uint64_t length, bool is_read,
2384 : : struct rw_from_file_arg *arg)
2385 : : {
2386 : : struct spdk_fs_request *req;
2387 : : struct spdk_fs_cb_args *args;
2388 : :
2389 [ # # # # ]: 3477735 : req = alloc_fs_request_with_iov(arg->channel, 1);
2390 [ - + ]: 3477735 : if (req == NULL) {
2391 [ # # # # : 0 : sem_post(&arg->channel->sem);
# # # # ]
2392 : 0 : return -ENOMEM;
2393 : : }
2394 : :
2395 [ # # ]: 3477735 : args = &req->args;
2396 [ # # # # ]: 3477735 : args->file = file;
2397 [ # # # # : 3477735 : args->sem = &arg->channel->sem;
# # # # #
# ]
2398 [ # # # # : 3477735 : args->iovs[0].iov_base = payload;
# # # # #
# ]
2399 [ # # # # : 3477735 : args->iovs[0].iov_len = (size_t)length;
# # # # #
# ]
2400 [ # # # # : 3477735 : args->op.rw.offset = offset;
# # # # ]
2401 [ # # # # : 3477735 : args->op.rw.is_read = is_read;
# # # # #
# ]
2402 [ # # # # : 3477735 : args->rwerrno = &arg->rwerrno;
# # ]
2403 [ # # # # : 3477735 : file->fs->send_request(__rw_from_file, req);
# # # # #
# # # ]
2404 : 3477735 : return 0;
2405 : 0 : }
2406 : :
2407 : : int
2408 : 503722 : spdk_file_write(struct spdk_file *file, struct spdk_fs_thread_ctx *ctx,
2409 : : void *payload, uint64_t offset, uint64_t length)
2410 : : {
2411 : 503722 : struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
2412 : : struct spdk_fs_request *flush_req;
2413 : : uint64_t rem_length, copy, blob_size, cluster_sz;
2414 : 503722 : uint32_t cache_buffers_filled = 0;
2415 : : uint8_t *cur_payload;
2416 : : struct cache_buffer *last;
2417 : :
2418 [ - + - + : 503722 : BLOBFS_TRACE_RW(file, "offset=%jx length=%jx\n", offset, length);
# # # # #
# ]
2419 : :
2420 [ + + ]: 503722 : if (length == 0) {
2421 : 3 : return 0;
2422 : : }
2423 : :
2424 [ - + # # : 503719 : if (offset != file->append_pos) {
# # ]
2425 [ # # # # : 0 : BLOBFS_TRACE(file, " error offset=%jx append_pos=%jx\n", offset, file->append_pos);
# # # # #
# # # #
# ]
2426 : 0 : return -EINVAL;
2427 : : }
2428 : :
2429 [ - + # # ]: 503719 : pthread_spin_lock(&file->lock);
2430 [ # # # # ]: 503719 : file->open_for_writing = true;
2431 : :
2432 [ + + + + : 503719 : if ((file->last == NULL) && (file->append_pos % CACHE_BUFFER_SIZE == 0)) {
# # # # #
# # # # #
# # ]
2433 : 2651 : cache_append_buffer(file);
2434 : 0 : }
2435 : :
2436 [ + + # # : 503719 : if (file->last == NULL) {
# # ]
2437 : 31144 : struct rw_from_file_arg arg = {};
2438 : : int rc;
2439 : :
2440 : 31144 : arg.channel = channel;
2441 [ # # ]: 31144 : arg.rwerrno = 0;
2442 [ # # # # ]: 31144 : file->append_pos += length;
2443 [ - + # # ]: 31144 : pthread_spin_unlock(&file->lock);
2444 : 31144 : rc = __send_rw_from_file(file, payload, offset, length, false, &arg);
2445 [ - + ]: 31144 : if (rc != 0) {
2446 : 0 : return rc;
2447 : : }
2448 [ - + # # ]: 31144 : sem_wait(&channel->sem);
2449 [ # # ]: 31144 : return arg.rwerrno;
2450 : : }
2451 : :
2452 : 472575 : blob_size = __file_get_blob_size(file);
2453 : :
2454 [ + + ]: 472575 : if ((offset + length) > blob_size) {
2455 : 110840 : struct spdk_fs_cb_args extend_args = {};
2456 : :
2457 [ # # # # : 110840 : cluster_sz = file->fs->bs_opts.cluster_sz;
# # # # #
# ]
2458 [ # # # # ]: 110840 : extend_args.sem = &channel->sem;
2459 [ # # # # : 110840 : extend_args.op.resize.num_clusters = __bytes_to_clusters((offset + length), cluster_sz);
# # ]
2460 [ # # ]: 110840 : extend_args.file = file;
2461 [ - + - + : 110840 : BLOBFS_TRACE(file, "start resize to %u clusters\n", extend_args.op.resize.num_clusters);
# # # # #
# # # # #
# # ]
2462 [ - + # # ]: 110840 : pthread_spin_unlock(&file->lock);
2463 [ # # # # : 110840 : file->fs->send_request(__file_extend_blob, &extend_args);
# # # # #
# # # ]
2464 [ - + # # ]: 110840 : sem_wait(&channel->sem);
2465 [ - + # # ]: 110840 : if (extend_args.rc) {
2466 [ # # ]: 0 : return extend_args.rc;
2467 : : }
2468 [ - + # # ]: 110840 : pthread_spin_lock(&file->lock);
2469 : 0 : }
2470 : :
2471 : 472575 : flush_req = alloc_fs_request(channel);
2472 [ - + ]: 472575 : if (flush_req == NULL) {
2473 [ # # # # ]: 0 : pthread_spin_unlock(&file->lock);
2474 : 0 : return -ENOMEM;
2475 : : }
2476 : :
2477 [ # # # # ]: 472575 : last = file->last;
2478 : 472575 : rem_length = length;
2479 : 472575 : cur_payload = payload;
2480 [ + + ]: 1738575 : while (rem_length > 0) {
2481 [ # # # # : 1266000 : copy = last->buf_size - last->bytes_filled;
# # # # ]
2482 [ + + ]: 1266000 : if (copy > rem_length) {
2483 : 472572 : copy = rem_length;
2484 : 0 : }
2485 [ - + - + : 1266000 : BLOBFS_TRACE_RW(file, " fill offset=%jx length=%jx\n", file->append_pos, copy);
# # # # #
# # # #
# ]
2486 [ - + - + : 1266000 : memcpy(&last->buf[last->bytes_filled], cur_payload, copy);
# # # # #
# # # #
# ]
2487 [ # # # # ]: 1266000 : file->append_pos += copy;
2488 [ + + # # : 1266000 : if (file->length < file->append_pos) {
# # # # #
# ]
2489 [ # # # # : 560585 : file->length = file->append_pos;
# # # # ]
2490 : 0 : }
2491 [ # # ]: 1266000 : cur_payload += copy;
2492 [ # # # # ]: 1266000 : last->bytes_filled += copy;
2493 : 1266000 : rem_length -= copy;
2494 [ + + # # : 1266000 : if (last->bytes_filled == last->buf_size) {
# # # # #
# ]
2495 : 793428 : cache_buffers_filled++;
2496 : 793428 : last = cache_append_buffer(file);
2497 [ - + ]: 793428 : if (last == NULL) {
2498 [ # # # # : 0 : BLOBFS_TRACE(file, "nomem\n");
# # # # #
# ]
2499 : 0 : free_fs_request(flush_req);
2500 [ # # # # ]: 0 : pthread_spin_unlock(&file->lock);
2501 : 0 : return -ENOMEM;
2502 : : }
2503 : 0 : }
2504 : : }
2505 : :
2506 [ - + # # ]: 472575 : pthread_spin_unlock(&file->lock);
2507 : :
2508 [ + + ]: 472575 : if (cache_buffers_filled == 0) {
2509 : 270807 : free_fs_request(flush_req);
2510 : 270807 : return 0;
2511 : : }
2512 : :
2513 [ # # # # : 201768 : flush_req->args.file = file;
# # ]
2514 [ # # # # : 201768 : file->fs->send_request(__file_flush, flush_req);
# # # # #
# # # ]
2515 : 201768 : return 0;
2516 : 0 : }
2517 : :
2518 : : static void
2519 : 251909 : __readahead_done(void *ctx, int bserrno)
2520 : : {
2521 : 251909 : struct spdk_fs_request *req = ctx;
2522 [ # # ]: 251909 : struct spdk_fs_cb_args *args = &req->args;
2523 [ # # # # : 251909 : struct cache_buffer *cache_buffer = args->op.readahead.cache_buffer;
# # # # ]
2524 [ # # # # ]: 251909 : struct spdk_file *file = args->file;
2525 : :
2526 [ - + - + : 251909 : BLOBFS_TRACE(file, "offset=%jx\n", cache_buffer->offset);
# # # # #
# # # #
# ]
2527 : :
2528 [ - + # # ]: 251909 : pthread_spin_lock(&file->lock);
2529 [ # # # # : 251909 : cache_buffer->bytes_filled = args->op.readahead.length;
# # # # #
# # # ]
2530 [ # # # # : 251909 : cache_buffer->bytes_flushed = args->op.readahead.length;
# # # # #
# # # ]
2531 [ # # # # ]: 251909 : cache_buffer->in_progress = false;
2532 [ - + # # ]: 251909 : pthread_spin_unlock(&file->lock);
2533 : :
2534 : 251909 : free_fs_request(req);
2535 : 251909 : }
2536 : :
2537 : : static void
2538 : 251909 : __readahead(void *ctx)
2539 : : {
2540 : 251909 : struct spdk_fs_request *req = ctx;
2541 [ # # ]: 251909 : struct spdk_fs_cb_args *args = &req->args;
2542 [ # # # # ]: 251909 : struct spdk_file *file = args->file;
2543 : 251909 : uint64_t offset, length, start_lba, num_lba;
2544 : 251909 : uint32_t lba_size;
2545 : :
2546 [ # # # # : 251909 : offset = args->op.readahead.offset;
# # # # ]
2547 [ # # # # : 251909 : length = args->op.readahead.length;
# # # # ]
2548 [ - + # # ]: 251909 : assert(length > 0);
2549 : :
2550 : 251909 : __get_page_parameters(file, offset, length, &start_lba, &lba_size, &num_lba);
2551 : :
2552 [ - + - + : 251909 : BLOBFS_TRACE(file, "offset=%jx length=%jx page start=%jx num=%jx\n",
# # # # #
# ]
2553 : : offset, length, start_lba, num_lba);
2554 [ # # # # : 251909 : spdk_blob_io_read(file->blob, file->fs->sync_target.sync_fs_channel->bs_channel,
# # # # #
# # # # #
# # # # ]
2555 [ # # # # : 251909 : args->op.readahead.cache_buffer->buf,
# # # # #
# # # ]
2556 : 0 : start_lba, num_lba, __readahead_done, req);
2557 : 251909 : }
2558 : :
2559 : : static uint64_t
2560 : 43496456 : __next_cache_buffer_offset(uint64_t offset)
2561 : : {
2562 [ # # # # ]: 43496456 : return (offset + CACHE_BUFFER_SIZE) & ~(CACHE_TREE_LEVEL_MASK(0));
2563 : : }
2564 : :
2565 : : static void
2566 : 43496456 : check_readahead(struct spdk_file *file, uint64_t offset,
2567 : : struct spdk_fs_channel *channel)
2568 : : {
2569 : : struct spdk_fs_request *req;
2570 : : struct spdk_fs_cb_args *args;
2571 : :
2572 : 43496456 : offset = __next_cache_buffer_offset(offset);
2573 [ + + + + : 43496456 : if (tree_find_buffer(file->tree, offset) != NULL || file->length <= offset) {
# # # # #
# # # ]
2574 : 43244547 : return;
2575 : : }
2576 : :
2577 : 251909 : req = alloc_fs_request(channel);
2578 [ - + ]: 251909 : if (req == NULL) {
2579 : 0 : return;
2580 : : }
2581 [ # # ]: 251909 : args = &req->args;
2582 : :
2583 [ - + - + : 251909 : BLOBFS_TRACE(file, "offset=%jx\n", offset);
# # # # #
# ]
2584 : :
2585 [ # # # # ]: 251909 : args->file = file;
2586 [ # # # # : 251909 : args->op.readahead.offset = offset;
# # # # ]
2587 [ # # # # : 251909 : args->op.readahead.cache_buffer = cache_insert_buffer(file, offset);
# # # # ]
2588 [ - + # # : 251909 : if (!args->op.readahead.cache_buffer) {
# # # # #
# ]
2589 [ # # # # : 0 : BLOBFS_TRACE(file, "Cannot allocate buf for offset=%jx\n", offset);
# # # # #
# ]
2590 : 0 : free_fs_request(req);
2591 : 0 : return;
2592 : : }
2593 : :
2594 [ # # # # : 251909 : args->op.readahead.cache_buffer->in_progress = true;
# # # # #
# # # ]
2595 [ + + # # : 251909 : if (file->length < (offset + CACHE_BUFFER_SIZE)) {
# # # # ]
2596 [ # # # # : 3132 : args->op.readahead.length = file->length & (CACHE_BUFFER_SIZE - 1);
# # # # #
# # # #
# ]
2597 : 0 : } else {
2598 [ # # # # : 248777 : args->op.readahead.length = CACHE_BUFFER_SIZE;
# # # # #
# ]
2599 : : }
2600 [ # # # # : 251909 : file->fs->send_request(__readahead, req);
# # # # #
# # # ]
2601 : 0 : }
2602 : :
2603 : : int64_t
2604 : 25903504 : spdk_file_read(struct spdk_file *file, struct spdk_fs_thread_ctx *ctx,
2605 : : void *payload, uint64_t offset, uint64_t length)
2606 : : {
2607 : 25903504 : struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
2608 : : uint64_t final_offset, final_length;
2609 : 25903504 : uint32_t sub_reads = 0;
2610 : : struct cache_buffer *buf;
2611 : : uint64_t read_len;
2612 : 25903504 : struct rw_from_file_arg arg = {};
2613 : :
2614 [ - + # # ]: 25903504 : pthread_spin_lock(&file->lock);
2615 : :
2616 [ - + - + : 25903504 : BLOBFS_TRACE_RW(file, "offset=%ju length=%ju\n", offset, length);
# # # # #
# ]
2617 : :
2618 [ # # # # ]: 25903504 : file->open_for_writing = false;
2619 : :
2620 [ + - + + : 25903504 : if (length == 0 || offset >= file->append_pos) {
# # # # ]
2621 [ - + # # ]: 15 : pthread_spin_unlock(&file->lock);
2622 : 15 : return 0;
2623 : : }
2624 : :
2625 [ + + # # : 25903489 : if (offset + length > file->append_pos) {
# # ]
2626 [ # # # # ]: 25 : length = file->append_pos - offset;
2627 : 0 : }
2628 : :
2629 [ + + # # : 25903489 : if (offset != file->next_seq_offset) {
# # ]
2630 [ # # # # ]: 3333032 : file->seq_byte_count = 0;
2631 : 0 : }
2632 [ # # # # ]: 25903489 : file->seq_byte_count += length;
2633 [ # # # # ]: 25903489 : file->next_seq_offset = offset + length;
2634 [ + + # # : 25903489 : if (file->seq_byte_count >= CACHE_READAHEAD_THRESHOLD) {
# # ]
2635 : 21748228 : check_readahead(file, offset, channel);
2636 [ # # ]: 21748228 : check_readahead(file, offset + CACHE_BUFFER_SIZE, channel);
2637 : 0 : }
2638 : :
2639 : 25903489 : arg.channel = channel;
2640 [ # # ]: 25903489 : arg.rwerrno = 0;
2641 : 25903489 : final_length = 0;
2642 : 25903489 : final_offset = offset + length;
2643 [ + + ]: 52215191 : while (offset < final_offset) {
2644 : 26311702 : int ret = 0;
2645 [ # # # # : 26311702 : length = NEXT_CACHE_BUFFER_OFFSET(offset) - offset;
# # ]
2646 [ + + ]: 26311702 : if (length > (final_offset - offset)) {
2647 : 25898020 : length = final_offset - offset;
2648 : 0 : }
2649 : :
2650 [ # # # # ]: 26311702 : buf = tree_find_filled_buffer(file->tree, offset);
2651 [ + + ]: 26311702 : if (buf == NULL) {
2652 [ - + # # ]: 3446591 : pthread_spin_unlock(&file->lock);
2653 : 3446591 : ret = __send_rw_from_file(file, payload, offset, length, true, &arg);
2654 [ - + # # ]: 3446591 : pthread_spin_lock(&file->lock);
2655 [ + - ]: 3446591 : if (ret == 0) {
2656 : 3446591 : sub_reads++;
2657 : 0 : }
2658 : 0 : } else {
2659 : 22865111 : read_len = length;
2660 [ - + # # : 22865111 : if ((offset + length) > (buf->offset + buf->bytes_filled)) {
# # # # #
# ]
2661 [ # # # # : 0 : read_len = buf->offset + buf->bytes_filled - offset;
# # # # ]
2662 : 0 : }
2663 [ - + - + : 22865111 : BLOBFS_TRACE(file, "read %p offset=%ju length=%ju\n", payload, offset, read_len);
# # # # #
# ]
2664 [ - + - + : 22865111 : memcpy(payload, &buf->buf[offset - buf->offset], read_len);
# # # # #
# # # #
# ]
2665 [ + + # # : 22865111 : if ((offset + read_len) % CACHE_BUFFER_SIZE == 0) {
# # ]
2666 [ # # # # ]: 355759 : tree_remove_buffer(file->tree, buf);
2667 [ + + # # : 355759 : if (file->tree->present_mask == 0) {
# # # # #
# ]
2668 : 163 : spdk_thread_send_msg(g_cache_pool_thread, _remove_file_from_cache_pool, file);
2669 : 0 : }
2670 : 0 : }
2671 : : }
2672 : :
2673 [ + - ]: 26311702 : if (ret == 0) {
2674 : 26311702 : final_length += length;
2675 : 0 : } else {
2676 [ # # ]: 0 : arg.rwerrno = ret;
2677 : 0 : break;
2678 : : }
2679 : 26311702 : payload += length;
2680 : 26311702 : offset += length;
2681 : : }
2682 [ - + # # ]: 25903489 : pthread_spin_unlock(&file->lock);
2683 [ + + ]: 29350080 : while (sub_reads > 0) {
2684 [ - + # # ]: 3446591 : sem_wait(&channel->sem);
2685 : 3446591 : sub_reads--;
2686 : : }
2687 [ + - # # ]: 25903489 : if (arg.rwerrno == 0) {
2688 : 25903489 : return final_length;
2689 : : } else {
2690 [ # # ]: 0 : return arg.rwerrno;
2691 : : }
2692 : 0 : }
2693 : :
2694 : : static void
2695 : 319750 : _file_sync(struct spdk_file *file, struct spdk_fs_channel *channel,
2696 : : spdk_file_op_complete cb_fn, void *cb_arg)
2697 : : {
2698 : : struct spdk_fs_request *sync_req;
2699 : : struct spdk_fs_request *flush_req;
2700 : : struct spdk_fs_cb_args *sync_args;
2701 : : struct spdk_fs_cb_args *flush_args;
2702 : :
2703 [ - + - + : 319750 : BLOBFS_TRACE(file, "offset=%jx\n", file->append_pos);
# # # # #
# # # #
# ]
2704 : :
2705 [ - + # # ]: 319750 : pthread_spin_lock(&file->lock);
2706 [ + + # # : 319750 : if (file->append_pos <= file->length_xattr) {
# # # # #
# ]
2707 [ - + - + : 15663 : BLOBFS_TRACE(file, "done - file already synced\n");
# # # # #
# ]
2708 [ - + # # ]: 15663 : pthread_spin_unlock(&file->lock);
2709 [ # # # # ]: 15663 : cb_fn(cb_arg, 0);
2710 : 15663 : return;
2711 : : }
2712 : :
2713 : 304087 : sync_req = alloc_fs_request(channel);
2714 [ - + ]: 304087 : if (!sync_req) {
2715 [ # # # # ]: 0 : SPDK_ERRLOG("Cannot allocate sync req for file=%s\n", file->name);
2716 [ # # # # ]: 0 : pthread_spin_unlock(&file->lock);
2717 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
2718 : 0 : return;
2719 : : }
2720 [ # # ]: 304087 : sync_args = &sync_req->args;
2721 : :
2722 : 304087 : flush_req = alloc_fs_request(channel);
2723 [ - + ]: 304087 : if (!flush_req) {
2724 [ # # # # ]: 0 : SPDK_ERRLOG("Cannot allocate flush req for file=%s\n", file->name);
2725 : 0 : free_fs_request(sync_req);
2726 [ # # # # ]: 0 : pthread_spin_unlock(&file->lock);
2727 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
2728 : 0 : return;
2729 : : }
2730 [ # # ]: 304087 : flush_args = &flush_req->args;
2731 : :
2732 [ # # # # ]: 304087 : sync_args->file = file;
2733 [ # # # # : 304087 : sync_args->fn.file_op = cb_fn;
# # ]
2734 [ # # # # ]: 304087 : sync_args->arg = cb_arg;
2735 [ # # # # : 304087 : sync_args->op.sync.offset = file->append_pos;
# # # # #
# # # ]
2736 [ # # # # : 304087 : sync_args->op.sync.xattr_in_progress = false;
# # # # ]
2737 [ # # # # : 304087 : TAILQ_INSERT_TAIL(&file->sync_requests, sync_req, args.op.sync.tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
2738 [ - + # # ]: 304087 : pthread_spin_unlock(&file->lock);
2739 : :
2740 [ # # # # ]: 304087 : flush_args->file = file;
2741 [ # # # # : 304087 : channel->send_request(__file_flush, flush_req);
# # # # ]
2742 : 0 : }
2743 : :
2744 : : int
2745 : 319732 : spdk_file_sync(struct spdk_file *file, struct spdk_fs_thread_ctx *ctx)
2746 : : {
2747 : 319732 : struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
2748 : 319732 : struct spdk_fs_cb_args args = {};
2749 : :
2750 [ # # # # ]: 319732 : args.sem = &channel->sem;
2751 : 319732 : _file_sync(file, channel, __wake_caller, &args);
2752 [ - + # # ]: 319732 : sem_wait(&channel->sem);
2753 : :
2754 [ # # ]: 319732 : return args.rc;
2755 : : }
2756 : :
2757 : : void
2758 : 18 : spdk_file_sync_async(struct spdk_file *file, struct spdk_io_channel *_channel,
2759 : : spdk_file_op_complete cb_fn, void *cb_arg)
2760 : : {
2761 : 18 : struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel);
2762 : :
2763 : 18 : _file_sync(file, channel, cb_fn, cb_arg);
2764 : 18 : }
2765 : :
2766 : : void
2767 : 0 : spdk_file_set_priority(struct spdk_file *file, uint32_t priority)
2768 : : {
2769 [ # # # # : 0 : BLOBFS_TRACE(file, "priority=%u\n", priority);
# # # # #
# ]
2770 [ # # # # ]: 0 : file->priority = priority;
2771 : :
2772 : 0 : }
2773 : :
2774 : : /*
2775 : : * Close routines
2776 : : */
2777 : :
2778 : : static void
2779 : 15702 : __file_close_async_done(void *ctx, int bserrno)
2780 : : {
2781 : 15702 : struct spdk_fs_request *req = ctx;
2782 [ # # ]: 15702 : struct spdk_fs_cb_args *args = &req->args;
2783 [ # # # # ]: 15702 : struct spdk_file *file = args->file;
2784 : :
2785 [ + + + + : 15702 : spdk_trace_record(TRACE_BLOBFS_CLOSE, 0, 0, 0, file->name);
# # # # #
# # # # #
# # # # #
# # # ]
2786 : :
2787 [ + + + + : 15702 : if (file->is_deleted) {
# # # # ]
2788 [ # # # # : 6 : spdk_fs_delete_file_async(file->fs, file->name, blob_delete_cb, ctx);
# # # # ]
2789 : 6 : return;
2790 : : }
2791 : :
2792 [ # # # # : 15696 : args->fn.file_op(args->arg, bserrno);
# # # # #
# # # #
# ]
2793 : 15696 : free_fs_request(req);
2794 : 0 : }
2795 : :
2796 : : static void
2797 : 15702 : __file_close_async(struct spdk_file *file, struct spdk_fs_request *req)
2798 : : {
2799 : : struct spdk_blob *blob;
2800 : :
2801 [ - + # # ]: 15702 : pthread_spin_lock(&file->lock);
2802 [ + + # # : 15702 : if (file->ref_count == 0) {
# # ]
2803 [ - + # # ]: 6786 : pthread_spin_unlock(&file->lock);
2804 : 6786 : __file_close_async_done(req, -EBADF);
2805 : 6786 : return;
2806 : : }
2807 : :
2808 [ # # ]: 8916 : file->ref_count--;
2809 [ - + # # : 8916 : if (file->ref_count > 0) {
# # ]
2810 [ # # # # ]: 0 : pthread_spin_unlock(&file->lock);
2811 [ # # # # : 0 : req->args.fn.file_op(req->args.arg, 0);
# # # # #
# # # # #
# # # # ]
2812 : 0 : free_fs_request(req);
2813 : 0 : return;
2814 : : }
2815 : :
2816 [ - + # # ]: 8916 : pthread_spin_unlock(&file->lock);
2817 : :
2818 [ # # # # ]: 8916 : blob = file->blob;
2819 [ # # # # ]: 8916 : file->blob = NULL;
2820 : 8916 : spdk_blob_close(blob, __file_close_async_done, req);
2821 : 0 : }
2822 : :
2823 : : static void
2824 : 18 : __file_close_async__sync_done(void *arg, int fserrno)
2825 : : {
2826 : 18 : struct spdk_fs_request *req = arg;
2827 [ # # ]: 18 : struct spdk_fs_cb_args *args = &req->args;
2828 : :
2829 [ # # # # ]: 18 : __file_close_async(args->file, req);
2830 : 18 : }
2831 : :
2832 : : void
2833 : 18 : spdk_file_close_async(struct spdk_file *file, spdk_file_op_complete cb_fn, void *cb_arg)
2834 : : {
2835 : : struct spdk_fs_request *req;
2836 : : struct spdk_fs_cb_args *args;
2837 : :
2838 [ # # # # : 18 : req = alloc_fs_request(file->fs->md_target.md_fs_channel);
# # # # #
# ]
2839 [ - + ]: 18 : if (req == NULL) {
2840 [ # # # # ]: 0 : SPDK_ERRLOG("Cannot allocate close async req for file=%s\n", file->name);
2841 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
2842 : 0 : return;
2843 : : }
2844 : :
2845 [ # # ]: 18 : args = &req->args;
2846 [ # # # # ]: 18 : args->file = file;
2847 [ # # # # : 18 : args->fn.file_op = cb_fn;
# # ]
2848 [ # # # # ]: 18 : args->arg = cb_arg;
2849 : :
2850 [ # # # # : 18 : spdk_file_sync_async(file, file->fs->md_target.md_io_channel, __file_close_async__sync_done, req);
# # # # #
# ]
2851 : 0 : }
2852 : :
2853 : : static void
2854 : 15684 : __file_close(void *arg)
2855 : : {
2856 : 15684 : struct spdk_fs_request *req = arg;
2857 [ # # ]: 15684 : struct spdk_fs_cb_args *args = &req->args;
2858 [ # # # # ]: 15684 : struct spdk_file *file = args->file;
2859 : :
2860 : 15684 : __file_close_async(file, req);
2861 : 15684 : }
2862 : :
2863 : : int
2864 : 15684 : spdk_file_close(struct spdk_file *file, struct spdk_fs_thread_ctx *ctx)
2865 : : {
2866 : 15684 : struct spdk_fs_channel *channel = (struct spdk_fs_channel *)ctx;
2867 : : struct spdk_fs_request *req;
2868 : : struct spdk_fs_cb_args *args;
2869 : :
2870 : 15684 : req = alloc_fs_request(channel);
2871 [ - + ]: 15684 : if (req == NULL) {
2872 [ # # # # ]: 0 : SPDK_ERRLOG("Cannot allocate close req for file=%s\n", file->name);
2873 : 0 : return -ENOMEM;
2874 : : }
2875 : :
2876 [ # # ]: 15684 : args = &req->args;
2877 : :
2878 : 15684 : spdk_file_sync(file, ctx);
2879 [ - + - + : 15684 : BLOBFS_TRACE(file, "name=%s\n", file->name);
# # # # #
# # # #
# ]
2880 [ # # # # ]: 15684 : args->file = file;
2881 [ # # # # : 15684 : args->sem = &channel->sem;
# # ]
2882 [ # # # # : 15684 : args->fn.file_op = __wake_caller;
# # ]
2883 [ # # # # ]: 15684 : args->arg = args;
2884 [ # # # # : 15684 : channel->send_request(__file_close, req);
# # # # ]
2885 [ - + # # ]: 15684 : sem_wait(&channel->sem);
2886 : :
2887 [ # # # # ]: 15684 : return args->rc;
2888 : 0 : }
2889 : :
2890 : : int
2891 : 0 : spdk_file_get_id(struct spdk_file *file, void *id, size_t size)
2892 : : {
2893 [ # # ]: 0 : if (size < sizeof(spdk_blob_id)) {
2894 : 0 : return -EINVAL;
2895 : : }
2896 : :
2897 [ # # # # : 0 : memcpy(id, &file->blobid, sizeof(spdk_blob_id));
# # ]
2898 : :
2899 : 0 : return sizeof(spdk_blob_id);
2900 : 0 : }
2901 : :
2902 : : static void
2903 : 875 : _file_free(void *ctx)
2904 : : {
2905 : 875 : struct spdk_file *file = ctx;
2906 : :
2907 [ + + # # : 875 : TAILQ_REMOVE(&g_caches, file, cache_tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
2908 : :
2909 [ # # # # ]: 875 : free(file->name);
2910 [ # # # # ]: 875 : free(file->tree);
2911 : 875 : free(file);
2912 : 875 : }
2913 : :
2914 : : static void
2915 : 8040 : file_free(struct spdk_file *file)
2916 : : {
2917 [ - + - + : 8040 : BLOBFS_TRACE(file, "free=%s\n", file->name);
# # # # #
# # # #
# ]
2918 [ - + # # ]: 8040 : pthread_spin_lock(&file->lock);
2919 [ + + # # : 8040 : if (file->tree->present_mask == 0) {
# # # # #
# ]
2920 [ - + # # ]: 7165 : pthread_spin_unlock(&file->lock);
2921 [ # # # # ]: 7165 : free(file->name);
2922 [ # # # # ]: 7165 : free(file->tree);
2923 : 7165 : free(file);
2924 : 7165 : return;
2925 : : }
2926 : :
2927 [ # # # # ]: 875 : tree_free_buffers(file->tree);
2928 [ - + # # : 875 : assert(file->tree->present_mask == 0);
# # # # #
# # # ]
2929 : 875 : spdk_thread_send_msg(g_cache_pool_thread, _file_free, file);
2930 [ - + # # ]: 875 : pthread_spin_unlock(&file->lock);
2931 : 0 : }
2932 : :
2933 : 2017 : SPDK_LOG_REGISTER_COMPONENT(blobfs)
2934 : 2017 : SPDK_LOG_REGISTER_COMPONENT(blobfs_rw)
|