|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
RstrtSup.c
Abstract:
This module implements support for dealing with the Lfs restart area.
Author:
Brian Andrew [BrianAn] 20-June-1991
Revision History:
--*/
#include "lfsprocs.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_RESTART_SUP)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, LfsFindOldestClientLsn)
#pragma alloc_text(PAGE, LfsWriteLfsRestart)
#endif
VOID LfsWriteLfsRestart ( IN PLFCB Lfcb, IN ULONG ThisRestartSize, IN BOOLEAN WaitForIo )
/*++
Routine Description:
This routine puts the Lfs restart area on the queue of operations to write to the file. We do this by allocating a second restart area and attaching it to the Lfcb. We also allocate a buffer control block to use for this write. We look at the WaitForIo boolean to determine whether this thread can perform the I/O. This also indicates whether this thread gives up the Lfcb.
Arguments:
Lfcb - A pointer to the log file control block for this operation.
ThisRestartSize - This is the size to use for the restart area.
WaitForIo - Indicates if this thread is to perform the work.
Return Value:
None.
--*/
{ PLBCB NewLbcb = NULL; PLFS_RESTART_AREA NewRestart = NULL;
PAGED_CODE();
DebugTrace( +1, Dbg, "LfsWriteLfsRestart: Entered\n", 0 ); DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); DebugTrace( 0, Dbg, "Write Chkdsk -> %04x\n", WriteChkdsk ); DebugTrace( 0, Dbg, "Restart Size -> %08lx\n", ThisRestartSize ); DebugTrace( 0, Dbg, "WaitForIo -> %08lx\n", WaitForIo );
//
// We'd absolutely hate for this to happen on a read only volume.
//
ASSERT(!(FlagOn( Lfcb->Flags, LFCB_READ_ONLY )));
//
// Use a try-finally to facilitate cleanup.
//
try {
PLBCB ActiveLbcb;
//
// We allocate another restart area and
// copy the current area into it. Attach the new area to the Lfcb.
//
LfsAllocateRestartArea( &NewRestart, ThisRestartSize );
//
// We allocate a Lbcb structure and update the values to
// reflect this restart area.
//
LfsAllocateLbcb( Lfcb, &NewLbcb ); SetFlag( NewLbcb->LbcbFlags, LBCB_RESTART_LBCB );
//
// If this is the second page, then add a page to the offset.
//
if (!Lfcb->InitialRestartArea) {
NewLbcb->FileOffset = Lfcb->LogPageSize + NewLbcb->FileOffset; }
(ULONG)NewLbcb->Length = ThisRestartSize;
NewLbcb->PageHeader = (PVOID) Lfcb->RestartArea;
//
// Set the lsn to a pseudo one right beyond the current lsn (the current may advance before flushing)
//
ASSERT( (sizeof( LFS_RECORD_HEADER ) >> 3) > Lfcb->LfsRestartBias );
NewLbcb->LastEndLsn.QuadPart = NewLbcb->LastLsn.QuadPart = Lfcb->RestartArea->CurrentLsn.QuadPart + Lfcb->LfsRestartBias; Lfcb->LfsRestartBias += 1; ASSERT( Lfcb->LfsRestartBias < 7 );
//
// Copy the existing restart area into the new area.
//
RtlCopyMemory( NewRestart, Lfcb->RestartArea, ThisRestartSize ); Lfcb->RestartArea = NewRestart;
Lfcb->ClientArray = Add2Ptr( NewRestart, Lfcb->ClientArrayOffset, PLFS_CLIENT_RECORD );
NewRestart = NULL;
//
// Update the Lfcb to indicate that the other restart area
// on the disk is to be used.
//
Lfcb->InitialRestartArea = !Lfcb->InitialRestartArea;
//
// Add this Lbcb to the end of the workque and flush to that point.
//
InsertTailList( &Lfcb->LbcbWorkque, &NewLbcb->WorkqueLinks );
//
// If we don't support a packed log file then we need to make
// sure that all file records written out ahead of this
// restart area make it out to disk and we don't add anything
// to this page.
//
if (!FlagOn( Lfcb->Flags, LFCB_PACK_LOG ) && !IsListEmpty( &Lfcb->LbcbActive )) {
ActiveLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink, LBCB, ActiveLinks );
if (FlagOn( ActiveLbcb->LbcbFlags, LBCB_NOT_EMPTY )) {
RemoveEntryList( &ActiveLbcb->ActiveLinks ); ClearFlag( ActiveLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE ); } }
if (WaitForIo) {
LfsFlushToLsnPriv( Lfcb, NewLbcb->LastEndLsn, TRUE ); } else {
}
} finally {
DebugUnwind( LfsWriteLfsRestart );
if (NewRestart != NULL) {
ExFreePool( NewRestart ); }
DebugTrace( -1, Dbg, "LfsWriteLfsRestart: Exit\n", 0 ); }
return; }
VOID LfsFindOldestClientLsn ( IN PLFS_RESTART_AREA RestartArea, IN PLFS_CLIENT_RECORD ClientArray, OUT PLSN OldestLsn )
/*++
Routine Description:
This routine walks through the active clients to determine the oldest Lsn the system must maintain.
Arguments:
RestartArea - This is the Restart Area to examine.
ClientArray - This is the start of the client data array.
OldestLsn - We store the oldest Lsn we find in this value. It is initialized with a starting value, we won't return a more recent Lsn.
Return Value:
None.
--*/
{ USHORT NextClient;
PLFS_CLIENT_RECORD ClientBlock;
PAGED_CODE();
DebugTrace( +1, Dbg, "LfsFindOldestClientLsn: Entered\n", 0 ); DebugTrace( 0, Dbg, "RestartArea -> %08lx\n", RestartArea ); DebugTrace( 0, Dbg, "Base Lsn (Low) -> %08lx\n", BaseLsn.LowPart ); DebugTrace( 0, Dbg, "Base Lsn (High) -> %08lx\n", BaseLsn.HighPart );
//
// Take the first client off the in use list.
//
NextClient = RestartArea->ClientInUseList;
//
// While there are more clients, compare their oldest Lsn with the
// current oldest.
//
while (NextClient != LFS_NO_CLIENT) {
ClientBlock = ClientArray + NextClient;
//
// We ignore this block if it's oldest Lsn is 0.
//
if (( ClientBlock->OldestLsn.QuadPart != 0 ) && ( ClientBlock->OldestLsn.QuadPart < OldestLsn->QuadPart )) {
*OldestLsn = ClientBlock->OldestLsn; }
//
// Try the next client block.
//
NextClient = ClientBlock->NextClient; }
DebugTrace( 0, Dbg, "OldestLsn (Low) -> %08lx\n", BaseLsn.LowPart ); DebugTrace( 0, Dbg, "OldestLsn (High) -> %08lx\n", BaseLsn.HighPart ); DebugTrace( -1, Dbg, "LfsFindOldestClientLsn: Exit\n", 0 );
return; }
|