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.

348 lines
9.2 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. largemem.c
  5. Abstract:
  6. The implementation of large memory allocator interfaces.
  7. Author:
  8. George V. Reilly (GeorgeRe) 10-Nov-2000
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "largemem.h"
  13. // Magic constant for use with MmAllocatePagesForMdl
  14. #define LOWEST_USABLE_PHYSICAL_ADDRESS (16 * 1024 * 1024)
  15. //
  16. // Globals
  17. //
  18. LONG g_LargeMemInitialized;
  19. volatile SIZE_T g_LargeMemPagesMaxLimit; // " " pages " " "
  20. volatile ULONG g_LargeMemPagesCurrent; // #pages currently used
  21. volatile ULONG g_LargeMemPagesMaxEverUsed; // max #pages ever used
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text( INIT, UlLargeMemInitialize )
  24. #endif // ALLOC_PRAGMA
  25. #if 0
  26. NOT PAGEABLE -- UlLargeMemTerminate
  27. #endif
  28. /***************************************************************************++
  29. Routine Description:
  30. Initialize global state for LargeMem
  31. Arguments:
  32. --***************************************************************************/
  33. NTSTATUS
  34. UlLargeMemInitialize(
  35. )
  36. {
  37. NTSTATUS Status = STATUS_SUCCESS;
  38. PAGED_CODE();
  39. g_LargeMemPagesCurrent = 0;
  40. g_LargeMemPagesMaxEverUsed = 0;
  41. // Set the upper bound on the amount of memory that we'll ever use
  42. // Set it to size of physical memory. We wont actually use this much
  43. // because the scavenger thread will get a low memory notification and
  44. // trim the cache
  45. g_LargeMemPagesMaxLimit = MEGABYTES_TO_PAGES(g_UlTotalPhysicalMemMB);
  46. UlTraceVerbose(LARGE_MEM,
  47. ("Http!UlLargeMemInitialize: "
  48. "g_UlTotalPhysicalMemMB=%dMB, "
  49. "\t g_LargeMemPagesMaxLimit=%I64u.\n",
  50. g_UlTotalPhysicalMemMB,
  51. g_LargeMemPagesMaxLimit));
  52. g_LargeMemInitialized = TRUE;
  53. return Status;
  54. } // UlLargeMemInitialize
  55. /***************************************************************************++
  56. Routine Description:
  57. Cleanup global state for LargeMem
  58. --***************************************************************************/
  59. VOID
  60. UlLargeMemTerminate(
  61. VOID
  62. )
  63. {
  64. PAGED_CODE();
  65. ASSERT(0 == g_LargeMemPagesCurrent);
  66. if (g_LargeMemInitialized)
  67. {
  68. //
  69. // Clear the "initialized" flag. If the memory tuner runs soon,
  70. // it will see this flag, set the termination event, and exit
  71. // quickly.
  72. //
  73. g_LargeMemInitialized = FALSE;
  74. }
  75. UlTraceVerbose(LARGE_MEM,
  76. ("Http!UlLargeMemTerminate: Memory used: "
  77. "Current = %d pages = %dMB; MaxEver = %d pages = %dMB.\n",
  78. g_LargeMemPagesCurrent,
  79. PAGES_TO_MEGABYTES(g_LargeMemPagesCurrent),
  80. g_LargeMemPagesMaxEverUsed,
  81. PAGES_TO_MEGABYTES(g_LargeMemPagesMaxEverUsed)
  82. ));
  83. } // UlLargeMemTerminate
  84. /***************************************************************************++
  85. Routine Description:
  86. Allocate a MDL from PAE memory
  87. --***************************************************************************/
  88. PMDL
  89. UlLargeMemAllocate(
  90. IN ULONG Length
  91. )
  92. {
  93. PMDL pMdl;
  94. PHYSICAL_ADDRESS LowAddress, HighAddress, SkipBytes;
  95. LONG PrevPagesUsed;
  96. LONG NewMaxUsed;
  97. LONG RoundUpBytes = (LONG) ROUND_TO_PAGES(Length);
  98. LONG NewPages = RoundUpBytes >> PAGE_SHIFT;
  99. PrevPagesUsed =
  100. InterlockedExchangeAdd((PLONG) &g_LargeMemPagesCurrent, NewPages);
  101. if (PrevPagesUsed + NewPages > (LONG)g_LargeMemPagesMaxLimit) {
  102. // overshot g_LargeMemPagesMaxLimit
  103. UlTrace(LARGE_MEM,
  104. ("http!UlLargeMemAllocate: "
  105. "overshot g_LargeMemPagesMaxLimit=%I64u pages. "
  106. "Releasing %d pages\n",
  107. g_LargeMemPagesMaxLimit, NewPages
  108. ));
  109. // CODEWORK: This implies that the MRU entries in the cache will
  110. // be not be cached, which probably leads to poor cache locality.
  111. // Really ought to free up some LRU cache entries instead.
  112. //
  113. // Start the scavenger
  114. //
  115. UlSetScavengerLimitEvent();
  116. // Fail the allocation. The cache miss path will be taken
  117. InterlockedExchangeAdd((PLONG) &g_LargeMemPagesCurrent, -NewPages);
  118. return NULL;
  119. }
  120. LowAddress.QuadPart = LOWEST_USABLE_PHYSICAL_ADDRESS;
  121. HighAddress.QuadPart = 0xfffffffff; // 64GB
  122. SkipBytes.QuadPart = 0;
  123. pMdl = MmAllocatePagesForMdl(
  124. LowAddress,
  125. HighAddress,
  126. SkipBytes,
  127. RoundUpBytes
  128. );
  129. // Completely failed to allocate memory
  130. if (pMdl == NULL)
  131. {
  132. UlTrace(LARGE_MEM,
  133. ("http!UlLargeMemAllocate: "
  134. "Completely failed to allocate %d bytes.\n",
  135. RoundUpBytes
  136. ));
  137. InterlockedExchangeAdd((PLONG) &g_LargeMemPagesCurrent, -NewPages);
  138. return NULL;
  139. }
  140. // Couldn't allocate all the memory we asked for. We need all the pages
  141. // we asked for, so we have to set the state of `this' to invalid.
  142. // Memory is probably really tight.
  143. if (MmGetMdlByteCount(pMdl) < Length)
  144. {
  145. UlTrace(LARGE_MEM,
  146. ("http!UlLargeMemAllocate: Failed to allocate %d bytes. "
  147. "Got %d instead.\n",
  148. RoundUpBytes, MmGetMdlByteCount(pMdl)
  149. ));
  150. // Free MDL but don't adjust g_LargeMemPagesCurrent downwards
  151. MmFreePagesFromMdl(pMdl);
  152. ExFreePool(pMdl);
  153. InterlockedExchangeAdd((PLONG) &g_LargeMemPagesCurrent, -NewPages);
  154. return NULL;
  155. }
  156. UlTrace(LARGE_MEM,
  157. ("http!UlLargeMemAllocate: %u->%u, mdl=%p, %d pages.\n",
  158. Length, pMdl->ByteCount, pMdl, NewPages
  159. ));
  160. ASSERT(pMdl->MdlFlags & MDL_PAGES_LOCKED);
  161. // Hurrah! a successful allocation
  162. //
  163. // update g_LargeMemPagesMaxEverUsed in a threadsafe manner
  164. // using interlocked instructions
  165. do
  166. {
  167. volatile LONG CurrentPages = g_LargeMemPagesCurrent;
  168. volatile LONG MaxEver = g_LargeMemPagesMaxEverUsed;
  169. NewMaxUsed = max(MaxEver, CurrentPages);
  170. if (NewMaxUsed > MaxEver)
  171. {
  172. InterlockedCompareExchange(
  173. (PLONG) &g_LargeMemPagesMaxEverUsed,
  174. NewMaxUsed,
  175. MaxEver
  176. );
  177. }
  178. PAUSE_PROCESSOR;
  179. } while (NewMaxUsed < (LONG)g_LargeMemPagesCurrent);
  180. UlTrace(LARGE_MEM,
  181. ("http!UlLargeMemAllocate: "
  182. "g_LargeMemPagesCurrent=%d pages. "
  183. "g_LargeMemPagesMaxEverUsed=%d pages.\n",
  184. g_LargeMemPagesCurrent, NewMaxUsed
  185. ));
  186. WRITE_REF_TRACE_LOG(
  187. g_pMdlTraceLog,
  188. REF_ACTION_ALLOCATE_MDL,
  189. PtrToLong(pMdl->Next), // bugbug64
  190. pMdl,
  191. __FILE__,
  192. __LINE__
  193. );
  194. return pMdl;
  195. } // UlLargeMemAllocate
  196. /***************************************************************************++
  197. Routine Description:
  198. Free a MDL to PAE memory
  199. --***************************************************************************/
  200. VOID
  201. UlLargeMemFree(
  202. IN PMDL pMdl
  203. )
  204. {
  205. LONG Pages;
  206. LONG PrevPagesUsed;
  207. ASSERT(ROUND_TO_PAGES(pMdl->ByteCount) == pMdl->ByteCount);
  208. Pages = pMdl->ByteCount >> PAGE_SHIFT;
  209. MmFreePagesFromMdl(pMdl);
  210. ExFreePool(pMdl);
  211. PrevPagesUsed
  212. = InterlockedExchangeAdd(
  213. (PLONG) &g_LargeMemPagesCurrent,
  214. - Pages);
  215. ASSERT(PrevPagesUsed >= Pages);
  216. } // UlLargeMemFree
  217. /***************************************************************************++
  218. Routine Description:
  219. Copy a buffer to the specified MDL starting from Offset.
  220. --***************************************************************************/
  221. BOOLEAN
  222. UlLargeMemSetData(
  223. IN PMDL pMdl,
  224. IN PUCHAR pBuffer,
  225. IN ULONG Length,
  226. IN ULONG Offset
  227. )
  228. {
  229. PUCHAR pSysAddr;
  230. ASSERT(Offset <= pMdl->ByteCount);
  231. ASSERT(Length <= (pMdl->ByteCount - Offset));
  232. ASSERT(pMdl->MdlFlags & MDL_PAGES_LOCKED);
  233. pSysAddr = (PUCHAR) MmMapLockedPagesSpecifyCache (
  234. pMdl, // MemoryDescriptorList,
  235. KernelMode, // AccessMode,
  236. MmCached, // CacheType,
  237. NULL, // BaseAddress,
  238. FALSE, // BugCheckOnFailure,
  239. NormalPagePriority // Priority
  240. );
  241. if (pSysAddr != NULL)
  242. {
  243. __try
  244. {
  245. RtlCopyMemory (
  246. pSysAddr + Offset,
  247. pBuffer,
  248. Length
  249. );
  250. }
  251. __except(UL_EXCEPTION_FILTER())
  252. {
  253. MmUnmapLockedPages (pSysAddr, pMdl);
  254. return FALSE;
  255. }
  256. MmUnmapLockedPages (pSysAddr, pMdl);
  257. return TRUE;
  258. }
  259. return FALSE;
  260. } // UlLargeMemSetData