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.

403 lines
11 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. LbcbSup.c
  5. Abstract:
  6. This module provides support for manipulating log buffer control blocks.
  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_LBCB_SUP)
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, LfsFlushToLsnPriv)
  18. #pragma alloc_text(PAGE, LfsGetLbcb)
  19. #endif
  20. extern LARGE_INTEGER LiMinus1;
  21. VOID
  22. LfsFlushToLsnPriv (
  23. IN PLFCB Lfcb,
  24. IN LSN Lsn,
  25. IN BOOLEAN RestartLsn
  26. )
  27. /*++
  28. Routine Description:
  29. This routine is the worker routine which performs the work of flushing
  30. a particular Lsn to disk. This routine is always called with the
  31. Lfcb acquired. This routines makes no guarantee about whether the Lfcb
  32. is acquired on exit.
  33. Arguments:
  34. Lfcb - This is the file control block for the log file.
  35. Lsn - This is the Lsn to flush to disk.
  36. RestartLsn - whether this lsn is a lfs restart lsn
  37. Return Value:
  38. None.
  39. --*/
  40. {
  41. LSN FlushedLsn;
  42. volatile LARGE_INTEGER StartTime;
  43. LFS_WAITER LfsWaiter;
  44. BOOLEAN OwnedExclusive;
  45. BOOLEAN Flush;
  46. PAGED_CODE();
  47. DebugTrace( +1, Dbg, "LfsFlushLbcb: Entered\n", 0 );
  48. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  49. DebugTrace( 0, Dbg, "Lbcb -> %08lx\n", Lbcb );
  50. KeQueryTickCount( &StartTime );
  51. //
  52. // Convert max lsn to the current lsn which will not change since we hold the
  53. // lfcb at least shared at this point and writers need it exclusive
  54. // We do not care if the log progresses beyond this point
  55. //
  56. if (!RestartLsn && (Lsn.QuadPart > Lfcb->RestartArea->CurrentLsn.QuadPart)) {
  57. Lsn = Lfcb->RestartArea->CurrentLsn;
  58. }
  59. //
  60. // Init a wait entry - this is a lightweight operation
  61. //
  62. KeInitializeEvent( &LfsWaiter.Event, SynchronizationEvent, FALSE );
  63. LfsWaiter.Lsn.QuadPart = Lsn.QuadPart;
  64. //
  65. // We loop here until the desired Lsn has made it to disk.
  66. // If we are able to do the I/O, we will perform it.
  67. //
  68. OwnedExclusive = ExIsResourceAcquiredExclusiveLite( &Lfcb->Sync->Resource );
  69. while (TRUE) {
  70. Flush = FALSE;
  71. ExAcquireFastMutexUnsafe( &Lfcb->Sync->Mutex );
  72. if (RestartLsn) {
  73. FlushedLsn = Lfcb->LastFlushedRestartLsn;
  74. } else {
  75. FlushedLsn = Lfcb->LastFlushedLsn;
  76. }
  77. //
  78. // Check if we still need to flush or can immediately return
  79. //
  80. if (Lsn.QuadPart <= FlushedLsn.QuadPart) {
  81. ExReleaseFastMutexUnsafe( &Lfcb->Sync->Mutex );
  82. break;
  83. }
  84. if (Lfcb->Sync->LfsIoState == LfsNoIoInProgress) {
  85. Lfcb->Sync->LfsIoState = LfsClientThreadIo;
  86. Lfcb->LfsIoThread = ExGetCurrentResourceThread();
  87. Flush = TRUE;
  88. } else {
  89. PLFS_WAITER TempWaiter = (PLFS_WAITER)Lfcb->WaiterList.Flink;
  90. //
  91. // Insert the wait entry in the sorted list of waiters -
  92. // find its place first
  93. //
  94. while ((PVOID)TempWaiter != &Lfcb->WaiterList) {
  95. if (TempWaiter->Lsn.QuadPart > Lsn.QuadPart) {
  96. break;
  97. }
  98. TempWaiter = (PLFS_WAITER)TempWaiter->Waiters.Flink;
  99. }
  100. InsertTailList( &TempWaiter->Waiters, &LfsWaiter.Waiters );
  101. }
  102. ExReleaseFastMutexUnsafe( &Lfcb->Sync->Mutex );
  103. //
  104. //
  105. // If we can do the Io, call down to flush the Lfcb.
  106. //
  107. if (Flush) {
  108. LfsFlushLfcb( Lfcb, Lsn, RestartLsn );
  109. break;
  110. }
  111. //
  112. // Otherwise we release the Lfcb and immediately wait on the event.
  113. //
  114. InterlockedIncrement( &Lfcb->Waiters );
  115. LfsReleaseLfcb( Lfcb );
  116. KeWaitForSingleObject( &LfsWaiter.Event,
  117. Executive,
  118. KernelMode,
  119. FALSE,
  120. NULL );
  121. if (OwnedExclusive) {
  122. LfsAcquireLfcbExclusive( Lfcb );
  123. } else {
  124. LfsAcquireLfcbShared( Lfcb );
  125. }
  126. InterlockedDecrement( &Lfcb->Waiters );
  127. }
  128. DebugTrace( -1, Dbg, "LfsFlushToLsnPriv: Exit\n", 0 );
  129. return;
  130. }
  131. PLBCB
  132. LfsGetLbcb (
  133. IN PLFCB Lfcb
  134. )
  135. /*++
  136. Routine Description:
  137. This routine is called to add a Lbcb to the active queue.
  138. Arguments:
  139. Lfcb - This is the file control block for the log file.
  140. Return Value:
  141. PLBCB - Pointer to the Lbcb allocated.
  142. --*/
  143. {
  144. PLBCB Lbcb = NULL;
  145. PVOID PageHeader;
  146. PBCB PageHeaderBcb = NULL;
  147. BOOLEAN WrappedOrUsaError;
  148. PAGED_CODE();
  149. DebugTrace( +1, Dbg, "LfsGetLbcb: Entered\n", 0 );
  150. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  151. //
  152. // Use a try-finally to facilitate cleanup.
  153. //
  154. try {
  155. //
  156. // Pin the desired record page.
  157. //
  158. LfsPreparePinWriteData( Lfcb,
  159. Lfcb->NextLogPage,
  160. (ULONG)Lfcb->LogPageSize,
  161. FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL ),
  162. &PageHeader,
  163. &PageHeaderBcb );
  164. #ifdef LFS_CLUSTER_CHECK
  165. //
  166. // Check the page to see if there is already data on this page with the current sequence
  167. // number. Useful to track cases where ntfs didn't find the correct end of the log or
  168. // where the cluster service has the volume mounted twice.
  169. //
  170. if (LfsTestCheckLbcb &&
  171. *((PULONG) PageHeader) == LFS_SIGNATURE_RECORD_PAGE_ULONG) {
  172. LSN LastLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Copy.LastLsn;
  173. //
  174. // This is not an exhaustive test but should be sufficient to catch the typical case.
  175. //
  176. ASSERT( FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_REUSE_TAIL ) ||
  177. (LfsLsnToSeqNumber( Lfcb, LastLsn ) < (ULONGLONG) Lfcb->SeqNumber) ||
  178. (Lfcb->NextLogPage == Lfcb->FirstLogPage) );
  179. }
  180. #endif
  181. //
  182. // Put our signature into the page so we won't fail if we
  183. // see a previous 'BAAD' signature.
  184. //
  185. *((PULONG) PageHeader) = LFS_SIGNATURE_RECORD_PAGE_ULONG;
  186. //
  187. // Now allocate an Lbcb.
  188. //
  189. LfsAllocateLbcb( Lfcb, &Lbcb );
  190. //
  191. // If we are at the beginning of the file we test that the
  192. // sequence number won't wrap to 0.
  193. //
  194. if (!FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_REUSE_TAIL )
  195. && ( Lfcb->NextLogPage == Lfcb->FirstLogPage )) {
  196. Lfcb->SeqNumber = Lfcb->SeqNumber + 1;
  197. //
  198. // If the sequence number is going from 0 to 1, then
  199. // this is the first time the log file has wrapped. We want
  200. // to remember this because it means that we can now do
  201. // large spiral writes.
  202. //
  203. if (Int64ShllMod32( Lfcb->SeqNumber, Lfcb->FileDataBits ) == 0) {
  204. DebugTrace( 0, Dbg, "Log sequence number about to wrap: Lfcb -> %08lx\n", Lfcb );
  205. KeBugCheckEx( FILE_SYSTEM, 4, 0, 0, 0 );
  206. }
  207. //
  208. // If this number is greater or equal to the wrap sequence number in
  209. // the Lfcb, set the wrap flag in the Lbcb.
  210. //
  211. if (!FlagOn( Lfcb->Flags, LFCB_LOG_WRAPPED )
  212. && ( Lfcb->SeqNumber >= Lfcb->SeqNumberForWrap )) {
  213. SetFlag( Lbcb->LbcbFlags, LBCB_LOG_WRAPPED );
  214. SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED );
  215. }
  216. }
  217. //
  218. // Now initialize the rest of the Lbcb fields.
  219. //
  220. Lbcb->FileOffset = Lfcb->NextLogPage;
  221. Lbcb->SeqNumber = Lfcb->SeqNumber;
  222. Lbcb->BufferOffset = Lfcb->LogPageDataOffset;
  223. //
  224. // Store the next page in the Lfcb.
  225. //
  226. LfsNextLogPageOffset( Lfcb,
  227. Lfcb->NextLogPage,
  228. &Lfcb->NextLogPage,
  229. &WrappedOrUsaError );
  230. Lbcb->Length = Lfcb->LogPageSize;
  231. Lbcb->PageHeader = PageHeader;
  232. Lbcb->LogPageBcb = PageHeaderBcb;
  233. Lbcb->ResourceThread = ExGetCurrentResourceThread();
  234. Lbcb->ResourceThread = (ERESOURCE_THREAD) ((ULONG) Lbcb->ResourceThread | 3);
  235. //
  236. // If we are reusing a previous page then set a flag in
  237. // the Lbcb to indicate that we should flush a copy
  238. // first.
  239. //
  240. if (FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL )) {
  241. SetFlag( Lbcb->LbcbFlags, LBCB_FLUSH_COPY );
  242. ClearFlag( Lfcb->Flags, LFCB_REUSE_TAIL );
  243. (ULONG)Lbcb->BufferOffset = Lfcb->ReusePageOffset;
  244. Lbcb->Flags = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Flags;
  245. Lbcb->LastLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Copy.LastLsn;
  246. Lbcb->LastEndLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Header.Packed.LastEndLsn;
  247. }
  248. //
  249. // Put the Lbcb on the active queue
  250. //
  251. InsertTailList( &Lfcb->LbcbActive, &Lbcb->ActiveLinks );
  252. SetFlag( Lbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE );
  253. //
  254. // Now that we have succeeded, set the owner thread to Thread + 1 so the resource
  255. // package will know not to peek in this thread. It may be deallocated before
  256. // we release the Bcb during flush.
  257. //
  258. CcSetBcbOwnerPointer( Lbcb->LogPageBcb, (PVOID) Lbcb->ResourceThread );
  259. } finally {
  260. DebugUnwind( LfsGetLbcb );
  261. //
  262. // If an error occurred, we need to clean up any blocks which
  263. // have not been added to the active queue.
  264. //
  265. if (AbnormalTermination()) {
  266. if (Lbcb != NULL) {
  267. LfsDeallocateLbcb( Lfcb, Lbcb );
  268. Lbcb = NULL;
  269. }
  270. //
  271. // Unpin the system page if pinned.
  272. //
  273. if (PageHeaderBcb != NULL) {
  274. CcUnpinData( PageHeaderBcb );
  275. }
  276. }
  277. DebugTrace( -1, Dbg, "LfsGetLbcb: Exit\n", 0 );
  278. }
  279. return Lbcb;
  280. }