blob: 9d4fa2cfbf3cac075f85798f42dd38724fae39f3 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdlib.h>
#include <utility>
#include <minfs/block-txn.h>
#include "inode-manager.h"
namespace minfs {
InodeManager::InodeManager(Bcache* bc, blk_t start_block) :
bc_(bc), start_block_(start_block) {}
InodeManager::~InodeManager() = default;
zx_status_t InodeManager::Create(Bcache* bc, SuperblockManager* sb, fs::ReadTxn* txn,
AllocatorMetadata metadata,
blk_t start_block, size_t inodes,
fbl::unique_ptr<InodeManager>* out) {
auto mgr = fbl::unique_ptr<InodeManager>(new InodeManager(bc, start_block));
InodeManager* mgr_raw = mgr.get();
auto grow_cb = [mgr_raw](uint32_t pool_size) {
return mgr_raw->Grow(pool_size);
};
zx_status_t status;
fbl::unique_ptr<PersistentStorage> storage(new PersistentStorage(bc, sb, kMinfsInodeSize,
std::move(grow_cb),
std::move(metadata)));
if ((status = Allocator::Create(txn, std::move(storage), &mgr->inode_allocator_)) != ZX_OK) {
return status;
}
#ifdef __Fuchsia__
uint32_t inoblks = (static_cast<uint32_t>(inodes) + kMinfsInodesPerBlock - 1) /
kMinfsInodesPerBlock;
if ((status = mgr->inode_table_.CreateAndMap(inoblks * kMinfsBlockSize, "minfs-inode-table"))
!= ZX_OK) {
return status;
}
fuchsia_hardware_block_VmoID vmoid;
if ((status = bc->AttachVmo(mgr->inode_table_.vmo(), &vmoid)) != ZX_OK) {
return status;
}
txn->Enqueue(vmoid.id, 0, start_block, inoblks);
#endif
*out = std::move(mgr);
return ZX_OK;
}
void InodeManager::Update(WriteTxn* txn, ino_t ino, const Inode* inode) {
// Obtain the offset of the inode within its containing block
const uint32_t off_of_ino = (ino % kMinfsInodesPerBlock) * kMinfsInodeSize;
const blk_t inoblock_rel = ino / kMinfsInodesPerBlock;
const blk_t inoblock_abs = inoblock_rel + start_block_;
assert(inoblock_abs < kFVMBlockDataStart);
#ifdef __Fuchsia__
void* inodata = (void*)((uintptr_t)(inode_table_.start()) +
(uintptr_t)(inoblock_rel * kMinfsBlockSize));
memcpy((void*)((uintptr_t)inodata + off_of_ino), inode, kMinfsInodeSize);
txn->Enqueue(inode_table_.vmo().get(), inoblock_rel, inoblock_abs, 1);
#else
// Since host-side tools don't have "mapped vmos", just read / update /
// write the single absolute inode block.
uint8_t inodata[kMinfsBlockSize];
bc_->Readblk(inoblock_abs, inodata);
memcpy((void*)((uintptr_t)inodata + off_of_ino), inode, kMinfsInodeSize);
bc_->Writeblk(inoblock_abs, inodata);
#endif
}
void InodeManager::Load(ino_t ino, Inode* out) const {
// obtain the block of the inode table we need
uint32_t off_of_ino = (ino % kMinfsInodesPerBlock) * kMinfsInodeSize;
#ifdef __Fuchsia__
void* inodata = (void*)((uintptr_t)(inode_table_.start()) +
(uintptr_t)((ino / kMinfsInodesPerBlock) * kMinfsBlockSize));
#else
uint8_t inodata[kMinfsBlockSize];
bc_->Readblk(start_block_ + (ino / kMinfsInodesPerBlock), inodata);
#endif
const Inode* inode = reinterpret_cast<const Inode*>((uintptr_t)inodata +
off_of_ino);
memcpy(out, inode, kMinfsInodeSize);
}
zx_status_t InodeManager::Grow(size_t inodes) {
#ifdef __Fuchsia__
uint32_t inoblks = (static_cast<uint32_t>(inodes) + kMinfsInodesPerBlock - 1) /
kMinfsInodesPerBlock;
if (inode_table_.Grow(inoblks * kMinfsBlockSize) != ZX_OK) {
return ZX_ERR_NO_SPACE;
}
return ZX_OK;
#else
return ZX_ERR_NO_SPACE;
#endif
}
} // namespace minfs