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.

1270 lines
31 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. psquota.c
  5. Abstract:
  6. This module implements the quota mechanism for NT
  7. Author:
  8. Mark Lucovsky (markl) 18-Sep-1989
  9. Revision History:
  10. Neill Clift (NeillC) 4-Nov-2000
  11. Changed to be mostly lock free. Preserved the basic design in terms of how quota is managed.
  12. --*/
  13. #include "psp.h"
  14. LIST_ENTRY PspQuotaBlockList; // List of all quota blocks except the default
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text (INIT, PsInitializeQuotaSystem)
  17. #pragma alloc_text (PAGE, PspInheritQuota)
  18. #pragma alloc_text (PAGE, PspDereferenceQuota)
  19. #pragma alloc_text (PAGE, PsChargeSharedPoolQuota)
  20. #pragma alloc_text (PAGE, PsReturnSharedPoolQuota)
  21. #endif
  22. VOID
  23. PsInitializeQuotaSystem (
  24. VOID
  25. )
  26. /*++
  27. Routine Description:
  28. This function initializes the quota system.
  29. Arguments:
  30. None.
  31. Return Value:
  32. None.
  33. --*/
  34. {
  35. KeInitializeSpinLock(&PspQuotaLock);
  36. PspDefaultQuotaBlock.ReferenceCount = 1;
  37. PspDefaultQuotaBlock.ProcessCount = 1;
  38. PspDefaultQuotaBlock.QuotaEntry[PsPagedPool].Limit = (SIZE_T)-1;
  39. PspDefaultQuotaBlock.QuotaEntry[PsNonPagedPool].Limit = (SIZE_T)-1;
  40. PspDefaultQuotaBlock.QuotaEntry[PsPageFile].Limit = (SIZE_T)-1;
  41. PsGetCurrentProcess()->QuotaBlock = &PspDefaultQuotaBlock;
  42. InitializeListHead (&PspQuotaBlockList);
  43. }
  44. VOID
  45. PspInsertQuotaBlock (
  46. IN PEPROCESS_QUOTA_BLOCK QuotaBlock
  47. )
  48. /*++
  49. Routine Description:
  50. This routines as a new quota block to the global list of system quota blocks.
  51. Arguments:
  52. QuotaBlock - Quota block to be inserted into the list.
  53. Return Value:
  54. None.
  55. --*/
  56. {
  57. KIRQL OldIrql;
  58. ExAcquireSpinLock (&PspQuotaLock, &OldIrql);
  59. InsertTailList (&PspQuotaBlockList, &QuotaBlock->QuotaList);
  60. ExReleaseSpinLock (&PspQuotaLock, OldIrql);
  61. }
  62. VOID
  63. PspDereferenceQuotaBlock (
  64. IN PEPROCESS_QUOTA_BLOCK QuotaBlock
  65. )
  66. /*++
  67. Routine Description:
  68. This removes a single reference from a quota block and deletes the block if it was the last.
  69. Arguments:
  70. QuotaBlock - Quota block to dereference
  71. Return Value:
  72. None.
  73. --*/
  74. {
  75. KIRQL OldIrql;
  76. SIZE_T ReturnQuota;
  77. PS_QUOTA_TYPE QuotaType;
  78. if (InterlockedDecrement ((PLONG) &QuotaBlock->ReferenceCount) == 0) {
  79. ExAcquireSpinLock (&PspQuotaLock, &OldIrql);
  80. RemoveEntryList (&QuotaBlock->QuotaList);
  81. //
  82. // Free any unreturned quota;
  83. //
  84. for (QuotaType = PsNonPagedPool;
  85. QuotaType <= PsPagedPool;
  86. QuotaType++) {
  87. ReturnQuota = QuotaBlock->QuotaEntry[QuotaType].Return + QuotaBlock->QuotaEntry[QuotaType].Limit;
  88. if (ReturnQuota > 0) {
  89. MmReturnPoolQuota (QuotaType, ReturnQuota);
  90. }
  91. }
  92. ExReleaseSpinLock (&PspQuotaLock, OldIrql);
  93. ExFreePool (QuotaBlock);
  94. }
  95. }
  96. SIZE_T
  97. FORCEINLINE
  98. PspInterlockedExchangeQuota (
  99. IN PSIZE_T pQuota,
  100. IN SIZE_T NewQuota)
  101. /*++
  102. Routine Description:
  103. This function does an interlocked exchange on a quota variable.
  104. Arguments:
  105. pQuota - Pointer to a quota entry to exchange into
  106. NewQuota - The new value to exchange into the quota location.
  107. Return Value:
  108. SIZE_T - Old value that was contained in the quota variable
  109. --*/
  110. {
  111. #if !defined(_WIN64)
  112. return InterlockedExchange ((PLONG) pQuota, NewQuota);
  113. #else
  114. return InterlockedExchange64 ((PLONGLONG) pQuota, NewQuota);
  115. #endif
  116. }
  117. SIZE_T
  118. FORCEINLINE
  119. PspInterlockedCompareExchangeQuota (
  120. IN PSIZE_T pQuota,
  121. IN SIZE_T NewQuota,
  122. IN SIZE_T OldQuota
  123. )
  124. /*++
  125. Routine Description:
  126. This function performs a compare exchange operation on a quota variable
  127. Arguments:
  128. pQuota - Pointer to the quota variable being changed
  129. NewQuota - New value to place in the quota variable
  130. OldQuota - The current contents of the quota variable
  131. Return Value:
  132. SIZE_T - The old contents of the variable
  133. --*/
  134. {
  135. #if !defined(_WIN64)
  136. return InterlockedCompareExchange ((PLONG) pQuota, NewQuota, OldQuota);
  137. #else
  138. return InterlockedCompareExchange64 ((PLONGLONG)pQuota, NewQuota, OldQuota);
  139. #endif
  140. }
  141. SIZE_T
  142. PspReleaseReturnedQuota (
  143. IN PS_QUOTA_TYPE QuotaType
  144. )
  145. /*++
  146. Routine Description:
  147. This function walks the list of system quota blocks and returns any non-returned quota.
  148. This function is called when we are about to fail a quota charge and we want to try and
  149. free some resources up.
  150. Arguments:
  151. QuotaType - Type of quota to scan for.
  152. Return Value:
  153. SIZE_T - Amount of that quota returned to the system.
  154. --*/
  155. {
  156. SIZE_T ReturnQuota, Usage, Limit;
  157. PLIST_ENTRY ListEntry;
  158. PEPROCESS_QUOTA_BLOCK QuotaBlock;
  159. ReturnQuota = 0;
  160. ListEntry = PspQuotaBlockList.Flink;
  161. while (1) {
  162. if (ListEntry == &PspQuotaBlockList) {
  163. break;
  164. }
  165. QuotaBlock = CONTAINING_RECORD (ListEntry, EPROCESS_QUOTA_BLOCK, QuotaList);
  166. //
  167. // Gather up any unreturned quota;
  168. //
  169. ReturnQuota += PspInterlockedExchangeQuota (&QuotaBlock->QuotaEntry[QuotaType].Return, 0);
  170. //
  171. // If no more processes are assocociated with this block then trim its limit back. This
  172. // block can only have quota returned at this point.
  173. //
  174. if (QuotaBlock->ProcessCount == 0) {
  175. Usage = QuotaBlock->QuotaEntry[QuotaType].Usage;
  176. Limit = QuotaBlock->QuotaEntry[QuotaType].Limit;
  177. if (Limit > Usage) {
  178. if (PspInterlockedCompareExchangeQuota (&QuotaBlock->QuotaEntry[QuotaType].Limit,
  179. Usage,
  180. Limit) == Limit) {
  181. ReturnQuota += Limit - Usage;
  182. }
  183. }
  184. }
  185. ListEntry = ListEntry->Flink;
  186. }
  187. if (ReturnQuota > 0) {
  188. MmReturnPoolQuota (QuotaType, ReturnQuota);
  189. }
  190. return ReturnQuota;
  191. }
  192. //
  193. // Interfaces return different status values for differen quotas. These are the values.
  194. //
  195. const static NTSTATUS PspQuotaStatus[PsQuotaTypes] = {STATUS_QUOTA_EXCEEDED,
  196. STATUS_QUOTA_EXCEEDED,
  197. STATUS_PAGEFILE_QUOTA_EXCEEDED};
  198. VOID
  199. FORCEINLINE
  200. PspInterlockedMaxQuota (
  201. IN PSIZE_T pQuota,
  202. IN SIZE_T NewQuota
  203. )
  204. /*++
  205. Routine Description:
  206. This function makes sure that the target contains a value that >= to the new quota value.
  207. This is used to maintain peak values.
  208. Arguments:
  209. pQuota - Pointer to a quota variable
  210. NewQuota - New value to be used in the maximum comparison.
  211. Return Value:
  212. None.
  213. --*/
  214. {
  215. SIZE_T Quota;
  216. Quota = *pQuota;
  217. while (1) {
  218. if (NewQuota <= Quota) {
  219. break;
  220. }
  221. //
  222. // This looks strange because we don't care if the exchanged suceeded. We only
  223. // care that the quota is greater than our new quota.
  224. //
  225. Quota = PspInterlockedCompareExchangeQuota (pQuota,
  226. NewQuota,
  227. Quota);
  228. }
  229. }
  230. SIZE_T
  231. FORCEINLINE
  232. PspInterlockedAddQuota (
  233. IN PSIZE_T pQuota,
  234. IN SIZE_T Amount
  235. )
  236. /*++
  237. Routine Description:
  238. This function adds the specified amount on to the target quota
  239. Arguments:
  240. pQuota - Pointer to a quota variable to be modified
  241. Amount - Amount to be added to the quota
  242. Return Value:
  243. SIZE_T - New value of quota variable after the addition was performed
  244. --*/
  245. {
  246. #if !defined(_WIN64)
  247. return InterlockedExchangeAdd ((PLONG) pQuota, Amount) + Amount;
  248. #else
  249. return InterlockedExchangeAdd64 ((PLONGLONG) pQuota, Amount) + Amount;
  250. #endif
  251. }
  252. SIZE_T
  253. FORCEINLINE
  254. PspInterlockedSubtractQuota (
  255. IN PSIZE_T pUsage,
  256. IN SIZE_T Amount
  257. )
  258. /*++
  259. Routine Description:
  260. This function subtracts the specified amount on to the target quota
  261. Arguments:
  262. pQuota - Pointer to a quota variable to be modified
  263. Amount - Amount to be subtracted from the quota
  264. Return Value:
  265. SIZE_T - New value of quota variable after the subtraction was performed
  266. --*/
  267. {
  268. #if !defined(_WIN64)
  269. return InterlockedExchangeAdd ((PLONG) pUsage, -(LONG)Amount) - Amount;
  270. #else
  271. return InterlockedExchangeAdd64 ((PLONGLONG) pUsage, -(LONGLONG)Amount) - Amount;
  272. #endif
  273. }
  274. BOOLEAN
  275. PspExpandQuota (
  276. IN PS_QUOTA_TYPE QuotaType,
  277. IN PEPROCESS_QUOTA_ENTRY QE,
  278. IN SIZE_T Usage,
  279. IN SIZE_T Amount,
  280. OUT SIZE_T *pLimit
  281. )
  282. /*++
  283. Routine Description:
  284. This function charges the specified quota to a process quota block
  285. Arguments:
  286. QuotaType - The quota being charged. One of PsNonPagedPool, PsPagedPool or PsPageFile.
  287. QE - Quota entry being modified
  288. Usage - The current quota usage
  289. Amount - The amount of quota being charged.
  290. pLimit - The new limit
  291. Return Value:
  292. BOOLEAN - TRUE if quota expansion suceeded.
  293. --*/
  294. {
  295. SIZE_T Limit, NewLimit;
  296. KIRQL OldIrql;
  297. //
  298. // We need to attempt quota expansion for this request.
  299. // Acquire the global lock and see if somebody else changed the limit.
  300. // We don't want to do too many expansions. If somebody else did it
  301. // then we want to use theirs if possible.
  302. //
  303. ExAcquireSpinLock (&PspQuotaLock, &OldIrql);
  304. //
  305. // Refetch limit information. Another thread may have done limit expansion/contraction.
  306. // By refetching limit we preserve the order we established above.
  307. //
  308. Limit = QE->Limit;
  309. //
  310. // If the request could be satisfied now then repeat.
  311. //
  312. if (Usage + Amount <= Limit) {
  313. ExReleaseSpinLock (&PspQuotaLock, OldIrql);
  314. *pLimit = Limit;
  315. return TRUE;
  316. }
  317. //
  318. // If expansion is currently enabled then attempt it.
  319. // If this fails then scavenge any returns from all the
  320. // quota blocks in the system and try again.
  321. //
  322. if (((QuotaType == PsNonPagedPool)?PspDefaultNonPagedLimit:PspDefaultPagedLimit) == 0) {
  323. if (MmRaisePoolQuota (QuotaType, Limit, &NewLimit) ||
  324. (PspReleaseReturnedQuota (QuotaType) > 0 &&
  325. MmRaisePoolQuota (QuotaType, Limit, &NewLimit))) {
  326. //
  327. // We refetch limit here but that doesn't violate the ordering
  328. //
  329. Limit = PspInterlockedAddQuota (&QE->Limit, NewLimit - Limit);
  330. ExReleaseSpinLock (&PspQuotaLock, OldIrql);
  331. *pLimit = Limit;
  332. return TRUE;
  333. }
  334. }
  335. ExReleaseSpinLock (&PspQuotaLock, OldIrql);
  336. *pLimit = Limit;
  337. return FALSE;
  338. }
  339. NTSTATUS
  340. FORCEINLINE
  341. PspChargeQuota (
  342. IN PEPROCESS_QUOTA_BLOCK QuotaBlock,
  343. IN PEPROCESS Process,
  344. IN PS_QUOTA_TYPE QuotaType,
  345. IN SIZE_T Amount)
  346. /*++
  347. Routine Description:
  348. This function charges the specified quota to a process quota block
  349. Arguments:
  350. QuotaBlock - Quota block to make charges to.
  351. Process - Process that is being charged.
  352. QuotaType - The quota being charged. One of PsNonPagedPool, PsPagedPool or PsPageFile.
  353. Amount - The amount of quota being charged.
  354. Return Value:
  355. NTSTATUS - Status of the operation
  356. --*/
  357. {
  358. PEPROCESS_QUOTA_ENTRY QE;
  359. SIZE_T Usage, Limit, NewUsage, tUsage, Extra;
  360. QE = &QuotaBlock->QuotaEntry[QuotaType];
  361. //
  362. // This memory barrier is important. In order not to have to recheck the limit after
  363. // we charge the quota we only ever reduce the limit by the same amount we are about
  364. // to reduce the usage by. Using an out of data limit will only allow us to over charge
  365. // by an amount another thread is just about to release.
  366. //
  367. Usage = QE->Usage;
  368. KeMemoryBarrier ();
  369. Limit = QE->Limit;
  370. while (1) {
  371. NewUsage = Usage + Amount;
  372. //
  373. // Wrapping cases are always rejected
  374. //
  375. if (NewUsage < Usage) {
  376. return PspQuotaStatus [QuotaType];
  377. }
  378. //
  379. // If its within the limits then try and grab the quota
  380. //
  381. if (NewUsage <= Limit) {
  382. tUsage = PspInterlockedCompareExchangeQuota (&QE->Usage,
  383. NewUsage,
  384. Usage);
  385. if (tUsage == Usage) {
  386. //
  387. // Update the Peak value
  388. //
  389. PspInterlockedMaxQuota (&QE->Peak, NewUsage);
  390. //
  391. // Update the process counts if needed
  392. //
  393. if (Process != NULL) {
  394. NewUsage = PspInterlockedAddQuota (&Process->QuotaUsage[QuotaType], Amount);
  395. //
  396. // Update the peak value
  397. //
  398. PspInterlockedMaxQuota (&Process->QuotaPeak[QuotaType], NewUsage);
  399. }
  400. return STATUS_SUCCESS;
  401. }
  402. //
  403. // The usage has changed under us. We have a new usage from the exchange
  404. // but must refetch the limit to preserve the ordering we established
  405. // above this loop. We don't need a memory barrier as we obtained
  406. // the new value via an interlocked operation and they contain barriers.
  407. //
  408. Usage = tUsage;
  409. KeMemoryBarrier ();
  410. Limit = QE->Limit;
  411. continue;
  412. }
  413. //
  414. // Page file quota is not increased
  415. //
  416. if (QuotaType == PsPageFile) {
  417. return PspQuotaStatus [QuotaType];
  418. } else {
  419. //
  420. // First try and grab any returns that this process has made.
  421. //
  422. Extra = PspInterlockedExchangeQuota (&QE->Return, 0);
  423. if (Extra > 0) {
  424. //
  425. // We had some returns so add this to the limit. We can retry the
  426. // acquire with the new limit. We refetch the limit here but that
  427. // doesn't violate the state we set up at the top of the loop.
  428. // The state is that we read the Usage before we read the limit.
  429. //
  430. Limit = PspInterlockedAddQuota (&QE->Limit, Extra);
  431. continue;
  432. }
  433. //
  434. // Try to expand quota if we can
  435. //
  436. if (PspExpandQuota (QuotaType, QE, Usage, Amount, &Limit)) {
  437. //
  438. // We refetched limit here but that doesn't violate the ordering
  439. //
  440. continue;
  441. }
  442. return PspQuotaStatus [QuotaType];
  443. }
  444. }
  445. }
  446. VOID
  447. PspGivebackQuota (
  448. IN PS_QUOTA_TYPE QuotaType,
  449. IN PEPROCESS_QUOTA_ENTRY QE
  450. )
  451. /*++
  452. Routine Description:
  453. This function returns excess freed quota to MM
  454. Arguments:
  455. QuotaType - The quota being returned. One of PsNonPagedPool, PsPagedPool or PsPageFile.
  456. QE - Quote entry to return to
  457. Return Value:
  458. None.
  459. --*/
  460. {
  461. SIZE_T GiveBack;
  462. KIRQL OldIrql;
  463. //
  464. // Acquire a global spinlock so we only have one thread giving back to the system
  465. //
  466. ExAcquireSpinLock (&PspQuotaLock, &OldIrql);
  467. GiveBack = PspInterlockedExchangeQuota (&QE->Return, 0);
  468. if (GiveBack > 0) {
  469. MmReturnPoolQuota (QuotaType, GiveBack);
  470. }
  471. ExReleaseSpinLock (&PspQuotaLock, OldIrql);
  472. }
  473. VOID
  474. FORCEINLINE
  475. PspReturnQuota (
  476. IN PEPROCESS_QUOTA_BLOCK QuotaBlock,
  477. IN PEPROCESS Process,
  478. IN PS_QUOTA_TYPE QuotaType,
  479. IN SIZE_T Amount)
  480. /*++
  481. Routine Description:
  482. This function returns previously charged quota to the quota block
  483. Arguments:
  484. QuotaBlock - Quota block to return charges to.
  485. Process - Process that was originaly charged.
  486. QuotaType - The quota being returned. One of PsNonPagedPool, PsPagedPool or PsPageFile.
  487. Amount - The amount of quota being returned.
  488. Return Value:
  489. None.
  490. --*/
  491. {
  492. PEPROCESS_QUOTA_ENTRY QE;
  493. SIZE_T Usage, NewUsage, tUsage, tAmount, rAmount, Limit, NewLimit, tLimit;
  494. SIZE_T GiveBackLimit, GiveBack;
  495. QE = &QuotaBlock->QuotaEntry[QuotaType];
  496. Usage = QE->Usage;
  497. Limit = QE->Limit;
  498. //
  499. // We need to give back quota here if we have lots to return.
  500. //
  501. #define PSMINGIVEBACK ((MMPAGED_QUOTA_INCREASE > MMNONPAGED_QUOTA_INCREASE)?MMNONPAGED_QUOTA_INCREASE:MMPAGED_QUOTA_INCREASE)
  502. if (Limit - Usage > PSMINGIVEBACK && Limit > Usage) {
  503. if (QuotaType != PsPageFile && QuotaBlock != &PspDefaultQuotaBlock && PspDoingGiveBacks) {
  504. if (QuotaType == PsPagedPool) {
  505. GiveBackLimit = MMPAGED_QUOTA_INCREASE;
  506. } else {
  507. GiveBackLimit = MMNONPAGED_QUOTA_INCREASE;
  508. }
  509. if (GiveBackLimit > Amount) {
  510. GiveBack = Amount;
  511. } else {
  512. GiveBack = GiveBackLimit;
  513. }
  514. NewLimit = Limit - GiveBack;
  515. tLimit = PspInterlockedCompareExchangeQuota (&QE->Limit,
  516. NewLimit,
  517. Limit);
  518. if (tLimit == Limit) {
  519. //
  520. // We suceeded in shrinking the limit. Add this reduction to the return field.
  521. // If returns exceed a threshhold then give the lot bacxk to MM.
  522. //
  523. GiveBack = PspInterlockedAddQuota (&QE->Return, GiveBack);
  524. if (GiveBack > GiveBackLimit) {
  525. PspGivebackQuota (QuotaType, QE);
  526. }
  527. }
  528. }
  529. }
  530. //
  531. // Now return the quota to the usage field.
  532. // The charge might have been split across the default quota block and
  533. // a new quota block. We have to handle this case here by first returning
  534. // quota to the specified quota block then skipping to the default.
  535. //
  536. rAmount = Amount;
  537. while (1) {
  538. if (rAmount > Usage) {
  539. tAmount = Usage;
  540. NewUsage = 0;
  541. } else {
  542. tAmount = rAmount;
  543. NewUsage = Usage - rAmount;
  544. }
  545. tUsage = PspInterlockedCompareExchangeQuota (&QE->Usage,
  546. NewUsage,
  547. Usage);
  548. if (tUsage == Usage) {
  549. //
  550. // Update the process counts if needed
  551. //
  552. if (Process != NULL) {
  553. ASSERT (tAmount <= Process->QuotaUsage[QuotaType]);
  554. NewUsage = PspInterlockedSubtractQuota (&Process->QuotaUsage[QuotaType], tAmount);
  555. }
  556. rAmount = rAmount - tAmount;
  557. if (rAmount == 0) {
  558. return;
  559. }
  560. ASSERT (QuotaBlock != &PspDefaultQuotaBlock);
  561. if (QuotaBlock == &PspDefaultQuotaBlock) {
  562. return;
  563. }
  564. QuotaBlock = &PspDefaultQuotaBlock;
  565. QE = &QuotaBlock->QuotaEntry[QuotaType];
  566. Usage = QE->Usage;
  567. } else {
  568. Usage = tUsage;
  569. }
  570. }
  571. }
  572. PEPROCESS_QUOTA_BLOCK
  573. PsChargeSharedPoolQuota(
  574. IN PEPROCESS Process,
  575. IN SIZE_T PagedAmount,
  576. IN SIZE_T NonPagedAmount
  577. )
  578. /*++
  579. Routine Description:
  580. This function charges shared pool quota of the specified pool type
  581. to the specified process's pooled quota block. If the quota charge
  582. would exceed the limits allowed to the process, then an exception is
  583. raised and quota is not charged.
  584. Arguments:
  585. Process - Supplies the process to charge quota to.
  586. PagedAmount - Supplies the amount of paged pool quota to charge.
  587. PagedAmount - Supplies the amount of non paged pool quota to charge.
  588. Return Value:
  589. NULL - Quota was exceeded
  590. NON-NULL - A referenced pointer to the quota block that was charged
  591. --*/
  592. {
  593. PEPROCESS_QUOTA_BLOCK QuotaBlock;
  594. NTSTATUS Status;
  595. ASSERT((Process->Pcb.Header.Type == ProcessObject) || (Process->Pcb.Header.Type == 0));
  596. if (Process == PsInitialSystemProcess) {
  597. return (PEPROCESS_QUOTA_BLOCK) 1;
  598. }
  599. QuotaBlock = Process->QuotaBlock;
  600. if (PagedAmount > 0) {
  601. Status = PspChargeQuota (QuotaBlock, NULL, PsPagedPool, PagedAmount);
  602. if (!NT_SUCCESS (Status)) {
  603. return NULL;
  604. }
  605. }
  606. if (NonPagedAmount > 0) {
  607. Status = PspChargeQuota (QuotaBlock, NULL, PsNonPagedPool, NonPagedAmount);
  608. if (!NT_SUCCESS (Status)) {
  609. if (PagedAmount > 0) {
  610. PspReturnQuota (QuotaBlock, NULL, PsPagedPool, PagedAmount);
  611. }
  612. return NULL;
  613. }
  614. }
  615. InterlockedIncrement ((PLONG) &QuotaBlock->ReferenceCount);
  616. return QuotaBlock;
  617. }
  618. VOID
  619. PsReturnSharedPoolQuota(
  620. IN PEPROCESS_QUOTA_BLOCK QuotaBlock,
  621. IN SIZE_T PagedAmount,
  622. IN SIZE_T NonPagedAmount
  623. )
  624. /*++
  625. Routine Description:
  626. This function returns pool quota of the specified pool type to the
  627. specified process.
  628. Arguments:
  629. QuotaBlock - Supplies the quota block to return quota to.
  630. PagedAmount - Supplies the amount of paged pool quota to return.
  631. PagedAmount - Supplies the amount of non paged pool quota to return.
  632. Return Value:
  633. None.
  634. --*/
  635. {
  636. //
  637. // if we bypassed the quota charge, don't do anything here either
  638. //
  639. if (QuotaBlock == (PEPROCESS_QUOTA_BLOCK) 1) {
  640. return;
  641. }
  642. if (PagedAmount > 0) {
  643. PspReturnQuota (QuotaBlock, NULL, PsPagedPool, PagedAmount);
  644. }
  645. if (NonPagedAmount > 0) {
  646. PspReturnQuota (QuotaBlock, NULL, PsNonPagedPool, NonPagedAmount);
  647. }
  648. PspDereferenceQuotaBlock (QuotaBlock);
  649. }
  650. VOID
  651. PsChargePoolQuota(
  652. IN PEPROCESS Process,
  653. IN POOL_TYPE PoolType,
  654. IN SIZE_T Amount
  655. )
  656. /*++
  657. Routine Description:
  658. This function charges pool quota of the specified pool type to
  659. the specified process. If the quota charge would exceed the limits
  660. allowed to the process, then an exception is raised and quota is
  661. not charged.
  662. Arguments:
  663. Process - Supplies the process to charge quota to.
  664. PoolType - Supplies the type of pool quota to charge.
  665. Amount - Supplies the amount of pool quota to charge.
  666. Return Value:
  667. Raises STATUS_QUOTA_EXCEEDED if the quota charge would exceed the
  668. limits allowed to the process.
  669. --*/
  670. {
  671. NTSTATUS Status;
  672. Status = PsChargeProcessPoolQuota (Process,
  673. PoolType,
  674. Amount);
  675. if (!NT_SUCCESS (Status)) {
  676. ExRaiseStatus (Status);
  677. }
  678. }
  679. NTSTATUS
  680. PsChargeProcessPoolQuota(
  681. IN PEPROCESS Process,
  682. IN POOL_TYPE PoolType,
  683. IN SIZE_T Amount
  684. )
  685. /*++
  686. Routine Description:
  687. This function charges pool quota of the specified pool type to
  688. the specified process. If the quota charge would exceed the limits
  689. allowed to the process, then an exception is raised and quota is
  690. not charged.
  691. Arguments:
  692. Process - Supplies the process to charge quota to.
  693. PoolType - Supplies the type of pool quota to charge.
  694. Amount - Supplies the amount of pool quota to charge.
  695. Return Value:
  696. NTSTATUS - Status of operation
  697. --*/
  698. {
  699. ASSERT ((Process->Pcb.Header.Type == ProcessObject) || (Process->Pcb.Header.Type == 0));
  700. ASSERT (PoolType == PagedPool || PoolType == NonPagedPool);
  701. __assume (PoolType == PagedPool || PoolType == NonPagedPool);
  702. if (Process == PsInitialSystemProcess) {
  703. return STATUS_SUCCESS;
  704. }
  705. return PspChargeQuota (Process->QuotaBlock, Process, PoolType, Amount);
  706. }
  707. VOID
  708. PsReturnPoolQuota(
  709. IN PEPROCESS Process,
  710. IN POOL_TYPE PoolType,
  711. IN SIZE_T Amount
  712. )
  713. /*++
  714. Routine Description:
  715. This function returns pool quota of the specified pool type to the
  716. specified process.
  717. Arguments:
  718. Process - Supplies the process to return quota to.
  719. PoolType - Supplies the type of pool quota to return.
  720. Amount - Supplies the amount of pool quota to return
  721. Return Value:
  722. Raises STATUS_QUOTA_EXCEEDED if the quota charge would exceed the
  723. limits allowed to the process.
  724. --*/
  725. {
  726. ASSERT((Process->Pcb.Header.Type == ProcessObject) || (Process->Pcb.Header.Type == 0));
  727. ASSERT (PoolType == PagedPool || PoolType == NonPagedPool);
  728. __assume (PoolType == PagedPool || PoolType == NonPagedPool);
  729. if (Process == PsInitialSystemProcess) {
  730. return;
  731. }
  732. PspReturnQuota (Process->QuotaBlock, Process, PoolType, Amount);
  733. return;
  734. }
  735. VOID
  736. PspInheritQuota(
  737. IN PEPROCESS NewProcess,
  738. IN PEPROCESS ParentProcess
  739. )
  740. {
  741. PEPROCESS_QUOTA_BLOCK QuotaBlock;
  742. if (ParentProcess) {
  743. QuotaBlock = ParentProcess->QuotaBlock;
  744. } else {
  745. QuotaBlock = &PspDefaultQuotaBlock;
  746. }
  747. InterlockedIncrement ((PLONG) &QuotaBlock->ReferenceCount);
  748. InterlockedIncrement ((PLONG) &QuotaBlock->ProcessCount);
  749. NewProcess->QuotaBlock = QuotaBlock;
  750. }
  751. VOID
  752. PspDereferenceQuota (
  753. IN PEPROCESS Process
  754. )
  755. /*++
  756. Routine Description:
  757. This function is called at process object deletion to remove the quota block.
  758. Arguments:
  759. Process - Supplies the process to return quota to.
  760. Return Value:
  761. None.
  762. --*/
  763. {
  764. PEPROCESS_QUOTA_BLOCK QuotaBlock;
  765. ASSERT (Process->QuotaUsage[PsNonPagedPool] == 0);
  766. ASSERT (Process->QuotaUsage[PsPagedPool] == 0);
  767. ASSERT (Process->QuotaUsage[PsPageFile] == 0);
  768. QuotaBlock = Process->QuotaBlock;
  769. InterlockedDecrement ((PLONG) &QuotaBlock->ProcessCount);
  770. PspDereferenceQuotaBlock (QuotaBlock);
  771. }
  772. NTSTATUS
  773. PsChargeProcessQuota (
  774. IN PEPROCESS Process,
  775. IN PS_QUOTA_TYPE QuotaType,
  776. IN SIZE_T Amount
  777. )
  778. /*++
  779. Routine Description:
  780. This function is called to charge against the specified quota.
  781. Arguments:
  782. Process - Supplies the process to charge against.
  783. QuotaType - Type of quota being charged
  784. Amount - Amount of quota being charged
  785. Return Value:
  786. NTSTATUS - Status of operation
  787. --*/
  788. {
  789. ASSERT ((Process->Pcb.Header.Type == ProcessObject) || (Process->Pcb.Header.Type == 0));
  790. if (Process == PsInitialSystemProcess) {
  791. return STATUS_SUCCESS;
  792. }
  793. return PspChargeQuota (Process->QuotaBlock, Process, QuotaType, Amount);
  794. }
  795. VOID
  796. PsReturnProcessQuota (
  797. IN PEPROCESS Process,
  798. IN PS_QUOTA_TYPE QuotaType,
  799. IN SIZE_T Amount
  800. )
  801. /*++
  802. Routine Description:
  803. This function is called to return previously charged quota to the specified process
  804. Arguments:
  805. Process - Supplies the process that was previously charged.
  806. QuotaType - Type of quota being returned
  807. Amount - Amount of quota being returned
  808. Return Value:
  809. NTSTATUS - Status of operation
  810. --*/
  811. {
  812. ASSERT ((Process->Pcb.Header.Type == ProcessObject) || (Process->Pcb.Header.Type == 0));
  813. if (Process == PsInitialSystemProcess) {
  814. return;
  815. }
  816. PspReturnQuota (Process->QuotaBlock, Process, QuotaType, Amount);
  817. }
  818. NTSTATUS
  819. PsChargeProcessNonPagedPoolQuota(
  820. IN PEPROCESS Process,
  821. IN SIZE_T Amount
  822. )
  823. /*++
  824. Routine Description:
  825. This function is called to charge non-paged pool quota against the specified process.
  826. Arguments:
  827. Process - Supplies the process to charge against.
  828. Amount - Amount of quota being charged
  829. Return Value:
  830. NTSTATUS - Status of operation
  831. --*/
  832. {
  833. if (Process == PsInitialSystemProcess) {
  834. return STATUS_SUCCESS;
  835. }
  836. return PspChargeQuota (Process->QuotaBlock, Process, PsNonPagedPool, Amount);
  837. }
  838. VOID
  839. PsReturnProcessNonPagedPoolQuota(
  840. IN PEPROCESS Process,
  841. IN SIZE_T Amount
  842. )
  843. /*++
  844. Routine Description:
  845. This function is called to return previously charged non-paged pool quota to the specified process
  846. Arguments:
  847. Process - Supplies the process that was previously charged.
  848. Amount - Amount of quota being returned
  849. Return Value:
  850. NTSTATUS - Status of operation
  851. --*/
  852. {
  853. if (Process == PsInitialSystemProcess) {
  854. return;
  855. }
  856. PspReturnQuota (Process->QuotaBlock, Process, PsNonPagedPool, Amount);
  857. }
  858. NTSTATUS
  859. PsChargeProcessPagedPoolQuota(
  860. IN PEPROCESS Process,
  861. IN SIZE_T Amount
  862. )
  863. /*++
  864. Routine Description:
  865. This function is called to charge paged pool quota against the specified process.
  866. Arguments:
  867. Process - Supplies the process to charge against.
  868. Amount - Amount of quota being charged
  869. Return Value:
  870. NTSTATUS - Status of operation
  871. --*/
  872. {
  873. if (Process == PsInitialSystemProcess) {
  874. return STATUS_SUCCESS;
  875. }
  876. return PspChargeQuota (Process->QuotaBlock, Process, PsPagedPool, Amount);
  877. }
  878. VOID
  879. PsReturnProcessPagedPoolQuota(
  880. IN PEPROCESS Process,
  881. IN SIZE_T Amount
  882. )
  883. /*++
  884. Routine Description:
  885. This function is called to return previously charged paged pool quota to the specified process
  886. Arguments:
  887. Process - Supplies the process that was previously charged.
  888. Amount - Amount of quota being returned
  889. Return Value:
  890. NTSTATUS - Status of operation
  891. --*/
  892. {
  893. if (Process == PsInitialSystemProcess) {
  894. return;
  895. }
  896. PspReturnQuota (Process->QuotaBlock, Process, PsPagedPool, Amount);
  897. }
  898. NTSTATUS
  899. PsChargeProcessPageFileQuota(
  900. IN PEPROCESS Process,
  901. IN SIZE_T Amount
  902. )
  903. /*++
  904. Routine Description:
  905. This function is called to charge page file quota against the specified process.
  906. Arguments:
  907. Process - Supplies the process to charge against.
  908. Amount - Amount of quota being charged
  909. Return Value:
  910. NTSTATUS - Status of operation
  911. --*/
  912. {
  913. if (Process == PsInitialSystemProcess) {
  914. return STATUS_SUCCESS;
  915. }
  916. return PspChargeQuota (Process->QuotaBlock, Process, PsPageFile, Amount);
  917. }
  918. VOID
  919. PsReturnProcessPageFileQuota(
  920. IN PEPROCESS Process,
  921. IN SIZE_T Amount
  922. )
  923. /*++
  924. Routine Description:
  925. This function is called to return previously charged page file quota to the specified process
  926. Arguments:
  927. Process - Supplies the process that was previously charged.
  928. Amount - Amount of quota being returned
  929. Return Value:
  930. NTSTATUS - Status of operation
  931. --*/
  932. {
  933. if (Process == PsInitialSystemProcess) {
  934. return;
  935. }
  936. PspReturnQuota (Process->QuotaBlock, Process, PsPageFile, Amount);
  937. }