| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <fbl/auto_lock.h> |
| #include <fs/paged_vfs.h> |
| #include <fs/paged_vnode.h> |
| |
| namespace fs { |
| |
| PagedVfs::PagedVfs(int num_pager_threads) { |
| pager_pool_ = std::make_unique<PagerThreadPool>(*this, num_pager_threads); |
| } |
| |
| PagedVfs::~PagedVfs() { |
| // TODO(fxbug.dev/51111) need to detach from PagedVnodes that have back-references to this class. |
| // The vnodes are reference counted and can outlive this class. |
| } |
| |
| zx::status<> PagedVfs::Init() { |
| if (zx_status_t status = zx::pager::create(0, &pager_); status != ZX_OK) |
| return zx::error(status); |
| |
| return pager_pool_->Init(); |
| } |
| |
| zx::status<> PagedVfs::SupplyPages(PagedVnode& node, uint64_t offset, uint64_t length, |
| zx::vmo& aux_vmo, uint64_t aux_offset) { |
| return zx::make_status(pager_.supply_pages(node.vmo(), offset, length, aux_vmo, aux_offset)); |
| } |
| |
| zx::status<> PagedVfs::ReportPagerError(PagedVnode& node, uint32_t op, uint64_t offset, |
| uint64_t length, uint64_t data) { |
| return zx::make_status(pager_.op_range(op, node.vmo(), offset, length, data)); |
| } |
| |
| zx::status<zx::vmo> PagedVfs::CreatePagedNodeVmo(fbl::RefPtr<PagedVnode> node, uint64_t size) { |
| // Register this node with a unique ID to associated it with pager requests. |
| uint64_t id; |
| { |
| fbl::AutoLock lock(&vfs_lock_); |
| |
| id = next_node_id_; |
| ++next_node_id_; |
| |
| paged_nodes_[id] = std::move(node); |
| } |
| |
| zx::vmo vmo; |
| if (auto status = pager_.create_vmo(0, pager_pool_->port(), id, size, &vmo); status != ZX_OK) { |
| // On error we need to undo the owning reference from above. This would be simpler if we only |
| // store the reference once the VMO was created, but that would require two separate lock |
| // steps. |
| fbl::AutoLock lock(&vfs_lock_); |
| paged_nodes_.erase(id); |
| return zx::error(status); |
| } |
| |
| return zx::ok(std::move(vmo)); |
| } |
| |
| void PagedVfs::PagerVmoRead(uint64_t node_id, uint64_t offset, uint64_t length) { |
| // Hold a reference to the object to ensure it doesn't go out of scope during processing. |
| fbl::RefPtr<PagedVnode> node; |
| |
| { |
| fbl::AutoLock lock(&vfs_lock_); |
| |
| auto found = paged_nodes_.find(node_id); |
| if (found == paged_nodes_.end()) |
| return; // Possible race with completion message on another thread, ignore. |
| |
| node = fbl::RefPtr<PagedVnode>(found->second); |
| } |
| |
| // Handle the request outside the lock while holding a reference to the node. |
| node->VmoRead(offset, length); |
| } |
| |
| } // namespace fs |