blob: 2228089b386e6b0b0729ba4b32cbb2ba0ed02d62 [file] [log] [blame]
// 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.
// This file describes the in-memory structures which construct
// a F2FS filesystem.
#ifndef SRC_STORAGE_F2FS_BCACHE_H_
#define SRC_STORAGE_F2FS_BCACHE_H_
#ifdef __Fuchsia__
#include <lib/zx/vmo.h>
#include <storage/buffer/vmo_buffer.h>
#include <storage/buffer/vmoid_registry.h>
#include "src/lib/storage/block_client/cpp/block_device.h"
#include "src/lib/storage/block_client/cpp/client.h"
#include "src/lib/storage/vfs/cpp/transaction/device_transaction_handler.h"
#else
#include <storage/buffer/array_buffer.h>
#include "src/lib/storage/vfs/cpp/transaction/transaction_handler.h"
#endif // __Fuchsia__
#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>
namespace f2fs {
#ifdef __Fuchsia__
class Bcache;
zx_status_t CreateBcache(std::unique_ptr<block_client::BlockDevice> device, bool* out_readonly,
std::unique_ptr<Bcache>* out);
class Bcache : public fs::DeviceTransactionHandler, public storage::VmoidRegistry {
#else // __Fuchsia__
class Bcache : public fs::TransactionHandler {
#endif // __Fuchsia__
public:
// Not copyable or movable
Bcache(const Bcache&) = delete;
Bcache& operator=(const Bcache&) = delete;
Bcache(Bcache&&) = delete;
Bcache& operator=(Bcache&&) = delete;
// Make a read/write operation from/to a 4KiB block at |bno|.
// |buffer_| is used as a block buffer.
zx_status_t Readblk(block_t bno, void* data) __TA_EXCLUDES(buffer_mutex_);
zx_status_t Writeblk(block_t bno, const void* data) __TA_EXCLUDES(buffer_mutex_);
zx_status_t Trim(block_t start, block_t num);
// 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() { mutex_.lock(); }
// Resumes all I/O operations paused by the Pause method.
void Resume() { mutex_.unlock(); }
uint64_t Maxblk() const { return max_blocks_; }
block_t BlockSize() const { return block_size_; }
zx_status_t RunRequests(const std::vector<storage::BufferedOperation>& operations) override;
#ifdef __Fuchsia__
// 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, uint64_t max_blocks,
block_t block_size, std::unique_ptr<Bcache>* out);
static zx_status_t Create(block_client::BlockDevice* device, uint64_t max_blocks,
block_t block_size, std::unique_ptr<Bcache>* out);
zx_status_t Flush() override { return DeviceTransactionHandler::Flush(); }
zx_status_t BlockAttachVmo(const zx::vmo& vmo, storage::Vmoid* out) final;
zx_status_t BlockDetachVmo(storage::Vmoid vmoid) final;
zx_status_t CreateVmoBuffer() __TA_EXCLUDES(buffer_mutex_) {
std::lock_guard lock(buffer_mutex_);
return buffer_.Initialize(this, 1, block_size_, "scratch-block");
}
void DestroyVmoBuffer() __TA_EXCLUDES(buffer_mutex_) {
std::lock_guard lock(buffer_mutex_);
__UNUSED auto unused = std::move(buffer_);
}
uint64_t BlockNumberToDevice(uint64_t block_num) const final {
return block_num * BlockSize() / info_.block_size;
}
uint64_t DeviceBlockSize() const { return info_.block_size; }
block_client::BlockDevice* GetDevice() final { return device_; }
// 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);
#else // __Fuchsia__
static zx_status_t Create(fbl::unique_fd fd, uint64_t max_blocks, std::unique_ptr<Bcache>* out);
zx_status_t Flush() override { return TransactionHandler::Flush(); }
uint64_t BlockNumberToDevice(uint64_t block_num) const final { return block_num; }
zx_status_t RunOperation(const storage::Operation& operation,
storage::BlockBuffer* buffer) override;
#endif
private:
friend class BlockNode;
// Used during initialization of this object.
zx_status_t VerifyDeviceInfo();
const uint64_t max_blocks_;
std::mutex buffer_mutex_;
std::shared_mutex mutex_;
#ifdef __Fuchsia__
Bcache(block_client::BlockDevice* device, uint64_t max_blocks, block_t block_size);
const block_t block_size_;
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.
// |buffer_| and |buffer_mutex_| are used in the "Readblk/Writeblk" methods.
storage::VmoBuffer buffer_ __TA_GUARDED(buffer_mutex_);
#else // __Fuchsia__
Bcache(fbl::unique_fd fd, uint64_t max_blocks);
const block_t block_size_ = kBlockSize;
const fbl::unique_fd fd_;
storage::ArrayBuffer buffer_ __TA_GUARDED(buffer_mutex_);
#endif // __Fuchsia__
};
} // namespace f2fs
#endif // SRC_STORAGE_F2FS_BCACHE_H_