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