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.

1475 lines
34 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. memory.c
  5. Abstract:
  6. This module contains the routines which allocates and free memory - both
  7. paged and non-paged.
  8. Author:
  9. Jameel Hyder (microsoft!jameelh)
  10. Revision History:
  11. 25 Apr 1992 Initial Version
  12. 11 Mar 1993 SueA - Fixed AfpAllocUnicodeString to expect byte count,
  13. not char count
  14. Notes: Tab stop: 4
  15. --*/
  16. #define FILENUM FILE_MEMORY
  17. #define AFPMEM_LOCALS
  18. #include <afp.h>
  19. #include <iopool.h>
  20. #include <scavengr.h>
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text( INIT, AfpMemoryInit)
  23. #pragma alloc_text( PAGE, AfpMemoryDeInit)
  24. #endif
  25. /*** AfpMemoryInit
  26. *
  27. * Initialize the IO Pool system.
  28. */
  29. NTSTATUS
  30. AfpMemoryInit(
  31. VOID
  32. )
  33. {
  34. NTSTATUS Status;
  35. INITIALIZE_SPIN_LOCK(&afpIoPoolLock);
  36. Status = AfpScavengerScheduleEvent(afpIoPoolAge,
  37. NULL,
  38. POOL_AGE_TIME,
  39. False);
  40. return Status;
  41. }
  42. /*** AfpMemoryDeInit
  43. *
  44. * Free any IO pool buffers.
  45. */
  46. VOID
  47. AfpMemoryDeInit(
  48. VOID
  49. )
  50. {
  51. PIOPOOL pPool, pFree;
  52. for (pPool = afpIoPoolHead;
  53. pPool != NULL;)
  54. {
  55. ASSERT(VALID_IOP(pPool));
  56. pFree = pPool;
  57. pPool = pPool->iop_Next;
  58. ASSERT (pFree->iop_NumFreeBufs == NUM_BUFS_IN_POOL);
  59. ASSERT (pFree->iop_NumFreeLocks == NUM_LOCKS_IN_POOL);
  60. AfpFreeMemory(pFree);
  61. }
  62. }
  63. /*** AfpAllocMemory
  64. *
  65. * Allocate a block of memory from either the paged or the non-paged pool
  66. * based on the memory tag. This is just a wrapper over ExAllocatePool.
  67. * Allocation failures are error-logged. We always allocate a DWORD more
  68. * than the specified size to accomodate the size. This is used by
  69. * AfpFreeMemory to update the statistics.
  70. *
  71. * While we are debugging, we also pad the block with a signature and test
  72. * it when we free it. This detects memory overrun.
  73. */
  74. PBYTE FASTCALL
  75. AfpAllocMemory(
  76. #ifdef TRACK_MEMORY_USAGE
  77. IN LONG Size,
  78. IN DWORD FileLine
  79. #else
  80. IN LONG Size
  81. #endif
  82. )
  83. {
  84. KIRQL OldIrql;
  85. PBYTE Buffer;
  86. DWORD OldMaxUsage;
  87. POOL_TYPE PoolType;
  88. PDWORD pCurUsage, pMaxUsage, pCount, pLimit;
  89. PDWORD pDwordBuf;
  90. BOOLEAN Zeroed;
  91. #if DBG
  92. DWORD Signature;
  93. #endif
  94. #ifdef PROFILING
  95. TIME TimeS1, TimeS2, TimeE, TimeD;
  96. AfpGetPerfCounter(&TimeS1);
  97. #endif
  98. ASSERT ((Size & ~MEMORY_TAG_MASK) < MAXIMUM_ALLOC_SIZE);
  99. // Make sure that this allocation will not put us over the limit
  100. // of paged/non-paged pool that we can allocate.
  101. //
  102. // Account for this allocation in the statistics database.
  103. Zeroed = False;
  104. if (Size & ZEROED_MEMORY_TAG)
  105. {
  106. Zeroed = True;
  107. Size &= ~ZEROED_MEMORY_TAG;
  108. }
  109. if (Size & NON_PAGED_MEMORY_TAG)
  110. {
  111. PoolType = NonPagedPool;
  112. pCurUsage = &AfpServerStatistics.stat_CurrNonPagedUsage;
  113. pMaxUsage = &AfpServerStatistics.stat_MaxNonPagedUsage;
  114. pCount = &AfpServerStatistics.stat_NonPagedCount;
  115. pLimit = &AfpNonPagedPoolLimit;
  116. #if DBG
  117. Signature = NONPAGED_BLOCK_SIGNATURE;
  118. #endif
  119. }
  120. else
  121. {
  122. ASSERT (Size & PAGED_MEMORY_TAG);
  123. PoolType = PagedPool;
  124. pCurUsage = &AfpServerStatistics.stat_CurrPagedUsage;
  125. pMaxUsage = &AfpServerStatistics.stat_MaxPagedUsage;
  126. pCount = &AfpServerStatistics.stat_PagedCount;
  127. pLimit = &AfpPagedPoolLimit;
  128. #if DBG
  129. Signature = PAGED_BLOCK_SIGNATURE;
  130. #endif
  131. }
  132. Size &= ~MEMORY_TAG_MASK;
  133. if (Size == 0 )
  134. {
  135. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_ERR,
  136. ("afpAllocMemory: Alloc for 0 bytes!\n"));
  137. ASSERT(0);
  138. return(NULL);
  139. }
  140. Size = DWORDSIZEBLOCK(Size) +
  141. #if DBG
  142. sizeof(DWORD) + // For the signature
  143. #endif
  144. LONGLONGSIZEBLOCK(sizeof(TAG));
  145. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  146. *pCurUsage += Size;
  147. (*pCount) ++;
  148. OldMaxUsage = *pMaxUsage;
  149. if (*pCurUsage > *pMaxUsage)
  150. *pMaxUsage = *pCurUsage;
  151. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  152. #ifdef PROFILING
  153. AfpGetPerfCounter(&TimeS2);
  154. #endif
  155. // Do the actual memory allocation. Allocate four extra bytes so
  156. // that we can store the size of the allocation for the free routine.
  157. if ((Buffer = ExAllocatePoolWithTag(PoolType, Size, AFP_TAG)) == NULL)
  158. {
  159. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  160. *pCurUsage -= Size;
  161. *pMaxUsage = OldMaxUsage;
  162. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  163. AFPLOG_DDERROR(AFPSRVMSG_PAGED_POOL, STATUS_NO_MEMORY, &Size,
  164. sizeof(Size), NULL);
  165. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_ERR,
  166. ("AfpAllocMemory: ExAllocatePool returned NULL for %d bytes\n",Size));
  167. return NULL;
  168. }
  169. #ifdef PROFILING
  170. AfpGetPerfCounter(&TimeE);
  171. TimeD.QuadPart = TimeE.QuadPart - TimeS2.QuadPart;
  172. if (PoolType == NonPagedPool)
  173. {
  174. INTERLOCKED_INCREMENT_LONG(AfpServerProfile->perf_ExAllocCountN);
  175. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_ExAllocTimeN,
  176. TimeD,
  177. &AfpStatisticsLock);
  178. else
  179. {
  180. INTERLOCKED_INCREMENT_LONG(AfpServerProfile->perf_ExAllocCountP);
  181. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_ExAllocTimeP,
  182. TimeD,
  183. &AfpStatisticsLock);
  184. }
  185. TimeD.QuadPart = TimeE.QuadPart - TimeS1.QuadPart;
  186. if (PoolType == NonPagedPool)
  187. {
  188. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_AfpAllocCountN);
  189. }
  190. else
  191. {
  192. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_AfpAllocTimeP,
  193. TimeD,
  194. &AfpStatisticsLock);
  195. }
  196. #endif
  197. // Save the size of this block along with the tag in the extra space we allocated.
  198. pDwordBuf = (PDWORD)Buffer;
  199. #if DBG
  200. *pDwordBuf = 0xCAFEBEAD;
  201. #endif
  202. // skip past the unused dword (it's only use in life is to get the buffer quad-aligned!)
  203. pDwordBuf++;
  204. ((PTAG)pDwordBuf)->tg_Size = Size;
  205. ((PTAG)pDwordBuf)->tg_Tag = (PoolType == PagedPool) ? PGD_MEM_TAG : NPG_MEM_TAG;
  206. #if DBG
  207. // Write the signature at the end
  208. *(PDWORD)((PBYTE)Buffer + Size - sizeof(DWORD)) = Signature;
  209. #endif
  210. #ifdef TRACK_MEMORY_USAGE
  211. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  212. ("AfpAllocMemory: %lx Allocated %lx bytes @%lx\n",
  213. *(PDWORD)((PBYTE)(&Size) - sizeof(Size)), Size, Buffer));
  214. AfpTrackMemoryUsage(Buffer, True, (BOOLEAN)(PoolType == PagedPool), FileLine);
  215. #endif
  216. // Return a pointer to the memory after the tag. Clear the memory, if requested
  217. //
  218. // We need the memory to be quad-aligned, so even though sizeof(TAG) is 4, we skip
  219. // LONGLONG..., which is 8. The 1st dword is unused (for now?), the 2nd dword is the TAG
  220. Buffer += LONGLONGSIZEBLOCK(sizeof(TAG));
  221. Size -= LONGLONGSIZEBLOCK(sizeof(TAG));
  222. if (Zeroed)
  223. {
  224. #if DBG
  225. RtlZeroMemory(Buffer, Size - sizeof(DWORD));
  226. #else
  227. RtlZeroMemory(Buffer, Size);
  228. #endif
  229. }
  230. return Buffer;
  231. }
  232. /*** AfpAllocNonPagedLowPriority
  233. *
  234. * Allocate a block of non-paged memory with a low priority
  235. */
  236. PBYTE FASTCALL
  237. AfpAllocNonPagedLowPriority(
  238. #ifdef TRACK_MEMORY_USAGE
  239. IN LONG Size,
  240. IN DWORD FileLine
  241. #else
  242. IN LONG Size
  243. #endif
  244. )
  245. {
  246. KIRQL OldIrql;
  247. PBYTE Buffer;
  248. DWORD OldMaxUsage;
  249. POOL_TYPE PoolType;
  250. PDWORD pCurUsage, pMaxUsage, pCount, pLimit;
  251. PDWORD pDwordBuf;
  252. #if DBG
  253. DWORD Signature;
  254. #endif
  255. #ifdef PROFILING
  256. TIME TimeS1, TimesS2, TimeE, TimeD;
  257. AfpGetPerfCounter(&TimeS1);
  258. #endif
  259. ASSERT ((Size & ~MEMORY_TAG_MASK) < MAXIMUM_ALLOC_SIZE);
  260. PoolType = NonPagedPool;
  261. pCurUsage = &AfpServerStatistics.stat_CurrNonPagedUsage;
  262. pMaxUsage = &AfpServerStatistics.stat_MaxNonPagedUsage;
  263. pCount = &AfpServerStatistics.stat_NonPagedCount;
  264. pLimit = &AfpNonPagedPoolLimit;
  265. #if DBG
  266. Signature = NONPAGED_BLOCK_SIGNATURE;
  267. #endif
  268. Size &= ~MEMORY_TAG_MASK;
  269. Size = DWORDSIZEBLOCK(Size) +
  270. #if DBG
  271. sizeof(DWORD) + // For the signature
  272. #endif
  273. LONGLONGSIZEBLOCK(sizeof(TAG));
  274. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  275. *pCurUsage += Size;
  276. (*pCount) ++;
  277. OldMaxUsage = *pMaxUsage;
  278. if (*pCurUsage > *pMaxUsage)
  279. *pMaxUsage = *pCurUsage;
  280. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  281. #ifdef PROFILING
  282. AfpGetPerfCounter(&TimeS2);
  283. #endif
  284. // Do the actual memory allocation. Allocate four extra bytes so
  285. // that we can store the size of the allocation for the free routine.
  286. Buffer = ExAllocatePoolWithTagPriority(PoolType,
  287. Size,
  288. AFP_TAG,
  289. LowPoolPriority);
  290. if (Buffer == NULL)
  291. {
  292. ASSERT(0);
  293. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  294. *pCurUsage -= Size;
  295. *pMaxUsage = OldMaxUsage;
  296. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  297. AFPLOG_DDERROR(AFPSRVMSG_PAGED_POOL, STATUS_NO_MEMORY, &Size,
  298. sizeof(Size), NULL);
  299. return NULL;
  300. }
  301. #ifdef PROFILING
  302. AfpGetPerfCounter(&TimeE);
  303. TimeD.QuadPart = TimeE.QuadPart - TimeS2.QuadPart;
  304. INTERLOCKED_INCREMENT_LONG(AfpServerProfile->perf_ExAllocCountN);
  305. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_ExAllocTimeN,
  306. TimeD,
  307. &AfpStatisticsLock);
  308. TimeD.QuadPart = TimeE.QuadPart - TimeS1.QuadPart;
  309. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_AfpAllocCountN);
  310. #endif
  311. // Save the size of this block along with the tag in the extra space we allocated.
  312. pDwordBuf = (PDWORD)Buffer;
  313. #if DBG
  314. *pDwordBuf = 0xCAFEBEAD;
  315. #endif
  316. // skip past the unused dword (it's only use in life is to get the buffer quad-aligned!)
  317. pDwordBuf++;
  318. ((PTAG)pDwordBuf)->tg_Size = Size;
  319. ((PTAG)pDwordBuf)->tg_Tag = (PoolType == PagedPool) ? PGD_MEM_TAG : NPG_MEM_TAG;
  320. #if DBG
  321. // Write the signature at the end
  322. *(PDWORD)((PBYTE)Buffer + Size - sizeof(DWORD)) = Signature;
  323. #endif
  324. #ifdef TRACK_MEMORY_USAGE
  325. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  326. ("AfpAllocMemory: %lx Allocated %lx bytes @%lx\n",
  327. *(PDWORD)((PBYTE)(&Size) - sizeof(Size)), Size, Buffer));
  328. AfpTrackMemoryUsage(Buffer, True, (BOOLEAN)(PoolType == PagedPool), FileLine);
  329. #endif
  330. // Return a pointer to the memory after the tag. Clear the memory, if requested
  331. //
  332. // We need the memory to be quad-aligned, so even though sizeof(TAG) is 4, we skip
  333. // LONGLONG..., which is 8. The 1st dword is unused (for now?), the 2nd dword is the TAG
  334. Buffer += LONGLONGSIZEBLOCK(sizeof(TAG));
  335. Size -= LONGLONGSIZEBLOCK(sizeof(TAG));
  336. return Buffer;
  337. }
  338. /*** AfpFreeMemory
  339. *
  340. * Free the block of memory allocated via AfpAllocMemory.
  341. * This is a wrapper around ExFreePool.
  342. */
  343. VOID FASTCALL
  344. AfpFreeMemory(
  345. IN PVOID pBuffer
  346. )
  347. {
  348. BOOLEAN Paged = False;
  349. DWORD Size;
  350. DWORD numDwords;
  351. PDWORD pDwordBuf;
  352. PTAG pTag;
  353. DWORD i;
  354. #ifdef PROFILING
  355. TIME TimeS1, TimeS2, TimeE, TimeD1, TimeD2;
  356. AfpGetPerfCounter(&TimeS1);
  357. #endif
  358. //
  359. // Get a pointer to the block allocated by ExAllocatePool.
  360. //
  361. pTag = (PTAG)((PBYTE)pBuffer - sizeof(TAG));
  362. Size = pTag->tg_Size;
  363. if (pTag->tg_Tag == IO_POOL_TAG)
  364. {
  365. AfpIOFreeBuffer(pBuffer);
  366. return;
  367. }
  368. pBuffer = ((PBYTE)pBuffer - LONGLONGSIZEBLOCK(sizeof(TAG)));
  369. if (pTag->tg_Tag == PGD_MEM_TAG)
  370. Paged = True;
  371. #if DBG
  372. {
  373. DWORD Signature;
  374. // Check the signature at the end
  375. Signature = (Paged) ? PAGED_BLOCK_SIGNATURE : NONPAGED_BLOCK_SIGNATURE;
  376. if (*(PDWORD)((PBYTE)pBuffer + Size - sizeof(DWORD)) != Signature)
  377. {
  378. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_FATAL,
  379. ("AfpFreeMemory: Memory Overrun\n"));
  380. DBGBRK(DBG_LEVEL_FATAL);
  381. return;
  382. }
  383. // Clear the signature
  384. *(PDWORD)((PBYTE)pBuffer + Size - sizeof(DWORD)) -= 1;
  385. // change the memory so that we can catch weirdnesses like using freed memory
  386. numDwords = (Size/sizeof(DWORD));
  387. numDwords -= 3; // 2 dwords at the beginning and 1 at the end
  388. pDwordBuf = (PULONG)pBuffer;
  389. *pDwordBuf++ = 0xABABABAB; // to indicate that it's freed!
  390. pDwordBuf++; // skip past the tag
  391. for (i=0; i<numDwords; i++,pDwordBuf++)
  392. {
  393. *pDwordBuf = 0x55667788;
  394. }
  395. }
  396. #endif // DBG
  397. #ifdef TRACK_MEMORY_USAGE
  398. AfpTrackMemoryUsage(pBuffer, False, Paged, 0);
  399. #endif
  400. //
  401. // Update the pool usage statistic.
  402. //
  403. if (Paged)
  404. {
  405. INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_CurrPagedUsage,
  406. (ULONG)(-(LONG)Size),
  407. &AfpStatisticsLock);
  408. INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_PagedCount,
  409. (ULONG)-1,
  410. &AfpStatisticsLock);
  411. }
  412. else
  413. {
  414. INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_CurrNonPagedUsage,
  415. (ULONG)(-(LONG)Size),
  416. &AfpStatisticsLock);
  417. INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_NonPagedCount,
  418. (ULONG)-1,
  419. &AfpStatisticsLock);
  420. }
  421. #ifdef PROFILING
  422. AfpGetPerfCounter(&TimeS2);
  423. #endif
  424. // Free the pool and return.
  425. ExFreePool(pBuffer);
  426. #ifdef PROFILING
  427. AfpGetPerfCounter(&TimeE);
  428. TimeD2.QuadPart = TimeE.QuadPart - TimeS2.QuadPart;
  429. if (Paged)
  430. {
  431. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_ExFreeCountP);
  432. INTERLOCKED_ADD_LARGE_INTGR(AfpServerProfile->perf_ExFreeTimeP,
  433. TimeD2,
  434. &AfpStatisticsLock);
  435. TimeD1.QuadPart = TimeE.QuadPart - TimeS1.QuadPart;
  436. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_AfpFreeCountP);
  437. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_AfpFreeTimeP,
  438. TimeD1,
  439. &AfpStatisticsLock);
  440. }
  441. else
  442. {
  443. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_ExFreeCountN);
  444. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_ExFreeTimeN,
  445. TimeD2,
  446. &AfpStatisticsLock);
  447. TimeD1.QuadPart = TimeE.QuadPart - TimeS1.QuadPart;
  448. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_AfpFreeCountN);
  449. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_AfpFreeTimeN,
  450. TimeD1,
  451. &AfpStatisticsLock);
  452. }
  453. #endif
  454. }
  455. /*** AfpAllocPAMemory
  456. *
  457. * Similar to AfpAllocMemory, except that this allocates page-aligned/page-granular memory.
  458. */
  459. PBYTE FASTCALL
  460. AfpAllocPAMemory(
  461. #ifdef TRACK_MEMORY_USAGE
  462. IN LONG Size,
  463. IN DWORD FileLine
  464. #else
  465. IN LONG Size
  466. #endif
  467. )
  468. {
  469. KIRQL OldIrql;
  470. PBYTE Buffer;
  471. DWORD OldMaxUsage;
  472. POOL_TYPE PoolType;
  473. PDWORD pCurUsage, pMaxUsage, pCount, pLimit;
  474. BOOLEAN PageAligned;
  475. #if DBG
  476. DWORD Signature;
  477. #endif
  478. #ifdef PROFILING
  479. TIME TimeS1, TimeS2, TimeE, TimeD;
  480. AfpGetPerfCounter(&TimeS1);
  481. #endif
  482. ASSERT ((Size & ~MEMORY_TAG_MASK) < MAXIMUM_ALLOC_SIZE);
  483. ASSERT (((Size & ~MEMORY_TAG_MASK) % PAGE_SIZE) == 0);
  484. //
  485. // Make sure that this allocation will not put us over the limit
  486. // of paged/non-paged pool that we can allocate.
  487. //
  488. // Account for this allocation in the statistics database.
  489. if (Size & NON_PAGED_MEMORY_TAG)
  490. {
  491. PoolType = NonPagedPool;
  492. pCurUsage = &AfpServerStatistics.stat_CurrNonPagedUsage;
  493. pMaxUsage = &AfpServerStatistics.stat_MaxNonPagedUsage;
  494. pCount = &AfpServerStatistics.stat_NonPagedCount;
  495. pLimit = &AfpNonPagedPoolLimit;
  496. #if DBG
  497. Signature = NONPAGED_BLOCK_SIGNATURE;
  498. #endif
  499. }
  500. else
  501. {
  502. ASSERT (Size & PAGED_MEMORY_TAG);
  503. PoolType = PagedPool;
  504. pCurUsage = &AfpServerStatistics.stat_CurrPagedUsage;
  505. pMaxUsage = &AfpServerStatistics.stat_MaxPagedUsage;
  506. pCount = &AfpServerStatistics.stat_PagedCount;
  507. pLimit = &AfpPagedPoolLimit;
  508. #if DBG
  509. Signature = PAGED_BLOCK_SIGNATURE;
  510. #endif
  511. }
  512. Size &= ~MEMORY_TAG_MASK;
  513. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  514. *pCurUsage += Size;
  515. (*pCount) ++;
  516. // apparently very old code, added to track some problem: not needed anymore
  517. #if 0
  518. #if DBG
  519. // Make sure that this allocation will not put us over the limit
  520. // of paged pool that we can allocate. ONLY FOR CHECKED BUILDS NOW.
  521. if (*pCurUsage > *pLimit)
  522. {
  523. *pCurUsage -= Size;
  524. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_ERR,
  525. ("afpAllocMemory: %sPaged Allocation exceeds limits %lx/%lx\n",
  526. (PoolType == NonPagedPool) ? "Non" : "", Size, *pLimit));
  527. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  528. DBGBRK(DBG_LEVEL_FATAL);
  529. AFPLOG_DDERROR((PoolType == PagedPool) ?
  530. AFPSRVMSG_PAGED_POOL : AFPSRVMSG_NONPAGED_POOL,
  531. STATUS_NO_MEMORY,
  532. NULL,
  533. 0,
  534. NULL);
  535. return NULL;
  536. }
  537. #endif
  538. #endif // #if 0
  539. OldMaxUsage = *pMaxUsage;
  540. if (*pCurUsage > *pMaxUsage)
  541. *pMaxUsage = *pCurUsage;
  542. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  543. #ifdef PROFILING
  544. AfpGetPerfCounter(&TimeS2);
  545. #endif
  546. // Do the actual memory allocation.
  547. if ((Buffer = ExAllocatePoolWithTag(PoolType, Size, AFP_TAG)) == NULL)
  548. {
  549. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  550. *pCurUsage -= Size;
  551. *pMaxUsage = OldMaxUsage;
  552. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  553. AFPLOG_DDERROR(AFPSRVMSG_PAGED_POOL, STATUS_NO_MEMORY, &Size,
  554. sizeof(Size), NULL);
  555. #if DBG
  556. DbgBreakPoint();
  557. #endif
  558. return NULL;
  559. }
  560. #ifdef PROFILING
  561. AfpGetPerfCounter(&TimeE);
  562. TimeD.QuadPart = TimeE.QuadPart - TimeS2.QuadPart;
  563. INTERLOCKED_INCREMENT_LONG((PoolType == NonPagedPool) ?
  564. &AfpServerProfile->perf_ExAllocCountN :
  565. &AfpServerProfile->perf_ExAllocCountP);
  566. INTERLOCKED_ADD_LARGE_INTGR((PoolType == NonPagedPool) ?
  567. &AfpServerProfile->perf_ExAllocTimeN :
  568. &AfpServerProfile->perf_ExAllocTimeP,
  569. TimeD,
  570. &AfpStatisticsLock);
  571. TimeD.QuadPart = TimeE.QuadPart - TimeS1.QuadPart;
  572. INTERLOCKED_INCREMENT_LONG((PoolType == NonPagedPool) ?
  573. &AfpServerProfile->perf_AfpAllocCountN :
  574. &AfpServerProfile->perf_AfpAllocCountP);
  575. INTERLOCKED_ADD_LARGE_INTGR((PoolType == NonPagedPool) ?
  576. &AfpServerProfile->perf_AfpAllocTimeN :
  577. &AfpServerProfile->perf_AfpAllocTimeP,
  578. TimeD,
  579. &AfpStatisticsLock);
  580. #endif
  581. #ifdef TRACK_MEMORY_USAGE
  582. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  583. ("AfpAllocMemory: %lx Allocated %lx bytes @%lx\n",
  584. *(PDWORD)((PBYTE)(&Size) - sizeof(Size)), Size, Buffer));
  585. AfpTrackMemoryUsage(Buffer, True, (BOOLEAN)(PoolType == PagedPool), FileLine);
  586. #endif
  587. return Buffer;
  588. }
  589. /*** AfpFreePAMemory
  590. *
  591. * Free the block of memory allocated via AfpAllocPAMemory.
  592. */
  593. VOID FASTCALL
  594. AfpFreePAMemory(
  595. IN PVOID pBuffer,
  596. IN DWORD Size
  597. )
  598. {
  599. BOOLEAN Paged = True;
  600. #ifdef PROFILING
  601. TIME TimeS1, TimeS2, TimeE, TimeD;
  602. AfpGetPerfCounter(&TimeS1);
  603. #endif
  604. ASSERT ((Size & ~MEMORY_TAG_MASK) < MAXIMUM_ALLOC_SIZE);
  605. ASSERT (((Size & ~MEMORY_TAG_MASK) % PAGE_SIZE) == 0);
  606. if (Size & NON_PAGED_MEMORY_TAG)
  607. Paged = False;
  608. #ifdef TRACK_MEMORY_USAGE
  609. AfpTrackMemoryUsage(pBuffer, False, Paged, 0);
  610. #endif
  611. //
  612. // Update the pool usage statistic.
  613. //
  614. Size &= ~(NON_PAGED_MEMORY_TAG | PAGED_MEMORY_TAG);
  615. if (Paged)
  616. {
  617. INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_CurrPagedUsage,
  618. (ULONG)(-(LONG)Size),
  619. &AfpStatisticsLock);
  620. INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_PagedCount,
  621. (ULONG)-1,
  622. &AfpStatisticsLock);
  623. }
  624. else
  625. {
  626. INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_CurrNonPagedUsage,
  627. (ULONG)(-(LONG)Size),
  628. &AfpStatisticsLock);
  629. INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_NonPagedCount,
  630. (ULONG)-1,
  631. &AfpStatisticsLock);
  632. }
  633. #ifdef PROFILING
  634. AfpGetPerfCounter(&TimeS2);
  635. #endif
  636. // Free the pool and return.
  637. ExFreePool(pBuffer);
  638. #ifdef PROFILING
  639. AfpGetPerfCounter(&TimeE);
  640. TimeD.QuadPart = TimeE.QuadPart - TimeS2.QuadPart;
  641. INTERLOCKED_INCREMENT_LONG( Paged ?
  642. &AfpServerProfile->perf_ExFreeCountP :
  643. &AfpServerProfile->perf_ExFreeCountN);
  644. INTERLOCKED_ADD_LARGE_INTGR(Paged ?
  645. &AfpServerProfile->perf_ExFreeTimeP :
  646. &AfpServerProfile->perf_ExFreeTimeN,
  647. TimeD,
  648. &AfpStatisticsLock);
  649. TimeD1.QuadPart = TimeE.QuadPart - TimeS1.QuadPart;
  650. INTERLOCKED_INCREMENT_LONG( Paged ?
  651. &AfpServerProfile->perf_AfpFreeCountP :
  652. &AfpServerProfile->perf_AfpFreeCountN);
  653. INTERLOCKED_ADD_LARGE_INTGR(Paged ?
  654. &AfpServerProfile->perf_AfpFreeTimeP :
  655. &AfpServerProfile->perf_AfpFreeTimeN,
  656. TimeD,
  657. &AfpStatisticsLock);
  658. #endif
  659. }
  660. /*** AfpAllocIrp
  661. *
  662. * This is a wrapper over IoAllocateIrp. We also do some book-keeping.
  663. */
  664. PIRP FASTCALL
  665. AfpAllocIrp(
  666. IN CCHAR StackSize
  667. )
  668. {
  669. PIRP pIrp;
  670. if ((pIrp = IoAllocateIrp(StackSize, False)) == NULL)
  671. {
  672. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_INFO,
  673. ("afpAllocIrp: Allocation failed\n"));
  674. if (KeGetCurrentIrql() < DISPATCH_LEVEL)
  675. {
  676. AFPLOG_ERROR(AFPSRVMSG_ALLOC_IRP, STATUS_INSUFFICIENT_RESOURCES,
  677. NULL, 0, NULL);
  678. }
  679. }
  680. else
  681. {
  682. #ifdef PROFILING
  683. INTERLOCKED_INCREMENT_LONG((PLONG)&AfpServerProfile->perf_cAllocatedIrps);
  684. #endif
  685. AFP_DBG_INC_COUNT(AfpDbgIrpsAlloced);
  686. }
  687. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  688. ("AfAllocIrp: Allocated Irp %lx\n", pIrp));
  689. return pIrp;
  690. }
  691. /*** AfpFreeIrp
  692. *
  693. * This is a wrapper over IoFreeIrp. We also do some book-keeping.
  694. */
  695. VOID FASTCALL
  696. AfpFreeIrp(
  697. IN PIRP pIrp
  698. )
  699. {
  700. ASSERT (pIrp != NULL);
  701. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  702. ("AfFreeIrp: Freeing Irp %lx\n", pIrp));
  703. IoFreeIrp(pIrp);
  704. AFP_DBG_DEC_COUNT(AfpDbgIrpsAlloced);
  705. #ifdef PROFILING
  706. INTERLOCKED_DECREMENT_LONG((PLONG)&AfpServerProfile->perf_cAllocatedIrps);
  707. #endif
  708. }
  709. /*** AfpAllocMdl
  710. *
  711. * This is a wrapper over IoAllocateMdl. We also do some book-keeping.
  712. */
  713. PMDL FASTCALL
  714. AfpAllocMdl(
  715. IN PVOID pBuffer,
  716. IN DWORD Size,
  717. IN PIRP pIrp
  718. )
  719. {
  720. PMDL pMdl;
  721. if ((pMdl = IoAllocateMdl(pBuffer, Size, False, False, pIrp)) == NULL)
  722. {
  723. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_INFO,
  724. ("AfpAllocMdl: Allocation failed\n"));
  725. AFPLOG_ERROR(AFPSRVMSG_ALLOC_MDL, STATUS_INSUFFICIENT_RESOURCES,
  726. NULL, 0, NULL);
  727. }
  728. else
  729. {
  730. #ifdef PROFILING
  731. INTERLOCKED_INCREMENT_LONG((PLONG)&AfpServerProfile->perf_cAllocatedMdls);
  732. #endif
  733. AFP_DBG_INC_COUNT(AfpDbgMdlsAlloced);
  734. MmBuildMdlForNonPagedPool(pMdl);
  735. }
  736. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  737. ("AfAllocMdl: Allocated Mdl %lx\n", pMdl));
  738. return pMdl;
  739. }
  740. /*** AfpFreeMdl
  741. *
  742. * This is a wrapper over IoFreeMdl. We also do some book-keeping.
  743. */
  744. VOID FASTCALL
  745. AfpFreeMdl(
  746. IN PMDL pMdl
  747. )
  748. {
  749. ASSERT (pMdl != NULL);
  750. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  751. ("AfFreeMdl: Freeing Mdl %lx\n", pMdl));
  752. IoFreeMdl(pMdl);
  753. AFP_DBG_DEC_COUNT(AfpDbgMdlsAlloced);
  754. #ifdef PROFILING
  755. INTERLOCKED_DECREMENT_LONG((PLONG)&AfpServerProfile->perf_cAllocatedMdls);
  756. #endif
  757. }
  758. /*** AfpMdlChainSize
  759. *
  760. * This routine counts the bytes in the mdl chain
  761. */
  762. DWORD FASTCALL
  763. AfpMdlChainSize(
  764. IN PMDL pMdl
  765. )
  766. {
  767. DWORD dwSize=0;
  768. while (pMdl)
  769. {
  770. dwSize += MmGetMdlByteCount(pMdl);
  771. pMdl = pMdl->Next;
  772. }
  773. return (dwSize);
  774. }
  775. /*** AfpIOAllocBuffer
  776. *
  777. * Maintain a pool of I/O buffers and fork-locks. These are aged out when not in use.
  778. */
  779. PVOID FASTCALL
  780. AfpIOAllocBuffer(
  781. IN DWORD BufSize
  782. )
  783. {
  784. KIRQL OldIrql;
  785. PIOPOOL pPool;
  786. PIOPOOL_HDR pPoolHdr, *ppPoolHdr;
  787. BOOLEAN Found = False;
  788. PVOID pBuf = NULL;
  789. #ifdef PROFILING
  790. TIME TimeS, TimeE, TimeD;
  791. INTERLOCKED_INCREMENT_LONG( &AfpServerProfile->perf_BPAllocCount );
  792. AfpGetPerfCounter(&TimeS);
  793. #endif
  794. ASSERT (BufSize <= (DSI_SERVER_REQUEST_QUANTUM+DSI_HEADER_SIZE));
  795. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  796. ("AfpIOAllocBuffer: Request for %d\n", BufSize));
  797. //
  798. // if a large block (over 4K on x86) is being allocated, we don't want to
  799. // tie it in in the IoPool. Do a direct allocation, set flags etc. so we know
  800. // how to free it when it's freed
  801. //
  802. if (BufSize > ASP_QUANTUM)
  803. {
  804. pPoolHdr = (PIOPOOL_HDR) ExAllocatePoolWithTag(
  805. NonPagedPool,
  806. (BufSize + sizeof(IOPOOL_HDR)),
  807. AFP_TAG);
  808. if (pPoolHdr == NULL)
  809. {
  810. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  811. ("AfpIOAllocBuffer: big buf alloc (%d bytes) failed!\n",BufSize));
  812. return(NULL);
  813. }
  814. #if DBG
  815. pPoolHdr->Signature = POOLHDR_SIGNATURE;
  816. #endif
  817. pPoolHdr->iph_Tag.tg_Tag = IO_POOL_TAG;
  818. pPoolHdr->iph_Tag.tg_Flags = IO_POOL_HUGE_BUFFER;
  819. // we only have 20 bits for tg_Size, so the size had better be less than that!
  820. ASSERT(BufSize <= 0xFFFFF);
  821. pPoolHdr->iph_Tag.tg_Size = BufSize;
  822. return((PVOID)((PBYTE)pPoolHdr + sizeof(IOPOOL_HDR)));
  823. }
  824. ACQUIRE_SPIN_LOCK(&afpIoPoolLock, &OldIrql);
  825. try_again:
  826. for (pPool = afpIoPoolHead;
  827. pPool != NULL;
  828. pPool = pPool->iop_Next)
  829. {
  830. ASSERT(VALID_IOP(pPool));
  831. if (BufSize > sizeof(FORKLOCK))
  832. {
  833. if (pPool->iop_NumFreeBufs > 0)
  834. {
  835. LONG i;
  836. for (i = 0, ppPoolHdr = &pPool->iop_FreeBufHead;
  837. (i < pPool->iop_NumFreeBufs);
  838. ppPoolHdr = &pPoolHdr->iph_Next, i++)
  839. {
  840. pPoolHdr = *ppPoolHdr;
  841. ASSERT(VALID_PLH(pPoolHdr));
  842. if (pPoolHdr->iph_Tag.tg_Size >= BufSize)
  843. {
  844. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  845. ("AfpIOAllocBuffer: Found space (bufs) in pool %lx\n", pPool));
  846. ASSERT (pPoolHdr->iph_Tag.tg_Flags == IO_POOL_NOT_IN_USE);
  847. *ppPoolHdr = pPoolHdr->iph_Next;
  848. INTERLOCKED_INCREMENT_LONG((PLONG)&AfpServerStatistics.stat_IoPoolHits);
  849. Found = True;
  850. break;
  851. }
  852. }
  853. if (Found)
  854. break;
  855. }
  856. }
  857. else if (pPool->iop_NumFreeLocks > 0)
  858. {
  859. // Even IO buffers for size <= sizeof(FORKLOCK) are allocated out of the
  860. // lock pool - hey why not !!!
  861. pPoolHdr = pPool->iop_FreeLockHead;
  862. ASSERT(VALID_PLH(pPoolHdr));
  863. ASSERT(pPoolHdr->iph_Tag.tg_Flags == IO_POOL_NOT_IN_USE);
  864. pPool->iop_FreeLockHead = pPoolHdr->iph_Next;
  865. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  866. ("AfpIOAllocBuffer: Found space (locks) in pool %lx\n", pPool));
  867. INTERLOCKED_INCREMENT_LONG((PLONG)&AfpServerStatistics.stat_IoPoolHits);
  868. Found = True;
  869. break;
  870. }
  871. // All empty pool blocks are the end.
  872. if ((pPool->iop_NumFreeBufs == 0) && (pPool->iop_NumFreeLocks == 0))
  873. {
  874. break;
  875. }
  876. }
  877. if (!Found)
  878. {
  879. INTERLOCKED_INCREMENT_LONG((PLONG)&AfpServerStatistics.stat_IoPoolMisses);
  880. // If we failed to find it, allocate a new pool chunk, initialize and
  881. // link it in
  882. pPool = (PIOPOOL)AfpAllocNonPagedMemory(POOL_ALLOC_SIZE);
  883. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  884. ("AfpIOAllocBuffer: No free slot, allocated a new pool %lx\n", pPool));
  885. if (pPool != NULL)
  886. {
  887. LONG i;
  888. PBYTE p;
  889. #if DBG
  890. pPool->Signature = IOPOOL_SIGNATURE;
  891. #endif
  892. pPool->iop_NumFreeBufs = NUM_BUFS_IN_POOL;
  893. pPool->iop_NumFreeLocks = (BYTE)NUM_LOCKS_IN_POOL;
  894. AfpLinkDoubleAtHead(afpIoPoolHead, pPool, iop_Next, iop_Prev);
  895. p = (PBYTE)pPool + sizeof(IOPOOL);
  896. pPool->iop_FreeBufHead = (PIOPOOL_HDR)p;
  897. // Initialize pool of buffers and locks
  898. for (i = 0, pPoolHdr = pPool->iop_FreeBufHead;
  899. i < (NUM_BUFS_IN_POOL + NUM_LOCKS_IN_POOL);
  900. i++)
  901. {
  902. #if DBG
  903. pPoolHdr->Signature = POOLHDR_SIGNATURE;
  904. #endif
  905. pPoolHdr->iph_Tag.tg_Flags = IO_POOL_NOT_IN_USE; // Mark it un-used
  906. pPoolHdr->iph_Tag.tg_Tag = IO_POOL_TAG;
  907. if (i < NUM_BUFS_IN_POOL)
  908. {
  909. p += sizeof(IOPOOL_HDR) + (pPoolHdr->iph_Tag.tg_Size = afpPoolAllocSizes[i]);
  910. if (i == (NUM_BUFS_IN_POOL-1))
  911. {
  912. pPoolHdr->iph_Next = NULL;
  913. pPoolHdr = pPool->iop_FreeLockHead = (PIOPOOL_HDR)p;
  914. }
  915. else
  916. {
  917. pPoolHdr->iph_Next = (PIOPOOL_HDR)p;
  918. pPoolHdr = (PIOPOOL_HDR)p;
  919. }
  920. }
  921. else
  922. {
  923. pPoolHdr->iph_Tag.tg_Size = sizeof(FORKLOCK);
  924. p += (sizeof(IOPOOL_HDR) + sizeof(FORKLOCK));
  925. if (i == (NUM_BUFS_IN_POOL+NUM_LOCKS_IN_POOL-1))
  926. {
  927. pPoolHdr->iph_Next = NULL;
  928. }
  929. else
  930. {
  931. pPoolHdr->iph_Next = (PIOPOOL_HDR)p;
  932. pPoolHdr = (PIOPOOL_HDR)p;
  933. }
  934. }
  935. }
  936. // Adjust this since we'll increment this again up above. This was
  937. // really a miss and not a hit
  938. INTERLOCKED_DECREMENT_LONG((PLONG)&AfpServerStatistics.stat_IoPoolHits);
  939. goto try_again;
  940. }
  941. }
  942. if (Found)
  943. {
  944. PIOPOOL pTmp;
  945. ASSERT(VALID_IOP(pPool));
  946. ASSERT(VALID_PLH(pPoolHdr));
  947. pPoolHdr->iph_pPool = pPool;
  948. pPoolHdr->iph_Tag.tg_Flags = IO_POOL_IN_USE; // Mark it used
  949. pPool->iop_Age = 0;
  950. pBuf = (PBYTE)pPoolHdr + sizeof(IOPOOL_HDR);
  951. if (BufSize > sizeof(FORKLOCK))
  952. {
  953. pPool->iop_NumFreeBufs --;
  954. }
  955. else
  956. {
  957. pPool->iop_NumFreeLocks --;
  958. }
  959. // If the block is now empty, unlink it from here and move it
  960. // to the first empty slot. We know that all blocks 'earlier' than
  961. // this are non-empty.
  962. if ((pPool->iop_NumFreeBufs == 0) &&
  963. (pPool->iop_NumFreeLocks == 0) &&
  964. ((pTmp = pPool->iop_Next) != NULL) &&
  965. ((pTmp->iop_NumFreeBufs > 0) || (pTmp->iop_NumFreeLocks > 0)))
  966. {
  967. ASSERT(VALID_IOP(pTmp));
  968. AfpUnlinkDouble(pPool, iop_Next, iop_Prev);
  969. for (; pTmp != NULL; pTmp = pTmp->iop_Next)
  970. {
  971. if (pTmp->iop_NumFreeBufs == 0)
  972. {
  973. // Found a free one. Park it right here.
  974. AfpInsertDoubleBefore(pPool, pTmp, iop_Next, iop_Prev);
  975. break;
  976. }
  977. else if (pTmp->iop_Next == NULL) // We reached the end
  978. {
  979. AfpLinkDoubleAtEnd(pPool, pTmp, iop_Next, iop_Prev);
  980. break;
  981. }
  982. }
  983. }
  984. }
  985. RELEASE_SPIN_LOCK(&afpIoPoolLock, OldIrql);
  986. #ifdef PROFILING
  987. AfpGetPerfCounter(&TimeE);
  988. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  989. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_BPAllocTime,
  990. TimeD,
  991. &AfpStatisticsLock);
  992. #endif
  993. return pBuf;
  994. }
  995. /*** AfpIOFreeBuffer
  996. *
  997. * Return the IO buffer to the pool. Reset its age to 0. Insert into the free list
  998. * in ascending order of sizes for bufs and at the head for locks
  999. */
  1000. VOID FASTCALL
  1001. AfpIOFreeBuffer(
  1002. IN PVOID pBuf
  1003. )
  1004. {
  1005. KIRQL OldIrql;
  1006. PIOPOOL pPool;
  1007. PIOPOOL_HDR pPoolHdr, *ppPoolHdr;
  1008. #ifdef PROFILING
  1009. TIME TimeS, TimeE, TimeD;
  1010. INTERLOCKED_INCREMENT_LONG( &AfpServerProfile->perf_BPFreeCount);
  1011. AfpGetPerfCounter(&TimeS);
  1012. #endif
  1013. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  1014. ("AfpIOFreeBuffer: Freeing %lx\n", pBuf));
  1015. pPoolHdr = (PIOPOOL_HDR)((PBYTE)pBuf - sizeof(IOPOOL_HDR));
  1016. ASSERT(VALID_PLH(pPoolHdr));
  1017. ASSERT (pPoolHdr->iph_Tag.tg_Flags != IO_POOL_NOT_IN_USE);
  1018. ASSERT (pPoolHdr->iph_Tag.tg_Tag == IO_POOL_TAG);
  1019. //
  1020. // if this is a huge buffer we allocated, free it here and return
  1021. //
  1022. if (pPoolHdr->iph_Tag.tg_Flags == IO_POOL_HUGE_BUFFER)
  1023. {
  1024. ASSERT(pPoolHdr->iph_Tag.tg_Size > ASP_QUANTUM);
  1025. ExFreePool((PVOID)pPoolHdr);
  1026. return;
  1027. }
  1028. pPool = pPoolHdr->iph_pPool;
  1029. ASSERT(VALID_IOP(pPool));
  1030. ACQUIRE_SPIN_LOCK(&afpIoPoolLock, &OldIrql);
  1031. if (pPoolHdr->iph_Tag.tg_Size > sizeof(FORKLOCK))
  1032. {
  1033. ASSERT (pPool->iop_NumFreeBufs < NUM_BUFS_IN_POOL);
  1034. for (ppPoolHdr = &pPool->iop_FreeBufHead;
  1035. (*ppPoolHdr) != NULL;
  1036. ppPoolHdr = &(*ppPoolHdr)->iph_Next)
  1037. {
  1038. ASSERT(VALID_PLH(*ppPoolHdr));
  1039. if ((*ppPoolHdr)->iph_Tag.tg_Size > pPoolHdr->iph_Tag.tg_Size)
  1040. {
  1041. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  1042. ("AfpIOFreeBuffer: Found slot for %lx (%lx)\n",
  1043. pBuf, pPool));
  1044. break;
  1045. }
  1046. }
  1047. pPoolHdr->iph_Next = (*ppPoolHdr);
  1048. *ppPoolHdr = pPoolHdr;
  1049. pPool->iop_NumFreeBufs ++;
  1050. }
  1051. else
  1052. {
  1053. ASSERT (pPool->iop_NumFreeLocks < NUM_LOCKS_IN_POOL);
  1054. pPoolHdr->iph_Next = pPool->iop_FreeLockHead;
  1055. pPool->iop_FreeLockHead = pPoolHdr;
  1056. pPool->iop_NumFreeLocks ++;
  1057. }
  1058. pPoolHdr->iph_Tag.tg_Flags = IO_POOL_NOT_IN_USE; // Mark it un-used
  1059. // If this block's status is changing from a 'none available' to 'available'
  1060. // move him to the head of the list.
  1061. if ((pPool->iop_NumFreeBufs + pPool->iop_NumFreeLocks) == 1)
  1062. {
  1063. AfpUnlinkDouble(pPool, iop_Next, iop_Prev);
  1064. AfpLinkDoubleAtHead(afpIoPoolHead,
  1065. pPool,
  1066. iop_Next,
  1067. iop_Prev);
  1068. }
  1069. RELEASE_SPIN_LOCK(&afpIoPoolLock, OldIrql);
  1070. #ifdef PROFILING
  1071. AfpGetPerfCounter(&TimeE);
  1072. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  1073. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_BPFreeTime,
  1074. TimeD,
  1075. &AfpStatisticsLock);
  1076. #endif
  1077. }
  1078. /*** afpIoPoolAge
  1079. *
  1080. * Scavenger worker for aging out the IO pool.
  1081. */
  1082. LOCAL AFPSTATUS FASTCALL
  1083. afpIoPoolAge(
  1084. IN PVOID pContext
  1085. )
  1086. {
  1087. PIOPOOL pPool;
  1088. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_INFO,
  1089. ("afpIOPoolAge: Entered\n"));
  1090. ACQUIRE_SPIN_LOCK_AT_DPC(&afpIoPoolLock);
  1091. for (pPool = afpIoPoolHead;
  1092. pPool != NULL;
  1093. NOTHING)
  1094. {
  1095. PIOPOOL pFree;
  1096. ASSERT(VALID_IOP(pPool));
  1097. pFree = pPool;
  1098. pPool = pPool->iop_Next;
  1099. // Since all blocks which are completely used up are at the tail end of
  1100. // the list, if we encounter one, we are done.
  1101. if ((pFree->iop_NumFreeBufs == 0) &&
  1102. (pFree->iop_NumFreeLocks == 0))
  1103. break;
  1104. if ((pFree->iop_NumFreeBufs == NUM_BUFS_IN_POOL) &&
  1105. (pFree->iop_NumFreeLocks == NUM_LOCKS_IN_POOL))
  1106. {
  1107. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_WARN,
  1108. ("afpIOPoolAge: Aging pool %lx\n", pFree));
  1109. if (++(pFree->iop_Age) >= MAX_POOL_AGE)
  1110. {
  1111. #ifdef PROFILING
  1112. INTERLOCKED_INCREMENT_LONG( &AfpServerProfile->perf_BPAgeCount);
  1113. #endif
  1114. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_WARN,
  1115. ("afpIOPoolAge: Freeing pool %lx\n", pFree));
  1116. AfpUnlinkDouble(pFree, iop_Next, iop_Prev);
  1117. AfpFreeMemory(pFree);
  1118. }
  1119. }
  1120. }
  1121. RELEASE_SPIN_LOCK_FROM_DPC(&afpIoPoolLock);
  1122. return AFP_ERR_REQUEUE;
  1123. }
  1124. #ifdef TRACK_MEMORY_USAGE
  1125. #define MAX_PTR_COUNT 4*1024
  1126. #define MAX_MEM_USERS 256
  1127. LOCAL struct _MemPtr
  1128. {
  1129. PVOID mptr_Ptr;
  1130. DWORD mptr_FileLine;
  1131. } afpMemPtrs[MAX_PTR_COUNT] = { 0 };
  1132. typedef struct
  1133. {
  1134. ULONG mem_FL;
  1135. ULONG mem_Count;
  1136. } MEM_USAGE, *PMEM_USAGE;
  1137. LOCAL MEM_USAGE afpMemUsageNonPaged[MAX_MEM_USERS] = {0};
  1138. LOCAL MEM_USAGE afpMemUsagePaged[MAX_MEM_USERS] = {0};
  1139. LOCAL AFP_SPIN_LOCK afpMemTrackLock = {0};
  1140. /*** AfpTrackMemoryUsage
  1141. *
  1142. * Keep track of memory usage by storing and clearing away pointers as and
  1143. * when they are allocated or freed. This helps in keeping track of memory
  1144. * leaks.
  1145. *
  1146. * LOCKS: AfpMemTrackLock (SPIN)
  1147. */
  1148. VOID
  1149. AfpTrackMemoryUsage(
  1150. IN PVOID pMem,
  1151. IN BOOLEAN Alloc,
  1152. IN BOOLEAN Paged,
  1153. IN ULONG FileLine
  1154. )
  1155. {
  1156. KIRQL OldIrql;
  1157. static int i = 0;
  1158. PMEM_USAGE pMemUsage;
  1159. int j, k;
  1160. pMemUsage = afpMemUsageNonPaged;
  1161. if (Paged)
  1162. pMemUsage = afpMemUsagePaged;
  1163. ACQUIRE_SPIN_LOCK(&afpMemTrackLock, &OldIrql);
  1164. if (Alloc)
  1165. {
  1166. for (j = 0; j < MAX_PTR_COUNT; i++, j++)
  1167. {
  1168. i = i & (MAX_PTR_COUNT-1);
  1169. if (afpMemPtrs[i].mptr_Ptr == NULL)
  1170. {
  1171. afpMemPtrs[i].mptr_FileLine = FileLine;
  1172. afpMemPtrs[i++].mptr_Ptr = pMem;
  1173. break;
  1174. }
  1175. }
  1176. for (k = 0; k < MAX_MEM_USERS; k++)
  1177. {
  1178. if (pMemUsage[k].mem_FL == FileLine)
  1179. {
  1180. pMemUsage[k].mem_Count ++;
  1181. break;
  1182. }
  1183. }
  1184. if (k == MAX_MEM_USERS)
  1185. {
  1186. for (k = 0; k < MAX_MEM_USERS; k++)
  1187. {
  1188. if (pMemUsage[k].mem_FL == 0)
  1189. {
  1190. pMemUsage[k].mem_FL = FileLine;
  1191. pMemUsage[k].mem_Count = 1;
  1192. break;
  1193. }
  1194. }
  1195. }
  1196. if (k == MAX_MEM_USERS)
  1197. {
  1198. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_ERR,
  1199. ("AfpTrackMemoryUsage: Out of space on afpMemUsage !!!\n"));
  1200. DBGBRK(DBG_LEVEL_FATAL);
  1201. }
  1202. }
  1203. else
  1204. {
  1205. for (j = 0, k = i; j < MAX_PTR_COUNT; j++, k--)
  1206. {
  1207. k = k & (MAX_PTR_COUNT-1);
  1208. if (afpMemPtrs[k].mptr_Ptr == pMem)
  1209. {
  1210. afpMemPtrs[k].mptr_Ptr = NULL;
  1211. afpMemPtrs[k].mptr_FileLine = 0;
  1212. break;
  1213. }
  1214. }
  1215. }
  1216. RELEASE_SPIN_LOCK(&afpMemTrackLock, OldIrql);
  1217. if (j == MAX_PTR_COUNT)
  1218. {
  1219. DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_ERR,
  1220. ("AfpTrackMemoryUsage: (%lx) %s\n",
  1221. FileLine, Alloc ? "Table Full" : "Can't find"));
  1222. }
  1223. }
  1224. #endif // TRACK_MEMORY_USAGE