blob: 95c74d52700539855d3676f6ca9151d70bbb195c [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 "src/storage/minfs/allocator/inode_manager.h"
#include <lib/syslog/cpp/macros.h>
#include <stdlib.h>
#include <memory>
#include <storage/buffer/block_buffer.h>
#include "src/storage/minfs/format.h"
#include "src/storage/minfs/unowned_vmo_buffer.h"
namespace minfs {
InodeManager::InodeManager(blk_t start_block, uint32_t block_size)
: start_block_(start_block), block_size_(block_size) {}
zx::result<std::unique_ptr<InodeManager>> InodeManager::Create(
block_client::BlockDevice* device, SuperblockManager* sb,
fs::BufferedOperationsBuilder* builder, AllocatorMetadata metadata, blk_t start_block,
size_t inodes) {
auto mgr = std::unique_ptr<InodeManager>(new InodeManager(start_block, sb->BlockSize()));
InodeManager* mgr_raw = mgr.get();
auto grow_cb = [mgr_raw](uint32_t pool_size) { return mgr_raw->Grow(pool_size); };
std::unique_ptr<PersistentStorage> storage(new PersistentStorage(
device, sb, kMinfsInodeSize, std::move(grow_cb), std::move(metadata), sb->BlockSize()));
auto inode_allocator_or = Allocator::Create(builder, std::move(storage));
if (inode_allocator_or.is_error()) {
return inode_allocator_or.take_error();
}
mgr->inode_allocator_ = std::move(inode_allocator_or.value());
uint64_t inoblks =
(static_cast<uint64_t>(inodes) + kMinfsInodesPerBlock - 1) / kMinfsInodesPerBlock;
if (zx_status_t status =
mgr->inode_table_.CreateAndMap(inoblks * sb->BlockSize(), "minfs-inode-table");
status != ZX_OK) {
return zx::error(status);
}
storage::Vmoid vmoid;
if (zx_status_t status = device->BlockAttachVmo(mgr->inode_table_.vmo(), &vmoid);
status != ZX_OK) {
return zx::error(status);
}
vmoid_t id = vmoid.get();
builder->AddVmoid(storage::OwnedVmoid(std::move(vmoid), device));
storage::Operation operation{
.type = storage::OperationType::kRead,
.vmo_offset = 0,
.dev_offset = start_block,
.length = inoblks,
};
fs::internal::BorrowedBuffer buffer(id);
builder->Add(operation, &buffer);
return zx::ok(std::move(mgr));
}
void InodeManager::Update(PendingWork* transaction, 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_;
ZX_DEBUG_ASSERT(inoblock_abs < kFVMBlockDataStart);
char* inodata = reinterpret_cast<char*>(inode_table_.start()) +
inoblock_rel * static_cast<size_t>(BlockSize());
memcpy(inodata + off_of_ino, inode, kMinfsInodeSize);
storage::Operation operation = {
.type = storage::OperationType::kWrite,
.vmo_offset = inoblock_rel,
.dev_offset = inoblock_abs,
.length = 1,
};
UnownedVmoBuffer buffer(zx::unowned_vmo(inode_table_.vmo()));
transaction->EnqueueMetadata(operation, &buffer);
}
const Allocator* InodeManager::GetInodeAllocator() const { return inode_allocator_.get(); }
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;
const char* inodata = reinterpret_cast<const char*>(inode_table_.start()) +
ino / kMinfsInodesPerBlock * static_cast<size_t>(BlockSize());
const Inode* inode = reinterpret_cast<const Inode*>(inodata + off_of_ino);
memcpy(out, inode, kMinfsInodeSize);
}
zx_status_t InodeManager::Grow(size_t inodes) {
size_t inoblks = (inodes + kMinfsInodesPerBlock - 1) / kMinfsInodesPerBlock;
if (zx_status_t status = inode_table_.Grow(inoblks * BlockSize()); status != ZX_OK) {
FX_LOGS(WARNING) << "InodeManager::Grow: failed: " << status;
return ZX_ERR_NO_SPACE;
}
return ZX_OK;
}
} // namespace minfs