/* * Copyright 2010, Haiku Inc. All rights reserved. * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de. * This file may be used under the terms of the MIT License. * * Authors: * Janito V. Ferreira Filho */ #ifndef JOURNAL_H #define JOURNAL_H #define JOURNAL_MAGIC 0xc03b3998U #define JOURNAL_DESCRIPTOR_BLOCK 1 #define JOURNAL_COMMIT_BLOCK 2 #define JOURNAL_SUPERBLOCK_V1 3 #define JOURNAL_SUPERBLOCK_V2 4 #define JOURNAL_REVOKE_BLOCK 5 #define JOURNAL_FLAG_ESCAPED 1 #define JOURNAL_FLAG_SAME_UUID 2 #define JOURNAL_FLAG_DELETED 4 #define JOURNAL_FLAG_LAST_TAG 8 #define JOURNAL_FEATURE_COMPATIBLE_CHECKSUM 0x1 #define JOURNAL_FEATURE_INCOMPATIBLE_REVOKE 0x1 #define JOURNAL_FEATURE_INCOMPATIBLE_64BIT 0x2 #define JOURNAL_FEATURE_INCOMPATIBLE_ASYNC_COMMIT 0x4 #define JOURNAL_FEATURE_INCOMPATIBLE_CSUM_V2 0x8 #define JOURNAL_FEATURE_INCOMPATIBLE_CSUM_V3 0x10 #define JOURNAL_KNOWN_READ_ONLY_COMPATIBLE_FEATURES 0 #define JOURNAL_KNOWN_INCOMPATIBLE_FEATURES \ (JOURNAL_FEATURE_INCOMPATIBLE_REVOKE | JOURNAL_FEATURE_INCOMPATIBLE_64BIT \ | JOURNAL_FEATURE_INCOMPATIBLE_CSUM_V3) #define JOURNAL_CHECKSUM_TYPE_CRC32 0x1 #define JOURNAL_CHECKSUM_TYPE_MD5 0x2 #define JOURNAL_CHECKSUM_TYPE_SHA1 0x3 #define JOURNAL_CHECKSUM_TYPE_CRC32C 0x4 #include "Volume.h" #include #include #include "Transaction.h" class RevokeManager; struct JournalHeader { uint32 magic; uint32 block_type; uint32 sequence; char data[0]; uint32 Magic() const { return B_BENDIAN_TO_HOST_INT32(magic); } uint32 BlockType() const { return B_BENDIAN_TO_HOST_INT32(block_type); } uint32 Sequence() const { return B_BENDIAN_TO_HOST_INT32(sequence); } bool CheckMagic() const { return Magic() == JOURNAL_MAGIC; } void IncrementSequence() { sequence = B_HOST_TO_BENDIAN_INT32(Sequence() + 1); } void DecrementSequence() { sequence = B_HOST_TO_BENDIAN_INT32(Sequence() - 1); } void MakeDescriptor(uint32 sequence); void MakeCommit(uint32 sequence); } _PACKED; struct JournalBlockTag { uint32 block_number; uint16 checksum; uint16 flags; uint32 BlockNumber() const { return B_BENDIAN_TO_HOST_INT32(block_number); } uint16 Flags() const { return B_BENDIAN_TO_HOST_INT16(flags); } void SetBlockNumber(uint32 block) { block_number = B_HOST_TO_BENDIAN_INT32(block); } void SetFlags(uint16 new_flags) { flags = B_HOST_TO_BENDIAN_INT16(new_flags); } void SetLastTagFlag() { flags |= B_HOST_TO_BENDIAN_INT16(JOURNAL_FLAG_LAST_TAG); } void SetEscapedFlag() { flags |= B_HOST_TO_BENDIAN_INT16(JOURNAL_FLAG_ESCAPED); } } _PACKED; struct JournalBlockTagV3 { uint32 block_number; uint32 flags; uint32 block_number_high; uint32 checksum; uint64 BlockNumber(bool has64bits) const { uint64 num = B_BENDIAN_TO_HOST_INT32(block_number); if (has64bits) num |= ((uint64)B_BENDIAN_TO_HOST_INT32(block_number_high) << 32); return num; } uint32 Flags() const { return B_BENDIAN_TO_HOST_INT32(flags); } void SetBlockNumber(uint64 block, bool has64bits) { block_number = B_HOST_TO_BENDIAN_INT32(block & 0xffffffff); if (has64bits) block_number_high = B_HOST_TO_BENDIAN_INT32(block >> 32); } void SetFlags(uint32 new_flags) { flags = B_HOST_TO_BENDIAN_INT32(new_flags); } void SetLastTagFlag() { flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_LAST_TAG); } void SetEscapedFlag() { flags |= B_HOST_TO_BENDIAN_INT32(JOURNAL_FLAG_ESCAPED); } } _PACKED; struct JournalBlockTail { uint32 checksum; uint32 Checksum() const { return B_BENDIAN_TO_HOST_INT32(checksum); } void SetChecksum(uint32 new_checksum) { checksum = B_HOST_TO_BENDIAN_INT32(new_checksum); } } _PACKED; struct JournalRevokeHeader { JournalHeader header; uint32 num_bytes; uint32 revoke_blocks[0]; uint32 NumBytes() const { return B_BENDIAN_TO_HOST_INT32(num_bytes); } uint32 RevokeBlock(int offset) const { return B_BENDIAN_TO_HOST_INT32(revoke_blocks[offset]); } } _PACKED; struct JournalSuperBlock { JournalHeader header; uint32 block_size; uint32 num_blocks; uint32 first_log_block; uint32 first_commit_id; uint32 log_start; uint32 error; uint32 compatible_features; uint32 incompatible_features; uint32 read_only_compatible_features; uint8 uuid[16]; uint32 num_users; uint32 dynamic_superblock; uint32 max_transaction_blocks; uint32 max_transaction_data; uint8 checksum_type; uint8 padding2[3]; uint32 padding[42]; uint32 checksum; uint8 user_ids[16*48]; uint32 BlockSize() const { return B_BENDIAN_TO_HOST_INT32(block_size); } uint32 NumBlocks() const { return B_BENDIAN_TO_HOST_INT32(num_blocks); } uint32 FirstLogBlock() const { return B_BENDIAN_TO_HOST_INT32(first_log_block); } uint32 FirstCommitID() const { return B_BENDIAN_TO_HOST_INT32(first_commit_id); } uint32 LogStart() const { return B_BENDIAN_TO_HOST_INT32(log_start); } uint32 IncompatibleFeatures() const { return B_BENDIAN_TO_HOST_INT32(incompatible_features); } uint32 ReadOnlyCompatibleFeatures() const { return B_BENDIAN_TO_HOST_INT32(read_only_compatible_features); } uint32 MaxTransactionBlocks() const { return B_BENDIAN_TO_HOST_INT32(max_transaction_blocks); } uint32 MaxTransactionData() const { return B_BENDIAN_TO_HOST_INT32(max_transaction_data); } uint32 Checksum() const { return B_BENDIAN_TO_HOST_INT32(checksum); } void SetLogStart(uint32 logStart) { log_start = B_HOST_TO_BENDIAN_INT32(logStart); } void SetFirstCommitID(uint32 firstCommitID) { first_commit_id = B_HOST_TO_BENDIAN_INT32(firstCommitID); } void SetChecksum(uint32 checksum) { log_start = B_HOST_TO_BENDIAN_INT32(checksum); } } _PACKED; class LogEntry; class Transaction; typedef DoublyLinkedList LogEntryList; class Journal { public: Journal(Volume *fsVolume, Volume *jVolume); virtual ~Journal(); virtual status_t InitCheck(); virtual status_t Uninit(); virtual status_t Recover(); virtual status_t StartLog(); status_t RestartLog(); virtual status_t Lock(Transaction* owner, bool separateSubTransactions); virtual status_t Unlock(Transaction* owner, bool success); virtual status_t MapBlock(off_t logical, fsblock_t& physical); inline uint32 FreeLogBlocks() const; status_t FlushLogAndBlocks(); int32 TransactionID() const; Volume* GetFilesystemVolume() { return fFilesystemVolume; } protected: Journal(); status_t _WritePartialTransactionToLog( JournalHeader* descriptorBlock, bool detached, uint8** escapedBlock, uint32& logBlock, off_t& blockNumber, long& cookie, ArrayDeleter& escapedDataDeleter, uint32& blockCount, bool& finished); virtual status_t _WriteTransactionToLog(); status_t _SaveSuperBlock(); status_t _LoadSuperBlock(); Volume* fJournalVolume; void* fJournalBlockCache; Volume* fFilesystemVolume; void* fFilesystemBlockCache; recursive_lock fLock; Transaction* fOwner; RevokeManager* fRevokeManager; status_t fInitStatus; uint32 fBlockSize; uint32 fFirstCommitID; uint32 fFirstCacheCommitID; uint32 fFirstLogBlock; uint32 fLogSize; uint32 fVersion; bool fIsStarted; uint32 fLogStart; uint32 fLogEnd; uint32 fFreeBlocks; uint32 fMaxTransactionSize; uint32 fCurrentCommitID; LogEntryList fLogEntries; mutex fLogEntriesLock; bool fHasSubTransaction; bool fSeparateSubTransactions; int32 fUnwrittenTransactions; int32 fTransactionID; bool fChecksumEnabled; bool fChecksumV3Enabled; bool fFeature64bits; uint32 fChecksumSeed; private: status_t _CheckFeatures(JournalSuperBlock* superblock); uint32 _Checksum(JournalSuperBlock* superblock); bool _Checksum(uint8 *block, bool set = false); uint32 _CountTags(JournalHeader *descriptorBlock); size_t _TagSize(); status_t _RecoverPassScan(uint32& lastCommitID); status_t _RecoverPassRevoke(uint32 lastCommitID); status_t _RecoverPassReplay(uint32 lastCommitID); status_t _FlushLog(bool canWait, bool flushBlocks); inline uint32 _WrapAroundLog(uint32 block); size_t _CurrentTransactionSize() const; size_t _FullTransactionSize() const; size_t _MainTransactionSize() const; virtual status_t _TransactionDone(bool success); static void _TransactionWritten(int32 transactionID, int32 event, void* _logEntry); static void _TransactionIdle(int32 transactionID, int32 event, void* _journal); }; #endif // JOURNAL_H