1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <lib/ftl/volume.h>
6 #include <zircon/assert.h>
7
8 #include "kprivate/ndm.h"
9 #include "posix.h"
10
11 namespace ftl {
12
Init(std::unique_ptr<NdmDriver> driver)13 const char* VolumeImpl::Init(std::unique_ptr<NdmDriver> driver) {
14 ZX_DEBUG_ASSERT(!driver_);
15 driver_ = std::move(driver);
16
17 if (!InitModules()) {
18 return "Module initialization failed";
19 }
20
21 const char* error = driver_->Init();
22 if (error) {
23 return error;
24 }
25
26 return Attach();
27 }
28
ReAttach()29 const char* VolumeImpl::ReAttach() {
30 if (!driver_->Detach()) {
31 return "Failed to remove volume";
32 }
33 name_ = nullptr;
34
35 return Attach();
36 }
37
Read(uint32_t first_page,int num_pages,void * buffer)38 zx_status_t VolumeImpl::Read(uint32_t first_page, int num_pages, void* buffer) {
39 if (read_pages_(buffer, first_page, num_pages, vol_) != 0) {
40 return ZX_ERR_IO;
41 }
42 return ZX_OK;
43 }
44
Write(uint32_t first_page,int num_pages,const void * buffer)45 zx_status_t VolumeImpl::Write(uint32_t first_page, int num_pages, const void* buffer) {
46 if (write_pages_(const_cast<void*>(buffer), first_page, num_pages, vol_) != 0) {
47 return ZX_ERR_IO;
48 }
49 return ZX_OK;
50 }
51
Format()52 zx_status_t VolumeImpl::Format() {
53 if (report_(vol_, FS_FORMAT) != 0) {
54 return ZX_ERR_BAD_STATE;
55 }
56 return ZX_OK;
57 }
58
Mount()59 zx_status_t VolumeImpl::Mount() {
60 if (report_(vol_, FS_MOUNT) != 0) {
61 return ZX_ERR_BAD_STATE;
62 }
63 return ZX_OK;
64 }
65
Unmount()66 zx_status_t VolumeImpl::Unmount() {
67 if (report_(vol_, FS_UNMOUNT) != 0) {
68 return ZX_ERR_BAD_STATE;
69 }
70 return ZX_OK;
71 }
72
Flush()73 zx_status_t VolumeImpl::Flush() {
74 if (report_(vol_, FS_SYNC) != 0) {
75 return ZX_ERR_BAD_STATE;
76 }
77 return ZX_OK;
78 }
79
Trim(uint32_t first_page,uint32_t num_pages)80 zx_status_t VolumeImpl::Trim(uint32_t first_page, uint32_t num_pages) {
81 if (report_(vol_, FS_MARK_UNUSED, first_page, num_pages) != 0) {
82 return ZX_ERR_BAD_STATE;
83 }
84 return ZX_OK;
85 }
86
GarbageCollect()87 zx_status_t VolumeImpl::GarbageCollect() {
88 int result = report_(vol_, FS_VCLEAN);
89 if (result < 0) {
90 return ZX_ERR_BAD_STATE;
91 }
92
93 if (result == 0) {
94 return ZX_ERR_STOP;
95 }
96 return ZX_OK;
97 }
98
GetStats(Stats * stats)99 zx_status_t VolumeImpl::GetStats(Stats* stats) {
100 union vstat buffer;
101 if (report_(vol_, FS_VSTAT, &buffer) != 0) {
102 return ZX_ERR_BAD_STATE;
103 }
104 stats->ram_used = buffer.fat.drvr_stats.ftl.ndm.ram_used;
105 stats->wear_count = buffer.fat.drvr_stats.ftl.ndm.wear_count;
106 stats->garbage_level = buffer.fat.garbage_level;
107 return ZX_OK;
108 }
109
OnVolumeAdded(const XfsVol * ftl)110 bool VolumeImpl::OnVolumeAdded(const XfsVol* ftl) {
111 ZX_DEBUG_ASSERT(!Created());
112 vol_ = ftl->vol;
113 name_ = ftl->name;
114 report_ = ftl->report;
115 write_pages_ = ftl->write_pages;
116 read_pages_ = ftl->read_pages;
117
118 return owner_->OnVolumeAdded(ftl->page_size, ftl->num_pages);
119 }
120
Created() const121 bool VolumeImpl::Created() const {
122 return name_;
123 }
124
Attach()125 const char* VolumeImpl::Attach() {
126 const char* error = driver_->Attach(this);
127 if (error) {
128 return error;
129 }
130
131 if (!Created()) {
132 return "No volume added";
133 }
134
135 if (Mount() != ZX_OK) {
136 return "Mount failed";
137 }
138 return nullptr;
139 }
140
141 } // namespace ftl
142
143 // Callback from the FTL.
XfsAddVol(XfsVol * ftl)144 int XfsAddVol(XfsVol* ftl) {
145 ftl::VolumeImpl* volume = reinterpret_cast<ftl::VolumeImpl*>(ftl->ftl_volume);
146 if (volume && !volume->OnVolumeAdded(ftl)) {
147 return -1;
148 }
149 return 0;
150 }
151
152 // Callback from the FTL.
XfsDelVol(const char * name)153 int XfsDelVol(const char* name) {
154 return 0;
155 }
156