Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4363 lines
127 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. Registry.c
  5. Abstract:
  6. This module implements the routines which clients use to register
  7. themselves with the Log File Service.
  8. Author:
  9. Brian Andrew [BrianAn] 20-June-1991
  10. Revision History:
  11. --*/
  12. #include "lfsprocs.h"
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_REGISTRY)
  17. #define MODULE_POOL_TAG ('rsfL')
  18. PLFCB
  19. LfsRestartLogFile (
  20. IN PFILE_OBJECT LogFile,
  21. IN USHORT MaximumClients,
  22. IN ULONG LogPageSize OPTIONAL,
  23. IN LONGLONG FileSize,
  24. IN OUT PLFS_INFO LfsInfo,
  25. OUT PLFS_WRITE_DATA WriteData
  26. );
  27. VOID
  28. LfsNormalizeBasicLogFile (
  29. IN OUT PLONGLONG FileSize,
  30. IN OUT PULONG LogPageSize,
  31. IN OUT PUSHORT LogClients,
  32. IN BOOLEAN UseDefaultLogPage
  33. );
  34. VOID
  35. LfsUpdateLfcbFromPgHeader (
  36. IN PLFCB Lfcb,
  37. IN ULONG LogPageSize,
  38. IN SHORT MajorVersion,
  39. IN SHORT MinorVersion,
  40. IN BOOLEAN PackLog
  41. );
  42. VOID
  43. LfsUpdateLfcbFromNoRestart (
  44. IN PLFCB Lfcb,
  45. IN LONGLONG FileSize,
  46. IN LSN LastLsn,
  47. IN ULONG LogClients,
  48. IN ULONG OpenLogCount,
  49. IN BOOLEAN LogFileWrapped,
  50. IN BOOLEAN UseMultiplePageIo
  51. );
  52. VOID
  53. LfsUpdateLfcbFromRestart (
  54. IN PLFCB Lfcb,
  55. IN LONGLONG FileSize,
  56. IN PLFS_RESTART_AREA RestartArea,
  57. IN USHORT RestartOffset
  58. );
  59. VOID
  60. LfsUpdateRestartAreaFromLfcb (
  61. IN PLFCB Lfcb,
  62. IN PLFS_RESTART_AREA RestartArea
  63. );
  64. VOID
  65. LfsInitializeLogFilePriv (
  66. IN PLFCB Lfcb,
  67. IN BOOLEAN ForceRestartToDisk,
  68. IN ULONG RestartAreaSize,
  69. IN LONGLONG StartOffsetForClear,
  70. IN BOOLEAN ClearLogFile
  71. );
  72. VOID
  73. LfsFindLastLsn (
  74. IN OUT PLFCB Lfcb
  75. );
  76. VOID
  77. LfsFlushLogPage (
  78. IN PLFCB Lfcb,
  79. PVOID LogPage,
  80. IN LONGLONG FileOffset,
  81. OUT PBCB *Bcb
  82. );
  83. VOID
  84. LfsRemoveClientFromList (
  85. IN PLFS_CLIENT_RECORD ClientArray,
  86. IN PLFS_CLIENT_RECORD ClientRecord,
  87. IN PUSHORT ListHead
  88. );
  89. VOID
  90. LfsAddClientToList (
  91. IN PLFS_CLIENT_RECORD ClientArray,
  92. IN USHORT ClientIndex,
  93. IN PUSHORT ListHead
  94. );
  95. #ifdef ALLOC_PRAGMA
  96. #pragma alloc_text(PAGE, LfsAddClientToList)
  97. #pragma alloc_text(PAGE, LfsCheckSubsequentLogPage)
  98. #pragma alloc_text(PAGE, LfsCloseLogFile)
  99. #pragma alloc_text(PAGE, LfsDeleteLogHandle)
  100. #pragma alloc_text(PAGE, LfsFindLastLsn)
  101. #pragma alloc_text(PAGE, LfsFlushLogPage)
  102. #pragma alloc_text(PAGE, LfsInitializeLogFilePriv)
  103. #pragma alloc_text(PAGE, LfsNormalizeBasicLogFile)
  104. #pragma alloc_text(PAGE, LfsOpenLogFile)
  105. #pragma alloc_text(PAGE, LfsReadLogFileInformation)
  106. #pragma alloc_text(PAGE, LfsRemoveClientFromList)
  107. #pragma alloc_text(PAGE, LfsResetUndoTotal)
  108. #pragma alloc_text(PAGE, LfsRestartLogFile)
  109. #pragma alloc_text(PAGE, LfsUpdateLfcbFromRestart)
  110. #pragma alloc_text(PAGE, LfsUpdateLfcbFromNoRestart)
  111. #pragma alloc_text(PAGE, LfsUpdateLfcbFromPgHeader)
  112. #pragma alloc_text(PAGE, LfsUpdateRestartAreaFromLfcb)
  113. #pragma alloc_text(PAGE, LfsVerifyLogFile)
  114. #endif
  115. ULONG
  116. LfsOpenLogFile (
  117. IN PFILE_OBJECT LogFile,
  118. IN UNICODE_STRING ClientName,
  119. IN USHORT MaximumClients,
  120. IN ULONG LogPageSize OPTIONAL,
  121. IN LONGLONG FileSize,
  122. IN OUT PLFS_INFO LfsInfo,
  123. OUT PLFS_LOG_HANDLE LogHandle,
  124. OUT PLFS_WRITE_DATA WriteData
  125. )
  126. /*++
  127. Routine Description:
  128. This routine is called when a client wishes to register with logging
  129. service. This can be a reregistration (i.e. restart after a crash)
  130. or an initial registration. There can be no other active clients
  131. with the same name. The Log Handle returned is then used for any
  132. subsequent access by this client.
  133. If an Lfs restart has not been done on the log file, it will be done
  134. at this time.
  135. Arguments:
  136. LogFile - A file object for a file previously initialized for use
  137. as a log file.
  138. ClientName - This unicode string is used to uniquely identify clients
  139. of the logging service. A case-sensitive comparison is
  140. used to check this name against active clients of the
  141. log file.
  142. MaximumClients - The maximum number of clients if the log file has
  143. never been initialized.
  144. LogPageSize - This is the recommeded size for the log page.
  145. FileSize - This is the size of the log file.
  146. LfsInfo - On entry, indicates the log file state the user may
  147. know about. On exit, indicates the log file state that Lfs
  148. knows about. This is a conduit for Lfs to communicate with its
  149. clients.
  150. LogHandle - The address to store the identifier the logging service
  151. will use to identify this client in all other Lfs calls.
  152. WriteData - Pointer to WRITE_DATA in caller's data structure.
  153. Return Value:
  154. ULONG - Amount to add to reservation value for header for log record.
  155. --*/
  156. {
  157. PLIST_ENTRY Link;
  158. PLFCB ThisLfcb = NULL;
  159. PLFCB NewLfcb = NULL;
  160. USHORT ThisClient;
  161. PLFS_CLIENT_RECORD ClientRecord;
  162. PLCH Lch = NULL;
  163. ULONG ReservedHeader;
  164. PAGED_CODE();
  165. DebugTrace( +1, Dbg, "LfsOpenLogFile: Entered\n", 0 );
  166. DebugTrace( 0, Dbg, "Log File -> %08lx\n", LogFile );
  167. DebugTrace( 0, Dbg, "Client Name -> %08lx\n", &ClientName );
  168. DebugTrace( 0, Dbg, "Maximum Clients -> %04x\n", MaximumClients );
  169. DebugTrace( 0, Dbg, "Log Page Size -> %08lx\n", LogPageSize );
  170. DebugTrace( 0, Dbg, "File Size (Low) -> %08lx\n", FileSize.LowPart );
  171. DebugTrace( 0, Dbg, "File Size (High) -> %08lx\n", FileSize.HighPart );
  172. //
  173. // Check that the client name length is a legal length.
  174. //
  175. if (ClientName.Length > LFS_CLIENT_NAME_MAX) {
  176. DebugTrace( 0, Dbg, "Illegal name length for client\n", 0 );
  177. DebugTrace( -1, Dbg, "LfsOpenLogFile: Exit\n", 0 );
  178. ExRaiseStatus( STATUS_INVALID_PARAMETER );
  179. }
  180. //
  181. // Aqcuire the global data.
  182. //
  183. LfsAcquireLfsData();
  184. //
  185. // Use a try-finally to facilitate cleanup.
  186. //
  187. try {
  188. //
  189. // Walk through the list searching for this file object.
  190. //
  191. Link = LfsData.LfcbLinks.Flink;
  192. while (Link != &LfsData.LfcbLinks) {
  193. ThisLfcb = CONTAINING_RECORD( Link, LFCB, LfcbLinks );
  194. if (ThisLfcb->FileObject == LogFile) {
  195. DebugTrace( 0, Dbg, "Found matching log file\n", 0 );
  196. break;
  197. }
  198. Link = Link->Flink;
  199. }
  200. //
  201. // If the log file doesn't exist, create an Lfcb and perform an
  202. // Lfs restart.
  203. //
  204. if (Link == &LfsData.LfcbLinks) {
  205. //
  206. // Call the Cache Manager to disable read ahead and write behind;
  207. // we flush the log file explicitly.
  208. //
  209. CcSetAdditionalCacheAttributes( LogFile, TRUE, TRUE );
  210. //
  211. // Perform Lfs restart on this file object.
  212. //
  213. ThisLfcb = NewLfcb = LfsRestartLogFile( LogFile,
  214. MaximumClients,
  215. LogPageSize,
  216. FileSize,
  217. LfsInfo,
  218. WriteData );
  219. //
  220. // Insert this Lfcb into the global list.
  221. //
  222. InsertHeadList( &LfsData.LfcbLinks, &ThisLfcb->LfcbLinks );
  223. }
  224. //
  225. // At this point we have the log file control block for the file
  226. // object given us. We first check whether the log file is fatally
  227. // corrupt.
  228. //
  229. if (FlagOn( ThisLfcb->Flags, LFCB_LOG_FILE_CORRUPT )) {
  230. //
  231. // We leave the in-memory data alone and raise an error if
  232. // anyone attempts to access this file.
  233. //
  234. DebugTrace( 0, Dbg, "The Lfcb is corrupt\n", 0 );
  235. ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
  236. }
  237. //
  238. // Search through and look for a client match.
  239. //
  240. ThisClient = ThisLfcb->RestartArea->ClientInUseList;
  241. while (ThisClient != LFS_NO_CLIENT) {
  242. ClientRecord = ThisLfcb->ClientArray + ThisClient;
  243. if (ClientRecord->ClientNameLength == (ULONG) ClientName.Length
  244. && RtlCompareMemory( ClientRecord->ClientName,
  245. ClientName.Buffer,
  246. ClientName.Length ) == (ULONG) ClientName.Length) {
  247. DebugTrace( 0, Dbg, "Matching client name found\n", 0 );
  248. break;
  249. }
  250. ThisClient = ClientRecord->NextClient;
  251. }
  252. //
  253. // Allocate an Lch structure and link it into the Lfcb.
  254. //
  255. LfsAllocateLch( &Lch );
  256. InsertTailList( &ThisLfcb->LchLinks, &Lch->LchLinks );
  257. //
  258. // Initialize the client handle with the data from the Lfcb.
  259. //
  260. Lch->Lfcb = ThisLfcb;
  261. Lch->Sync = ThisLfcb->Sync;
  262. Lch->Sync->UserCount += 1;
  263. //
  264. // If a match isn't found, take a client block off the free list
  265. // if available.
  266. //
  267. if (ThisClient == LFS_NO_CLIENT) {
  268. //
  269. // Raise an error status if out of client blocks.
  270. //
  271. ThisClient = ThisLfcb->RestartArea->ClientFreeList;
  272. if (ThisClient == LFS_NO_CLIENT) {
  273. DebugTrace( 0, Dbg, "No free client records available\n", 0 );
  274. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  275. }
  276. //
  277. // Initialize the client block.
  278. //
  279. ClientRecord = ThisLfcb->ClientArray + ThisClient;
  280. LfsRemoveClientFromList( ThisLfcb->ClientArray,
  281. ClientRecord,
  282. &ThisLfcb->RestartArea->ClientFreeList );
  283. ClientRecord->ClientRestartLsn = LfsZeroLsn;
  284. ClientRecord->OldestLsn = ThisLfcb->OldestLsn;
  285. ClientRecord->ClientNameLength = ClientName.Length;
  286. RtlCopyMemory( ClientRecord->ClientName,
  287. ClientName.Buffer,
  288. ClientName.Length );
  289. //
  290. // Add it to the in use list.
  291. //
  292. LfsAddClientToList( ThisLfcb->ClientArray,
  293. ThisClient,
  294. &ThisLfcb->RestartArea->ClientInUseList );
  295. }
  296. //
  297. // Update the client handle with the client block information.
  298. //
  299. Lch->ClientId.SeqNumber = ClientRecord->SeqNumber;
  300. Lch->ClientId.ClientIndex = ThisClient;
  301. Lch->ClientArrayByteOffset = PtrOffset( ThisLfcb->ClientArray,
  302. ClientRecord );
  303. *LogHandle = (LFS_LOG_HANDLE) Lch;
  304. } finally {
  305. DebugUnwind( LfsOpenLogFile );
  306. //
  307. // If the Lfcb has been acquired, we release it now.
  308. //
  309. if (ThisLfcb != NULL) {
  310. //
  311. // Pass information back to our caller for the number
  312. // of bytes to add to the reserved amount for a
  313. // log header.
  314. //
  315. ReservedHeader = ThisLfcb->RecordHeaderLength;
  316. if (FlagOn( ThisLfcb->Flags, LFCB_PACK_LOG )) {
  317. ReservedHeader *= 2;
  318. }
  319. LfsReleaseLfcb( ThisLfcb );
  320. }
  321. //
  322. // If there is an error then deallocate the Lch and any new Lfcb.
  323. //
  324. if (AbnormalTermination()) {
  325. if (Lch != NULL) {
  326. LfsDeallocateLch( Lch );
  327. ThisLfcb->Sync->UserCount -= 1;
  328. }
  329. if (NewLfcb != NULL) {
  330. LfsDeallocateLfcb( NewLfcb, TRUE );
  331. }
  332. }
  333. //
  334. // Always free the global.
  335. //
  336. LfsReleaseLfsData();
  337. DebugTrace( 0, Dbg, "Log Handle -> %08ln\n", *LogHandle );
  338. DebugTrace( -1, Dbg, "LfsOpenLogFile: Exit\n", 0 );
  339. }
  340. return ReservedHeader;
  341. }
  342. VOID
  343. LfsCloseLogFile (
  344. IN LFS_LOG_HANDLE LogHandle
  345. )
  346. /*++
  347. Routine Description:
  348. This routine is called when a client detaches itself from the log
  349. file. On return, all prior references to this client in the log
  350. file are inaccessible.
  351. Arguments:
  352. LogHandle - Pointer to private Lfs structure used to identify this
  353. client.
  354. Return Value:
  355. None
  356. --*/
  357. {
  358. volatile NTSTATUS Status = STATUS_SUCCESS;
  359. PLCH Lch;
  360. PLFCB Lfcb;
  361. USHORT ClientIndex;
  362. PLFS_CLIENT_RECORD ClientRecord;
  363. LFS_WAITER LfsWaiter;
  364. BOOLEAN FlushRestart;
  365. BOOLEAN ExitLoop;
  366. PAGED_CODE();
  367. DebugTrace( +1, Dbg, "LfsCloseLogFile: Entered\n", 0 );
  368. DebugTrace( 0, Dbg, "LogHandle -> %08lx\n", LogHandle );
  369. Lch = (PLCH) LogHandle;
  370. //
  371. // Enclose this in a loop. We will loop as long as there are waiters or there is an IO
  372. // in progress.
  373. //
  374. while (TRUE) {
  375. //
  376. // Always assume we exit the loop.
  377. //
  378. ExitLoop = TRUE;
  379. //
  380. // Check that the structure is a valid log handle structure.
  381. //
  382. LfsValidateLch( Lch );
  383. //
  384. // Protect this entry point with a try-except.
  385. //
  386. try {
  387. //
  388. // Use a try-finally to facilitate cleanup.
  389. //
  390. //
  391. // Acquire the global data block and the log file control block.
  392. //
  393. LfsAcquireLfsData();
  394. try {
  395. PLBCB ThisLbcb;
  396. LfsAcquireLchExclusive( Lch );
  397. Lfcb = Lch->Lfcb;
  398. //
  399. // If the Log file has been closed then return immediately.
  400. //
  401. if (Lfcb == NULL) {
  402. try_return( NOTHING );
  403. }
  404. //
  405. // Check that there are no waiters or IO in progress before proceeding.
  406. //
  407. if ((Lfcb->Waiters != 0) ||
  408. (Lfcb->Sync->LfsIoState != LfsNoIoInProgress)) {
  409. //
  410. // setup notification for the wait completion
  411. //
  412. KeInitializeEvent( &LfsWaiter.Event, SynchronizationEvent, FALSE );
  413. LfsWaiter.Lsn.QuadPart = MAXLONGLONG;
  414. InsertTailList( &Lfcb->WaiterList, &LfsWaiter.Waiters );
  415. ExitLoop = FALSE;
  416. Lfcb->Waiters += 1;
  417. try_return( NOTHING );
  418. }
  419. //
  420. // Check that the client Id is valid.
  421. //
  422. LfsValidateClientId( Lfcb, Lch );
  423. ClientRecord = Add2Ptr( Lfcb->ClientArray,
  424. Lch->ClientArrayByteOffset,
  425. PLFS_CLIENT_RECORD );
  426. //
  427. // Remember if this client wrote a restart area.
  428. //
  429. FlushRestart = (BOOLEAN) ( LfsZeroLsn.QuadPart != ClientRecord->ClientRestartLsn.QuadPart );
  430. //
  431. // Set the flag to indicate we are at the final close.
  432. //
  433. SetFlag( Lfcb->Flags, LFCB_FINAL_SHUTDOWN );
  434. //
  435. // Walk through the active queue and remove any Lbcb's with
  436. // data from that queue. That will allow them to get out to disk.
  437. //
  438. while (!IsListEmpty( &Lfcb->LbcbActive )) {
  439. ThisLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink,
  440. LBCB,
  441. ActiveLinks );
  442. RemoveEntryList( &ThisLbcb->ActiveLinks );
  443. ClearFlag( ThisLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE );
  444. //
  445. // If this page has some new entries, allow it to
  446. // be flushed to disk elsewhere. Otherwise deallocate it
  447. // here. We set LBCB_NOT_EMPTY when we first put data into
  448. // the page and add it to the workqueue.
  449. //
  450. if (!FlagOn( ThisLbcb->LbcbFlags, LBCB_NOT_EMPTY )) {
  451. ASSERT( NULL == ThisLbcb->WorkqueLinks.Flink );
  452. if (ThisLbcb->LogPageBcb != NULL) {
  453. CcUnpinDataForThread( ThisLbcb->LogPageBcb,
  454. ThisLbcb->ResourceThread );
  455. }
  456. LfsDeallocateLbcb( Lfcb, ThisLbcb );
  457. }
  458. }
  459. //
  460. // It's possible that we have the two restart areas in the workque.
  461. // They can be removed and the memory deallocated if we have no
  462. // more clients.
  463. //
  464. // We skip this action if the there is Io in progress or the user
  465. // had a restart area.
  466. //
  467. if ((Lfcb->Sync->LfsIoState == LfsNoIoInProgress) && !FlushRestart) {
  468. PLIST_ENTRY Links;
  469. //
  470. // Now walk through the workque list looking for a non-restart
  471. // entry.
  472. //
  473. Links = Lfcb->LbcbWorkque.Flink;
  474. //
  475. // We don't expect to see any workitems queued on readonly volumes.
  476. //
  477. ASSERT( !BooleanFlagOn( Lfcb->Flags, LFCB_READ_ONLY ) ||
  478. (Links == &Lfcb->LbcbWorkque) );
  479. while (Links != &Lfcb->LbcbWorkque) {
  480. ThisLbcb = CONTAINING_RECORD( Links,
  481. LBCB,
  482. WorkqueLinks );
  483. //
  484. // If this is not a restart area, we exit and remember that
  485. // we need to flush the restart areas.
  486. //
  487. if (!LfsLbcbIsRestart( ThisLbcb )) {
  488. FlushRestart = TRUE;
  489. break;
  490. }
  491. Links = Links->Flink;
  492. }
  493. //
  494. // If we are still not to flush the restart areas remove
  495. // all of the restart areas from the queue.
  496. //
  497. if (!FlushRestart) {
  498. while (!IsListEmpty( &Lfcb->LbcbWorkque)) {
  499. ThisLbcb = CONTAINING_RECORD( Lfcb->LbcbWorkque.Blink,
  500. LBCB,
  501. WorkqueLinks );
  502. RemoveEntryList( &ThisLbcb->WorkqueLinks );
  503. LfsDeallocateLbcb( Lfcb, ThisLbcb );
  504. }
  505. }
  506. } else {
  507. FlushRestart = TRUE;
  508. }
  509. //
  510. // Flush the new restart area if we need to.
  511. //
  512. if (FlushRestart && (!FlagOn( Lfcb->Flags, LFCB_READ_ONLY ))) {
  513. #ifdef BENL_DBG
  514. KdPrint(( "Set clean flag lfcb %x\n", Lfcb ));
  515. #endif
  516. SetFlag( Lfcb->RestartArea->Flags, LFS_CLEAN_SHUTDOWN );
  517. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, FALSE );
  518. LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, TRUE );
  519. }
  520. #ifdef SUPW_DBG
  521. if (FlushRestart && FlagOn( Lfcb->Flags, LFCB_READ_ONLY )) {
  522. DbgPrint("INFO: Not writing restart areas in CloseLog for READONLY lfcb %8lx (ok)\n", Lfcb);
  523. }
  524. #endif
  525. //
  526. // Clear the Lfcb pointer in the client handle.
  527. //
  528. Lch->Lfcb = NULL;
  529. RemoveEntryList( &Lch->LchLinks );
  530. //
  531. // If there are no active clients, we can remove this log file
  532. // control block from the active queue.
  533. //
  534. RemoveEntryList( &Lfcb->LfcbLinks );
  535. LfsDeallocateLfcb( Lfcb, FALSE );
  536. try_exit: NOTHING;
  537. } finally {
  538. DebugUnwind( LfsCloseLogFile );
  539. //
  540. // Release the log file control block if held.
  541. //
  542. LfsReleaseLch( Lch );
  543. //
  544. // Release the global data block if held.
  545. //
  546. LfsReleaseLfsData();
  547. DebugTrace( -1, Dbg, "LfsCloseLogFile: Exit\n", 0 );
  548. }
  549. } except (LfsExceptionFilter( GetExceptionInformation() )) {
  550. Status = GetExceptionCode();
  551. }
  552. //
  553. // Test if we want to exit the loop now.
  554. //
  555. if (ExitLoop) { break; }
  556. //
  557. // Wait for the io to complete.
  558. //
  559. KeWaitForSingleObject( &LfsWaiter.Event,
  560. Executive,
  561. KernelMode,
  562. FALSE,
  563. NULL );
  564. LfsAcquireLfcbExclusive( Lfcb );
  565. Lfcb->Waiters -= 1;
  566. LfsReleaseLfcb( Lfcb );
  567. }
  568. //
  569. // We always let this operation succeed.
  570. //
  571. return;
  572. }
  573. VOID
  574. LfsDeleteLogHandle (
  575. IN LFS_LOG_HANDLE LogHandle
  576. )
  577. /*++
  578. Routine Description:
  579. This routine is called when a client is tearing down the last of
  580. his volume structures. There will be no more references to this
  581. handle. If it is the last handle for the log file then we will
  582. deallocate the Sync structure as well.
  583. Arguments:
  584. LogHandle - Pointer to private Lfs structure used to identify this
  585. client.
  586. Return Value:
  587. None
  588. --*/
  589. {
  590. PLCH Lch;
  591. PAGED_CODE();
  592. //
  593. // If the log handle is null then return immediately.
  594. //
  595. Lch = (PLCH) LogHandle;
  596. if ((Lch == NULL) ||
  597. (Lch->NodeTypeCode != LFS_NTC_LCH)) {
  598. return;
  599. }
  600. //
  601. // Ignore all errors from now on.
  602. //
  603. try {
  604. LfsAcquireLchExclusive( Lch );
  605. Lch->Sync->UserCount -= 1;
  606. //
  607. // If we are the last user then deallocate the sync structure.
  608. //
  609. if (Lch->Sync->UserCount == 0) {
  610. ExDeleteResourceLite( &Lch->Sync->Resource );
  611. ExFreePool( Lch->Sync );
  612. Lch->Sync = NULL;
  613. if (Lch->Lfcb) {
  614. Lch->Lfcb->Sync = NULL;
  615. }
  616. } else {
  617. LfsReleaseLch( Lch );
  618. }
  619. LfsDeallocateLch( Lch );
  620. } except (LfsExceptionFilter( GetExceptionInformation() )) {
  621. NOTHING;
  622. }
  623. return;
  624. }
  625. VOID
  626. LfsReadLogFileInformation (
  627. IN LFS_LOG_HANDLE LogHandle,
  628. IN PLOG_FILE_INFORMATION Buffer,
  629. IN OUT PULONG Length
  630. )
  631. /*++
  632. Routine Description:
  633. This routine returns information about the current state of the log
  634. file, primarily to aid the client perform its checkpoint processing.
  635. Arguments:
  636. LogHandle - Pointer to private Lfs structure used to identify this
  637. client.
  638. Buffer - Pointer to buffer to return the log file information.
  639. Length - On input this is the length of the user's buffer. On output,
  640. it is the amount of data stored by the Lfs in the buffer.
  641. Return Value:
  642. None
  643. --*/
  644. {
  645. PLCH Lch;
  646. PLFCB Lfcb;
  647. PAGED_CODE();
  648. DebugTrace( +1, Dbg, "LfsReadLogFileInformation: Entered\n", 0 );
  649. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  650. DebugTrace( 0, Dbg, "Buffer -> %08lx\n", Buffer );
  651. DebugTrace( 0, Dbg, "Length -> %08lx\n", *Length );
  652. Lch = (PLCH) LogHandle;
  653. //
  654. // Check that the structure is a valid log handle structure.
  655. //
  656. LfsValidateLch( Lch );
  657. //
  658. // Use a try-finally to facilitate cleanup.
  659. //
  660. try {
  661. //
  662. // Acquire the log file control block for this log file.
  663. //
  664. LfsAcquireLchExclusive( Lch );
  665. Lfcb = Lch->Lfcb;
  666. //
  667. // If the Log file has been closed then return immediately.
  668. //
  669. if (Lfcb == NULL) {
  670. try_return( *Length = 0 );
  671. }
  672. //
  673. // Check that the client Id is valid.
  674. //
  675. LfsValidateClientId( Lfcb, Lch );
  676. //
  677. // The buffer better be large enough.
  678. //
  679. if (*Length >= sizeof( LOG_FILE_INFORMATION )) {
  680. PLOG_FILE_INFORMATION Information;
  681. LONGLONG CurrentAvail;
  682. ULONG UnusedBytes;
  683. LfsCurrentAvailSpace( Lfcb,
  684. &CurrentAvail,
  685. &UnusedBytes );
  686. //
  687. // Cast a pointer to the buffer and fill in the
  688. // data.
  689. //
  690. Information = (PLOG_FILE_INFORMATION) Buffer;
  691. Information->TotalAvailable = Lfcb->TotalAvailable;
  692. Information->CurrentAvailable = CurrentAvail;
  693. Information->TotalUndoCommitment = Lfcb->TotalUndoCommitment;
  694. Information->ClientUndoCommitment = Lch->ClientUndoCommitment;
  695. //
  696. // Acquire mutex to guard last flushed lsn access
  697. //
  698. ExAcquireFastMutexUnsafe( &Lfcb->Sync->Mutex );
  699. Information->OldestLsn = Lfcb->OldestLsn;
  700. Information->LastFlushedLsn.QuadPart = Lfcb->LastFlushedLsn.QuadPart;
  701. Information->LastLsn = Lfcb->RestartArea->CurrentLsn;
  702. ExReleaseFastMutexUnsafe( &Lfcb->Sync->Mutex );
  703. *Length = sizeof( LOG_FILE_INFORMATION );
  704. } else {
  705. *Length = 0;
  706. }
  707. try_exit: NOTHING;
  708. } finally {
  709. DebugUnwind( LfsReadLogFileInformation );
  710. //
  711. // Release the log file control block if held.
  712. //
  713. LfsReleaseLch( Lch );
  714. DebugTrace( -1, Dbg, "LfsReadLogFileInformation: Exit\n", 0 );
  715. }
  716. return;
  717. }
  718. BOOLEAN
  719. LfsVerifyLogFile (
  720. IN LFS_LOG_HANDLE LogHandle,
  721. IN PVOID LogFileHeader,
  722. IN ULONG Length
  723. )
  724. /*++
  725. Routine Description:
  726. This routine is called by a client to verify that the volume has not been removed
  727. from the system and then reattached. We will verify the log file open count on
  728. disk matches the value in the user's handle.
  729. Arguments:
  730. LogHandle - Pointer to private Lfs structure used to identify this
  731. client.
  732. LogFileHeader - Pointer to start of log file.
  733. Length - Number bytes returned with the read.
  734. Return Value:
  735. BOOLEAN - TRUE if the log file has not been altered externally, FALSE if we
  736. fail for any reason.
  737. --*/
  738. {
  739. BOOLEAN ValidLogFile = FALSE;
  740. PLCH Lch;
  741. PLFCB Lfcb;
  742. PLFS_RESTART_PAGE_HEADER RestartPage = LogFileHeader;
  743. PAGED_CODE();
  744. Lch = (PLCH) LogHandle;
  745. //
  746. // Check that the structure is a valid log handle structure.
  747. //
  748. if ((Lch == NULL) ||
  749. (Lch->NodeTypeCode != LFS_NTC_LCH) ||
  750. ((Lch->Lfcb != NULL) &&
  751. (Lch->Lfcb->NodeTypeCode != LFS_NTC_LFCB))) {
  752. return FALSE;
  753. }
  754. //
  755. // Acquire the log file control block for this log file.
  756. //
  757. LfsAcquireLchExclusive( Lch );
  758. Lfcb = Lch->Lfcb;
  759. //
  760. // If the Log file has been closed then return immediately.
  761. //
  762. if (Lfcb == NULL) {
  763. LfsReleaseLch( Lch );
  764. return FALSE;
  765. }
  766. //
  767. // Check that we have at least one page and that the page is valid.
  768. //
  769. if ((Length >= (ULONG) Lfcb->LogPageSize) &&
  770. (*((PULONG) RestartPage) == LFS_SIGNATURE_RESTART_PAGE_ULONG) &&
  771. ((RestartPage->RestartOffset + sizeof( LFS_RESTART_AREA )) < (ULONG) Lfcb->LogPageSize) &&
  772. ((Add2Ptr( RestartPage, RestartPage->RestartOffset, PLFS_RESTART_AREA ))->RestartOpenLogCount == Lfcb->CurrentOpenLogCount)) {
  773. ValidLogFile = TRUE;
  774. }
  775. LfsReleaseLfcb( Lfcb );
  776. return ValidLogFile;
  777. }
  778. VOID
  779. LfsResetUndoTotal (
  780. IN LFS_LOG_HANDLE LogHandle,
  781. IN ULONG NumberRecords,
  782. IN LONG ResetTotal
  783. )
  784. /*++
  785. Routine Description:
  786. This routine is called to adjust the undo commitment for this client.
  787. If the reset total is positive, then we absolutely set the
  788. reserve value for the client using this as the basis. If the value
  789. is negative, we will adjust the current value for the client.
  790. To adjust the values in the Lfcb, we first return the Undo commitment
  791. in the handle and then adjust by the values passed in.
  792. To adjust the value in the client handle, we simply set it if
  793. the reset value is positive, adjust it if the value is negative.
  794. For a packed log file we just reserve the space requested. We
  795. have already taken into account the loss of the tail of each page.
  796. For an unpacked log file we double each value.
  797. Arguments:
  798. LogHandle - Pointer to private Lfs structure used to identify this
  799. client.
  800. NumberRecords - This is the number of records we should assume the
  801. reset total covers. We allow an Lfs header for
  802. each one.
  803. ResetTotal - This is the amount to adjust (or set) the undo
  804. commitment.
  805. Return Value:
  806. None
  807. --*/
  808. {
  809. PLCH Lch;
  810. PLFCB Lfcb;
  811. LONGLONG AdjustedUndoTotal;
  812. LONG LfsHeaderBytes;
  813. PAGED_CODE();
  814. DebugTrace( +1, Dbg, "LfsResetUndoTotal: Entered\n", 0 );
  815. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  816. DebugTrace( 0, Dbg, "Number Records -> %08lx\n", NumberRecords );
  817. DebugTrace( 0, Dbg, "ResetTotal -> %08lx\n", ResetTotal );
  818. Lch = (PLCH) LogHandle;
  819. //
  820. // Check that the structure is a valid log handle structure.
  821. //
  822. LfsValidateLch( Lch );
  823. //
  824. // Use a try-finally to facilitate cleanup.
  825. //
  826. try {
  827. //
  828. // Acquire the log file control block for this log file.
  829. //
  830. LfsAcquireLchExclusive( Lch );
  831. Lfcb = Lch->Lfcb;
  832. //
  833. // If the Log file has been closed then refuse access.
  834. //
  835. if (Lfcb == NULL) {
  836. ExRaiseStatus( STATUS_ACCESS_DENIED );
  837. }
  838. //
  839. // Check that the client Id is valid.
  840. //
  841. LfsValidateClientId( Lfcb, Lch );
  842. //
  843. // Compute the adjusted reset total. Start by computing the
  844. // bytes needed for the Lfs log headers. Add (or subtract) this
  845. // from the reset total and multiply by 2 (only if not packing the
  846. // log).
  847. //
  848. LfsHeaderBytes = NumberRecords * Lfcb->RecordHeaderLength;
  849. LfsHeaderBytes *= 2;
  850. if (!FlagOn( Lfcb->Flags, LFCB_PACK_LOG )) {
  851. ResetTotal *= 2;
  852. }
  853. //
  854. // If the reset total is positive, add the header bytes.
  855. //
  856. if (ResetTotal > 0) {
  857. //
  858. // Subtract the client's current value from the TotalUndo
  859. // commit if he is setting his value exactly.
  860. //
  861. Lfcb->TotalUndoCommitment = Lfcb->TotalUndoCommitment - Lch->ClientUndoCommitment;
  862. //
  863. // We can clear the values in the user's handle at this
  864. // time.
  865. //
  866. Lch->ClientUndoCommitment = 0;
  867. ResetTotal += LfsHeaderBytes;
  868. //
  869. // Otherwise subtract the value for the header bytes.
  870. //
  871. } else {
  872. ResetTotal -= LfsHeaderBytes;
  873. }
  874. //
  875. // Now we adjust the Lfcb and Lch values by the adjustment amount.
  876. //
  877. AdjustedUndoTotal = ResetTotal;
  878. Lfcb->TotalUndoCommitment = Lfcb->TotalUndoCommitment + AdjustedUndoTotal;
  879. Lch->ClientUndoCommitment = Lch->ClientUndoCommitment + AdjustedUndoTotal;
  880. } finally {
  881. DebugUnwind( LfsResetUndoTotal );
  882. //
  883. // Release the log file control block if held.
  884. //
  885. LfsReleaseLch( Lch );
  886. DebugTrace( -1, Dbg, "LfsResetUndoTotal: Exit\n", 0 );
  887. }
  888. return;
  889. }
  890. //
  891. // Local support routine.
  892. //
  893. PLFCB
  894. LfsRestartLogFile (
  895. IN PFILE_OBJECT LogFile,
  896. IN USHORT MaximumClients,
  897. IN ULONG LogPageSize OPTIONAL,
  898. IN LONGLONG FileSize,
  899. IN OUT PLFS_INFO LfsInfo,
  900. OUT PLFS_WRITE_DATA WriteData
  901. )
  902. /*++
  903. Routine Description:
  904. This routine is called to process an existing log file when it opened
  905. for the first time on a running system. We walk through the beginning
  906. of the file looking for a valid restart area. Once we have a restart
  907. area, we can find the next restart area and determine which is the
  908. most recent. The data in the restart area will tell us if the system
  909. has been gracefully shutdown and whether the log file in its current
  910. state can run on the current system.
  911. If the file is usable, we perform any necessary initialization on the
  912. file to prepare it for operation.
  913. Arguments:
  914. LogFile - This is the file to use as a log file.
  915. MaximumClients - This is the maximum number of clients that will be
  916. active in the log file at any one time.
  917. LogPageSize - If specified (not 0), this is the recommended size of
  918. the log page. Lfs will use this as a guide in
  919. determining the log page size.
  920. FileSize - This is the available size of the log file.
  921. LfsInfo - On entry, indicates the log file state the user may
  922. know about. On exit, indicates the log file state that Lfs
  923. knows about. This is a conduit for Lfs to communicate with its
  924. clients.
  925. WriteData - Pointer to WRITE_DATA in caller's data structure.
  926. Return Value:
  927. PLFCB - A pointer to an initialized Lfcb to use for
  928. this log file.
  929. --*/
  930. {
  931. PLFCB ThisLfcb = NULL;
  932. PLFS_RESTART_AREA RestartArea = NULL;
  933. PLFS_RESTART_AREA DiskRestartArea;
  934. BOOLEAN UninitializedFile;
  935. LONGLONG OriginalFileSize = FileSize;
  936. LONGLONG FirstRestartOffset;
  937. PLFS_RESTART_PAGE_HEADER FirstRestartPage;
  938. BOOLEAN FirstChkdskWasRun;
  939. BOOLEAN FirstValidPage;
  940. BOOLEAN FirstLogPacked;
  941. LSN FirstRestartLastLsn;
  942. PBCB FirstRestartPageBcb = NULL;
  943. PBCB SecondRestartPageBcb = NULL;
  944. //
  945. // By default pack any new logs
  946. //
  947. BOOLEAN PackLogFile = TRUE;
  948. BOOLEAN UseDefaultLogPage = FALSE;
  949. LARGE_INTEGER CurrentTime;
  950. BOOLEAN ForceRestartToDisk = FALSE;
  951. BOOLEAN ClearLogFile = FALSE;
  952. LONGLONG StartOffsetForClear = 0;
  953. PAGED_CODE();
  954. DebugTrace( +1, Dbg, "LfsRestartLogFile: Entered\n", 0 );
  955. DebugTrace( 0, Dbg, "LogFile -> %08lx\n", LogFile );
  956. DebugTrace( 0, Dbg, "Maximum Clients -> %04x\n", MaximumClients );
  957. DebugTrace( 0, Dbg, "Log Page Size -> %08lx\n", LogPageSize );
  958. DebugTrace( 0, Dbg, "File Size (Low) -> %08lx\n", FileSize.LowPart );
  959. DebugTrace( 0, Dbg, "File Size (High) -> %08lx\n", FileSize.HighPart );
  960. DebugTrace( 0, Dbg, "Pack Log -> %04x\n", *LfsInfo );
  961. //
  962. // Remember if we are to pack the log file. Once a log file has
  963. // been packed we will attempt to keep it that way.
  964. //
  965. ASSERT( LfsInfo->LfsClientInfo >= LfsPackLog );
  966. if (LogPageSize == 0) {
  967. UseDefaultLogPage = TRUE;
  968. }
  969. //
  970. // Use a try-finally to facilitate cleanup.
  971. //
  972. try {
  973. //
  974. // Normalize the values passed in with this call.
  975. //
  976. LfsNormalizeBasicLogFile( &FileSize,
  977. &LogPageSize,
  978. &MaximumClients,
  979. UseDefaultLogPage );
  980. //
  981. // Allocate an Lfcb to use for this file.
  982. //
  983. ThisLfcb = LfsAllocateLfcb( LogPageSize, FileSize );
  984. //
  985. // Acquire the Lfcb and store it in the global queue.
  986. //
  987. LfsAcquireLfcbExclusive( ThisLfcb );
  988. //
  989. // Remember this log file in the Lfcb.
  990. //
  991. ThisLfcb->FileObject = LogFile;
  992. SetFlag( ThisLfcb->Flags,
  993. (LFCB_READ_FIRST_RESTART |
  994. LFCB_READ_SECOND_RESTART) );
  995. if (LfsInfo->ReadOnly) {
  996. SetFlag( ThisLfcb->Flags, LFCB_READ_ONLY );
  997. }
  998. //
  999. // Look for a restart area on the disk.
  1000. //
  1001. if (!LfsInfo->BadRestart &&
  1002. LfsReadRestart( ThisLfcb,
  1003. FileSize,
  1004. TRUE,
  1005. &FirstRestartOffset,
  1006. &FirstRestartPage,
  1007. &FirstRestartPageBcb,
  1008. &FirstChkdskWasRun,
  1009. &FirstValidPage,
  1010. &UninitializedFile,
  1011. &FirstLogPacked,
  1012. &FirstRestartLastLsn )) {
  1013. BOOLEAN DoubleRestart;
  1014. LONGLONG SecondRestartOffset;
  1015. PLFS_RESTART_PAGE_HEADER SecondRestartPage;
  1016. BOOLEAN SecondChkdskWasRun;
  1017. BOOLEAN SecondValidPage;
  1018. BOOLEAN SecondLogPacked;
  1019. LSN SecondRestartLastLsn;
  1020. //
  1021. // If the restart offset above wasn't zero then we
  1022. // won't look for a second restart.
  1023. //
  1024. if (FirstRestartOffset == 0) {
  1025. ClearFlag( ThisLfcb->Flags, LFCB_READ_FIRST_RESTART );
  1026. DoubleRestart = LfsReadRestart( ThisLfcb,
  1027. FileSize,
  1028. FALSE,
  1029. &SecondRestartOffset,
  1030. &SecondRestartPage,
  1031. &SecondRestartPageBcb,
  1032. &SecondChkdskWasRun,
  1033. &SecondValidPage,
  1034. &UninitializedFile,
  1035. &SecondLogPacked,
  1036. &SecondRestartLastLsn );
  1037. if (DoubleRestart) {
  1038. ClearFlag( ThisLfcb->Flags, LFCB_READ_SECOND_RESTART );
  1039. }
  1040. } else {
  1041. ClearFlag( ThisLfcb->Flags, LFCB_READ_SECOND_RESTART );
  1042. DoubleRestart = FALSE;
  1043. }
  1044. //
  1045. // Determine which restart area to use.
  1046. //
  1047. if (DoubleRestart && (SecondRestartLastLsn.QuadPart > FirstRestartLastLsn.QuadPart)) {
  1048. BOOLEAN UseSecondPage = TRUE;
  1049. PULONG SecondPage;
  1050. PBCB SecondPageBcb = NULL;
  1051. BOOLEAN UsaError;
  1052. //
  1053. // In a very strange case we could have crashed on a system with
  1054. // a different page size and then run chkdsk on the new system.
  1055. // The second restart page may not have the chkdsk signature in
  1056. // that case but could have a higher final Lsn.
  1057. // We want to ignore the second restart area in that case.
  1058. //
  1059. if (FirstChkdskWasRun &&
  1060. (SecondRestartOffset != PAGE_SIZE)) {
  1061. if (NT_SUCCESS( LfsPinOrMapData( ThisLfcb,
  1062. PAGE_SIZE,
  1063. PAGE_SIZE,
  1064. FALSE,
  1065. TRUE,
  1066. TRUE,
  1067. &UsaError,
  1068. &SecondPage,
  1069. &SecondPageBcb )) &&
  1070. (*SecondPage == LFS_SIGNATURE_MODIFIED_ULONG)) {
  1071. UseSecondPage = FALSE;
  1072. }
  1073. if (SecondPageBcb != NULL) {
  1074. CcUnpinData( SecondPageBcb );
  1075. }
  1076. }
  1077. if (UseSecondPage) {
  1078. FirstRestartOffset = SecondRestartOffset;
  1079. FirstRestartPage = SecondRestartPage;
  1080. FirstChkdskWasRun = SecondChkdskWasRun;
  1081. FirstValidPage = SecondValidPage;
  1082. FirstLogPacked = SecondLogPacked;
  1083. FirstRestartLastLsn = SecondRestartLastLsn;
  1084. }
  1085. }
  1086. #ifdef LFS_CLUSTER_CHECK
  1087. //
  1088. // Capture the current position out of the page.
  1089. //
  1090. ThisLfcb->LsnRangeIndex = *(Add2Ptr( FirstRestartPage, 0xe00 - sizeof( ULONG ), PULONG ));
  1091. if (ThisLfcb->LsnRangeIndex >= 0x20) {
  1092. ThisLfcb->LsnRangeIndex = 0;
  1093. }
  1094. #endif
  1095. //
  1096. // If the restart area is at offset 0, we want to write
  1097. // the second restart area out first.
  1098. //
  1099. if (FirstRestartOffset != 0) {
  1100. ThisLfcb->InitialRestartArea = TRUE;
  1101. }
  1102. //
  1103. // If we have a valid page then grab a pointer to the restart area.
  1104. //
  1105. if (FirstValidPage) {
  1106. DiskRestartArea = Add2Ptr( FirstRestartPage, FirstRestartPage->RestartOffset, PLFS_RESTART_AREA );
  1107. }
  1108. //
  1109. // If checkdisk was run or there are no active clients,
  1110. // then we will begin at the start of the log file.
  1111. //
  1112. if (FirstChkdskWasRun ||
  1113. (DiskRestartArea->ClientInUseList == LFS_NO_CLIENT)) {
  1114. //
  1115. // Default version is 1.1.
  1116. //
  1117. SHORT MajorVersion = 1;
  1118. SHORT MinorVersion = 1;
  1119. BOOLEAN LogFileWrapped = FALSE;
  1120. BOOLEAN UseMultiplePageIo = FALSE;
  1121. //
  1122. // We want to do a complete initialization
  1123. //
  1124. ForceRestartToDisk = TRUE;
  1125. ClearLogFile = TRUE;
  1126. StartOffsetForClear = LogPageSize * 2;
  1127. //
  1128. // Do some checks based on whether we have a valid log page.
  1129. //
  1130. if (FirstValidPage) {
  1131. CurrentTime.LowPart = DiskRestartArea->RestartOpenLogCount;
  1132. //
  1133. // If the restart page size isn't changing then we want to
  1134. // check how much work we need to do.
  1135. //
  1136. if (LogPageSize == FirstRestartPage->SystemPageSize) {
  1137. //
  1138. // If the file size is changing we want to remember
  1139. // at which point we want to start clearing the file.
  1140. //
  1141. if (FileSize > DiskRestartArea->FileSize) {
  1142. StartOffsetForClear = DiskRestartArea->FileSize;
  1143. } else {
  1144. if (!FlagOn( DiskRestartArea->Flags, RESTART_SINGLE_PAGE_IO )) {
  1145. UseMultiplePageIo = TRUE;
  1146. LogFileWrapped = TRUE;
  1147. }
  1148. //
  1149. // If the page is valid we don't need to clear the log
  1150. // file or force the data to disk.
  1151. //
  1152. ForceRestartToDisk = FALSE;
  1153. ClearLogFile = FALSE;
  1154. }
  1155. }
  1156. } else {
  1157. KeQuerySystemTime( &CurrentTime );
  1158. }
  1159. //
  1160. // Initialize our Lfcb for the current log page values.
  1161. //
  1162. LfsUpdateLfcbFromPgHeader( ThisLfcb,
  1163. LogPageSize,
  1164. MajorVersion,
  1165. MinorVersion,
  1166. PackLogFile );
  1167. LfsUpdateLfcbFromNoRestart( ThisLfcb,
  1168. FileSize,
  1169. FirstRestartLastLsn,
  1170. MaximumClients,
  1171. CurrentTime.LowPart,
  1172. LogFileWrapped,
  1173. UseMultiplePageIo );
  1174. LfsAllocateRestartArea( &RestartArea, ThisLfcb->RestartDataSize );
  1175. LfsUpdateRestartAreaFromLfcb( ThisLfcb, RestartArea );
  1176. ThisLfcb->RestartArea = RestartArea;
  1177. ThisLfcb->ClientArray = Add2Ptr( RestartArea,
  1178. ThisLfcb->ClientArrayOffset,
  1179. PLFS_CLIENT_RECORD );
  1180. RestartArea = NULL;
  1181. //
  1182. // Unpin any pages pinned here.
  1183. //
  1184. if (FirstRestartPageBcb != NULL) {
  1185. CcUnpinData( FirstRestartPageBcb );
  1186. FirstRestartPageBcb = NULL;
  1187. }
  1188. if (SecondRestartPageBcb != NULL) {
  1189. CcUnpinData( SecondRestartPageBcb );
  1190. SecondRestartPageBcb = NULL;
  1191. }
  1192. //
  1193. // Now update the caller's WRITE_DATA structure.
  1194. //
  1195. ThisLfcb->UserWriteData = WriteData;
  1196. WriteData->LfsStructureSize = LogPageSize;
  1197. WriteData->Lfcb = ThisLfcb;
  1198. //
  1199. // If we are doing a read only mount and we need to
  1200. // write restart areas to disk, we are hosed.
  1201. //
  1202. if (LfsInfo->ReadOnly && ForceRestartToDisk) {
  1203. ASSERTMSG("INFO: ReadOnly Mount, Cant write restart. Raising\n", FALSE);
  1204. ExRaiseStatus( STATUS_MEDIA_WRITE_PROTECTED );
  1205. }
  1206. //
  1207. // If the log page or the system page sizes have changed,
  1208. // we can't use the log file. We must use the system
  1209. // page size instead of the default size if there is not
  1210. // a clean shutdown.
  1211. //
  1212. } else {
  1213. if (LogPageSize != FirstRestartPage->SystemPageSize) {
  1214. FileSize = OriginalFileSize;
  1215. LfsNormalizeBasicLogFile( &FileSize,
  1216. &LogPageSize,
  1217. &MaximumClients,
  1218. (BOOLEAN) (FirstRestartPage->SystemPageSize == LFS_DEFAULT_LOG_PAGE_SIZE) );
  1219. }
  1220. if ((LogPageSize != FirstRestartPage->SystemPageSize) ||
  1221. (LogPageSize != FirstRestartPage->LogPageSize)) {
  1222. DebugTrace( 0, Dbg, "Page size mismatch\n", 0 );
  1223. ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
  1224. //
  1225. // Otherwise we have a restart area to deal with.
  1226. //
  1227. } else {
  1228. //
  1229. // We preserve the packed status from the disk.
  1230. //
  1231. PackLogFile = FirstLogPacked;
  1232. //
  1233. // Update the Lfcb from the values in the restart area
  1234. // page header and the active restart page.
  1235. //
  1236. LfsUpdateLfcbFromPgHeader( ThisLfcb,
  1237. LogPageSize,
  1238. FirstRestartPage->MajorVersion,
  1239. FirstRestartPage->MinorVersion,
  1240. FirstLogPacked );
  1241. LfsUpdateLfcbFromRestart( ThisLfcb,
  1242. FileSize,
  1243. DiskRestartArea,
  1244. FirstRestartPage->RestartOffset );
  1245. //
  1246. // Now allocate a restart area.
  1247. //
  1248. LfsAllocateRestartArea( &RestartArea, ThisLfcb->RestartDataSize );
  1249. //
  1250. // We may need to grow the restart area to allow room for the open
  1251. // log file count.
  1252. //
  1253. if (ThisLfcb->ClientArrayOffset == FIELD_OFFSET( LFS_RESTART_AREA, LogClientArray )) {
  1254. RtlCopyMemory( RestartArea, DiskRestartArea, ThisLfcb->RestartAreaSize );
  1255. } else {
  1256. //
  1257. // Copy the start of the restart area over.
  1258. //
  1259. RtlCopyMemory( RestartArea, DiskRestartArea, ThisLfcb->ClientArrayOffset );
  1260. //
  1261. // Now copy over the client data to its new location.
  1262. //
  1263. RtlCopyMemory( RestartArea->LogClientArray,
  1264. Add2Ptr( DiskRestartArea, ThisLfcb->ClientArrayOffset, PVOID ),
  1265. DiskRestartArea->RestartAreaLength - ThisLfcb->ClientArrayOffset );
  1266. //
  1267. // Update the system open count.
  1268. //
  1269. KeQuerySystemTime( &CurrentTime );
  1270. ThisLfcb->CurrentOpenLogCount =
  1271. RestartArea->RestartOpenLogCount = CurrentTime.LowPart;
  1272. //
  1273. // Now update the numbers in the Lfcb and restart area.
  1274. //
  1275. ThisLfcb->ClientArrayOffset = FIELD_OFFSET( LFS_RESTART_AREA, LogClientArray );
  1276. ThisLfcb->RestartAreaSize = ThisLfcb->ClientArrayOffset
  1277. + (sizeof( LFS_CLIENT_RECORD ) * ThisLfcb->LogClients );
  1278. RestartArea->ClientArrayOffset = ThisLfcb->ClientArrayOffset;
  1279. RestartArea->RestartAreaLength = (USHORT) ThisLfcb->RestartAreaSize;
  1280. }
  1281. //
  1282. // clear the clean shutdown flag from on disk
  1283. //
  1284. ClearFlag( RestartArea->Flags, LFS_CLEAN_SHUTDOWN );
  1285. //
  1286. // Update the log file open count.
  1287. //
  1288. RestartArea->RestartOpenLogCount += 1;
  1289. ThisLfcb->RestartArea = RestartArea;
  1290. ThisLfcb->ClientArray = Add2Ptr( RestartArea, ThisLfcb->ClientArrayOffset, PLFS_CLIENT_RECORD );
  1291. RestartArea = NULL;
  1292. //
  1293. // Unpin any pages pinned here.
  1294. //
  1295. if (FirstRestartPageBcb != NULL) {
  1296. CcUnpinData( FirstRestartPageBcb );
  1297. FirstRestartPageBcb = NULL;
  1298. }
  1299. if (SecondRestartPageBcb != NULL) {
  1300. CcUnpinData( SecondRestartPageBcb );
  1301. SecondRestartPageBcb = NULL;
  1302. }
  1303. //
  1304. // update the caller's WRITE_DATA structure before finding
  1305. // last LSN which may flush a log page.
  1306. //
  1307. ThisLfcb->UserWriteData = WriteData;
  1308. WriteData->LfsStructureSize = LogPageSize;
  1309. WriteData->Lfcb = ThisLfcb;
  1310. //
  1311. // Now we need to walk through looking for the last
  1312. // Lsn.
  1313. //
  1314. LfsFindLastLsn( ThisLfcb );
  1315. //
  1316. // Recalculate the available pages in the Lfcb.
  1317. //
  1318. LfsFindCurrentAvail( ThisLfcb );
  1319. //
  1320. // Remember which restart area to write out first.
  1321. //
  1322. if (FirstRestartOffset != 0) {
  1323. ThisLfcb->InitialRestartArea = TRUE;
  1324. }
  1325. }
  1326. }
  1327. #ifdef LFS_CLUSTER_CHECK
  1328. if (FirstValidPage) {
  1329. //
  1330. // Copy the tail of the page to the restart area.
  1331. //
  1332. RtlCopyMemory( Add2Ptr( ThisLfcb->RestartArea,
  1333. 0xe00 - sizeof( ULONG ) - ThisLfcb->RestartDataOffset,
  1334. PVOID ),
  1335. Add2Ptr( FirstRestartPage,
  1336. 0xe00 - sizeof( ULONG ),
  1337. PVOID ),
  1338. 0x200 + sizeof( ULONG ));
  1339. DiskRestartArea = Add2Ptr( FirstRestartPage, FirstRestartPage->RestartOffset, PLFS_RESTART_AREA );
  1340. }
  1341. #endif
  1342. //
  1343. // If the file is uninitialized, we will initialized it with new
  1344. // restart areas. We can move to version 1.0 where we use
  1345. // update sequence array support but don't have to force the values
  1346. // to disk.
  1347. //
  1348. } else {
  1349. //
  1350. // Need to determine if we are in a bad restart state.
  1351. // If not, treat the file as if it is not initialized.
  1352. //
  1353. if (!LfsInfo->BadRestart && !UninitializedFile) {
  1354. //
  1355. // We didn't find a restart area but the file is not initialized.
  1356. // This is a corrupt disk.
  1357. //
  1358. DebugTrace( 0, Dbg, "Log file has no restart area\n", 0 );
  1359. ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
  1360. }
  1361. //
  1362. // We need to fail the mount if the media is readonly.
  1363. //
  1364. if (LfsInfo->ReadOnly) {
  1365. ExRaiseStatus( STATUS_MEDIA_WRITE_PROTECTED );
  1366. }
  1367. //
  1368. // If we are here due to bad restart, we need to wipe the log
  1369. // completely so as not to confuse LfsFindLastLsn on next reboot.
  1370. //
  1371. if (LfsInfo->BadRestart) {
  1372. ForceRestartToDisk = TRUE;
  1373. ClearLogFile = TRUE;
  1374. StartOffsetForClear = LogPageSize * 2;
  1375. }
  1376. //
  1377. // We go to a packed system if possible.
  1378. //
  1379. LfsUpdateLfcbFromPgHeader( ThisLfcb,
  1380. LogPageSize,
  1381. 1,
  1382. 1,
  1383. PackLogFile );
  1384. KeQuerySystemTime( &CurrentTime );
  1385. LfsUpdateLfcbFromNoRestart( ThisLfcb,
  1386. FileSize,
  1387. LfsLi0,
  1388. MaximumClients,
  1389. CurrentTime.LowPart,
  1390. FALSE,
  1391. TRUE );
  1392. LfsAllocateRestartArea( &RestartArea, ThisLfcb->RestartDataSize );
  1393. LfsUpdateRestartAreaFromLfcb( ThisLfcb, RestartArea );
  1394. ThisLfcb->RestartArea = RestartArea;
  1395. ThisLfcb->ClientArray = Add2Ptr( RestartArea, ThisLfcb->ClientArrayOffset, PLFS_CLIENT_RECORD );
  1396. ThisLfcb->InitialRestartArea = TRUE;
  1397. RestartArea = NULL;
  1398. //
  1399. // update the caller's WRITE_DATA structure.
  1400. //
  1401. ThisLfcb->UserWriteData = WriteData;
  1402. WriteData->LfsStructureSize = LogPageSize;
  1403. WriteData->Lfcb = ThisLfcb;
  1404. }
  1405. //
  1406. // Common initialization for all cases - If we're readonly we don't do any preallocations
  1407. // that are only used for the write paths (like error logs for write failures)
  1408. //
  1409. if (!LfsInfo->ReadOnly) {
  1410. //
  1411. // Allocate buffer for the first 4 pages - this includes the 2 restart pages and the 2
  1412. // ping - pong pages
  1413. //
  1414. ThisLfcb->LogHeadBuffer = LfsAllocatePool( NonPagedPool, (ULONG)(ThisLfcb->LogPageSize * 4) );
  1415. ThisLfcb->LogHeadMdl = IoAllocateMdl( ThisLfcb->LogHeadBuffer,
  1416. (ULONG)(ThisLfcb->LogPageSize * 4),
  1417. FALSE,
  1418. FALSE,
  1419. NULL );
  1420. if (ThisLfcb->LogHeadMdl == NULL) {
  1421. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1422. }
  1423. ThisLfcb->LogHeadPartialMdl = IoAllocateMdl( ThisLfcb->LogHeadBuffer,
  1424. (ULONG)(ThisLfcb->LogPageSize),
  1425. FALSE,
  1426. FALSE,
  1427. NULL );
  1428. if (ThisLfcb->LogHeadPartialMdl == NULL) {
  1429. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1430. }
  1431. MmBuildMdlForNonPagedPool( ThisLfcb->LogHeadMdl );
  1432. ThisLfcb->ErrorLogPacket = IoAllocateErrorLogEntry( ThisLfcb->FileObject->DeviceObject, ERROR_LOG_MAXIMUM_SIZE );
  1433. //
  1434. // Put both restart areas in the queue to be flushed but don't
  1435. // force them to disk.
  1436. //
  1437. LfsInitializeLogFilePriv( ThisLfcb,
  1438. ForceRestartToDisk,
  1439. ThisLfcb->RestartDataSize,
  1440. StartOffsetForClear,
  1441. ClearLogFile );
  1442. }
  1443. } finally {
  1444. DebugUnwind( LfsRestartLogFile );
  1445. //
  1446. // Free the Lfcb if allocated.
  1447. //
  1448. if (ThisLfcb != NULL) {
  1449. LfsReleaseLfcb( ThisLfcb );
  1450. //
  1451. // Free the Lfcb and Restart areas in the event of an error.
  1452. //
  1453. if (AbnormalTermination()) {
  1454. LfsDeallocateLfcb( ThisLfcb, TRUE );
  1455. if (RestartArea != NULL) {
  1456. LfsDeallocateRestartArea( RestartArea );
  1457. }
  1458. }
  1459. }
  1460. if (FirstRestartPageBcb != NULL) {
  1461. CcUnpinData( FirstRestartPageBcb );
  1462. }
  1463. if (SecondRestartPageBcb != NULL) {
  1464. CcUnpinData( SecondRestartPageBcb );
  1465. }
  1466. DebugTrace( -1, Dbg, "LfsRestartLogFile: Exit\n", 0 );
  1467. }
  1468. //
  1469. // Indicate whether the log is packed.
  1470. //
  1471. if (PackLogFile && (LfsInfo->LfsClientInfo < LfsPackLog)) {
  1472. LfsInfo->LfsClientInfo = LfsPackLog;
  1473. }
  1474. #ifdef LFS_CLUSTER_CHECK
  1475. ThisLfcb->LsnAtMount = ThisLfcb->LastFlushedLsn;
  1476. #endif
  1477. return ThisLfcb;
  1478. }
  1479. //
  1480. // Local support routine
  1481. //
  1482. VOID
  1483. LfsNormalizeBasicLogFile (
  1484. IN OUT PLONGLONG FileSize,
  1485. IN OUT PULONG LogPageSize,
  1486. IN OUT PUSHORT LogClients,
  1487. IN BOOLEAN UseDefaultLogPage
  1488. )
  1489. /*++
  1490. Routine Description:
  1491. This routine is called to normalize the values which describe the
  1492. log file. It will make the log page a multiple of the system page.
  1493. Finally we make sure the file size ends on a log page boundary.
  1494. On input all of the parameters have the requested values, on return
  1495. they have the values to use.
  1496. Arguments:
  1497. FileSize - Stated size of the log file.
  1498. LogPageSize - Suggested size for the log page.
  1499. LogClients - Requested number of log clients.
  1500. UseDefaultLogPage - Indicates if we should use the hardwired log page size or base
  1501. it on the system page size.
  1502. Return Value:
  1503. None.
  1504. --*/
  1505. {
  1506. ULONG LocalLogPageSize;
  1507. LONGLONG RestartPageBytes;
  1508. LONGLONG LogPages;
  1509. USHORT MaximumClients;
  1510. PAGED_CODE();
  1511. DebugTrace( +1, Dbg, "LfsNormalizeBasicLogFile: Entered\n", 0 );
  1512. if (!UseDefaultLogPage) {
  1513. if (*LogPageSize == 0) {
  1514. *LogPageSize = PAGE_SIZE;
  1515. }
  1516. } else {
  1517. *LogPageSize = LFS_DEFAULT_LOG_PAGE_SIZE;
  1518. }
  1519. //
  1520. // If the log file is greater than the maximum log file size, we
  1521. // set the log file size to the maximum size.
  1522. //
  1523. if (*FileSize > LfsMaximumFileSize) {
  1524. *FileSize = LfsMaximumFileSize;
  1525. }
  1526. //
  1527. // We round the file size down to a system page boundary. This
  1528. // may also change if we allow non-system page sized log pages.
  1529. //
  1530. *(PULONG)FileSize &= ~(*LogPageSize - 1);
  1531. //
  1532. // There better be at least 2 restart pages.
  1533. //
  1534. RestartPageBytes = 2 * *LogPageSize;
  1535. if (*FileSize <= RestartPageBytes) {
  1536. DebugTrace( 0, Dbg, "Log file is too small\n", 0 );
  1537. DebugTrace( -1, Dbg, "LfsValidateBasicLogFile: Abnormal Exit\n", 0 );
  1538. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1539. }
  1540. //
  1541. // Now compute the number of log pages.
  1542. //
  1543. LogPages = *FileSize - RestartPageBytes;
  1544. LocalLogPageSize = *LogPageSize >> 1;
  1545. while (LocalLogPageSize) {
  1546. LocalLogPageSize = LocalLogPageSize >> 1;
  1547. LogPages = ((ULONGLONG)(LogPages)) >> 1;
  1548. }
  1549. //
  1550. // If there aren't enough log pages then raise an error condition.
  1551. //
  1552. if (((PLARGE_INTEGER)&LogPages)->HighPart == 0
  1553. && (ULONG)LogPages < MINIMUM_LFS_PAGES) {
  1554. DebugTrace( 0, Dbg, "Not enough log pages -> %08lx\n", LogPages.LowPart );
  1555. DebugTrace( -1, Dbg, "LfsValidateBasicLogFile: Abnormal Exit\n", 0 );
  1556. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  1557. }
  1558. //
  1559. // Now we compute the amount of space available for log clients.
  1560. // We will limit the clients to half of the restart system page.
  1561. //
  1562. MaximumClients = (USHORT) ((*LogPageSize / 2) / sizeof( LFS_CLIENT_RECORD ));
  1563. if (*LogClients == 0) {
  1564. *LogClients = 1;
  1565. } else if (*LogClients > MaximumClients) {
  1566. *LogClients = MaximumClients;
  1567. }
  1568. DebugTrace( -1, Dbg, "LfsNormalizeBasicLogFile: Exit\n", 0 );
  1569. return;
  1570. }
  1571. //
  1572. // Local support routine
  1573. //
  1574. VOID
  1575. LfsUpdateLfcbFromPgHeader (
  1576. IN PLFCB Lfcb,
  1577. IN ULONG LogPageSize,
  1578. IN SHORT MajorVersion,
  1579. IN SHORT MinorVersion,
  1580. IN BOOLEAN PackLog
  1581. )
  1582. /*++
  1583. Routine Description:
  1584. This routine updates the values in the Lfcb which depend on values in the
  1585. restart page header.
  1586. Arguments:
  1587. Lfcb - Log file control block to update.
  1588. LogPageSize - Log page size to use.
  1589. MajorVersion - Major version number for Lfs.
  1590. MinorVersion - Minor version number for Lfs.
  1591. PackLog - Indicates if we are packing the log file. This is the default for new logs
  1592. Return Value:
  1593. None.
  1594. --*/
  1595. {
  1596. PAGED_CODE();
  1597. DebugTrace( +1, Dbg, "LfsUpdateLfcbFromPgHeader: Entered\n", 0 );
  1598. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  1599. DebugTrace( 0, Dbg, "System Page Size -> %08lx\n", SystemPageSize );
  1600. DebugTrace( 0, Dbg, "Log Page Size -> %08lx\n", LogPageSize );
  1601. DebugTrace( 0, Dbg, "Major Version -> %04x\n", MajorVersion );
  1602. DebugTrace( 0, Dbg, "Minor Version -> %04x\n", MinorVersion );
  1603. //
  1604. // Do the same for the log pages.
  1605. //
  1606. Lfcb->LogPageSize = LogPageSize;
  1607. Lfcb->LogPageMask = LogPageSize - 1;
  1608. Lfcb->LogPageInverseMask = ~Lfcb->LogPageMask;
  1609. Lfcb->LogPageShift = 0;
  1610. while (TRUE) {
  1611. LogPageSize = LogPageSize >> 1;
  1612. if (LogPageSize == 0) {
  1613. break;
  1614. }
  1615. Lfcb->LogPageShift += 1;
  1616. }
  1617. //
  1618. // If we are packing the log file then the first log page is page
  1619. // 4 (in log pages). Otherwise it is page 2. Use the PackLog value to determine the
  1620. // Usa values.
  1621. //
  1622. if (PackLog) {
  1623. Lfcb->FirstLogPage = Lfcb->LogPageSize << 2;
  1624. Lfcb->LogRecordUsaOffset = (USHORT) LFS_PACKED_RECORD_PAGE_HEADER_SIZE;
  1625. SetFlag( Lfcb->Flags, LFCB_PACK_LOG );
  1626. } else {
  1627. Lfcb->FirstLogPage = Lfcb->LogPageSize << 1;
  1628. Lfcb->LogRecordUsaOffset = (USHORT) LFS_UNPACKED_RECORD_PAGE_HEADER_SIZE;
  1629. }
  1630. //
  1631. // Remember the values for the version numbers.
  1632. //
  1633. Lfcb->MajorVersion = MajorVersion;
  1634. Lfcb->MinorVersion = MinorVersion;
  1635. //
  1636. // Compute the offsets for the update sequence arrays.
  1637. //
  1638. Lfcb->RestartUsaOffset = LFS_RESTART_PAGE_HEADER_SIZE;
  1639. Lfcb->UsaArraySize = (USHORT) UpdateSequenceArraySize( (ULONG)Lfcb->LogPageSize );
  1640. DebugTrace( -1, Dbg, "LfsUpdateLfcbFromPgHeader: Exit\n", 0 );
  1641. return;
  1642. }
  1643. //
  1644. // Local support routine
  1645. //
  1646. VOID
  1647. LfsUpdateLfcbFromNoRestart (
  1648. IN PLFCB Lfcb,
  1649. IN LONGLONG FileSize,
  1650. IN LSN LastLsn,
  1651. IN ULONG LogClients,
  1652. IN ULONG OpenLogCount,
  1653. IN BOOLEAN LogFileWrapped,
  1654. IN BOOLEAN UseMultiplePageIo
  1655. )
  1656. /*++
  1657. Routine Description:
  1658. This routine updates the values in the Lfcb in cases when we don't have a
  1659. restart area to use.
  1660. Arguments:
  1661. Lfcb - Log file control block to update.
  1662. FileSize - Log file size. This is the usable size of the log file. It has
  1663. already been adjusted to the log page size.
  1664. LastLsn - This is the last Lsn to use for the disk.
  1665. LogClients - This is the number of clients supported.
  1666. OpenLogCount - This is the current count of opens for this log file.
  1667. LogFileWrapped - Indicates if the log file has wrapped.
  1668. UseMultiplePageIo - Indicates if we should be using large i/o transfers.
  1669. Return Value:
  1670. None.
  1671. --*/
  1672. {
  1673. ULONG Count;
  1674. PAGED_CODE();
  1675. DebugTrace( +1, Dbg, "LfsUpdateLfcbFromNoRestart: Entered\n", 0 );
  1676. Lfcb->FileSize = FileSize;
  1677. //
  1678. // We can compute the number of bits needed for the file size by shifting
  1679. // until the size is 0. We then can subtract 3 bits to account for
  1680. // quadaligning all file offsets for log records.
  1681. //
  1682. for (Count = 0;
  1683. ( FileSize != 0 );
  1684. Count += 1,
  1685. FileSize = ((ULONGLONG)(FileSize)) >> 1) {
  1686. }
  1687. Lfcb->FileDataBits = Count - 3;
  1688. Lfcb->SeqNumberBits = (sizeof( LSN ) * 8) - Lfcb->FileDataBits;
  1689. //
  1690. // We get a starting sequence number from the given Lsn.
  1691. // We add 2 to this for our starting sequence number.
  1692. //
  1693. Lfcb->SeqNumber = LfsLsnToSeqNumber( Lfcb, LastLsn ) + 2;
  1694. Lfcb->SeqNumberForWrap = Lfcb->SeqNumber + 1;
  1695. Lfcb->NextLogPage = Lfcb->FirstLogPage;
  1696. SetFlag( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_NO_OLDEST_LSN );
  1697. //
  1698. // The oldest Lsn is contructed from the sequence number.
  1699. //
  1700. Lfcb->OldestLsn.QuadPart = LfsFileOffsetToLsn( Lfcb, 0, Lfcb->SeqNumber );
  1701. Lfcb->OldestLsnOffset = 0;
  1702. Lfcb->LastFlushedLsn = Lfcb->OldestLsn;
  1703. //
  1704. // Set the correct flags for the I/O and indicate if we have wrapped.
  1705. //
  1706. if (LogFileWrapped) {
  1707. SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED );
  1708. }
  1709. if (UseMultiplePageIo) {
  1710. SetFlag( Lfcb->Flags, LFCB_MULTIPLE_PAGE_IO );
  1711. }
  1712. //
  1713. // Compute the Log page values.
  1714. //
  1715. (ULONG)Lfcb->LogPageDataOffset = QuadAlign( Lfcb->LogRecordUsaOffset + (sizeof( UPDATE_SEQUENCE_NUMBER ) * Lfcb->UsaArraySize) );
  1716. Lfcb->LogPageDataSize = Lfcb->LogPageSize - Lfcb->LogPageDataOffset;
  1717. Lfcb->RecordHeaderLength = LFS_RECORD_HEADER_SIZE;
  1718. if (FlagOn( Lfcb->Flags, LFCB_PACK_LOG )) {
  1719. //
  1720. // Allocate the Lbcb for the tail of the packed log file.
  1721. //
  1722. LfsAllocateLbcb( Lfcb, &Lfcb->PrevTail );
  1723. Lfcb->PrevTail->FileOffset = Lfcb->FirstLogPage - Lfcb->LogPageSize;
  1724. LfsAllocateLbcb( Lfcb, &Lfcb->ActiveTail );
  1725. Lfcb->ActiveTail->FileOffset = Lfcb->PrevTail->FileOffset - Lfcb->LogPageSize;
  1726. //
  1727. // Remember the different page sizes for reservation.
  1728. //
  1729. (ULONG)Lfcb->ReservedLogPageSize = (ULONG)Lfcb->LogPageDataSize - Lfcb->RecordHeaderLength;
  1730. } else {
  1731. (ULONG)Lfcb->ReservedLogPageSize = (ULONG)Lfcb->LogPageDataSize;
  1732. }
  1733. //
  1734. // Compute the restart page values.
  1735. //
  1736. Lfcb->RestartDataOffset = QuadAlign( LFS_RESTART_PAGE_HEADER_SIZE + (sizeof( UPDATE_SEQUENCE_NUMBER ) * Lfcb->UsaArraySize) );
  1737. Lfcb->RestartDataSize = (ULONG)Lfcb->LogPageSize - Lfcb->RestartDataOffset;
  1738. Lfcb->LogClients = (USHORT) LogClients;
  1739. Lfcb->ClientArrayOffset = FIELD_OFFSET( LFS_RESTART_AREA, LogClientArray );
  1740. Lfcb->RestartAreaSize = Lfcb->ClientArrayOffset
  1741. + (sizeof( LFS_CLIENT_RECORD ) * Lfcb->LogClients );
  1742. Lfcb->CurrentOpenLogCount = OpenLogCount;
  1743. //
  1744. // The total available log file space is the number of log file pages times
  1745. // the space available on each page.
  1746. //
  1747. Lfcb->TotalAvailInPages = Lfcb->FileSize - Lfcb->FirstLogPage;
  1748. Lfcb->TotalAvailable = Int64ShrlMod32(((ULONGLONG)(Lfcb->TotalAvailInPages)), Lfcb->LogPageShift);
  1749. //
  1750. // If the log file is packed we assume that we can't use the end of the
  1751. // page less than the file record size. Then we won't need to reserve more
  1752. // than the caller asks for.
  1753. //
  1754. Lfcb->MaxCurrentAvail = Lfcb->TotalAvailable * (ULONG)Lfcb->ReservedLogPageSize;
  1755. Lfcb->TotalAvailable = Lfcb->TotalAvailable * (ULONG)Lfcb->LogPageDataSize;
  1756. Lfcb->CurrentAvailable = Lfcb->MaxCurrentAvail;
  1757. DebugTrace( -1, Dbg, "LfsUpdateLfcbFromNoRestart: Exit\n", 0 );
  1758. return;
  1759. }
  1760. //
  1761. // Local support routine.
  1762. //
  1763. VOID
  1764. LfsUpdateLfcbFromRestart (
  1765. IN OUT PLFCB Lfcb,
  1766. IN LONGLONG FileSize,
  1767. IN PLFS_RESTART_AREA RestartArea,
  1768. IN USHORT RestartOffset
  1769. )
  1770. /*++
  1771. Routine Description:
  1772. This routine updates the values in the Lfcb based on data in the
  1773. restart area.
  1774. Arguments:
  1775. Lfcb - Log file control block to update.
  1776. RestartArea - Restart area to use to update the Lfcb.
  1777. RestartOffset - This is the offset to the restart area in the restart page.
  1778. Return Value:
  1779. None.
  1780. --*/
  1781. {
  1782. LONGLONG LsnFileOffset;
  1783. PAGED_CODE();
  1784. DebugTrace( +1, Dbg, "LfsUpdateLfcbFromRestartArea: Entered\n", 0 );
  1785. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  1786. DebugTrace( 0, Dbg, "RestartArea -> %08lx\n", RestartArea );
  1787. //
  1788. // Never set the filesize bigger than the actual filesize
  1789. // on clean shutdowns use the real size - on non clean shutdowns
  1790. // let the filesize shrink but not expand - we're stuck the the file data bits
  1791. // until the next boot when we can adjust it for the new size
  1792. //
  1793. if (FlagOn( RestartArea->Flags, LFS_CLEAN_SHUTDOWN)) {
  1794. Lfcb->FileSize = FileSize;
  1795. } else {
  1796. Lfcb->FileSize = min( FileSize, RestartArea->FileSize );
  1797. }
  1798. //
  1799. // We get the sequence number bits from the restart area and compute the
  1800. // file data bits.
  1801. //
  1802. Lfcb->SeqNumberBits = RestartArea->SeqNumberBits;
  1803. Lfcb->FileDataBits = (sizeof( LSN ) * 8) - Lfcb->SeqNumberBits;
  1804. //
  1805. // We look at the last flushed Lsn to determine the current sequence count and
  1806. // the next log page to examine.
  1807. //
  1808. Lfcb->LastFlushedLsn = RestartArea->CurrentLsn;
  1809. Lfcb->SeqNumber = LfsLsnToSeqNumber( Lfcb, Lfcb->LastFlushedLsn );
  1810. Lfcb->SeqNumberForWrap = Lfcb->SeqNumber + 1;
  1811. //
  1812. // The restart area size depends on the number of clients and whether the
  1813. // the file is packed.
  1814. //
  1815. Lfcb->LogClients = RestartArea->LogClients;
  1816. //
  1817. // Compute the restart page values from the restart offset.
  1818. //
  1819. Lfcb->RestartDataOffset = RestartOffset;
  1820. Lfcb->RestartDataSize = (ULONG)Lfcb->LogPageSize - RestartOffset;
  1821. //
  1822. // For a packed log file we can find the following values in the restart
  1823. // area. Otherwise we compute them from the current structure sizes.
  1824. //
  1825. if (FlagOn( Lfcb->Flags, LFCB_PACK_LOG )) {
  1826. Lfcb->RecordHeaderLength = RestartArea->RecordHeaderLength;
  1827. Lfcb->ClientArrayOffset = RestartArea->ClientArrayOffset;
  1828. Lfcb->RestartAreaSize = RestartArea->RestartAreaLength;
  1829. (ULONG)Lfcb->LogPageDataOffset = RestartArea->LogPageDataOffset;
  1830. Lfcb->LogPageDataSize = Lfcb->LogPageSize - Lfcb->LogPageDataOffset;
  1831. //
  1832. // For packed files we allocate the tail Lbcbs.
  1833. //
  1834. LfsAllocateLbcb( Lfcb, &Lfcb->PrevTail );
  1835. Lfcb->PrevTail->FileOffset = Lfcb->FirstLogPage - Lfcb->LogPageSize;
  1836. LfsAllocateLbcb( Lfcb, &Lfcb->ActiveTail );
  1837. Lfcb->ActiveTail->FileOffset = Lfcb->PrevTail->FileOffset - Lfcb->LogPageSize;
  1838. //
  1839. // Remember the different page sizes for reservation.
  1840. //
  1841. (ULONG)Lfcb->ReservedLogPageSize = (ULONG)Lfcb->LogPageDataSize - Lfcb->RecordHeaderLength;
  1842. } else {
  1843. Lfcb->RecordHeaderLength = LFS_RECORD_HEADER_SIZE;
  1844. Lfcb->ClientArrayOffset = FIELD_OFFSET( LFS_OLD_RESTART_AREA, LogClientArray );
  1845. Lfcb->RestartAreaSize = Lfcb->ClientArrayOffset
  1846. + (sizeof( LFS_CLIENT_RECORD ) * Lfcb->LogClients);
  1847. (ULONG)Lfcb->LogPageDataOffset = QuadAlign( Lfcb->LogRecordUsaOffset + (sizeof( UPDATE_SEQUENCE_NUMBER ) * Lfcb->UsaArraySize) );
  1848. Lfcb->LogPageDataSize = Lfcb->LogPageSize - Lfcb->LogPageDataOffset;
  1849. (ULONG)Lfcb->ReservedLogPageSize = (ULONG)Lfcb->LogPageDataSize;
  1850. }
  1851. //
  1852. // If the current last flushed Lsn offset is before the first log page
  1853. // then this is a pseudo Lsn.
  1854. //
  1855. LsnFileOffset = LfsLsnToFileOffset( Lfcb, Lfcb->LastFlushedLsn );
  1856. if ( LsnFileOffset < Lfcb->FirstLogPage ) {
  1857. SetFlag( Lfcb->Flags, LFCB_NO_LAST_LSN );
  1858. Lfcb->NextLogPage = Lfcb->FirstLogPage;
  1859. //
  1860. // Otherwise look at the last Lsn to determine where it ends in the file.
  1861. //
  1862. } else {
  1863. LONGLONG LsnFinalOffset;
  1864. BOOLEAN Wrapped;
  1865. ULONG DataLength;
  1866. ULONG RemainingPageBytes;
  1867. DataLength = RestartArea->LastLsnDataLength;
  1868. //
  1869. // Find the end of this log record.
  1870. //
  1871. LfsLsnFinalOffset( Lfcb,
  1872. Lfcb->LastFlushedLsn,
  1873. DataLength,
  1874. &LsnFinalOffset );
  1875. //
  1876. // If we wrapped in the file then increment the sequence number.
  1877. //
  1878. if ( LsnFinalOffset <= LsnFileOffset ) {
  1879. Lfcb->SeqNumber = 1 + Lfcb->SeqNumber;
  1880. SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED );
  1881. }
  1882. //
  1883. // Now compute the next log page to use. If we are packing the log file
  1884. // we will attempt to use the same page.
  1885. //
  1886. LfsTruncateOffsetToLogPage( Lfcb, LsnFinalOffset, &LsnFileOffset );
  1887. RemainingPageBytes = (ULONG)Lfcb->LogPageSize
  1888. - ((((ULONG)LsnFinalOffset) & Lfcb->LogPageMask) + 1);
  1889. //
  1890. // If we are packing the log file and we can fit another log record on the
  1891. // page, move back a page in the log file.
  1892. //
  1893. if (FlagOn( Lfcb->Flags, LFCB_PACK_LOG )
  1894. && (RemainingPageBytes >= Lfcb->RecordHeaderLength)) {
  1895. SetFlag( Lfcb->Flags, LFCB_REUSE_TAIL );
  1896. Lfcb->NextLogPage = LsnFileOffset;
  1897. Lfcb->ReusePageOffset = (ULONG)Lfcb->LogPageSize - RemainingPageBytes;
  1898. } else {
  1899. LfsNextLogPageOffset( Lfcb, LsnFileOffset, &Lfcb->NextLogPage, &Wrapped );
  1900. }
  1901. }
  1902. //
  1903. // Find the oldest client Lsn. Use the last flushed Lsn as a starting point.
  1904. //
  1905. Lfcb->OldestLsn = Lfcb->LastFlushedLsn;
  1906. LfsFindOldestClientLsn( RestartArea,
  1907. Add2Ptr( RestartArea, Lfcb->ClientArrayOffset, PLFS_CLIENT_RECORD ),
  1908. &Lfcb->OldestLsn );
  1909. Lfcb->OldestLsnOffset = LfsLsnToFileOffset( Lfcb, Lfcb->OldestLsn );
  1910. //
  1911. // If there is no oldest client Lsn, then update the flag in the Lfcb.
  1912. //
  1913. if ( Lfcb->OldestLsnOffset < Lfcb->FirstLogPage ) {
  1914. SetFlag( Lfcb->Flags, LFCB_NO_OLDEST_LSN );
  1915. }
  1916. //
  1917. // We need to determine the flags for the Lfcb. These flags let us know
  1918. // if we wrapped in the file and if we are using multiple page I/O.
  1919. //
  1920. if (!FlagOn( RestartArea->Flags, RESTART_SINGLE_PAGE_IO )) {
  1921. SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED | LFCB_MULTIPLE_PAGE_IO );
  1922. }
  1923. //
  1924. // Remember the current open log count from the disk. We may be plucking random data out
  1925. // of the client area if the restart area hasn't been grown yet but we will detect that
  1926. // elsewhere.
  1927. //
  1928. Lfcb->CurrentOpenLogCount = RestartArea->RestartOpenLogCount;
  1929. //
  1930. // The total available log file space is the number of log file pages times
  1931. // the space available on each page.
  1932. //
  1933. Lfcb->TotalAvailInPages = Lfcb->FileSize - Lfcb->FirstLogPage;
  1934. Lfcb->TotalAvailable = Int64ShrlMod32(((ULONGLONG)(Lfcb->TotalAvailInPages)), Lfcb->LogPageShift);
  1935. //
  1936. // If the log file is packed we assume that we can't use the end of the
  1937. // page less than the file record size. Then we won't need to reserve more
  1938. // than the caller asks for.
  1939. //
  1940. Lfcb->MaxCurrentAvail = Lfcb->TotalAvailable * (ULONG)Lfcb->ReservedLogPageSize;
  1941. Lfcb->TotalAvailable = Lfcb->TotalAvailable * (ULONG)Lfcb->LogPageDataSize;
  1942. LfsFindCurrentAvail( Lfcb );
  1943. DebugTrace( -1, Dbg, "LfsUpdateLfcbFromRestartArea: Exit\n", 0 );
  1944. return;
  1945. }
  1946. //
  1947. // Local support routine
  1948. //
  1949. VOID
  1950. LfsUpdateRestartAreaFromLfcb (
  1951. IN PLFCB Lfcb,
  1952. IN PLFS_RESTART_AREA RestartArea
  1953. )
  1954. /*++
  1955. Routine Description:
  1956. This routine is called to update a restart area from the values stored
  1957. in the Lfcb. This is typically done in a case where we won't use
  1958. any of the current values in the restart area.
  1959. Arguments:
  1960. Lfcb - Log file control block.
  1961. RestartArea - Restart area to update.
  1962. Return Value:
  1963. None.
  1964. --*/
  1965. {
  1966. PLFS_CLIENT_RECORD Client;
  1967. USHORT ClientIndex;
  1968. USHORT PrevClient = LFS_NO_CLIENT;
  1969. PAGED_CODE();
  1970. DebugTrace( +1, Dbg, "LfsUpdateRestartAreaFromLfcb: Entered\n", 0 );
  1971. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  1972. //
  1973. // We can copy most of the fields directly out of Lfcb.
  1974. //
  1975. RestartArea->CurrentLsn = Lfcb->LastFlushedLsn;
  1976. RestartArea->LogClients = Lfcb->LogClients;
  1977. if (!FlagOn( Lfcb->Flags, LFCB_MULTIPLE_PAGE_IO )) {
  1978. SetFlag( RestartArea->Flags, RESTART_SINGLE_PAGE_IO );
  1979. }
  1980. RestartArea->SeqNumberBits = Lfcb->SeqNumberBits;
  1981. RestartArea->FileSize = Lfcb->FileSize;
  1982. RestartArea->LastLsnDataLength = 0;
  1983. RestartArea->ClientArrayOffset = Lfcb->ClientArrayOffset;
  1984. RestartArea->RestartAreaLength = (USHORT) Lfcb->RestartAreaSize;
  1985. RestartArea->RecordHeaderLength = Lfcb->RecordHeaderLength;
  1986. RestartArea->LogPageDataOffset = (USHORT)Lfcb->LogPageDataOffset;
  1987. //
  1988. // We set the in use list as empty and the free list as containing
  1989. // all of the client entries.
  1990. //
  1991. RestartArea->ClientInUseList = LFS_NO_CLIENT;
  1992. RestartArea->ClientFreeList = 0;
  1993. for (ClientIndex = 1,
  1994. Client = Add2Ptr( RestartArea, Lfcb->ClientArrayOffset, PLFS_CLIENT_RECORD );
  1995. ClientIndex < Lfcb->LogClients;
  1996. ClientIndex += 1,
  1997. Client++) {
  1998. Client->PrevClient = PrevClient;
  1999. Client->NextClient = ClientIndex;
  2000. PrevClient = ClientIndex - 1;
  2001. }
  2002. //
  2003. // We're now at the last client.
  2004. //
  2005. Client->PrevClient = PrevClient;
  2006. Client->NextClient = LFS_NO_CLIENT;
  2007. //
  2008. // Use the current value out of the Lfcb to stamp this usage of the log file.
  2009. //
  2010. RestartArea->RestartOpenLogCount = Lfcb->CurrentOpenLogCount + 1;
  2011. DebugTrace( -1, Dbg, "LfsUpdateRestartAreaFromLfcb: Exit\n", 0 );
  2012. return;
  2013. }
  2014. //
  2015. // Local support routine.
  2016. //
  2017. VOID
  2018. LfsInitializeLogFilePriv (
  2019. IN PLFCB Lfcb,
  2020. IN BOOLEAN ForceRestartToDisk,
  2021. IN ULONG RestartAreaSize,
  2022. IN LONGLONG StartOffsetForClear,
  2023. IN BOOLEAN ClearLogFile
  2024. )
  2025. /*++
  2026. Routine Description:
  2027. This routine is our internal routine for initializing a log file.
  2028. This can be the case where we are updating the log file for
  2029. update sequence array, or differing page size or new log file size.
  2030. Arguments:
  2031. Lfcb - This is the Lfcb for this log file. It should already have
  2032. the version number information stored.
  2033. ForceRestartToDisk - Indicates that we want to actually force restart
  2034. areas to disk instead of simply queueing them to the start of the
  2035. workqueue.
  2036. RestartAreaSize - This is the size for the restart areas. This may
  2037. be larger than the size in the Lfcb because we may be clearing
  2038. stale data out of the file.
  2039. StartOffsetForClear - If we are clearing the file we want to uninitialize
  2040. from this point.
  2041. ClearLogFile - Indicates if we want to uninitialize the log file to
  2042. remove stale data. This is done specifically when changing
  2043. system page sizes.
  2044. Return Value:
  2045. None
  2046. --*/
  2047. {
  2048. PAGED_CODE();
  2049. DebugTrace( +1, Dbg, "LfsInitializeLogFilePriv: Entered\n", 0 );
  2050. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  2051. DebugTrace( 0, Dbg, "Force Restart -> %04x\n", ForceRestartToDisk );
  2052. DebugTrace( 0, Dbg, "RestartAreaSize -> %08lx\n", RestartAreaSize );
  2053. DebugTrace( 0, Dbg, "StartOffset (Low) -> %08lx\n", StartOffsetForClear.LowPart );
  2054. DebugTrace( 0, Dbg, "StartOffset (High) -> %08lx\n", StartOffsetForClear.HighPart );
  2055. DebugTrace( 0, Dbg, "Clear Log File -> %04x\n", ClearLogFile );
  2056. //
  2057. // We start by queueing the restart areas.
  2058. //
  2059. LfsWriteLfsRestart( Lfcb,
  2060. RestartAreaSize,
  2061. FALSE );
  2062. LfsWriteLfsRestart( Lfcb,
  2063. RestartAreaSize,
  2064. ForceRestartToDisk );
  2065. //
  2066. // If we are to clear the log file, we write all 0xff into the
  2067. // log pages beginning at the log page offset.
  2068. //
  2069. if (ClearLogFile) {
  2070. PCHAR LogPage;
  2071. PBCB LogPageBcb = NULL;
  2072. try {
  2073. while ( StartOffsetForClear < Lfcb->FileSize ) {
  2074. BOOLEAN UsaError;
  2075. //
  2076. // We'll do the best we can and ignore all errors.
  2077. //
  2078. if (NT_SUCCESS( LfsPinOrMapData( Lfcb,
  2079. StartOffsetForClear,
  2080. (ULONG)Lfcb->LogPageSize,
  2081. TRUE,
  2082. FALSE,
  2083. TRUE,
  2084. &UsaError,
  2085. (PVOID *) &LogPage,
  2086. &LogPageBcb ))) {
  2087. RtlFillMemoryUlong( (PVOID)LogPage,
  2088. (ULONG)Lfcb->LogPageSize,
  2089. LFS_SIGNATURE_UNINITIALIZED_ULONG );
  2090. LfsFlushLogPage( Lfcb,
  2091. LogPage,
  2092. StartOffsetForClear,
  2093. &LogPageBcb );
  2094. StartOffsetForClear = Lfcb->LogPageSize + StartOffsetForClear;
  2095. }
  2096. }
  2097. } finally {
  2098. if (LogPageBcb != NULL) {
  2099. CcUnpinData( LogPageBcb );
  2100. }
  2101. }
  2102. }
  2103. DebugTrace( -1, Dbg, "LfsInitializeLogFilePriv: Exit\n", 0 );
  2104. return;
  2105. }
  2106. //
  2107. // Local support routine.
  2108. //
  2109. VOID
  2110. LfsFindLastLsn (
  2111. IN OUT PLFCB Lfcb
  2112. )
  2113. /*++
  2114. Routine Description:
  2115. This routine walks through the log pages for a file, searching for the
  2116. last log page written to the file. It updates the Lfcb and the current
  2117. restart area as well.
  2118. We proceed in the following manner.
  2119. 1 - Walk through and find all of the log pages successfully
  2120. flushed to disk. This search terminates when either we find
  2121. an error or when we find a previous page on the disk.
  2122. 2 - For the error case above, we want to insure that the error found
  2123. was due to a system crash and that there are no complete I/O
  2124. transfers after the bad region.
  2125. 3 - We will look at the 2 pages with the tail copies if the log file
  2126. is packed to check on pages with errors.
  2127. At the end of this routine we will repair the log file by copying the tail
  2128. copies back to their correct location in the log file.
  2129. Arguments:
  2130. Lfcb - Log file control block for this log file.
  2131. Return Value:
  2132. None.
  2133. --*/
  2134. {
  2135. USHORT PageCount;
  2136. USHORT PagePosition;
  2137. LONGLONG CurrentLogPageOffset;
  2138. LONGLONG NextLogPageOffset;
  2139. LSN LastKnownLsn;
  2140. BOOLEAN Wrapped;
  2141. BOOLEAN WrappedLogFile = FALSE;
  2142. LONGLONG ExpectedSeqNumber;
  2143. LONGLONG FirstPartialIo;
  2144. ULONG PartialIoCount = 0;
  2145. PLFS_RECORD_PAGE_HEADER LogPageHeader;
  2146. PBCB LogPageHeaderBcb = NULL;
  2147. PLFS_RECORD_PAGE_HEADER TestPageHeader;
  2148. PBCB TestPageHeaderBcb = NULL;
  2149. LONGLONG FirstTailFileOffset;
  2150. PLFS_RECORD_PAGE_HEADER FirstTailPage;
  2151. LONGLONG FirstTailOffset = 0;
  2152. PBCB FirstTailPageBcb = NULL;
  2153. LONGLONG SecondTailFileOffset;
  2154. PLFS_RECORD_PAGE_HEADER SecondTailPage;
  2155. LONGLONG SecondTailOffset = 0;
  2156. PBCB SecondTailPageBcb = NULL;
  2157. PLFS_RECORD_PAGE_HEADER TailPage;
  2158. BOOLEAN UsaError;
  2159. BOOLEAN ReplacePage = FALSE;
  2160. BOOLEAN ValidFile = FALSE;
  2161. BOOLEAN InitialReusePage = FALSE;
  2162. NTSTATUS Status;
  2163. PAGED_CODE();
  2164. DebugTrace( +1, Dbg, "LfsFindLastLsn: Entered\n", 0 );
  2165. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  2166. //
  2167. // The page count and page position are from the last page
  2168. // sucessfully read. Initialize these to indicate the
  2169. // 'previous' transfer was complete.
  2170. //
  2171. PageCount = 1;
  2172. PagePosition = 1;
  2173. //
  2174. // We have the current Lsn in the restart area. This is the last
  2175. // Lsn on a log page. We compute the next file offset and sequence
  2176. // number.
  2177. //
  2178. CurrentLogPageOffset = Lfcb->NextLogPage;
  2179. //
  2180. // If the next log page is the first log page in the file and
  2181. // the last Lsn represented a log record, then remember that we
  2182. // have wrapped in the log file.
  2183. //
  2184. if ((CurrentLogPageOffset == Lfcb->FirstLogPage) &&
  2185. !FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_REUSE_TAIL )) {
  2186. ExpectedSeqNumber = Lfcb->SeqNumber + 1;
  2187. WrappedLogFile = TRUE;
  2188. } else {
  2189. ExpectedSeqNumber = Lfcb->SeqNumber;
  2190. }
  2191. //
  2192. // If we are going to try to reuse the tail of the last known
  2193. // page, then remember the last Lsn on this page.
  2194. //
  2195. if (FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL )) {
  2196. LastKnownLsn = Lfcb->LastFlushedLsn;
  2197. //
  2198. // There are some special conditions allowed for this page when
  2199. // we read it. It could be either the first or last of the transfer.
  2200. // It may also have a tail copy.
  2201. //
  2202. InitialReusePage = TRUE;
  2203. } else {
  2204. LastKnownLsn = LfsLi0;
  2205. }
  2206. //
  2207. // Use a try-finally to facilitate cleanup.
  2208. //
  2209. try {
  2210. //
  2211. // If this is a packed log file, let's pin the two tail copy pages.
  2212. //
  2213. if (FlagOn( Lfcb->Flags, LFCB_PACK_LOG )) {
  2214. //
  2215. // Start with the second page.
  2216. //
  2217. SecondTailFileOffset = Lfcb->FirstLogPage - Lfcb->LogPageSize;
  2218. if (NT_SUCCESS( LfsPinOrMapData( Lfcb,
  2219. SecondTailFileOffset,
  2220. (ULONG)Lfcb->LogPageSize,
  2221. TRUE,
  2222. TRUE,
  2223. TRUE,
  2224. &UsaError,
  2225. &SecondTailPage,
  2226. &SecondTailPageBcb ))) {
  2227. //
  2228. // If this isn't a valid page then ignore it.
  2229. //
  2230. if (UsaError
  2231. || *((PULONG) &SecondTailPage->MultiSectorHeader.Signature) != LFS_SIGNATURE_RECORD_PAGE_ULONG) {
  2232. CcUnpinData( SecondTailPageBcb );
  2233. SecondTailPageBcb = SecondTailPage = NULL;
  2234. } else {
  2235. SecondTailOffset = SecondTailPage->Copy.FileOffset;
  2236. }
  2237. } else if (SecondTailPageBcb != NULL) {
  2238. CcUnpinData( SecondTailPageBcb );
  2239. SecondTailPageBcb = SecondTailPage = NULL;
  2240. }
  2241. FirstTailFileOffset = SecondTailFileOffset - Lfcb->LogPageSize;
  2242. //
  2243. // Now try the first.
  2244. //
  2245. if (NT_SUCCESS( LfsPinOrMapData( Lfcb,
  2246. FirstTailFileOffset,
  2247. (ULONG)Lfcb->LogPageSize,
  2248. TRUE,
  2249. TRUE,
  2250. TRUE,
  2251. &UsaError,
  2252. &FirstTailPage,
  2253. &FirstTailPageBcb ))) {
  2254. //
  2255. // If this isn't a valid page then ignore it.
  2256. //
  2257. if (UsaError
  2258. || *((PULONG) &FirstTailPage->MultiSectorHeader.Signature) != LFS_SIGNATURE_RECORD_PAGE_ULONG) {
  2259. CcUnpinData( FirstTailPageBcb );
  2260. FirstTailPageBcb = FirstTailPage = NULL;
  2261. } else {
  2262. FirstTailOffset = FirstTailPage->Copy.FileOffset;
  2263. }
  2264. } else if (FirstTailPageBcb != NULL) {
  2265. CcUnpinData( FirstTailPageBcb );
  2266. FirstTailPageBcb = FirstTailPage = NULL;
  2267. }
  2268. }
  2269. //
  2270. // We continue walking through the file, log page by log page looking
  2271. // for the end of the data transferred. The loop below looks for
  2272. // a log page which contains the end of a log record. Each time a
  2273. // log record is successfully read from the disk, we update our in-memory
  2274. // structures to reflect this. We exit this loop when we are at a point
  2275. // where we don't want to find any subsequent pages. This occurs when
  2276. //
  2277. // - we get an I/O error reading a page
  2278. // - we get a Usa error reading a page
  2279. // - we have a tail copy with more recent data than contained on the page
  2280. //
  2281. while (TRUE) {
  2282. LONGLONG ActualSeqNumber;
  2283. TailPage = NULL;
  2284. //
  2285. // Pin the next log page, allowing errors.
  2286. //
  2287. Status = LfsPinOrMapData( Lfcb,
  2288. CurrentLogPageOffset,
  2289. (ULONG)Lfcb->LogPageSize,
  2290. TRUE,
  2291. TRUE,
  2292. TRUE,
  2293. &UsaError,
  2294. (PVOID *) &LogPageHeader,
  2295. &LogPageHeaderBcb );
  2296. //
  2297. // Compute the next log page offset in the file.
  2298. //
  2299. LfsNextLogPageOffset( Lfcb,
  2300. CurrentLogPageOffset,
  2301. &NextLogPageOffset,
  2302. &Wrapped );
  2303. //
  2304. // If we are at the expected first page of a transfer
  2305. // check to see if either tail copy is at this offset.
  2306. // If this page is the last page of a transfer, check
  2307. // if we wrote a subsequent tail copy.
  2308. //
  2309. if (FlagOn( Lfcb->Flags, LFCB_PACK_LOG ) &&
  2310. ((PageCount == PagePosition) ||
  2311. (PageCount == PagePosition + 1))) {
  2312. //
  2313. // Check if the offset matches either the first or second
  2314. // tail copy. It is possible it will match both.
  2315. //
  2316. if (CurrentLogPageOffset == FirstTailOffset) {
  2317. TailPage = FirstTailPage;
  2318. }
  2319. if (CurrentLogPageOffset == SecondTailOffset) {
  2320. //
  2321. // If we already matched on the first page then
  2322. // check the ending Lsn's.
  2323. //
  2324. if ((TailPage == NULL) ||
  2325. (SecondTailPage->Header.Packed.LastEndLsn.QuadPart >
  2326. FirstTailPage->Header.Packed.LastEndLsn.QuadPart )) {
  2327. TailPage = SecondTailPage;
  2328. }
  2329. }
  2330. //
  2331. // If we have a candidate for a tail copy, check and see if it is
  2332. // in the expected pass through the file. For that to be true we
  2333. // must be at the first page of an I/O block. Also the last Lsn on the
  2334. // copy page must match the last known flushed Lsn or the sequence
  2335. // number on the page must be the expected sequence number.
  2336. //
  2337. if (TailPage) {
  2338. if (LastKnownLsn.QuadPart < TailPage->Header.Packed.LastEndLsn.QuadPart) {
  2339. ActualSeqNumber = LfsLsnToSeqNumber( Lfcb, TailPage->Header.Packed.LastEndLsn );
  2340. //
  2341. // If the sequence number is not expected, then don't use the tail
  2342. // copy.
  2343. //
  2344. if (ExpectedSeqNumber != ActualSeqNumber) {
  2345. TailPage = NULL;
  2346. }
  2347. //
  2348. // If the last Lsn is greater than the one on this page
  2349. // then forget this tail.
  2350. //
  2351. } else if (LastKnownLsn.QuadPart > TailPage->Header.Packed.LastEndLsn.QuadPart) {
  2352. TailPage = NULL;
  2353. }
  2354. }
  2355. }
  2356. //
  2357. // If we have an error on the current page, we will break out of
  2358. // this loop.
  2359. //
  2360. if (!NT_SUCCESS( Status ) || UsaError) {
  2361. break;
  2362. }
  2363. //
  2364. // If the last Lsn on this page doesn't match the previous
  2365. // known last Lsn and the sequence number is not expected
  2366. // we are done.
  2367. //
  2368. ActualSeqNumber = LfsLsnToSeqNumber( Lfcb,
  2369. LogPageHeader->Copy.LastLsn );
  2370. if ((LastKnownLsn.QuadPart != LogPageHeader->Copy.LastLsn.QuadPart) &&
  2371. (ActualSeqNumber != ExpectedSeqNumber)) {
  2372. break;
  2373. }
  2374. //
  2375. // Check that the page position and page count values are correct.
  2376. // If this is the first page of a transfer the position must be
  2377. // 1 and the count will be unknown.
  2378. //
  2379. if (PageCount == PagePosition) {
  2380. //
  2381. // If the current page is the first page we are looking at
  2382. // and we are reusing this page then it can be either the
  2383. // first or last page of a transfer. Otherwise it can only
  2384. // be the first.
  2385. //
  2386. if ((LogPageHeader->PagePosition != 1) &&
  2387. (!InitialReusePage ||
  2388. (LogPageHeader->PagePosition != LogPageHeader->PageCount))) {
  2389. break;
  2390. }
  2391. //
  2392. // The page position better be 1 more than the last page position
  2393. // and the page count better match.
  2394. //
  2395. } else if ((LogPageHeader->PageCount != PageCount) ||
  2396. (LogPageHeader->PagePosition != PagePosition + 1)) {
  2397. break;
  2398. }
  2399. //
  2400. // We have a valid page in the file and may have a valid page in
  2401. // the tail copy area. If the tail page was written after
  2402. // the page in the file then break out of the loop.
  2403. //
  2404. if (TailPage &&
  2405. (TailPage->Header.Packed.LastEndLsn.QuadPart >= LogPageHeader->Copy.LastLsn.QuadPart)) {
  2406. //
  2407. // Remember if we will replace the page.
  2408. //
  2409. ReplacePage = TRUE;
  2410. break;
  2411. }
  2412. TailPage = NULL;
  2413. //
  2414. // The log page is expected. If this contains the end of
  2415. // some log record we can update some fields in the Lfcb.
  2416. //
  2417. if (FlagOn( LogPageHeader->Flags, LOG_PAGE_LOG_RECORD_END )) {
  2418. //
  2419. // Since we have read this page we know the Lfcb sequence
  2420. // number is the same as our expected value. We also
  2421. // assume we will not reuse the tail.
  2422. //
  2423. Lfcb->SeqNumber = ExpectedSeqNumber;
  2424. ClearFlag( Lfcb->Flags, LFCB_REUSE_TAIL );
  2425. if (FlagOn( Lfcb->Flags, LFCB_PACK_LOG )) {
  2426. Lfcb->LastFlushedLsn = LogPageHeader->Header.Packed.LastEndLsn;
  2427. //
  2428. // If there is room on this page for another header then
  2429. // remember we want to reuse the page.
  2430. //
  2431. if (Lfcb->RecordHeaderLength <=
  2432. ((ULONG)Lfcb->LogPageSize - LogPageHeader->Header.Packed.NextRecordOffset )) {
  2433. SetFlag( Lfcb->Flags, LFCB_REUSE_TAIL );
  2434. Lfcb->ReusePageOffset = LogPageHeader->Header.Packed.NextRecordOffset;
  2435. }
  2436. } else {
  2437. Lfcb->LastFlushedLsn = LogPageHeader->Copy.LastLsn;
  2438. }
  2439. Lfcb->RestartArea->CurrentLsn = Lfcb->LastFlushedLsn;
  2440. ClearFlag( Lfcb->Flags, LFCB_NO_LAST_LSN );
  2441. //
  2442. // If we may try to reuse the current page then use
  2443. // that as the next page offset. Otherwise move to the
  2444. // next page in the file.
  2445. //
  2446. if (FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL )) {
  2447. Lfcb->NextLogPage = CurrentLogPageOffset;
  2448. } else {
  2449. Lfcb->NextLogPage = NextLogPageOffset;
  2450. }
  2451. //
  2452. // If we wrapped the log file, then we set the bit indicating so.
  2453. //
  2454. if (WrappedLogFile) {
  2455. SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED );
  2456. }
  2457. }
  2458. //
  2459. // Remember the last page count and position. Also remember
  2460. // the last known lsn.
  2461. //
  2462. PageCount = LogPageHeader->PageCount;
  2463. PagePosition = LogPageHeader->PagePosition;
  2464. LastKnownLsn = LogPageHeader->Copy.LastLsn;
  2465. //
  2466. // If we are wrapping to the beginning of the file then update
  2467. // the expected sequence number.
  2468. //
  2469. if (Wrapped) {
  2470. ExpectedSeqNumber = ExpectedSeqNumber + 1;
  2471. WrappedLogFile = TRUE;
  2472. }
  2473. CurrentLogPageOffset = NextLogPageOffset;
  2474. //
  2475. // Unpin the last log page pinned.
  2476. //
  2477. CcUnpinData( LogPageHeaderBcb );
  2478. LogPageHeaderBcb = NULL;
  2479. InitialReusePage = FALSE;
  2480. }
  2481. //
  2482. // At this point we expect that there will be no more new pages in
  2483. // the log file. We could have had an error of some sort on the most recent
  2484. // page or we may have found a tail copy for the current page.
  2485. // If the error occurred on the last Io to the file then
  2486. // this log file is useful. Otherwise the log file can't be used.
  2487. //
  2488. //
  2489. // If we have a tail copy page then update the values in the
  2490. // Lfcb and restart area.
  2491. //
  2492. if (TailPage != NULL) {
  2493. //
  2494. // Since we have read this page we know the Lfcb sequence
  2495. // number is the same as our expected value.
  2496. //
  2497. Lfcb->SeqNumber = ExpectedSeqNumber;
  2498. Lfcb->LastFlushedLsn = TailPage->Header.Packed.LastEndLsn;
  2499. Lfcb->RestartArea->CurrentLsn = Lfcb->LastFlushedLsn;
  2500. ClearFlag( Lfcb->Flags, LFCB_NO_LAST_LSN );
  2501. //
  2502. // If there is room on this page for another header then
  2503. // remember we want to reuse the page.
  2504. //
  2505. if (((ULONG)Lfcb->LogPageSize - TailPage->Header.Packed.NextRecordOffset )
  2506. >= Lfcb->RecordHeaderLength) {
  2507. SetFlag( Lfcb->Flags, LFCB_REUSE_TAIL );
  2508. Lfcb->NextLogPage = CurrentLogPageOffset;
  2509. Lfcb->ReusePageOffset = TailPage->Header.Packed.NextRecordOffset;
  2510. } else {
  2511. ClearFlag( Lfcb->Flags, LFCB_REUSE_TAIL );
  2512. Lfcb->NextLogPage = NextLogPageOffset;
  2513. }
  2514. //
  2515. // If we wrapped the log file, then we set the bit indicating so.
  2516. //
  2517. if (WrappedLogFile) {
  2518. SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED );
  2519. }
  2520. }
  2521. //
  2522. // Remember that the partial IO will start at the next page.
  2523. //
  2524. FirstPartialIo = NextLogPageOffset;
  2525. //
  2526. // If the next page is the first page of the file then update
  2527. // the sequence number for log records which begin on the next
  2528. // page.
  2529. //
  2530. if (Wrapped) {
  2531. ExpectedSeqNumber = ExpectedSeqNumber + 1;
  2532. }
  2533. //
  2534. // If we know the length of the transfer containing the page we stopped
  2535. // on we can just go to the page following the transfer and check
  2536. // the sequence number. If we replaced the page then we have already
  2537. // modified the numbers. If we know that only single pages were written
  2538. // to disk then we will munge the numbers now. If we were in the
  2539. // middle of a multi-page I/O then the numbers are already set up.
  2540. //
  2541. //
  2542. // If we have a tail copy or are performing single page I/O
  2543. // we can immediately look at the next page.
  2544. //
  2545. if (ReplacePage ||
  2546. FlagOn( Lfcb->RestartArea->Flags, RESTART_SINGLE_PAGE_IO )) {
  2547. //
  2548. // Fudge the counts to show that we don't need swallow any pages.
  2549. //
  2550. PageCount = 2;
  2551. PagePosition = 1;
  2552. //
  2553. // If the counts match it means the current page should be the first
  2554. // page of a transfer. We need to walk forward enough to guarantee
  2555. // that there was no subsequent transfer that made it out to disk.
  2556. //
  2557. } else if (PagePosition == PageCount) {
  2558. USHORT CurrentPosition;
  2559. //
  2560. // If the next page causes us to wrap to the beginning of the log
  2561. // file then we know which page to check next.
  2562. //
  2563. if (Wrapped) {
  2564. //
  2565. // Fudge the counts to show that we don't need swallow any pages.
  2566. //
  2567. PageCount = 2;
  2568. PagePosition = 1;
  2569. //
  2570. // Walk forward looking for a page which is from a different IO transfer
  2571. // from the page we failed on.
  2572. //
  2573. } else {
  2574. //
  2575. // We need to find a log page we know is not part of the log
  2576. // page which caused the original error.
  2577. //
  2578. // Maintain the count within the current transfer.
  2579. //
  2580. CurrentPosition = 2;
  2581. do {
  2582. //
  2583. // We walk through the file, reading log pages. If we find
  2584. // a readable log page that must lie in a subsequent Io block,
  2585. // we exit.
  2586. //
  2587. if (TestPageHeaderBcb != NULL) {
  2588. CcUnpinData( TestPageHeaderBcb );
  2589. TestPageHeaderBcb = NULL;
  2590. }
  2591. Status = LfsPinOrMapData( Lfcb,
  2592. NextLogPageOffset,
  2593. (ULONG)Lfcb->LogPageSize,
  2594. TRUE,
  2595. TRUE,
  2596. TRUE,
  2597. &UsaError,
  2598. (PVOID *) &TestPageHeader,
  2599. &TestPageHeaderBcb );
  2600. //
  2601. // If we get a USA error then assume that we correctly
  2602. // found the end of the original transfer.
  2603. //
  2604. if (UsaError) {
  2605. ValidFile = TRUE;
  2606. break;
  2607. //
  2608. // If we were able to read the page, we examine it to see
  2609. // if it is in the same or different Io block.
  2610. //
  2611. } else if (NT_SUCCESS( Status )) {
  2612. //
  2613. // If this page is part of the error causing I/O, we will
  2614. // use the transfer length to determine the page to
  2615. // read for a subsequent error.
  2616. //
  2617. if ((TestPageHeader->PagePosition == CurrentPosition) &&
  2618. LfsCheckSubsequentLogPage( Lfcb,
  2619. TestPageHeader,
  2620. NextLogPageOffset,
  2621. ExpectedSeqNumber )) {
  2622. PageCount = TestPageHeader->PageCount + 1;
  2623. PagePosition = TestPageHeader->PagePosition;
  2624. break;
  2625. //
  2626. // We found know the Io causing the error didn't
  2627. // complete. So we have no more checks to do.
  2628. //
  2629. } else {
  2630. ValidFile = TRUE;
  2631. break;
  2632. }
  2633. //
  2634. // Try the next page.
  2635. //
  2636. } else {
  2637. //
  2638. // Move to the next log page.
  2639. //
  2640. LfsNextLogPageOffset( Lfcb,
  2641. NextLogPageOffset,
  2642. &NextLogPageOffset,
  2643. &Wrapped );
  2644. //
  2645. // If the file wrapped then initialize the page count
  2646. // and position so that we will not skip over any
  2647. // pages in the final verification below.
  2648. //
  2649. if (Wrapped) {
  2650. ExpectedSeqNumber = ExpectedSeqNumber + 1;
  2651. PageCount = 2;
  2652. PagePosition = 1;
  2653. }
  2654. CurrentPosition += 1;
  2655. }
  2656. //
  2657. // This is one more page we will want to uninitialize.
  2658. //
  2659. PartialIoCount += 1;
  2660. } while( !Wrapped );
  2661. }
  2662. }
  2663. //
  2664. // If we are unsure whether the file is valid then we will have
  2665. // the count and position in the current transfer. We will walk through
  2666. // this transfer and read the subsequent page.
  2667. //
  2668. if (!ValidFile) {
  2669. ULONG RemainingPages;
  2670. //
  2671. // Skip over the remaining pages in this transfer.
  2672. //
  2673. RemainingPages = (PageCount - PagePosition) - 1;
  2674. PartialIoCount += RemainingPages;
  2675. while (RemainingPages--) {
  2676. LfsNextLogPageOffset( Lfcb,
  2677. NextLogPageOffset,
  2678. &NextLogPageOffset,
  2679. &Wrapped );
  2680. if (Wrapped) {
  2681. ExpectedSeqNumber = ExpectedSeqNumber + 1;
  2682. }
  2683. }
  2684. //
  2685. // Call our routine to check this log page.
  2686. //
  2687. if (TestPageHeaderBcb != NULL) {
  2688. CcUnpinData( TestPageHeaderBcb );
  2689. TestPageHeaderBcb = NULL;
  2690. }
  2691. Status = LfsPinOrMapData( Lfcb,
  2692. NextLogPageOffset,
  2693. (ULONG)Lfcb->LogPageSize,
  2694. TRUE,
  2695. TRUE,
  2696. TRUE,
  2697. &UsaError,
  2698. (PVOID *) &TestPageHeader,
  2699. &TestPageHeaderBcb );
  2700. if (NT_SUCCESS( Status ) && !UsaError) {
  2701. if (LfsCheckSubsequentLogPage( Lfcb,
  2702. TestPageHeader,
  2703. NextLogPageOffset,
  2704. ExpectedSeqNumber )) {
  2705. DebugTrace( 0, Dbg, "Log file is fatally flawed\n", 0 );
  2706. ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
  2707. }
  2708. }
  2709. ValidFile = TRUE;
  2710. }
  2711. //
  2712. // Make sure the current page is unpinned.
  2713. //
  2714. if (LogPageHeaderBcb != NULL) {
  2715. CcUnpinData( LogPageHeaderBcb );
  2716. LogPageHeaderBcb = NULL;
  2717. }
  2718. #ifdef SUPW_DBG
  2719. if ((TailPage != NULL) && FlagOn( Lfcb->Flags, LFCB_READ_ONLY )) {
  2720. DbgPrint("INFO: TailPage isn't getting written because of READ-ONLY (ok)\n");
  2721. }
  2722. if (PartialIoCount && FlagOn( Lfcb->Flags, LFCB_READ_ONLY )) {
  2723. DbgPrint("INFO: PartialIoCount = 0x%x, not writing because of READ-ONLY (ok)\n");
  2724. }
  2725. #endif
  2726. //
  2727. // We have a valid file. The Lfcb is initialized to the point where
  2728. // the last log record was found. We possibly have a copy of the
  2729. // last page in the log file stored as a copy. Or we could just have
  2730. // a page that we would like to reuse the end of.
  2731. //
  2732. if (!FlagOn( Lfcb->Flags, LFCB_READ_ONLY )) {
  2733. if (TailPage != NULL) {
  2734. //
  2735. // We will pin the correct page and copy the data from this
  2736. // page into it. We will then flush it out to disk.
  2737. //
  2738. LfsPinOrMapData( Lfcb,
  2739. TailPage->Copy.FileOffset,
  2740. (ULONG)Lfcb->LogPageSize,
  2741. TRUE,
  2742. FALSE,
  2743. TRUE,
  2744. &UsaError,
  2745. (PVOID *) &LogPageHeader,
  2746. &LogPageHeaderBcb );
  2747. RtlCopyMemory( LogPageHeader,
  2748. TailPage,
  2749. (ULONG)Lfcb->LogPageSize );
  2750. //
  2751. // Fill in last flushed lsn value flush the page.
  2752. //
  2753. LogPageHeader->Copy.LastLsn = TailPage->Header.Packed.LastEndLsn;
  2754. LfsFlushLogPage( Lfcb,
  2755. LogPageHeader,
  2756. TailPage->Copy.FileOffset,
  2757. &LogPageHeaderBcb );
  2758. }
  2759. //
  2760. // We also want to write over any partial I/O so it doesn't cause
  2761. // us problems on a subsequent restart. We have the starting offset
  2762. // and the number of blocks. We will simply write a Baad signature into
  2763. // each of these pages. Any subsequent reads will have a Usa error.
  2764. //
  2765. while (PartialIoCount--) {
  2766. //
  2767. // Make sure the current page is unpinned.
  2768. //
  2769. if (LogPageHeaderBcb != NULL) {
  2770. CcUnpinData( LogPageHeaderBcb );
  2771. LogPageHeaderBcb = NULL;
  2772. }
  2773. if (NT_SUCCESS( LfsPinOrMapData( Lfcb,
  2774. FirstPartialIo,
  2775. (ULONG)Lfcb->LogPageSize,
  2776. TRUE,
  2777. TRUE,
  2778. TRUE,
  2779. &UsaError,
  2780. (PVOID *) &LogPageHeader,
  2781. &LogPageHeaderBcb ))) {
  2782. //
  2783. // Just store a the usa array header in the multi-section
  2784. // header.
  2785. //
  2786. *((PULONG) &LogPageHeader->MultiSectorHeader.Signature) = LFS_SIGNATURE_BAD_USA_ULONG;
  2787. LfsFlushLogPage( Lfcb,
  2788. LogPageHeader,
  2789. FirstPartialIo,
  2790. &LogPageHeaderBcb );
  2791. }
  2792. LfsNextLogPageOffset( Lfcb,
  2793. FirstPartialIo,
  2794. &FirstPartialIo,
  2795. &Wrapped );
  2796. }
  2797. }
  2798. //
  2799. // We used to invalidate any tail pages we reused, now we let them
  2800. // be recopied every restart even if we fail a little later
  2801. //
  2802. } finally {
  2803. DebugUnwind( LfsFindLastLsn );
  2804. //
  2805. // Unpin the tail pages is pinned.
  2806. //
  2807. if (SecondTailPageBcb != NULL) {
  2808. CcUnpinData( SecondTailPageBcb );
  2809. }
  2810. if (FirstTailPageBcb != NULL) {
  2811. CcUnpinData( FirstTailPageBcb );
  2812. }
  2813. //
  2814. // Unpin the log page header if neccessary.
  2815. //
  2816. if (LogPageHeaderBcb != NULL) {
  2817. CcUnpinData( LogPageHeaderBcb );
  2818. }
  2819. if (TestPageHeaderBcb != NULL) {
  2820. CcUnpinData( TestPageHeaderBcb );
  2821. }
  2822. DebugTrace( -1, Dbg, "LfsFindLastLsn: Exit\n", 0 );
  2823. }
  2824. return;
  2825. }
  2826. //
  2827. // Local support routine.
  2828. //
  2829. BOOLEAN
  2830. LfsCheckSubsequentLogPage (
  2831. IN PLFCB Lfcb,
  2832. IN PLFS_RECORD_PAGE_HEADER RecordPageHeader,
  2833. IN LONGLONG LogFileOffset,
  2834. IN LONGLONG SequenceNumber
  2835. )
  2836. /*++
  2837. Routine Description:
  2838. This routine is called to check that a particular log page could not
  2839. have been written after a prior Io transfer. What we are looking for
  2840. is the start of a transfer which was written after an Io which we
  2841. we cannot read from during restart. The presence of an additional
  2842. Io means that we cannot guarantee that we can recover all of the
  2843. restart data for the disk. This makes the disk unrecoverable.
  2844. We are given the sequence number of the Lsn that would occur on this page
  2845. (if it is not part of an Log record which spans the end of a file).
  2846. If we haven't wrapped the file and find an Lsn whose
  2847. sequence number matches this, then we have an error. If we have
  2848. wrapped the file, and the sequence number in the Lsn in the
  2849. first log page is
  2850. written subsequent to a previous failing Io.
  2851. Arguments:
  2852. Lfcb - Log file control block for this log file.
  2853. RecordPageHeader - This is the header of a log page to check.
  2854. LogFileOffset - This is the offset in the log file of this page.
  2855. SequenceNumber - This is the sequence number that this log page should
  2856. not have. This will be the sequence number for
  2857. any log records which begin on this page if written
  2858. after the page that failed.
  2859. Return Value:
  2860. BOOLEAN - TRUE if this log page was written after some previous page,
  2861. FALSE otherwise.
  2862. --*/
  2863. {
  2864. BOOLEAN IsSubsequent;
  2865. LSN Lsn;
  2866. LONGLONG LsnSeqNumber;
  2867. LONGLONG SeqNumberMinus1;
  2868. LONGLONG LogPageFileOffset;
  2869. PAGED_CODE();
  2870. DebugTrace( +1, Dbg, "LfsCheckSubsequentLogPage: Entered\n", 0 );
  2871. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  2872. DebugTrace( 0, Dbg, "RecordPageHeader -> %08lx\n", RecordPageHeader );
  2873. DebugTrace( 0, Dbg, "LogFileOffset (Low) -> %08lx\n", LogFileOffset.LowPart );
  2874. DebugTrace( 0, Dbg, "LogFileOffset (High) -> %08lx\n", LogFileOffset.HighPart );
  2875. DebugTrace( 0, Dbg, "SequenceNumber (Low) -> %08lx\n", SequenceNumber.LowPart );
  2876. DebugTrace( 0, Dbg, "SequenceNumber (High) -> %08lx\n", SequenceNumber.HighPart );
  2877. //
  2878. // If the page header is either 0 or -1 then we say this page was not written
  2879. // after some previous page.
  2880. //
  2881. if (*((PULONG) RecordPageHeader->MultiSectorHeader.Signature) == LFS_SIGNATURE_UNINITIALIZED_ULONG ||
  2882. *((PULONG) RecordPageHeader->MultiSectorHeader.Signature) == 0) {
  2883. DebugTrace( -1, Dbg, "LfsCheckSubsequentLogPage: Exit -> %08x\n", FALSE );
  2884. return FALSE;
  2885. }
  2886. //
  2887. // If the last Lsn on the page occurs was
  2888. // written after the page that caused the original error. Then we
  2889. // have a fatal error.
  2890. //
  2891. Lsn = RecordPageHeader->Copy.LastLsn;
  2892. LfsTruncateLsnToLogPage( Lfcb, Lsn, &LogPageFileOffset );
  2893. LsnSeqNumber = LfsLsnToSeqNumber( Lfcb, Lsn );
  2894. SeqNumberMinus1 = SequenceNumber - 1;
  2895. //
  2896. // If the sequence number for the Lsn in the page is equal or greater than
  2897. // Lsn we expect, then this is a subsequent write.
  2898. //
  2899. if ( LsnSeqNumber >= SequenceNumber ) {
  2900. IsSubsequent = TRUE;
  2901. //
  2902. // If this page is the start of the file and the sequence number is 1 less
  2903. // than we expect and the Lsn indicates that we wrapped the file, then it
  2904. // is also part of a subsequent io.
  2905. //
  2906. // The following test checks
  2907. //
  2908. // 1 - The sequence number for the Lsn is from the previous pass
  2909. // through the file.
  2910. // 2 - We are at the first page in the file.
  2911. // 3 - The log record didn't begin on the current page.
  2912. //
  2913. } else if (( LsnSeqNumber == SeqNumberMinus1 )
  2914. && ( Lfcb->FirstLogPage == LogFileOffset )
  2915. && ( LogFileOffset != LogPageFileOffset )) {
  2916. IsSubsequent = TRUE;
  2917. } else {
  2918. IsSubsequent = FALSE;
  2919. }
  2920. DebugTrace( -1, Dbg, "LfsCheckSubsequentLogPage: Exit -> %08x\n", IsSubsequent );
  2921. return IsSubsequent;
  2922. }
  2923. //
  2924. // Local support routine
  2925. //
  2926. VOID
  2927. LfsFlushLogPage (
  2928. IN PLFCB Lfcb,
  2929. PVOID LogPage,
  2930. IN LONGLONG FileOffset,
  2931. OUT PBCB *Bcb
  2932. )
  2933. /*++
  2934. Routine Description:
  2935. This routine is called to write a single log page to the log file. We will
  2936. mark it dirty in the cache, unpin it and call our flush routine.
  2937. Arguments:
  2938. Lfcb - Log file control block for this log file.
  2939. LogPage - Pointer to the log page in the cache.
  2940. FileOffset - Offset of the page in the stream.
  2941. Bcb - Address of the Bcb pointer for the cache.
  2942. Return Value:
  2943. None
  2944. --*/
  2945. {
  2946. PAGED_CODE();
  2947. //
  2948. // We'd absolutely hate for this to happen on a read only volume.
  2949. //
  2950. ASSERT( !(FlagOn( Lfcb->Flags, LFCB_READ_ONLY )) );
  2951. //
  2952. // Set the page dirty and unpin it.
  2953. //
  2954. CcSetDirtyPinnedData( *Bcb, NULL );
  2955. CcUnpinData( *Bcb );
  2956. *Bcb = NULL;
  2957. //
  2958. // Now flush the data.
  2959. //
  2960. Lfcb->UserWriteData->FileOffset = FileOffset;
  2961. Lfcb->UserWriteData->Length = (ULONG) Lfcb->LogPageSize;
  2962. CcFlushCache( Lfcb->FileObject->SectionObjectPointer,
  2963. (PLARGE_INTEGER) &FileOffset,
  2964. (ULONG) Lfcb->LogPageSize,
  2965. NULL );
  2966. return;
  2967. }
  2968. //
  2969. // Local support routine.
  2970. //
  2971. VOID
  2972. LfsRemoveClientFromList (
  2973. PLFS_CLIENT_RECORD ClientArray,
  2974. PLFS_CLIENT_RECORD ClientRecord,
  2975. IN PUSHORT ListHead
  2976. )
  2977. /*++
  2978. Routine Description:
  2979. This routine is called to remove a client record from a client record
  2980. list in an Lfs restart area.
  2981. Arguments:
  2982. ClientArray - Base of client records in restart area.
  2983. ClientRecord - A pointer to the record to add.
  2984. ListHead - A pointer to the beginning of the list. This points to a
  2985. USHORT which is the value of the first element in the list.
  2986. Return Value:
  2987. None.
  2988. --*/
  2989. {
  2990. PLFS_CLIENT_RECORD TempClientRecord;
  2991. PAGED_CODE();
  2992. DebugTrace( +1, Dbg, "LfsRemoveClientFromList: Entered\n", 0 );
  2993. DebugTrace( 0, Dbg, "Client Array -> %08lx\n", ClientArray );
  2994. DebugTrace( 0, Dbg, "Client Record -> %08lx\n", ClientRecord );
  2995. DebugTrace( 0, Dbg, "List Head -> %08lx\n", ListHead );
  2996. //
  2997. // If this is the first element in the list, then the head of the list
  2998. // points to the element after this record.
  2999. //
  3000. if (ClientRecord->PrevClient == LFS_NO_CLIENT) {
  3001. DebugTrace( 0, Dbg, "Element is first element in the list\n", 0 );
  3002. *ListHead = ClientRecord->NextClient;
  3003. //
  3004. // Otherwise the previous element points to the next element.
  3005. //
  3006. } else {
  3007. TempClientRecord = ClientArray + ClientRecord->PrevClient;
  3008. TempClientRecord->NextClient = ClientRecord->NextClient;
  3009. }
  3010. //
  3011. // If this is not the last element in the list, the previous element
  3012. // becomes the last element.
  3013. //
  3014. if (ClientRecord->NextClient != LFS_NO_CLIENT) {
  3015. TempClientRecord = ClientArray + ClientRecord->NextClient;
  3016. TempClientRecord->PrevClient = ClientRecord->PrevClient;
  3017. }
  3018. DebugTrace( -1, Dbg, "LfsRemoveClientFromList: Exit\n", 0 );
  3019. return;
  3020. }
  3021. //
  3022. // Local support routine.
  3023. //
  3024. VOID
  3025. LfsAddClientToList (
  3026. IN PLFS_CLIENT_RECORD ClientArray,
  3027. IN USHORT ClientIndex,
  3028. IN PUSHORT ListHead
  3029. )
  3030. /*++
  3031. Routine Description:
  3032. This routine is called to add a client record to the start of a list.
  3033. Arguments:
  3034. ClientArray - This is the base of the client record.
  3035. ClientIndex - The index for the record to add.
  3036. ListHead - A pointer to the beginning of the list. This points to a
  3037. USHORT which is the value of the first element in the list.
  3038. Return Value:
  3039. None.
  3040. --*/
  3041. {
  3042. PLFS_CLIENT_RECORD ClientRecord;
  3043. PLFS_CLIENT_RECORD TempClientRecord;
  3044. PAGED_CODE();
  3045. DebugTrace( +1, Dbg, "LfsAddClientToList: Entered\n", 0 );
  3046. DebugTrace( 0, Dbg, "Client Array -> %08lx\n", ClientArray );
  3047. DebugTrace( 0, Dbg, "Client Index -> %04x\n", ClientIndex );
  3048. DebugTrace( 0, Dbg, "List Head -> %08lx\n", ListHead );
  3049. ClientRecord = ClientArray + ClientIndex;
  3050. //
  3051. // This element will become the first element on the list.
  3052. //
  3053. ClientRecord->PrevClient = LFS_NO_CLIENT;
  3054. //
  3055. // The next element for this record is the previous head of the list.
  3056. //
  3057. ClientRecord->NextClient = *ListHead;
  3058. //
  3059. // If there is at least one element currently on the list, we point
  3060. // the first element to this new record.
  3061. //
  3062. if (*ListHead != LFS_NO_CLIENT) {
  3063. TempClientRecord = ClientArray + *ListHead;
  3064. TempClientRecord->PrevClient = ClientIndex;
  3065. }
  3066. //
  3067. // This index is now the head of the list.
  3068. //
  3069. *ListHead = ClientIndex;
  3070. DebugTrace( -1, Dbg, "LfsAddClientToList: Exit\n", 0 );
  3071. return;
  3072. }