Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

cachesup.c File Reference

#include "lfsprocs.h"

Go to the source code of this file.

Defines

#define Dbg   (DEBUG_TRACE_CACHE_SUP)

Functions

BOOLEAN LfsIsRestartPageHeaderValid (IN LONGLONG FileOffset, IN PLFS_RESTART_PAGE_HEADER PageHeader, OUT PBOOLEAN LogPacked)
BOOLEAN LfsIsRestartAreaValid (IN PLFS_RESTART_PAGE_HEADER PageHeader, IN BOOLEAN LogPacked)
BOOLEAN LfsIsClientAreaValid (IN PLFS_RESTART_PAGE_HEADER PageHeader, IN BOOLEAN LogPacked, IN BOOLEAN UsaError)
VOID LfsFindFirstIo (IN PLFCB Lfcb, IN PLBCB TargetLbcb, IN PLBCB FirstLbcb, OUT PLBCB *NextLbcb, OUT PLONGLONG FileOffset, OUT PBOOLEAN ContainsLastEntry, OUT PBOOLEAN LfsRestart, OUT PBOOLEAN UseTailCopy, OUT PULONG IoBlocks)
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 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 PLBCB Lbcb)
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)

Variables

USHORT LfsUsaSeqNumber


Define Documentation

#define Dbg   (DEBUG_TRACE_CACHE_SUP)
 

Definition at line 27 of file lfs/cachesup.c.


Function Documentation

VOID LfsCopyReadLogRecord IN PLFCB  Lfcb,
IN PLFS_RECORD_HEADER  RecordHeader,
OUT PVOID  Buffer
 

Definition at line 339 of file lfs/cachesup.c.

References Add2Ptr, Buffer, CcUnpinData(), Dbg, DebugTrace, ExRaiseStatus(), FALSE, FlagOn, LFCB_PACK_LOG, LfsLsnToPageOffset, LfsNextLogPageOffset(), LfsPinOrMapData(), LfsTruncateLsnToLogPage, LOG_PAGE_LOG_RECORD_END, NULL, PAGED_CODE, and TRUE.

Referenced by LfsFindLogRecord(), and LfsReadRestartArea().

00347 : 00348 00349 This routines copies a log record from the file to a buffer. The log 00350 record may span several log pages and may even wrap in the file. 00351 00352 Arguments: 00353 00354 Lfcb - A pointer to the control block for the log file. 00355 00356 RecordHeader - Pointer to the log record header for this log record. 00357 00358 Buffer - Pointer to the buffer to store the log record. 00359 00360 Return Value: 00361 00362 None. 00363 00364 --*/ 00365 00366 { 00367 PBCB Bcb = NULL; 00368 BOOLEAN UsaError; 00369 00370 PLFS_RECORD_PAGE_HEADER PageHeader; 00371 00372 LONGLONG LogPageFileOffset; 00373 ULONG LogPageOffset; 00374 00375 ULONG RemainingTransferBytes; 00376 00377 PAGED_CODE(); 00378 00379 DebugTrace( +1, Dbg, "LfsCopyReadLogRecord: Entered\n", 0 ); 00380 DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); 00381 DebugTrace( 0, Dbg, "RecordHeader -> %08lx\n", RecordHeader ); 00382 DebugTrace( 0, Dbg, "Buffer -> %08lx\n", Buffer ); 00383 00384 // 00385 // We find the file offset of the log page containing the start of 00386 // this log record, the offset within the page to start the transfer from, 00387 // the number of bytes to transfer on this page and the starting 00388 // position in the buffer to begin the transfer to. 00389 // 00390 00391 LfsTruncateLsnToLogPage( Lfcb, RecordHeader->ThisLsn, &LogPageFileOffset ); 00392 LogPageOffset = LfsLsnToPageOffset( Lfcb, RecordHeader->ThisLsn ) + Lfcb->RecordHeaderLength; 00393 00394 RemainingTransferBytes = RecordHeader->ClientDataLength; 00395 00396 // 00397 // Use a try-finally to facilitate cleanup. 00398 // 00399 00400 try { 00401 00402 // 00403 // While there are more bytes to transfer, we continue to attempt to 00404 // perform the read. 00405 // 00406 00407 while (TRUE) { 00408 00409 ULONG RemainingPageBytes; 00410 00411 BOOLEAN Wrapped; 00412 00413 RemainingPageBytes = (ULONG)Lfcb->LogPageSize - LogPageOffset; 00414 00415 // 00416 // We compute the number of bytes to read from this log page and 00417 // call the cache package to perform the transfer. 00418 // 00419 00420 if (RemainingTransferBytes <= RemainingPageBytes) { 00421 00422 RemainingPageBytes = RemainingTransferBytes; 00423 } 00424 00425 RemainingTransferBytes -= RemainingPageBytes; 00426 00427 // 00428 // Unpin any previous buffer. 00429 // 00430 00431 if (Bcb != NULL) { 00432 00433 CcUnpinData( Bcb ); 00434 Bcb = NULL; 00435 } 00436 00437 LfsPinOrMapData( Lfcb, 00438 LogPageFileOffset, 00439 (ULONG)Lfcb->LogPageSize, 00440 FALSE, 00441 FALSE, 00442 TRUE, 00443 &UsaError, 00444 (PVOID *) &PageHeader, 00445 &Bcb ); 00446 00447 // 00448 // The last Lsn on this page better be greater or equal to the Lsn we 00449 // are copying. 00450 // 00451 00452 if ( PageHeader->Copy.LastLsn.QuadPart < RecordHeader->ThisLsn.QuadPart ) { 00453 00454 ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); 00455 } 00456 00457 RtlCopyMemory( Buffer, 00458 Add2Ptr( PageHeader, LogPageOffset, PVOID ), 00459 RemainingPageBytes ); 00460 00461 // 00462 // If there are no more bytes to transfer, we exit the loop. 00463 // 00464 00465 if (RemainingTransferBytes == 0) { 00466 00467 // 00468 // Our log record better not span this page. 00469 // 00470 00471 if (!FlagOn( PageHeader->Flags, LOG_PAGE_LOG_RECORD_END ) 00472 00473 || (FlagOn( Lfcb->Flags, LFCB_PACK_LOG ) 00474 && ( RecordHeader->ThisLsn.QuadPart > PageHeader->Header.Packed.LastEndLsn.QuadPart ))) { 00475 00476 ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); 00477 } 00478 00479 break; 00480 } 00481 00482 // 00483 // If the page header indicates that the log record ended on this page, 00484 // this is a disk corrupt condition. For a packed page it means 00485 // that the last Lsn and the last Ending Lsn are the same. 00486 // 00487 00488 if (FlagOn( Lfcb->Flags, LFCB_PACK_LOG )) { 00489 00490 // 00491 // If there is no spanning log record this is an error. 00492 // 00493 00494 if (( PageHeader->Copy.LastLsn.QuadPart == PageHeader->Header.Packed.LastEndLsn.QuadPart ) 00495 00496 || ( RecordHeader->ThisLsn.QuadPart > PageHeader->Copy.LastLsn.QuadPart )) { 00497 00498 ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); 00499 } 00500 00501 // 00502 // For an unpacked page it simply means that the page 00503 // contains the end of a log record. 00504 // 00505 00506 } else if (FlagOn( PageHeader->Flags, LOG_PAGE_LOG_RECORD_END )) { 00507 00508 ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); 00509 } 00510 00511 // 00512 // We find the start of the next log page and the offset within 00513 // that page to start transferring bytes. 00514 // 00515 00516 LfsNextLogPageOffset( Lfcb, 00517 LogPageFileOffset, 00518 &LogPageFileOffset, 00519 &Wrapped ); 00520 00521 LogPageOffset = (ULONG)Lfcb->LogPageDataOffset; 00522 00523 // 00524 // We also adjust our pointer in the user's buffer to transfer 00525 // the next block to. 00526 // 00527 00528 Buffer = Add2Ptr( Buffer, RemainingPageBytes, PVOID ); 00529 } 00530 00531 } finally { 00532 00533 // 00534 // Unpin any previous buffer. 00535 // 00536 00537 if (Bcb != NULL) { 00538 00539 CcUnpinData( Bcb ); 00540 Bcb = NULL; 00541 } 00542 00543 DebugTrace( -1, Dbg, "LfsCopyReadLogRecord: Exit\n", 0 ); 00544 } 00545 00546 return; 00547 }

VOID LfsFindFirstIo IN PLFCB  Lfcb,
IN PLBCB  TargetLbcb,
IN PLBCB  FirstLbcb,
OUT PLBCB NextLbcb,
OUT PLONGLONG  FileOffset,
OUT PBOOLEAN  ContainsLastEntry,
OUT PBOOLEAN  LfsRestart,
OUT PBOOLEAN  UseTailCopy,
OUT PULONG  IoBlocks
 

Definition at line 2191 of file lfs/cachesup.c.

References ClearFlag, Dbg, DebugTrace, FALSE, _LBCB::FileOffset, FlagOn, LBCB_FLUSH_COPY, LBCB_ON_ACTIVE_QUEUE, _LBCB::LbcbFlags, LFCB_MULTIPLE_PAGE_IO, LFCB_PACK_LOG, LfsLbcbIsRestart, NULL, PAGE_SIZE, PAGED_CODE, and TRUE.

Referenced by LfsFlushLfcb().

02205 : 02206 02207 This routine walks through the linked Lbcb's for a Lfcb and groups 02208 as many of them as can be grouped into a single I/O transfer. 02209 It updates pointers to indicate the file offset and length of the 02210 transfer, whether the I/O includes a particular Lbcb, whether the 02211 transfer is a restart area or a log record page and the number of 02212 Lbcb's included in the transfer. We only flush a single log page 02213 if we are passing through the file for the first time. 02214 02215 Arguments: 02216 02217 Lfcb - This is the file control block for the log file. 02218 02219 TargetLbcb - This is the Lbcb that the caller wants to have included in 02220 the transfer. 02221 02222 FirstLbcb - This is the first Lbcb to look at in the list. 02223 02224 NextLbcb - This is the Lbcb to look at first on the next call to this 02225 routine. 02226 02227 FileOffset - Supplies the address where we store the offset in the 02228 log file of this transfer. 02229 02230 ContainsLastEntry - Supplies the address where we store whether this 02231 I/O includes the 'LastEntry' Lbcb. 02232 02233 LfsRestart - Supplies the address where we store whether this transfer 02234 is a Lfs restart area. 02235 02236 UseTailCopy - Supplies the address where we store whether we should 02237 use of page for a copy of the end of the log file. 02238 02239 IoBlocks - Supplies the address where we store the number of Lbcb's 02240 for this transfer. 02241 02242 Return Value: 02243 02244 None. 02245 02246 --*/ 02247 02248 { 02249 PAGED_CODE(); 02250 02251 DebugTrace( +1, Dbg, "LfsFindFirstIo: Entered\n", 0 ); 02252 DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); 02253 02254 // 02255 // Initialize the file offset, length and io blocks values. 02256 // Also assume the last entry is not contained here. 02257 // Also assume we have no next Lbcb. 02258 // 02259 02260 *FileOffset = FirstLbcb->FileOffset; 02261 *IoBlocks = 1; 02262 02263 *LfsRestart = FALSE; 02264 *UseTailCopy = FALSE; 02265 02266 *NextLbcb = NULL; 02267 02268 // 02269 // Check if we have found the desired Lbcb. We reject the match 02270 // if the Lbcb indicates that we should flush the copy first. 02271 // 02272 02273 if (FirstLbcb == TargetLbcb 02274 && !FlagOn( TargetLbcb->LbcbFlags, LBCB_FLUSH_COPY )) { 02275 02276 *ContainsLastEntry = TRUE; 02277 02278 } else { 02279 02280 *ContainsLastEntry = FALSE; 02281 } 02282 02283 // 02284 // Check if this is a restart block or if we are passing through the log 02285 // file for the first time or if this Lbcb is still in the active queue. 02286 // If not, then group as many of the Lbcb's as can be part of a single Io. 02287 // 02288 02289 if (LfsLbcbIsRestart( FirstLbcb )) { 02290 02291 *LfsRestart = TRUE; 02292 02293 } else if (FlagOn( Lfcb->Flags, LFCB_PACK_LOG ) 02294 && (FlagOn( FirstLbcb->LbcbFlags, LBCB_FLUSH_COPY | LBCB_ON_ACTIVE_QUEUE ))) { 02295 02296 *UseTailCopy = TRUE; 02297 02298 // 02299 // If we haven't found the last entry then we want to resume from 02300 // this same Lbcb if we flushed a copy otherwise we will want to 02301 // go to the next Lbcb. 02302 // 02303 02304 if (FlagOn( FirstLbcb->LbcbFlags, LBCB_FLUSH_COPY )) { 02305 02306 *NextLbcb = FirstLbcb; 02307 ClearFlag( FirstLbcb->LbcbFlags, LBCB_FLUSH_COPY ); 02308 } 02309 02310 } else if (FlagOn( Lfcb->Flags, LFCB_MULTIPLE_PAGE_IO )) { 02311 02312 PLBCB EndOfPageLbcb = NULL; 02313 ULONG EndOfPageIoBlocks; 02314 02315 // 02316 // We loop until there are no more blocks or they aren't 02317 // contiguous in the file or we have found an entry on the 02318 // active queue or we found an entry where we want to explicitly 02319 // flush a copy first. 02320 // 02321 02322 while ((FirstLbcb->WorkqueLinks.Flink != &Lfcb->LbcbWorkque) && 02323 !FlagOn( FirstLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE )) { 02324 02325 LONGLONG ExpectedFileOffset; 02326 PLBCB TempLbcb; 02327 02328 // 02329 // Get the next Lbcb. 02330 // 02331 02332 TempLbcb = CONTAINING_RECORD( FirstLbcb->WorkqueLinks.Flink, 02333 LBCB, 02334 WorkqueLinks ); 02335 02336 // 02337 // Break out of the loop if the file offset is not the 02338 // expected value or the next entry is on the active queue. 02339 // 02340 02341 ExpectedFileOffset = FirstLbcb->FileOffset + Lfcb->LogPageSize; 02342 02343 // 02344 // We want to stop at this point if the next Lbcb is not 02345 // the expected offset or we are packing the log file and 02346 // the next Lbcb is on the active queue or we want to write 02347 // a copy of the data before this page goes out. 02348 // 02349 02350 if ((TempLbcb->FileOffset != ExpectedFileOffset) || 02351 (FlagOn( Lfcb->Flags, LFCB_PACK_LOG ) && 02352 FlagOn( TempLbcb->LbcbFlags, LBCB_FLUSH_COPY | LBCB_ON_ACTIVE_QUEUE))) { 02353 02354 // 02355 // Use the Lbcb at the end of a page if possible. 02356 // 02357 02358 if (EndOfPageLbcb != NULL) { 02359 02360 FirstLbcb = EndOfPageLbcb; 02361 *IoBlocks = EndOfPageIoBlocks; 02362 } 02363 02364 break; 02365 } 02366 02367 // 02368 // We can add this to our I/o. Increment the Io blocks 02369 // and length of the transfer. Also check if this entry 02370 // is the Last Entry specified by the caller. 02371 // 02372 02373 *IoBlocks += 1; 02374 02375 if (TempLbcb == TargetLbcb ) { 02376 02377 *ContainsLastEntry = TRUE; 02378 } 02379 02380 // 02381 // Check if this Lbcb is at the end of a system page. 02382 // 02383 02384 if (*ContainsLastEntry && 02385 (PAGE_SIZE != (ULONG) Lfcb->SystemPageSize) && 02386 !FlagOn( ((ULONG) TempLbcb->FileOffset + (ULONG) Lfcb->LogPageSize), 02387 PAGE_SIZE - 1 )) { 02388 02389 EndOfPageLbcb = TempLbcb; 02390 EndOfPageIoBlocks = *IoBlocks; 02391 } 02392 02393 // 02394 // Use this entry as the current entry. 02395 // 02396 02397 FirstLbcb = TempLbcb; 02398 } 02399 } 02400 02401 // 02402 // If the current Lbcb is on the active queue and we aren't using 02403 // a tail copy, then remove this from the active queue. If this 02404 // not our target and removing this will cause us to swallow up 02405 // part of our reserved quota then back up one Lbcb. 02406 // 02407 02408 if (!(*UseTailCopy) && FlagOn( FirstLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE )) { 02409 02410 if (Lfcb->CurrentAvailable < Lfcb->TotalUndoCommitment) { 02411 02412 // 02413 // Move back one file record. 02414 // 02415 02416 *IoBlocks -= 1; 02417 *NextLbcb = FirstLbcb; 02418 02419 // 02420 // Otherwise remove it from the active queue. 02421 // 02422 02423 } else { 02424 02425 ClearFlag( FirstLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE ); 02426 RemoveEntryList( &FirstLbcb->ActiveLinks ); 02427 } 02428 } 02429 02430 // 02431 // If we haven't found the Lbcb to restart from we will just use the 02432 // next Lbcb after the last one found. 02433 // 02434 02435 if (*NextLbcb == NULL) { 02436 02437 *NextLbcb = CONTAINING_RECORD( FirstLbcb->WorkqueLinks.Flink, 02438 LBCB, 02439 WorkqueLinks ); 02440 } 02441 02442 DebugTrace( 0, Dbg, "File Offset (Low) -> %08lx\n", FileOffset->LowPart ); 02443 DebugTrace( 0, Dbg, "File Offset (High) -> %08lx\n", FileOffset->HighPart ); 02444 DebugTrace( 0, Dbg, "Contains Last Entry -> %08x\n", *ContainsLastEntry ); 02445 DebugTrace( 0, Dbg, "LfsRestart -> %08x\n", *LfsRestart ); 02446 DebugTrace( 0, Dbg, "IoBlocks -> %08lx\n", *IoBlocks ); 02447 DebugTrace( -1, Dbg, "LfsFindFirstIo: Exit\n", 0 ); 02448 02449 return; 02450 }

VOID LfsFlushLfcb IN PLFCB  Lfcb,
IN PLBCB  Lbcb
 

Definition at line 551 of file lfs/cachesup.c.

References Add2Ptr, ASSERT, CcFlushCache(), CcMapData(), CcSetDirtyPinnedData(), CcUnpinData(), CcUnpinDataForThread(), _LFS_RESTART_PAGE_HEADER::ChkDskLsn, ClearFlag, _LFS_RECORD_PAGE_HEADER::Copy, Count, Dbg, DebugTrace, DebugUnwind, ExGetCurrentResourceThread, ExRaiseStatus(), FALSE, _LBCB::FileOffset, FlagOn, _LBCB::Flags, KeClearEvent, KeSetEvent(), _LBCB::LastEndLsn, _LBCB::LastLsn, LBCB, _LBCB::Length, LFCB_FINAL_SHUTDOWN, LFCB_LOG_WRAPPED, LFCB_MULTIPLE_PAGE_IO, LFCB_READ_FIRST_RESTART, LFCB_READ_SECOND_RESTART, LFS_SIGNATURE_RECORD_PAGE_ULONG, LFS_SIGNATURE_RESTART_PAGE_ULONG, LfsAcquireLfcb, LfsClientThreadIo, LfsDeallocateLbcb(), LfsFindFirstIo(), LfsFlushLfcb(), LfsLi0, LfsNoIoInProgress, LfsPinOrMapData(), LfsPreparePinWriteData, LfsReleaseLfcb, LfsUsaSeqNumber, LOG_PAGE_LOG_RECORD_END, _LBCB::LogPageBcb, _LFS_RESTART_PAGE_HEADER::LogPageSize, LSN, _LFS_RESTART_PAGE_HEADER::MajorVersion, _LFS_RESTART_PAGE_HEADER::MinorVersion, _LFS_RESTART_PAGE_HEADER::MultiSectorHeader, _LFS_RECORD_PAGE_HEADER::MultiSectorHeader, NT_SUCCESS, NTSTATUS(), NULL, PAGE_SIZE, _LFS_RECORD_PAGE_HEADER::PageCount, PAGED_CODE, _LBCB::PageHeader, _LFS_RECORD_PAGE_HEADER::PagePosition, PLFS_RESTART_AREA, PUSHORT, _LBCB::ResourceThread, RESTART_SINGLE_PAGE_IO, _LFS_RESTART_PAGE_HEADER::RestartOffset, SetFlag, _MULTI_SECTOR_HEADER::Signature, Status, _LFS_RESTART_PAGE_HEADER::SystemPageSize, TRUE, try_return, _MULTI_SECTOR_HEADER::UpdateSequenceArrayOffset, _MULTI_SECTOR_HEADER::UpdateSequenceArraySize, USHORT, and _LBCB::WorkqueLinks.

Referenced by LfsFlushLbcb(), and LfsFlushLfcb().

00558 : 00559 00560 This routine is called to flush the current Lbcbs in on the Lfcb 00561 work queue. It will flush up to the I/O which contains the desired 00562 Lbcb. 00563 00564 Arguments: 00565 00566 Lfcb - This is the file control block for the log file. 00567 00568 Lbcb - This is the block which is needed to be flushed to disk. 00569 00570 Return Value: 00571 00572 None. 00573 00574 --*/ 00575 00576 { 00577 PLBCB FirstLbcb; 00578 PLBCB ThisLbcb; 00579 PLBCB NextLbcb; 00580 00581 PLBCB TargetLbcb; 00582 PULONG Signature; 00583 00584 LONGLONG FileOffset; 00585 ULONG Length; 00586 00587 BOOLEAN RaiseCorrupt = FALSE; 00588 BOOLEAN ValidLastLsn = FALSE; 00589 00590 BOOLEAN ContainsLastEntry = FALSE; 00591 BOOLEAN LfsRestart; 00592 BOOLEAN UseTailCopy; 00593 00594 ULONG IoBlocks; 00595 ULONG NewLfcbFlags = 0; 00596 00597 PBCB MapPageBcb = NULL; 00598 PVOID MapPage; 00599 00600 LSN LastLsn; 00601 00602 IO_STATUS_BLOCK Iosb; 00603 00604 PBCB PageBcb = NULL; 00605 00606 PAGED_CODE(); 00607 00608 DebugTrace( +1, Dbg, "LfsFlushLfcb: Entered\n", 0 ); 00609 DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); 00610 00611 // 00612 // Use a try-finally to facilitate cleanup. 00613 // 00614 00615 try { 00616 00617 // 00618 // If there are no elements on the list, we are done. 00619 // 00620 00621 if (IsListEmpty( &Lfcb->LbcbWorkque )) { 00622 00623 try_return( NOTHING ); 00624 } 00625 00626 // 00627 // Mark the Lfcb as Io in progress. 00628 // 00629 00630 Lfcb->LfsIoState = LfsClientThreadIo; 00631 #ifdef BRIANDBG 00632 Lfcb->LfsIoThread = ExGetCurrentResourceThread(); 00633 #endif 00634 00635 // 00636 // Remember the first Lbcb in the list. 00637 // 00638 00639 FirstLbcb = CONTAINING_RECORD( Lfcb->LbcbWorkque.Flink, 00640 LBCB, 00641 WorkqueLinks ); 00642 00643 // 00644 // We continue looping and performing I/o for as long as possible. 00645 // 00646 00647 while (!ContainsLastEntry) { 00648 00649 ASSERT( Lfcb->PageToDirty == NULL ); 00650 00651 // 00652 // Reset the notify event for all of the waiting threads. 00653 // 00654 00655 KeClearEvent( &Lfcb->Sync->Event ); 00656 00657 // 00658 // Find the block of Lbcb's that make up the first I/O, remembering 00659 // how many there are. Also remember if this I/O contains the 00660 // last element on the list when we were called. 00661 // 00662 00663 LfsFindFirstIo( Lfcb, 00664 Lbcb, 00665 FirstLbcb, 00666 &NextLbcb, 00667 &FileOffset, 00668 &ContainsLastEntry, 00669 &LfsRestart, 00670 &UseTailCopy, 00671 &IoBlocks ); 00672 00673 Length = IoBlocks * (ULONG) Lfcb->LogPageSize; 00674 if (UseTailCopy) { 00675 00676 TargetLbcb = Lfcb->ActiveTail; 00677 Lfcb->ActiveTail = Lfcb->PrevTail; 00678 Lfcb->PrevTail = TargetLbcb; 00679 00680 FileOffset = TargetLbcb->FileOffset; 00681 00682 } else { 00683 00684 TargetLbcb = FirstLbcb; 00685 } 00686 00687 // 00688 // Give up the Lfcb unless we are looking at an active page. 00689 // 00690 00691 if (!UseTailCopy) { 00692 00693 LfsReleaseLfcb( Lfcb ); 00694 } 00695 00696 // 00697 // If this I/O involves the Lfs restart area, write it to the 00698 // cache pages. 00699 // 00700 00701 if (LfsRestart) { 00702 00703 PLFS_RESTART_PAGE_HEADER RestartPage; 00704 BOOLEAN UsaError; 00705 NTSTATUS Status; 00706 00707 // 00708 // If there was some error in initially reading the restart page then 00709 // it is OK to settle for a page of zeroes. 00710 // 00711 00712 if (FlagOn( Lfcb->Flags, LFCB_READ_FIRST_RESTART | LFCB_READ_SECOND_RESTART ) && 00713 ((FileOffset == 0) ? 00714 FlagOn( Lfcb->Flags, LFCB_READ_FIRST_RESTART ) : 00715 FlagOn( Lfcb->Flags, LFCB_READ_SECOND_RESTART ))) { 00716 00717 LfsPreparePinWriteData( Lfcb, 00718 FileOffset, 00719 (ULONG) Lfcb->SystemPageSize, 00720 &RestartPage, 00721 &PageBcb ); 00722 00723 Status = STATUS_SUCCESS; 00724 00725 if (FileOffset == 0) { 00726 00727 SetFlag( NewLfcbFlags, LFCB_READ_FIRST_RESTART ); 00728 00729 } else { 00730 00731 SetFlag( NewLfcbFlags, LFCB_READ_SECOND_RESTART ); 00732 } 00733 00734 } else { 00735 00736 Status = LfsPinOrMapData( Lfcb, 00737 FileOffset, 00738 (ULONG)Lfcb->SystemPageSize, 00739 TRUE, 00740 TRUE, 00741 TRUE, 00742 &UsaError, 00743 &RestartPage, 00744 &PageBcb ); 00745 } 00746 00747 if (NT_SUCCESS( Status )) { 00748 00749 // 00750 // Initialize the restart page header. 00751 // 00752 00753 Signature = (PULONG) &RestartPage->MultiSectorHeader.Signature; 00754 00755 *Signature = LFS_SIGNATURE_RESTART_PAGE_ULONG; 00756 RestartPage->ChkDskLsn = LfsLi0; 00757 00758 RestartPage->MultiSectorHeader.UpdateSequenceArrayOffset 00759 = Lfcb->RestartUsaOffset; 00760 00761 RestartPage->MultiSectorHeader.UpdateSequenceArraySize 00762 = Lfcb->RestartUsaArraySize; 00763 00764 RestartPage->SystemPageSize = (ULONG)Lfcb->SystemPageSize; 00765 RestartPage->LogPageSize = (ULONG)Lfcb->LogPageSize; 00766 00767 RestartPage->RestartOffset = (USHORT) Lfcb->RestartDataOffset; 00768 RestartPage->MajorVersion = Lfcb->MajorVersion; 00769 RestartPage->MinorVersion = Lfcb->MinorVersion; 00770 00771 // 00772 // If the Lfcb indicates that the file has wrapped, then clear the 00773 // first pass flag in the restart area. 00774 // 00775 00776 if (FlagOn( Lfcb->Flags, LFCB_LOG_WRAPPED )) { 00777 00778 ClearFlag( ((PLFS_RESTART_AREA) FirstLbcb->PageHeader)->Flags, RESTART_SINGLE_PAGE_IO ); 00779 SetFlag( Lfcb->Flags, LFCB_MULTIPLE_PAGE_IO ); 00780 } 00781 00782 // 00783 // Write the page header into the page and mark the page dirty. 00784 // 00785 00786 RtlCopyMemory( Add2Ptr( RestartPage, Lfcb->RestartDataOffset, PVOID ), 00787 FirstLbcb->PageHeader, 00788 (ULONG)FirstLbcb->Length ); 00789 00790 // 00791 // Make sure the modified bit gets set in the pfn database. The 00792 // cache manager should do this even for files we told him not to 00793 // lazy write. 00794 // 00795 00796 CcSetDirtyPinnedData( PageBcb, NULL ); 00797 00798 // 00799 // We unpin any buffers pinned on this page. 00800 // 00801 00802 CcUnpinData( PageBcb ); 00803 PageBcb = NULL; 00804 00805 LastLsn = FirstLbcb->LastLsn; 00806 ValidLastLsn = TRUE; 00807 00808 // 00809 // Use a system page size as the length we need to flush. 00810 // 00811 00812 Length = (ULONG)Lfcb->SystemPageSize; 00813 00814 } else { 00815 00816 RaiseCorrupt = TRUE; 00817 } 00818 00819 // 00820 // Otherwise these are log record pages 00821 // 00822 00823 } else { 00824 00825 PLFS_RECORD_PAGE_HEADER RecordPageHeader; 00826 00827 ULONG Count; 00828 00829 // 00830 // Mark the last Lsn fields for the page headers and each 00831 // page's position in the transfer. Also unpin all of the 00832 // log pages. 00833 // 00834 00835 Count = 1; 00836 00837 ThisLbcb = FirstLbcb; 00838 00839 while (TRUE) { 00840 00841 // 00842 // If we have to use the tail copy, then pin a page to use. 00843 // 00844 00845 if (UseTailCopy) { 00846 00847 BOOLEAN UsaError; 00848 00849 if (!NT_SUCCESS( LfsPinOrMapData( Lfcb, 00850 TargetLbcb->FileOffset, 00851 (ULONG)Lfcb->LogPageSize, 00852 TRUE, 00853 TRUE, 00854 TRUE, 00855 &UsaError, 00856 &RecordPageHeader, 00857 &PageBcb ))) { 00858 00859 RaiseCorrupt = TRUE; 00860 break; 00861 } 00862 00863 } else { 00864 00865 PUSHORT SeqNumber; 00866 00867 RecordPageHeader = (PLFS_RECORD_PAGE_HEADER) ThisLbcb->PageHeader; 00868 00869 // 00870 // If the sequence number is zero then this is probably a 00871 // page of zeroes produced by the cache manager. In order 00872 // to insure that we don't have the same sequence number 00873 // on each page we will seed the sequence number. 00874 // 00875 00876 SeqNumber = Add2Ptr( RecordPageHeader, 00877 Lfcb->LogRecordUsaOffset, 00878 PUSHORT ); 00879 00880 if (*SeqNumber == 0) { 00881 00882 *SeqNumber = LfsUsaSeqNumber; 00883 LfsUsaSeqNumber += 1; 00884 } 00885 } 00886 00887 // 00888 // Make sure the modified bit gets set in the pfn database. The 00889 // cache manager should do this even for files we told him not to 00890 // lazy write. 00891 // 00892 00893 if (UseTailCopy) { 00894 00895 // 00896 // Store the file offset of the real page in the header. 00897 // Also set the flag indicating the page is a tail copy. 00898 // 00899 00900 RtlCopyMemory( RecordPageHeader, 00901 ThisLbcb->PageHeader, 00902 (ULONG)Lfcb->LogPageSize ); 00903 00904 RecordPageHeader->Copy.FileOffset = ThisLbcb->FileOffset; 00905 } 00906 00907 // 00908 // We update all of fields as yet not updated. 00909 // 00910 00911 RecordPageHeader->PagePosition = (USHORT) Count; 00912 RecordPageHeader->PageCount = (USHORT) IoBlocks; 00913 00914 // 00915 // We set up the update sequence array for this structure. 00916 // 00917 00918 Signature = (PULONG) &RecordPageHeader->MultiSectorHeader.Signature; 00919 *Signature = LFS_SIGNATURE_RECORD_PAGE_ULONG; 00920 00921 RecordPageHeader->MultiSectorHeader.UpdateSequenceArrayOffset 00922 = Lfcb->LogRecordUsaOffset; 00923 00924 RecordPageHeader->MultiSectorHeader.UpdateSequenceArraySize 00925 = Lfcb->LogRecordUsaArraySize; 00926 00927 // 00928 // Make sure the modified bit gets set in the pfn database. The 00929 // cache manager should do this even for files we told him not to 00930 // lazy write. 00931 // 00932 00933 if (UseTailCopy) { 00934 00935 CcSetDirtyPinnedData( PageBcb, NULL ); 00936 00937 CcUnpinData( PageBcb ); 00938 PageBcb = NULL; 00939 00940 } else { 00941 00942 CcSetDirtyPinnedData( ThisLbcb->LogPageBcb, NULL ); 00943 00944 // 00945 // We unpin any buffers pinned on this page. 00946 // 00947 00948 CcUnpinDataForThread( ThisLbcb->LogPageBcb, ThisLbcb->ResourceThread ); 00949 } 00950 00951 // 00952 // Remember the last lsn and its length if this is the final 00953 // page of an Lsn. 00954 // 00955 00956 if (FlagOn( ThisLbcb->Flags, LOG_PAGE_LOG_RECORD_END )) { 00957 00958 LastLsn = ThisLbcb->LastEndLsn; 00959 ValidLastLsn = TRUE; 00960 } 00961 00962 // 00963 // Exit the loop if this is the last block. 00964 // 00965 00966 if (Count == IoBlocks) { 00967 00968 break; 00969 } 00970 00971 // 00972 // Otherwise move to the next entry. 00973 // 00974 00975 ThisLbcb = CONTAINING_RECORD( ThisLbcb->WorkqueLinks.Flink, 00976 LBCB, 00977 WorkqueLinks ); 00978 00979 Count += 1; 00980 } 00981 } 00982 00983 // 00984 // Remember the range we are flushing and find the second half of a page 00985 // if necessary. 00986 // 00987 00988 Lfcb->UserWriteData->FileOffset = FileOffset; 00989 Lfcb->UserWriteData->Length = Length; 00990 00991 if (!UseTailCopy && !LfsRestart) { 00992 00993 PLBCB TailLbcb; 00994 PLIST_ENTRY Links; 00995 LONGLONG NextOffset; 00996 00997 // 00998 // We are flushing log records. If the current request does not end on 00999 // a system page boundary then check if there is another page in 01000 // memory that we are concerned with. 01001 // 01002 01003 if (FlagOn( (ULONG)(FileOffset + Length), (PAGE_SIZE - 1) )) { 01004 01005 NextOffset = FileOffset + Length; 01006 01007 LfsAcquireLfcb( Lfcb ); 01008 01009 // 01010 // Start by looking through the Lbcbs on the active queue. 01011 // 01012 01013 Links = Lfcb->LbcbActive.Flink; 01014 01015 while (Links != &Lfcb->LbcbActive) { 01016 01017 TailLbcb = CONTAINING_RECORD( Links, 01018 LBCB, 01019 ActiveLinks ); 01020 01021 if (TailLbcb->FileOffset == NextOffset) { 01022 01023 Lfcb->PageToDirty = TailLbcb; 01024 break; 01025 } 01026 01027 Links = Links->Flink; 01028 } 01029 01030 // 01031 // If we didn't find it then scan to the end of the workque. 01032 // 01033 01034 if (Lfcb->PageToDirty == NULL) { 01035 01036 Links = Lfcb->LbcbWorkque.Flink; 01037 01038 while (Links != &Lfcb->LbcbWorkque) { 01039 01040 TailLbcb = CONTAINING_RECORD( Links, 01041 LBCB, 01042 WorkqueLinks ); 01043 01044 if (TailLbcb->FileOffset == NextOffset) { 01045 01046 Lfcb->PageToDirty = TailLbcb; 01047 break; 01048 } 01049 01050 Links = Links->Flink; 01051 } 01052 } 01053 01054 // 01055 // If we found an Lbcb then unpin the page temporarily. 01056 // Other users will have to detect this is not pinned. 01057 // 01058 01059 if (Lfcb->PageToDirty != NULL) { 01060 01061 // 01062 // Go ahead and map this page to keep the virtual address 01063 // valid. 01064 // 01065 01066 CcMapData( Lfcb->FileObject, 01067 (PLARGE_INTEGER) &Lfcb->PageToDirty->FileOffset, 01068 (ULONG) Lfcb->LogPageSize, 01069 TRUE, 01070 &MapPageBcb, 01071 &MapPage ); 01072 01073 CcUnpinDataForThread( Lfcb->PageToDirty->LogPageBcb, 01074 Lfcb->PageToDirty->ResourceThread ); 01075 01076 Lfcb->PageToDirty->LogPageBcb = NULL; 01077 } 01078 01079 LfsReleaseLfcb( Lfcb ); 01080 } 01081 } 01082 01083 // 01084 // We are ready to do the I/O. Flush the pages to the log file. 01085 // 01086 01087 CcFlushCache( Lfcb->FileObject->SectionObjectPointer, 01088 (PLARGE_INTEGER)&FileOffset, 01089 Length, 01090 &Iosb ); 01091 01092 // 01093 // Recover the state of any partial page first. 01094 // 01095 01096 if (Lfcb->PageToDirty != NULL) { 01097 01098 LfsPreparePinWriteData( Lfcb, 01099 Lfcb->PageToDirty->FileOffset, 01100 (ULONG) Lfcb->LogPageSize, 01101 &Lfcb->PageToDirty->PageHeader, 01102 &Lfcb->PageToDirty->LogPageBcb ); 01103 01104 Lfcb->PageToDirty->ResourceThread = ExGetCurrentResourceThread(); 01105 Lfcb->PageToDirty = NULL; 01106 01107 CcUnpinData( MapPageBcb ); 01108 MapPageBcb = NULL; 01109 } 01110 01111 if (!NT_SUCCESS( Iosb.Status )) { 01112 01113 LONG BytesRemaining = (LONG) Length; 01114 01115 // 01116 // If we get an error then try each individual page. 01117 // 01118 01119 while (BytesRemaining > 0) { 01120 01121 // 01122 // Remember the range we are flushing and find the second half of a page 01123 // if necessary. 01124 // 01125 01126 Lfcb->UserWriteData->FileOffset = FileOffset; 01127 Lfcb->UserWriteData->Length = Length; 01128 01129 if (!UseTailCopy && !LfsRestart) { 01130 01131 PLBCB TailLbcb; 01132 PLIST_ENTRY Links; 01133 LONGLONG NextOffset; 01134 01135 // 01136 // We are flushing log records. If the current request does not end on 01137 // a system page boundary then check if there is another page in 01138 // memory that we are concerned with. 01139 // 01140 01141 if (FlagOn( (ULONG)(FileOffset + Length), (PAGE_SIZE - 1) )) { 01142 01143 NextOffset = FileOffset + Length; 01144 01145 LfsAcquireLfcb( Lfcb ); 01146 01147 // 01148 // Start by looking through the Lbcbs on the active queue. 01149 // 01150 01151 Links = Lfcb->LbcbActive.Flink; 01152 01153 while (Links != &Lfcb->LbcbActive) { 01154 01155 TailLbcb = CONTAINING_RECORD( Links, 01156 LBCB, 01157 ActiveLinks ); 01158 01159 if (TailLbcb->FileOffset == NextOffset) { 01160 01161 Lfcb->PageToDirty = TailLbcb; 01162 break; 01163 } 01164 01165 Links = Links->Flink; 01166 } 01167 01168 // 01169 // If we didn't find it then scan to the end of the workque. 01170 // 01171 01172 if (Lfcb->PageToDirty == NULL) { 01173 01174 Links = Lfcb->LbcbWorkque.Flink; 01175 01176 while (Links != &Lfcb->LbcbWorkque) { 01177 01178 TailLbcb = CONTAINING_RECORD( Links, 01179 LBCB, 01180 WorkqueLinks ); 01181 01182 if (TailLbcb->FileOffset == NextOffset) { 01183 01184 Lfcb->PageToDirty = TailLbcb; 01185 break; 01186 } 01187 01188 Links = Links->Flink; 01189 } 01190 } 01191 01192 // 01193 // If we found an Lbcb then unpin the page temporarily. 01194 // Other users will have to detect this is not pinned. 01195 // 01196 01197 if (Lfcb->PageToDirty != NULL) { 01198 01199 CcMapData( Lfcb->FileObject, 01200 (PLARGE_INTEGER) &Lfcb->PageToDirty->FileOffset, 01201 (ULONG) Lfcb->PageToDirty->Length, 01202 TRUE, 01203 &MapPageBcb, 01204 &MapPage ); 01205 01206 CcUnpinDataForThread( Lfcb->PageToDirty->LogPageBcb, 01207 Lfcb->PageToDirty->ResourceThread ); 01208 01209 Lfcb->PageToDirty->LogPageBcb = NULL; 01210 } 01211 } 01212 LfsReleaseLfcb( Lfcb ); 01213 } 01214 01215 CcFlushCache( Lfcb->FileObject->SectionObjectPointer, 01216 (PLARGE_INTEGER)&FileOffset, 01217 (ULONG)Lfcb->SystemPageSize, 01218 &Iosb ); 01219 01220 // 01221 // Recover the state of any partial page first. 01222 // 01223 01224 if (Lfcb->PageToDirty != NULL) { 01225 01226 LfsPreparePinWriteData( Lfcb, 01227 Lfcb->PageToDirty->FileOffset, 01228 (ULONG) Lfcb->PageToDirty->Length, 01229 &Lfcb->PageToDirty->PageHeader, 01230 &Lfcb->PageToDirty->LogPageBcb ); 01231 01232 Lfcb->PageToDirty->ResourceThread = ExGetCurrentResourceThread(); 01233 Lfcb->PageToDirty = NULL; 01234 01235 CcUnpinData( MapPageBcb ); 01236 MapPageBcb = NULL; 01237 } 01238 01239 if (!NT_SUCCESS( Iosb.Status )) { 01240 01241 #ifdef NTFS_RESTART 01242 ASSERT( FALSE ); 01243 #endif 01244 RaiseCorrupt = TRUE; 01245 } 01246 01247 BytesRemaining -= (LONG)Lfcb->SystemPageSize; 01248 FileOffset = FileOffset + Lfcb->SystemPageSize; 01249 } 01250 } 01251 01252 // 01253 // Reacquire the Lfcb, remembering that we have it. 01254 // 01255 01256 if (!UseTailCopy) { 01257 01258 LfsAcquireLfcb( Lfcb ); 01259 } 01260 01261 // 01262 // Update the last flushed Lsn value if this isn't a 01263 // restart write. 01264 // 01265 01266 if (!LfsRestart) { 01267 01268 if (ValidLastLsn) { 01269 01270 Lfcb->LastFlushedLsn = LastLsn; 01271 } 01272 01273 // 01274 // Remember the Lsn we assigned to this restart area. 01275 // 01276 01277 } else { 01278 01279 Lfcb->LastFlushedRestartLsn = LastLsn; 01280 01281 // 01282 // Clear any neccessary flags on a successful operation. 01283 // 01284 01285 if (!RaiseCorrupt) { 01286 01287 ClearFlag( Lfcb->Flags, NewLfcbFlags ); 01288 NewLfcbFlags = 0; 01289 } 01290 01291 // 01292 // If this is the first write of a restart area and we have 01293 // updated the LogOpenCount then update the field in the Lfcb. 01294 // 01295 01296 if (NT_SUCCESS( Iosb.Status ) && 01297 (Lfcb->CurrentOpenLogCount != ((PLFS_RESTART_AREA) FirstLbcb->PageHeader)->RestartOpenLogCount)) { 01298 01299 Lfcb->CurrentOpenLogCount = ((PLFS_RESTART_AREA) FirstLbcb->PageHeader)->RestartOpenLogCount; 01300 } 01301 } 01302 01303 // 01304 // Walk through all the Lbcb's we flushed, deallocating the Lbcbs. 01305 // 01306 01307 if (!UseTailCopy) { 01308 01309 PLBCB TempLbcb; 01310 01311 ThisLbcb = FirstLbcb; 01312 01313 while (TRUE) { 01314 01315 // 01316 // Remember the next entry on the list. 01317 // 01318 01319 TempLbcb = CONTAINING_RECORD( ThisLbcb->WorkqueLinks.Flink, 01320 LBCB, 01321 WorkqueLinks ); 01322 01323 // 01324 // Remove it from the LbcbWorkque queue. 01325 // 01326 01327 RemoveEntryList( &ThisLbcb->WorkqueLinks ); 01328 01329 // 01330 // Deallocate the structure. 01331 // 01332 01333 LfsDeallocateLbcb( Lfcb, ThisLbcb ); 01334 01335 if (IoBlocks-- == 1) { 01336 01337 break; 01338 } 01339 01340 ThisLbcb = TempLbcb; 01341 } 01342 } 01343 01344 // 01345 // If we flushed the Lbcb we were interested in, we are done. 01346 // We will signal all waiting threads regardless 01347 // 01348 01349 KeSetEvent( &Lfcb->Sync->Event, 0, FALSE ); 01350 01351 // 01352 // Remember the starting Lbcb for the next I/O. 01353 // 01354 01355 FirstLbcb = NextLbcb; 01356 } 01357 01358 try_exit: NOTHING; 01359 } finally { 01360 01361 DebugUnwind( LfsFlushLfcb ); 01362 01363 ASSERT( Lfcb->PageToDirty == NULL ); 01364 01365 // 01366 // Show that there is no Io in progress. 01367 // 01368 01369 Lfcb->LfsIoState = LfsNoIoInProgress; 01370 #ifdef BRIANDBG 01371 Lfcb->LfsIoThread = 0; 01372 #endif 01373 01374 // 01375 // Make sure we didn't leave any pages pinned. 01376 // 01377 01378 if (PageBcb != NULL) { 01379 01380 CcUnpinData( PageBcb ); 01381 } 01382 01383 DebugTrace( -1, Dbg, "LfsFlushLfcb: Exit\n", 0 ); 01384 } 01385 01386 // 01387 // If the Io failed at some point, we raise a corrupt disk error. 01388 // The only exception is if this is the final flush of the log file. 01389 // In this case the client may not be able to cleanup after this error. 01390 // 01391 01392 if (RaiseCorrupt && (!FlagOn( Lfcb->Flags, LFCB_FINAL_SHUTDOWN ))) { 01393 01394 ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); 01395 } 01396 01397 return; 01398 }

BOOLEAN LfsIsClientAreaValid IN PLFS_RESTART_PAGE_HEADER  PageHeader,
IN BOOLEAN  LogPacked,
IN BOOLEAN  UsaError
 

Definition at line 2046 of file lfs/cachesup.c.

References Add2Ptr, _LFS_RESTART_AREA::ClientArrayOffset, _LFS_RESTART_AREA::ClientFreeList, _LFS_RESTART_AREA::ClientInUseList, FALSE, FIRST_STRIDE, LFS_NO_CLIENT, _LFS_RESTART_AREA::LogClients, _LFS_CLIENT_RECORD::NextClient, PAGED_CODE, PLFS_CLIENT_RECORD, _LFS_CLIENT_RECORD::PrevClient, _LFS_RESTART_AREA::RestartAreaLength, TRUE, and USHORT.

Referenced by LfsReadRestart().

02054 : 02055 02056 This routine is called to verify that the client array is valid. We test 02057 if the client lists are correctly chained. If the entire restart area is 02058 within the first Usa stride, we will ignore any Usa errors. 02059 02060 Arguments: 02061 02062 PageHeader - This is the page to examine. 02063 02064 LogPacked - Indicates if the log file is packed. 02065 02066 UsaError - There was a Usa error in reading the full page. 02067 02068 Return Value: 02069 02070 BOOLEAN - TRUE if there is no corruption in client array values. 02071 FALSE otherwise. 02072 02073 --*/ 02074 02075 { 02076 PLFS_RESTART_AREA RestartArea; 02077 USHORT ThisClientIndex; 02078 USHORT ClientCount; 02079 02080 PLFS_CLIENT_RECORD ClientArray; 02081 PLFS_CLIENT_RECORD ThisClient; 02082 02083 ULONG LoopCount; 02084 02085 PAGED_CODE(); 02086 02087 RestartArea = Add2Ptr( PageHeader, PageHeader->RestartOffset, PLFS_RESTART_AREA ); 02088 02089 // 02090 // If there was a Usa error and the restart area isn't contained in the 02091 // first Usa stride, then we have an error. 02092 // 02093 02094 if (UsaError 02095 && (RestartArea->RestartAreaLength + PageHeader->RestartOffset) > FIRST_STRIDE) { 02096 02097 return FALSE; 02098 } 02099 02100 // 02101 // Find the start of the client array. 02102 // 02103 02104 if (LogPacked) { 02105 02106 ClientArray = Add2Ptr( RestartArea, 02107 RestartArea->ClientArrayOffset, 02108 PLFS_CLIENT_RECORD ); 02109 02110 } else { 02111 02112 // 02113 // Handle the case where the offset of the client array is fixed. 02114 // 02115 02116 ClientArray = Add2Ptr( RestartArea, 02117 FIELD_OFFSET( LFS_OLD_RESTART_AREA, 02118 LogClientArray ), 02119 PLFS_CLIENT_RECORD ); 02120 } 02121 02122 // 02123 // Start with the free list. Check that all the clients are valid and 02124 // that there isn't a cycle. Do the in-use list on the second pass. 02125 // 02126 02127 ThisClientIndex = RestartArea->ClientFreeList; 02128 02129 LoopCount = 2; 02130 02131 do { 02132 02133 BOOLEAN FirstClient; 02134 02135 FirstClient = TRUE; 02136 02137 ClientCount = RestartArea->LogClients; 02138 02139 while (ThisClientIndex != LFS_NO_CLIENT) { 02140 02141 // 02142 // If the client count is zero then we must have hit a loop. 02143 // If the client index is greater or equal to the log client 02144 // count then the list is corrupt. 02145 // 02146 02147 if (ClientCount == 0 02148 || ThisClientIndex >= RestartArea->LogClients) { 02149 02150 return FALSE; 02151 } 02152 02153 ClientCount -= 1; 02154 02155 ThisClient = ClientArray + ThisClientIndex; 02156 ThisClientIndex = ThisClient->NextClient; 02157 02158 // 02159 // If this is the first client, then the previous value 02160 // should indicate no client. 02161 // 02162 02163 if (FirstClient) { 02164 02165 FirstClient = FALSE; 02166 02167 if (ThisClient->PrevClient != LFS_NO_CLIENT) { 02168 02169 return FALSE; 02170 } 02171 } 02172 } 02173 02174 ThisClientIndex = RestartArea->ClientInUseList; 02175 02176 } while (--LoopCount); 02177 02178 // 02179 // The client list is valid. 02180 // 02181 02182 return TRUE; 02183 }

BOOLEAN LfsIsRestartAreaValid IN PLFS_RESTART_PAGE_HEADER  PageHeader,
IN BOOLEAN  LogPacked
 

Definition at line 1885 of file lfs/cachesup.c.

References Add2Ptr, _LFS_RESTART_AREA::ClientArrayOffset, _LFS_RESTART_AREA::ClientFreeList, _LFS_RESTART_AREA::ClientInUseList, FALSE, _LFS_RESTART_AREA::FileSize, FIRST_STRIDE, LFS_CLIENT_RECORD, LFS_NO_CLIENT, LFS_OLD_RESTART_AREA, LFS_RESTART_AREA, _LFS_RESTART_AREA::LogClients, _LFS_RESTART_AREA::LogPageDataOffset, LSN, PAGED_CODE, QuadAlign, _LFS_RESTART_AREA::RecordHeaderLength, _LFS_RESTART_AREA::RestartAreaLength, _LFS_RESTART_AREA::SeqNumberBits, and TRUE.

Referenced by LfsReadRestart().

01892 : 01893 01894 This routine is called to verify that the restart area attached to the 01895 log page header is valid. The restart values must be contained within 01896 the first Usa stride of the file. This is so we can restart successfully 01897 after chkdsk. 01898 01899 Arguments: 01900 01901 PageHeader - This is the page to examine. 01902 01903 LogPacked - Indicates if the log file is packed. 01904 01905 Return Value: 01906 01907 BOOLEAN - TRUE if there is no corruption in the restart area values. 01908 FALSE otherwise. 01909 01910 --*/ 01911 01912 { 01913 PLFS_RESTART_AREA RestartArea; 01914 ULONG OffsetInRestart; 01915 ULONG SeqNumberBits; 01916 01917 LONGLONG FileSize; 01918 01919 PAGED_CODE(); 01920 01921 // 01922 // The basic part of the restart area must fit into the first stride of 01923 // the page. This will allow chkdsk to work even if there are Usa errors. 01924 // 01925 01926 OffsetInRestart = FIELD_OFFSET( LFS_RESTART_AREA, FileSize ); 01927 01928 if ((PageHeader->RestartOffset + OffsetInRestart) > FIRST_STRIDE) { 01929 01930 return FALSE; 01931 } 01932 01933 RestartArea = Add2Ptr( PageHeader, PageHeader->RestartOffset, PLFS_RESTART_AREA ); 01934 01935 // 01936 // Everything in the restart area except the actual client array must also 01937 // be in the first stride. If the structure is packed, then we can use 01938 // a field in the restart area for the client offset. 01939 // 01940 01941 if (LogPacked) { 01942 01943 OffsetInRestart = RestartArea->ClientArrayOffset; 01944 01945 } else { 01946 01947 // 01948 // We shouldn't see any of the older disks now. 01949 // 01950 01951 OffsetInRestart = FIELD_OFFSET( LFS_OLD_RESTART_AREA, LogClientArray ); 01952 } 01953 01954 if (QuadAlign( OffsetInRestart ) != OffsetInRestart 01955 || (PageHeader->RestartOffset + OffsetInRestart) > FIRST_STRIDE) { 01956 01957 return FALSE; 01958 } 01959 01960 // 01961 // The full size of the restart area must fit in the system page specified by 01962 // the page header. We compute the size of the restart area by calculating 01963 // the space needed by all clients. We also check the given size of the 01964 // restart area. 01965 // 01966 01967 OffsetInRestart += (RestartArea->LogClients * sizeof( LFS_CLIENT_RECORD )); 01968 01969 if (OffsetInRestart > PageHeader->SystemPageSize ) { 01970 01971 return FALSE; 01972 } 01973 01974 // 01975 // If the log is packed, then check the restart length field and whether 01976 // the entire restart area is contained in that length. 01977 // 01978 01979 if (LogPacked 01980 && ((ULONG) (PageHeader->RestartOffset + RestartArea->RestartAreaLength) > PageHeader->SystemPageSize 01981 || OffsetInRestart > RestartArea->RestartAreaLength)) { 01982 01983 return FALSE; 01984 } 01985 01986 // 01987 // As a final check make sure that the in use list and the free list are either 01988 // empty or point to a valid client. 01989 // 01990 01991 if ((RestartArea->ClientFreeList != LFS_NO_CLIENT 01992 && RestartArea->ClientFreeList >= RestartArea->LogClients) 01993 01994 || (RestartArea->ClientInUseList != LFS_NO_CLIENT 01995 && RestartArea->ClientInUseList >= RestartArea->LogClients)) { 01996 01997 return FALSE; 01998 } 01999 02000 // 02001 // Make sure the sequence number bits match the log file size. 02002 // 02003 02004 FileSize = RestartArea->FileSize; 02005 02006 for (SeqNumberBits = 0; 02007 ( FileSize != 0 ); 02008 SeqNumberBits += 1, 02009 FileSize = ((ULONGLONG)(FileSize)) >> 1 ) { 02010 } 02011 02012 SeqNumberBits = (sizeof( LSN ) * 8) + 3 - SeqNumberBits; 02013 02014 if (SeqNumberBits != RestartArea->SeqNumberBits) { 02015 02016 return FALSE; 02017 } 02018 02019 // 02020 // We will check the fields that apply only to a packed log file. 02021 // 02022 02023 if (LogPacked) { 02024 02025 // 02026 // The log page data offset and record header length must be 02027 // quad-aligned. 02028 // 02029 02030 if ((QuadAlign( RestartArea->LogPageDataOffset ) != RestartArea->LogPageDataOffset ) || 02031 (QuadAlign( RestartArea->RecordHeaderLength ) != RestartArea->RecordHeaderLength )) { 02032 02033 return FALSE; 02034 } 02035 } 02036 02037 return TRUE; 02038 }

BOOLEAN LfsIsRestartPageHeaderValid IN LONGLONG  FileOffset,
IN PLFS_RESTART_PAGE_HEADER  PageHeader,
OUT PBOOLEAN  LogPacked
 

Definition at line 1711 of file lfs/cachesup.c.

References FALSE, PAGED_CODE, QuadAlign, SEQUENCE_NUMBER_STRIDE, TRUE, UPDATE_SEQUENCE_NUMBER, UpdateSequenceArraySize, and USHORT.

Referenced by LfsReadRestart().

01719 : 01720 01721 This routine is called to verify that the candidate for a restart page 01722 has no corrupt values in the page header. It verifies that the restart and 01723 system page size have only one bit set and are at least the value of 01724 the update sequence array stride. 01725 01726 Arguments: 01727 01728 FileOffset - This is the offset in the file of the restart area to examine. 01729 If this offset is not 0, then it should match the system page size. 01730 01731 PageHeader - This is the page to examine. 01732 01733 LogPacked - Address to store whether the log file is packed. 01734 01735 Return Value: 01736 01737 BOOLEAN - TRUE if there is no corruption in the pool header values. 01738 FALSE otherwise. 01739 01740 --*/ 01741 01742 { 01743 ULONG SystemPage; 01744 ULONG LogPageSize; 01745 ULONG Mask; 01746 ULONG BitCount; 01747 01748 USHORT EndOfUsa; 01749 01750 PAGED_CODE(); 01751 01752 *LogPacked = FALSE; 01753 01754 // 01755 // Copy the values from the page header into the local variables. 01756 // 01757 01758 SystemPage = PageHeader->SystemPageSize; 01759 LogPageSize = PageHeader->LogPageSize; 01760 01761 // 01762 // The system page and log page sizes must be greater or equal to the 01763 // update sequence stride. 01764 // 01765 01766 if (SystemPage < SEQUENCE_NUMBER_STRIDE 01767 || LogPageSize < SEQUENCE_NUMBER_STRIDE) { 01768 01769 return FALSE; 01770 } 01771 01772 // 01773 // Now we check that the Log page and system page are multiples of two. 01774 // They should only have a single bit set. 01775 // 01776 01777 for (Mask = 1, BitCount = 0; Mask != 0; Mask = Mask << 1) { 01778 01779 if (Mask & LogPageSize) { 01780 01781 BitCount += 1; 01782 } 01783 } 01784 01785 // 01786 // If the bit count isn't 1, return false. 01787 // 01788 01789 if (BitCount != 1) { 01790 01791 return FALSE; 01792 } 01793 01794 // 01795 // Now do the system page size. 01796 // 01797 01798 for (Mask = 1, BitCount = 0; Mask != 0; Mask = Mask << 1) { 01799 01800 if (Mask & SystemPage) { 01801 01802 BitCount += 1; 01803 } 01804 } 01805 01806 // 01807 // If the bit count isn't 1, return false. 01808 // 01809 01810 if (BitCount != 1) { 01811 01812 return FALSE; 01813 } 01814 01815 // 01816 // Check that if the file offset isn't 0, it is the system page size. 01817 // 01818 01819 if (( FileOffset != 0 ) 01820 && ((ULONG)FileOffset != SystemPage)) { 01821 01822 return FALSE; 01823 } 01824 01825 // 01826 // We only support major version numbers 0.x and 1.x 01827 // 01828 // Version number beyond 1.0 mean the log file is packed. 01829 // 01830 01831 if (PageHeader->MajorVersion != 0 01832 && PageHeader->MajorVersion != 1) { 01833 01834 return FALSE; 01835 } 01836 01837 // 01838 // Check that the restart area offset is within the system page and that 01839 // the restart length field will fit within the system page size. 01840 // 01841 01842 if (QuadAlign( PageHeader->RestartOffset ) != PageHeader->RestartOffset 01843 || PageHeader->RestartOffset > (USHORT) PageHeader->SystemPageSize) { 01844 01845 return FALSE; 01846 } 01847 01848 // 01849 // Check that the restart offset will lie beyond the Usa Array for this page. 01850 // 01851 01852 EndOfUsa = (USHORT) (UpdateSequenceArraySize( PageHeader->SystemPageSize ) 01853 * sizeof( UPDATE_SEQUENCE_NUMBER )); 01854 01855 EndOfUsa += PageHeader->MultiSectorHeader.UpdateSequenceArrayOffset; 01856 01857 if (PageHeader->RestartOffset < EndOfUsa) { 01858 01859 return FALSE; 01860 } 01861 01862 // 01863 // Check if the log pages are packed. 01864 // 01865 01866 if (PageHeader->MajorVersion == 1 01867 && PageHeader->MinorVersion > 0) { 01868 01869 *LogPacked = TRUE; 01870 } 01871 01872 // 01873 // Otherwise the page header is valid. 01874 // 01875 01876 return TRUE; 01877 }

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
 

Definition at line 84 of file lfs/cachesup.c.

References Buffer, CcMapData(), CcPinRead(), CcUnpinData(), Dbg, DebugTrace, DebugUnwind, ExRaiseStatus(), FALSE, LFS_SIGNATURE_BAD_USA_ULONG, LfsExceptionFilter(), LfsPinOrMapData(), NT_SUCCESS, NTSTATUS(), NULL, PAGED_CODE, Status, and TRUE.

Referenced by LfsCopyReadLogRecord(), LfsFindLastLsn(), LfsFindNextLsn(), LfsFlushLfcb(), LfsInitializeLogFilePriv(), LfsPinOrMapData(), LfsPinOrMapLogRecordHeader(), LfsReadRestart(), and LfsRestartLogFile().

00098 : 00099 00100 This routine will pin or map a portion of the log file. 00101 00102 Arguments: 00103 00104 Lfcb - This is the file control block for the log file. 00105 00106 FileOffset - This is the offset of the log page to pin. 00107 00108 Length - This is the length of the data to access. 00109 00110 PinData - Boolean indicating if we are to pin or map this data. 00111 00112 AllowErrors - This boolean indicates whether we should raise on an 00113 I/O error or return on an I/O error. 00114 00115 IgnoreUsaErrors - Boolean indicating whether we will raise on Usa 00116 errors. 00117 00118 UsaError - Address to store whether the Usa had an error. 00119 00120 Buffer - This is the address to store the address of the data. 00121 00122 Bcb - This is the Bcb for this operation. 00123 00124 Return Value: 00125 00126 NTSTATUS - The result of the I/O. 00127 00128 --*/ 00129 00130 { 00131 volatile NTSTATUS Status; 00132 ULONG Signature; 00133 BOOLEAN Result = FALSE; 00134 00135 Status = STATUS_SUCCESS; 00136 00137 PAGED_CODE(); 00138 00139 DebugTrace( +1, Dbg, "LfsPinReadLogPage: Entered\n", 0 ); 00140 DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); 00141 DebugTrace( 0, Dbg, "FileOffset (Low) -> %08lx\n", FileOffset.HighPart ); 00142 DebugTrace( 0, Dbg, "FileOffset (High) -> %08lx\n", FileOffset.LowPart ); 00143 DebugTrace( 0, Dbg, "Length -> %08lx\n", Length ); 00144 DebugTrace( 0, Dbg, "PinData -> %04x\n", PinData ); 00145 DebugTrace( 0, Dbg, "AllowErrors -> %08x\n", AllowErrors ); 00146 DebugTrace( 0, Dbg, "IgnoreUsaErrors -> %04x\n", IgnoreUsaErrors ); 00147 00148 // 00149 // Use a try-finally to facilitate cleanup. 00150 // 00151 00152 try { 00153 00154 // 00155 // Use a try-except to catch cache manager errors. 00156 // 00157 00158 try { 00159 00160 // 00161 // We call the cache to perform the work. 00162 // 00163 00164 if (PinData) { 00165 00166 Result = CcPinRead( Lfcb->FileObject, 00167 (PLARGE_INTEGER)&FileOffset, 00168 Length, 00169 TRUE, 00170 Bcb, 00171 Buffer ); 00172 00173 } else { 00174 00175 Result = CcMapData( Lfcb->FileObject, 00176 (PLARGE_INTEGER)&FileOffset, 00177 Length, 00178 TRUE, 00179 Bcb, 00180 Buffer ); 00181 } 00182 00183 // 00184 // Capture the signature now while we are within the 00185 // exception filter. 00186 // 00187 00188 Signature = *((PULONG) *Buffer); 00189 00190 } except( LfsExceptionFilter( GetExceptionInformation() )) { 00191 00192 Status = GetExceptionCode(); 00193 if (Result) { 00194 CcUnpinData( *Bcb ); 00195 *Bcb = NULL; 00196 } 00197 } 00198 00199 *UsaError = FALSE; 00200 00201 // 00202 // If an error occurred, we raise the status. 00203 // 00204 00205 if (!NT_SUCCESS( Status )) { 00206 00207 if (!AllowErrors) { 00208 00209 DebugTrace( 0, Dbg, "Read on log page failed -> %08lx\n", Status ); 00210 ExRaiseStatus( Status ); 00211 } 00212 00213 // 00214 // Check that the update sequence array for this 00215 // page is valid. 00216 // 00217 00218 } else if (Signature == LFS_SIGNATURE_BAD_USA_ULONG) { 00219 00220 // 00221 // If we don't allow errors, raise an error status. 00222 // 00223 00224 if (!IgnoreUsaErrors) { 00225 00226 DebugTrace( 0, Dbg, "Usa error on log page\n", 0 ); 00227 ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); 00228 } 00229 00230 *UsaError = TRUE; 00231 } 00232 00233 } finally { 00234 00235 DebugUnwind( LfsPinOrMapData ); 00236 00237 DebugTrace( 0, Dbg, "Buffer -> %08lx\n", *Buffer ); 00238 DebugTrace( 0, Dbg, "Bcb -> %08lx\n", *Bcb ); 00239 00240 DebugTrace( -1, Dbg, "LfsPinOrMapData: Exit -> %08lx\n", Status ); 00241 } 00242 00243 return Status; 00244 }

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
 

Definition at line 248 of file lfs/cachesup.c.

References Add2Ptr, Dbg, DebugTrace, FALSE, LfsLsnToPageOffset, LfsPinOrMapData(), LfsTruncateLsnToLogPage, PAGED_CODE, PLFS_RECORD_HEADER, and PLFS_RECORD_PAGE_HEADER.

Referenced by LfsFindClientNextLsn(), LfsFindLogRecord(), LfsReadRestartArea(), and LfsSearchForwardByClient().

00260 : 00261 00262 This routine will pin or map a log record for read access. 00263 00264 Arguments: 00265 00266 Lfcb - This is the file control block for the log file. 00267 00268 Lsn - This is the Lsn whose header should be pinned. 00269 00270 PinData - Boolean indicating if we are to pin or map this data. 00271 00272 IgnoreUsaErrors - Boolean indicating whether we will raise on Usa 00273 errors. 00274 00275 UsaError - Address to store whether the Usa had an error. 00276 00277 RecordHeader - This is the address to store the address of the pinned data. 00278 00279 Bcb - This is the Bcb for this pin operation. 00280 00281 Return Value: 00282 00283 None. 00284 00285 --*/ 00286 00287 { 00288 PLFS_RECORD_PAGE_HEADER LogPageHeader; 00289 LONGLONG LogPage; 00290 ULONG PageOffset; 00291 00292 PAGED_CODE(); 00293 00294 DebugTrace( +1, Dbg, "LfsPinOrMapLogRecordHeader: Entered\n", 0 ); 00295 DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); 00296 DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn.HighPart ); 00297 DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn.LowPart ); 00298 DebugTrace( 0, Dbg, "PinData -> %04x\n", PinData ); 00299 DebugTrace( 0, Dbg, "IgnoreUsaErrors -> %04x\n", IgnoreUsaErrors ); 00300 00301 // 00302 // Compute the log page and the offset of the log record header 00303 // in the log page. 00304 // 00305 00306 LfsTruncateLsnToLogPage( Lfcb, Lsn, &LogPage ); 00307 PageOffset = LfsLsnToPageOffset( Lfcb, Lsn ); 00308 00309 // 00310 // Call the cache manager to pin the page. 00311 // 00312 00313 LfsPinOrMapData( Lfcb, 00314 LogPage, 00315 (ULONG)Lfcb->LogPageSize, 00316 PinData, 00317 FALSE, 00318 IgnoreUsaErrors, 00319 UsaError, 00320 (PVOID *) &LogPageHeader, 00321 Bcb ); 00322 00323 // 00324 // The actual offset we need is at PageOffset from the start of the page. 00325 // 00326 00327 *RecordHeader = Add2Ptr( LogPageHeader, PageOffset, PLFS_RECORD_HEADER ); 00328 00329 DebugTrace( 0, Dbg, "Record Header -> %08lx\n", *RecordHeader ); 00330 DebugTrace( 0, Dbg, "Bcb -> %08lx\n", *Bcb ); 00331 00332 DebugTrace( -1, Dbg, "LfsPinOrMapLogRecordHeader: Exit\n", 0 ); 00333 00334 return; 00335 }

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
 

Definition at line 1402 of file lfs/cachesup.c.

References Add2Ptr, CcUnpinData(), _LFS_RESTART_AREA::ClientInUseList, _LFS_RESTART_AREA::CurrentLsn, Dbg, DebugTrace, DebugUnwind, FALSE, LFS_NO_CLIENT, LFS_SIGNATURE_MODIFIED_ULONG, LFS_SIGNATURE_RECORD_PAGE_ULONG, LFS_SIGNATURE_RESTART_PAGE_ULONG, LFS_SIGNATURE_UNINITIALIZED_ULONG, LfsIsClientAreaValid(), LfsIsRestartAreaValid(), LfsIsRestartPageHeaderValid(), LfsPinOrMapData(), LfsReadRestart(), NT_SUCCESS, NTSTATUS(), NULL, PAGED_CODE, PLSN, SEQUENCE_NUMBER_STRIDE, Status, and TRUE.

Referenced by LfsReadRestart(), and LfsRestartLogFile().

01418 : 01419 01420 This routine will walk through 512 blocks of the file looking for a 01421 valid restart page header. It will stop the first time we find 01422 a valid page header. 01423 01424 Arguments: 01425 01426 Lfcb - This is the Lfcb for the log file. 01427 01428 FileSize - Size in bytes for the log file. 01429 01430 FirstRestart - Indicates if we are looking for the first valid 01431 restart area. 01432 01433 RestartPageOffset - This is the location to store the offset in the 01434 file where the log page was found. 01435 01436 RestartPage - This is the location to store the address of the 01437 pinned restart page. 01438 01439 RestartPageBcb - This is the location to store the Bcb for this 01440 cache pin operation. 01441 01442 ChkdskWasRun - Address to store whether checkdisk was run on this volume. 01443 01444 ValidPage - Address to store whether there was valid data on this page. 01445 01446 UninitializedFile - Address to store whether this is an uninitialized 01447 log file. Return value only valid if for the first restart area. 01448 01449 LogPacked - Address to store whether the log file is packed. 01450 01451 LastLsn - Address to store the last Lsn for this restart page. It will be the 01452 chkdsk value if checkdisk was run. Otherwise it is the LastFlushedLsn 01453 for this restart page. 01454 01455 Return Value: 01456 01457 BOOLEAN - TRUE if a restart area was found, FALSE otherwise. 01458 01459 --*/ 01460 01461 { 01462 ULONG FileOffsetIncrement; 01463 LONGLONG FileOffset; 01464 01465 PLFS_RESTART_AREA RestartArea; 01466 01467 NTSTATUS Status; 01468 01469 PLFS_RESTART_PAGE_HEADER ThisPage; 01470 PBCB ThisPageBcb = NULL; 01471 01472 BOOLEAN FoundRestart = FALSE; 01473 01474 PAGED_CODE(); 01475 01476 DebugTrace( +1, Dbg, "LfsReadRestart: Entered\n", 0 ); 01477 DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); 01478 01479 // 01480 // Use a try-finally to facilitate cleanup. 01481 // 01482 01483 *UninitializedFile = TRUE; 01484 *ValidPage = FALSE; 01485 *ChkdskWasRun = FALSE; 01486 *LogPacked = FALSE; 01487 01488 try { 01489 01490 // 01491 // Determine which restart area we are looking for. 01492 // 01493 01494 if (FirstRestart) { 01495 01496 FileOffset = 0; 01497 FileOffsetIncrement = SEQUENCE_NUMBER_STRIDE; 01498 01499 } else { 01500 01501 FileOffset = SEQUENCE_NUMBER_STRIDE; 01502 FileOffsetIncrement = 0; 01503 } 01504 01505 // 01506 // We loop continuously until we succeed, pin a log record page 01507 // or exhaust the number of possible tries. 01508 // 01509 01510 while ( FileOffset < FileSize ) { 01511 01512 ULONG Signature; 01513 BOOLEAN UsaError; 01514 01515 if (ThisPageBcb != NULL) { 01516 01517 CcUnpinData( ThisPageBcb ); 01518 ThisPageBcb = NULL; 01519 } 01520 01521 // 01522 // Attempt to pin a page header at the current offset. 01523 // 01524 01525 Status = LfsPinOrMapData( Lfcb, 01526 FileOffset, 01527 SEQUENCE_NUMBER_STRIDE, 01528 TRUE, 01529 TRUE, 01530 TRUE, 01531 &UsaError, 01532 (PVOID *)&ThisPage, 01533 &ThisPageBcb ); 01534 01535 // 01536 // 01537 // If we succeeded, we look at the 4 byte signature. 01538 // 01539 01540 if (NT_SUCCESS( Status )) { 01541 01542 Signature = *((PULONG) &ThisPage->MultiSectorHeader.Signature); 01543 01544 // 01545 // If the signature is a log record page, we will exit. 01546 // 01547 01548 if (Signature == LFS_SIGNATURE_RECORD_PAGE_ULONG) { 01549 01550 *UninitializedFile = FALSE; 01551 break; 01552 } 01553 01554 // 01555 // Continue analyzing the page if the signature is chkdsk or 01556 // a restart page. 01557 // 01558 01559 if (Signature == LFS_SIGNATURE_MODIFIED_ULONG 01560 || Signature == LFS_SIGNATURE_RESTART_PAGE_ULONG) { 01561 01562 *UninitializedFile = FALSE; 01563 01564 // 01565 // Remember where we found this page. 01566 // 01567 01568 *RestartPageOffset = FileOffset; 01569 01570 // 01571 // Let's check the restart area if this is a valid page. 01572 // 01573 01574 if (LfsIsRestartPageHeaderValid( FileOffset, 01575 ThisPage, 01576 LogPacked ) 01577 01578 && LfsIsRestartAreaValid( ThisPage, *LogPacked )) { 01579 01580 // 01581 // We have a valid restart page header and restart area. 01582 // If chkdsk was run or we have no clients then 01583 // we have no more checking to do. 01584 // 01585 01586 RestartArea = Add2Ptr( ThisPage, 01587 ThisPage->RestartOffset, 01588 PLFS_RESTART_AREA ); 01589 01590 if (Signature == LFS_SIGNATURE_RESTART_PAGE_ULONG 01591 && RestartArea->ClientInUseList != LFS_NO_CLIENT) { 01592 01593 // 01594 // Pin the entire restart area if we didn't have an earlier 01595 // 01596 01597 CcUnpinData( ThisPageBcb ); 01598 ThisPageBcb = NULL; 01599 01600 Status = LfsPinOrMapData( Lfcb, 01601 FileOffset, 01602 ThisPage->SystemPageSize, 01603 TRUE, 01604 TRUE, 01605 TRUE, 01606 &UsaError, 01607 (PVOID *)&ThisPage, 01608 &ThisPageBcb ); 01609 01610 if (NT_SUCCESS( Status ) 01611 && LfsIsClientAreaValid( ThisPage, *LogPacked, UsaError )) { 01612 01613 *ValidPage = TRUE; 01614 01615 RestartArea = Add2Ptr( ThisPage, 01616 ThisPage->RestartOffset, 01617 PLFS_RESTART_AREA ); 01618 } 01619 01620 } else { 01621 01622 *ValidPage = TRUE; 01623 } 01624 } 01625 01626 // 01627 // If chkdsk was run then update the caller's values and return. 01628 // 01629 01630 if (Signature == LFS_SIGNATURE_MODIFIED_ULONG) { 01631 01632 *ChkdskWasRun = TRUE; 01633 01634 *LastLsn = ThisPage->ChkDskLsn; 01635 01636 FoundRestart = TRUE; 01637 01638 *RestartPageBcb = ThisPageBcb; 01639 *RestartPage = ThisPage; 01640 01641 ThisPageBcb = NULL; 01642 break; 01643 } 01644 01645 // 01646 // If we have a valid page then copy the values we need from it. 01647 // 01648 01649 if (*ValidPage) { 01650 01651 *LastLsn = RestartArea->CurrentLsn; 01652 01653 FoundRestart = TRUE; 01654 01655 *RestartPageBcb = ThisPageBcb; 01656 *RestartPage = ThisPage; 01657 01658 ThisPageBcb = NULL; 01659 break; 01660 } 01661 01662 // 01663 // Remember if the signature does not indicate uninitialized file. 01664 // 01665 01666 } else if (Signature != LFS_SIGNATURE_UNINITIALIZED_ULONG) { 01667 01668 *UninitializedFile = FALSE; 01669 } 01670 } 01671 01672 // 01673 // Move to the next possible log page. 01674 // 01675 01676 FileOffset = FileOffset << 1; 01677 01678 (ULONG)FileOffset += FileOffsetIncrement; 01679 01680 FileOffsetIncrement = 0; 01681 } 01682 01683 } finally { 01684 01685 DebugUnwind( LfsReadRestart ); 01686 01687 // 01688 // Unpin the log pages if pinned. 01689 // 01690 01691 if (ThisPageBcb != NULL) { 01692 01693 CcUnpinData( ThisPageBcb ); 01694 } 01695 01696 DebugTrace( 0, Dbg, "RestartPageAddress (Low) -> %08lx\n", RestartPageAddress->LowPart ); 01697 DebugTrace( 0, Dbg, "RestartPageAddress (High) -> %08lx\n", RestartPageAddress->HighPart ); 01698 DebugTrace( 0, Dbg, "FirstRestartPage -> %08lx\n", *FirstRestartPage ); 01699 DebugTrace( -1, Dbg, "LfsReadRestart: Exit\n", 0 ); 01700 } 01701 01702 return FoundRestart; 01703 }


Variable Documentation

USHORT LfsUsaSeqNumber
 

Definition at line 35 of file lfs/cachesup.c.

Referenced by LfsFlushLfcb(), and LfsInitializeLogFileService().


Generated on Sat May 15 19:42:59 2004 for test by doxygen 1.3.7