blob: 7247d2512561da867efbf42bbaf161b19c1a0979 [file] [log] [blame]
// 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 <lib/zx/status.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 <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 <fbl/vector.h>
#include "src/lib/storage/vfs/cpp/transaction/transaction_handler.h"
#endif
namespace minfs {
#ifdef __Fuchsia__
// A helper function for converting "fd" to "BlockDevice".
zx::status<std::unique_ptr<block_client::BlockDevice>> FdToBlockDevice(fbl::unique_fd& fd);
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<> Readblk(blk_t bno, void* data);
zx::status<> 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<std::unique_ptr<Bcache>> Create(
std::unique_ptr<block_client::BlockDevice> device, uint32_t max_blocks);
static zx::status<std::unique_ptr<Bcache>> Create(block_client::BlockDevice* device,
uint32_t max_blocks);
// 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<> 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<> 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;
////////////////
// 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<> Readblk(blk_t bno, void* data);
zx::status<> Writeblk(blk_t bno, const void* data);
////////////////
// Other methods.
static zx::status<std::unique_ptr<Bcache>> Create(fbl::unique_fd fd, uint32_t max_blocks);
// 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<> 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<> SetSparse(off_t offset, const fbl::Vector<size_t>& extent_lengths);
zx::status<> 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_