1 // Copyright 2017 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 <fvm/fvm-sparse.h>
6 #include <minfs/transaction-limits.h>
7 
8 #include <utility>
9 
10 #include "fvm-host/format.h"
11 
MinfsFormat(fbl::unique_fd fd,const char * type)12 MinfsFormat::MinfsFormat(fbl::unique_fd fd, const char* type)
13     : Format() {
14     if (!strcmp(type, kDataTypeName)) {
15         memcpy(type_, kDataType, sizeof(kDataType));
16         flags_ |= fvm::kSparseFlagZxcrypt;
17 
18     } else if (!strcmp(type, kDataUnsafeTypeName)) {
19         memcpy(type_, kDataType, sizeof(kDataType));
20 
21     } else if (!strcmp(type, kSystemTypeName)) {
22         memcpy(type_, kSystemType, sizeof(kSystemType));
23 
24     } else if (!strcmp(type, kDefaultTypeName)) {
25         memcpy(type_, kDefaultType, sizeof(kDefaultType));
26 
27     } else {
28         fprintf(stderr, "Unrecognized type for minfs: %s\n", type);
29         exit(-1);
30     }
31 
32     struct stat s;
33 
34     if (fstat(fd.get(), &s) < 0) {
35         fprintf(stderr, "error: minfs could not find end of file/device\n");
36         exit(-1);
37     } else if (s.st_size == 0) {
38         fprintf(stderr, "minfs: failed to access block device\n");
39         exit(-1);
40     }
41 
42     off_t size = s.st_size / minfs::kMinfsBlockSize;
43 
44     if (minfs::Bcache::Create(&bc_, std::move(fd), (uint32_t)size) < 0) {
45         fprintf(stderr, "error: cannot create block cache\n");
46         exit(-1);
47     }
48 
49     if (bc_->Readblk(0, &blk_) != ZX_OK) {
50         fprintf(stderr, "minfs: could not read info block\n");
51         exit(-1);
52     }
53 
54     if (CheckSuperblock(&info_, bc_.get()) != ZX_OK) {
55         fprintf(stderr, "Check info failed\n");
56         exit(-1);
57     }
58 }
59 
MakeFvmReady(size_t slice_size,uint32_t vpart_index)60 zx_status_t MinfsFormat::MakeFvmReady(size_t slice_size, uint32_t vpart_index) {
61     memcpy(&fvm_blk_, &blk_, minfs::kMinfsBlockSize);
62     fvm_info_.slice_size = slice_size;
63     fvm_info_.flags |= minfs::kMinfsFlagFVM;
64 
65     if (fvm_info_.slice_size % minfs::kMinfsBlockSize) {
66         fprintf(stderr, "minfs mkfs: Slice size not multiple of minfs block\n");
67         return ZX_ERR_INVALID_ARGS;
68     }
69 
70     size_t kBlocksPerSlice = fvm_info_.slice_size / minfs::kMinfsBlockSize;
71     uint32_t ibm_blocks = info_.abm_block - info_.ibm_block;
72     uint32_t abm_blocks = info_.ino_block - info_.abm_block;
73     uint32_t ino_blocks = info_.journal_start_block - info_.ino_block;
74     uint32_t journal_blocks = info_.dat_block - info_.journal_start_block;
75     uint32_t dat_blocks = info_.block_count;
76 
77     //TODO(planders): Once blobfs journaling patch is landed, use fvm::BlocksToSlices() here.
78     fvm_info_.ibm_slices = (ibm_blocks + kBlocksPerSlice - 1) / kBlocksPerSlice;
79     fvm_info_.abm_slices = (abm_blocks + kBlocksPerSlice - 1) / kBlocksPerSlice;
80     fvm_info_.ino_slices = (ino_blocks + kBlocksPerSlice - 1) / kBlocksPerSlice;
81 
82     // TODO(planders): Weird things may happen if we grow the journal here while it contains valid
83     //                 entries. Make sure to account for this case (or verify that the journal is
84     //                 resolved prior to extension).
85     minfs::TransactionLimits limits(fvm_info_);
86     journal_blocks = fbl::max(journal_blocks, limits.GetRecommendedJournalBlocks());
87     fvm_info_.journal_slices = (journal_blocks + kBlocksPerSlice - 1) / kBlocksPerSlice;
88     fvm_info_.dat_slices = (dat_blocks + kBlocksPerSlice - 1) / kBlocksPerSlice;
89     fvm_info_.vslice_count = 1 + fvm_info_.ibm_slices + fvm_info_.abm_slices +
90                              fvm_info_.ino_slices + fvm_info_.journal_slices + fvm_info_.dat_slices;
91 
92     xprintf("Minfs: slice_size is %" PRIu64 "u, kBlocksPerSlice is %zu\n", fvm_info_.slice_size,
93             kBlocksPerSlice);
94     xprintf("Minfs: ibm_blocks: %u, ibm_slices: %u\n", ibm_blocks, fvm_info_.ibm_slices);
95     xprintf("Minfs: abm_blocks: %u, abm_slices: %u\n", abm_blocks, fvm_info_.abm_slices);
96     xprintf("Minfs: ino_blocks: %u, ino_slices: %u\n", ino_blocks, fvm_info_.ino_slices);
97     xprintf("Minfs: jnl_blocks: %u, jnl_slices: %u\n", journal_blocks,
98             fvm_info_.journal_slices);
99     xprintf("Minfs: dat_blocks: %u, dat_slices: %u\n", dat_blocks, fvm_info_.dat_slices);
100 
101     fvm_info_.inode_count = static_cast<uint32_t>(fvm_info_.ino_slices * fvm_info_.slice_size /
102                                                   minfs::kMinfsInodeSize);
103     fvm_info_.block_count = static_cast<uint32_t>(fvm_info_.dat_slices * fvm_info_.slice_size /
104                                                   minfs::kMinfsBlockSize);
105 
106     fvm_info_.ibm_block = minfs::kFVMBlockInodeBmStart;
107     fvm_info_.abm_block = minfs::kFVMBlockDataBmStart;
108     fvm_info_.ino_block = minfs::kFVMBlockInodeStart;
109     fvm_info_.journal_start_block = minfs::kFVMBlockJournalStart;
110     fvm_info_.dat_block = minfs::kFVMBlockDataStart;
111 
112     zx_status_t status;
113     // Check if bitmaps are the wrong size, slice extents run on too long, etc.
114     if ((status = CheckSuperblock(&fvm_info_, bc_.get())) != ZX_OK) {
115         fprintf(stderr, "Check info failed\n");
116         return status;
117     }
118 
119     fvm_ready_ = true;
120     vpart_index_ = vpart_index;
121     return ZX_OK;
122 }
123 
GetVsliceRange(unsigned extent_index,vslice_info_t * vslice_info) const124 zx_status_t MinfsFormat::GetVsliceRange(unsigned extent_index, vslice_info_t* vslice_info) const {
125     CheckFvmReady();
126     switch (extent_index) {
127     case 0: {
128         vslice_info->vslice_start = 0;
129         vslice_info->slice_count = 1;
130         vslice_info->block_offset = 0;
131         vslice_info->block_count = 1;
132         vslice_info->zero_fill = true;
133         return ZX_OK;
134     }
135     case 1: {
136         vslice_info->vslice_start = minfs::kFVMBlockInodeBmStart;
137         vslice_info->slice_count = fvm_info_.ibm_slices;
138         vslice_info->block_offset = info_.ibm_block;
139         vslice_info->block_count = info_.abm_block - info_.ibm_block;
140         vslice_info->zero_fill = true;
141         return ZX_OK;
142     }
143     case 2: {
144         vslice_info->vslice_start = minfs::kFVMBlockDataBmStart;
145         vslice_info->slice_count = fvm_info_.abm_slices;
146         vslice_info->block_offset = info_.abm_block;
147         vslice_info->block_count = info_.ino_block - info_.abm_block;
148         vslice_info->zero_fill = true;
149         return ZX_OK;
150     }
151     case 3: {
152         vslice_info->vslice_start = minfs::kFVMBlockInodeStart;
153         vslice_info->slice_count = fvm_info_.ino_slices;
154         vslice_info->block_offset = info_.ino_block;
155         vslice_info->block_count = info_.journal_start_block - info_.ino_block;
156         vslice_info->zero_fill = true;
157         return ZX_OK;
158     }
159     case 4: {
160         vslice_info->vslice_start = minfs::kFVMBlockJournalStart;
161         vslice_info->slice_count = fvm_info_.journal_slices;
162         vslice_info->block_offset = info_.journal_start_block;
163         vslice_info->block_count = info_.dat_block - info_.journal_start_block;
164         vslice_info->zero_fill = false;
165         return ZX_OK;
166     }
167     case 5: {
168         vslice_info->vslice_start = minfs::kFVMBlockDataStart;
169         vslice_info->slice_count = fvm_info_.dat_slices;
170         vslice_info->block_offset = info_.dat_block;
171         vslice_info->block_count = info_.block_count;
172         vslice_info->zero_fill = false;
173         return ZX_OK;
174     }
175     }
176 
177     return ZX_ERR_OUT_OF_RANGE;
178 }
179 
GetSliceCount(uint32_t * slices_out) const180 zx_status_t MinfsFormat::GetSliceCount(uint32_t* slices_out) const {
181     CheckFvmReady();
182     *slices_out = fvm_info_.vslice_count;
183     return ZX_OK;
184 }
185 
FillBlock(size_t block_offset)186 zx_status_t MinfsFormat::FillBlock(size_t block_offset) {
187     CheckFvmReady();
188     if (block_offset == 0) {
189         memcpy(datablk, fvm_blk_, minfs::kMinfsBlockSize);
190     } else if (bc_->Readblk(block_offset, datablk) != ZX_OK) {
191         fprintf(stderr, "minfs: could not read block\n");
192         exit(-1);
193     }
194     return ZX_OK;
195 }
196 
EmptyBlock()197 zx_status_t MinfsFormat::EmptyBlock() {
198     CheckFvmReady();
199     memset(datablk, 0, BlockSize());
200     return ZX_OK;
201 }
202 
Data()203 void* MinfsFormat::Data() {
204     return datablk;
205 }
206 
Name() const207 const char* MinfsFormat::Name() const {
208     return kMinfsName;
209 }
210 
BlockSize() const211 uint32_t MinfsFormat::BlockSize() const {
212     return minfs::kMinfsBlockSize;
213 }
214 
BlocksPerSlice() const215 uint32_t MinfsFormat::BlocksPerSlice() const {
216     CheckFvmReady();
217     return fvm_info_.slice_size / BlockSize();
218 }
219