blob: a62d6f9294da5f36e282626a93f06ce5c9bfccaa [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 "src/storage/volume_image/ftl/ftl_io.h"
#include <iostream>
#include <memory>
namespace storage::volume_image {
class FtlReader final : public Reader {
public:
explicit FtlReader(std::shared_ptr<FtlInstance> instance, std::shared_ptr<ftl::Volume> volume,
uint64_t length)
: instance_(std::move(instance)), volume_(std::move(volume)), length_(length) {}
uint64_t length() const final { return length_; }
fpromise::result<void, std::string> Read(uint64_t offset,
cpp20::span<uint8_t> buffer) const final {
if (offset % instance_->page_size() != 0) {
return fpromise::error("FtlReader requires aligned offset(" + std::to_string(offset) +
") at page boundaries(" + std::to_string(instance_->page_size()) +
").");
}
if (buffer.size() % instance_->page_size() != 0) {
return fpromise::error("FtlReader requires aligned page buffer(size " +
std::to_string(buffer.size()) + ") at page boundaries(" +
std::to_string(instance_->page_size()) + ").");
}
uint32_t page_offset = static_cast<uint32_t>(offset / instance_->page_size());
int page_count = static_cast<int>(buffer.size() / instance_->page_size());
if (page_count == 0) {
return fpromise::ok();
}
uint64_t page_range_end = page_offset + page_count;
if (page_range_end > instance_->page_count()) {
return fpromise::error("FtlReader::Read out of bounds. Offset " + std::to_string(offset) +
" (Page: " + std::to_string(page_offset) + ")" +
" attempting to write " + std::to_string(buffer.size()) +
" bytes (Page Count: " + std::to_string(page_count) +
"), exceeds maximum offset of " + std::to_string(offset) +
"(Page Size: " + std::to_string(instance_->page_size()) +
", Page Count: " + std::to_string(instance_->page_count()) + ").");
}
if (auto result = volume_->Read(page_offset, page_count, buffer.data()); result != ZX_OK) {
return fpromise::error("Failed to read " + std::to_string(page_count) +
" pages starting at " + std::to_string(page_offset) +
". More specifically: " + std::to_string(result) + ".");
}
return fpromise::ok();
}
private:
std::shared_ptr<FtlInstance> instance_;
std::shared_ptr<ftl::Volume> volume_;
uint64_t length_ = 0;
};
class FtlWriter final : public Writer {
public:
explicit FtlWriter(std::shared_ptr<FtlInstance> instance, std::shared_ptr<ftl::Volume> volume)
: instance_(std::move(instance)), volume_(std::move(volume)) {}
~FtlWriter() final { volume_->Flush(); }
fpromise::result<void, std::string> Write(uint64_t offset,
cpp20::span<const uint8_t> buffer) final {
if (offset % instance_->page_size() != 0) {
return fpromise::error("FtlWriter requires aligned offset(" + std::to_string(offset) +
") at page boundaries(" + std::to_string(instance_->page_size()) +
").");
}
if (buffer.size() % instance_->page_size() != 0) {
return fpromise::error("FtlWriter requires aligned page buffer(size " +
std::to_string(buffer.size()) + ") at page boundaries(" +
std::to_string(instance_->page_size()) + ").");
}
uint32_t page_offset = static_cast<uint32_t>(offset / instance_->page_size());
int page_count = static_cast<int>(buffer.size() / instance_->page_size());
if (page_count == 0) {
return fpromise::ok();
}
uint64_t page_range_end = page_offset + page_count;
if (page_range_end > instance_->page_count()) {
return fpromise::error("FtlWriter::Write out of bounds. Offset " + std::to_string(offset) +
" (Page: " + std::to_string(page_offset) + ")" +
" attempting to write " + std::to_string(buffer.size()) +
" bytes (Page Count: " + std::to_string(page_count) +
"), exceeds maximum offset of " + std::to_string(offset) +
"(Page Size: " + std::to_string(instance_->page_size()) +
", Page Count: " + std::to_string(instance_->page_count()) + ").");
}
if (auto result = volume_->Write(page_offset, page_count, buffer.data()); result != ZX_OK) {
return fpromise::error("Failed to write " + std::to_string(page_count) +
" pages starting at " + std::to_string(page_offset) +
". More specifically: " + std::to_string(result) + ".");
}
return fpromise::ok();
}
private:
std::shared_ptr<FtlInstance> instance_;
std::shared_ptr<ftl::Volume> volume_;
};
fpromise::result<void, std::string> FtlHandle::Init(std::unique_ptr<ftl::NdmDriver> driver) {
auto* error = volume_->Init(std::move(driver));
if (error != nullptr) {
return fpromise::error("FtlHandle::Init failed. More specifically: " + std::string(error) +
".");
}
return fpromise::ok();
}
std::unique_ptr<Reader> FtlHandle::MakeReader() {
return std::make_unique<FtlReader>(instance_, volume_,
instance_->page_count() * instance_->page_size());
}
std::unique_ptr<Writer> FtlHandle::MakeWriter() {
return std::make_unique<FtlWriter>(instance_, volume_);
}
} // namespace storage::volume_image