blob: ec29cfc1e1fbe5324922e45cfe897786e559850b [file] [log] [blame] [edit]
// 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.
#ifndef SRC_STORAGE_MINFS_WRITEBACK_H_
#define SRC_STORAGE_MINFS_WRITEBACK_H_
#include <lib/zx/status.h>
#include <memory>
#include <utility>
#include <vector>
#include <fbl/ref_ptr.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 <fs/transaction/writeback.h>
#endif
#include <fbl/algorithm.h>
#include <fbl/intrusive_hash_table.h>
#include <fbl/intrusive_single_list.h>
#include <fbl/macros.h>
#include <fs/queue.h>
#include <fs/transaction/buffered_operations_builder.h>
#include <fs/vfs.h>
#include "src/storage/minfs/allocator_reservation.h"
#include "src/storage/minfs/bcache.h"
#include "src/storage/minfs/cached_block_transaction.h"
#include "src/storage/minfs/format.h"
#include "src/storage/minfs/pending_work.h"
namespace minfs {
class DataAssignableVnode;
class InodeManager;
class TransactionalFs;
class VnodeMinfs;
// Tracks the current transaction, including any enqueued writes, and reserved blocks
// and inodes. Also handles allocation of previously reserved blocks/inodes.
// Upon construction, acquires a lock to ensure that all work being done within the
// scope of the transaction is thread-safe. Specifically, the Minfs superblock, block bitmap, and
// inode table, as well as the Vnode block count and inode size may in the near future be modified
// asynchronously. Since these modifications require a Transaction to be in progress, this lock
// will protect against multiple simultaneous writes to these structures.
class Transaction final : public PendingWork {
public:
static zx_status_t Create(TransactionalFs* minfs, size_t reserve_inodes, size_t reserve_blocks,
InodeManager* inode_manager, std::unique_ptr<Transaction>* out);
// Creates a Transaction object from CachedBlockTransaction. Consumes cached_transaction.
static std::unique_ptr<Transaction> FromCachedBlockTransaction(
TransactionalFs* minfs, std::unique_ptr<CachedBlockTransaction> cached_transaction);
Transaction() = delete;
explicit Transaction(TransactionalFs* minfs,
std::unique_ptr<CachedBlockTransaction> cached_transaction = nullptr);
~Transaction() final;
AllocatorReservation& inode_reservation() { return inode_reservation_; }
AllocatorReservation& block_reservation() { return *block_reservation_; }
////////////////
// PendingWork interface.
void EnqueueMetadata(storage::Operation operation, storage::BlockBuffer* buffer) final;
void EnqueueData(storage::Operation operation, storage::BlockBuffer* buffer) final;
size_t AllocateBlock() final { return block_reservation_->Allocate(); }
void DeallocateBlock(size_t block) final { return block_reservation_->Deallocate(block); }
////////////////
// Other methods.
size_t AllocateInode() { return inode_reservation_.Allocate(); }
void PinVnode(fbl::RefPtr<VnodeMinfs> vnode);
// Extends block reservation by |reserve_blocks| number of blocks. It may fail
// if the underlying allocator runs out of space.
zx_status_t ExtendBlockReservation(size_t reserve_blocks);
#ifdef __Fuchsia__
// Returns a vector of all enqueued metadata write operations.
std::vector<storage::UnbufferedOperation> RemoveMetadataOperations() {
return metadata_operations_.TakeOperations();
}
// Returns a vector of all enqueued data write operations.
std::vector<storage::UnbufferedOperation> RemoveDataOperations() {
return data_operations_.TakeOperations();
}
size_t SwapBlock(size_t old_bno) { return block_reservation_->Swap(old_bno); }
std::vector<fbl::RefPtr<VnodeMinfs>> RemovePinnedVnodes();
// Returns the block reservations within |transaction| and consumes |transaction|.
// Asserts that there are no inode reservations.
static std::unique_ptr<AllocatorReservation> TakeBlockReservations(
std::unique_ptr<Transaction> transaction) {
// When consuming transaction, we ignore any pending data and matadata operations
// as they will be enqueued again.
ZX_ASSERT(transaction->inode_reservation_.GetReserved() == 0);
return (std::move(transaction->block_reservation_));
}
#else
std::vector<storage::BufferedOperation> TakeOperations() { return builder_.TakeOperations(); }
#endif
private:
#ifdef __Fuchsia__
fbl::AutoLock<fbl::Mutex> lock_;
storage::UnbufferedOperationsBuilder metadata_operations_;
storage::UnbufferedOperationsBuilder data_operations_;
std::vector<fbl::RefPtr<VnodeMinfs>> pinned_vnodes_;
#else
fs::BufferedOperationsBuilder builder_;
#endif
AllocatorReservation inode_reservation_;
std::unique_ptr<AllocatorReservation> block_reservation_;
};
} // namespace minfs
#endif // SRC_STORAGE_MINFS_WRITEBACK_H_