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 <inttypes.h>
6 
7 #include <utility>
8 
9 #include "fvm-host/format.h"
10 
BlobfsFormat(fbl::unique_fd fd,const char * type)11 BlobfsFormat::BlobfsFormat(fbl::unique_fd fd, const char* type)
12     : Format(), fd_(std::move(fd)) {
13     if (!strcmp(type, kBlobTypeName)) {
14         memcpy(type_, kBlobType, sizeof(kBlobType));
15     } else if (!strcmp(type, kDefaultTypeName)) {
16         memcpy(type_, kDefaultType, sizeof(kDefaultType));
17     } else {
18         fprintf(stderr, "Unrecognized type for blobfs: %s\n", type);
19         exit(-1);
20     }
21 
22     if (blobfs::readblk(fd_.get(), 0, reinterpret_cast<void*>(blk_)) < 0) {
23         fprintf(stderr, "blobfs: could not read info block\n");
24         exit(-1);
25     }
26 
27     if (blobfs::GetBlockCount(fd_.get(), &blocks_) != ZX_OK) {
28         fprintf(stderr, "blobfs: cannot find end of underlying device\n");
29         exit(-1);
30     } else if (blobfs::CheckSuperblock(&info_, blocks_) != ZX_OK) {
31         fprintf(stderr, "blobfs: Info check failed\n");
32         exit(-1);
33     }
34 }
35 
36 BlobfsFormat::~BlobfsFormat() = default;
37 
MakeFvmReady(size_t slice_size,uint32_t vpart_index)38 zx_status_t BlobfsFormat::MakeFvmReady(size_t slice_size, uint32_t vpart_index) {
39     memcpy(&fvm_blk_, &blk_, BlockSize());
40     xprintf("fvm_info has data block count %" PRIu64 "\n", fvm_info_.data_block_count);
41     fvm_info_.slice_size = slice_size;
42 
43     if (fvm_info_.slice_size % BlockSize()) {
44         fprintf(stderr, "MakeFvmReady: Slice size not multiple of minfs block\n");
45         return ZX_ERR_INVALID_ARGS;
46     }
47 
48     fvm_info_.abm_slices = BlocksToSlices(BlockMapBlocks(info_));
49     fvm_info_.ino_slices = BlocksToSlices(NodeMapBlocks(info_));
50     fvm_info_.journal_slices = BlocksToSlices(JournalBlocks(info_));
51     fvm_info_.dat_slices = BlocksToSlices(DataBlocks(info_));
52     fvm_info_.vslice_count = 1 + fvm_info_.abm_slices + fvm_info_.ino_slices +
53                              fvm_info_.dat_slices + fvm_info_.journal_slices;
54 
55     xprintf("Blobfs: slice_size is %" PRIu64 "\n", fvm_info_.slice_size);
56     xprintf("Blobfs: abm_blocks: %" PRIu64 ", abm_slices: %u\n", BlockMapBlocks(info_),
57             fvm_info_.abm_slices);
58     xprintf("Blobfs: ino_blocks: %" PRIu64 ", ino_slices: %u\n", NodeMapBlocks(info_),
59             fvm_info_.ino_slices);
60     xprintf("Blobfs: jnl_blocks: %" PRIu64 ", jnl_slices: %u\n", JournalBlocks(info_),
61             fvm_info_.journal_slices);
62     xprintf("Blobfs: dat_blocks: %" PRIu64 ", dat_slices: %u\n", DataBlocks(info_),
63             fvm_info_.dat_slices);
64 
65     fvm_info_.inode_count = static_cast<uint32_t>(fvm_info_.ino_slices * fvm_info_.slice_size /
66                                                   blobfs::kBlobfsInodeSize);
67     fvm_info_.journal_block_count = SlicesToBlocks(fvm_info_.journal_slices);
68     fvm_info_.data_block_count = SlicesToBlocks(fvm_info_.dat_slices);
69     fvm_info_.flags |= blobfs::kBlobFlagFVM;
70 
71     zx_status_t status;
72     if ((status = CheckSuperblock(&fvm_info_, blocks_)) != ZX_OK) {
73         fprintf(stderr, "Check info failed\n");
74         return status;
75     }
76 
77     fvm_ready_ = true;
78     vpart_index_ = vpart_index;
79     return ZX_OK;
80 }
81 
GetVsliceRange(unsigned extent_index,vslice_info_t * vslice_info) const82 zx_status_t BlobfsFormat::GetVsliceRange(unsigned extent_index, vslice_info_t* vslice_info) const {
83     CheckFvmReady();
84     switch (extent_index) {
85     case 0: {
86         vslice_info->vslice_start = 0;
87         vslice_info->slice_count = 1;
88         vslice_info->block_offset = 0;
89         vslice_info->block_count = 1;
90         vslice_info->zero_fill = true;
91         return ZX_OK;
92     }
93     case 1: {
94         vslice_info->vslice_start = blobfs::kFVMBlockMapStart;
95         vslice_info->slice_count = fvm_info_.abm_slices;
96         vslice_info->block_offset = BlockMapStartBlock(info_);
97         vslice_info->block_count = BlockMapBlocks(info_);
98         vslice_info->zero_fill = true;
99         return ZX_OK;
100     }
101     case 2: {
102         vslice_info->vslice_start = blobfs::kFVMNodeMapStart;
103         vslice_info->slice_count = fvm_info_.ino_slices;
104         vslice_info->block_offset = NodeMapStartBlock(info_);
105         vslice_info->block_count = NodeMapBlocks(info_);
106         vslice_info->zero_fill = true;
107         return ZX_OK;
108     }
109     case 3: {
110         vslice_info->vslice_start = blobfs::kFVMJournalStart;
111         vslice_info->slice_count = fvm_info_.journal_slices;
112         vslice_info->block_offset = JournalStartBlock(info_);
113         vslice_info->block_count = JournalBlocks(info_);
114         vslice_info->zero_fill = false;
115         return ZX_OK;
116     }
117     case 4: {
118         vslice_info->vslice_start = blobfs::kFVMDataStart;
119         vslice_info->slice_count = fvm_info_.dat_slices;
120         vslice_info->block_offset = DataStartBlock(info_);
121         vslice_info->block_count = DataBlocks(info_);
122         vslice_info->zero_fill = false;
123         return ZX_OK;
124     }
125     }
126 
127     return ZX_ERR_OUT_OF_RANGE;
128 }
129 
GetSliceCount(uint32_t * slices_out) const130 zx_status_t BlobfsFormat::GetSliceCount(uint32_t* slices_out) const {
131     CheckFvmReady();
132     *slices_out = 1 + fvm_info_.abm_slices + fvm_info_.ino_slices + fvm_info_.journal_slices
133                   + fvm_info_.dat_slices;
134     return ZX_OK;
135 }
136 
FillBlock(size_t block_offset)137 zx_status_t BlobfsFormat::FillBlock(size_t block_offset) {
138     CheckFvmReady();
139     // If we are reading the super block, make sure it is the fvm version and not the original
140     if (block_offset == 0) {
141         memcpy(datablk, fvm_blk_, BlockSize());
142     } else if (blobfs::readblk(fd_.get(), block_offset, datablk) != ZX_OK) {
143         fprintf(stderr, "blobfs: could not read block\n");
144         return ZX_ERR_INTERNAL;
145     }
146     return ZX_OK;
147 }
148 
EmptyBlock()149 zx_status_t BlobfsFormat::EmptyBlock() {
150     CheckFvmReady();
151     memset(datablk, 0, BlockSize());
152     return ZX_OK;
153 }
154 
Data()155 void* BlobfsFormat::Data() {
156     return datablk;
157 }
158 
Name() const159 const char* BlobfsFormat::Name() const {
160     return kBlobfsName;
161 }
162 
BlockSize() const163 uint32_t BlobfsFormat::BlockSize() const {
164     return blobfs::kBlobfsBlockSize;
165 }
166 
BlocksPerSlice() const167 uint32_t BlobfsFormat::BlocksPerSlice() const {
168     CheckFvmReady();
169     return fvm_info_.slice_size / BlockSize();
170 }
171 
BlocksToSlices(uint32_t block_count) const172 uint32_t BlobfsFormat::BlocksToSlices(uint32_t block_count) const {
173     return fvm::BlocksToSlices(fvm_info_.slice_size, BlockSize(), block_count);
174 }
175 
SlicesToBlocks(uint32_t slice_count) const176 uint32_t BlobfsFormat::SlicesToBlocks(uint32_t slice_count) const {
177     return fvm::SlicesToBlocks(fvm_info_.slice_size, BlockSize(), slice_count);
178 }
179