Windows2000/private/ntos/lfs/logpgsup.c
2020-09-30 17:12:32 +02:00

380 lines
8.7 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;
PAGED_CODE();
DebugTrace( +1, Dbg, "LfsFreeSpanningBuffer: Entered\n", 0 );
// Do an unsafe test of the buffer flags. If we own a buffer then they must be non-zero.
// Otherwise do the correct check of the resource thread.
if (!FlagOn( LfsData.BufferFlags, LFS_BUFFER1_OWNED | LFS_BUFFER2_OWNED ) ||
(LfsData.BufferOwner != ExGetCurrentResourceThread())) {
LfsFreePool( Buffer );
} else {
// Acquire the lock for synchronization.
LfsAcquireBufferLock();
// Check which buffer it is.
if (Buffer == LfsData.Buffer1) {
ClearFlag( LfsData.BufferFlags, LFS_BUFFER1_OWNED );
} else {
// It better be buffer2
ASSERT( FlagOn( LfsData.BufferFlags, LFS_BUFFER2_OWNED ));
ClearFlag( LfsData.BufferFlags, LFS_BUFFER2_OWNED );
}
// 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();
}
DebugTrace( -1, Dbg, "LfsFreeSpanningBuffer: Exit\n", 0 );
return;
}