Source code of Windows XP (NT5)
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.

374 lines
9.1 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. LogPgSup.c
  5. Abstract:
  6. This module implements support for manipulating log pages.
  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_LOG_PAGE_SUP)
  16. #undef MODULE_POOL_TAG
  17. #define MODULE_POOL_TAG ('PsfL')
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, LfsAllocateSpanningBuffer)
  20. #pragma alloc_text(PAGE, LfsFreeSpanningBuffer)
  21. #pragma alloc_text(PAGE, LfsNextLogPageOffset)
  22. #endif
  23. VOID
  24. LfsNextLogPageOffset (
  25. IN PLFCB Lfcb,
  26. IN LONGLONG CurrentLogPageOffset,
  27. OUT PLONGLONG NextLogPageOffset,
  28. OUT PBOOLEAN Wrapped
  29. )
  30. /*++
  31. Routine Description:
  32. This routine will compute the offset in the log file of the next log
  33. page.
  34. Arguments:
  35. Lfcb - This is the file control block for the log file.
  36. CurrentLogPageOffset - This is the file offset of the current log page.
  37. NextLogPageOffset - Address to store the next log page to use.
  38. Wrapped - This is a pointer to a boolean variable that, if present,
  39. we use to indicate whether we wrapped in the log file.
  40. Return Value:
  41. None.
  42. --*/
  43. {
  44. PAGED_CODE();
  45. DebugTrace( +1, Dbg, "LfsNextLogPageOffset: Entered\n", 0 );
  46. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  47. DebugTrace( 0, Dbg, "CurrentLogPageOffset (Low) -> %08lx\n", CurrentLogPageOffset.LowPart );
  48. DebugTrace( 0, Dbg, "CurrentLogPageOffset (High) -> %08lx\n", CurrentLogPageOffset.HighPart );
  49. DebugTrace( 0, Dbg, "Wrapped -> %08lx\n", Wrapped );
  50. //
  51. // We add the log page size to the current log offset.
  52. //
  53. LfsTruncateOffsetToLogPage( Lfcb, CurrentLogPageOffset, &CurrentLogPageOffset );
  54. *NextLogPageOffset = CurrentLogPageOffset + Lfcb->LogPageSize; //**** xxAdd( CurrentLogPageOffset, Lfcb->LogPageSize );
  55. //
  56. // If the result is larger than the file, we use the first page offset
  57. // in the file.
  58. //
  59. if ( *NextLogPageOffset >= Lfcb->FileSize ) { //**** xxGeq( *NextLogPageOffset, Lfcb->FileSize )
  60. *NextLogPageOffset = Lfcb->FirstLogPage;
  61. *Wrapped = TRUE;
  62. } else {
  63. *Wrapped = FALSE;
  64. }
  65. DebugTrace( 0, Dbg, "NextLogPageOffset (Low) -> %08lx\n", NextLogPageOffset->LowPart );
  66. DebugTrace( 0, Dbg, "NextLogPageOffset (High) -> %08lx\n", NextLogPageOffset->HighPart );
  67. DebugTrace( 0, Dbg, "Wrapped -> %08x\n", *Wrapped );
  68. DebugTrace( -1, Dbg, "LfsNextLogPageOffset: Exit\n", 0 );
  69. return;
  70. }
  71. PVOID
  72. LfsAllocateSpanningBuffer (
  73. IN PLFCB Lfcb,
  74. IN ULONG Length
  75. )
  76. /*++
  77. Routine Description:
  78. This routine is called to allocate a spare buffer to read a file record
  79. which spans a log page. We will first try to allocate one. If that
  80. fails we will use one of the existing spare buffers. If that fails then
  81. we will raise.
  82. Arguments:
  83. Lfcb - This is the file control block for the log file.
  84. Length - Length of the buffer required.
  85. Return Value:
  86. PVOID - Pointer to the buffer to use for reading the log record.
  87. May be either from pool or from the auxilary buffer pool.
  88. --*/
  89. {
  90. PVOID NewBuffer = NULL;
  91. ERESOURCE_THREAD Thread;
  92. BOOLEAN Wait = FALSE;
  93. PAGED_CODE();
  94. DebugTrace( +1, Dbg, "LfsAllocateSpanningBuffer: Entered\n", 0 );
  95. //
  96. // Loop while we don't have a buffer. First try to get our reserved buffer
  97. // without waiting. Then try to allocate a buffer. Finally wait for the reserved
  98. // buffer as the final alternative.
  99. //
  100. do {
  101. //
  102. // Skip the reserved buffer if the request is larger than we can read into it.
  103. //
  104. if (Length <= LFS_BUFFER_SIZE) {
  105. //
  106. // If this thread already owns one buffer it can get the second directly.
  107. //
  108. Thread = ExGetCurrentResourceThread();
  109. if (Thread == LfsData.BufferOwner) {
  110. if (!FlagOn( LfsData.BufferFlags, LFS_BUFFER1_OWNED )) {
  111. SetFlag( LfsData.BufferFlags, LFS_BUFFER1_OWNED );
  112. NewBuffer = LfsData.Buffer1;
  113. break;
  114. } else if (!FlagOn( LfsData.BufferFlags, LFS_BUFFER2_OWNED )) {
  115. SetFlag( LfsData.BufferFlags, LFS_BUFFER2_OWNED );
  116. NewBuffer = LfsData.Buffer2;
  117. break;
  118. } else if (Wait) {
  119. //
  120. // This shouldn't happen but handle anyway.
  121. //
  122. DebugTrace( -1, Dbg, "LfsAllocateSpanningBuffer: Exit\n", 0 );
  123. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  124. }
  125. //
  126. // Otherwise acquire the buffer lock and check the state of the buffers.
  127. //
  128. } else {
  129. BOOLEAN LfcbOwned = TRUE;
  130. while (TRUE) {
  131. LfsAcquireBufferLock();
  132. //
  133. // Check to see if the buffers are available. No
  134. // need to drop the Lfcb in the typical case.
  135. //
  136. if (LfsData.BufferOwner == (ERESOURCE_THREAD) NULL) {
  137. ASSERT( !FlagOn( LfsData.BufferFlags, LFS_BUFFER1_OWNED | LFS_BUFFER2_OWNED ));
  138. NewBuffer = LfsData.Buffer1;
  139. LfsData.BufferOwner = Thread;
  140. SetFlag( LfsData.BufferFlags, LFS_BUFFER1_OWNED );
  141. LfsBlockBufferWaiters();
  142. //
  143. // Reacquire the Lfcb if needed.
  144. //
  145. if (!LfcbOwned) {
  146. LfsAcquireLfcb( Lfcb );
  147. }
  148. //
  149. // Break out.
  150. //
  151. LfsReleaseBufferLock();
  152. break;
  153. }
  154. //
  155. // Release the Lfcb and wait on the notification for the buffers.
  156. //
  157. if (Wait) {
  158. if (LfcbOwned) {
  159. LfsReleaseLfcb( Lfcb );
  160. LfcbOwned = FALSE;
  161. }
  162. LfsReleaseBufferLock();
  163. LfsWaitForBufferNotification();
  164. } else {
  165. //
  166. // Go ahead and try to allocate a buffer from pool next.
  167. //
  168. LfsReleaseBufferLock();
  169. break;
  170. }
  171. }
  172. }
  173. //
  174. // Raise if we already tried the allocate path.
  175. //
  176. } else if (Wait) {
  177. DebugTrace( -1, Dbg, "LfsAllocateSpanningBuffer: Exit\n", 0 );
  178. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  179. }
  180. //
  181. // Try pool if we didn't get a buffer above.
  182. //
  183. if (NewBuffer == NULL) {
  184. //
  185. // Try pool next but don't let this fail on pool allocation.
  186. //
  187. NewBuffer = LfsAllocatePoolNoRaise( PagedPool, Length );
  188. }
  189. //
  190. // Wait on the next pass through the loop.
  191. //
  192. Wait = TRUE;
  193. } while (NewBuffer == NULL);
  194. DebugTrace( -1, Dbg, "LfsAllocateSpanningBuffer: Exit\n", 0 );
  195. return NewBuffer;
  196. }
  197. VOID
  198. LfsFreeSpanningBuffer (
  199. IN PVOID Buffer
  200. )
  201. /*++
  202. Routine Description:
  203. This routine is called to free a buffer used to read a log record
  204. which spans pages. We will check if it is one of our special buffers
  205. and deal with synchronization in that case.
  206. Arguments:
  207. Buffer - Buffer to free.
  208. Return Value:
  209. None.
  210. --*/
  211. {
  212. ERESOURCE_THREAD Thread;
  213. ULONG BufferFlag;
  214. PAGED_CODE();
  215. DebugTrace( +1, Dbg, "LfsFreeSpanningBuffer: Entered\n", 0 );
  216. //
  217. // Check if either buffer1 or buffer2 are being freed.
  218. //
  219. if (Buffer == LfsData.Buffer1) {
  220. BufferFlag = LFS_BUFFER1_OWNED;
  221. goto ReservedBuffers;
  222. } else if (Buffer == LfsData.Buffer2) {
  223. BufferFlag = LFS_BUFFER2_OWNED;
  224. ReservedBuffers:
  225. //
  226. // Acquire the buffer lock and clear the correct flag.
  227. //
  228. LfsAcquireBufferLock();
  229. ClearFlag( LfsData.BufferFlags, BufferFlag );
  230. //
  231. // If no buffers owned then signal the waiters.
  232. //
  233. if (!FlagOn( LfsData.BufferFlags, LFS_BUFFER1_OWNED | LFS_BUFFER2_OWNED )) {
  234. LfsData.BufferOwner = (ERESOURCE_THREAD) NULL;
  235. LfsNotifyBufferWaiters();
  236. }
  237. LfsReleaseBufferLock();
  238. } else {
  239. //
  240. // Simply free the buffer.
  241. //
  242. LfsFreePool( Buffer );
  243. }
  244. DebugTrace( -1, Dbg, "LfsFreeSpanningBuffer: Exit\n", 0 );
  245. return;
  246. }