|
|
/*++ 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 <ntifs.h>
#include <string.h>
#include <lfs.h>
#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_
|