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(); LfsDebugTrace( +1, Dbg, "LfsWriteLfsRestart: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); LfsDebugTrace( 0, Dbg, "Write Chkdsk -> %04x\n", WriteChkdsk ); LfsDebugTrace( 0, Dbg, "Restart Size -> %08lx\n", ThisRestartSize ); LfsDebugTrace( 0, Dbg, "WaitForIo -> %08lx\n", WaitForIo ); // // 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 system page to the offset. // if (!Lfcb->InitialRestartArea) { NewLbcb->FileOffset = Lfcb->SystemPageSize + NewLbcb->FileOffset; } (ULONG)NewLbcb->Length = ThisRestartSize; NewLbcb->PageHeader = (PVOID) Lfcb->RestartArea; // // Lets put the current lsn in the Lbcb. // NewLbcb->LastEndLsn = NewLbcb->LastLsn = Lfcb->NextRestartLsn; Lfcb->NextRestartLsn.QuadPart = 1 + Lfcb->NextRestartLsn.QuadPart; // // Copy the existing restart area into the new area. // RtlCopyMemory( NewRestart, Lfcb->RestartArea, ThisRestartSize ); Lfcb->RestartArea = NewRestart; Lfcb->ClientArray = LfsAdd2Ptr( 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) { LfsFlushLbcb( Lfcb, NewLbcb ); } } __finally { DebugUnwind( LfsWriteLfsRestart ); if (NewRestart != NULL) { ExFreePool( NewRestart ); } LfsDebugTrace( -1, Dbg, "LfsWriteLfsRestart: Exit\n", 0 ); } return; }
PLBCB LfsGetLbcb ( IN PLFCB Lfcb ) /*++ Routine Description: This routine is called to add a Lbcb to the active queue. Arguments: Lfcb - This is the file control block for the log file. Return Value: PLBCB - Pointer to the Lbcb allocated. --*/ { PLBCB Lbcb = NULL; PVOID PageHeader; PBCB PageHeaderBcb = NULL; BOOLEAN WrappedOrUsaError; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsGetLbcb: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); // // Use a try-finally to facilitate cleanup. // try { // // Pin the desired record page. // LfsPreparePinWriteData( Lfcb, Lfcb->NextLogPage, (ULONG)Lfcb->LogPageSize, &PageHeader, &PageHeaderBcb ); // // Put our signature into the page so we won't fail if we // see a previous 'BAAD' signature. // *((PULONG) PageHeader) = LFS_SIGNATURE_RECORD_PAGE_ULONG; // // Now allocate an Lbcb. // LfsAllocateLbcb( Lfcb, &Lbcb ); // // If we are at the beginning of the file we test that the // sequence number won't wrap to 0. // if (!FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_REUSE_TAIL ) && ( Lfcb->NextLogPage == Lfcb->FirstLogPage )) { Lfcb->SeqNumber = Lfcb->SeqNumber + 1; // // If the sequence number is going from 0 to 1, then // this is the first time the log file has wrapped. We want // to remember this because it means that we can now do // large spiral writes. // if (Int64ShllMod32( Lfcb->SeqNumber, Lfcb->FileDataBits ) == 0) { LfsDebugTrace( 0, Dbg, "Log sequence number about to wrap: Lfcb -> %08lx\n", Lfcb ); KeBugCheck( FILE_SYSTEM ); } // // If this number is greater or equal to the wrap sequence number in // the Lfcb, set the wrap flag in the Lbcb. // if (!FlagOn( Lfcb->Flags, LFCB_LOG_WRAPPED ) && ( Lfcb->SeqNumber >= Lfcb->SeqNumberForWrap )) { SetFlag( Lbcb->LbcbFlags, LBCB_LOG_WRAPPED ); SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED ); } } // // Now initialize the rest of the Lbcb fields. // Lbcb->FileOffset = Lfcb->NextLogPage; Lbcb->SeqNumber = Lfcb->SeqNumber; Lbcb->BufferOffset = Lfcb->LogPageDataOffset; // // Store the next page in the Lfcb. // LfsNextLogPageOffset( Lfcb, Lfcb->NextLogPage, &Lfcb->NextLogPage, &WrappedOrUsaError ); Lbcb->Length = Lfcb->LogPageSize; Lbcb->PageHeader = PageHeader; Lbcb->LogPageBcb = PageHeaderBcb; Lbcb->ResourceThread = ExGetCurrentResourceThread(); // // If we are reusing a previous page then set a flag in // the Lbcb to indicate that we should flush a copy // first. // if (FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL )) { SetFlag( Lbcb->LbcbFlags, LBCB_FLUSH_COPY ); ClearFlag( Lfcb->Flags, LFCB_REUSE_TAIL ); (ULONG)Lbcb->BufferOffset = Lfcb->ReusePageOffset; Lbcb->Flags = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Flags; Lbcb->LastLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Copy.LastLsn; Lbcb->LastEndLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Header.Packed.LastEndLsn; } // // Put the Lbcb on the active queue // InsertTailList( &Lfcb->LbcbActive, &Lbcb->ActiveLinks ); SetFlag( Lbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE ); } finally { DebugUnwind( LfsGetLbcb ); // // If an error occurred, we need to clean up any blocks which // have not been added to the active queue. // if (AbnormalTermination()) { if (Lbcb != NULL) { LfsDeallocateLbcb( Lfcb, Lbcb ); Lbcb = NULL; } // // Unpin the system page if pinned. // if (PageHeaderBcb != NULL) { CcUnpinData( PageHeaderBcb ); } } LfsDebugTrace( -1, Dbg, "LfsGetLbcb: Exit\n", 0 ); } return Lbcb; }