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

281 lines
7.0 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. RstrtSup.c
  5. Abstract:
  6. This module implements support for dealing with the Lfs restart area.
  7. Author:
  8. Brian Andrew [BrianAn] 20-June-1991
  9. Revision History:
  10. --*/
  11. #include "lfsprocs.h"
  12. //
  13. // The debug trace level
  14. //
  15. #define Dbg (DEBUG_TRACE_RESTART_SUP)
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, LfsFindOldestClientLsn)
  18. #pragma alloc_text(PAGE, LfsWriteLfsRestart)
  19. #endif
  20. VOID
  21. LfsWriteLfsRestart (
  22. IN PLFCB Lfcb,
  23. IN ULONG ThisRestartSize,
  24. IN BOOLEAN WaitForIo
  25. )
  26. /*++
  27. Routine Description:
  28. This routine puts the Lfs restart area on the queue of operations to
  29. write to the file. We do this by allocating a second restart area
  30. and attaching it to the Lfcb. We also allocate a buffer control
  31. block to use for this write. We look at the WaitForIo boolean to
  32. determine whether this thread can perform the I/O. This also indicates
  33. whether this thread gives up the Lfcb.
  34. Arguments:
  35. Lfcb - A pointer to the log file control block for this operation.
  36. ThisRestartSize - This is the size to use for the restart area.
  37. WaitForIo - Indicates if this thread is to perform the work.
  38. Return Value:
  39. None.
  40. --*/
  41. {
  42. PLBCB NewLbcb = NULL;
  43. PLFS_RESTART_AREA NewRestart = NULL;
  44. PAGED_CODE();
  45. DebugTrace( +1, Dbg, "LfsWriteLfsRestart: Entered\n", 0 );
  46. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  47. DebugTrace( 0, Dbg, "Write Chkdsk -> %04x\n", WriteChkdsk );
  48. DebugTrace( 0, Dbg, "Restart Size -> %08lx\n", ThisRestartSize );
  49. DebugTrace( 0, Dbg, "WaitForIo -> %08lx\n", WaitForIo );
  50. //
  51. // We'd absolutely hate for this to happen on a read only volume.
  52. //
  53. ASSERT(!(FlagOn( Lfcb->Flags, LFCB_READ_ONLY )));
  54. //
  55. // Use a try-finally to facilitate cleanup.
  56. //
  57. try {
  58. PLBCB ActiveLbcb;
  59. //
  60. // We allocate another restart area and
  61. // copy the current area into it. Attach the new area to the Lfcb.
  62. //
  63. LfsAllocateRestartArea( &NewRestart, ThisRestartSize );
  64. //
  65. // We allocate a Lbcb structure and update the values to
  66. // reflect this restart area.
  67. //
  68. LfsAllocateLbcb( Lfcb, &NewLbcb );
  69. SetFlag( NewLbcb->LbcbFlags, LBCB_RESTART_LBCB );
  70. //
  71. // If this is the second page, then add a page to the offset.
  72. //
  73. if (!Lfcb->InitialRestartArea) {
  74. NewLbcb->FileOffset = Lfcb->LogPageSize + NewLbcb->FileOffset;
  75. }
  76. (ULONG)NewLbcb->Length = ThisRestartSize;
  77. NewLbcb->PageHeader = (PVOID) Lfcb->RestartArea;
  78. //
  79. // Set the lsn to a pseudo one right beyond the current lsn (the current may advance before flushing)
  80. //
  81. ASSERT( (sizeof( LFS_RECORD_HEADER ) >> 3) > Lfcb->LfsRestartBias );
  82. NewLbcb->LastEndLsn.QuadPart = NewLbcb->LastLsn.QuadPart = Lfcb->RestartArea->CurrentLsn.QuadPart + Lfcb->LfsRestartBias;
  83. Lfcb->LfsRestartBias += 1;
  84. ASSERT( Lfcb->LfsRestartBias < 7 );
  85. //
  86. // Copy the existing restart area into the new area.
  87. //
  88. RtlCopyMemory( NewRestart, Lfcb->RestartArea, ThisRestartSize );
  89. Lfcb->RestartArea = NewRestart;
  90. Lfcb->ClientArray = Add2Ptr( NewRestart, Lfcb->ClientArrayOffset, PLFS_CLIENT_RECORD );
  91. NewRestart = NULL;
  92. //
  93. // Update the Lfcb to indicate that the other restart area
  94. // on the disk is to be used.
  95. //
  96. Lfcb->InitialRestartArea = !Lfcb->InitialRestartArea;
  97. //
  98. // Add this Lbcb to the end of the workque and flush to that point.
  99. //
  100. InsertTailList( &Lfcb->LbcbWorkque, &NewLbcb->WorkqueLinks );
  101. //
  102. // If we don't support a packed log file then we need to make
  103. // sure that all file records written out ahead of this
  104. // restart area make it out to disk and we don't add anything
  105. // to this page.
  106. //
  107. if (!FlagOn( Lfcb->Flags, LFCB_PACK_LOG )
  108. && !IsListEmpty( &Lfcb->LbcbActive )) {
  109. ActiveLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink,
  110. LBCB,
  111. ActiveLinks );
  112. if (FlagOn( ActiveLbcb->LbcbFlags, LBCB_NOT_EMPTY )) {
  113. RemoveEntryList( &ActiveLbcb->ActiveLinks );
  114. ClearFlag( ActiveLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE );
  115. }
  116. }
  117. if (WaitForIo) {
  118. LfsFlushToLsnPriv( Lfcb, NewLbcb->LastEndLsn, TRUE );
  119. } else {
  120. }
  121. } finally {
  122. DebugUnwind( LfsWriteLfsRestart );
  123. if (NewRestart != NULL) {
  124. ExFreePool( NewRestart );
  125. }
  126. DebugTrace( -1, Dbg, "LfsWriteLfsRestart: Exit\n", 0 );
  127. }
  128. return;
  129. }
  130. VOID
  131. LfsFindOldestClientLsn (
  132. IN PLFS_RESTART_AREA RestartArea,
  133. IN PLFS_CLIENT_RECORD ClientArray,
  134. OUT PLSN OldestLsn
  135. )
  136. /*++
  137. Routine Description:
  138. This routine walks through the active clients to determine the oldest
  139. Lsn the system must maintain.
  140. Arguments:
  141. RestartArea - This is the Restart Area to examine.
  142. ClientArray - This is the start of the client data array.
  143. OldestLsn - We store the oldest Lsn we find in this value. It is
  144. initialized with a starting value, we won't return a more recent
  145. Lsn.
  146. Return Value:
  147. None.
  148. --*/
  149. {
  150. USHORT NextClient;
  151. PLFS_CLIENT_RECORD ClientBlock;
  152. PAGED_CODE();
  153. DebugTrace( +1, Dbg, "LfsFindOldestClientLsn: Entered\n", 0 );
  154. DebugTrace( 0, Dbg, "RestartArea -> %08lx\n", RestartArea );
  155. DebugTrace( 0, Dbg, "Base Lsn (Low) -> %08lx\n", BaseLsn.LowPart );
  156. DebugTrace( 0, Dbg, "Base Lsn (High) -> %08lx\n", BaseLsn.HighPart );
  157. //
  158. // Take the first client off the in use list.
  159. //
  160. NextClient = RestartArea->ClientInUseList;
  161. //
  162. // While there are more clients, compare their oldest Lsn with the
  163. // current oldest.
  164. //
  165. while (NextClient != LFS_NO_CLIENT) {
  166. ClientBlock = ClientArray + NextClient;
  167. //
  168. // We ignore this block if it's oldest Lsn is 0.
  169. //
  170. if (( ClientBlock->OldestLsn.QuadPart != 0 )
  171. && ( ClientBlock->OldestLsn.QuadPart < OldestLsn->QuadPart )) {
  172. *OldestLsn = ClientBlock->OldestLsn;
  173. }
  174. //
  175. // Try the next client block.
  176. //
  177. NextClient = ClientBlock->NextClient;
  178. }
  179. DebugTrace( 0, Dbg, "OldestLsn (Low) -> %08lx\n", BaseLsn.LowPart );
  180. DebugTrace( 0, Dbg, "OldestLsn (High) -> %08lx\n", BaseLsn.HighPart );
  181. DebugTrace( -1, Dbg, "LfsFindOldestClientLsn: Exit\n", 0 );
  182. return;
  183. }