blob: eab78ab3640b373f90d82bda31100fb80d1c4302 [file] [log] [blame]
// Copyright 2020 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 "minfs_private.h"
#include "vmo_indirect.h"
namespace minfs {
zx_status_t VmoIndirect::Init(VnodeMinfs* vnode) {
if (vmo_ != nullptr) {
return ZX_OK;
}
vmo_ = fzl::ResizeableVmoMapper::Create(GetVmoSizeForDoublyIndirect(), "minfs-indirect");
zx_status_t status =
vnode->Vfs()->GetMutableBcache()->device()->BlockAttachVmo(vmo_->vmo(), &vmoid_);
if (status != ZX_OK) {
vmo_.reset();
return status;
}
// Load initial set of indirect blocks
if ((status = LoadIndirectBlocks(vnode, vnode->GetInode()->inum, kMinfsIndirect, 0)) != ZX_OK) {
vmo_.reset();
return status;
}
// Load doubly indirect blocks
if ((status = LoadIndirectBlocks(vnode, vnode->GetInode()->dinum, kMinfsDoublyIndirect,
GetVmoOffsetForDoublyIndirect(0)) != ZX_OK)) {
vmo_.reset();
return status;
}
return ZX_OK;
}
zx_status_t VmoIndirect::LoadIndirectBlocks(VnodeMinfs* vnode, const blk_t* iarray, uint32_t count,
uint32_t block) {
zx_status_t status;
if ((status = Init(vnode)) != ZX_OK) {
return status;
}
// It's not safe to grow the VMO here because |iarray| might be a pointer to something within the
// VMO (e.g. a double indirect block pointer).
ValidateVmoSize(vmo_->vmo().get(), block + count - 1);
fs::BufferedOperationsBuilder builder;
for (uint32_t i = 0; i < count; i++) {
const blk_t ibno = iarray[i];
if (ibno != 0) {
vnode->Vfs()->ValidateBno(ibno);
fs::internal::BorrowedBuffer buffer(vmoid_.get());
builder.Add(storage::Operation{.type = storage::OperationType::kRead,
.vmo_offset = block + i,
.dev_offset = ibno + vnode->Vfs()->Info().dat_block,
.length = 1},
&buffer);
}
}
return vnode->Vfs()->GetMutableBcache()->RunRequests(builder.TakeOperations());
}
zx_status_t VmoIndirect::LoadIndirectWithinDoublyIndirect(VnodeMinfs* vnode, uint32_t dindex) {
size_t size = GetVmoSizeForIndirect(dindex);
if (vmo_->size() >= size) {
// We've already loaded this indirect (within dind) block.
return ZX_OK;
} else {
zx_status_t status = vmo_->Grow(size);
if (status != ZX_OK) {
return status;
}
}
blk_t* dientry = GetBlocks(GetVmoOffsetForDoublyIndirect(dindex));
return LoadIndirectBlocks(vnode, dientry, kMinfsDirectPerIndirect,
GetVmoOffsetForIndirect(dindex));
}
void VmoIndirect::ClearBlock(uint32_t block) {
ZX_DEBUG_ASSERT(IsValid());
uintptr_t addr = reinterpret_cast<uintptr_t>(vmo_->start());
ValidateVmoSize(vmo_->vmo().get(), block);
memset(reinterpret_cast<void*>(addr + kMinfsBlockSize * block), 0, kMinfsBlockSize);
}
} // namespace minfs