xref: /haiku/src/add-ons/kernel/file_systems/ext2/Journal.h (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
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 
52 class RevokeManager;
53 
54 
55 struct 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 
80 struct 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 
101 struct 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 
134 struct 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 
145 struct 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 
158 struct 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 
220 class LogEntry;
221 class Transaction;
222 typedef DoublyLinkedList<LogEntry> LogEntryList;
223 
224 
225 class Journal {
226 public:
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; }
250 protected:
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 
304 private:
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