[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;
     }