|  | // Copyright 2016 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. | 
|  |  | 
|  | // This file describes the in-memory structures which construct | 
|  | // a MinFS filesystem. | 
|  |  | 
|  | #ifndef SRC_STORAGE_MINFS_BCACHE_H_ | 
|  | #define SRC_STORAGE_MINFS_BCACHE_H_ | 
|  |  | 
|  | #include <errno.h> | 
|  | #include <inttypes.h> | 
|  |  | 
|  | #include <atomic> | 
|  | #include <shared_mutex> | 
|  |  | 
|  | #include <fbl/algorithm.h> | 
|  | #include <fbl/array.h> | 
|  | #include <fbl/macros.h> | 
|  | #include <fbl/unique_fd.h> | 
|  |  | 
|  | #include "src/storage/minfs/format.h" | 
|  |  | 
|  | #ifdef __Fuchsia__ | 
|  | #include <fuchsia/hardware/block/c/fidl.h> | 
|  | #include <lib/zx/vmo.h> | 
|  |  | 
|  | #include <block-client/cpp/block-device.h> | 
|  | #include <block-client/cpp/client.h> | 
|  | #include <fs/transaction/device_transaction_handler.h> | 
|  | #include <storage/buffer/vmo_buffer.h> | 
|  | #include <storage/buffer/vmoid_registry.h> | 
|  | #else | 
|  | #include <fbl/vector.h> | 
|  | #include <fs/transaction/transaction_handler.h> | 
|  | #endif | 
|  |  | 
|  | namespace minfs { | 
|  |  | 
|  | #ifdef __Fuchsia__ | 
|  |  | 
|  | // A helper function for converting "fd" to "BlockDevice". | 
|  | zx_status_t FdToBlockDevice(fbl::unique_fd& fd, std::unique_ptr<block_client::BlockDevice>* out); | 
|  |  | 
|  | class Bcache : public fs::DeviceTransactionHandler, public storage::VmoidRegistry { | 
|  | public: | 
|  | // Not copyable or movable | 
|  | Bcache(const Bcache&) = delete; | 
|  | Bcache& operator=(const Bcache&) = delete; | 
|  | Bcache(Bcache&&) = delete; | 
|  | Bcache& operator=(Bcache&&) = delete; | 
|  |  | 
|  | ~Bcache() = default; | 
|  |  | 
|  | // Destroys a "bcache" object, but take back ownership of the underlying block device. | 
|  | static std::unique_ptr<block_client::BlockDevice> Destroy(std::unique_ptr<Bcache> bcache); | 
|  |  | 
|  | //////////////// | 
|  | // fs::TransactionHandler interface. | 
|  |  | 
|  | zx_status_t RunRequests(const std::vector<storage::BufferedOperation>& operations) override { | 
|  | std::shared_lock lock(mutex_); | 
|  | return DeviceTransactionHandler::RunRequests(operations); | 
|  | } | 
|  |  | 
|  | uint64_t BlockNumberToDevice(uint64_t block_num) const final { | 
|  | return block_num * kMinfsBlockSize / info_.block_size; | 
|  | } | 
|  |  | 
|  | block_client::BlockDevice* GetDevice() final { return device_; } | 
|  |  | 
|  | uint32_t DeviceBlockSize() const; | 
|  |  | 
|  | // Raw block read functions. | 
|  | // These do not track blocks (or attempt to access the block cache) | 
|  | // NOTE: Not marked as final, since these are overridden methods on host, | 
|  | // but not on __Fuchsia__. | 
|  | zx_status_t Readblk(blk_t bno, void* data); | 
|  | zx_status_t Writeblk(blk_t bno, const void* data); | 
|  |  | 
|  | // TODO(rvargas): Move this to BlockDevice. | 
|  | // VmoidRegistry interface: | 
|  | zx_status_t BlockAttachVmo(const zx::vmo& vmo, storage::Vmoid* out) final; | 
|  | zx_status_t BlockDetachVmo(storage::Vmoid vmoid) final; | 
|  |  | 
|  | //////////////// | 
|  | // Other methods. | 
|  |  | 
|  | // This factory allows building this object from a BlockDevice. Bcache can take ownership of the | 
|  | // device (the first Create method), or not (the second Create method). | 
|  | static zx_status_t Create(std::unique_ptr<block_client::BlockDevice> device, uint32_t max_blocks, | 
|  | std::unique_ptr<Bcache>* out); | 
|  |  | 
|  | static zx_status_t Create(block_client::BlockDevice* device, uint32_t max_blocks, | 
|  | std::unique_ptr<Bcache>* out); | 
|  |  | 
|  | // Returns the maximum number of available blocks, | 
|  | // assuming the filesystem is non-resizable. | 
|  | uint32_t Maxblk() const { return max_blocks_; } | 
|  |  | 
|  | block_client::BlockDevice* device() { return device_; } | 
|  | const block_client::BlockDevice* device() const { return device_; } | 
|  |  | 
|  | zx_status_t Sync(); | 
|  |  | 
|  | // Blocks all I/O operations to the underlying device (that go via the RunRequests method). This | 
|  | // does *not* block operations that go directly to the device. | 
|  | void Pause(); | 
|  |  | 
|  | // Resumes all I/O operations paused by the Pause method. | 
|  | void Resume(); | 
|  |  | 
|  | private: | 
|  | friend class BlockNode; | 
|  |  | 
|  | Bcache(block_client::BlockDevice* device, uint32_t max_blocks); | 
|  |  | 
|  | // Used during initialization of this object. | 
|  | zx_status_t VerifyDeviceInfo(); | 
|  |  | 
|  | uint32_t max_blocks_; | 
|  | fuchsia_hardware_block_BlockInfo info_ = {}; | 
|  | std::unique_ptr<block_client::BlockDevice> owned_device_;  // The device, if owned. | 
|  | block_client::BlockDevice* device_;  // Pointer to the device, irrespective of ownership. | 
|  | // This buffer is used as internal scratch space for the "Readblk/Writeblk" methods. | 
|  | storage::VmoBuffer buffer_; | 
|  | std::shared_mutex mutex_; | 
|  | }; | 
|  |  | 
|  | #else  // __Fuchsia__ | 
|  |  | 
|  | class Bcache : public fs::TransactionHandler { | 
|  | public: | 
|  | // Not copyable or movable | 
|  | Bcache(const Bcache&) = delete; | 
|  | Bcache& operator=(const Bcache&) = delete; | 
|  | Bcache(Bcache&&) = delete; | 
|  | Bcache& operator=(Bcache&&) = delete; | 
|  |  | 
|  | ~Bcache() {} | 
|  |  | 
|  | //////////////// | 
|  | // fs::TransactionHandler interface. | 
|  |  | 
|  | uint64_t BlockNumberToDevice(uint64_t block_num) const final { return block_num; } | 
|  |  | 
|  | zx_status_t RunRequests(const std::vector<storage::BufferedOperation>& operations) final; | 
|  |  | 
|  | // Raw block read functions. | 
|  | // These do not track blocks (or attempt to access the block cache) | 
|  | // NOTE: Not marked as final, since these are overridden methods on host, | 
|  | // but not on __Fuchsia__. | 
|  | zx_status_t Readblk(blk_t bno, void* data); | 
|  | zx_status_t Writeblk(blk_t bno, const void* data); | 
|  |  | 
|  | //////////////// | 
|  | // Other methods. | 
|  |  | 
|  | static zx_status_t Create(fbl::unique_fd fd, uint32_t max_blocks, std::unique_ptr<Bcache>* out); | 
|  |  | 
|  | // Returns the maximum number of available blocks, | 
|  | // assuming the filesystem is non-resizable. | 
|  | uint32_t Maxblk() const { return max_blocks_; } | 
|  |  | 
|  | // Lengths of each extent (in bytes) | 
|  | fbl::Array<size_t> extent_lengths_; | 
|  | // Tell Bcache to look for Minfs partition starting at |offset| bytes | 
|  | zx_status_t SetOffset(off_t offset); | 
|  | // Tell the Bcache it is pointing at a sparse file | 
|  | // |offset| indicates where the minfs partition begins within the file | 
|  | // |extent_lengths| contains the length of each extent (in bytes) | 
|  | zx_status_t SetSparse(off_t offset, const fbl::Vector<size_t>& extent_lengths); | 
|  |  | 
|  | int Sync(); | 
|  |  | 
|  | private: | 
|  | friend class BlockNode; | 
|  |  | 
|  | Bcache(fbl::unique_fd fd, uint32_t max_blocks); | 
|  |  | 
|  | const fbl::unique_fd fd_; | 
|  | uint32_t max_blocks_; | 
|  | off_t offset_ = 0; | 
|  | }; | 
|  |  | 
|  | #endif | 
|  |  | 
|  | }  // namespace minfs | 
|  |  | 
|  | #endif  // SRC_STORAGE_MINFS_BCACHE_H_ |