[blobfs] Remove dependency on Blobfs from journal, writeback.
Using dependency injection, this patch allows the journaling
and writeback subsystems of blobfs to be unit-tested without
initializing a real "Blobfs" object.
Test: Compiles
Change-Id: I9054aed78cb568593b080ebca701666bd3e64530
diff --git a/system/ulib/blobfs/blobfs.cpp b/system/ulib/blobfs/blobfs.cpp
index 8676905..ed8ed13 100644
--- a/system/ulib/blobfs/blobfs.cpp
+++ b/system/ulib/blobfs/blobfs.cpp
@@ -16,6 +16,7 @@
#include <blobfs/extent-reserver.h>
#include <blobfs/lz4.h>
#include <blobfs/node-reserver.h>
+#include <blobfs/writeback.h>
#include <cobalt-client/cpp/collector.h>
#include <digest/digest.h>
#include <digest/merkle-tree.h>
diff --git a/system/ulib/blobfs/include/blobfs/blob.h b/system/ulib/blobfs/include/blobfs/blob.h
index 83c0765..c1f60ac 100644
--- a/system/ulib/blobfs/include/blobfs/blob.h
+++ b/system/ulib/blobfs/include/blobfs/blob.h
@@ -22,6 +22,7 @@
#include <fs/vfs.h>
#include <fs/vnode.h>
#include <fuchsia/io/c/fidl.h>
+#include <lib/async/cpp/wait.h>
#include <lib/fzl/owned-vmo-mapper.h>
#include <lib/zx/event.h>
diff --git a/system/ulib/blobfs/include/blobfs/blobfs.h b/system/ulib/blobfs/include/blobfs/blobfs.h
index f90879a..5246c08 100644
--- a/system/ulib/blobfs/include/blobfs/blobfs.h
+++ b/system/ulib/blobfs/include/blobfs/blobfs.h
@@ -58,19 +58,8 @@
namespace blobfs {
-class Blobfs;
-class Journal;
-class Blob;
-class WritebackQueue;
-class WritebackWork;
-
using digest::Digest;
-enum class EnqueueType {
- kJournal,
- kData,
-};
-
// Toggles that may be set on blobfs during initialization.
struct MountOptions {
bool readonly = false;
@@ -81,8 +70,7 @@
class Blobfs : public fs::ManagedVfs,
public fbl::RefCounted<Blobfs>,
- public fs::TransactionHandler,
- public SpaceManager {
+ public TransactionManager {
public:
DISALLOW_COPY_ASSIGN_AND_MOVE(Blobfs);
@@ -92,7 +80,9 @@
void Shutdown(fs::Vfs::ShutdownCallback closure) final;
////////////////
- // fs::TransactionHandler interface.
+ // TransactionManager's fs::TransactionHandler interface.
+ //
+ // Allows transmitting read and write transactions directly to the underlying storage.
uint32_t FsBlockSize() const final { return kBlobfsBlockSize; }
@@ -110,14 +100,29 @@
}
////////////////
- // SpaceManager interface.
+ // TransactionManager's SpaceManager interface.
+ //
+ // Allows viewing and controlling the size of the underlying volume.
+ const Superblock& Info() const final { return info_; }
zx_status_t AttachVmo(const zx::vmo& vmo, vmoid_t* out) final;
zx_status_t DetachVmo(vmoid_t vmoid) final;
zx_status_t AddInodes(fzl::ResizeableVmoMapper* node_map) final;
zx_status_t AddBlocks(size_t nblocks, RawBitmap* block_map) final;
////////////////
+ // TransactionManager interface.
+ //
+ // Allows attaching VMOs, controlling the underlying volume, and sending transactions to the
+ // underlying storage (optionally through the journal).
+
+ BlobfsMetrics& LocalMetrics() final {
+ return metrics_;
+ }
+ zx_status_t CreateWork(fbl::unique_ptr<WritebackWork>* out, Blob* vnode) final;
+ zx_status_t EnqueueWork(fbl::unique_ptr<WritebackWork> work, EnqueueType type) final;
+
+ ////////////////
// Other methods.
uint64_t DataStart() const { return DataStartBlock(info_); }
@@ -143,10 +148,6 @@
static zx_status_t Create(fbl::unique_fd blockfd, const MountOptions& options,
const Superblock* info, fbl::unique_ptr<Blobfs>* out);
- BlobfsMetrics& LocalMetrics() {
- return metrics_;
- }
-
void CollectMetrics() {
collecting_metrics_ = true;
cobalt_metrics_.EnableMetrics(true);
@@ -186,22 +187,12 @@
int Fd() const { return blockfd_.get(); }
- const Superblock& Info() const { return info_; }
-
// Returns an unique identifier for this instance.
uint64_t GetFsId() const { return fs_id_; }
using SyncCallback = fs::Vnode::SyncCallback;
void Sync(SyncCallback closure);
- zx_status_t CreateWork(fbl::unique_ptr<WritebackWork>* out, Blob* vnode);
-
- // Enqueues |work| to the appropriate buffer. If |journal| is true and the journal is enabled,
- // the transaction(s) will first be written to the journal. Otherwise, they will be sent
- // straight to the writeback buffer.
- zx_status_t EnqueueWork(fbl::unique_ptr<WritebackWork> work,
- EnqueueType type) __WARN_UNUSED_RESULT;
-
// Frees an inode, from both the reserved map and the inode table. If the
// inode was allocated in the inode table, write the deleted inode out to
// disk.
diff --git a/system/ulib/blobfs/include/blobfs/journal.h b/system/ulib/blobfs/include/blobfs/journal.h
index 68d5a25..021fe6e 100644
--- a/system/ulib/blobfs/include/blobfs/journal.h
+++ b/system/ulib/blobfs/include/blobfs/journal.h
@@ -8,17 +8,22 @@
static_assert(false, "Fuchsia only header");
#endif
-#include <zircon/types.h>
-
-#include <stdint.h>
-
-#include <blobfs/format.h>
-#include <blobfs/writeback.h>
-
#include <atomic>
#include <utility>
+#include <stdint.h>
+
+#include <blobfs/blob.h>
+#include <blobfs/format.h>
+#include <blobfs/transaction-manager.h>
+#include <blobfs/writeback.h>
+#include <fbl/intrusive_single_list.h>
+#include <fbl/mutex.h>
+#include <fbl/unique_ptr.h>
+#include <zircon/types.h>
+
namespace blobfs {
+
class JournalBase;
class JournalProcessor;
@@ -209,8 +214,8 @@
DISALLOW_COPY_ASSIGN_AND_MOVE(Journal);
// Calls constructor, return an error if anything goes wrong.
- static zx_status_t Create(Blobfs* bs, uint64_t block_count, uint64_t start_block,
- fbl::unique_ptr<Journal>* out);
+ static zx_status_t Create(TransactionManager* transaction_manager, uint64_t block_count,
+ uint64_t start_block, fbl::unique_ptr<Journal>* out);
~Journal();
@@ -270,9 +275,9 @@
struct Waiter : public fbl::SinglyLinkedListable<Waiter*> {};
using ProducerQueue = fs::Queue<Waiter*>;
- Journal(Blobfs* blobfs, fbl::unique_ptr<Buffer> info, fbl::unique_ptr<Buffer> entries,
- uint64_t start_block)
- : blobfs_(blobfs), start_block_(start_block),
+ Journal(TransactionManager* transaction_manager, fbl::unique_ptr<Buffer> info,
+ fbl::unique_ptr<Buffer> entries, uint64_t start_block)
+ : transaction_manager_(transaction_manager), start_block_(start_block),
info_(std::move(info)), entries_(std::move(entries)) {}
bool IsRunning() const __TA_REQUIRES(lock_);
@@ -344,7 +349,7 @@
// Processes entries in the work queue and the processor queues.
void ProcessQueues(JournalProcessor* processor) __TA_EXCLUDES(lock_);
- Blobfs* blobfs_;
+ TransactionManager* transaction_manager_;
// The absolute start block of the journal on disk. Used for transactions.
uint64_t start_block_;
diff --git a/system/ulib/blobfs/include/blobfs/transaction-manager.h b/system/ulib/blobfs/include/blobfs/transaction-manager.h
new file mode 100644
index 0000000..0dc61cf
--- /dev/null
+++ b/system/ulib/blobfs/include/blobfs/transaction-manager.h
@@ -0,0 +1,46 @@
+// Copyright 2019 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.
+
+#pragma once
+
+#ifndef __Fuchsia__
+#error Fuchsia-only Header
+#endif
+
+#include <blobfs/allocator.h>
+#include <blobfs/blob.h>
+#include <blobfs/metrics.h>
+#include <fbl/unique_ptr.h>
+#include <fs/block-txn.h>
+#include <fs/vnode.h>
+
+namespace blobfs {
+
+class WritebackWork;
+
+// EnqueueType describes the classes of data which may be enqueued to the
+// underlying storage medium.
+enum class EnqueueType {
+ kJournal,
+ kData,
+};
+
+// An interface which controls access to the underlying storage.
+class TransactionManager : public fs::TransactionHandler,
+ public SpaceManager {
+public:
+ virtual ~TransactionManager() = default;
+ virtual BlobfsMetrics& LocalMetrics() = 0;
+
+ virtual zx_status_t CreateWork(fbl::unique_ptr<WritebackWork>* out, Blob* vnode) = 0;
+
+ // Enqueues |work| to the appropriate buffer.
+ // If the data is journaled, |work| will be transmitted to the journal, where it will be
+ // persisted only after consistency is ensured.
+ // If the data is not journaled, |work| will be transmitted directly to the writeback buffer /
+ // persistent storage.
+ virtual zx_status_t EnqueueWork(fbl::unique_ptr<WritebackWork> work, EnqueueType type) = 0;
+};
+
+} // namespace blobfs
diff --git a/system/ulib/blobfs/include/blobfs/writeback.h b/system/ulib/blobfs/include/blobfs/writeback.h
index d1f1feb..c0bef26 100644
--- a/system/ulib/blobfs/include/blobfs/writeback.h
+++ b/system/ulib/blobfs/include/blobfs/writeback.h
@@ -8,6 +8,13 @@
#error Fuchsia-only Header
#endif
+#include <utility>
+
+#include <blobfs/allocator.h>
+#include <blobfs/blob.h>
+#include <blobfs/format.h>
+#include <blobfs/metrics.h>
+#include <blobfs/transaction-manager.h>
#include <fbl/algorithm.h>
#include <fbl/auto_lock.h>
#include <fbl/intrusive_hash_table.h>
@@ -17,26 +24,16 @@
#include <fbl/ref_ptr.h>
#include <fbl/unique_ptr.h>
#include <fbl/vector.h>
-
#include <fs/block-txn.h>
#include <fs/queue.h>
#include <fs/vfs.h>
-
+#include <fs/vnode.h>
#include <lib/sync/completion.h>
-
#include <lib/fzl/owned-vmo-mapper.h>
#include <lib/zx/vmo.h>
-#include <blobfs/blobfs.h>
-#include <blobfs/format.h>
-
-#include <utility>
-
namespace blobfs {
-class Blobfs;
-class Blob;
-
struct WriteRequest {
zx_handle_t vmo;
size_t vmo_offset;
@@ -58,7 +55,8 @@
public:
DISALLOW_COPY_ASSIGN_AND_MOVE(WriteTxn);
- explicit WriteTxn(Blobfs* bs) : bs_(bs), vmoid_(VMOID_INVALID), block_count_(0) {}
+ explicit WriteTxn(TransactionManager* transaction_manager)
+ : transaction_manager_(transaction_manager), vmoid_(VMOID_INVALID), block_count_(0) {}
virtual ~WriteTxn();
@@ -101,13 +99,12 @@
zx_status_t Flush();
private:
- Blobfs* bs_;
+ TransactionManager* transaction_manager_;
vmoid_t vmoid_;
fbl::Vector<WriteRequest> requests_;
size_t block_count_;
};
-
// A wrapper around a WriteTxn, holding references to the underlying Vnodes
// corresponding to the txn, so their Vnodes (and VMOs) are not released
// while being written out to disk.
@@ -122,7 +119,7 @@
// Create a WritebackWork given a vnode (which may be null)
// Vnode is stored for duration of txn so that it isn't destroyed during the write process
- WritebackWork(Blobfs* bs, fbl::RefPtr<Blob> vnode);
+ WritebackWork(TransactionManager* transaction_manager, fbl::RefPtr<Blob> vnode);
~WritebackWork() = default;
// Sets the WritebackWork to a completed state. |status| should indicate whether the work was
@@ -178,8 +175,8 @@
~Buffer();
// Initializes the buffer VMO with |blocks| blocks of size kBlobfsBlockSize.
- static zx_status_t Create(Blobfs* blobfs, const size_t blocks, const char* label,
- fbl::unique_ptr<Buffer>* out);
+ static zx_status_t Create(TransactionManager* transaction_manager, const size_t blocks,
+ const char* label, fbl::unique_ptr<Buffer>* out);
// Adds a transaction to |txn| which reads all data into buffer
// starting from |disk_start| on disk.
@@ -233,11 +230,11 @@
return reinterpret_cast<char*>(mapper_.start()) + (index * kBlobfsBlockSize);
}
private:
- Buffer(Blobfs* blobfs, fzl::OwnedVmoMapper mapper)
- : blobfs_(blobfs), mapper_(std::move(mapper)), start_(0), length_(0),
- capacity_(mapper_.size() / kBlobfsBlockSize) {}
+ Buffer(TransactionManager* transaction_manager, fzl::OwnedVmoMapper mapper)
+ : transaction_manager_(transaction_manager), mapper_(std::move(mapper)), start_(0),
+ length_(0), capacity_(mapper_.size() / kBlobfsBlockSize) {}
- Blobfs* blobfs_;
+ TransactionManager* transaction_manager_;
fzl::OwnedVmoMapper mapper_;
vmoid_t vmoid_ = VMOID_INVALID;
@@ -257,7 +254,7 @@
// Initializes the WritebackBuffer at |out|
// with a buffer of |buffer_blocks| blocks of size kBlobfsBlockSize.
- static zx_status_t Create(Blobfs* bs, const size_t buffer_blocks,
+ static zx_status_t Create(TransactionManager* transaction_manager, const size_t buffer_blocks,
fbl::unique_ptr<WritebackQueue>* out);
// Copies all transaction data referenced from |work| into the writeback buffer.
diff --git a/system/ulib/blobfs/journal.cpp b/system/ulib/blobfs/journal.cpp
index 6f63568..6b99c8a 100644
--- a/system/ulib/blobfs/journal.cpp
+++ b/system/ulib/blobfs/journal.cpp
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include <blobfs/journal.h>
-
#include <fbl/unique_ptr.h>
#include <lib/cksum.h>
#include <zircon/types.h>
@@ -99,19 +98,20 @@
commit_block_.checksum = checksum;
}
-zx_status_t Journal::Create(Blobfs* blobfs, uint64_t journal_blocks, uint64_t start_block,
- fbl::unique_ptr<Journal>* out) {
+zx_status_t Journal::Create(TransactionManager* transaction_manager, uint64_t journal_blocks,
+ uint64_t start_block, fbl::unique_ptr<Journal>* out) {
// Create the buffer with 1 less than total journal blocks.
// (1 block must be reserved for journal info).
zx_status_t status;
fbl::unique_ptr<Buffer> buffer;
- if ((status = Buffer::Create(blobfs, journal_blocks - 1, "blobfs-journal", &buffer)) != ZX_OK) {
+ if ((status = Buffer::Create(transaction_manager, journal_blocks - 1, "blobfs-journal",
+ &buffer)) != ZX_OK) {
return status;
}
// Create another buffer for the journal info block.
fbl::unique_ptr<Buffer> info;
- if ((status = Buffer::Create(blobfs, 1, "blobfs-journal-info", &info)) != ZX_OK) {
+ if ((status = Buffer::Create(transaction_manager, 1, "blobfs-journal-info", &info)) != ZX_OK) {
return status;
}
@@ -119,8 +119,8 @@
info->ReserveIndex();
// Create the Journal with the newly created vmos.
- fbl::unique_ptr<Journal> journal(new Journal(blobfs, std::move(info), std::move(buffer),
- start_block));
+ fbl::unique_ptr<Journal> journal(new Journal(transaction_manager, std::move(info),
+ std::move(buffer), start_block));
// Load contents of journal from disk.
if ((status = journal->Load()) != ZX_OK) {
@@ -171,7 +171,7 @@
ZX_DEBUG_ASSERT(state_ == WritebackState::kInit);
// Load info block and journal entries into their respective buffers.
- fs::ReadTxn txn(blobfs_);
+ fs::ReadTxn txn(transaction_manager_);
info_->Load(&txn, start_block_);
entries_->Load(&txn, start_block_ + 1);
zx_status_t status = txn.Transact();
@@ -490,14 +490,14 @@
fbl::unique_ptr<WritebackWork> Journal::CreateWork() {
fbl::unique_ptr<WritebackWork> work;
- blobfs_->CreateWork(&work, nullptr);
+ transaction_manager_->CreateWork(&work, nullptr);
ZX_DEBUG_ASSERT(work != nullptr);
return work;
}
zx_status_t Journal::EnqueueEntryWork(fbl::unique_ptr<WritebackWork> work) {
entries_->ValidateTransaction(work.get());
- return blobfs_->EnqueueWork(std::move(work), EnqueueType::kData);
+ return transaction_manager_->EnqueueWork(std::move(work), EnqueueType::kData);
}
bool Journal::VerifyEntryMetadata(size_t header_index, uint64_t last_timestamp, bool expect_valid) {
@@ -631,7 +631,7 @@
}
fbl::unique_ptr<WritebackWork> work;
- blobfs_->CreateWork(&work, nullptr);
+ transaction_manager_->CreateWork(&work, nullptr);
info->start_block = start;
info->num_blocks = length;
@@ -644,7 +644,7 @@
info_->AddTransaction(0, start_block_, 1, work.get());
info_->ValidateTransaction(work.get());
- return blobfs_->EnqueueWork(std::move(work), EnqueueType::kData);
+ return transaction_manager_->EnqueueWork(std::move(work), EnqueueType::kData);
}
void Journal::EnsureSpaceLocked(size_t blocks) {
diff --git a/system/ulib/blobfs/writeback.cpp b/system/ulib/blobfs/writeback.cpp
index 4e3d450..a361520 100644
--- a/system/ulib/blobfs/writeback.cpp
+++ b/system/ulib/blobfs/writeback.cpp
@@ -66,13 +66,14 @@
zx_status_t WriteTxn::Flush() {
ZX_ASSERT(IsBuffered());
- fs::Ticker ticker(bs_->LocalMetrics().Collecting());
+ fs::Ticker ticker(transaction_manager_->LocalMetrics().Collecting());
// Update all the outgoing transactions to be in disk blocks
block_fifo_request_t blk_reqs[requests_.size()];
- const uint32_t kDiskBlocksPerBlobfsBlock = kBlobfsBlockSize / bs_->DeviceBlockSize();
+ const uint32_t kDiskBlocksPerBlobfsBlock =
+ kBlobfsBlockSize / transaction_manager_->DeviceBlockSize();
for (size_t i = 0; i < requests_.size(); i++) {
- blk_reqs[i].group = bs_->BlockGroupID();
+ blk_reqs[i].group = transaction_manager_->BlockGroupID();
blk_reqs[i].vmoid = vmoid_;
blk_reqs[i].opcode = BLOCKIO_WRITE;
blk_reqs[i].vmo_offset = requests_[i].vmo_offset * kDiskBlocksPerBlobfsBlock;
@@ -85,14 +86,14 @@
}
// Actually send the operations to the underlying block device.
- zx_status_t status = bs_->Transaction(blk_reqs, requests_.size());
+ zx_status_t status = transaction_manager_->Transaction(blk_reqs, requests_.size());
- if (bs_->LocalMetrics().Collecting()) {
+ if (transaction_manager_->LocalMetrics().Collecting()) {
uint64_t sum = 0;
for (const auto& blk_req : blk_reqs) {
sum += blk_req.length * kBlobfsBlockSize;
}
- bs_->LocalMetrics().UpdateWriteback(sum, ticker.End());
+ transaction_manager_->LocalMetrics().UpdateWriteback(sum, ticker.End());
}
requests_.reset();
@@ -148,8 +149,9 @@
return status;
}
-WritebackWork::WritebackWork(Blobfs* bs, fbl::RefPtr<Blob> vn) :
- WriteTxn(bs), ready_cb_(nullptr), sync_cb_(nullptr), sync_(false), vn_(std::move(vn)) {}
+WritebackWork::WritebackWork(TransactionManager* transaction_manager, fbl::RefPtr<Blob> vn)
+ : WriteTxn(transaction_manager), ready_cb_(nullptr), sync_cb_(nullptr), sync_(false),
+ vn_(std::move(vn)) {}
void WritebackWork::InvokeSyncCallback(zx_status_t status) {
if (sync_cb_) {
@@ -167,14 +169,14 @@
if (vmoid_ != VMOID_INVALID) {
// Close the buffer vmo.
block_fifo_request_t request;
- request.group = blobfs_->BlockGroupID();
+ request.group = transaction_manager_->BlockGroupID();
request.vmoid = vmoid_;
request.opcode = BLOCKIO_CLOSE_VMO;
- blobfs_->Transaction(&request, 1);
+ transaction_manager_->Transaction(&request, 1);
}
}
-zx_status_t Buffer::Create(Blobfs* blobfs, size_t blocks, const char* label,
+zx_status_t Buffer::Create(TransactionManager* blobfs, size_t blocks, const char* label,
fbl::unique_ptr<Buffer>* out) {
fzl::OwnedVmoMapper mapper;
@@ -185,7 +187,7 @@
}
fbl::unique_ptr<Buffer> buffer(new Buffer(blobfs, std::move(mapper)));
- if ((status = buffer->blobfs_->AttachVmo(buffer->mapper_.vmo(), &buffer->vmoid_))
+ if ((status = buffer->transaction_manager_->AttachVmo(buffer->mapper_.vmo(), &buffer->vmoid_))
!= ZX_OK) {
FS_TRACE_ERROR("Buffer: Failed to attach vmo\n");
return status;
@@ -366,11 +368,13 @@
return status;
}
-zx_status_t WritebackQueue::Create(Blobfs* blobfs, const size_t buffer_blocks,
+zx_status_t WritebackQueue::Create(TransactionManager* transaction_manager,
+ const size_t buffer_blocks,
fbl::unique_ptr<WritebackQueue>* out) {
zx_status_t status;
fbl::unique_ptr<Buffer> buffer;
- if ((status = Buffer::Create(blobfs, buffer_blocks, "blobfs-writeback", &buffer)) != ZX_OK) {
+ if ((status = Buffer::Create(transaction_manager, buffer_blocks, "blobfs-writeback", &buffer))
+ != ZX_OK) {
return status;
}