Windows NT 4.0 source code leak
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.

4234 lines
116 KiB

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