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 <stdlib.h>
6 
7 #include <minfs/block-txn.h>
8 #include <minfs/inode-manager.h>
9 
10 #include <utility>
11 
12 namespace minfs {
13 
InodeManager(Bcache * bc,blk_t start_block)14 InodeManager::InodeManager(Bcache* bc, blk_t start_block) :
15     bc_(bc), start_block_(start_block) {}
16 InodeManager::~InodeManager() = default;
17 
Create(Bcache * bc,SuperblockManager * sb,fs::ReadTxn * txn,AllocatorMetadata metadata,blk_t start_block,size_t inodes,fbl::unique_ptr<InodeManager> * out)18 zx_status_t InodeManager::Create(Bcache* bc, SuperblockManager* sb, fs::ReadTxn* txn,
19                                  AllocatorMetadata metadata,
20                                  blk_t start_block, size_t inodes,
21                                  fbl::unique_ptr<InodeManager>* out) {
22 
23     auto mgr = fbl::unique_ptr<InodeManager>(new InodeManager(bc, start_block));
24     InodeManager* mgr_raw = mgr.get();
25 
26     auto grow_cb = [mgr_raw](uint32_t pool_size) {
27         return mgr_raw->Grow(pool_size);
28     };
29 
30     zx_status_t status;
31     if ((status = Allocator::Create(bc, sb, txn, kMinfsInodeSize,
32                                     std::move(grow_cb), std::move(metadata),
33                                     &mgr->inode_allocator_)) != ZX_OK) {
34         return status;
35     }
36 
37 #ifdef __Fuchsia__
38     uint32_t inoblks = (static_cast<uint32_t>(inodes) + kMinfsInodesPerBlock - 1) /
39             kMinfsInodesPerBlock;
40     if ((status = mgr->inode_table_.CreateAndMap(inoblks * kMinfsBlockSize, "minfs-inode-table"))
41         != ZX_OK) {
42         return status;
43     }
44 
45     vmoid_t vmoid;
46     if ((status = bc->AttachVmo(mgr->inode_table_.vmo(), &vmoid)) != ZX_OK) {
47         return status;
48     }
49     txn->Enqueue(vmoid, 0, start_block, inoblks);
50 #endif
51     *out = std::move(mgr);
52     return ZX_OK;
53 }
54 
Update(WriteTxn * txn,ino_t ino,const Inode * inode)55 void InodeManager::Update(WriteTxn* txn, ino_t ino, const Inode* inode) {
56     // Obtain the offset of the inode within its containing block
57     const uint32_t off_of_ino = (ino % kMinfsInodesPerBlock) * kMinfsInodeSize;
58     const blk_t inoblock_rel = ino / kMinfsInodesPerBlock;
59     const blk_t inoblock_abs = inoblock_rel + start_block_;
60     assert(inoblock_abs < kFVMBlockDataStart);
61 #ifdef __Fuchsia__
62     void* inodata = (void*)((uintptr_t)(inode_table_.start()) +
63                             (uintptr_t)(inoblock_rel * kMinfsBlockSize));
64     memcpy((void*)((uintptr_t)inodata + off_of_ino), inode, kMinfsInodeSize);
65     txn->Enqueue(inode_table_.vmo().get(), inoblock_rel, inoblock_abs, 1);
66 #else
67     // Since host-side tools don't have "mapped vmos", just read / update /
68     // write the single absolute inode block.
69     uint8_t inodata[kMinfsBlockSize];
70     bc_->Readblk(inoblock_abs, inodata);
71     memcpy((void*)((uintptr_t)inodata + off_of_ino), inode, kMinfsInodeSize);
72     bc_->Writeblk(inoblock_abs, inodata);
73 #endif
74 }
75 
Load(ino_t ino,Inode * out) const76 void InodeManager::Load(ino_t ino, Inode* out) const {
77     // obtain the block of the inode table we need
78     uint32_t off_of_ino = (ino % kMinfsInodesPerBlock) * kMinfsInodeSize;
79 #ifdef __Fuchsia__
80     void* inodata = (void*)((uintptr_t)(inode_table_.start()) +
81                             (uintptr_t)((ino / kMinfsInodesPerBlock) * kMinfsBlockSize));
82 #else
83     uint8_t inodata[kMinfsBlockSize];
84     bc_->Readblk(start_block_ + (ino / kMinfsInodesPerBlock), inodata);
85 #endif
86     const Inode* inode = reinterpret_cast<const Inode*>((uintptr_t)inodata +
87                                                                         off_of_ino);
88     memcpy(out, inode, kMinfsInodeSize);
89 }
90 
Grow(size_t inodes)91 zx_status_t InodeManager::Grow(size_t inodes) {
92 #ifdef __Fuchsia__
93     uint32_t inoblks = (static_cast<uint32_t>(inodes) + kMinfsInodesPerBlock - 1) /
94             kMinfsInodesPerBlock;
95     if (inode_table_.Grow(inoblks * kMinfsBlockSize) != ZX_OK) {
96         return ZX_ERR_NO_SPACE;
97     }
98     return ZX_OK;
99 #else
100     return ZX_ERR_NO_SPACE;
101 #endif
102 }
103 
104 } // namespace minfs
105