/*++ 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 #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') // // 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, // OUT PVOID *Buffer, // OUT PBCB *Bcb // ); // #define LfsPreparePinWriteData(L,FO,LEN,BUF,B) { \ LONGLONG _LocalFileOffset = (FO); \ CcPreparePinWrite( (L)->FileObject, \ (PLARGE_INTEGER)&_LocalFileOffset, \ (LEN), \ FALSE, \ TRUE, \ (B), \ (BUF) ); \ } 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 PLBCB Lbcb ); 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 ); 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)->SystemPageInverseMask #define LfsLogPageOffset(LFCB,INT) \ (INT & (LFCB)->LogPageMask) VOID LfsNextLogPageOffset ( IN PLFCB Lfcb, IN LONGLONG CurrentLogPageOffset, OUT PLONGLONG NextLogPageOffset, OUT PBOOLEAN Wrapped ); // // 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 ( ); 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 // LfsAllocateLcb ( // OUT PLCB *NewLcb // ); // // VOID // LfsInitializeLcb ( // IN PLCB Lcb, // IN LFS_CLIENT_ID ClientId, // IN LFS_CONTEXT_MODE ContextMode // ); // // VOID // LfsDeallocateLcb ( // IN PLCB Lcb // ); // // 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 LfsAllocateLcb(NEW) { \ (*NEW) = FsRtlAllocatePool( PagedPool, sizeof( LCB )); \ RtlZeroMemory( (*NEW), sizeof( LCB )); \ (*NEW)->NodeTypeCode = LFS_NTC_LCB; \ (*NEW)->NodeByteSize = sizeof( LCB ); \ } #define LfsInitializeLcb(LCB,ID,MODE) \ (LCB)->ClientId = ID; \ (LCB)->ContextMode = MODE #define LfsDeallocateLcb(LCB) { \ if ((LCB)->RecordHeaderBcb != NULL) { \ CcUnpinData( (LCB)->RecordHeaderBcb ); \ } \ if ((LCB)->CurrentLogRecord != NULL \ && (LCB)->AuxilaryBuffer == TRUE) { \ ExFreePool( (LCB)->CurrentLogRecord ); \ } \ ExFreePool( LCB ); \ } #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 // LfsAcquireLch ( // IN PLCH Lch // ); // // VOID // LfsReleaseLfcb ( // IN PLCH Lch // ); // #define LfsAcquireLfsData() \ KeWaitForSingleObject( &LfsData.Event, \ Executive, \ KernelMode, \ FALSE, \ NULL ) #define LfsReleaseLfsData() \ KeSetEvent( &LfsData.Event, 0 , FALSE ) #define LfsAcquireLfcb(LFCB) \ ExAcquireResourceExclusive( &(LFCB)->Sync->Resource, TRUE ) #define LfsReleaseLfcb(LFCB) \ if ((LFCB)->Sync->Resource.OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread()) {\ ExReleaseResource( &(LFCB)->Sync->Resource ); \ } #define LfsAcquireLch(LCH) \ ExAcquireResourceExclusive( &(LCH)->Sync->Resource, TRUE ) #define LfsReleaseLch(LCH) \ if ((LCH)->Sync->Resource.OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread()) { \ ExReleaseResource( &(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 ); // // 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 // LfsValidateLcb ( // IN PLFS_CONTEXT_BLOCK Lcb, // 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 LfsValidateLcb(LCB,LCH) \ if (LCB == NULL \ || (LCB)->NodeTypeCode != LFS_NTC_LCB \ || !LfsClientIdMatch( &(LCB)->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 // ); // // // This macro returns TRUE if a flag in a set of flags is on and FALSE // otherwise // #define FlagOn(F,SF) ( \ (((F) & (SF))) \ ) #define BooleanFlagOn(F,SF) ( \ (BOOLEAN)(((F) & (SF)) != 0) \ ) #define SetFlag(Flags,SingleFlag) { \ (Flags) |= (SingleFlag); \ } #define ClearFlag(Flags,SingleFlag) { \ (Flags) &= ~(SingleFlag); \ } // // 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)(OFFSET) - (ULONG)(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_