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