1 /*
2 * Copyright 2017, Chế Vũ Gia Hy, cvghy116@gmail.com.
3 * Copyright 2001-2012, Axel Dörfler, axeld@pinc-software.de.
4 * This file may be used under the terms of the MIT License.
5 */
6
7
8 #include "Journal.h"
9
10
11 //#define TRACE_BTRFS
12 #ifdef TRACE_BTRFS
13 # define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
14 #else
15 # define TRACE(x...) ;
16 #endif
17 # define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
18
19
Journal(Volume * volume)20 Journal::Journal(Volume* volume)
21 :
22 fVolume(volume),
23 fOwner(NULL),
24 fTransactionID(0),
25 fCurrentGeneration(volume->SuperBlock().Generation())
26 {
27 recursive_lock_init(&fLock, "btrfs journal");
28 }
29
30
~Journal()31 Journal::~Journal()
32 {
33 recursive_lock_destroy(&fLock);
34 }
35
36
37 /*static*/ void
_TransactionWritten(int32 transactionID,int32 event,void * _journal)38 Journal::_TransactionWritten(int32 transactionID, int32 event, void* _journal)
39 {
40 TRACE("TRANSACTION WRITTEN id %i\n", transactionID);
41 }
42
43
44 status_t
_TransactionDone(bool success)45 Journal::_TransactionDone(bool success)
46 {
47 if (!success) {
48 cache_abort_transaction(fVolume->BlockCache(), fTransactionID);
49 return B_OK;
50 }
51 cache_end_transaction(fVolume->BlockCache(), fTransactionID,
52 &_TransactionWritten, this);
53 // cache_sync_transaction(fVolume->BlockCache(), fTransactionID);
54 return B_OK;
55 }
56
57
58 status_t
Lock(Transaction * owner)59 Journal::Lock(Transaction* owner)
60 {
61 status_t status = recursive_lock_lock(&fLock);
62 if (status != B_OK)
63 return status;
64 if (recursive_lock_get_recursion(&fLock) > 1) {
65 // we'll just use the current transaction again
66 return B_OK;
67 }
68
69
70 if (owner != NULL)
71 owner->SetParent(fOwner);
72
73 fOwner = owner;
74
75 if (fOwner != NULL) {
76 fTransactionID = cache_start_transaction(fVolume->BlockCache());
77
78 if (fTransactionID < B_OK) {
79 recursive_lock_unlock(&fLock);
80 return fTransactionID;
81 }
82 fCurrentGeneration++;
83 TRACE("Journal::Lock() start transaction id: %i\n", fTransactionID);
84 }
85
86 return B_OK;
87 }
88
89
90 status_t
UnLock(Transaction * owner,bool success)91 Journal::UnLock(Transaction* owner, bool success)
92 {
93 if (recursive_lock_get_recursion(&fLock) == 1) {
94 if (owner != NULL) {
95 status_t status = _TransactionDone(success);
96 if (status != B_OK)
97 return status;
98 fOwner = owner->Parent();
99 } else {
100 fOwner = NULL;
101 }
102 }
103 recursive_lock_unlock(&fLock);
104 return B_OK;
105 }
106
107
108 // Transaction
109
110
Transaction(Volume * volume)111 Transaction::Transaction(Volume* volume)
112 :
113 fJournal(NULL),
114 fParent(NULL)
115 {
116 Start(volume);
117 }
118
119
Transaction()120 Transaction::Transaction()
121 :
122 fJournal(NULL),
123 fParent(NULL)
124 {
125 }
126
127
~Transaction()128 Transaction::~Transaction()
129 {
130 if (fJournal != NULL) {
131 fJournal->UnLock(this, false);
132 }
133 }
134
135
136 bool
HasBlock(fsblock_t blockNumber) const137 Transaction::HasBlock(fsblock_t blockNumber) const
138 {
139 return cache_has_block_in_transaction(fJournal->GetVolume()->BlockCache(),
140 ID(), blockNumber);
141 }
142
143
144 status_t
Start(Volume * volume)145 Transaction::Start(Volume* volume)
146 {
147 if (fJournal != NULL)
148 return B_OK;
149
150 fJournal = volume->GetJournal();
151 if (fJournal != NULL && fJournal->Lock(this) == B_OK) {
152 return B_OK;
153 }
154 fJournal = NULL;
155 return B_ERROR;
156 }
157
158
159 status_t
Done()160 Transaction::Done()
161 {
162 status_t status = B_OK;
163 if (fJournal != NULL) {
164 status = fJournal->UnLock(this, true);
165 if (status == B_OK)
166 fJournal = NULL;
167 }
168 return status;
169 }
170