blob: 0bbf08a4742e3f08377743296f076852cff274b1 [file] [log] [blame]
// Copyright 2022 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.
// clang-format off
#include "src/storage/f2fs/f2fs.h"
#include "src/storage/f2fs/test/compatibility/file_backed_block_device.h"
// clang-format on
namespace f2fs {
FileBackedBlockDevice::FileBackedBlockDevice(fbl::unique_fd fd, const uint64_t block_count,
const uint32_t block_size)
: fd_(std::move(fd)), block_count_(block_count), block_size_(block_size) {}
zx_status_t FileBackedBlockDevice::FifoTransaction(block_fifo_request_t* requests, size_t count) {
std::lock_guard mutex_lock(mutex_);
for (size_t i = 0; i < count; ++i) {
switch (requests[i].command.opcode) {
case BLOCK_OPCODE_READ: {
vmoid_t vmoid = requests[i].vmoid;
zx::vmo& target_vmoid = vmos_.at(vmoid);
auto buffer = std::make_unique<uint8_t[]>(block_size_);
for (size_t j = 0; j < requests[i].length; ++j) {
uint64_t offset = (requests[i].dev_offset + j) * block_size_;
if (lseek(fd_.get(), offset, SEEK_SET) < 0) {
FX_LOGS(ERROR) << "seek for read failed at " << offset << ". " << errno;
return ZX_ERR_IO;
}
if (size_t ret = read(fd_.get(), buffer.get(), block_size_); ret != block_size_) {
FX_LOGS(ERROR) << "read failed at " << offset;
return ZX_ERR_IO;
}
offset = (requests[i].vmo_offset + j) * block_size_;
if (zx_status_t status = target_vmoid.write(buffer.get(), offset, block_size_);
status != ZX_OK) {
FX_LOGS(ERROR) << "Write to buffer failed: offset=" << offset
<< ", block_size_=" << block_size_;
return status;
}
}
break;
}
case BLOCK_OPCODE_WRITE: {
vmoid_t vmoid = requests[i].vmoid;
zx::vmo& target_vmoid = vmos_.at(vmoid);
auto buffer = std::make_unique<uint8_t[]>(block_size_);
for (size_t j = 0; j < requests[i].length; j++) {
uint64_t offset = (requests[i].vmo_offset + j) * block_size_;
if (zx_status_t status = target_vmoid.read(buffer.get(), offset, block_size_);
status != ZX_OK) {
FX_LOGS(ERROR) << "Read from buffer failed: offset=" << offset
<< ", block_size_=" << block_size_;
return status;
}
offset = (requests[i].dev_offset + j) * block_size_;
if (lseek(fd_.get(), offset, SEEK_SET) < 0) {
FX_LOGS(ERROR) << "seek for write failed at " << offset << ". " << errno;
return ZX_ERR_IO;
}
if (size_t ret = write(fd_.get(), buffer.get(), block_size_); ret != block_size_) {
FX_LOGS(ERROR) << "write failed at " << offset;
return ZX_ERR_IO;
}
}
break;
}
case BLOCK_OPCODE_FLUSH:
continue;
case BLOCK_OPCODE_CLOSE_VMO:
vmos_.erase(requests[i].vmoid);
break;
case BLOCK_OPCODE_TRIM:
// TODO: support trim using truncate
default:
return ZX_ERR_NOT_SUPPORTED;
}
}
return ZX_OK;
}
zx_status_t FileBackedBlockDevice::BlockGetInfo(
fuchsia_hardware_block::wire::BlockInfo* out_info) const {
out_info->block_count = block_count_;
out_info->block_size = block_size_;
out_info->flags = block_info_flags_;
out_info->max_transfer_size = max_transfer_size_;
return ZX_OK;
}
zx_status_t FileBackedBlockDevice::BlockAttachVmo(const zx::vmo& vmo, storage::Vmoid* out_vmoid) {
zx::vmo xfer_vmo;
zx_status_t status = vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &xfer_vmo);
if (status != ZX_OK) {
return status;
}
std::lock_guard mutex_lock(mutex_);
// Find a free vmoid.
vmoid_t vmoid = 1;
for (const auto& [used_vmoid, vmo] : vmos_) {
if (used_vmoid > vmoid) {
break;
}
if (used_vmoid == std::numeric_limits<vmoid_t>::max()) {
return ZX_ERR_NO_RESOURCES;
}
vmoid = used_vmoid + 1;
}
vmos_.insert(std::make_pair(vmoid, std::move(xfer_vmo)));
*out_vmoid = storage::Vmoid(vmoid);
return ZX_OK;
}
} // namespace f2fs