/*++ BUILD Version: 0000 // Increment this if a change has global effects Copyright (c) 1989 Microsoft Corporation Module Name: LfsProcs.h Abstract: This module defines all of the globally used procedures in the Log File Service. Author: Brian Andrew [BrianAn] 20-June-1991 Revision History: --*/ #ifndef _LFSPROCS_ #define _LFSPROCS_ #include #include #include #include "nodetype.h" #include "LfsDisk.h" #include "LfsStruc.h" #include "LfsData.h" // // Tag all of our allocations if tagging is turned on // #undef FsRtlAllocatePool #undef FsRtlAllocatePoolWithQuota #define FsRtlAllocatePool(a,b) FsRtlAllocatePoolWithTag(a,b,' sfL') #define FsRtlAllocatePoolWithQuota(a,b) FsRtlAllocatePoolWithQuotaTag(a,b,' sfL') #define LfsAllocatePoolNoRaise(a,b) ExAllocatePoolWithTag((a),(b),MODULE_POOL_TAG) #define LfsAllocatePool(a,b) ExAllocatePoolWithTag(((a) | POOL_RAISE_IF_ALLOCATION_FAILURE),(b),MODULE_POOL_TAG) #define LfsFreePool(pv) ExFreePool(pv) #ifndef INLINE // definition of inline #define INLINE __inline #endif // // The following routines provide an interface with the cache package. // They are contained in 'CacheSup.c'. // NTSTATUS LfsPinOrMapData ( IN PLFCB Lfcb, IN LONGLONG FileOffset, IN ULONG Length, IN BOOLEAN PinData, IN BOOLEAN AllowErrors, IN BOOLEAN IgnoreUsaErrors, OUT PBOOLEAN UsaError, OUT PVOID *Buffer, OUT PBCB *Bcb ); // // VOID // LfsPreparePinWriteData ( // IN PLFCB Lfcb, // IN LONGLONG FileOffset, // IN ULONG Length, // IN LOGICAL ReadFromDisk, // OUT PVOID *Buffer, // OUT PBCB *Bcb // ); // #ifdef LFS_CLUSTER_CHECK #define LfsPreparePinWriteData(L,FO,LEN,R,BUF,B) { \ LONGLONG _LocalFileOffset = (FO); \ CcPinRead( (L)->FileObject, \ (PLARGE_INTEGER)&_LocalFileOffset, \ (LEN), \ TRUE, \ (B), \ (BUF) ); \ } #else #define LfsPreparePinWriteData(L,FO,LEN,R,BUF,B) { \ LONGLONG _LocalFileOffset = (FO); \ if (R) { \ CcPinRead( (L)->FileObject, \ (PLARGE_INTEGER)&_LocalFileOffset, \ (LEN), \ TRUE, \ (B), \ (BUF) ); \ } else { \ CcPreparePinWrite( (L)->FileObject, \ (PLARGE_INTEGER)&_LocalFileOffset, \ (LEN), \ FALSE, \ TRUE, \ (B), \ (BUF) ); \ } \ } #endif VOID LfsPinOrMapLogRecordHeader ( IN PLFCB Lfcb, IN LSN Lsn, IN BOOLEAN PinData, IN BOOLEAN IgnoreUsaErrors, OUT PBOOLEAN UsaError, OUT PLFS_RECORD_HEADER *RecordHeader, OUT PBCB *Bcb ); VOID LfsCopyReadLogRecord ( IN PLFCB Lfcb, IN PLFS_RECORD_HEADER RecordHeader, OUT PVOID Buffer ); VOID LfsFlushLfcb ( IN PLFCB Lfcb, IN LSN TargetLsn, IN BOOLEAN RestartLsn ); BOOLEAN LfsReadRestart ( IN PLFCB Lfcb, IN LONGLONG FileSize, IN BOOLEAN FirstRestart, OUT PLONGLONG RestartPageOffset, OUT PLFS_RESTART_PAGE_HEADER *RestartPage, OUT PBCB *RestartPageBcb, OUT PBOOLEAN ChkdskWasRun, OUT PBOOLEAN ValidPage, OUT PBOOLEAN UninitializedFile, OUT PBOOLEAN LogPacked, OUT PLSN LastLsn ); // // The following routines manipulate buffer control blocks. They are // contained in 'LbcbSup.c' // VOID LfsFlushLbcb ( IN PLFCB Lfcb, IN PLBCB Lbcb ); VOID LfsFlushToLsnPriv ( IN PLFCB Lfcb, IN LSN Lsn, IN BOOLEAN RestartLsn ); PLBCB LfsGetLbcb ( IN PLFCB Lfcb ); // // The following routines are in LfsData.c // LONG LfsExceptionFilter ( IN PEXCEPTION_POINTERS ExceptionPointer ); // // Log page support routines. The following routines manipulate and // modify log pages. They are contained in 'LogPgSup.c' // // // VOID // LfsTruncateOffsetToLogPage ( // IN PLFCB Lfcb, // IN LONGLONG LargeInt, // OUT PLONGLONG Result // ); // // ULONG // LfsLogPageOffset ( // IN PLFCB Lfcb, // IN ULONG Integer // ); // #define LfsTruncateOffsetToLogPage(LFCB,LI,OUTLI) \ *(OUTLI) = LI; \ *((PULONG)(OUTLI)) &= (LFCB)->LogPageInverseMask #define LfsLogPageOffset(LFCB,INT) \ (INT & (LFCB)->LogPageMask) VOID LfsNextLogPageOffset ( IN PLFCB Lfcb, IN LONGLONG CurrentLogPageOffset, OUT PLONGLONG NextLogPageOffset, OUT PBOOLEAN Wrapped ); PVOID LfsAllocateSpanningBuffer ( IN PLFCB Lfcb, IN ULONG Length ); VOID LfsFreeSpanningBuffer ( IN PVOID Buffer ); // // The following routines provide support for dealing with log records. They // are contained in 'LogRcSup.c' // BOOLEAN LfsWriteLogRecordIntoLogPage ( IN PLFCB Lfcb, IN PLCH Lch, IN ULONG NumberOfWriteEntries, IN PLFS_WRITE_ENTRY WriteEntries, IN LFS_RECORD_TYPE RecordType, IN TRANSACTION_ID *TransactionId OPTIONAL, IN LSN ClientUndoNextLsn OPTIONAL, IN LSN ClientPreviousLsn OPTIONAL, IN LONG UndoRequirement, IN BOOLEAN ForceToDisk, OUT PLSN Lsn ); // // Lsn support routines. The following routines provide support for // manipulating Lsn values. They are contained in 'LsnSup.c' // // // LSN // LfsFileOffsetToLsn ( // IN PLFCB Lfcb, // IN LONGLONG FileOffset, // IN LONGLONG SequenceNumber // ); // // BOOLEAN // LfsIsLsnInFile ( // IN PLFCB Lfcb, // IN LSN Lsn // ); // // LSN // LfsComputeLsnFromLbcb ( // IN PLFCB Lfcb, // IN PLBCB Lbcb // ); // // VOID // LfsTruncateLsnToLogPage ( // IN PLFCB Lfcb, // IN LSN Lsn, // OUT PLONGLONG FileOffset // ); // // LONGLONG // LfsLsnToFileOffset ( // IN PLFCB Lfcb, // IN LSN Lsn // ); // // LONGLONG // LfsLsnToSeqNumber ( // IN PLFCB Lfcb, // IN LSN Lsn // ); // // ULONG // LfsLsnToPageOffset ( // IN PLFCB Lfcb, // IN LSN Lsn // ); // #define LfsFileOffsetToLsn(LFCB,FO,SN) ( \ (((ULONGLONG)(FO)) >> 3) + Int64ShllMod32((SN), (LFCB)->FileDataBits) \ ) #define LfsIsLsnInFile(LFCB,LSN) \ (/*xxGeq*/( (LSN).QuadPart >= ((LFCB)->OldestLsn).QuadPart ) \ && /*xxLeq*/( (LSN).QuadPart <= ((LFCB)->RestartArea->CurrentLsn).QuadPart )) #define LfsComputeLsnFromLbcb(LFCB,LBCB) ( \ LfsFileOffsetToLsn( LFCB, \ (LBCB)->FileOffset + (LBCB)->BufferOffset, \ (LBCB)->SeqNumber ) \ ) #define LfsTruncateLsnToLogPage(LFCB,LSN,FO) { \ *(FO) = LfsLsnToFileOffset( LFCB, LSN ); \ *((PULONG)(FO)) &= (LFCB)->LogPageInverseMask; \ } #define LfsLsnToFileOffset(LFCB,LSN) \ /*xxShr*/( ((ULONGLONG)/*xxShl*/( (LSN).QuadPart << (LFCB)->SeqNumberBits )) >> ((LFCB)->SeqNumberBits - 3) ) #define LfsLsnToSeqNumber(LFCB,LSN) \ /*xxShr*/Int64ShrlMod32( ((ULONGLONG)(LSN).QuadPart), (LFCB)->FileDataBits ) #define LfsLsnToPageOffset(LFCB,LSN) \ LfsLogPageOffset( LFCB, (LSN).LowPart << 3 ) VOID LfsLsnFinalOffset ( IN PLFCB Lfcb, IN LSN Lsn, IN ULONG DataLength, OUT PLONGLONG FinalOffset ); BOOLEAN LfsFindNextLsn ( IN PLFCB Lfcb, IN PLFS_RECORD_HEADER RecordHeader, OUT PLSN Lsn ); // // The following routines support the Lfs restart areas. They are contained // in 'RstrtSup.c' // VOID LfsWriteLfsRestart ( IN PLFCB Lfcb, IN ULONG ThisRestartSize, IN BOOLEAN WaitForIo ); VOID LfsFindOldestClientLsn ( IN PLFS_RESTART_AREA RestartArea, IN PLFS_CLIENT_RECORD ClientArray, OUT PLSN OldestLsn ); // // The following routines are used for managing the structures allocated // by us. They are contained in 'StrucSup.c' // PLFCB LfsAllocateLfcb ( IN ULONG LogPageSize, IN LONGLONG FileSize ); VOID LfsDeallocateLfcb ( IN PLFCB Lfcb, IN BOOLEAN CompleteTeardown ); VOID LfsAllocateLbcb ( IN PLFCB Lfcb, OUT PLBCB *Lbcb ); VOID LfsDeallocateLbcb ( IN PLFCB Lfcb, IN PLBCB Lbcb ); VOID LfsAllocateLeb ( IN PLFCB Lfcb, OUT PLEB *NewLeb ); VOID LfsDeallocateLeb ( IN PLFCB Lfcb, IN PLEB Leb ); VOID LfsReadPage ( IN PLFCB Lfcb, IN PLARGE_INTEGER Offset, OUT PMDL *Mdl, OUT PVOID *Buffer ); // // VOID // LfsInitializeLeb ( // IN PLEB Leb, // IN LFS_CLIENT_ID ClientId, // IN LFS_CONTEXT_MODE ContextMode // ); // // // VOID // LfsAllocateLch ( // OUT PLCH *Lch // ); // // VOID // LfsDeallocateLch ( // IN PLCH Lch // ); // // VOID // LfsAllocateRestartArea ( // OUT PLFS_RESTART_AREA *RestartArea, // ULONG Size // ); // // VOID // LfsDeallocateRestartArea ( // IN PLFS_RESTART_AREA RestartArea // ); // // BOOLEAN // LfsLbcbIsRestart ( // IN PLBCB Lbcb // ); // #define LfsInitializeLeb(LEB,ID,MODE) \ (LEB)->ClientId = ID; \ (LEB)->ContextMode = MODE #define LfsAllocateLch(NEW) { \ *(NEW) = FsRtlAllocatePool( PagedPool, sizeof( LCH )); \ RtlZeroMemory( (*NEW), sizeof( LCH )); \ (*(NEW))->NodeTypeCode = LFS_NTC_LCH; \ (*(NEW))->NodeByteSize = sizeof( LCH ); \ } #define LfsDeallocateLch(LCH) \ ExFreePool( LCH ) #define LfsAllocateRestartArea(RS,SIZE) \ *(RS) = FsRtlAllocatePool( PagedPool, (SIZE) ); \ RtlZeroMemory( *(RS), (SIZE) ) #define LfsDeallocateRestartArea(RS) \ ExFreePool( RS ) #define LfsLbcbIsRestart(LBCB) \ (FlagOn( (LBCB)->LbcbFlags, LBCB_RESTART_LBCB )) // // The following routines provide synchronization support for the Lfs // shared structures. They are contained in 'SyncSup.c' // // // VOID // LfsAcquireLfsData ( // ); // // VOID // LfsReleaseLfsData ( // ); // // VOID // LfsAcquireLfcb ( // IN PLFCB Lfcb // ); // // VOID // LfsReleaseLfcb ( // IN PLFCB Lfcb // ); // // VOID // LfsAcquireLchExclusive ( // IN PLCH Lch // ); // // VOID // LfsAcquireLchShared ( // IN PLCH Lch // ); // // VOID // LfsReleaseLfcb ( // IN PLCH Lch // ); // #define LfsAcquireLfsData() \ ExAcquireFastMutex( &LfsData.LfsDataLock ) #define LfsReleaseLfsData() \ ExReleaseFastMutex( &LfsData.LfsDataLock ) #define LfsAcquireBufferLock() \ ExAcquireFastMutex( &LfsData.BufferLock ) #define LfsReleaseBufferLock() \ ExReleaseFastMutex( &LfsData.BufferLock ) #define LfsWaitForBufferNotification() \ KeWaitForSingleObject( &LfsData.BufferNotification, \ Executive, \ KernelMode, \ FALSE, \ NULL ) #define LfsNotifyBufferWaiters() \ KeSetEvent( &LfsData.BufferNotification, 0, FALSE ) #define LfsBlockBufferWaiters() \ KeClearEvent( &LfsData.BufferNotification ) INLINE VOID LfsAcquireLfcbExclusive ( IN PLFCB Lfcb ) { ExAcquireResourceExclusiveLite( &Lfcb->Sync->Resource, TRUE ); } INLINE VOID LfsAcquireLfcbShared ( IN PLFCB Lfcb ) { ExAcquireResourceSharedLite( &Lfcb->Sync->Resource, TRUE ); } INLINE VOID LfsReleaseLfcb ( IN PLFCB Lfcb ) { // // If the resource is owned either shared or exlcusive release it // if (ExIsResourceAcquiredSharedLite( &Lfcb->Sync->Resource )) { ExReleaseResourceLite( &Lfcb->Sync->Resource ); } } INLINE VOID LfsAcquireLchExclusive ( IN PLCH Lch ) { ExAcquireResourceExclusiveLite( &(Lch->Sync->Resource), TRUE ); } INLINE VOID LfsAcquireLchShared ( IN PLCH Lch ) { ExAcquireResourceSharedLite( &(Lch->Sync->Resource), TRUE ); } INLINE VOID LfsReleaseLch ( IN PLCH Lch ) { if (ExIsResourceAcquiredSharedLite( &Lch->Sync->Resource )) { ExReleaseResourceLite( &Lch->Sync->Resource ); } } // // The following routines are used to check various structures for validity // and comparability. They are contained in 'VerfySup.c'. // VOID LfsCurrentAvailSpace ( IN PLFCB Lfcb, OUT PLONGLONG CurrentAvailSpace, OUT PULONG CurrentPageBytes ); BOOLEAN LfsVerifyLogSpaceAvail ( IN PLFCB Lfcb, IN PLCH Lch, IN ULONG RemainingLogBytes, IN LONG UndoRequirement, IN BOOLEAN ForceToDisk ); VOID LfsFindCurrentAvail ( IN PLFCB Lfcb ); BOOLEAN LfsCheckSubsequentLogPage ( IN PLFCB Lfcb, IN PLFS_RECORD_PAGE_HEADER RecordPageHeader, IN LONGLONG LogFileOffset, IN LONGLONG SequenceNumber ); // // VOID // LfsValidateLch ( // IN PLCH Lch // ); // // VOID // LfsValidateClientId ( // IN PLFCB Lfcb, // IN PLCH Lch // ); // // BOOLEAN // LfsVerifyClientLsnInRange ( // IN PLFCB Lfcb, // IN PLFS_CLIENT_RECORD ClientRecord, // IN LSN Lsn // ); // // BOOLEAN // LfsClientIdMatch ( // IN PLFS_CLIENT_ID ClientA, // IN PLFS_CLIENT_ID ClientB // ) // // VOID // LfsValidateLeb ( // IN PLFS_CONTEXT_BLOCK Leb, // IN PLCH Lch // ) // #define LfsValidateLch(LCH) \ if ((LCH) == NULL \ || (LCH)->NodeTypeCode != LFS_NTC_LCH \ || ((LCH)->Lfcb != NULL \ && (LCH)->Lfcb->NodeTypeCode != LFS_NTC_LFCB)) { \ \ ExRaiseStatus( STATUS_ACCESS_DENIED ); \ } #define LfsValidateClientId(LFCB,LCH) \ if ((LCH)->ClientId.ClientIndex >= (LFCB)->RestartArea->LogClients \ || (LCH)->ClientId.SeqNumber \ != Add2Ptr( Lfcb->ClientArray, \ (LCH)->ClientArrayByteOffset, \ PLFS_CLIENT_RECORD )->SeqNumber) { \ ExRaiseStatus( STATUS_ACCESS_DENIED ); \ } #define LfsVerifyClientLsnInRange(LFCB,CLIENT,LSN) \ (/*xxGeq*/( (LSN).QuadPart >= ((CLIENT)->OldestLsn).QuadPart ) \ && /*xxLeq*/( (LSN).QuadPart <= ((LFCB)->RestartArea->CurrentLsn).QuadPart ) \ && /*xxNeqZero*/( (LSN).QuadPart != 0 )) #define LfsClientIdMatch(CLIENT_A,CLIENT_B) \ ((BOOLEAN) ((CLIENT_A)->SeqNumber == (CLIENT_B)->SeqNumber \ && (CLIENT_A)->ClientIndex == (CLIENT_B)->ClientIndex)) #define LfsValidateLeb(LEB,LCH) \ if (LEB == NULL \ || (LEB)->NodeTypeCode != LFS_NTC_LEB \ || !LfsClientIdMatch( &(LEB)->ClientId, &(LCH)->ClientId )) { \ ExRaiseStatus( STATUS_ACCESS_DENIED ); \ } // // Miscellaneous support routines // // // ULONG // FlagOn ( // IN ULONG Flags, // IN ULONG SingleFlag // ); // // BOOLEAN // BooleanFlagOn ( // IN ULONG Flags, // IN ULONG SingleFlag // ); // // VOID // SetFlag ( // IN ULONG Flags, // IN ULONG SingleFlag // ); // // VOID // ClearFlag ( // IN ULONG Flags, // IN ULONG SingleFlag // ); // //#ifndef BooleanFlagOn //#define BooleanFlagOn(F,SF) ( \ // (BOOLEAN)(((F) & (SF)) != 0) \ //) //#endif //#ifndef SetFlag //#define SetFlag(Flags,SingleFlag) { \ // (Flags) |= (SingleFlag); \ //} //#endif //#ifndef ClearFlag //#define ClearFlag(Flags,SingleFlag) { \ // (Flags) &= ~(SingleFlag); \ //} //#endif // // This macro takes a pointer (or ulong) and returns its rounded up word // value // #define WordAlign(Ptr) ( \ ((((ULONG)(Ptr)) + 1) & 0xfffffffe) \ ) // // This macro takes a pointer (or ulong) and returns its rounded up longword // value // #define LongAlign(Ptr) ( \ ((((ULONG)(Ptr)) + 3) & 0xfffffffc) \ ) // // This macro takes a pointer (or ulong) and returns its rounded up quadword // value // #define QuadAlign(Ptr) ( \ ((((ULONG)(Ptr)) + 7) & 0xfffffff8) \ ) // // This macro will up a 64 bit value to the next quad align boundary. // #define LiQuadAlign(LI,OUT) { \ *(OUT) = /*xxAdd*/( (LI) + 7 ); \ *((PULONG)(OUT)) &= 0xfffffff8; \ } // // CAST // Add2Ptr ( // IN PVOID Pointer, // IN ULONG Increment // IN (CAST) // ); // // ULONG // PtrOffset ( // IN PVOID BasePtr, // IN PVOID OffsetPtr // ); // #define Add2Ptr(PTR,INC,CAST) ((CAST)((PUCHAR)(PTR) + (INC))) #define PtrOffset(BASE,OFFSET) ((ULONG)((ULONG_PTR)(OFFSET) - (ULONG_PTR)(BASE))) // // The following macros are used to establish the semantics needed // to do a return from within a try-finally clause. As a rule every // try clause must end with a label call try_exit. For example, // // try { // : // : // // try_exit: NOTHING; // } finally { // // : // : // } // // Every return statement executed inside of a try clause should use the // try_return macro. If the compiler fully supports the try-finally construct // then the macro should be // // #define try_return(S) { return(S); } // // If the compiler does not support the try-finally construct then the macro // should be // // #define try_return(S) { S; goto try_exit; } // #define try_return(S) { S; goto try_exit; } #endif // _LFSPROCS_