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 MagicJournalHeader61 uint32 Magic() const 62 { return B_BENDIAN_TO_HOST_INT32(magic); } BlockTypeJournalHeader63 uint32 BlockType() const 64 { return B_BENDIAN_TO_HOST_INT32(block_type); } SequenceJournalHeader65 uint32 Sequence() const 66 { return B_BENDIAN_TO_HOST_INT32(sequence); } 67 CheckMagicJournalHeader68 bool CheckMagic() const 69 { return Magic() == JOURNAL_MAGIC; } 70 IncrementSequenceJournalHeader71 void IncrementSequence() 72 { sequence = B_HOST_TO_BENDIAN_INT32(Sequence() + 1); } DecrementSequenceJournalHeader73 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 BlockNumberJournalBlockTag85 uint32 BlockNumber() const 86 { return B_BENDIAN_TO_HOST_INT32(block_number); } FlagsJournalBlockTag87 uint16 Flags() const 88 { return B_BENDIAN_TO_HOST_INT16(flags); } 89 SetBlockNumberJournalBlockTag90 void SetBlockNumber(uint32 block) 91 { block_number = B_HOST_TO_BENDIAN_INT32(block); } SetFlagsJournalBlockTag92 void SetFlags(uint16 new_flags) 93 { flags = B_HOST_TO_BENDIAN_INT16(new_flags); } SetLastTagFlagJournalBlockTag94 void SetLastTagFlag() 95 { flags |= B_HOST_TO_BENDIAN_INT16(JOURNAL_FLAG_LAST_TAG); } SetEscapedFlagJournalBlockTag96 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 BlockNumberJournalBlockTagV3107 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 FlagsJournalBlockTagV3115 uint32 Flags() const 116 { return B_BENDIAN_TO_HOST_INT32(flags); } 117 SetBlockNumberJournalBlockTagV3118 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 SetFlagsJournalBlockTagV3125 void SetFlags(uint32 new_flags) 126 { flags = B_HOST_TO_BENDIAN_INT32(new_flags); } SetLastTagFlagJournalBlockTagV3127 void SetLastTagFlag() 128 { flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_LAST_TAG); } SetEscapedFlagJournalBlockTagV3129 void SetEscapedFlag() 130 { flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_ESCAPED); } 131 } _PACKED; 132 133 134 struct JournalBlockTail { 135 uint32 checksum; 136 ChecksumJournalBlockTail137 uint32 Checksum() const 138 { return B_BENDIAN_TO_HOST_INT32(checksum); } 139 SetChecksumJournalBlockTail140 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 NumBytesJournalRevokeHeader151 uint32 NumBytes() const 152 { return B_BENDIAN_TO_HOST_INT32(num_bytes); } RevokeBlockJournalRevokeHeader153 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 BlockSizeJournalSuperBlock189 uint32 BlockSize() const 190 { return B_BENDIAN_TO_HOST_INT32(block_size); } NumBlocksJournalSuperBlock191 uint32 NumBlocks() const 192 { return B_BENDIAN_TO_HOST_INT32(num_blocks); } FirstLogBlockJournalSuperBlock193 uint32 FirstLogBlock() const 194 { return B_BENDIAN_TO_HOST_INT32(first_log_block); } FirstCommitIDJournalSuperBlock195 uint32 FirstCommitID() const 196 { return B_BENDIAN_TO_HOST_INT32(first_commit_id); } LogStartJournalSuperBlock197 uint32 LogStart() const 198 { return B_BENDIAN_TO_HOST_INT32(log_start); } IncompatibleFeaturesJournalSuperBlock199 uint32 IncompatibleFeatures() const 200 { return B_BENDIAN_TO_HOST_INT32(incompatible_features); } ReadOnlyCompatibleFeaturesJournalSuperBlock201 uint32 ReadOnlyCompatibleFeatures() const 202 { return B_BENDIAN_TO_HOST_INT32(read_only_compatible_features); } MaxTransactionBlocksJournalSuperBlock203 uint32 MaxTransactionBlocks() const 204 { return B_BENDIAN_TO_HOST_INT32(max_transaction_blocks); } MaxTransactionDataJournalSuperBlock205 uint32 MaxTransactionData() const 206 { return B_BENDIAN_TO_HOST_INT32(max_transaction_data); } ChecksumJournalSuperBlock207 uint32 Checksum() const 208 { return B_BENDIAN_TO_HOST_INT32(checksum); } 209 SetLogStartJournalSuperBlock210 void SetLogStart(uint32 logStart) 211 { log_start = B_HOST_TO_BENDIAN_INT32(logStart); } SetFirstCommitIDJournalSuperBlock212 void SetFirstCommitID(uint32 firstCommitID) 213 { first_commit_id = B_HOST_TO_BENDIAN_INT32(firstCommitID); } SetChecksumJournalSuperBlock214 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 GetFilesystemVolume()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