1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <blobfs/journal.h>
6 #include <unittest/unittest.h>
7 
8 namespace blobfs {
9 namespace {
10 
11 // Mock journal implementation which can be used to test JournalEntry / JournalProcessor
12 // functionality.
13 class MockJournal : public JournalBase {
14 public:
MockJournal()15     MockJournal() : readonly_(false), capacity_(0) {}
16 
SendSignal(zx_status_t status)17     void SendSignal(zx_status_t status) final {
18         if (status != ZX_OK) {
19             readonly_ = true;
20         }
21     }
22 
CreateDefaultWork()23     fbl::unique_ptr<blobfs::WritebackWork> CreateDefaultWork() {
24         return CreateWork();
25     }
26 
CreateBufferedWork(size_t block_count)27     fbl::unique_ptr<WritebackWork> CreateBufferedWork(size_t block_count) {
28         fbl::unique_ptr<WritebackWork> work = CreateWork();
29 
30         zx::vmo vmo;
31         ZX_ASSERT(zx::vmo::create(PAGE_SIZE, 0, &vmo) == ZX_OK);
32         work->Enqueue(vmo, 0, 0, block_count);
33         work->SetBuffer(2);
34         return work;
35     }
36 
37 private:
GetCapacity() const38     size_t GetCapacity() const final {
39         return capacity_;
40     }
41 
IsReadOnly() const42     bool IsReadOnly() const final {
43         return readonly_;
44     }
45 
CreateWork()46     fbl::unique_ptr<WritebackWork> CreateWork() final {
47         return fbl::make_unique<blobfs::WritebackWork>(nullptr, nullptr);
48     }
49 
50     // The following functions are no-ops, and only exist so they can be called by the
51     // JournalProcessor.
PrepareBuffer(JournalEntry * entry)52     void PrepareBuffer(JournalEntry* entry) final {}
PrepareDelete(JournalEntry * entry,WritebackWork * work)53     void PrepareDelete(JournalEntry* entry, WritebackWork* work) final {}
EnqueueEntryWork(fbl::unique_ptr<WritebackWork> work)54     zx_status_t EnqueueEntryWork(fbl::unique_ptr<WritebackWork> work) final {
55         return ZX_OK;
56     }
57 
58     bool readonly_;
59     size_t capacity_;
60 };
61 
JournalEntryLifetimeTest()62 static bool JournalEntryLifetimeTest() {
63     BEGIN_TEST;
64 
65     // Create a dummy journal and journal processor.
66     MockJournal journal;
67     blobfs::JournalProcessor processor(&journal);
68 
69     // Create and process a 'work' entry.
70     fbl::unique_ptr<blobfs::JournalEntry> entry(
71         new blobfs::JournalEntry(&journal, blobfs::EntryStatus::kInit, 0, 0,
72                                  journal.CreateBufferedWork(1)));
73     fbl::unique_ptr<blobfs::WritebackWork> first_work = journal.CreateDefaultWork();
74     first_work->SetSyncCallback(entry->CreateSyncCallback());
75     processor.ProcessWorkEntry(std::move(entry));
76 
77     // Create and process another 'work' entry.
78     entry.reset(new blobfs::JournalEntry(&journal, blobfs::EntryStatus::kInit, 0, 0,
79                                          journal.CreateBufferedWork(1)));
80     fbl::unique_ptr<blobfs::WritebackWork> second_work = journal.CreateDefaultWork();
81     second_work->SetSyncCallback(entry->CreateSyncCallback());
82     processor.ProcessWorkEntry(std::move(entry));
83 
84     // Enqueue the processor's work (this is a no-op).
85     processor.EnqueueWork();
86 
87     // Simulate an error in the writeback thread by calling the first entry's callback with an
88     // error status.
89     first_work->Reset(ZX_ERR_BAD_STATE);
90 
91     // Process the wait queue.
92     processor.ProcessWaitQueue();
93 
94     // Now, attempt to call the second entry's callback with the error. If we are incorrectly
95     // disposing of entries before their callbacks have been invoked, this should trigger a
96     // "use-after-free" asan error, since the JournalEntry referenced by second_work will have
97     // already been deleted (see ZX-2940).
98     second_work->Reset(ZX_ERR_BAD_STATE);
99 
100     // Additionally, we should check that the processor queues are not empty - i.e., there is still
101     // one entry waiting to be processed.
102     ASSERT_FALSE(processor.IsEmpty());
103 
104     // Process the rest of the queues.
105     processor.ProcessWaitQueue();
106     processor.ProcessDeleteQueue();
107     processor.ProcessSyncQueue();
108 
109     END_TEST;
110 }
111 
112 } // namespace
113 } // namespace blobfs
114 
115 BEGIN_TEST_CASE(blobfsJournalTests)
116 RUN_TEST(blobfs::JournalEntryLifetimeTest)
117 END_TEST_CASE(blobfsJournalTests);
118