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.

1576 lines
35 KiB

  1. // Copyright (c) 1997, Microsoft Corporation, all rights reserved
  2. //
  3. // bpool.c
  4. // RAS L2TP WAN mini-port/call-manager driver
  5. // Buffer pool management routines
  6. //
  7. // 01/07/97 Steve Cobb, adapted from Gurdeep's WANARP code.
  8. #define __FILE_SIG__ BPOOL_SIG
  9. #include "inc.h"
  10. LONG g_lHPool;
  11. #define CHECK_LOCK_ENTRY(pPool) \
  12. { \
  13. if(InterlockedExchange(&g_lHPool, \
  14. 1) isnot 0) \
  15. { \
  16. RtAssert(FALSE); \
  17. } \
  18. }
  19. #define CHECK_LOCK_EXIT(pPool) \
  20. { \
  21. if(InterlockedExchange(&g_lHPool, \
  22. 0) isnot 1) \
  23. { \
  24. RtAssert(FALSE); \
  25. } \
  26. }
  27. //-----------------------------------------------------------------------------
  28. // Local prototypes (alphabetically)
  29. //-----------------------------------------------------------------------------
  30. BOOLEAN
  31. AddBufferBlockToPool(
  32. IN PBUFFER_POOL pPool,
  33. OUT BYTE **ppHead
  34. );
  35. VOID
  36. FreeUnusedPoolBlocks(
  37. IN PBUFFER_POOL pPool
  38. );
  39. BOOLEAN
  40. IsEntryOnList(
  41. PLIST_ENTRY pleHead,
  42. PLIST_ENTRY pleEntry
  43. );
  44. //-----------------------------------------------------------------------------
  45. // Interface routines
  46. //-----------------------------------------------------------------------------
  47. VOID
  48. InitBufferPool(
  49. OUT PBUFFER_POOL pPool,
  50. IN ULONG ulBufferSize,
  51. IN ULONG ulMaxBuffers,
  52. IN ULONG ulBuffersPerBlock,
  53. IN ULONG ulFreesPerCollection,
  54. IN BOOLEAN fAssociateNdisBuffer,
  55. IN ULONG ulTag
  56. )
  57. /*++
  58. Routine Description
  59. Initialize caller's buffer pool control block
  60. Locks
  61. Caller's 'pPool' buffer must be protected from multiple access during
  62. this call
  63. Arguments
  64. pPool The buffer pool to be initialized
  65. ulBufferSize Size in bytes of an individual buffer
  66. ulMaxBuffers Maximum number of buffers allowed in the entire
  67. pool or 0 for unlimited.
  68. ulBuffersPerBlock Number of buffers to include in each block of buffers.
  69. ulFreesPerCollection Number of FreeBufferToPool calls until the next
  70. garbage collect scan, or 0 for default.
  71. fAssociateNdisBuffer Set if an NDIS_BUFFER should be allocated and
  72. associated with each individual buffer.
  73. ulTag Pool tag to use when allocating blocks.
  74. Return Value
  75. None
  76. --*/
  77. {
  78. ULONG ulNumBuffers;
  79. pPool->ulBufferSize = ulBufferSize;
  80. pPool->ulMaxBuffers = ulMaxBuffers;
  81. pPool->ulFreesSinceCollection = 0;
  82. pPool->fAssociateNdisBuffer = fAssociateNdisBuffer;
  83. pPool->fAllocatePage = TRUE;
  84. pPool->ulTag = ulTag;
  85. //
  86. // Figure out the number of buffers if we allocated a page
  87. //
  88. ulNumBuffers = (PAGE_SIZE - ALIGN8_BLOCK_SIZE)/(ALIGN8_HEAD_SIZE + ALIGN_UP(ulBufferSize, ULONGLONG));
  89. pPool->ulBuffersPerBlock = ulNumBuffers;
  90. if(ulFreesPerCollection)
  91. {
  92. pPool->ulFreesPerCollection = ulFreesPerCollection;
  93. }
  94. else
  95. {
  96. //
  97. // Calculate default garbage collection trigger. Don't want to be too
  98. // aggressive here.
  99. //
  100. pPool->ulFreesPerCollection = 50 * pPool->ulBuffersPerBlock;
  101. }
  102. InitializeListHead(&(pPool->leBlockHead));
  103. InitializeListHead(&(pPool->leFreeBufferHead));
  104. RtInitializeSpinLock(&(pPool->rlLock));
  105. }
  106. BOOLEAN
  107. FreeBufferPool(
  108. IN PBUFFER_POOL pPool
  109. )
  110. /*++
  111. Routine Description
  112. Free up all resources allocated in buffer pool. This is the
  113. inverse of InitPool.
  114. Locks
  115. Arguments
  116. Return Value
  117. TRUE if successful
  118. FALSE if any of the pool could not be freed due to outstanding packets.
  119. --*/
  120. {
  121. BOOLEAN fSuccess;
  122. KIRQL irql;
  123. RtAcquireSpinLock(&(pPool->rlLock),
  124. &irql);
  125. FreeUnusedPoolBlocks(pPool);
  126. fSuccess = (pPool->ulCurBuffers is 0);
  127. RtReleaseSpinLock(&(pPool->rlLock),
  128. irql);
  129. return fSuccess;
  130. }
  131. #if LIST_DBG
  132. PBYTE
  133. GET(
  134. IN PBUFFER_POOL pPool,
  135. IN ULONG ulFileSig,
  136. IN ULONG ulLine
  137. )
  138. #else
  139. PBYTE
  140. GetBufferFromPool(
  141. IN PBUFFER_POOL pPool
  142. )
  143. #endif
  144. /*++
  145. Routine Description
  146. Returns the address of the useable memory in an individual buffer
  147. allocated from the pool. The pool is expanded, if necessary, but caller
  148. should still check for NULL return since the pool may have been at
  149. maximum size.
  150. Locks
  151. Arguments
  152. pPool Pointer to pool
  153. Return Value
  154. NO_ERROR
  155. --*/
  156. {
  157. PLIST_ENTRY pleNode;
  158. PBUFFER_HEAD pHead;
  159. PBYTE pbyBuffer;
  160. KIRQL irql;
  161. RtAcquireSpinLock(&(pPool->rlLock),
  162. &irql);
  163. if(IsListEmpty(&pPool->leFreeBufferHead))
  164. {
  165. pleNode = NULL;
  166. }
  167. else
  168. {
  169. pleNode = RemoveHeadList(&pPool->leFreeBufferHead);
  170. pHead = CONTAINING_RECORD(pleNode, BUFFER_HEAD, leFreeBufferLink);
  171. #if LIST_DBG
  172. RtAssert(!IsEntryOnList(&pPool->leFreeBufferHead,
  173. pleNode));
  174. pHead->ulAllocFile = ulFileSig;
  175. pHead->ulAllocLine = ulLine;
  176. #endif
  177. pHead->pBlock->ulFreeBuffers--;
  178. //
  179. // If there was an associated NDIS_BUFFER, adjust its length
  180. // to the full size
  181. //
  182. if(pPool->fAssociateNdisBuffer)
  183. {
  184. RtAssert(pHead->pNdisBuffer);
  185. NdisAdjustBufferLength(pHead->pNdisBuffer,
  186. pPool->ulBufferSize);
  187. }
  188. }
  189. #if LIST_DBG
  190. RtAssert(pPool->leFreeBufferHead.Flink is pleNode->Flink);
  191. #endif
  192. RtReleaseSpinLock(&(pPool->rlLock),
  193. irql);
  194. if(pleNode)
  195. {
  196. #if LIST_DBG
  197. RtAssert(NotOnList(pHead));
  198. RtAssert(!(pHead->bBusy));
  199. pHead->bBusy = TRUE;
  200. InitializeListHead(&(pHead->leFreeBufferLink));
  201. #endif
  202. pbyBuffer = BUFFER_FROM_HEAD(pHead);
  203. }
  204. else
  205. {
  206. //
  207. // The free list was empty. Try to expand the pool.
  208. //
  209. AddBufferBlockToPool(pPool,
  210. &pbyBuffer);
  211. #if LIST_DBG
  212. pHead = HEAD_FROM_BUFFER(pbyBuffer);
  213. pHead->ulAllocFile = ulFileSig;
  214. pHead->ulAllocLine = ulLine;
  215. pHead->bBusy = TRUE;
  216. #endif
  217. }
  218. return pbyBuffer;
  219. }
  220. #if LIST_DBG
  221. NTSTATUS
  222. GETCHAIN(
  223. IN PBUFFER_POOL pPool,
  224. IN OUT PNDIS_PACKET pnpPacket,
  225. IN ULONG ulBufferLength,
  226. OUT NDIS_BUFFER **ppnbFirstBuffer,
  227. OUT VOID **ppvFirstData,
  228. IN ULONG ulFileSig,
  229. IN ULONG ulLine
  230. )
  231. #else
  232. NTSTATUS
  233. GetBufferChainFromPool(
  234. IN PBUFFER_POOL pPool,
  235. IN OUT PNDIS_PACKET pnpPacket,
  236. IN ULONG ulBufferLength,
  237. OUT NDIS_BUFFER **ppnbFirstBuffer OPTIONAL,
  238. OUT VOID **ppvFirstData OPTIONAL
  239. )
  240. #endif
  241. /*++
  242. Routine Description
  243. Gets a chain of buffers and hooks them onto an NDIS_PACKET
  244. This requires that the BUFFER_POOL have been created with the
  245. fAssociateNdisBuffer option
  246. Locks
  247. Acquires the Pool lock.
  248. Also calls GetPacketFromPool() which acquires the packet pool lock
  249. Arguments
  250. Return Value
  251. NO_ERROR
  252. --*/
  253. {
  254. ULONG i, ulBufNeeded, ulLastSize;
  255. KIRQL irql;
  256. PLIST_ENTRY pleNode;
  257. PBUFFER_HEAD pHead;
  258. NTSTATUS nStatus;
  259. RtAcquireSpinLock(&(pPool->rlLock),
  260. &irql);
  261. RtAssert(pPool->fAssociateNdisBuffer is TRUE);
  262. //
  263. // Figure out the number of buffers needed
  264. //
  265. ulBufNeeded = ulBufferLength / pPool->ulBufferSize;
  266. ulLastSize = ulBufferLength % pPool->ulBufferSize;
  267. if(ulLastSize isnot 0)
  268. {
  269. //
  270. // The buffer length is not an exact multiple of the buffer size
  271. // so we need one more buffer with length == ulLastSize
  272. //
  273. ulBufNeeded++;
  274. }
  275. else
  276. {
  277. //
  278. // Set it to the full size, needed to make some code work
  279. // without extra if()
  280. //
  281. ulLastSize = pPool->ulBufferSize;
  282. }
  283. RtAssert(ulBufNeeded);
  284. i = 0;
  285. nStatus = STATUS_SUCCESS;
  286. while(i < ulBufNeeded)
  287. {
  288. //
  289. // The buffer pool must be locked at this point
  290. //
  291. while(!IsListEmpty(&pPool->leFreeBufferHead))
  292. {
  293. pleNode = RemoveHeadList(&pPool->leFreeBufferHead);
  294. pHead = CONTAINING_RECORD(pleNode,
  295. BUFFER_HEAD,
  296. leFreeBufferLink);
  297. (pHead->pBlock->ulFreeBuffers)--;
  298. #if LIST_DBG
  299. RtAssert(pPool->leFreeBufferHead.Flink is pleNode->Flink);
  300. RtAssert(!IsEntryOnList(&pPool->leFreeBufferHead,
  301. pleNode));
  302. RtAssert(NotOnList(pHead));
  303. RtAssert(!(pHead->bBusy));
  304. pHead->bBusy = TRUE;
  305. InitializeListHead(&(pHead->leFreeBufferLink));
  306. pHead->ulAllocFile = ulFileSig;
  307. pHead->ulAllocLine = ulLine;
  308. #endif
  309. if(i is 0)
  310. {
  311. //
  312. // This is the first buffer
  313. //
  314. if(ppnbFirstBuffer)
  315. {
  316. *ppnbFirstBuffer = pHead->pNdisBuffer;
  317. }
  318. if(ppnbFirstBuffer)
  319. {
  320. *ppvFirstData = BUFFER_FROM_HEAD(pHead);
  321. }
  322. }
  323. i++;
  324. if(i is ulBufNeeded)
  325. {
  326. //
  327. // This is the last buffer. Set the length to the last length
  328. //
  329. NdisAdjustBufferLength(pHead->pNdisBuffer,
  330. ulLastSize);
  331. //
  332. // Add the buffer to the NDIS_PACKET
  333. //
  334. NdisChainBufferAtBack(pnpPacket,
  335. pHead->pNdisBuffer);
  336. //
  337. // Done chaining packets - break out of the
  338. // while(!IsListEmpty()) loop
  339. //
  340. break;
  341. }
  342. else
  343. {
  344. //
  345. // Adjust the length to the full length, since the buffer
  346. // may have earlier been used as smaller sized
  347. //
  348. NdisAdjustBufferLength(pHead->pNdisBuffer,
  349. pPool->ulBufferSize);
  350. //
  351. // Add the buffer to the NDIS_PACKET
  352. //
  353. NdisChainBufferAtBack(pnpPacket,
  354. pHead->pNdisBuffer);
  355. }
  356. }
  357. RtReleaseSpinLock(&(pPool->rlLock),
  358. irql);
  359. if(i isnot ulBufNeeded)
  360. {
  361. //
  362. // We did not get all the buffers we needed
  363. // Grow the buffer pool and try again
  364. //
  365. if(AddBufferBlockToPool(pPool, NULL))
  366. {
  367. //
  368. // Ok atleast one buffer was added, go to the
  369. // while(i < ulBufNeeded)
  370. //
  371. RtAcquireSpinLock(&(pPool->rlLock),
  372. &irql);
  373. continue;
  374. }
  375. else
  376. {
  377. //
  378. // Looks like there is not enough memory. Free what ever we
  379. // have chained up and get out
  380. //
  381. FreeBufferChainToPool(pPool,
  382. pnpPacket);
  383. nStatus = STATUS_INSUFFICIENT_RESOURCES;
  384. break;
  385. }
  386. }
  387. }
  388. return nStatus;
  389. }
  390. #if LIST_DBG
  391. BOOLEAN
  392. GETLIST(
  393. IN PBUFFER_POOL pPool,
  394. IN ULONG ulNumBuffersNeeded,
  395. OUT PLIST_ENTRY pleList,
  396. IN ULONG ulFileSig,
  397. IN ULONG ulLine
  398. )
  399. #else
  400. BOOLEAN
  401. GetBufferListFromPool(
  402. IN PBUFFER_POOL pPool,
  403. IN ULONG ulNumBuffersNeeded,
  404. OUT PLIST_ENTRY pleList
  405. )
  406. #endif
  407. /*++
  408. Routine Description
  409. Gets a chain of buffers and hooks them onto a BUFFER_HEAD using the
  410. leFreeBufferLink
  411. Locks
  412. Acquires the Pool lock.
  413. Arguments
  414. Return Value
  415. TRUE if successful
  416. --*/
  417. {
  418. ULONG i;
  419. KIRQL irql;
  420. BOOLEAN bRet;
  421. RtAcquireSpinLock(&(pPool->rlLock),
  422. &irql);
  423. RtAssert(pPool->fAssociateNdisBuffer is TRUE);
  424. RtAssert(ulNumBuffersNeeded);
  425. i = 0;
  426. bRet = TRUE;
  427. InitializeListHead(pleList);
  428. while(i < ulNumBuffersNeeded)
  429. {
  430. //
  431. // The buffer pool must be locked at this point
  432. //
  433. while(!IsListEmpty(&pPool->leFreeBufferHead))
  434. {
  435. PBUFFER_HEAD pHead;
  436. PLIST_ENTRY pleNode;
  437. pleNode = RemoveHeadList(&pPool->leFreeBufferHead);
  438. pHead = CONTAINING_RECORD(pleNode,
  439. BUFFER_HEAD,
  440. leFreeBufferLink);
  441. (pHead->pBlock->ulFreeBuffers)--;
  442. #if LIST_DBG
  443. RtAssert(pPool->leFreeBufferHead.Flink is pleNode->Flink);
  444. RtAssert(!IsEntryOnList(&pPool->leFreeBufferHead,
  445. pleNode));
  446. RtAssert(NotOnList(pHead));
  447. RtAssert(!(pHead->bBusy));
  448. pHead->bBusy = TRUE;
  449. InitializeListHead(&(pHead->leFreeBufferLink));
  450. pHead->ulAllocFile = ulFileSig;
  451. pHead->ulAllocLine = ulLine;
  452. #endif
  453. //
  454. // Insert the buffer to the tail of the list
  455. //
  456. #if LIST_DBG
  457. InsertTailList(pleList,
  458. &(pHead->leListLink));
  459. #else
  460. InsertTailList(pleList,
  461. &(pHead->leFreeBufferLink));
  462. #endif
  463. i++;
  464. //
  465. // Adjust the length to the full length, since the buffer
  466. // may have earlier been used as smaller sized
  467. //
  468. NdisAdjustBufferLength(pHead->pNdisBuffer,
  469. pPool->ulBufferSize);
  470. if(i is ulNumBuffersNeeded)
  471. {
  472. //
  473. // Got all the buffer we need
  474. //
  475. break;
  476. }
  477. }
  478. //
  479. // At this point we either have all the buffers we need or are out
  480. // of buffers. Release the lock and see which case
  481. //
  482. RtReleaseSpinLock(&(pPool->rlLock),
  483. irql);
  484. if(i isnot ulNumBuffersNeeded)
  485. {
  486. //
  487. // We did not get all the buffers we needed
  488. // Grow the buffer pool and try again
  489. //
  490. if(AddBufferBlockToPool(pPool, NULL))
  491. {
  492. //
  493. // Ok atleast one buffer was added, go to the
  494. // while(i < ulNumBuffersNeeded)
  495. //
  496. RtAcquireSpinLock(&(pPool->rlLock),
  497. &irql);
  498. continue;
  499. }
  500. else
  501. {
  502. //
  503. // Looks like there is not enough memory. Free what ever we
  504. // have chained up and get out
  505. //
  506. if(!IsListEmpty(pleList))
  507. {
  508. FreeBufferListToPool(pPool,
  509. pleList);
  510. }
  511. bRet = FALSE;
  512. break;
  513. }
  514. }
  515. }
  516. return bRet;
  517. }
  518. #if LIST_DBG
  519. VOID
  520. FREE(
  521. IN PBUFFER_POOL pPool,
  522. IN PBYTE pbyBuffer,
  523. IN BOOLEAN fGarbageCollection,
  524. IN ULONG ulFileSig,
  525. IN ULONG ulLine
  526. )
  527. #else
  528. VOID
  529. FreeBufferToPoolEx(
  530. IN PBUFFER_POOL pPool,
  531. IN PBYTE pbyBuffer,
  532. IN BOOLEAN fGarbageCollection
  533. )
  534. #endif
  535. /*++
  536. Routine Description
  537. Returns a buffer to the pool of unused buffers. The buffer must have
  538. been previously allocated with GetBufferFromPool.
  539. Locks
  540. Arguments
  541. pBuffer Buffer to free
  542. pPool Pool to free to
  543. fGarbageCollection is set when the free should be considered for
  544. purposes of garbage collection. This is used by the AddBufferToPool
  545. routine to avoid counting the initial "add" frees. Normal callers
  546. should set this flag.
  547. Return Value
  548. NO_ERROR
  549. --*/
  550. {
  551. PBUFFER_HEAD pHead;
  552. KIRQL irql;
  553. PLIST_ENTRY pNext;
  554. //
  555. // The buffer head would be just above the actual data buffer
  556. //
  557. pHead = HEAD_FROM_BUFFER(pbyBuffer);
  558. RtAcquireSpinLock(&(pPool->rlLock),
  559. &irql);
  560. #if LIST_DBG
  561. RtAssert(!IsEntryOnList(&pPool->leFreeBufferHead,
  562. &pHead->leFreeBufferLink));
  563. RtAssert(NotOnList(pHead));
  564. RtAssert(IsListEmpty(&(pHead->leFreeBufferLink)));
  565. RtAssert(pHead->bBusy);
  566. pHead->bBusy = FALSE;
  567. pHead->ulFreeFile = ulFileSig;
  568. pHead->ulFreeLine = ulLine;
  569. pNext = pPool->leFreeBufferHead.Flink;
  570. #endif
  571. InsertHeadList(&(pPool->leFreeBufferHead),
  572. &(pHead->leFreeBufferLink));
  573. #if LIST_DBG
  574. RtAssert(pHead->leFreeBufferLink.Flink is pNext);
  575. #endif
  576. pHead->pBlock->ulFreeBuffers++;
  577. if(fGarbageCollection)
  578. {
  579. pPool->ulFreesSinceCollection++;
  580. if(pPool->ulFreesSinceCollection >= pPool->ulFreesPerCollection)
  581. {
  582. //
  583. // Time to collect garbage, i.e. free any blocks in the pool
  584. // not in use.
  585. //
  586. FreeUnusedPoolBlocks(pPool);
  587. pPool->ulFreesSinceCollection = 0;
  588. }
  589. }
  590. RtReleaseSpinLock(&(pPool->rlLock),
  591. irql);
  592. }
  593. #if LIST_DBG
  594. VOID
  595. FREECHAIN(
  596. IN PBUFFER_POOL pPool,
  597. IN PNDIS_PACKET pnpPacket,
  598. IN ULONG ulFileSig,
  599. IN ULONG ulLine
  600. )
  601. #else
  602. VOID
  603. FreeBufferChainToPool(
  604. IN PBUFFER_POOL pPool,
  605. IN PNDIS_PACKET pnpPacket
  606. )
  607. #endif
  608. /*++
  609. Routine Description
  610. Frees a chain of buffers off an NDIS_PACKET to a buffer pool
  611. Locks
  612. Acquires the buffer spin lock
  613. Arguments
  614. pPool The buffer pool
  615. pnpPacket NDIS_PACKET off of which the buffers are chained
  616. Return Value
  617. NO_ERROR
  618. --*/
  619. {
  620. PBUFFER_HEAD pHead;
  621. PNDIS_BUFFER pnbBuffer;
  622. KIRQL irql;
  623. UINT uiBuffLength;
  624. PVOID pvData;
  625. RtAcquireSpinLock(&(pPool->rlLock),
  626. &irql);
  627. //
  628. // Loop through the chained buffers, free each
  629. //
  630. while(TRUE)
  631. {
  632. PLIST_ENTRY pNext;
  633. NdisUnchainBufferAtFront(pnpPacket,
  634. &pnbBuffer);
  635. if(pnbBuffer is NULL)
  636. {
  637. //
  638. // No more buffers
  639. //
  640. break;
  641. }
  642. NdisQueryBuffer(pnbBuffer,
  643. &pvData,
  644. &uiBuffLength);
  645. pHead = HEAD_FROM_BUFFER(pvData);
  646. #if LIST_DBG
  647. RtAssert(!IsEntryOnList(&pPool->leFreeBufferHead,
  648. &pHead->leFreeBufferLink));
  649. RtAssert(NotOnList(pHead));
  650. RtAssert(IsListEmpty(&(pHead->leFreeBufferLink)));
  651. RtAssert(pHead->bBusy);
  652. pHead->bBusy = FALSE;
  653. pHead->ulFreeFile = ulFileSig;
  654. pHead->ulFreeLine = ulLine;
  655. pNext = pPool->leFreeBufferHead.Flink;
  656. #endif
  657. InsertHeadList(&(pPool->leFreeBufferHead),
  658. &(pHead->leFreeBufferLink));
  659. #if LIST_DBG
  660. RtAssert(pHead->leFreeBufferLink.Flink is pNext);
  661. #endif
  662. pHead->pBlock->ulFreeBuffers++;
  663. pPool->ulFreesSinceCollection++;
  664. }
  665. if(pPool->ulFreesSinceCollection >= pPool->ulFreesPerCollection)
  666. {
  667. //
  668. // Time to collect garbage, i.e. free any blocks in the pool
  669. // not in use.
  670. //
  671. FreeUnusedPoolBlocks(pPool);
  672. pPool->ulFreesSinceCollection = 0;
  673. }
  674. RtReleaseSpinLock(&(pPool->rlLock),
  675. irql);
  676. }
  677. #if LIST_DBG
  678. VOID
  679. FREELIST(
  680. IN PBUFFER_POOL pPool,
  681. IN PLIST_ENTRY pleList,
  682. IN ULONG ulFileSig,
  683. IN ULONG ulLine
  684. )
  685. #else
  686. VOID
  687. FreeBufferListToPool(
  688. IN PBUFFER_POOL pPool,
  689. IN PLIST_ENTRY pleList
  690. )
  691. #endif
  692. /*++
  693. Routine Description
  694. Frees a list of buffers, linked using the leFreeBufferLink
  695. Locks
  696. Locks the bufferpool
  697. Arguments
  698. Return Value
  699. None
  700. --*/
  701. {
  702. KIRQL irql;
  703. if(IsListEmpty(pleList))
  704. {
  705. RtAssert(FALSE);
  706. return;
  707. }
  708. RtAcquireSpinLock(&(pPool->rlLock),
  709. &irql);
  710. //
  711. // Loop through the list of buffers, free each
  712. //
  713. while(!IsListEmpty(pleList))
  714. {
  715. PLIST_ENTRY pleNode, pNext;
  716. PBUFFER_HEAD pTempBuffHead;
  717. pleNode = RemoveHeadList(pleList);
  718. #if LIST_DBG
  719. pTempBuffHead = CONTAINING_RECORD(pleNode,
  720. BUFFER_HEAD,
  721. leListLink);
  722. RtAssert(IsListEmpty(&(pTempBuffHead->leFreeBufferLink)));
  723. RtAssert(!IsEntryOnList(&pPool->leFreeBufferHead,
  724. &pTempBuffHead->leFreeBufferLink));
  725. pTempBuffHead->leListLink.Flink = NULL;
  726. pTempBuffHead->leListLink.Blink = NULL;
  727. RtAssert(pTempBuffHead->bBusy);
  728. pTempBuffHead->bBusy = FALSE;
  729. pTempBuffHead->ulFreeFile = ulFileSig;
  730. pTempBuffHead->ulFreeLine = ulLine;
  731. pNext = pPool->leFreeBufferHead.Flink;
  732. #else
  733. pTempBuffHead = CONTAINING_RECORD(pleNode,
  734. BUFFER_HEAD,
  735. leFreeBufferLink);
  736. #endif
  737. InsertHeadList(&(pPool->leFreeBufferHead),
  738. &(pTempBuffHead->leFreeBufferLink));
  739. #if LIST_DBG
  740. RtAssert(pTempBuffHead->leFreeBufferLink.Flink is pNext);
  741. #endif
  742. pTempBuffHead->pBlock->ulFreeBuffers++;
  743. pPool->ulFreesSinceCollection++;
  744. }
  745. if(pPool->ulFreesSinceCollection >= pPool->ulFreesPerCollection)
  746. {
  747. //
  748. // Time to collect garbage, i.e. free any blocks in the pool
  749. // not in use.
  750. //
  751. FreeUnusedPoolBlocks(pPool);
  752. pPool->ulFreesSinceCollection = 0;
  753. }
  754. RtReleaseSpinLock(&(pPool->rlLock),
  755. irql);
  756. }
  757. //
  758. // should make the following #define's
  759. //
  760. PNDIS_BUFFER
  761. GetNdisBufferFromBuffer(
  762. IN PBYTE pbyBuffer
  763. )
  764. /*++
  765. Routine Description
  766. Returns the NDIS_BUFFER associated with the buffer which was
  767. obtained previously with GetBufferFromPool.
  768. Locks
  769. Arguments
  770. Return Value
  771. Pointer to NDIS_BUFFER associated with the buffer
  772. --*/
  773. {
  774. PBUFFER_HEAD pHead;
  775. pHead = HEAD_FROM_BUFFER(pbyBuffer);
  776. return pHead->pNdisBuffer;
  777. }
  778. ULONG
  779. BufferSizeFromBuffer(
  780. IN PBYTE pbyBuffer
  781. )
  782. /*++
  783. Routine Description
  784. Returns the original size of the buffer 'pBuffer' which was obtained
  785. previously with GetBufferFromPool. This is useful for undoing
  786. NdisAdjustBufferLength
  787. Locks
  788. Arguments
  789. Return Value
  790. Original size of buffer
  791. --*/
  792. {
  793. PBUFFER_HEAD pHead;
  794. pHead = HEAD_FROM_BUFFER(pbyBuffer);
  795. return pHead->pBlock->pPool->ulBufferSize;
  796. }
  797. PNDIS_BUFFER
  798. PoolHandleFromBuffer(
  799. IN PBYTE pbyBuffer
  800. )
  801. /*++
  802. Routine Description
  803. Returns the handle of the NDIS buffer pool from which the NDIS_BUFFER
  804. associated with this buffer was obtained. Caller may use the handle to
  805. pass to NdisCopyBuffer, one such use per buffer at a time.
  806. Locks
  807. Arguments
  808. Return Value
  809. NO_ERROR
  810. --*/
  811. {
  812. PBUFFER_HEAD pHead;
  813. pHead = HEAD_FROM_BUFFER(pbyBuffer);
  814. return pHead->pBlock->nhNdisPool;
  815. }
  816. //-----------------------------------------------------------------------------
  817. // Local utility routines (alphabetically)
  818. //-----------------------------------------------------------------------------
  819. BOOLEAN
  820. AddBufferBlockToPool(
  821. IN PBUFFER_POOL pPool,
  822. OUT BYTE **ppbyRetBuff OPTIONAL
  823. )
  824. /*++
  825. Routine Description
  826. Allocate a new buffer block and add it to the buffer pool 'pPool'.
  827. Locks
  828. Arguments
  829. Return Value
  830. TRUE If we could add a buffer block
  831. FALSE otherwise
  832. --*/
  833. {
  834. ULONG ulSize, i;
  835. BOOLEAN fOk, fAssociateNdisBuffer;
  836. PBYTE pbyReturn, pbyBuffer;
  837. KIRQL irql;
  838. PBUFFER_HEAD pHead;
  839. NDIS_STATUS nsStatus;
  840. PBUFFER_BLOCK pNew;
  841. fOk = FALSE;
  842. pNew = NULL;
  843. RtAcquireSpinLock(&(pPool->rlLock),
  844. &irql);
  845. //
  846. // Save this for reference after the lock is released.
  847. //
  848. fAssociateNdisBuffer = pPool->fAssociateNdisBuffer;
  849. do
  850. {
  851. //
  852. // If it is already over the max, dont allocate any more
  853. // Note that we dont STRICTLY respect the max, we will allow, one
  854. // block over max
  855. //
  856. if(pPool->ulMaxBuffers and (pPool->ulCurBuffers >= pPool->ulMaxBuffers))
  857. {
  858. Trace(MEMORY, WARN,
  859. ("AddBufferBlockToPool: Quota exceeded\n"));
  860. //
  861. // No can do. The pool was created with a maximum size and that
  862. // has been reached.
  863. //
  864. break;
  865. }
  866. ulSize = PAGE_SIZE;
  867. //
  868. // Allocate the contiguous memory block for the BUFFERBLOCK header
  869. // and the individual buffers.
  870. //
  871. pNew = RtAllocate(NonPagedPool,
  872. ulSize,
  873. pPool->ulTag);
  874. if(!pNew)
  875. {
  876. Trace(MEMORY, ERROR,
  877. ("AddBufferBlockToPool: Cant allocate %d bytes\n",
  878. ulSize));
  879. break;
  880. }
  881. //
  882. // Zero only the block header portion.
  883. //
  884. NdisZeroMemory(pNew,
  885. ALIGN8_BLOCK_SIZE);
  886. if(fAssociateNdisBuffer)
  887. {
  888. //
  889. // Allocate a pool of NDIS_BUFFER descriptors.
  890. //
  891. // Twice as many descriptors are allocated as buffers so
  892. // caller can use the PoolHandleForNdisCopyBufferFromBuffer
  893. // routine to obtain a pool handle to pass to the
  894. // NdisCopyBuffer used to trim the L2TP header from received
  895. // packets. In the current NDIS implmentation on NT this does
  896. // nothing but return a NULL handle and STATUS_SUCCESS,
  897. // because NDIS_BUFFER's are just MDL's,
  898. // NdisAllocatePool is basically a no-op, and for that
  899. // matter, NdisCopyBuffer doesn't really use the pool handle
  900. // it's passed. It's cheap to stay strictly compliant here,
  901. // though, so we do that.
  902. //
  903. NdisAllocateBufferPool(&nsStatus,
  904. &pNew->nhNdisPool,
  905. pPool->ulBuffersPerBlock * 2);
  906. if(nsStatus isnot NDIS_STATUS_SUCCESS)
  907. {
  908. Trace(MEMORY, ERROR,
  909. ("AddBufferBlockToPool: Status %x allocating buffer pool\n",
  910. nsStatus));
  911. break;
  912. }
  913. }
  914. //
  915. // Fill in the back pointer to the pool.
  916. //
  917. pNew->pPool = pPool;
  918. //
  919. // Link the new block. At this point, all the buffers are
  920. // effectively "in use". They are made available in the loop
  921. // below.
  922. //
  923. pPool->ulCurBuffers += pPool->ulBuffersPerBlock;
  924. InsertHeadList(&pPool->leBlockHead, &pNew->leBlockLink);
  925. fOk = TRUE;
  926. }while(FALSE);
  927. RtReleaseSpinLock(&(pPool->rlLock),
  928. irql);
  929. if(!fOk)
  930. {
  931. //
  932. // Bailing, undo whatever succeeded.
  933. //
  934. if(pNew)
  935. {
  936. RtFree(pNew);
  937. if(pNew->nhNdisPool)
  938. {
  939. NdisFreeBufferPool(pNew->nhNdisPool);
  940. }
  941. }
  942. return FALSE;
  943. }
  944. //
  945. // Initialize each individual buffer slice and add it to the list of free
  946. // buffers.
  947. //
  948. if(ppbyRetBuff isnot NULL)
  949. {
  950. //
  951. // User has passed a pointer to pointer and wants us to return
  952. // a buffer back
  953. //
  954. pbyReturn = NULL;
  955. }
  956. else
  957. {
  958. //
  959. // User wants us to grow the pool but not return a buffer.
  960. // Set the pbyReturn to a non null value, this way all buffers
  961. // will be freed to pool
  962. //
  963. pbyReturn = (PBYTE)1;
  964. }
  965. //
  966. // For each slice of the block, where a slice consists of a BUFFER_HEAD
  967. // and the buffer memory that immediately follows it...
  968. //
  969. #define NEXT_HEAD(h) \
  970. (PBUFFER_HEAD)((ULONG_PTR)(h) + ALIGN8_HEAD_SIZE + ALIGN_UP(pPool->ulBufferSize, ULONGLONG))
  971. for(i = 0, pHead = (PBUFFER_HEAD)((ULONG_PTR)pNew + ALIGN8_BLOCK_SIZE);
  972. i < pPool->ulBuffersPerBlock;
  973. i++, pHead = NEXT_HEAD(pHead))
  974. {
  975. pbyBuffer = BUFFER_FROM_HEAD(pHead);
  976. InitializeListHead(&pHead->leFreeBufferLink);
  977. #if LIST_DBG
  978. pHead->leListLink.Flink = NULL;
  979. pHead->leListLink.Blink = NULL;
  980. //
  981. // Set to TRUE here because the FreeBuffer below expects it to
  982. // be true
  983. //
  984. pHead->bBusy = TRUE;
  985. #endif
  986. pHead->pBlock = pNew;
  987. pHead->pNdisBuffer = NULL;
  988. if(fAssociateNdisBuffer)
  989. {
  990. //
  991. // Associate an NDIS_BUFFER descriptor from the pool we
  992. // allocated above.
  993. //
  994. NdisAllocateBuffer(&nsStatus,
  995. &pHead->pNdisBuffer,
  996. pNew->nhNdisPool,
  997. pbyBuffer,
  998. pPool->ulBufferSize);
  999. if(nsStatus isnot NDIS_STATUS_SUCCESS)
  1000. {
  1001. Trace(MEMORY, ERROR,
  1002. ("AddBufferBlockToPool: Status %x allocating buffer\n",
  1003. nsStatus));
  1004. continue;
  1005. }
  1006. }
  1007. if(pbyReturn)
  1008. {
  1009. //
  1010. // Add the constructed buffer to the list of free buffers.
  1011. // The 'FALSE' tells the garbage collection algorithm the
  1012. // operation is an "add" rather than a "release" and should be
  1013. // ignored.
  1014. //
  1015. FreeBufferToPoolEx(pPool,
  1016. pbyBuffer,
  1017. FALSE);
  1018. }
  1019. else
  1020. {
  1021. //
  1022. // The first successfully constructed buffer is returned by
  1023. // this routine.
  1024. //
  1025. pbyReturn = pbyBuffer;
  1026. }
  1027. }
  1028. if(ppbyRetBuff isnot NULL)
  1029. {
  1030. RtAssert(pbyReturn);
  1031. *ppbyRetBuff = pbyReturn;
  1032. }
  1033. return TRUE;
  1034. }
  1035. VOID
  1036. FreeUnusedPoolBlocks(
  1037. IN PBUFFER_POOL pPool
  1038. )
  1039. /*++
  1040. Routine Description
  1041. Check if any of the blocks in pool 'pPool' are not in use, and if so,
  1042. free them.
  1043. Locks
  1044. IMPORTANT: Caller must hold the pool lock.
  1045. The MSDN doc says that no locks may be held while calling
  1046. NdisFreePacketXxx, but according to JameelH that is incorrect.
  1047. Arguments
  1048. Return Value
  1049. None
  1050. --*/
  1051. {
  1052. PLIST_ENTRY pleNode, pleNextNode;
  1053. PBUFFER_BLOCK pBlock;
  1054. ULONG i;
  1055. PBUFFER_HEAD pHead;
  1056. //
  1057. // For each block in the pool...
  1058. //
  1059. pleNode = pPool->leBlockHead.Flink;
  1060. while(pleNode isnot &pPool->leBlockHead)
  1061. {
  1062. pleNextNode = pleNode->Flink;
  1063. pBlock = CONTAINING_RECORD(pleNode, BUFFER_BLOCK, leBlockLink);
  1064. if(pBlock->ulFreeBuffers == pPool->ulBuffersPerBlock)
  1065. {
  1066. //
  1067. // Found a block with no buffers in use. Walk the buffer block
  1068. // removing each buffer from the pool's free list and freeing any
  1069. // associated NDIS_BUFFER descriptor.
  1070. //
  1071. pHead = (PBUFFER_HEAD)((ULONG_PTR)pBlock + ALIGN8_BLOCK_SIZE);
  1072. for(i = 0;
  1073. i < pPool->ulBuffersPerBlock;
  1074. i++, pHead = NEXT_HEAD(pHead))
  1075. {
  1076. #if LIST_DBG
  1077. RtAssert(IsEntryOnList(&(pPool->leFreeBufferHead),
  1078. &(pHead->leFreeBufferLink)));
  1079. RtAssert(NotOnList(pHead));
  1080. RtAssert(!(pHead->bBusy));
  1081. #endif
  1082. RemoveEntryList(&pHead->leFreeBufferLink);
  1083. if(pHead->pNdisBuffer)
  1084. {
  1085. NdisFreeBuffer(pHead->pNdisBuffer);
  1086. }
  1087. }
  1088. //
  1089. // Remove and release the unused block.
  1090. //
  1091. RemoveEntryList(pleNode);
  1092. pPool->ulCurBuffers -= pPool->ulBuffersPerBlock;
  1093. if(pBlock->nhNdisPool)
  1094. {
  1095. NdisFreeBufferPool(pBlock->nhNdisPool);
  1096. }
  1097. RtFree(pBlock);
  1098. }
  1099. else
  1100. {
  1101. RtAssert(pBlock->ulFreeBuffers < pPool->ulBuffersPerBlock);
  1102. }
  1103. pleNode = pleNextNode;
  1104. }
  1105. }