375 lines
9.1 KiB
C
375 lines
9.1 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
LogPgSup.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements support for manipulating log pages.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Brian Andrew [BrianAn] 20-June-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "lfsprocs.h"
|
|||
|
|
|||
|
//
|
|||
|
// The debug trace level
|
|||
|
//
|
|||
|
|
|||
|
#define Dbg (DEBUG_TRACE_LOG_PAGE_SUP)
|
|||
|
|
|||
|
#undef MODULE_POOL_TAG
|
|||
|
#define MODULE_POOL_TAG ('PsfL')
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, LfsAllocateSpanningBuffer)
|
|||
|
#pragma alloc_text(PAGE, LfsFreeSpanningBuffer)
|
|||
|
#pragma alloc_text(PAGE, LfsNextLogPageOffset)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
LfsNextLogPageOffset (
|
|||
|
IN PLFCB Lfcb,
|
|||
|
IN LONGLONG CurrentLogPageOffset,
|
|||
|
OUT PLONGLONG NextLogPageOffset,
|
|||
|
OUT PBOOLEAN Wrapped
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will compute the offset in the log file of the next log
|
|||
|
page.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Lfcb - This is the file control block for the log file.
|
|||
|
|
|||
|
CurrentLogPageOffset - This is the file offset of the current log page.
|
|||
|
|
|||
|
NextLogPageOffset - Address to store the next log page to use.
|
|||
|
|
|||
|
Wrapped - This is a pointer to a boolean variable that, if present,
|
|||
|
we use to indicate whether we wrapped in the log file.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DebugTrace( +1, Dbg, "LfsNextLogPageOffset: Entered\n", 0 );
|
|||
|
DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
|
|||
|
DebugTrace( 0, Dbg, "CurrentLogPageOffset (Low) -> %08lx\n", CurrentLogPageOffset.LowPart );
|
|||
|
DebugTrace( 0, Dbg, "CurrentLogPageOffset (High) -> %08lx\n", CurrentLogPageOffset.HighPart );
|
|||
|
DebugTrace( 0, Dbg, "Wrapped -> %08lx\n", Wrapped );
|
|||
|
|
|||
|
//
|
|||
|
// We add the log page size to the current log offset.
|
|||
|
//
|
|||
|
|
|||
|
LfsTruncateOffsetToLogPage( Lfcb, CurrentLogPageOffset, &CurrentLogPageOffset );
|
|||
|
*NextLogPageOffset = CurrentLogPageOffset + Lfcb->LogPageSize; //**** xxAdd( CurrentLogPageOffset, Lfcb->LogPageSize );
|
|||
|
|
|||
|
//
|
|||
|
// If the result is larger than the file, we use the first page offset
|
|||
|
// in the file.
|
|||
|
//
|
|||
|
|
|||
|
if ( *NextLogPageOffset >= Lfcb->FileSize ) { //**** xxGeq( *NextLogPageOffset, Lfcb->FileSize )
|
|||
|
|
|||
|
*NextLogPageOffset = Lfcb->FirstLogPage;
|
|||
|
|
|||
|
*Wrapped = TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
*Wrapped = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace( 0, Dbg, "NextLogPageOffset (Low) -> %08lx\n", NextLogPageOffset->LowPart );
|
|||
|
DebugTrace( 0, Dbg, "NextLogPageOffset (High) -> %08lx\n", NextLogPageOffset->HighPart );
|
|||
|
DebugTrace( 0, Dbg, "Wrapped -> %08x\n", *Wrapped );
|
|||
|
DebugTrace( -1, Dbg, "LfsNextLogPageOffset: Exit\n", 0 );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PVOID
|
|||
|
LfsAllocateSpanningBuffer (
|
|||
|
IN PLFCB Lfcb,
|
|||
|
IN ULONG Length
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called to allocate a spare buffer to read a file record
|
|||
|
which spans a log page. We will first try to allocate one. If that
|
|||
|
fails we will use one of the existing spare buffers. If that fails then
|
|||
|
we will raise.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Lfcb - This is the file control block for the log file.
|
|||
|
|
|||
|
Length - Length of the buffer required.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
PVOID - Pointer to the buffer to use for reading the log record.
|
|||
|
May be either from pool or from the auxilary buffer pool.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PVOID NewBuffer = NULL;
|
|||
|
ERESOURCE_THREAD Thread;
|
|||
|
BOOLEAN Wait = FALSE;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DebugTrace( +1, Dbg, "LfsAllocateSpanningBuffer: Entered\n", 0 );
|
|||
|
|
|||
|
//
|
|||
|
// Loop while we don't have a buffer. First try to get our reserved buffer
|
|||
|
// without waiting. Then try to allocate a buffer. Finally wait for the reserved
|
|||
|
// buffer as the final alternative.
|
|||
|
//
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
//
|
|||
|
// Skip the reserved buffer if the request is larger than we can read into it.
|
|||
|
//
|
|||
|
|
|||
|
if (Length <= LFS_BUFFER_SIZE) {
|
|||
|
|
|||
|
//
|
|||
|
// If this thread already owns one buffer it can get the second directly.
|
|||
|
//
|
|||
|
|
|||
|
Thread = ExGetCurrentResourceThread();
|
|||
|
|
|||
|
if (Thread == LfsData.BufferOwner) {
|
|||
|
|
|||
|
if (!FlagOn( LfsData.BufferFlags, LFS_BUFFER1_OWNED )) {
|
|||
|
|
|||
|
SetFlag( LfsData.BufferFlags, LFS_BUFFER1_OWNED );
|
|||
|
NewBuffer = LfsData.Buffer1;
|
|||
|
break;
|
|||
|
|
|||
|
} else if (!FlagOn( LfsData.BufferFlags, LFS_BUFFER2_OWNED )) {
|
|||
|
|
|||
|
SetFlag( LfsData.BufferFlags, LFS_BUFFER2_OWNED );
|
|||
|
NewBuffer = LfsData.Buffer2;
|
|||
|
break;
|
|||
|
|
|||
|
} else if (Wait) {
|
|||
|
|
|||
|
//
|
|||
|
// This shouldn't happen but handle anyway.
|
|||
|
//
|
|||
|
|
|||
|
DebugTrace( -1, Dbg, "LfsAllocateSpanningBuffer: Exit\n", 0 );
|
|||
|
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Otherwise acquire the buffer lock and check the state of the buffers.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
BOOLEAN LfcbOwned = TRUE;
|
|||
|
|
|||
|
while (TRUE) {
|
|||
|
|
|||
|
LfsAcquireBufferLock();
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if the buffers are available. No
|
|||
|
// need to drop the Lfcb in the typical case.
|
|||
|
//
|
|||
|
|
|||
|
if (LfsData.BufferOwner == (ERESOURCE_THREAD) NULL) {
|
|||
|
|
|||
|
ASSERT( !FlagOn( LfsData.BufferFlags, LFS_BUFFER1_OWNED | LFS_BUFFER2_OWNED ));
|
|||
|
NewBuffer = LfsData.Buffer1;
|
|||
|
LfsData.BufferOwner = Thread;
|
|||
|
SetFlag( LfsData.BufferFlags, LFS_BUFFER1_OWNED );
|
|||
|
LfsBlockBufferWaiters();
|
|||
|
|
|||
|
//
|
|||
|
// Reacquire the Lfcb if needed.
|
|||
|
//
|
|||
|
|
|||
|
if (!LfcbOwned) {
|
|||
|
|
|||
|
LfsAcquireLfcb( Lfcb );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Break out.
|
|||
|
//
|
|||
|
|
|||
|
LfsReleaseBufferLock();
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Release the Lfcb and wait on the notification for the buffers.
|
|||
|
//
|
|||
|
|
|||
|
if (Wait) {
|
|||
|
|
|||
|
if (LfcbOwned) {
|
|||
|
LfsReleaseLfcb( Lfcb );
|
|||
|
LfcbOwned = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
LfsReleaseBufferLock();
|
|||
|
LfsWaitForBufferNotification();
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Go ahead and try to allocate a buffer from pool next.
|
|||
|
//
|
|||
|
|
|||
|
LfsReleaseBufferLock();
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Raise if we already tried the allocate path.
|
|||
|
//
|
|||
|
|
|||
|
} else if (Wait) {
|
|||
|
|
|||
|
DebugTrace( -1, Dbg, "LfsAllocateSpanningBuffer: Exit\n", 0 );
|
|||
|
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Try pool if we didn't get a buffer above.
|
|||
|
//
|
|||
|
|
|||
|
if (NewBuffer == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Try pool next but don't let this fail on pool allocation.
|
|||
|
//
|
|||
|
|
|||
|
NewBuffer = LfsAllocatePoolNoRaise( PagedPool, Length );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Wait on the next pass through the loop.
|
|||
|
//
|
|||
|
|
|||
|
Wait = TRUE;
|
|||
|
|
|||
|
} while (NewBuffer == NULL);
|
|||
|
|
|||
|
DebugTrace( -1, Dbg, "LfsAllocateSpanningBuffer: Exit\n", 0 );
|
|||
|
return NewBuffer;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
LfsFreeSpanningBuffer (
|
|||
|
IN PVOID Buffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called to free a buffer used to read a log record
|
|||
|
which spans pages. We will check if it is one of our special buffers
|
|||
|
and deal with synchronization in that case.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Buffer - Buffer to free.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ERESOURCE_THREAD Thread;
|
|||
|
ULONG BufferFlag;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DebugTrace( +1, Dbg, "LfsFreeSpanningBuffer: Entered\n", 0 );
|
|||
|
|
|||
|
//
|
|||
|
// Check if either buffer1 or buffer2 are being freed.
|
|||
|
//
|
|||
|
|
|||
|
if (Buffer == LfsData.Buffer1) {
|
|||
|
|
|||
|
BufferFlag = LFS_BUFFER1_OWNED;
|
|||
|
goto ReservedBuffers;
|
|||
|
|
|||
|
} else if (Buffer == LfsData.Buffer2) {
|
|||
|
|
|||
|
BufferFlag = LFS_BUFFER2_OWNED;
|
|||
|
|
|||
|
ReservedBuffers:
|
|||
|
|
|||
|
//
|
|||
|
// Acquire the buffer lock and clear the correct flag.
|
|||
|
//
|
|||
|
|
|||
|
LfsAcquireBufferLock();
|
|||
|
ClearFlag( LfsData.BufferFlags, BufferFlag );
|
|||
|
|
|||
|
//
|
|||
|
// If no buffers owned then signal the waiters.
|
|||
|
//
|
|||
|
|
|||
|
if (!FlagOn( LfsData.BufferFlags, LFS_BUFFER1_OWNED | LFS_BUFFER2_OWNED )) {
|
|||
|
|
|||
|
LfsData.BufferOwner = (ERESOURCE_THREAD) NULL;
|
|||
|
LfsNotifyBufferWaiters();
|
|||
|
}
|
|||
|
|
|||
|
LfsReleaseBufferLock();
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Simply free the buffer.
|
|||
|
//
|
|||
|
|
|||
|
LfsFreePool( Buffer );
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace( -1, Dbg, "LfsFreeSpanningBuffer: Exit\n", 0 );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|