1/*
2 * Copyright 2010, Haiku Inc. All rights reserved.
3 * Copyright 2001-2010, Axel D��rfler, axeld@pinc-software.de.
4 * This file may be used under the terms of the MIT License.
5 *
6 * Authors:
7 *		Janito V. Ferreira Filho
8 */
9#ifndef JOURNAL_H
10#define JOURNAL_H
11
12
13#define JOURNAL_MAGIC								0xc03b3998U
14
15#define JOURNAL_DESCRIPTOR_BLOCK					1
16#define JOURNAL_COMMIT_BLOCK						2
17#define JOURNAL_SUPERBLOCK_V1						3
18#define JOURNAL_SUPERBLOCK_V2						4
19#define JOURNAL_REVOKE_BLOCK						5
20
21#define JOURNAL_FLAG_ESCAPED						1
22#define JOURNAL_FLAG_SAME_UUID						2
23#define JOURNAL_FLAG_DELETED						4
24#define JOURNAL_FLAG_LAST_TAG						8
25
26#define JOURNAL_FEATURE_COMPATIBLE_CHECKSUM			0x1
27
28#define JOURNAL_FEATURE_INCOMPATIBLE_REVOKE			0x1
29#define JOURNAL_FEATURE_INCOMPATIBLE_64BIT			0x2
30#define JOURNAL_FEATURE_INCOMPATIBLE_ASYNC_COMMIT	0x4
31#define JOURNAL_FEATURE_INCOMPATIBLE_CSUM_V2		0x8
32#define JOURNAL_FEATURE_INCOMPATIBLE_CSUM_V3		0x10
33
34#define JOURNAL_KNOWN_READ_ONLY_COMPATIBLE_FEATURES	0
35#define JOURNAL_KNOWN_INCOMPATIBLE_FEATURES			\
36	(JOURNAL_FEATURE_INCOMPATIBLE_REVOKE | JOURNAL_FEATURE_INCOMPATIBLE_64BIT \
37		| JOURNAL_FEATURE_INCOMPATIBLE_CSUM_V3)
38
39#define JOURNAL_CHECKSUM_TYPE_CRC32					0x1
40#define JOURNAL_CHECKSUM_TYPE_MD5					0x2
41#define JOURNAL_CHECKSUM_TYPE_SHA1					0x3
42#define JOURNAL_CHECKSUM_TYPE_CRC32C				0x4
43
44#include "Volume.h"
45
46#include <AutoDeleter.h>
47#include <util/DoublyLinkedList.h>
48
49#include "Transaction.h"
50
51
52class RevokeManager;
53
54
55struct JournalHeader {
56	uint32			magic;
57	uint32			block_type;
58	uint32			sequence;
59	char			data[0];
60
61	uint32			Magic()			const
62		{ return B_BENDIAN_TO_HOST_INT32(magic); }
63	uint32			BlockType()		const
64		{ return B_BENDIAN_TO_HOST_INT32(block_type); }
65	uint32			Sequence()		const
66		{ return B_BENDIAN_TO_HOST_INT32(sequence); }
67
68	bool			CheckMagic()	const
69		{ return Magic() == JOURNAL_MAGIC; }
70
71	void			IncrementSequence()
72		{ sequence = B_HOST_TO_BENDIAN_INT32(Sequence() + 1); }
73	void			DecrementSequence()
74		{ sequence = B_HOST_TO_BENDIAN_INT32(Sequence() - 1); }
75	void			MakeDescriptor(uint32 sequence);
76	void			MakeCommit(uint32 sequence);
77} _PACKED;
78
79
80struct JournalBlockTag {
81	uint32			block_number;
82	uint16			checksum;
83	uint16			flags;
84
85	uint32			BlockNumber()	const
86		{ return B_BENDIAN_TO_HOST_INT32(block_number); }
87	uint16			Flags()			const
88		{ return B_BENDIAN_TO_HOST_INT16(flags); }
89
90	void			SetBlockNumber(uint32 block)
91		{ block_number = B_HOST_TO_BENDIAN_INT32(block); }
92	void			SetFlags(uint16 new_flags)
93		{ flags = B_HOST_TO_BENDIAN_INT16(new_flags); }
94	void			SetLastTagFlag()
95		{ flags |= B_HOST_TO_BENDIAN_INT16(JOURNAL_FLAG_LAST_TAG); }
96	void			SetEscapedFlag()
97		{ flags |= B_HOST_TO_BENDIAN_INT16(JOURNAL_FLAG_ESCAPED); }
98} _PACKED;
99
100
101struct JournalBlockTagV3 {
102	uint32			block_number;
103	uint32			flags;
104	uint32			block_number_high;
105	uint32			checksum;
106
107	uint64 BlockNumber(bool has64bits) const
108	{
109		uint64 num = B_BENDIAN_TO_HOST_INT32(block_number);
110		if (has64bits)
111			num |= ((uint64)B_BENDIAN_TO_HOST_INT32(block_number_high) << 32);
112		return num;
113	}
114
115	uint32			Flags()			const
116		{ return B_BENDIAN_TO_HOST_INT32(flags); }
117
118	void SetBlockNumber(uint64 block, bool has64bits)
119	{
120		block_number = B_HOST_TO_BENDIAN_INT32(block & 0xffffffff);
121		if (has64bits)
122			block_number_high = B_HOST_TO_BENDIAN_INT32(block >> 32);
123	}
124
125	void			SetFlags(uint32 new_flags)
126		{ flags = B_HOST_TO_BENDIAN_INT32(new_flags); }
127	void			SetLastTagFlag()
128		{ flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_LAST_TAG); }
129	void			SetEscapedFlag()
130		{ flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_ESCAPED); }
131} _PACKED;
132
133
134struct JournalBlockTail {
135	uint32			checksum;
136
137	uint32			Checksum()	const
138		{ return B_BENDIAN_TO_HOST_INT32(checksum); }
139
140	void			SetChecksum(uint32 new_checksum)
141		{ checksum = B_HOST_TO_BENDIAN_INT32(new_checksum); }
142} _PACKED;
143
144
145struct JournalRevokeHeader {
146	JournalHeader	header;
147	uint32			num_bytes;
148
149	uint32			revoke_blocks[0];
150
151	uint32			NumBytes()		const
152		{ return B_BENDIAN_TO_HOST_INT32(num_bytes); }
153	uint32			RevokeBlock(int offset)	const
154		{ return B_BENDIAN_TO_HOST_INT32(revoke_blocks[offset]); }
155} _PACKED;
156
157
158struct JournalSuperBlock {
159	JournalHeader	header;
160
161	uint32			block_size;
162	uint32			num_blocks;
163	uint32			first_log_block;
164
165	uint32			first_commit_id;
166	uint32			log_start;
167
168	uint32			error;
169
170	uint32			compatible_features;
171	uint32			incompatible_features;
172	uint32			read_only_compatible_features;
173
174	uint8			uuid[16];
175
176	uint32			num_users;
177	uint32			dynamic_superblock;
178
179	uint32			max_transaction_blocks;
180	uint32			max_transaction_data;
181
182	uint8			checksum_type;
183	uint8			padding2[3];
184	uint32			padding[42];
185	uint32			checksum;
186
187	uint8			user_ids[16*48];
188
189	uint32			BlockSize() const
190		{ return B_BENDIAN_TO_HOST_INT32(block_size); }
191	uint32			NumBlocks() const
192		{ return B_BENDIAN_TO_HOST_INT32(num_blocks); }
193	uint32			FirstLogBlock() const
194		{ return B_BENDIAN_TO_HOST_INT32(first_log_block); }
195	uint32			FirstCommitID() const
196		{ return B_BENDIAN_TO_HOST_INT32(first_commit_id); }
197	uint32			LogStart() const
198		{ return B_BENDIAN_TO_HOST_INT32(log_start); }
199	uint32			IncompatibleFeatures() const
200		{ return B_BENDIAN_TO_HOST_INT32(incompatible_features); }
201	uint32			ReadOnlyCompatibleFeatures() const
202		{ return B_BENDIAN_TO_HOST_INT32(read_only_compatible_features); }
203	uint32			MaxTransactionBlocks() const
204		{ return B_BENDIAN_TO_HOST_INT32(max_transaction_blocks); }
205	uint32			MaxTransactionData() const
206		{ return B_BENDIAN_TO_HOST_INT32(max_transaction_data); }
207	uint32			Checksum() const
208		{ return B_BENDIAN_TO_HOST_INT32(checksum); }
209
210	void			SetLogStart(uint32 logStart)
211		{ log_start = B_HOST_TO_BENDIAN_INT32(logStart); }
212	void			SetFirstCommitID(uint32 firstCommitID)
213		{ first_commit_id = B_HOST_TO_BENDIAN_INT32(firstCommitID); }
214	void			SetChecksum(uint32 checksum)
215		{ log_start = B_HOST_TO_BENDIAN_INT32(checksum); }
216
217
218} _PACKED;
219
220class LogEntry;
221class Transaction;
222typedef DoublyLinkedList<LogEntry> LogEntryList;
223
224
225class Journal {
226public:
227								Journal(Volume *fsVolume, Volume *jVolume);
228	virtual						~Journal();
229
230	virtual	status_t			InitCheck();
231	virtual	status_t			Uninit();
232
233	virtual	status_t			Recover();
234	virtual	status_t			StartLog();
235			status_t			RestartLog();
236
237	virtual	status_t			Lock(Transaction* owner,
238									bool separateSubTransactions);
239	virtual	status_t			Unlock(Transaction* owner, bool success);
240
241	virtual	status_t			MapBlock(off_t logical, fsblock_t& physical);
242	inline	uint32				FreeLogBlocks() const;
243
244			status_t			FlushLogAndBlocks();
245
246			int32				TransactionID() const;
247
248			Volume*				GetFilesystemVolume()
249				{ return fFilesystemVolume; }
250protected:
251								Journal();
252
253			status_t			_WritePartialTransactionToLog(
254									JournalHeader* descriptorBlock,
255									bool detached, uint8** escapedBlock,
256									uint32& logBlock, off_t& blockNumber,
257									long& cookie,
258									ArrayDeleter<uint8>& escapedDataDeleter,
259									uint32& blockCount, bool& finished);
260	virtual status_t			_WriteTransactionToLog();
261
262			status_t			_SaveSuperBlock();
263			status_t			_LoadSuperBlock();
264
265
266			Volume*				fJournalVolume;
267			void*				fJournalBlockCache;
268			Volume*				fFilesystemVolume;
269			void*				fFilesystemBlockCache;
270
271			recursive_lock		fLock;
272			Transaction*		fOwner;
273
274			RevokeManager*		fRevokeManager;
275
276			status_t			fInitStatus;
277			uint32				fBlockSize;
278			uint32				fFirstCommitID;
279			uint32				fFirstCacheCommitID;
280			uint32				fFirstLogBlock;
281			uint32				fLogSize;
282			uint32				fVersion;
283
284			bool				fIsStarted;
285			uint32				fLogStart;
286			uint32				fLogEnd;
287			uint32				fFreeBlocks;
288			uint32				fMaxTransactionSize;
289
290			uint32				fCurrentCommitID;
291
292			LogEntryList		fLogEntries;
293			mutex				fLogEntriesLock;
294			bool				fHasSubTransaction;
295			bool				fSeparateSubTransactions;
296			int32				fUnwrittenTransactions;
297			int32				fTransactionID;
298
299			bool				fChecksumEnabled;
300			bool				fChecksumV3Enabled;
301			bool				fFeature64bits;
302			uint32				fChecksumSeed;
303
304private:
305			status_t			_CheckFeatures(JournalSuperBlock* superblock);
306
307			uint32				_Checksum(JournalSuperBlock* superblock);
308			bool				_Checksum(uint8 *block, bool set = false);
309
310			uint32				_CountTags(JournalHeader *descriptorBlock);
311			size_t				_TagSize();
312			status_t			_RecoverPassScan(uint32& lastCommitID);
313			status_t			_RecoverPassRevoke(uint32 lastCommitID);
314			status_t			_RecoverPassReplay(uint32 lastCommitID);
315
316			status_t			_FlushLog(bool canWait, bool flushBlocks);
317
318	inline	uint32				_WrapAroundLog(uint32 block);
319
320			size_t				_CurrentTransactionSize() const;
321			size_t				_FullTransactionSize() const;
322			size_t				_MainTransactionSize() const;
323
324	virtual	status_t			_TransactionDone(bool success);
325
326	static	void				_TransactionWritten(int32 transactionID,
327									int32 event, void* _logEntry);
328	static	void				_TransactionIdle(int32 transactionID,
329									int32 event, void* _journal);
330};
331
332#endif	// JOURNAL_H
333
334