blob: e146bcfa167a304ffa66a9b9e8a2389f1ac9057f [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.
#include "f2fs.h"
#include <assert.h>
#include <fuchsia/device/c/fidl.h>
#include <fuchsia/io/llcpp/fidl.h>
#include <lib/fdio/cpp/caller.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace/event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <utility>
#include <block-client/cpp/remote-block-device.h>
#include <fbl/alloc_checker.h>
#include <fbl/ref_ptr.h>
#include <storage/buffer/block_buffer.h>
#include <storage/buffer/vmo_buffer.h>
#include <storage/operation/operation.h>
namespace f2fs {
std::unique_ptr<block_client::BlockDevice> Bcache::Destroy(std::unique_ptr<Bcache> bcache) {
{
// Destroy the VmoBuffer before extracting the underlying device, as it needs
// to de-register itself from the underlying block device to be terminated.
__UNUSED auto unused = std::move(bcache->buffer_);
}
return std::move(bcache->owned_device_);
}
zx_status_t Bcache::Readblk(block_t bno, void* data) {
TRACE_DURATION("f2fs", "Bcache::Readblk", "blk", bno);
storage::Operation operation = {};
operation.type = storage::OperationType::kRead;
operation.vmo_offset = 0;
operation.dev_offset = bno;
operation.length = 1;
zx_status_t status = RunOperation(operation, &buffer_);
if (status != ZX_OK) {
return status;
}
memcpy(data, buffer_.Data(0), BlockSize());
return ZX_OK;
}
zx_status_t Bcache::Writeblk(block_t bno, const void* data) {
TRACE_DURATION("f2fs", "Bcache::Writeblk", "blk", bno);
storage::Operation operation = {};
operation.type = storage::OperationType::kWrite;
operation.vmo_offset = 0;
operation.dev_offset = bno;
operation.length = 1;
memcpy(buffer_.Data(0), data, BlockSize());
return RunOperation(operation, &buffer_);
}
zx_status_t Bcache::BlockAttachVmo(const zx::vmo& vmo, storage::Vmoid* out) {
return device()->BlockAttachVmo(vmo, out);
}
zx_status_t Bcache::BlockDetachVmo(storage::Vmoid vmoid) {
return device()->BlockDetachVmo(std::move(vmoid));
}
zx_status_t Bcache::Sync() {
block_fifo_request_t request = {};
request.opcode = BLOCKIO_FLUSH;
return device_->FifoTransaction(&request, 1);
}
zx_status_t FdToBlockDevice(fbl::unique_fd& fd, std::unique_ptr<block_client::BlockDevice>* out) {
zx::channel channel, server;
zx_status_t status = zx::channel::create(0, &channel, &server);
if (status != ZX_OK) {
return status;
}
fdio_cpp::UnownedFdioCaller caller(fd.get());
status =
::fuchsia_io::Node::Call::Clone(zx::unowned_channel(caller.borrow_channel()),
::fuchsia_io::wire::CLONE_FLAG_SAME_RIGHTS, std::move(server))
.status();
if (status != ZX_OK) {
return status;
}
std::unique_ptr<block_client::RemoteBlockDevice> device;
status = block_client::RemoteBlockDevice::Create(std::move(channel), &device);
if (status != ZX_OK) {
FX_LOGS(ERROR) << "cannot create block device: " << status;
return status;
}
*out = std::move(device);
return ZX_OK;
}
zx_status_t Bcache::Create(std::unique_ptr<block_client::BlockDevice> device, uint32_t max_blocks,
std::unique_ptr<Bcache>* out) {
zx_status_t status = Create(device.get(), max_blocks, out);
if (status == ZX_OK) {
(*out)->owned_device_ = std::move(device);
}
return status;
}
zx_status_t Bcache::Create(block_client::BlockDevice* device, uint32_t max_blocks,
std::unique_ptr<Bcache>* out) {
std::unique_ptr<Bcache> bcache(new Bcache(device, max_blocks, kF2fsBlockSize));
zx_status_t status = bcache->buffer_.Initialize(bcache.get(), 1, kF2fsBlockSize, "scratch-block");
if (status != ZX_OK) {
return status;
}
status = bcache->VerifyDeviceInfo();
if (status != ZX_OK) {
return status;
}
*out = std::move(bcache);
return ZX_OK;
}
zx_status_t Bcache::Create(std::unique_ptr<block_client::BlockDevice> device, uint32_t max_blocks,
std::unique_ptr<Bcache>* out, uint32_t block_size) {
zx_status_t status = Create(device.get(), max_blocks, out, block_size);
if (status == ZX_OK) {
(*out)->owned_device_ = std::move(device);
}
return status;
}
zx_status_t Bcache::Create(block_client::BlockDevice* device, uint32_t max_blocks,
std::unique_ptr<Bcache>* out, uint32_t block_size) {
std::unique_ptr<Bcache> bcache(new Bcache(device, max_blocks, block_size));
zx_status_t status = bcache->buffer_.Initialize(bcache.get(), 1, block_size, "scratch-block");
if (status != ZX_OK) {
return status;
}
status = bcache->VerifyDeviceInfo();
if (status != ZX_OK) {
return status;
}
*out = std::move(bcache);
return ZX_OK;
}
uint32_t Bcache::DeviceBlockSize() const { return info_.block_size; }
Bcache::Bcache(block_client::BlockDevice* device, uint32_t max_blocks, uint32_t block_size)
: max_blocks_(max_blocks), block_size_(block_size), device_(device) {}
zx_status_t Bcache::VerifyDeviceInfo() {
zx_status_t status = device_->BlockGetInfo(&info_);
if (status != ZX_OK) {
FX_LOGS(ERROR) << "cannot get block device information: " << status;
return status;
}
if (BlockSize() % info_.block_size != 0) {
FX_LOGS(ERROR) << "minfs Block size not multiple of underlying block size: "
<< info_.block_size;
return ZX_ERR_BAD_STATE;
}
return ZX_OK;
}
void Bcache::Pause() { mutex_.lock(); }
void Bcache::Resume() { mutex_.unlock(); }
} // namespace f2fs