blob: b001993a828154a05dac3395c383bc030728dc23 [file] [log] [blame]
// Copyright 2017 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 <inttypes.h>
#include <lib/zx/result.h>
#include <memory>
#include "src/storage/minfs/allocator/allocator_reservation.h"
#include "zircon/types.h"
#ifdef __Fuchsia__
#include <lib/fzl/owned-vmo-mapper.h>
#include <lib/zx/vmo.h>
#include <fbl/auto_lock.h>
#include <fbl/mutex.h>
#include <fbl/vector.h>
#endif
#include <utility>
#include <fbl/algorithm.h>
#include <fbl/intrusive_hash_table.h>
#include <fbl/intrusive_single_list.h>
#include <fbl/macros.h>
#include <fbl/ref_ptr.h>
#include "src/storage/lib/vfs/cpp/vfs.h"
#include "src/storage/minfs/minfs_private.h"
#include "src/storage/minfs/writeback.h"
namespace minfs {
zx::result<std::unique_ptr<Transaction>> Transaction::Create(TransactionalFs* minfs,
size_t reserve_inodes,
size_t reserve_blocks,
InodeManager* inode_manager) {
auto transaction = std::make_unique<Transaction>(minfs, nullptr);
if (reserve_inodes) {
// The inode allocator is currently not accessed asynchronously.
// However, acquiring the reservation may cause the superblock to be modified via extension,
// so we still need to acquire the lock first.
auto status =
inode_manager->Reserve(transaction.get(), reserve_inodes, &transaction->inode_reservation_);
if (status.is_error()) {
return status.take_error();
}
}
if (reserve_blocks) {
auto status =
transaction->block_reservation_->ExtendReservation(transaction.get(), reserve_blocks);
if (status.is_error()) {
return status.take_error();
}
}
return zx::ok(std::move(transaction));
}
std::unique_ptr<Transaction> Transaction::FromCachedBlockTransaction(
TransactionalFs* minfs, std::unique_ptr<CachedBlockTransaction> cached_transaction) {
auto transaction = std::make_unique<Transaction>(minfs, std::move(cached_transaction));
return transaction;
}
Transaction::Transaction(TransactionalFs* minfs,
std::unique_ptr<CachedBlockTransaction> cached_transaction)
:
#ifdef __Fuchsia__
lock_(minfs->GetLock()),
#endif
inode_reservation_(&minfs->GetInodeAllocator()),
block_reservation_(cached_transaction == nullptr
? std::make_unique<AllocatorReservation>(&minfs->GetBlockAllocator())
: cached_transaction->TakeBlockReservations()) {
}
Transaction::~Transaction() {
// Unreserve all reserved inodes/blocks while the lock is still held.
inode_reservation_.Cancel();
if (block_reservation_ != nullptr) {
block_reservation_->Cancel();
}
}
#ifdef __Fuchsia__
void Transaction::EnqueueMetadata(storage::Operation operation, storage::BlockBuffer* buffer) {
storage::UnbufferedOperation unbuffered_operation = {.vmo = zx::unowned_vmo(buffer->Vmo()),
.op = operation};
metadata_operations_.Add(std::move(unbuffered_operation));
}
void Transaction::EnqueueData(storage::Operation operation, storage::BlockBuffer* buffer) {
storage::UnbufferedOperation unbuffered_operation = {.vmo = zx::unowned_vmo(buffer->Vmo()),
.op = operation};
data_operations_.Add(std::move(unbuffered_operation));
}
void Transaction::PinVnode(fbl::RefPtr<VnodeMinfs> vnode) {
if (auto it = std::find_if(pinned_vnodes_.begin(), pinned_vnodes_.end(),
[&](const auto& pinned) { return pinned.get() == vnode.get(); });
it != pinned_vnodes_.end()) {
// Already pinned
return;
}
pinned_vnodes_.push_back(std::move(vnode));
}
std::vector<fbl::RefPtr<VnodeMinfs>> Transaction::RemovePinnedVnodes() {
return std::move(pinned_vnodes_);
}
#else
void Transaction::EnqueueMetadata(storage::Operation operation, storage::BlockBuffer* buffer) {
builder_.Add(operation, buffer);
}
void Transaction::EnqueueData(storage::Operation operation, storage::BlockBuffer* buffer) {
builder_.Add(operation, buffer);
}
// No-op - don't need to pin vnodes on host.
// NOLINTNEXTLINE(performance-unnecessary-value-param)
void Transaction::PinVnode(fbl::RefPtr<VnodeMinfs> vnode) {}
#endif
zx::result<> Transaction::ExtendBlockReservation(size_t reserve_blocks) {
return block_reservation_->ExtendReservation(this, reserve_blocks);
}
} // namespace minfs