1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "spdk/blobfs.h" 37 #include "blobfs_internal.h" 38 39 #include "spdk/queue.h" 40 #include "spdk/io_channel.h" 41 #include "spdk/assert.h" 42 #include "spdk/env.h" 43 #include "spdk/util.h" 44 #include "spdk_internal/log.h" 45 46 #define BLOBFS_TRACE(file, str, args...) \ 47 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s " str, file->name, ##args) 48 49 #define BLOBFS_TRACE_RW(file, str, args...) \ 50 SPDK_TRACELOG(SPDK_TRACE_BLOBFS_RW, "file=%s " str, file->name, ##args) 51 52 #define BLOBFS_CACHE_SIZE (4ULL * 1024 * 1024 * 1024) 53 54 static uint64_t g_fs_cache_size = BLOBFS_CACHE_SIZE; 55 static struct spdk_mempool *g_cache_pool; 56 static TAILQ_HEAD(, spdk_file) g_caches; 57 static pthread_spinlock_t g_caches_lock; 58 59 static void 60 __sem_post(void *arg, int bserrno) 61 { 62 sem_t *sem = arg; 63 64 sem_post(sem); 65 } 66 67 void 68 spdk_cache_buffer_free(struct cache_buffer *cache_buffer) 69 { 70 spdk_mempool_put(g_cache_pool, cache_buffer->buf); 71 free(cache_buffer); 72 } 73 74 #define CACHE_READAHEAD_THRESHOLD (128 * 1024) 75 76 struct spdk_file { 77 struct spdk_filesystem *fs; 78 struct spdk_blob *blob; 79 char *name; 80 uint64_t length; 81 bool open_for_writing; 82 uint64_t length_flushed; 83 uint64_t append_pos; 84 uint64_t seq_byte_count; 85 uint64_t next_seq_offset; 86 uint32_t priority; 87 TAILQ_ENTRY(spdk_file) tailq; 88 spdk_blob_id blobid; 89 uint32_t ref_count; 90 pthread_spinlock_t lock; 91 struct cache_buffer *last; 92 struct cache_tree *tree; 93 TAILQ_HEAD(open_requests_head, spdk_fs_request) open_requests; 94 TAILQ_HEAD(sync_requests_head, spdk_fs_request) sync_requests; 95 TAILQ_ENTRY(spdk_file) cache_tailq; 96 }; 97 98 struct spdk_filesystem { 99 struct spdk_blob_store *bs; 100 TAILQ_HEAD(, spdk_file) files; 101 struct spdk_bs_opts bs_opts; 102 struct spdk_bs_dev *bdev; 103 fs_send_request_fn send_request; 104 struct spdk_io_channel *sync_io_channel; 105 struct spdk_fs_channel *sync_fs_channel; 106 struct spdk_io_channel *md_io_channel; 107 struct spdk_fs_channel *md_fs_channel; 108 109 struct { 110 uint32_t max_ops; 111 } io_target; 112 }; 113 114 struct spdk_fs_cb_args { 115 union { 116 spdk_fs_op_with_handle_complete fs_op_with_handle; 117 spdk_fs_op_complete fs_op; 118 spdk_file_op_with_handle_complete file_op_with_handle; 119 spdk_file_op_complete file_op; 120 spdk_file_stat_op_complete stat_op; 121 } fn; 122 void *arg; 123 sem_t *sem; 124 struct spdk_filesystem *fs; 125 struct spdk_file *file; 126 int rc; 127 bool from_request; 128 union { 129 struct { 130 uint64_t length; 131 } truncate; 132 struct { 133 struct spdk_io_channel *channel; 134 void *user_buf; 135 void *pin_buf; 136 int is_read; 137 off_t offset; 138 size_t length; 139 uint64_t start_page; 140 uint64_t num_pages; 141 uint32_t blocklen; 142 } rw; 143 struct { 144 const char *old_name; 145 const char *new_name; 146 } rename; 147 struct { 148 struct cache_buffer *cache_buffer; 149 uint64_t length; 150 } flush; 151 struct { 152 struct cache_buffer *cache_buffer; 153 uint64_t length; 154 uint64_t offset; 155 } readahead; 156 struct { 157 uint64_t offset; 158 TAILQ_ENTRY(spdk_fs_request) tailq; 159 } sync; 160 struct { 161 uint32_t num_clusters; 162 } resize; 163 struct { 164 const char *name; 165 uint32_t flags; 166 TAILQ_ENTRY(spdk_fs_request) tailq; 167 } open; 168 struct { 169 const char *name; 170 } create; 171 struct { 172 const char *name; 173 } delete; 174 struct { 175 const char *name; 176 } stat; 177 } op; 178 }; 179 180 static void cache_free_buffers(struct spdk_file *file); 181 182 static void 183 __initialize_cache(void) 184 { 185 if (g_cache_pool != NULL) { 186 return; 187 } 188 189 g_cache_pool = spdk_mempool_create("spdk_fs_cache", 190 g_fs_cache_size / CACHE_BUFFER_SIZE, 191 CACHE_BUFFER_SIZE, -1, SPDK_ENV_SOCKET_ID_ANY); 192 TAILQ_INIT(&g_caches); 193 pthread_spin_init(&g_caches_lock, 0); 194 } 195 196 static uint64_t 197 __file_get_blob_size(struct spdk_file *file) 198 { 199 uint64_t cluster_sz; 200 201 cluster_sz = file->fs->bs_opts.cluster_sz; 202 return cluster_sz * spdk_blob_get_num_clusters(file->blob); 203 } 204 205 struct spdk_fs_request { 206 struct spdk_fs_cb_args args; 207 TAILQ_ENTRY(spdk_fs_request) link; 208 struct spdk_fs_channel *channel; 209 }; 210 211 struct spdk_fs_channel { 212 struct spdk_fs_request *req_mem; 213 TAILQ_HEAD(, spdk_fs_request) reqs; 214 sem_t sem; 215 struct spdk_filesystem *fs; 216 struct spdk_io_channel *bs_channel; 217 fs_send_request_fn send_request; 218 }; 219 220 static struct spdk_fs_request * 221 alloc_fs_request(struct spdk_fs_channel *channel) 222 { 223 struct spdk_fs_request *req; 224 225 req = TAILQ_FIRST(&channel->reqs); 226 if (!req) { 227 return NULL; 228 } 229 TAILQ_REMOVE(&channel->reqs, req, link); 230 memset(req, 0, sizeof(*req)); 231 req->channel = channel; 232 req->args.from_request = true; 233 234 return req; 235 } 236 237 static void 238 free_fs_request(struct spdk_fs_request *req) 239 { 240 TAILQ_INSERT_HEAD(&req->channel->reqs, req, link); 241 } 242 243 static int 244 _spdk_fs_channel_create(struct spdk_filesystem *fs, struct spdk_fs_channel *channel, 245 uint32_t max_ops) 246 { 247 uint32_t i; 248 249 channel->req_mem = calloc(max_ops, sizeof(struct spdk_fs_request)); 250 if (!channel->req_mem) { 251 return -1; 252 } 253 254 TAILQ_INIT(&channel->reqs); 255 sem_init(&channel->sem, 0, 0); 256 257 for (i = 0; i < max_ops; i++) { 258 TAILQ_INSERT_TAIL(&channel->reqs, &channel->req_mem[i], link); 259 } 260 261 channel->fs = fs; 262 263 return 0; 264 } 265 266 static int 267 _spdk_fs_md_channel_create(void *io_device, uint32_t priority, void *ctx_buf, void *unique_ctx) 268 { 269 return _spdk_fs_channel_create(io_device, ctx_buf, 512); 270 } 271 272 static int 273 _spdk_fs_io_channel_create(void *io_device, uint32_t priority, void *ctx_buf, void *unique_ctx) 274 { 275 struct spdk_filesystem *fs; 276 struct spdk_fs_channel *channel = ctx_buf; 277 278 fs = SPDK_CONTAINEROF(io_device, struct spdk_filesystem, io_target); 279 280 return _spdk_fs_channel_create(fs, channel, fs->io_target.max_ops); 281 } 282 283 static void 284 _spdk_fs_channel_destroy(void *io_device, void *ctx_buf) 285 { 286 struct spdk_fs_channel *channel = ctx_buf; 287 288 free(channel->req_mem); 289 if (channel->bs_channel != NULL) { 290 spdk_bs_free_io_channel(channel->bs_channel); 291 } 292 } 293 294 static void 295 __send_request_direct(fs_request_fn fn, void *arg) 296 { 297 fn(arg); 298 } 299 300 static void 301 common_fs_bs_init(struct spdk_filesystem *fs, struct spdk_blob_store *bs) 302 { 303 fs->bs = bs; 304 fs->bs_opts.cluster_sz = spdk_bs_get_cluster_size(bs); 305 fs->md_fs_channel->bs_channel = spdk_bs_alloc_io_channel(fs->bs, SPDK_IO_PRIORITY_DEFAULT); 306 fs->md_fs_channel->send_request = __send_request_direct; 307 fs->sync_fs_channel->bs_channel = spdk_bs_alloc_io_channel(fs->bs, SPDK_IO_PRIORITY_DEFAULT); 308 fs->sync_fs_channel->send_request = __send_request_direct; 309 } 310 311 static void 312 init_cb(void *ctx, struct spdk_blob_store *bs, int bserrno) 313 { 314 struct spdk_fs_request *req = ctx; 315 struct spdk_fs_cb_args *args = &req->args; 316 struct spdk_filesystem *fs = args->fs; 317 318 if (bserrno == 0) { 319 common_fs_bs_init(fs, bs); 320 } else { 321 free(fs); 322 fs = NULL; 323 } 324 325 args->fn.fs_op_with_handle(args->arg, fs, bserrno); 326 free_fs_request(req); 327 } 328 329 static struct spdk_filesystem * 330 fs_alloc(struct spdk_bs_dev *dev, fs_send_request_fn send_request_fn) 331 { 332 struct spdk_filesystem *fs; 333 334 fs = calloc(1, sizeof(*fs)); 335 if (fs == NULL) { 336 return NULL; 337 } 338 339 fs->bdev = dev; 340 fs->send_request = send_request_fn; 341 TAILQ_INIT(&fs->files); 342 spdk_io_device_register(fs, _spdk_fs_md_channel_create, _spdk_fs_channel_destroy, 343 sizeof(struct spdk_fs_channel)); 344 345 fs->md_io_channel = spdk_get_io_channel(fs, SPDK_IO_PRIORITY_DEFAULT, true, NULL); 346 fs->md_fs_channel = spdk_io_channel_get_ctx(fs->md_io_channel); 347 348 fs->sync_io_channel = spdk_get_io_channel(fs, SPDK_IO_PRIORITY_DEFAULT, true, NULL); 349 fs->sync_fs_channel = spdk_io_channel_get_ctx(fs->sync_io_channel); 350 351 fs->io_target.max_ops = 512; 352 spdk_io_device_register(&fs->io_target, _spdk_fs_io_channel_create, _spdk_fs_channel_destroy, 353 sizeof(struct spdk_fs_channel)); 354 355 __initialize_cache(); 356 357 return fs; 358 } 359 360 void 361 spdk_fs_init(struct spdk_bs_dev *dev, fs_send_request_fn send_request_fn, 362 spdk_fs_op_with_handle_complete cb_fn, void *cb_arg) 363 { 364 struct spdk_filesystem *fs; 365 struct spdk_fs_request *req; 366 struct spdk_fs_cb_args *args; 367 368 fs = fs_alloc(dev, send_request_fn); 369 if (fs == NULL) { 370 cb_fn(cb_arg, NULL, -ENOMEM); 371 return; 372 } 373 374 req = alloc_fs_request(fs->md_fs_channel); 375 if (req == NULL) { 376 cb_fn(cb_arg, NULL, -ENOMEM); 377 return; 378 } 379 380 args = &req->args; 381 args->fn.fs_op_with_handle = cb_fn; 382 args->arg = cb_arg; 383 args->fs = fs; 384 385 spdk_bs_init(dev, NULL, init_cb, req); 386 } 387 388 static struct spdk_file * 389 file_alloc(struct spdk_filesystem *fs) 390 { 391 struct spdk_file *file; 392 393 file = calloc(1, sizeof(*file)); 394 if (file == NULL) { 395 return NULL; 396 } 397 398 file->fs = fs; 399 TAILQ_INIT(&file->open_requests); 400 TAILQ_INIT(&file->sync_requests); 401 pthread_spin_init(&file->lock, 0); 402 file->tree = calloc(1, sizeof(*file->tree)); 403 TAILQ_INSERT_TAIL(&fs->files, file, tailq); 404 file->priority = SPDK_FILE_PRIORITY_LOW; 405 return file; 406 } 407 408 static void 409 iter_cb(void *ctx, struct spdk_blob *blob, int rc) 410 { 411 struct spdk_fs_request *req = ctx; 412 struct spdk_fs_cb_args *args = &req->args; 413 struct spdk_filesystem *fs = args->fs; 414 struct spdk_file *f; 415 uint64_t *length; 416 const char *name; 417 size_t value_len; 418 419 if (rc == -ENOENT) { 420 /* Finished iterating */ 421 args->fn.fs_op_with_handle(args->arg, fs, 0); 422 free_fs_request(req); 423 return; 424 } else if (rc < 0) { 425 args->fn.fs_op_with_handle(args->arg, fs, rc); 426 free_fs_request(req); 427 return; 428 } 429 430 rc = spdk_bs_md_get_xattr_value(blob, "name", (const void **)&name, &value_len); 431 if (rc < 0) { 432 args->fn.fs_op_with_handle(args->arg, fs, rc); 433 free_fs_request(req); 434 return; 435 } 436 437 rc = spdk_bs_md_get_xattr_value(blob, "length", (const void **)&length, &value_len); 438 if (rc < 0) { 439 args->fn.fs_op_with_handle(args->arg, fs, rc); 440 free_fs_request(req); 441 return; 442 } 443 assert(value_len == 8); 444 445 f = file_alloc(fs); 446 if (f == NULL) { 447 args->fn.fs_op_with_handle(args->arg, fs, -ENOMEM); 448 free_fs_request(req); 449 return; 450 } 451 452 f->name = strdup(name); 453 f->blobid = spdk_blob_get_id(blob); 454 f->length = *length; 455 f->length_flushed = *length; 456 f->append_pos = *length; 457 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "added file %s length=%ju\n", f->name, f->length); 458 459 spdk_bs_md_iter_next(fs->bs, &blob, iter_cb, req); 460 } 461 462 static void 463 load_cb(void *ctx, struct spdk_blob_store *bs, int bserrno) 464 { 465 struct spdk_fs_request *req = ctx; 466 struct spdk_fs_cb_args *args = &req->args; 467 struct spdk_filesystem *fs = args->fs; 468 469 if (bserrno != 0) { 470 args->fn.fs_op_with_handle(args->arg, NULL, bserrno); 471 free_fs_request(req); 472 free(fs); 473 return; 474 } 475 476 common_fs_bs_init(fs, bs); 477 spdk_bs_md_iter_first(fs->bs, iter_cb, req); 478 } 479 480 void 481 spdk_fs_load(struct spdk_bs_dev *dev, fs_send_request_fn send_request_fn, 482 spdk_fs_op_with_handle_complete cb_fn, void *cb_arg) 483 { 484 struct spdk_filesystem *fs; 485 struct spdk_fs_cb_args *args; 486 struct spdk_fs_request *req; 487 488 fs = fs_alloc(dev, send_request_fn); 489 if (fs == NULL) { 490 cb_fn(cb_arg, NULL, -ENOMEM); 491 return; 492 } 493 494 req = alloc_fs_request(fs->md_fs_channel); 495 if (req == NULL) { 496 cb_fn(cb_arg, NULL, -ENOMEM); 497 return; 498 } 499 500 args = &req->args; 501 args->fn.fs_op_with_handle = cb_fn; 502 args->arg = cb_arg; 503 args->fs = fs; 504 505 spdk_bs_load(dev, load_cb, req); 506 } 507 508 static void 509 unload_cb(void *ctx, int bserrno) 510 { 511 struct spdk_fs_request *req = ctx; 512 struct spdk_fs_cb_args *args = &req->args; 513 struct spdk_filesystem *fs = args->fs; 514 515 args->fn.fs_op(args->arg, bserrno); 516 free(req); 517 spdk_io_device_unregister(&fs->io_target); 518 spdk_io_device_unregister(fs); 519 free(fs); 520 } 521 522 void 523 spdk_fs_unload(struct spdk_filesystem *fs, spdk_fs_op_complete cb_fn, void *cb_arg) 524 { 525 struct spdk_fs_request *req; 526 struct spdk_fs_cb_args *args; 527 528 /* 529 * We must free the md_channel before unloading the blobstore, so just 530 * allocate this request from the general heap. 531 */ 532 req = calloc(1, sizeof(*req)); 533 if (req == NULL) { 534 cb_fn(cb_arg, -ENOMEM); 535 return; 536 } 537 538 args = &req->args; 539 args->fn.fs_op = cb_fn; 540 args->arg = cb_arg; 541 args->fs = fs; 542 543 spdk_fs_free_io_channel(fs->md_io_channel); 544 spdk_fs_free_io_channel(fs->sync_io_channel); 545 spdk_bs_unload(fs->bs, unload_cb, req); 546 } 547 548 static struct spdk_file * 549 fs_find_file(struct spdk_filesystem *fs, const char *name) 550 { 551 struct spdk_file *file; 552 553 TAILQ_FOREACH(file, &fs->files, tailq) { 554 if (!strncmp(name, file->name, SPDK_FILE_NAME_MAX)) { 555 return file; 556 } 557 } 558 559 return NULL; 560 } 561 562 void 563 spdk_fs_file_stat_async(struct spdk_filesystem *fs, const char *name, 564 spdk_file_stat_op_complete cb_fn, void *cb_arg) 565 { 566 struct spdk_file_stat stat; 567 struct spdk_file *f = NULL; 568 569 if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) { 570 cb_fn(cb_arg, NULL, -ENAMETOOLONG); 571 return; 572 } 573 574 f = fs_find_file(fs, name); 575 if (f != NULL) { 576 stat.blobid = f->blobid; 577 stat.size = f->length; 578 cb_fn(cb_arg, &stat, 0); 579 return; 580 } 581 582 cb_fn(cb_arg, NULL, -ENOENT); 583 } 584 585 static void 586 __copy_stat(void *arg, struct spdk_file_stat *stat, int fserrno) 587 { 588 struct spdk_fs_request *req = arg; 589 struct spdk_fs_cb_args *args = &req->args; 590 591 args->rc = fserrno; 592 if (fserrno == 0) { 593 memcpy(args->arg, stat, sizeof(*stat)); 594 } 595 sem_post(args->sem); 596 } 597 598 static void 599 __file_stat(void *arg) 600 { 601 struct spdk_fs_request *req = arg; 602 struct spdk_fs_cb_args *args = &req->args; 603 604 spdk_fs_file_stat_async(args->fs, args->op.stat.name, 605 args->fn.stat_op, req); 606 } 607 608 int 609 spdk_fs_file_stat(struct spdk_filesystem *fs, struct spdk_io_channel *_channel, 610 const char *name, struct spdk_file_stat *stat) 611 { 612 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 613 struct spdk_fs_request *req; 614 int rc; 615 616 req = alloc_fs_request(channel); 617 assert(req != NULL); 618 619 req->args.fs = fs; 620 req->args.op.stat.name = name; 621 req->args.fn.stat_op = __copy_stat; 622 req->args.arg = stat; 623 req->args.sem = &channel->sem; 624 channel->send_request(__file_stat, req); 625 sem_wait(&channel->sem); 626 627 rc = req->args.rc; 628 free_fs_request(req); 629 630 return rc; 631 } 632 633 static void 634 fs_create_blob_close_cb(void *ctx, int bserrno) 635 { 636 struct spdk_fs_request *req = ctx; 637 struct spdk_fs_cb_args *args = &req->args; 638 639 args->fn.file_op(args->arg, bserrno); 640 free_fs_request(req); 641 } 642 643 static void 644 fs_create_blob_open_cb(void *ctx, struct spdk_blob *blob, int bserrno) 645 { 646 struct spdk_fs_request *req = ctx; 647 struct spdk_fs_cb_args *args = &req->args; 648 struct spdk_file *f = args->file; 649 uint64_t length = 0; 650 651 f->blob = blob; 652 spdk_bs_md_resize_blob(blob, 1); 653 spdk_blob_md_set_xattr(blob, "name", f->name, strlen(f->name) + 1); 654 spdk_blob_md_set_xattr(blob, "length", &length, sizeof(length)); 655 656 spdk_bs_md_close_blob(&f->blob, fs_create_blob_close_cb, args); 657 } 658 659 static void 660 fs_create_blob_create_cb(void *ctx, spdk_blob_id blobid, int bserrno) 661 { 662 struct spdk_fs_request *req = ctx; 663 struct spdk_fs_cb_args *args = &req->args; 664 struct spdk_file *f = args->file; 665 666 f->blobid = blobid; 667 spdk_bs_md_open_blob(f->fs->bs, blobid, fs_create_blob_open_cb, req); 668 } 669 670 void 671 spdk_fs_create_file_async(struct spdk_filesystem *fs, const char *name, 672 spdk_file_op_complete cb_fn, void *cb_arg) 673 { 674 struct spdk_file *file; 675 struct spdk_fs_request *req; 676 struct spdk_fs_cb_args *args; 677 678 if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) { 679 cb_fn(cb_arg, -ENAMETOOLONG); 680 return; 681 } 682 683 file = fs_find_file(fs, name); 684 if (file != NULL) { 685 cb_fn(cb_arg, -EEXIST); 686 return; 687 } 688 689 file = file_alloc(fs); 690 if (file == NULL) { 691 cb_fn(cb_arg, -ENOMEM); 692 return; 693 } 694 695 req = alloc_fs_request(fs->md_fs_channel); 696 if (req == NULL) { 697 cb_fn(cb_arg, -ENOMEM); 698 return; 699 } 700 701 args = &req->args; 702 args->file = file; 703 args->fn.file_op = cb_fn; 704 args->arg = cb_arg; 705 706 file->name = strdup(name); 707 spdk_bs_md_create_blob(fs->bs, fs_create_blob_create_cb, args); 708 } 709 710 static void 711 __fs_create_file_done(void *arg, int fserrno) 712 { 713 struct spdk_fs_request *req = arg; 714 struct spdk_fs_cb_args *args = &req->args; 715 716 args->rc = fserrno; 717 sem_post(args->sem); 718 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s\n", args->op.create.name); 719 } 720 721 static void 722 __fs_create_file(void *arg) 723 { 724 struct spdk_fs_request *req = arg; 725 struct spdk_fs_cb_args *args = &req->args; 726 727 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s\n", args->op.create.name); 728 spdk_fs_create_file_async(args->fs, args->op.create.name, __fs_create_file_done, req); 729 } 730 731 int 732 spdk_fs_create_file(struct spdk_filesystem *fs, struct spdk_io_channel *_channel, const char *name) 733 { 734 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 735 struct spdk_fs_request *req; 736 struct spdk_fs_cb_args *args; 737 int rc; 738 739 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s\n", name); 740 741 req = alloc_fs_request(channel); 742 assert(req != NULL); 743 744 args = &req->args; 745 args->fs = fs; 746 args->op.create.name = name; 747 args->sem = &channel->sem; 748 fs->send_request(__fs_create_file, req); 749 sem_wait(&channel->sem); 750 rc = args->rc; 751 free_fs_request(req); 752 753 return rc; 754 } 755 756 static void 757 fs_open_blob_done(void *ctx, struct spdk_blob *blob, int bserrno) 758 { 759 struct spdk_fs_request *req = ctx; 760 struct spdk_fs_cb_args *args = &req->args; 761 struct spdk_file *f = args->file; 762 763 f->blob = blob; 764 while (!TAILQ_EMPTY(&f->open_requests)) { 765 req = TAILQ_FIRST(&f->open_requests); 766 args = &req->args; 767 TAILQ_REMOVE(&f->open_requests, req, args.op.open.tailq); 768 args->fn.file_op_with_handle(args->arg, f, bserrno); 769 free_fs_request(req); 770 } 771 } 772 773 static void 774 fs_open_blob_create_cb(void *ctx, int bserrno) 775 { 776 struct spdk_fs_request *req = ctx; 777 struct spdk_fs_cb_args *args = &req->args; 778 struct spdk_file *file = args->file; 779 struct spdk_filesystem *fs = args->fs; 780 781 if (file == NULL) { 782 /* 783 * This is from an open with CREATE flag - the file 784 * is now created so look it up in the file list for this 785 * filesystem. 786 */ 787 file = fs_find_file(fs, args->op.open.name); 788 assert(file != NULL); 789 args->file = file; 790 } 791 792 file->ref_count++; 793 TAILQ_INSERT_TAIL(&file->open_requests, req, args.op.open.tailq); 794 if (file->ref_count == 1) { 795 assert(file->blob == NULL); 796 spdk_bs_md_open_blob(fs->bs, file->blobid, fs_open_blob_done, req); 797 } else if (file->blob != NULL) { 798 fs_open_blob_done(req, file->blob, 0); 799 } else { 800 /* 801 * The blob open for this file is in progress due to a previous 802 * open request. When that open completes, it will invoke the 803 * open callback for this request. 804 */ 805 } 806 } 807 808 void 809 spdk_fs_open_file_async(struct spdk_filesystem *fs, const char *name, uint32_t flags, 810 spdk_file_op_with_handle_complete cb_fn, void *cb_arg) 811 { 812 struct spdk_file *f = NULL; 813 struct spdk_fs_request *req; 814 struct spdk_fs_cb_args *args; 815 816 if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) { 817 cb_fn(cb_arg, NULL, -ENAMETOOLONG); 818 return; 819 } 820 821 f = fs_find_file(fs, name); 822 if (f == NULL && !(flags & SPDK_BLOBFS_OPEN_CREATE)) { 823 cb_fn(cb_arg, NULL, -ENOENT); 824 return; 825 } 826 827 req = alloc_fs_request(fs->md_fs_channel); 828 if (req == NULL) { 829 cb_fn(cb_arg, NULL, -ENOMEM); 830 return; 831 } 832 833 args = &req->args; 834 args->fn.file_op_with_handle = cb_fn; 835 args->arg = cb_arg; 836 args->file = f; 837 args->fs = fs; 838 args->op.open.name = name; 839 840 if (f == NULL) { 841 spdk_fs_create_file_async(fs, name, fs_open_blob_create_cb, req); 842 } else { 843 fs_open_blob_create_cb(req, 0); 844 } 845 } 846 847 static void 848 __fs_open_file_done(void *arg, struct spdk_file *file, int bserrno) 849 { 850 struct spdk_fs_request *req = arg; 851 struct spdk_fs_cb_args *args = &req->args; 852 853 args->file = file; 854 args->rc = bserrno; 855 sem_post(args->sem); 856 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s\n", args->op.open.name); 857 } 858 859 static void 860 __fs_open_file(void *arg) 861 { 862 struct spdk_fs_request *req = arg; 863 struct spdk_fs_cb_args *args = &req->args; 864 865 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s\n", args->op.open.name); 866 spdk_fs_open_file_async(args->fs, args->op.open.name, args->op.open.flags, 867 __fs_open_file_done, req); 868 } 869 870 int 871 spdk_fs_open_file(struct spdk_filesystem *fs, struct spdk_io_channel *_channel, 872 const char *name, uint32_t flags, struct spdk_file **file) 873 { 874 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 875 struct spdk_fs_request *req; 876 struct spdk_fs_cb_args *args; 877 int rc; 878 879 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s\n", name); 880 881 req = alloc_fs_request(channel); 882 assert(req != NULL); 883 884 args = &req->args; 885 args->fs = fs; 886 args->op.open.name = name; 887 args->op.open.flags = flags; 888 args->sem = &channel->sem; 889 fs->send_request(__fs_open_file, req); 890 sem_wait(&channel->sem); 891 rc = args->rc; 892 if (rc == 0) { 893 *file = args->file; 894 } else { 895 *file = NULL; 896 } 897 free_fs_request(req); 898 899 return rc; 900 } 901 902 static void 903 fs_rename_blob_close_cb(void *ctx, int bserrno) 904 { 905 struct spdk_fs_request *req = ctx; 906 struct spdk_fs_cb_args *args = &req->args; 907 908 args->fn.fs_op(args->arg, bserrno); 909 free_fs_request(req); 910 } 911 912 static void 913 fs_rename_blob_open_cb(void *ctx, struct spdk_blob *blob, int bserrno) 914 { 915 struct spdk_fs_request *req = ctx; 916 struct spdk_fs_cb_args *args = &req->args; 917 struct spdk_file *f = args->file; 918 const char *new_name = args->op.rename.new_name; 919 920 f->blob = blob; 921 spdk_blob_md_set_xattr(blob, "name", new_name, strlen(new_name) + 1); 922 spdk_bs_md_close_blob(&f->blob, fs_rename_blob_close_cb, req); 923 } 924 925 static void 926 __spdk_fs_md_rename_file(struct spdk_fs_request *req) 927 { 928 struct spdk_fs_cb_args *args = &req->args; 929 struct spdk_file *f; 930 931 f = fs_find_file(args->fs, args->op.rename.old_name); 932 if (f == NULL) { 933 args->fn.fs_op(args->arg, -ENOENT); 934 free_fs_request(req); 935 return; 936 } 937 938 free(f->name); 939 f->name = strdup(args->op.rename.new_name); 940 args->file = f; 941 spdk_bs_md_open_blob(args->fs->bs, f->blobid, fs_rename_blob_open_cb, req); 942 } 943 944 static void 945 fs_rename_delete_done(void *arg, int fserrno) 946 { 947 __spdk_fs_md_rename_file(arg); 948 } 949 950 void 951 spdk_fs_rename_file_async(struct spdk_filesystem *fs, 952 const char *old_name, const char *new_name, 953 spdk_file_op_complete cb_fn, void *cb_arg) 954 { 955 struct spdk_file *f; 956 struct spdk_fs_request *req; 957 struct spdk_fs_cb_args *args; 958 959 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "old=%s new=%s\n", old_name, new_name); 960 if (strnlen(new_name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) { 961 cb_fn(cb_arg, -ENAMETOOLONG); 962 return; 963 } 964 965 req = alloc_fs_request(fs->md_fs_channel); 966 if (req == NULL) { 967 cb_fn(cb_arg, -ENOMEM); 968 return; 969 } 970 971 args = &req->args; 972 args->fn.fs_op = cb_fn; 973 args->fs = fs; 974 args->arg = cb_arg; 975 args->op.rename.old_name = old_name; 976 args->op.rename.new_name = new_name; 977 978 f = fs_find_file(fs, new_name); 979 if (f == NULL) { 980 __spdk_fs_md_rename_file(req); 981 return; 982 } 983 984 /* 985 * The rename overwrites an existing file. So delete the existing file, then 986 * do the actual rename. 987 */ 988 spdk_fs_delete_file_async(fs, new_name, fs_rename_delete_done, req); 989 } 990 991 static void 992 __fs_rename_file_done(void *arg, int fserrno) 993 { 994 struct spdk_fs_request *req = arg; 995 struct spdk_fs_cb_args *args = &req->args; 996 997 args->rc = fserrno; 998 sem_post(args->sem); 999 } 1000 1001 static void 1002 __fs_rename_file(void *arg) 1003 { 1004 struct spdk_fs_request *req = arg; 1005 struct spdk_fs_cb_args *args = &req->args; 1006 1007 spdk_fs_rename_file_async(args->fs, args->op.rename.old_name, args->op.rename.new_name, 1008 __fs_rename_file_done, req); 1009 } 1010 1011 int 1012 spdk_fs_rename_file(struct spdk_filesystem *fs, struct spdk_io_channel *_channel, 1013 const char *old_name, const char *new_name) 1014 { 1015 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 1016 struct spdk_fs_request *req; 1017 struct spdk_fs_cb_args *args; 1018 int rc; 1019 1020 req = alloc_fs_request(channel); 1021 assert(req != NULL); 1022 1023 args = &req->args; 1024 1025 args->fs = fs; 1026 args->op.rename.old_name = old_name; 1027 args->op.rename.new_name = new_name; 1028 args->sem = &channel->sem; 1029 fs->send_request(__fs_rename_file, req); 1030 sem_wait(&channel->sem); 1031 rc = args->rc; 1032 free_fs_request(req); 1033 return rc; 1034 } 1035 1036 static void 1037 blob_delete_cb(void *ctx, int bserrno) 1038 { 1039 struct spdk_fs_request *req = ctx; 1040 struct spdk_fs_cb_args *args = &req->args; 1041 1042 args->fn.file_op(args->arg, bserrno); 1043 free_fs_request(req); 1044 } 1045 1046 void 1047 spdk_fs_delete_file_async(struct spdk_filesystem *fs, const char *name, 1048 spdk_file_op_complete cb_fn, void *cb_arg) 1049 { 1050 struct spdk_file *f; 1051 spdk_blob_id blobid; 1052 struct spdk_fs_request *req; 1053 struct spdk_fs_cb_args *args; 1054 1055 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s\n", name); 1056 1057 if (strnlen(name, SPDK_FILE_NAME_MAX + 1) == SPDK_FILE_NAME_MAX + 1) { 1058 cb_fn(cb_arg, -ENAMETOOLONG); 1059 return; 1060 } 1061 1062 f = fs_find_file(fs, name); 1063 if (f == NULL) { 1064 cb_fn(cb_arg, -ENOENT); 1065 return; 1066 } 1067 1068 if (f->ref_count > 0) { 1069 /* For now, do not allow deleting files with open references. */ 1070 cb_fn(cb_arg, -EBUSY); 1071 return; 1072 } 1073 1074 req = alloc_fs_request(fs->md_fs_channel); 1075 if (req == NULL) { 1076 cb_fn(cb_arg, -ENOMEM); 1077 return; 1078 } 1079 1080 TAILQ_REMOVE(&fs->files, f, tailq); 1081 1082 cache_free_buffers(f); 1083 1084 blobid = f->blobid; 1085 1086 free(f->name); 1087 free(f->tree); 1088 free(f); 1089 1090 args = &req->args; 1091 args->fn.file_op = cb_fn; 1092 args->arg = cb_arg; 1093 spdk_bs_md_delete_blob(fs->bs, blobid, blob_delete_cb, req); 1094 } 1095 1096 static void 1097 __fs_delete_file_done(void *arg, int fserrno) 1098 { 1099 struct spdk_fs_request *req = arg; 1100 struct spdk_fs_cb_args *args = &req->args; 1101 1102 args->rc = fserrno; 1103 sem_post(args->sem); 1104 } 1105 1106 static void 1107 __fs_delete_file(void *arg) 1108 { 1109 struct spdk_fs_request *req = arg; 1110 struct spdk_fs_cb_args *args = &req->args; 1111 1112 spdk_fs_delete_file_async(args->fs, args->op.delete.name, __fs_delete_file_done, req); 1113 } 1114 1115 int 1116 spdk_fs_delete_file(struct spdk_filesystem *fs, struct spdk_io_channel *_channel, 1117 const char *name) 1118 { 1119 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 1120 struct spdk_fs_request *req; 1121 struct spdk_fs_cb_args *args; 1122 int rc; 1123 1124 req = alloc_fs_request(channel); 1125 assert(req != NULL); 1126 1127 args = &req->args; 1128 args->fs = fs; 1129 args->op.delete.name = name; 1130 args->sem = &channel->sem; 1131 fs->send_request(__fs_delete_file, req); 1132 sem_wait(&channel->sem); 1133 rc = args->rc; 1134 free_fs_request(req); 1135 1136 return rc; 1137 } 1138 1139 spdk_fs_iter 1140 spdk_fs_iter_first(struct spdk_filesystem *fs) 1141 { 1142 struct spdk_file *f; 1143 1144 f = TAILQ_FIRST(&fs->files); 1145 return f; 1146 } 1147 1148 spdk_fs_iter 1149 spdk_fs_iter_next(spdk_fs_iter iter) 1150 { 1151 struct spdk_file *f = iter; 1152 1153 if (f == NULL) { 1154 return NULL; 1155 } 1156 1157 f = TAILQ_NEXT(f, tailq); 1158 return f; 1159 } 1160 1161 const char * 1162 spdk_file_get_name(struct spdk_file *file) 1163 { 1164 return file->name; 1165 } 1166 1167 uint64_t 1168 spdk_file_get_length(struct spdk_file *file) 1169 { 1170 assert(file != NULL); 1171 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s length=0x%jx\n", file->name, file->length); 1172 return file->length; 1173 } 1174 1175 static void 1176 fs_truncate_complete_cb(void *ctx, int bserrno) 1177 { 1178 struct spdk_fs_request *req = ctx; 1179 struct spdk_fs_cb_args *args = &req->args; 1180 1181 args->fn.file_op(args->arg, bserrno); 1182 free_fs_request(req); 1183 } 1184 1185 static uint64_t 1186 __bytes_to_clusters(uint64_t length, uint64_t cluster_sz) 1187 { 1188 return (length + cluster_sz - 1) / cluster_sz; 1189 } 1190 1191 void 1192 spdk_file_truncate_async(struct spdk_file *file, uint64_t length, 1193 spdk_file_op_complete cb_fn, void *cb_arg) 1194 { 1195 struct spdk_filesystem *fs; 1196 size_t num_clusters; 1197 struct spdk_fs_request *req; 1198 struct spdk_fs_cb_args *args; 1199 1200 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s old=0x%jx new=0x%jx\n", file->name, file->length, length); 1201 if (length == file->length) { 1202 cb_fn(cb_arg, 0); 1203 return; 1204 } 1205 1206 req = alloc_fs_request(file->fs->md_fs_channel); 1207 if (req == NULL) { 1208 cb_fn(cb_arg, -ENOMEM); 1209 return; 1210 } 1211 1212 args = &req->args; 1213 args->fn.file_op = cb_fn; 1214 args->arg = cb_arg; 1215 args->file = file; 1216 fs = file->fs; 1217 1218 num_clusters = __bytes_to_clusters(length, fs->bs_opts.cluster_sz); 1219 1220 spdk_bs_md_resize_blob(file->blob, num_clusters); 1221 spdk_blob_md_set_xattr(file->blob, "length", &length, sizeof(length)); 1222 1223 file->length = length; 1224 if (file->append_pos > file->length) { 1225 file->append_pos = file->length; 1226 } 1227 1228 spdk_bs_md_sync_blob(file->blob, fs_truncate_complete_cb, args); 1229 } 1230 1231 static void 1232 __truncate(void *arg) 1233 { 1234 struct spdk_fs_request *req = arg; 1235 struct spdk_fs_cb_args *args = &req->args; 1236 1237 spdk_file_truncate_async(args->file, args->op.truncate.length, 1238 args->fn.file_op, args->arg); 1239 } 1240 1241 void 1242 spdk_file_truncate(struct spdk_file *file, struct spdk_io_channel *_channel, 1243 uint64_t length) 1244 { 1245 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 1246 struct spdk_fs_request *req; 1247 struct spdk_fs_cb_args *args; 1248 1249 req = alloc_fs_request(channel); 1250 assert(req != NULL); 1251 1252 args = &req->args; 1253 1254 args->file = file; 1255 args->op.truncate.length = length; 1256 args->fn.file_op = __sem_post; 1257 args->arg = &channel->sem; 1258 1259 channel->send_request(__truncate, req); 1260 sem_wait(&channel->sem); 1261 free_fs_request(req); 1262 } 1263 1264 static void 1265 __rw_done(void *ctx, int bserrno) 1266 { 1267 struct spdk_fs_request *req = ctx; 1268 struct spdk_fs_cb_args *args = &req->args; 1269 1270 spdk_free(args->op.rw.pin_buf); 1271 args->fn.file_op(args->arg, bserrno); 1272 free_fs_request(req); 1273 } 1274 1275 static void 1276 __read_done(void *ctx, int bserrno) 1277 { 1278 struct spdk_fs_request *req = ctx; 1279 struct spdk_fs_cb_args *args = &req->args; 1280 1281 if (args->op.rw.is_read) { 1282 memcpy(args->op.rw.user_buf, 1283 args->op.rw.pin_buf + (args->op.rw.offset & 0xFFF), 1284 args->op.rw.length); 1285 __rw_done(req, 0); 1286 } else { 1287 memcpy(args->op.rw.pin_buf + (args->op.rw.offset & 0xFFF), 1288 args->op.rw.user_buf, 1289 args->op.rw.length); 1290 spdk_bs_io_write_blob(args->file->blob, args->op.rw.channel, 1291 args->op.rw.pin_buf, 1292 args->op.rw.start_page, args->op.rw.num_pages, 1293 __rw_done, req); 1294 } 1295 } 1296 1297 static void 1298 __do_blob_read(void *ctx, int fserrno) 1299 { 1300 struct spdk_fs_request *req = ctx; 1301 struct spdk_fs_cb_args *args = &req->args; 1302 1303 spdk_bs_io_read_blob(args->file->blob, args->op.rw.channel, 1304 args->op.rw.pin_buf, 1305 args->op.rw.start_page, args->op.rw.num_pages, 1306 __read_done, req); 1307 } 1308 1309 static void 1310 __get_page_parameters(struct spdk_file *file, uint64_t offset, uint64_t length, 1311 uint64_t *start_page, uint32_t *page_size, uint64_t *num_pages) 1312 { 1313 uint64_t end_page; 1314 1315 *page_size = spdk_bs_get_page_size(file->fs->bs); 1316 *start_page = offset / *page_size; 1317 end_page = (offset + length - 1) / *page_size; 1318 *num_pages = (end_page - *start_page + 1); 1319 } 1320 1321 static void 1322 __readwrite(struct spdk_file *file, struct spdk_io_channel *_channel, 1323 void *payload, uint64_t offset, uint64_t length, 1324 spdk_file_op_complete cb_fn, void *cb_arg, int is_read) 1325 { 1326 struct spdk_fs_request *req; 1327 struct spdk_fs_cb_args *args; 1328 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 1329 uint64_t start_page, num_pages, pin_buf_length; 1330 uint32_t page_size; 1331 1332 if (is_read && offset + length > file->length) { 1333 cb_fn(cb_arg, -EINVAL); 1334 return; 1335 } 1336 1337 req = alloc_fs_request(channel); 1338 if (req == NULL) { 1339 cb_fn(cb_arg, -ENOMEM); 1340 return; 1341 } 1342 1343 args = &req->args; 1344 args->fn.file_op = cb_fn; 1345 args->arg = cb_arg; 1346 args->file = file; 1347 args->op.rw.channel = channel->bs_channel; 1348 args->op.rw.user_buf = payload; 1349 args->op.rw.is_read = is_read; 1350 args->op.rw.offset = offset; 1351 args->op.rw.length = length; 1352 1353 __get_page_parameters(file, offset, length, &start_page, &page_size, &num_pages); 1354 pin_buf_length = num_pages * page_size; 1355 args->op.rw.pin_buf = spdk_malloc(pin_buf_length, 4096, NULL); 1356 1357 args->op.rw.start_page = start_page; 1358 args->op.rw.num_pages = num_pages; 1359 1360 if (!is_read && file->length < offset + length) { 1361 spdk_file_truncate_async(file, offset + length, __do_blob_read, req); 1362 } else { 1363 __do_blob_read(req, 0); 1364 } 1365 } 1366 1367 void 1368 spdk_file_write_async(struct spdk_file *file, struct spdk_io_channel *channel, 1369 void *payload, uint64_t offset, uint64_t length, 1370 spdk_file_op_complete cb_fn, void *cb_arg) 1371 { 1372 __readwrite(file, channel, payload, offset, length, cb_fn, cb_arg, 0); 1373 } 1374 1375 void 1376 spdk_file_read_async(struct spdk_file *file, struct spdk_io_channel *channel, 1377 void *payload, uint64_t offset, uint64_t length, 1378 spdk_file_op_complete cb_fn, void *cb_arg) 1379 { 1380 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "file=%s offset=%jx length=%jx\n", 1381 file->name, offset, length); 1382 __readwrite(file, channel, payload, offset, length, cb_fn, cb_arg, 1); 1383 } 1384 1385 struct spdk_io_channel * 1386 spdk_fs_alloc_io_channel(struct spdk_filesystem *fs, uint32_t priority) 1387 { 1388 struct spdk_io_channel *io_channel; 1389 struct spdk_fs_channel *fs_channel; 1390 1391 io_channel = spdk_get_io_channel(&fs->io_target, priority, false, NULL); 1392 fs_channel = spdk_io_channel_get_ctx(io_channel); 1393 fs_channel->bs_channel = spdk_bs_alloc_io_channel(fs->bs, SPDK_IO_PRIORITY_DEFAULT); 1394 fs_channel->send_request = __send_request_direct; 1395 1396 return io_channel; 1397 } 1398 1399 struct spdk_io_channel * 1400 spdk_fs_alloc_io_channel_sync(struct spdk_filesystem *fs, uint32_t priority) 1401 { 1402 struct spdk_io_channel *io_channel; 1403 struct spdk_fs_channel *fs_channel; 1404 1405 io_channel = spdk_get_io_channel(&fs->io_target, priority, false, NULL); 1406 fs_channel = spdk_io_channel_get_ctx(io_channel); 1407 fs_channel->send_request = fs->send_request; 1408 1409 return io_channel; 1410 } 1411 1412 void 1413 spdk_fs_free_io_channel(struct spdk_io_channel *channel) 1414 { 1415 spdk_put_io_channel(channel); 1416 } 1417 1418 void 1419 spdk_fs_set_cache_size(uint64_t size_in_mb) 1420 { 1421 g_fs_cache_size = size_in_mb * 1024 * 1024; 1422 } 1423 1424 uint64_t 1425 spdk_fs_get_cache_size(void) 1426 { 1427 return g_fs_cache_size / (1024 * 1024); 1428 } 1429 1430 static void __file_flush(void *_args); 1431 1432 static void * 1433 alloc_cache_memory_buffer(struct spdk_file *context) 1434 { 1435 struct spdk_file *file; 1436 void *buf; 1437 1438 buf = spdk_mempool_get(g_cache_pool); 1439 if (buf != NULL) { 1440 return buf; 1441 } 1442 1443 pthread_spin_lock(&g_caches_lock); 1444 TAILQ_FOREACH(file, &g_caches, cache_tailq) { 1445 if (!file->open_for_writing && 1446 file->priority == SPDK_FILE_PRIORITY_LOW && 1447 file != context) { 1448 TAILQ_REMOVE(&g_caches, file, cache_tailq); 1449 TAILQ_INSERT_TAIL(&g_caches, file, cache_tailq); 1450 break; 1451 } 1452 } 1453 pthread_spin_unlock(&g_caches_lock); 1454 if (file != NULL) { 1455 cache_free_buffers(file); 1456 buf = spdk_mempool_get(g_cache_pool); 1457 if (buf != NULL) { 1458 return buf; 1459 } 1460 } 1461 1462 pthread_spin_lock(&g_caches_lock); 1463 TAILQ_FOREACH(file, &g_caches, cache_tailq) { 1464 if (!file->open_for_writing && file != context) { 1465 TAILQ_REMOVE(&g_caches, file, cache_tailq); 1466 TAILQ_INSERT_TAIL(&g_caches, file, cache_tailq); 1467 break; 1468 } 1469 } 1470 pthread_spin_unlock(&g_caches_lock); 1471 if (file != NULL) { 1472 cache_free_buffers(file); 1473 buf = spdk_mempool_get(g_cache_pool); 1474 if (buf != NULL) { 1475 return buf; 1476 } 1477 } 1478 1479 pthread_spin_lock(&g_caches_lock); 1480 TAILQ_FOREACH(file, &g_caches, cache_tailq) { 1481 if (file != context) { 1482 TAILQ_REMOVE(&g_caches, file, cache_tailq); 1483 TAILQ_INSERT_TAIL(&g_caches, file, cache_tailq); 1484 break; 1485 } 1486 } 1487 pthread_spin_unlock(&g_caches_lock); 1488 if (file != NULL) { 1489 cache_free_buffers(file); 1490 buf = spdk_mempool_get(g_cache_pool); 1491 if (buf != NULL) { 1492 return buf; 1493 } 1494 } 1495 1496 assert(false); 1497 return NULL; 1498 } 1499 1500 static struct cache_buffer * 1501 cache_insert_buffer(struct spdk_file *file, uint64_t offset) 1502 { 1503 struct cache_buffer *buf; 1504 int count = 0; 1505 1506 buf = calloc(1, sizeof(*buf)); 1507 if (buf == NULL) { 1508 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "calloc failed\n"); 1509 return NULL; 1510 } 1511 1512 buf->buf = alloc_cache_memory_buffer(file); 1513 if (buf->buf == NULL) { 1514 while (buf->buf == NULL) { 1515 /* 1516 * TODO: alloc_cache_memory_buffer() should eventually free 1517 * some buffers. Need a more sophisticated check here, instead 1518 * of just bailing if 100 tries does not result in getting a 1519 * free buffer. This will involve using the sync channel's 1520 * semaphore to block until a buffer becomes available. 1521 */ 1522 if (count++ == 100) { 1523 SPDK_ERRLOG("could not allocate cache buffer\n"); 1524 assert(false); 1525 free(buf); 1526 return NULL; 1527 } 1528 buf->buf = alloc_cache_memory_buffer(file); 1529 } 1530 } 1531 1532 buf->buf_size = CACHE_BUFFER_SIZE; 1533 buf->offset = offset; 1534 1535 pthread_spin_lock(&g_caches_lock); 1536 if (file->tree->present_mask == 0) { 1537 TAILQ_INSERT_TAIL(&g_caches, file, cache_tailq); 1538 } 1539 file->tree = spdk_tree_insert_buffer(file->tree, buf); 1540 pthread_spin_unlock(&g_caches_lock); 1541 1542 return buf; 1543 } 1544 1545 static struct cache_buffer * 1546 cache_append_buffer(struct spdk_file *file) 1547 { 1548 struct cache_buffer *last; 1549 1550 assert(file->last == NULL || file->last->bytes_filled == file->last->buf_size); 1551 assert((file->append_pos % CACHE_BUFFER_SIZE) == 0); 1552 1553 last = cache_insert_buffer(file, file->append_pos); 1554 if (last == NULL) { 1555 SPDK_TRACELOG(SPDK_TRACE_BLOBFS, "cache_insert_buffer failed\n"); 1556 return NULL; 1557 } 1558 1559 if (file->last != NULL) { 1560 file->last->next = last; 1561 } 1562 file->last = last; 1563 1564 return last; 1565 } 1566 1567 static void 1568 __wake_caller(struct spdk_fs_cb_args *args) 1569 { 1570 sem_post(args->sem); 1571 } 1572 1573 static void 1574 __file_cache_finish_sync(struct spdk_file *file) 1575 { 1576 struct spdk_fs_request *sync_req; 1577 struct spdk_fs_cb_args *sync_args; 1578 1579 pthread_spin_lock(&file->lock); 1580 while (!TAILQ_EMPTY(&file->sync_requests)) { 1581 sync_req = TAILQ_FIRST(&file->sync_requests); 1582 sync_args = &sync_req->args; 1583 if (sync_args->op.sync.offset > file->length_flushed) { 1584 break; 1585 } 1586 BLOBFS_TRACE(file, "sync done offset=%jx\n", sync_args->op.sync.offset); 1587 TAILQ_REMOVE(&file->sync_requests, sync_req, args.op.sync.tailq); 1588 pthread_spin_unlock(&file->lock); 1589 sync_args->fn.file_op(sync_args->arg, 0); 1590 pthread_spin_lock(&file->lock); 1591 free_fs_request(sync_req); 1592 } 1593 pthread_spin_unlock(&file->lock); 1594 } 1595 1596 static void 1597 __file_cache_finish_sync_bs_cb(void *ctx, int bserrno) 1598 { 1599 struct spdk_file *file = ctx; 1600 1601 __file_cache_finish_sync(file); 1602 } 1603 1604 static void 1605 __free_args(struct spdk_fs_cb_args *args) 1606 { 1607 struct spdk_fs_request *req; 1608 1609 if (!args->from_request) { 1610 free(args); 1611 } else { 1612 /* Depends on args being at the start of the spdk_fs_request structure. */ 1613 req = (struct spdk_fs_request *)args; 1614 free_fs_request(req); 1615 } 1616 } 1617 1618 static void 1619 __file_flush_done(void *arg, int bserrno) 1620 { 1621 struct spdk_fs_cb_args *args = arg; 1622 struct spdk_fs_request *sync_req; 1623 struct spdk_file *file = args->file; 1624 struct cache_buffer *next = args->op.flush.cache_buffer; 1625 1626 BLOBFS_TRACE(file, "length=%jx\n", args->op.flush.length); 1627 1628 pthread_spin_lock(&file->lock); 1629 next->in_progress = false; 1630 next->bytes_flushed += args->op.flush.length; 1631 file->length_flushed += args->op.flush.length; 1632 if (file->length_flushed > file->length) { 1633 file->length = file->length_flushed; 1634 } 1635 if (next->bytes_flushed == next->buf_size) { 1636 BLOBFS_TRACE(file, "write buffer fully flushed 0x%jx\n", file->length_flushed); 1637 next = spdk_tree_find_buffer(file->tree, file->length_flushed); 1638 } 1639 1640 TAILQ_FOREACH_REVERSE(sync_req, &file->sync_requests, sync_requests_head, args.op.sync.tailq) { 1641 if (sync_req->args.op.sync.offset <= file->length_flushed) { 1642 break; 1643 } 1644 } 1645 1646 /* 1647 * Assert that there is no cached data that extends past the end of the underlying 1648 * blob. 1649 */ 1650 assert(next == NULL || next->offset < __file_get_blob_size(file) || 1651 next->bytes_filled == 0); 1652 1653 if (sync_req != NULL) { 1654 BLOBFS_TRACE(file, "set xattr length 0x%jx\n", file->length_flushed); 1655 spdk_blob_md_set_xattr(file->blob, "length", &file->length_flushed, 1656 sizeof(file->length_flushed)); 1657 1658 pthread_spin_unlock(&file->lock); 1659 spdk_bs_md_sync_blob(file->blob, __file_cache_finish_sync_bs_cb, file); 1660 } else { 1661 pthread_spin_unlock(&file->lock); 1662 __file_cache_finish_sync(file); 1663 } 1664 1665 __file_flush(args); 1666 } 1667 1668 static void 1669 __file_flush(void *_args) 1670 { 1671 struct spdk_fs_cb_args *args = _args; 1672 struct spdk_file *file = args->file; 1673 struct cache_buffer *next; 1674 uint64_t offset, length, start_page, num_pages; 1675 uint32_t page_size; 1676 1677 pthread_spin_lock(&file->lock); 1678 next = spdk_tree_find_buffer(file->tree, file->length_flushed); 1679 if (next == NULL || next->in_progress) { 1680 /* 1681 * There is either no data to flush, or a flush I/O is already in 1682 * progress. So return immediately - if a flush I/O is in 1683 * progress we will flush more data after that is completed. 1684 */ 1685 __free_args(args); 1686 pthread_spin_unlock(&file->lock); 1687 return; 1688 } 1689 1690 offset = next->offset + next->bytes_flushed; 1691 length = next->bytes_filled - next->bytes_flushed; 1692 if (length == 0) { 1693 __free_args(args); 1694 pthread_spin_unlock(&file->lock); 1695 return; 1696 } 1697 args->op.flush.length = length; 1698 args->op.flush.cache_buffer = next; 1699 1700 __get_page_parameters(file, offset, length, &start_page, &page_size, &num_pages); 1701 1702 next->in_progress = true; 1703 BLOBFS_TRACE(file, "offset=%jx length=%jx page start=%jx num=%jx\n", 1704 offset, length, start_page, num_pages); 1705 pthread_spin_unlock(&file->lock); 1706 spdk_bs_io_write_blob(file->blob, file->fs->sync_fs_channel->bs_channel, 1707 next->buf + (start_page * page_size) - next->offset, 1708 start_page, num_pages, 1709 __file_flush_done, args); 1710 } 1711 1712 static void 1713 __file_extend_done(void *arg, int bserrno) 1714 { 1715 struct spdk_fs_cb_args *args = arg; 1716 1717 __wake_caller(args); 1718 } 1719 1720 static void 1721 __file_extend_blob(void *_args) 1722 { 1723 struct spdk_fs_cb_args *args = _args; 1724 struct spdk_file *file = args->file; 1725 1726 spdk_bs_md_resize_blob(file->blob, args->op.resize.num_clusters); 1727 1728 spdk_bs_md_sync_blob(file->blob, __file_extend_done, args); 1729 } 1730 1731 static void 1732 __rw_from_file_done(void *arg, int bserrno) 1733 { 1734 struct spdk_fs_cb_args *args = arg; 1735 1736 __wake_caller(args); 1737 __free_args(args); 1738 } 1739 1740 static void 1741 __rw_from_file(void *_args) 1742 { 1743 struct spdk_fs_cb_args *args = _args; 1744 struct spdk_file *file = args->file; 1745 1746 if (args->op.rw.is_read) { 1747 spdk_file_read_async(file, file->fs->sync_io_channel, args->op.rw.user_buf, 1748 args->op.rw.offset, args->op.rw.length, 1749 __rw_from_file_done, args); 1750 } else { 1751 spdk_file_write_async(file, file->fs->sync_io_channel, args->op.rw.user_buf, 1752 args->op.rw.offset, args->op.rw.length, 1753 __rw_from_file_done, args); 1754 } 1755 } 1756 1757 static int 1758 __send_rw_from_file(struct spdk_file *file, sem_t *sem, void *payload, 1759 uint64_t offset, uint64_t length, bool is_read) 1760 { 1761 struct spdk_fs_cb_args *args; 1762 1763 args = calloc(1, sizeof(*args)); 1764 if (args == NULL) { 1765 sem_post(sem); 1766 return -ENOMEM; 1767 } 1768 1769 args->file = file; 1770 args->sem = sem; 1771 args->op.rw.user_buf = payload; 1772 args->op.rw.offset = offset; 1773 args->op.rw.length = length; 1774 args->op.rw.is_read = is_read; 1775 file->fs->send_request(__rw_from_file, args); 1776 return 0; 1777 } 1778 1779 int 1780 spdk_file_write(struct spdk_file *file, struct spdk_io_channel *_channel, 1781 void *payload, uint64_t offset, uint64_t length) 1782 { 1783 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 1784 struct spdk_fs_cb_args *args; 1785 uint64_t rem_length, copy, blob_size, cluster_sz; 1786 uint32_t cache_buffers_filled = 0; 1787 uint8_t *cur_payload; 1788 struct cache_buffer *last; 1789 1790 BLOBFS_TRACE_RW(file, "offset=%jx length=%jx\n", offset, length); 1791 1792 if (length == 0) { 1793 return 0; 1794 } 1795 1796 if (offset != file->append_pos) { 1797 BLOBFS_TRACE(file, " error offset=%jx append_pos=%jx\n", offset, file->append_pos); 1798 return -EINVAL; 1799 } 1800 1801 pthread_spin_lock(&file->lock); 1802 file->open_for_writing = true; 1803 1804 if (file->last == NULL) { 1805 if (file->append_pos % CACHE_BUFFER_SIZE == 0) { 1806 cache_append_buffer(file); 1807 } else { 1808 int rc; 1809 1810 file->append_pos += length; 1811 rc = __send_rw_from_file(file, &channel->sem, payload, 1812 offset, length, false); 1813 pthread_spin_unlock(&file->lock); 1814 sem_wait(&channel->sem); 1815 return rc; 1816 } 1817 } 1818 1819 blob_size = __file_get_blob_size(file); 1820 1821 if ((offset + length) > blob_size) { 1822 struct spdk_fs_cb_args extend_args = {}; 1823 1824 cluster_sz = file->fs->bs_opts.cluster_sz; 1825 extend_args.sem = &channel->sem; 1826 extend_args.op.resize.num_clusters = __bytes_to_clusters((offset + length), cluster_sz); 1827 extend_args.file = file; 1828 BLOBFS_TRACE(file, "start resize to %u clusters\n", extend_args.op.resize.num_clusters); 1829 pthread_spin_unlock(&file->lock); 1830 file->fs->send_request(__file_extend_blob, &extend_args); 1831 sem_wait(&channel->sem); 1832 } 1833 1834 last = file->last; 1835 rem_length = length; 1836 cur_payload = payload; 1837 while (rem_length > 0) { 1838 copy = last->buf_size - last->bytes_filled; 1839 if (copy > rem_length) { 1840 copy = rem_length; 1841 } 1842 BLOBFS_TRACE_RW(file, " fill offset=%jx length=%jx\n", file->append_pos, copy); 1843 memcpy(&last->buf[last->bytes_filled], cur_payload, copy); 1844 file->append_pos += copy; 1845 if (file->length < file->append_pos) { 1846 file->length = file->append_pos; 1847 } 1848 cur_payload += copy; 1849 last->bytes_filled += copy; 1850 rem_length -= copy; 1851 if (last->bytes_filled == last->buf_size) { 1852 cache_buffers_filled++; 1853 last = cache_append_buffer(file); 1854 if (last == NULL) { 1855 BLOBFS_TRACE(file, "nomem\n"); 1856 pthread_spin_unlock(&file->lock); 1857 return -ENOMEM; 1858 } 1859 } 1860 } 1861 1862 if (cache_buffers_filled == 0) { 1863 pthread_spin_unlock(&file->lock); 1864 return 0; 1865 } 1866 1867 args = calloc(1, sizeof(*args)); 1868 if (args == NULL) { 1869 pthread_spin_unlock(&file->lock); 1870 return -ENOMEM; 1871 } 1872 1873 args->file = file; 1874 file->fs->send_request(__file_flush, args); 1875 pthread_spin_unlock(&file->lock); 1876 return 0; 1877 } 1878 1879 static void 1880 __readahead_done(void *arg, int bserrno) 1881 { 1882 struct spdk_fs_cb_args *args = arg; 1883 struct cache_buffer *cache_buffer = args->op.readahead.cache_buffer; 1884 struct spdk_file *file = args->file; 1885 1886 BLOBFS_TRACE(file, "offset=%jx\n", cache_buffer->offset); 1887 1888 pthread_spin_lock(&file->lock); 1889 cache_buffer->bytes_filled = args->op.readahead.length; 1890 cache_buffer->bytes_flushed = args->op.readahead.length; 1891 cache_buffer->in_progress = false; 1892 pthread_spin_unlock(&file->lock); 1893 1894 __free_args(args); 1895 } 1896 1897 static void 1898 __readahead(void *_args) 1899 { 1900 struct spdk_fs_cb_args *args = _args; 1901 struct spdk_file *file = args->file; 1902 uint64_t offset, length, start_page, num_pages; 1903 uint32_t page_size; 1904 1905 offset = args->op.readahead.offset; 1906 length = args->op.readahead.length; 1907 assert(length > 0); 1908 1909 __get_page_parameters(file, offset, length, &start_page, &page_size, &num_pages); 1910 1911 BLOBFS_TRACE(file, "offset=%jx length=%jx page start=%jx num=%jx\n", 1912 offset, length, start_page, num_pages); 1913 spdk_bs_io_read_blob(file->blob, file->fs->sync_fs_channel->bs_channel, 1914 args->op.readahead.cache_buffer->buf, 1915 start_page, num_pages, 1916 __readahead_done, args); 1917 } 1918 1919 static uint64_t 1920 __next_cache_buffer_offset(uint64_t offset) 1921 { 1922 return (offset + CACHE_BUFFER_SIZE) & ~(CACHE_TREE_LEVEL_MASK(0)); 1923 } 1924 1925 static void 1926 check_readahead(struct spdk_file *file, uint64_t offset) 1927 { 1928 struct spdk_fs_cb_args *args; 1929 1930 offset = __next_cache_buffer_offset(offset); 1931 if (spdk_tree_find_buffer(file->tree, offset) != NULL || file->length <= offset) { 1932 return; 1933 } 1934 1935 args = calloc(1, sizeof(*args)); 1936 if (args == NULL) { 1937 return; 1938 } 1939 1940 BLOBFS_TRACE(file, "offset=%jx\n", offset); 1941 1942 args->file = file; 1943 args->op.readahead.offset = offset; 1944 args->op.readahead.cache_buffer = cache_insert_buffer(file, offset); 1945 args->op.readahead.cache_buffer->in_progress = true; 1946 if (file->length < (offset + CACHE_BUFFER_SIZE)) { 1947 args->op.readahead.length = file->length & (CACHE_BUFFER_SIZE - 1); 1948 } else { 1949 args->op.readahead.length = CACHE_BUFFER_SIZE; 1950 } 1951 file->fs->send_request(__readahead, args); 1952 } 1953 1954 static int 1955 __file_read(struct spdk_file *file, void *payload, uint64_t offset, uint64_t length, sem_t *sem) 1956 { 1957 struct cache_buffer *buf; 1958 1959 buf = spdk_tree_find_filled_buffer(file->tree, offset); 1960 if (buf == NULL) { 1961 return __send_rw_from_file(file, sem, payload, offset, length, true); 1962 } 1963 1964 if ((offset + length) > (buf->offset + buf->bytes_filled)) { 1965 length = buf->offset + buf->bytes_filled - offset; 1966 } 1967 BLOBFS_TRACE(file, "read %p offset=%ju length=%ju\n", payload, offset, length); 1968 memcpy(payload, &buf->buf[offset - buf->offset], length); 1969 if ((offset + length) % CACHE_BUFFER_SIZE == 0) { 1970 pthread_spin_lock(&g_caches_lock); 1971 spdk_tree_remove_buffer(file->tree, buf); 1972 if (file->tree->present_mask == 0) { 1973 TAILQ_REMOVE(&g_caches, file, cache_tailq); 1974 } 1975 pthread_spin_unlock(&g_caches_lock); 1976 } 1977 1978 sem_post(sem); 1979 return 0; 1980 } 1981 1982 int64_t 1983 spdk_file_read(struct spdk_file *file, struct spdk_io_channel *_channel, 1984 void *payload, uint64_t offset, uint64_t length) 1985 { 1986 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 1987 uint64_t final_offset, final_length; 1988 uint32_t sub_reads = 0; 1989 int rc = 0; 1990 1991 pthread_spin_lock(&file->lock); 1992 1993 BLOBFS_TRACE_RW(file, "offset=%ju length=%ju\n", offset, length); 1994 1995 file->open_for_writing = false; 1996 1997 if (length == 0 || offset >= file->length) { 1998 pthread_spin_unlock(&file->lock); 1999 return 0; 2000 } 2001 2002 if (offset + length > file->length) { 2003 length = file->length - offset; 2004 } 2005 2006 if (offset != file->next_seq_offset) { 2007 file->seq_byte_count = 0; 2008 } 2009 file->seq_byte_count += length; 2010 file->next_seq_offset = offset + length; 2011 if (file->seq_byte_count >= CACHE_READAHEAD_THRESHOLD) { 2012 check_readahead(file, offset); 2013 check_readahead(file, offset + CACHE_BUFFER_SIZE); 2014 } 2015 2016 final_length = 0; 2017 final_offset = offset + length; 2018 while (offset < final_offset) { 2019 length = NEXT_CACHE_BUFFER_OFFSET(offset) - offset; 2020 if (length > (final_offset - offset)) { 2021 length = final_offset - offset; 2022 } 2023 rc = __file_read(file, payload, offset, length, &channel->sem); 2024 if (rc == 0) { 2025 final_length += length; 2026 } else { 2027 break; 2028 } 2029 payload += length; 2030 offset += length; 2031 sub_reads++; 2032 } 2033 pthread_spin_unlock(&file->lock); 2034 while (sub_reads-- > 0) { 2035 sem_wait(&channel->sem); 2036 } 2037 if (rc == 0) { 2038 return final_length; 2039 } else { 2040 return rc; 2041 } 2042 } 2043 2044 static void 2045 _file_sync(struct spdk_file *file, struct spdk_fs_channel *channel, 2046 spdk_file_op_complete cb_fn, void *cb_arg) 2047 { 2048 struct spdk_fs_request *sync_req; 2049 struct spdk_fs_request *flush_req; 2050 struct spdk_fs_cb_args *sync_args; 2051 struct spdk_fs_cb_args *flush_args; 2052 2053 BLOBFS_TRACE(file, "offset=%jx\n", file->append_pos); 2054 2055 pthread_spin_lock(&file->lock); 2056 if (file->append_pos <= file->length_flushed || file->last == NULL) { 2057 BLOBFS_TRACE(file, "done - no data to flush\n"); 2058 pthread_spin_unlock(&file->lock); 2059 cb_fn(cb_arg, 0); 2060 return; 2061 } 2062 2063 sync_req = alloc_fs_request(channel); 2064 assert(sync_req != NULL); 2065 sync_args = &sync_req->args; 2066 2067 flush_req = alloc_fs_request(channel); 2068 assert(flush_req != NULL); 2069 flush_args = &flush_req->args; 2070 2071 sync_args->file = file; 2072 sync_args->fn.file_op = cb_fn; 2073 sync_args->arg = cb_arg; 2074 sync_args->op.sync.offset = file->append_pos; 2075 TAILQ_INSERT_TAIL(&file->sync_requests, sync_req, args.op.sync.tailq); 2076 pthread_spin_unlock(&file->lock); 2077 2078 flush_args->file = file; 2079 channel->send_request(__file_flush, flush_args); 2080 } 2081 2082 int 2083 spdk_file_sync(struct spdk_file *file, struct spdk_io_channel *_channel) 2084 { 2085 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 2086 2087 _file_sync(file, channel, __sem_post, &channel->sem); 2088 sem_wait(&channel->sem); 2089 2090 return 0; 2091 } 2092 2093 void 2094 spdk_file_sync_async(struct spdk_file *file, struct spdk_io_channel *_channel, 2095 spdk_file_op_complete cb_fn, void *cb_arg) 2096 { 2097 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 2098 2099 _file_sync(file, channel, cb_fn, cb_arg); 2100 } 2101 2102 void 2103 spdk_file_set_priority(struct spdk_file *file, uint32_t priority) 2104 { 2105 BLOBFS_TRACE(file, "priority=%u\n", priority); 2106 file->priority = priority; 2107 2108 } 2109 2110 /* 2111 * Close routines 2112 */ 2113 2114 static void 2115 __file_close_async_done(void *ctx, int bserrno) 2116 { 2117 struct spdk_fs_request *req = ctx; 2118 struct spdk_fs_cb_args *args = &req->args; 2119 2120 args->fn.file_op(args->arg, bserrno); 2121 free_fs_request(req); 2122 } 2123 2124 static void 2125 __file_close_async(struct spdk_file *file, struct spdk_fs_request *req) 2126 { 2127 pthread_spin_lock(&file->lock); 2128 if (file->ref_count == 0) { 2129 pthread_spin_unlock(&file->lock); 2130 __file_close_async_done(req, -EBADF); 2131 return; 2132 } 2133 2134 file->ref_count--; 2135 if (file->ref_count > 0) { 2136 pthread_spin_unlock(&file->lock); 2137 __file_close_async_done(req, 0); 2138 return; 2139 } 2140 2141 pthread_spin_unlock(&file->lock); 2142 2143 spdk_bs_md_close_blob(&file->blob, __file_close_async_done, req); 2144 } 2145 2146 static void 2147 __file_close_async__sync_done(void *arg, int fserrno) 2148 { 2149 struct spdk_fs_request *req = arg; 2150 struct spdk_fs_cb_args *args = &req->args; 2151 2152 __file_close_async(args->file, req); 2153 } 2154 2155 void 2156 spdk_file_close_async(struct spdk_file *file, spdk_file_op_complete cb_fn, void *cb_arg) 2157 { 2158 struct spdk_fs_request *req; 2159 struct spdk_fs_cb_args *args; 2160 2161 req = alloc_fs_request(file->fs->md_fs_channel); 2162 if (req == NULL) { 2163 cb_fn(cb_arg, -ENOMEM); 2164 return; 2165 } 2166 2167 args = &req->args; 2168 args->file = file; 2169 args->fn.file_op = cb_fn; 2170 args->arg = cb_arg; 2171 2172 spdk_file_sync_async(file, file->fs->md_io_channel, __file_close_async__sync_done, req); 2173 } 2174 2175 static void 2176 __file_close_done(void *arg, int fserrno) 2177 { 2178 struct spdk_fs_cb_args *args = arg; 2179 2180 args->rc = fserrno; 2181 sem_post(args->sem); 2182 } 2183 2184 static void 2185 __file_close(void *arg) 2186 { 2187 struct spdk_fs_request *req = arg; 2188 struct spdk_fs_cb_args *args = &req->args; 2189 struct spdk_file *file = args->file; 2190 2191 __file_close_async(file, req); 2192 } 2193 2194 int 2195 spdk_file_close(struct spdk_file *file, struct spdk_io_channel *_channel) 2196 { 2197 struct spdk_fs_channel *channel = spdk_io_channel_get_ctx(_channel); 2198 struct spdk_fs_request *req; 2199 struct spdk_fs_cb_args *args; 2200 2201 req = alloc_fs_request(channel); 2202 assert(req != NULL); 2203 2204 args = &req->args; 2205 2206 spdk_file_sync(file, _channel); 2207 BLOBFS_TRACE(file, "name=%s\n", file->name); 2208 args->file = file; 2209 args->sem = &channel->sem; 2210 args->fn.file_op = __file_close_done; 2211 args->arg = req; 2212 channel->send_request(__file_close, req); 2213 sem_wait(&channel->sem); 2214 2215 return args->rc; 2216 } 2217 2218 static void 2219 cache_free_buffers(struct spdk_file *file) 2220 { 2221 BLOBFS_TRACE(file, "free=%s\n", file->name); 2222 pthread_spin_lock(&file->lock); 2223 pthread_spin_lock(&g_caches_lock); 2224 if (file->tree->present_mask == 0) { 2225 pthread_spin_unlock(&g_caches_lock); 2226 pthread_spin_unlock(&file->lock); 2227 return; 2228 } 2229 spdk_tree_free_buffers(file->tree); 2230 if (file->tree->present_mask == 0) { 2231 TAILQ_REMOVE(&g_caches, file, cache_tailq); 2232 } 2233 file->last = NULL; 2234 pthread_spin_unlock(&g_caches_lock); 2235 pthread_spin_unlock(&file->lock); 2236 } 2237 2238 SPDK_LOG_REGISTER_TRACE_FLAG("blobfs", SPDK_TRACE_BLOBFS); 2239 SPDK_LOG_REGISTER_TRACE_FLAG("blobfs_rw", SPDK_TRACE_BLOBFS_RW); 2240