blob: e534505815dd547f00c004aa57e703f6f7fee5bf [file] [log] [blame]
// Copyright 2018 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 <lib/ftl/volume.h>
#include <zircon/assert.h>
#include <ftl_private.h>
#include "kprivate/ndm.h"
#include "posix.h"
namespace ftl {
const char* VolumeImpl::Init(std::unique_ptr<NdmDriver> driver) {
ZX_DEBUG_ASSERT(!driver_);
driver_ = std::move(driver);
if (!InitModules()) {
return "Module initialization failed";
}
return Attach();
}
const char* VolumeImpl::ReAttach() {
if (!driver_->Detach()) {
return "Failed to remove volume";
}
name_ = nullptr;
return Attach();
}
zx_status_t VolumeImpl::Read(uint32_t first_page, int num_pages, void* buffer) {
if (read_pages_(buffer, first_page, num_pages, vol_) != 0) {
return ZX_ERR_IO;
}
return ZX_OK;
}
zx_status_t VolumeImpl::Write(uint32_t first_page, int num_pages, const void* buffer) {
if (write_pages_(const_cast<void*>(buffer), first_page, num_pages, vol_) != 0) {
return ZX_ERR_IO;
}
return ZX_OK;
}
zx_status_t VolumeImpl::Format() {
if (report_(vol_, FS_FORMAT) != 0) {
return ZX_ERR_BAD_STATE;
}
return ZX_OK;
}
zx_status_t VolumeImpl::Mount() {
if (report_(vol_, FS_MOUNT) != 0) {
return ZX_ERR_BAD_STATE;
}
return ZX_OK;
}
zx_status_t VolumeImpl::Unmount() {
if (report_(vol_, FS_UNMOUNT) != 0) {
return ZX_ERR_BAD_STATE;
}
return ZX_OK;
}
zx_status_t VolumeImpl::Flush() {
if (report_(vol_, FS_SYNC) != 0) {
return ZX_ERR_BAD_STATE;
}
return ZX_OK;
}
zx_status_t VolumeImpl::Trim(uint32_t first_page, uint32_t num_pages) {
if (report_(vol_, FS_MARK_UNUSED, first_page, num_pages) != 0) {
return ZX_ERR_BAD_STATE;
}
return ZX_OK;
}
zx_status_t VolumeImpl::GarbageCollect() {
int result = report_(vol_, FS_VCLEAN);
if (result < 0) {
return ZX_ERR_BAD_STATE;
}
if (result == 0) {
return ZX_ERR_STOP;
}
return ZX_OK;
}
zx_status_t VolumeImpl::GetStats(Stats* stats) {
union vstat buffer;
if (report_(vol_, FS_VSTAT, &buffer) != 0) {
return ZX_ERR_BAD_STATE;
}
stats->ram_used = buffer.xfs.drvr_stats.ftl.ndm.ram_used;
stats->wear_count = buffer.xfs.drvr_stats.ftl.ndm.wear_count;
stats->garbage_level = buffer.xfs.garbage_level;
return ZX_OK;
}
bool VolumeImpl::OnVolumeAdded(const XfsVol* ftl) {
ZX_DEBUG_ASSERT(!Created());
vol_ = ftl->vol;
name_ = ftl->name;
report_ = ftl->report;
write_pages_ = ftl->write_pages;
read_pages_ = ftl->read_pages;
return owner_->OnVolumeAdded(ftl->page_size, ftl->num_pages);
}
bool VolumeImpl::Created() const {
return name_;
}
const char* VolumeImpl::Attach() {
const char* error = driver_->Attach(this);
if (error) {
return error;
}
if (!Created()) {
return "No volume added";
}
if (Mount() != ZX_OK) {
return "Mount failed";
}
return nullptr;
}
} // namespace ftl
// Callback from the FTL.
int XfsAddVol(XfsVol* ftl) {
ftl::VolumeImpl* volume = reinterpret_cast<ftl::VolumeImpl*>(ftl->ftl_volume);
if (volume && !volume->OnVolumeAdded(ftl)) {
return -1;
}
return 0;
}