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
20Journal::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
31Journal::~Journal()
32{
33	recursive_lock_destroy(&fLock);
34}
35
36
37/*static*/ void
38Journal::_TransactionWritten(int32 transactionID, int32 event, void* _journal)
39{
40	TRACE("TRANSACTION WRITTEN id %i\n", transactionID);
41}
42
43
44status_t
45Journal::_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
58status_t
59Journal::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
90status_t
91Journal::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
111Transaction::Transaction(Volume* volume)
112	:
113	fJournal(NULL),
114	fParent(NULL)
115{
116	Start(volume);
117}
118
119
120Transaction::Transaction()
121	:
122	fJournal(NULL),
123	fParent(NULL)
124{
125}
126
127
128Transaction::~Transaction()
129{
130	if (fJournal != NULL) {
131		fJournal->UnLock(this, false);
132	}
133}
134
135
136bool
137Transaction::HasBlock(fsblock_t blockNumber) const
138{
139	return cache_has_block_in_transaction(fJournal->GetVolume()->BlockCache(),
140		ID(), blockNumber);
141}
142
143
144status_t
145Transaction::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
159status_t
160Transaction::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