Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

mmquota.c File Reference

#include "mi.h"

Go to the source code of this file.

Defines

#define MM_MAXIMUM_QUOTA_OVERCHARGE   9
#define MM_DONT_EXTEND_SIZE   512
#define MM_COMMIT_POPUP_MAX   ((512*1024)/PAGE_SIZE)
#define MM_EXTEND_COMMIT   ((1024*1024)/PAGE_SIZE)

Functions

LOGICAL MiCauseOverCommitPopup (IN SIZE_T NumberOfPages, IN ULONG Extension)
ULONG FASTCALL MiChargePageFileQuota (IN SIZE_T QuotaCharge, IN PEPROCESS CurrentProcess)
VOID MiReturnPageFileQuota (IN SIZE_T QuotaCharge, IN PEPROCESS CurrentProcess)
LOGICAL FASTCALL MiChargeCommitment (IN SIZE_T QuotaCharge, IN PEPROCESS Process OPTIONAL)
LOGICAL FASTCALL MiChargeCommitmentCantExpand (IN SIZE_T QuotaCharge, IN ULONG MustSucceed)
VOID FASTCALL MiReturnCommitment (IN SIZE_T QuotaCharge)
SIZE_T MiCalculatePageCommitment (IN PVOID StartingAddress, IN PVOID EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
VOID MiReturnPageTablePageCommitment (IN PVOID StartingAddress, IN PVOID EndingAddress, IN PEPROCESS CurrentProcess, IN PMMVAD PreviousVad, IN PMMVAD NextVad)
LOGICAL MiCauseOverCommitPopup (SIZE_T NumberOfPages, IN ULONG Extension)
BOOLEAN MmRaisePoolQuota (IN POOL_TYPE PoolType, IN SIZE_T OldQuotaLimit, OUT PSIZE_T NewQuotaLimit)
VOID MmReturnPoolQuota (IN POOL_TYPE PoolType, IN SIZE_T ReturnedQuota)

Variables

SIZE_T MmPeakCommitment
SIZE_T MmExtendedCommit
SIZE_T MmExtendedCommitLimit
LOGICAL MiCommitExtensionActive = FALSE
ULONG_PTR MmAllocatedPagedPool
SIZE_T MmPageFileFullExtendPages
ULONG MiOverCommitCallCount
EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock
SIZE_T MmTotalPagedPoolQuota
SIZE_T MmTotalNonPagedPoolQuota


Define Documentation

#define MM_COMMIT_POPUP_MAX   ((512*1024)/PAGE_SIZE)
 

Definition at line 29 of file mmquota.c.

Referenced by MiCauseOverCommitPopup().

#define MM_DONT_EXTEND_SIZE   512
 

Definition at line 27 of file mmquota.c.

Referenced by MiChargeCommitmentCantExpand().

#define MM_EXTEND_COMMIT   ((1024*1024)/PAGE_SIZE)
 

Definition at line 31 of file mmquota.c.

Referenced by MiChargeCommitment().

#define MM_MAXIMUM_QUOTA_OVERCHARGE   9
 

Definition at line 25 of file mmquota.c.

Referenced by MiChargeCommitment().


Function Documentation

SIZE_T MiCalculatePageCommitment IN PVOID  StartingAddress,
IN PVOID  EndingAddress,
IN PMMVAD  Vad,
IN PEPROCESS  Process
 

Definition at line 519 of file mmquota.c.

References BYTES_TO_PAGES, FALSE, MiDoesPdeExistAndMakeValid(), MiDoesPpeExistAndMakeValid, MiGetPdeAddress, MiGetPpeAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiIsPteDecommittedPage(), MiIsPteOnPdeBoundary, and _MMPTE::u.

Referenced by NtAllocateVirtualMemory(), and NtFreeVirtualMemory().

00528 : 00529 00530 This routine examines the range of pages from the starting address 00531 up to and including the ending address and returns the commit charge 00532 for the pages within the range. 00533 00534 Arguments: 00535 00536 StartingAddress - Supplies the starting address of the range. 00537 00538 EndingAddress - Supplies the ending address of the range. 00539 00540 Vad - Supplies the virtual address descriptor which describes the range. 00541 00542 Process - Supplies the current process. 00543 00544 Return Value: 00545 00546 Commitment charge for the range. 00547 00548 Environment: 00549 00550 Kernel mode, APCs disabled, WorkingSetLock and AddressCreation mutexes 00551 held. 00552 00553 --*/ 00554 00555 { 00556 PMMPTE PointerPte; 00557 PMMPTE LastPte; 00558 PMMPTE PointerPde; 00559 PMMPTE PointerPpe; 00560 PMMPTE TempEnd; 00561 SIZE_T NumberOfCommittedPages; 00562 ULONG Waited; 00563 00564 NumberOfCommittedPages = 0; 00565 00566 PointerPpe = MiGetPpeAddress (StartingAddress); 00567 PointerPde = MiGetPdeAddress (StartingAddress); 00568 PointerPte = MiGetPteAddress (StartingAddress); 00569 00570 if (Vad->u.VadFlags.MemCommit == 1) { 00571 00572 TempEnd = EndingAddress; 00573 00574 // 00575 // All the pages are committed within this range. 00576 // 00577 00578 NumberOfCommittedPages = BYTES_TO_PAGES ((PCHAR)TempEnd - 00579 (PCHAR)StartingAddress); 00580 00581 00582 // 00583 // Examine the PTEs to determine how many pages are committed. 00584 // 00585 00586 LastPte = MiGetPteAddress (TempEnd); 00587 00588 do { 00589 00590 while (!MiDoesPpeExistAndMakeValid (PointerPpe, 00591 Process, 00592 FALSE, 00593 &Waited)) { 00594 00595 // 00596 // No PPE exists for the starting address, therefore the page 00597 // is not committed. 00598 // 00599 00600 PointerPpe += 1; 00601 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 00602 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00603 if (PointerPte > LastPte) { 00604 goto DoneCommit; 00605 } 00606 } 00607 00608 Waited = 0; 00609 00610 while (!MiDoesPdeExistAndMakeValid (PointerPde, 00611 Process, 00612 FALSE, 00613 &Waited)) { 00614 00615 // 00616 // No PDE exists for the starting address, therefore the page 00617 // is not committed. 00618 // 00619 00620 PointerPde += 1; 00621 PointerPpe = MiGetPteAddress (PointerPde); 00622 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00623 if (PointerPte > LastPte) { 00624 goto DoneCommit; 00625 } 00626 #if defined (_WIN64) 00627 if (MiIsPteOnPdeBoundary (PointerPde)) { 00628 Waited = 1; 00629 break; 00630 } 00631 #endif 00632 } 00633 00634 } while (Waited != 0); 00635 00636 restart: 00637 00638 while (PointerPte <= LastPte) { 00639 00640 if (MiIsPteOnPdeBoundary (PointerPte)) { 00641 00642 // 00643 // This is a PDE boundary, check to see if the entire 00644 // PPE/PDE pages exist. 00645 // 00646 00647 PointerPde = MiGetPteAddress (PointerPte); 00648 PointerPpe = MiGetPteAddress (PointerPde); 00649 00650 do { 00651 00652 if (!MiDoesPpeExistAndMakeValid (PointerPpe, 00653 Process, 00654 FALSE, 00655 &Waited)) { 00656 00657 // 00658 // No PDE exists for the starting address, check the VAD 00659 // to see if the pages are not committed. 00660 // 00661 00662 PointerPpe += 1; 00663 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 00664 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00665 00666 // 00667 // Check next page. 00668 // 00669 00670 goto restart; 00671 } 00672 00673 Waited = 0; 00674 00675 if (!MiDoesPdeExistAndMakeValid (PointerPde, 00676 Process, 00677 FALSE, 00678 &Waited)) { 00679 00680 // 00681 // No PDE exists for the starting address, check the VAD 00682 // to see if the pages are not committed. 00683 // 00684 00685 PointerPde += 1; 00686 PointerPpe = MiGetPteAddress (PointerPde); 00687 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00688 00689 // 00690 // Check next page. 00691 // 00692 00693 goto restart; 00694 } 00695 } while (Waited != 0); 00696 } 00697 00698 // 00699 // The PDE exists, examine the PTE. 00700 // 00701 00702 if (PointerPte->u.Long != 0) { 00703 00704 // 00705 // Has this page been explicitly decommitted? 00706 // 00707 00708 if (MiIsPteDecommittedPage (PointerPte)) { 00709 00710 // 00711 // This page is decommitted, remove it from the count. 00712 // 00713 00714 NumberOfCommittedPages -= 1; 00715 00716 } 00717 } 00718 00719 PointerPte += 1; 00720 } 00721 00722 DoneCommit: 00723 00724 if (TempEnd == EndingAddress) { 00725 return NumberOfCommittedPages; 00726 } 00727 00728 } 00729 00730 // 00731 // Examine non committed range. 00732 // 00733 00734 LastPte = MiGetPteAddress (EndingAddress); 00735 00736 do { 00737 00738 while (!MiDoesPpeExistAndMakeValid (PointerPpe, 00739 Process, 00740 FALSE, 00741 &Waited)) { 00742 00743 00744 // 00745 // No PDE exists for the starting address, therefore the page 00746 // is not committed. 00747 // 00748 00749 PointerPpe += 1; 00750 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 00751 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00752 if (PointerPte > LastPte) { 00753 return NumberOfCommittedPages; 00754 } 00755 } 00756 00757 Waited = 0; 00758 00759 while (!MiDoesPdeExistAndMakeValid (PointerPde, 00760 Process, 00761 FALSE, 00762 &Waited)) { 00763 00764 // 00765 // No PDE exists for the starting address, therefore the page 00766 // is not committed. 00767 // 00768 00769 PointerPde += 1; 00770 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00771 if (PointerPte > LastPte) { 00772 return NumberOfCommittedPages; 00773 } 00774 #if defined (_WIN64) 00775 if (MiIsPteOnPdeBoundary (PointerPde)) { 00776 PointerPpe = MiGetPteAddress (PointerPde); 00777 Waited = 1; 00778 break; 00779 } 00780 #endif 00781 } 00782 00783 } while (Waited != 0); 00784 00785 restart2: 00786 00787 while (PointerPte <= LastPte) { 00788 00789 if (MiIsPteOnPdeBoundary (PointerPte)) { 00790 00791 // 00792 // This is a PDE boundary, check to see if the entire 00793 // PPE/PDE pages exist. 00794 // 00795 00796 PointerPde = MiGetPteAddress (PointerPte); 00797 PointerPpe = MiGetPteAddress (PointerPde); 00798 00799 do { 00800 00801 if (!MiDoesPpeExistAndMakeValid (PointerPpe, 00802 Process, 00803 FALSE, 00804 &Waited)) { 00805 00806 // 00807 // No PPE exists for the starting address, check the VAD 00808 // to see if the pages are not committed. 00809 // 00810 00811 PointerPpe += 1; 00812 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 00813 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00814 00815 // 00816 // Check next page. 00817 // 00818 00819 goto restart2; 00820 } 00821 00822 Waited = 0; 00823 00824 if (!MiDoesPdeExistAndMakeValid (PointerPde, 00825 Process, 00826 FALSE, 00827 &Waited)) { 00828 00829 // 00830 // No PDE exists for the starting address, check the VAD 00831 // to see if the pages are not committed. 00832 // 00833 00834 PointerPde += 1; 00835 PointerPpe = MiGetPteAddress (PointerPde); 00836 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00837 00838 // 00839 // Check next page. 00840 // 00841 00842 goto restart2; 00843 } 00844 00845 } while (Waited != 0); 00846 } 00847 00848 // 00849 // The PDE exists, examine the PTE. 00850 // 00851 00852 if ((PointerPte->u.Long != 0) && 00853 (!MiIsPteDecommittedPage (PointerPte))) { 00854 00855 // 00856 // This page is committed, count it. 00857 // 00858 00859 NumberOfCommittedPages += 1; 00860 } 00861 00862 PointerPte += 1; 00863 } 00864 00865 return NumberOfCommittedPages; 00866 }

LOGICAL MiCauseOverCommitPopup SIZE_T  NumberOfPages,
IN ULONG  Extension
 

Definition at line 1001 of file mmquota.c.

References FALSE, IoRaiseInformationalHardError(), MiCommitExtensionActive, MiOverCommitCallCount, MM_COMMIT_POPUP_MAX, MmChargeCommitmentLock, MmExtendedCommit, MmExtendedCommitLimit, MmPageFileFullExtendPages, MmPeakCommitment, MmTotalCommitLimit, MmTotalCommitLimitMaximum, MmTotalCommittedPages, NULL, and TRUE.

01008 : 01009 01010 This function causes an over commit popup to occur. If a popup is pending 01011 it returns FALSE. Otherwise, it queues a popup to a noncritical worker 01012 thread. 01013 01014 Arguments: 01015 01016 NumberOfPages - Supplies the number of pages of commit requested. 01017 01018 Extension - Supplies the extension to grant. 01019 01020 Return Value: 01021 01022 TRUE - An overcommit popup was queued. 01023 01024 FALSE - An overcommit popup is still pending and will not be queued. 01025 01026 --*/ 01027 01028 { 01029 KIRQL OldIrql; 01030 BOOLEAN RaisedPopup; 01031 ULONG PopupNumber; 01032 01033 if (NumberOfPages > MM_COMMIT_POPUP_MAX || 01034 MmTotalCommittedPages + NumberOfPages > MmTotalCommitLimitMaximum) { 01035 return FALSE; 01036 } 01037 01038 // 01039 // Give the user a meaningful message - either to increase the minimum, 01040 // maximum, or both. 01041 // 01042 01043 if (MmTotalCommittedPages > MmTotalCommitLimitMaximum - 100) { 01044 PopupNumber = STATUS_COMMITMENT_LIMIT; 01045 } 01046 else { 01047 PopupNumber = STATUS_COMMITMENT_MINIMUM; 01048 } 01049 01050 RaisedPopup = IoRaiseInformationalHardError (PopupNumber, NULL, NULL); 01051 01052 ExAcquireFastLock (&MmChargeCommitmentLock, &OldIrql); 01053 01054 if ((RaisedPopup == FALSE) && (MiOverCommitCallCount > 0)) { 01055 01056 // 01057 // There is already a popup outstanding and we have not 01058 // returned any of the quota. 01059 // 01060 01061 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 01062 return FALSE; 01063 } 01064 01065 // 01066 // Now that the commitment lock is held, ensure the commit is not being 01067 // raised past the absolute maximum. 01068 // 01069 01070 if (MmTotalCommittedPages + NumberOfPages > MmTotalCommitLimitMaximum) { 01071 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 01072 return FALSE; 01073 } 01074 01075 // 01076 // Don't automatically grant increases forever as this can allow the 01077 // system to run out of available pages. 01078 // 01079 01080 if (MmExtendedCommit > 1024) { 01081 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 01082 return FALSE; 01083 } 01084 01085 MiOverCommitCallCount += 1; 01086 01087 MiCommitExtensionActive = TRUE; 01088 01089 MmTotalCommitLimit += Extension; 01090 MmExtendedCommitLimit += Extension; 01091 01092 MmTotalCommittedPages += NumberOfPages; 01093 01094 // 01095 // The caller will not release this commit, so we must earmark it now 01096 // for later release. 01097 // 01098 01099 if (Extension == 0) { 01100 MmExtendedCommit += NumberOfPages; 01101 } 01102 01103 if ((MmTotalCommittedPages > MmPeakCommitment) && 01104 (MmPageFileFullExtendPages == 0)) { 01105 MmPeakCommitment = MmTotalCommittedPages; 01106 } 01107 01108 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 01109 01110 return TRUE; 01111 }

LOGICAL MiCauseOverCommitPopup IN SIZE_T  NumberOfPages,
IN ULONG  Extension
 

LOGICAL FASTCALL MiChargeCommitment IN SIZE_T  QuotaCharge,
IN PEPROCESS Process  OPTIONAL
 

Definition at line 191 of file mmquota.c.

References _MMPAGE_FILE_EXPANSION::ActualExpansion, ASSERT, _MMPAGE_FILE_EXPANSION::Event, FALSE, KeInitializeEvent, LOCK_WS, LOCK_WS_REGARDLESS, LOCK_WS_UNSAFE, MI_EXTEND_ANY_PAGEFILE, MiCauseOverCommitPopup(), MiChargeCommitmentCantExpand(), MiIssuePageExtendRequest(), MM_EXTEND_COMMIT, MM_MAXIMUM_QUOTA_OVERCHARGE, MmChargeCommitmentLock, MmPageFileFullExtendPages, MmPeakCommitment, MmTotalCommitLimit, MmTotalCommittedPages, NULL, _MMPAGE_FILE_EXPANSION::PageFileNumber, _MMPAGE_FILE_EXPANSION::RequestedExpansionSize, _MMPAGE_FILE_EXPANSION::Segment, TRUE, and UNLOCK_WS_REGARDLESS.

Referenced by MiCreateImageFileMap(), MiCreatePagingFileMap(), MiInitializeSessionPool(), MiInsertVad(), MiMapViewOfDataSection(), MiSessionCommitImagePages(), MiSessionCommitPageTables(), MiSessionCreateInternal(), MiSessionInitializeWorkingSetList(), MiSetProtectionOnSection(), MiShareSessionImage(), MmCreateKernelStack(), MmCreateProcessAddressSpace(), NtAllocateVirtualMemory(), and NtCreatePagingFile().

00198 : 00199 00200 This routine checks to ensure the system has sufficient page file 00201 space remaining. 00202 00203 Arguments: 00204 00205 QuotaCharge - Supplies the quota amount to charge. 00206 00207 Process - Optionally supplies the current process IF AND ONLY IF 00208 the working set mutex is held. If the paging file 00209 is being extended, the working set mutex is released if 00210 this is non-null. 00211 00212 Return Value: 00213 00214 TRUE if there is sufficient space, FALSE if not. 00215 00216 Environment: 00217 00218 Kernel mode, APCs disabled, WorkingSetLock and AddressCreation mutexes 00219 held. 00220 00221 --*/ 00222 00223 { 00224 KIRQL OldIrql; 00225 SIZE_T NewCommitValue; 00226 MMPAGE_FILE_EXPANSION PageExtend; 00227 LOGICAL WsHeldSafe; 00228 00229 #if !defined (_WIN64) 00230 ASSERT (QuotaCharge < 0x100000); 00231 #endif 00232 00233 ExAcquireFastLock (&MmChargeCommitmentLock, &OldIrql); 00234 00235 NewCommitValue = MmTotalCommittedPages + QuotaCharge; 00236 00237 while (NewCommitValue > MmTotalCommitLimit) { 00238 00239 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 00240 00241 if (Process != NULL) { 00242 00243 // 00244 // The working set lock may have been acquired safely or unsafely 00245 // by our caller. Handle both cases here and below. 00246 // 00247 00248 UNLOCK_WS_REGARDLESS(Process, WsHeldSafe); 00249 } 00250 00251 // 00252 // Queue a message to the segment dereferencing / pagefile extending 00253 // thread to see if the page file can be extended. This is done 00254 // in the context of a system thread due to mutexes which may 00255 // currently be held. 00256 // 00257 00258 PageExtend.RequestedExpansionSize = QuotaCharge; 00259 PageExtend.Segment = NULL; 00260 PageExtend.PageFileNumber = MI_EXTEND_ANY_PAGEFILE; 00261 KeInitializeEvent (&PageExtend.Event, NotificationEvent, FALSE); 00262 00263 if (MiIssuePageExtendRequest (&PageExtend) == FALSE) { 00264 00265 if (Process != NULL) { 00266 LOCK_WS_REGARDLESS(Process, WsHeldSafe); 00267 } 00268 00269 // 00270 // If the quota is small enough, commit it anyway. Otherwise 00271 // return an error. 00272 // 00273 00274 if (QuotaCharge < MM_MAXIMUM_QUOTA_OVERCHARGE) { 00275 00276 // 00277 // Try the can't expand routine. 00278 // 00279 00280 if (MiChargeCommitmentCantExpand (QuotaCharge, FALSE) == FALSE) { 00281 return FALSE; 00282 } 00283 } else { 00284 00285 // 00286 // Put up a popup and grant an extension if possible. 00287 // 00288 00289 if (MiCauseOverCommitPopup (QuotaCharge, MM_EXTEND_COMMIT) == FALSE) { 00290 return FALSE; 00291 } 00292 } 00293 return TRUE; 00294 } 00295 00296 if (Process != NULL) { 00297 if (WsHeldSafe == TRUE) { 00298 LOCK_WS (Process); 00299 } 00300 else { 00301 LOCK_WS_UNSAFE (Process); 00302 } 00303 } 00304 00305 if (PageExtend.ActualExpansion == 0) { 00306 if (MiCauseOverCommitPopup (QuotaCharge, MM_EXTEND_COMMIT) == FALSE) { 00307 return FALSE; 00308 } 00309 return TRUE; 00310 } 00311 00312 ExAcquireFastLock (&MmChargeCommitmentLock, &OldIrql); 00313 NewCommitValue = MmTotalCommittedPages + QuotaCharge; 00314 } 00315 00316 MmTotalCommittedPages = NewCommitValue; 00317 if ((MmTotalCommittedPages > MmPeakCommitment) && 00318 (MmPageFileFullExtendPages == 0)) { 00319 MmPeakCommitment = MmTotalCommittedPages; 00320 } 00321 00322 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 00323 00324 return TRUE; 00325 }

LOGICAL FASTCALL MiChargeCommitmentCantExpand IN SIZE_T  QuotaCharge,
IN ULONG  MustSucceed
 

Definition at line 329 of file mmquota.c.

References _MMPAGE_FILE_EXPANSION::DereferenceList, FALSE, _MMPAGE_FILE_EXPANSION::InProgress, KeReleaseSemaphore(), L, _MMDEREFERENCE_SEGMENT_HEADER::ListHead, _MMDEREFERENCE_SEGMENT_HEADER::Lock, MM_DONT_EXTEND_SIZE, MmAttemptForCantExtend, MmChargeCommitmentLock, MmDereferenceSegmentHeader, MmTotalCommitLimit, MmTotalCommitLimitMaximum, MmTotalCommittedPages, _MMPAGE_FILE_EXPANSION::RequestedExpansionSize, _MMDEREFERENCE_SEGMENT_HEADER::Semaphore, and TRUE.

Referenced by MiAddWorkingSetPage(), MiAddWsleHash(), MiAllocatePoolPages(), MiAllocateSpecialPool(), MiChargeCommitment(), MiFillSystemPageDirectory(), MiFindContiguousMemory(), MiLoadImageSection(), MiPageFileFull(), MmAllocateIndependentPages(), MmAllocateNonCachedMemory(), MmAllocatePagesForMdl(), and MmInitSystem().

00336 : 00337 00338 This routine charges the specified commitment without attempting 00339 to expand paging file and waiting for the expansion. The routine 00340 determines if the paging file space is exhausted, and if so, 00341 it attempts to ascertain if the paging file space could be expanded. 00342 00343 Arguments: 00344 00345 QuotaCharge - Supplies the quota amount to charge. 00346 00347 MustSucceed - Supplies TRUE if the charge must succeed. 00348 00349 Return Value: 00350 00351 TRUE if the commitment was permitted, FALSE if not. 00352 00353 Environment: 00354 00355 Kernel mode, APCs disabled. 00356 00357 --*/ 00358 00359 { 00360 KIRQL OldIrql; 00361 SIZE_T NewCommitValue; 00362 SIZE_T ExtendAmount; 00363 00364 ExAcquireFastLock (&MmChargeCommitmentLock, &OldIrql); 00365 00366 // 00367 // If the overcommitment is bigger than 512 pages, don't extend. 00368 // 00369 00370 NewCommitValue = MmTotalCommittedPages + QuotaCharge; 00371 00372 if (!MustSucceed) { 00373 00374 if (NewCommitValue > MmTotalCommitLimit) { 00375 00376 if ((NewCommitValue - MmTotalCommitLimit > MM_DONT_EXTEND_SIZE) || 00377 (NewCommitValue < MmTotalCommittedPages) || 00378 (NewCommitValue > MmTotalCommitLimitMaximum)) { 00379 00380 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 00381 return FALSE; 00382 } 00383 } 00384 else if (NewCommitValue > MmTotalCommitLimitMaximum) { 00385 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 00386 return FALSE; 00387 } 00388 } 00389 00390 ExtendAmount = NewCommitValue - MmTotalCommitLimit; 00391 MmTotalCommittedPages = NewCommitValue; 00392 00393 if (NewCommitValue > (MmTotalCommitLimit + 20)) { 00394 00395 // 00396 // Attempt to expand the paging file, but don't wait 00397 // to see if it succeeds. 00398 // 00399 00400 if (MmAttemptForCantExtend.InProgress != FALSE) { 00401 00402 // 00403 // An expansion request is already in progress, assume 00404 // this will succeed. 00405 // 00406 00407 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 00408 return TRUE; 00409 } 00410 00411 MmAttemptForCantExtend.InProgress = TRUE; 00412 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 00413 00414 // 00415 // Queue a message to the segment dereferencing / pagefile extending 00416 // thread to see if the page file can be extended. This is done 00417 // in the context of a system thread due to mutexes which may 00418 // currently be held. 00419 // 00420 00421 if (QuotaCharge > ExtendAmount) { 00422 ExtendAmount = QuotaCharge; 00423 } 00424 00425 MmAttemptForCantExtend.RequestedExpansionSize = ExtendAmount; 00426 ExAcquireFastLock (&MmDereferenceSegmentHeader.Lock, &OldIrql); 00427 InsertTailList ( &MmDereferenceSegmentHeader.ListHead, 00428 &MmAttemptForCantExtend.DereferenceList); 00429 ExReleaseFastLock (&MmDereferenceSegmentHeader.Lock, OldIrql); 00430 00431 KeReleaseSemaphore (&MmDereferenceSegmentHeader.Semaphore, 0L, 1L, FALSE); 00432 } 00433 else { 00434 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 00435 } 00436 00437 return TRUE; 00438 }

ULONG FASTCALL MiChargePageFileQuota IN SIZE_T  QuotaCharge,
IN PEPROCESS  CurrentProcess
 

Definition at line 58 of file mmquota.c.

References ExRaiseStatus(), _EPROCESS_QUOTA_BLOCK::PagefileLimit, _EPROCESS_QUOTA_BLOCK::PagefileUsage, _EPROCESS_QUOTA_BLOCK::PeakPagefileUsage, PEPROCESS_QUOTA_BLOCK, PspDefaultQuotaBlock, _EPROCESS_QUOTA_BLOCK::QuotaLock, and TRUE.

Referenced by MiInsertVad(), MiSetProtectionOnSection(), and NtAllocateVirtualMemory().

00065 : 00066 00067 This routine checks to ensure the user has sufficient page file 00068 quota remaining and, if so, charges the quota. If not an exception 00069 is raised. 00070 00071 Arguments: 00072 00073 QuotaCharge - Supplies the quota amount to charge. 00074 00075 CurrentProcess - Supplies a pointer to the current process. 00076 00077 Return Value: 00078 00079 TRUE if the quota was successfully charged, raises an exception 00080 otherwise. 00081 00082 Environment: 00083 00084 Kernel mode, APCs disabled, WorkingSetLock and AddressCreation mutexes 00085 held. 00086 00087 --*/ 00088 00089 { 00090 SIZE_T NewPagefileValue; 00091 PEPROCESS_QUOTA_BLOCK QuotaBlock; 00092 KIRQL OldIrql; 00093 00094 QuotaBlock = CurrentProcess->QuotaBlock; 00095 00096 retry_charge: 00097 if ( QuotaBlock != &PspDefaultQuotaBlock) { 00098 ExAcquireFastLock (&QuotaBlock->QuotaLock,&OldIrql); 00099 do_charge: 00100 NewPagefileValue = QuotaBlock->PagefileUsage + QuotaCharge; 00101 00102 if (NewPagefileValue > QuotaBlock->PagefileLimit) { 00103 ExReleaseFastLock (&QuotaBlock->QuotaLock,OldIrql); 00104 ExRaiseStatus (STATUS_PAGEFILE_QUOTA_EXCEEDED); 00105 } 00106 00107 QuotaBlock->PagefileUsage = NewPagefileValue; 00108 00109 if (NewPagefileValue > QuotaBlock->PeakPagefileUsage) { 00110 QuotaBlock->PeakPagefileUsage = NewPagefileValue; 00111 } 00112 00113 NewPagefileValue = CurrentProcess->PagefileUsage + QuotaCharge; 00114 CurrentProcess->PagefileUsage = NewPagefileValue; 00115 00116 if (NewPagefileValue > CurrentProcess->PeakPagefileUsage) { 00117 CurrentProcess->PeakPagefileUsage = NewPagefileValue; 00118 } 00119 ExReleaseFastLock (&QuotaBlock->QuotaLock,OldIrql); 00120 } else { 00121 ExAcquireFastLock (&PspDefaultQuotaBlock.QuotaLock,&OldIrql); 00122 00123 if ( (QuotaBlock = CurrentProcess->QuotaBlock) != &PspDefaultQuotaBlock) { 00124 ExReleaseFastLock(&PspDefaultQuotaBlock.QuotaLock,OldIrql); 00125 goto retry_charge; 00126 } 00127 goto do_charge; 00128 } 00129 return TRUE; 00130 }

VOID FASTCALL MiReturnCommitment IN SIZE_T  QuotaCharge  ) 
 

Definition at line 442 of file mmquota.c.

References ASSERT, FALSE, MiCommitExtensionActive, MmChargeCommitmentLock, MmExtendedCommit, MmExtendedCommitLimit, MmPageFileFullExtendPages, MmTotalCommitLimit, MmTotalCommittedPages, and TRUE.

Referenced by MiCreateImageFileMap(), MiCreatePagingFileMap(), MiDereferenceSession(), MiFreeNonPagedPool(), MiFreePoolPages(), MiInitializeSessionPool(), MiLoadImageSection(), MiMapViewOfDataSection(), MiPageFileFull(), MiRemoveVad(), MiReturnPageTablePageCommitment(), MiSegmentDelete(), MiSessionCommitImagePages(), MiSessionCommitPageTables(), MiSessionCreateInternal(), MiSessionInitializeWorkingSetList(), MiSetProtectionOnSection(), MiShareSessionImage(), MmAllocateNonCachedMemory(), MmAllocatePagesForMdl(), MmCleanProcessAddressSpace(), MmCreateKernelStack(), MmCreateProcessAddressSpace(), MmDeleteKernelStack(), MmDeleteProcessAddressSpace(), MmFreeDriverInitialization(), MmFreeNonCachedMemory(), MmFreePagesFromMdl(), MmFreeSpecialPool(), MmRemovePhysicalMemory(), MmUnloadSystemImage(), NtAllocateVirtualMemory(), NtCreatePagingFile(), and NtFreeVirtualMemory().

00448 : 00449 00450 This routine releases page file quota. 00451 00452 Arguments: 00453 00454 QuotaCharge - Supplies the quota amount to charge. 00455 00456 CurrentProcess - Supplies a pointer to the current process. 00457 00458 Return Value: 00459 00460 none. 00461 00462 Environment: 00463 00464 Kernel mode, APCs disabled, WorkingSetLock and AddressCreation mutexes 00465 held. 00466 00467 --*/ 00468 00469 { 00470 KIRQL OldIrql; 00471 00472 ExAcquireFastLock (&MmChargeCommitmentLock, &OldIrql); 00473 00474 ASSERT (MmTotalCommittedPages >= QuotaCharge); 00475 00476 MmTotalCommittedPages -= QuotaCharge; 00477 00478 // 00479 // If commit allotments have been temporarily blocked then open the 00480 // floodgates provided either enough commit has been freed or the pagefile 00481 // extension has succeeded. 00482 // 00483 00484 if (MmPageFileFullExtendPages) { 00485 ASSERT (MmTotalCommittedPages >= MmPageFileFullExtendPages); 00486 MmTotalCommittedPages -= MmPageFileFullExtendPages; 00487 MmPageFileFullExtendPages = 0; 00488 } 00489 00490 // 00491 // If the system automatically granted an increase that can be returned 00492 // now, do it. 00493 // 00494 00495 if (MiCommitExtensionActive == TRUE) { 00496 00497 if ((MmExtendedCommitLimit != 0) && 00498 (MmTotalCommitLimit > MmTotalCommittedPages) && 00499 (MmTotalCommitLimit - MmTotalCommittedPages > MmExtendedCommitLimit)) { 00500 MmTotalCommitLimit -= MmExtendedCommitLimit; 00501 MmExtendedCommitLimit = 0; 00502 } 00503 00504 if (MmExtendedCommit != 0) { 00505 MmTotalCommittedPages -= MmExtendedCommit; 00506 MmExtendedCommit = 0; 00507 } 00508 00509 if ((MmExtendedCommitLimit == 0) && (MmExtendedCommit == 0)) { 00510 MiCommitExtensionActive = FALSE; 00511 } 00512 } 00513 00514 ExReleaseFastLock (&MmChargeCommitmentLock, OldIrql); 00515 return; 00516 }

VOID MiReturnPageFileQuota IN SIZE_T  QuotaCharge,
IN PEPROCESS  CurrentProcess
 

Definition at line 133 of file mmquota.c.

References ASSERT, _EPROCESS_QUOTA_BLOCK::PagefileUsage, PspDefaultQuotaBlock, and _EPROCESS_QUOTA_BLOCK::QuotaLock.

Referenced by MiInsertVad(), MiRemoveVad(), MiReturnPageTablePageCommitment(), MiSetProtectionOnSection(), NtAllocateVirtualMemory(), NtFreeVirtualMemory(), and PspDereferenceQuota().

00140 : 00141 00142 This routine releases page file quota. 00143 00144 Arguments: 00145 00146 QuotaCharge - Supplies the quota amount to charge. 00147 00148 CurrentProcess - Supplies a pointer to the current process. 00149 00150 Return Value: 00151 00152 none. 00153 00154 Environment: 00155 00156 Kernel mode, APCs disabled, WorkingSetLock and AddressCreation mutexes 00157 held. 00158 00159 --*/ 00160 00161 { 00162 00163 PEPROCESS_QUOTA_BLOCK QuotaBlock; 00164 KIRQL OldIrql; 00165 00166 QuotaBlock = CurrentProcess->QuotaBlock; 00167 00168 retry_return: 00169 if ( QuotaBlock != &PspDefaultQuotaBlock) { 00170 ExAcquireFastLock (&QuotaBlock->QuotaLock, &OldIrql); 00171 do_return: 00172 ASSERT (CurrentProcess->PagefileUsage >= QuotaCharge); 00173 CurrentProcess->PagefileUsage -= QuotaCharge; 00174 00175 ASSERT (QuotaBlock->PagefileUsage >= QuotaCharge); 00176 QuotaBlock->PagefileUsage -= QuotaCharge; 00177 ExReleaseFastLock(&QuotaBlock->QuotaLock,OldIrql); 00178 } else { 00179 ExAcquireFastLock (&PspDefaultQuotaBlock.QuotaLock, &OldIrql); 00180 if ( (QuotaBlock = CurrentProcess->QuotaBlock) != &PspDefaultQuotaBlock ) { 00181 ExReleaseFastLock(&PspDefaultQuotaBlock.QuotaLock,OldIrql); 00182 goto retry_return; 00183 } 00184 goto do_return; 00185 } 00186 return; 00187 }

VOID MiReturnPageTablePageCommitment IN PVOID  StartingAddress,
IN PVOID  EndingAddress,
IN PEPROCESS  CurrentProcess,
IN PMMVAD  PreviousVad,
IN PMMVAD  NextVad
 

Definition at line 869 of file mmquota.c.

References ASSERT, _MMWSL::CommittedPageTables, MI_CHECK_BIT, MI_CLEAR_BIT, MI_VPN_TO_VA, MiGetPpePdeOffset, MiReturnCommitment(), MiReturnPageFileQuota(), MM_DBG_COMMIT_RETURN_PAGETABLES, MM_TRACK_COMMIT, MmWorkingSetList, NULL, _MMWSL::NumberOfCommittedPageTables, PS_JOB_STATUS_REPORT_COMMIT_CHANGES, and PsChangeJobMemoryUsage().

Referenced by MmUnmapViewOfSection(), and NtFreeVirtualMemory().

00879 : 00880 00881 This routine returns commitment for COMPLETE page table pages which 00882 span the virtual address range. For example (assuming 4k pages), 00883 if the StartingAddress = 64k and the EndingAddress = 5mb, no 00884 page table charges would be freed as a complete page table page is 00885 not covered by the range. However, if the StartingAddress was 4mb 00886 and the EndingAddress was 9mb, 1 page table page would be freed. 00887 00888 Arguments: 00889 00890 StartingAddress - Supplies the starting address of the range. 00891 00892 EndingAddress - Supplies the ending address of the range. 00893 00894 CurrentProcess - Supplies a pointer to the current process. 00895 00896 PreviousVad - Supplies a pointer to the previous VAD, NULL if none. 00897 00898 NextVad - Supplies a pointer to the next VAD, NULL if none. 00899 00900 Return Value: 00901 00902 None. 00903 00904 Environment: 00905 00906 Kernel mode, APCs disabled, WorkingSetLock and AddressCreation mutexes 00907 held. 00908 00909 --*/ 00910 00911 { 00912 #ifdef _WIN64 00913 DBG_UNREFERENCED_PARAMETER (StartingAddress); 00914 DBG_UNREFERENCED_PARAMETER (EndingAddress); 00915 DBG_UNREFERENCED_PARAMETER (CurrentProcess); 00916 DBG_UNREFERENCED_PARAMETER (PreviousVad); 00917 DBG_UNREFERENCED_PARAMETER (NextVad); 00918 #else 00919 ULONG NumberToClear; 00920 LONG FirstPage; 00921 LONG LastPage; 00922 LONG PreviousPage; 00923 LONG NextPage; 00924 00925 // 00926 // Check to see if any page table pages would be freed. 00927 // 00928 00929 ASSERT (StartingAddress != EndingAddress); 00930 00931 if (PreviousVad == NULL) { 00932 PreviousPage = -1; 00933 } else { 00934 PreviousPage = MiGetPpePdeOffset (MI_VPN_TO_VA (PreviousVad->EndingVpn)); 00935 } 00936 00937 if (NextVad == NULL) { 00938 NextPage = MiGetPpePdeOffset (MM_HIGHEST_USER_ADDRESS) + 1; 00939 } else { 00940 NextPage = MiGetPpePdeOffset (MI_VPN_TO_VA (NextVad->StartingVpn)); 00941 } 00942 00943 ASSERT (PreviousPage <= NextPage); 00944 00945 FirstPage = MiGetPpePdeOffset (StartingAddress); 00946 00947 LastPage = MiGetPpePdeOffset (EndingAddress); 00948 00949 if (PreviousPage == FirstPage) { 00950 00951 // 00952 // A VAD is within the starting page table page. 00953 // 00954 00955 FirstPage += 1; 00956 } 00957 00958 if (NextPage == LastPage) { 00959 00960 // 00961 // A VAD is within the ending page table page. 00962 // 00963 00964 LastPage -= 1; 00965 } 00966 00967 // 00968 // Indicate that the page table page is not in use. 00969 // 00970 00971 if (FirstPage > LastPage) { 00972 return; 00973 } 00974 00975 NumberToClear = 1 + LastPage - FirstPage; 00976 00977 while (FirstPage <= LastPage) { 00978 ASSERT (MI_CHECK_BIT (MmWorkingSetList->CommittedPageTables, 00979 FirstPage)); 00980 00981 MI_CLEAR_BIT (MmWorkingSetList->CommittedPageTables, FirstPage); 00982 FirstPage += 1; 00983 } 00984 00985 MmWorkingSetList->NumberOfCommittedPageTables -= NumberToClear; 00986 MiReturnCommitment (NumberToClear); 00987 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_PAGETABLES, NumberToClear); 00988 MiReturnPageFileQuota (NumberToClear, CurrentProcess); 00989 00990 if (CurrentProcess->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 00991 PsChangeJobMemoryUsage(-(SSIZE_T)NumberToClear); 00992 } 00993 CurrentProcess->CommitCharge -= NumberToClear; 00994 00995 return; 00996 #endif 00997 }

BOOLEAN MmRaisePoolQuota IN POOL_TYPE  PoolType,
IN SIZE_T  OldQuotaLimit,
OUT PSIZE_T  NewQuotaLimit
 

Definition at line 1118 of file mmquota.c.

References _MM_PAGED_POOL_INFO::AllocatedPagedPool, FALSE, MmAllocatedNonPagedPool, MmAvailablePages, MmMaximumNonPagedPoolInBytes, MMNONPAGED_QUOTA_INCREASE, MMPAGED_QUOTA_CHECK, MMPAGED_QUOTA_INCREASE, MmPagedPoolInfo, MmSizeOfPagedPoolInBytes, MmTotalNonPagedPoolQuota, MmTotalPagedPoolQuota, PAGE_SHIFT, PagedPool, and TRUE.

Referenced by PsChargePoolQuota(), PsChargeSharedPoolQuota(), and PspSetQuotaLimits().

01126 : 01127 01128 This function is called (with a spinlock) whenever PS detects a quota 01129 limit has been exceeded. The purpose of this function is to attempt to 01130 increase the specified quota. 01131 01132 Arguments: 01133 01134 PoolType - Supplies the pool type of the quota to be raised 01135 01136 OldQuotaLimit - Supplies the current quota limit for this pool type 01137 01138 NewQuotaLimit - Returns the new limit 01139 01140 Return Value: 01141 01142 TRUE - The API succeeded and the quota limit was raised. 01143 01144 FALSE - We were unable to raise the quota limit. 01145 01146 Environment: 01147 01148 Kernel mode, QUOTA SPIN LOCK HELD!! 01149 01150 --*/ 01151 01152 { 01153 SIZE_T Limit; 01154 PMM_PAGED_POOL_INFO PagedPoolInfo; 01155 01156 if (PoolType == PagedPool) { 01157 01158 // 01159 // Check commit limit and make sure at least 1mb is available. 01160 // Check to make sure 4mb of paged pool still exists. 01161 // 01162 01163 PagedPoolInfo = &MmPagedPoolInfo; 01164 01165 if ((MmSizeOfPagedPoolInBytes >> PAGE_SHIFT) < 01166 (PagedPoolInfo->AllocatedPagedPool + ((MMPAGED_QUOTA_CHECK) >> PAGE_SHIFT))) { 01167 01168 return FALSE; 01169 } 01170 01171 MmTotalPagedPoolQuota += (MMPAGED_QUOTA_INCREASE); 01172 *NewQuotaLimit = OldQuotaLimit + (MMPAGED_QUOTA_INCREASE); 01173 return TRUE; 01174 01175 } else { 01176 01177 if ( (ULONG_PTR)(MmAllocatedNonPagedPool + ((1*1024*1024) >> PAGE_SHIFT)) < (MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT)) { 01178 goto aok; 01179 } 01180 01181 // 01182 // Make sure 200 pages and 5mb of nonpaged pool expansion 01183 // available. Raise quota by 64k. 01184 // 01185 01186 if ((MmAvailablePages < 200) || 01187 (MmResidentAvailablePages < ((MMNONPAGED_QUOTA_CHECK) >> PAGE_SHIFT))) { 01188 01189 return FALSE; 01190 } 01191 01192 if (MmAvailablePages > ((4*1024*1024) >> PAGE_SHIFT)) { 01193 Limit = (1*1024*1024) >> PAGE_SHIFT; 01194 } else { 01195 Limit = (4*1024*1024) >> PAGE_SHIFT; 01196 } 01197 01198 if ((ULONG_PTR)((MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT)) < 01199 (MmAllocatedNonPagedPool + Limit)) { 01200 01201 return FALSE; 01202 } 01203 aok: 01204 MmTotalNonPagedPoolQuota += (MMNONPAGED_QUOTA_INCREASE); 01205 *NewQuotaLimit = OldQuotaLimit + (MMNONPAGED_QUOTA_INCREASE); 01206 return TRUE; 01207 } 01208 }

VOID MmReturnPoolQuota IN POOL_TYPE  PoolType,
IN SIZE_T  ReturnedQuota
 

Definition at line 1212 of file mmquota.c.

References MmTotalNonPagedPoolQuota, MmTotalPagedPoolQuota, and PagedPool.

Referenced by PsReturnPoolQuota().

01219 : 01220 01221 Returns pool quota. 01222 01223 Arguments: 01224 01225 PoolType - Supplies the pool type of the quota to be returned. 01226 01227 ReturnedQuota - Number of bytes returned. 01228 01229 Return Value: 01230 01231 NONE. 01232 01233 Environment: 01234 01235 Kernel mode, QUOTA SPIN LOCK HELD!! 01236 01237 --*/ 01238 01239 { 01240 01241 if (PoolType == PagedPool) { 01242 MmTotalPagedPoolQuota -= ReturnedQuota; 01243 } else { 01244 MmTotalNonPagedPoolQuota -= ReturnedQuota; 01245 } 01246 01247 return; 01248 } }


Variable Documentation

LOGICAL MiCommitExtensionActive = FALSE
 

Definition at line 39 of file mmquota.c.

Referenced by MiCauseOverCommitPopup(), and MiReturnCommitment().

ULONG MiOverCommitCallCount
 

Definition at line 45 of file mmquota.c.

Referenced by MiCauseOverCommitPopup().

ULONG_PTR MmAllocatedPagedPool
 

Definition at line 41 of file mmquota.c.

SIZE_T MmExtendedCommit
 

Definition at line 35 of file mmquota.c.

SIZE_T MmExtendedCommitLimit
 

Definition at line 37 of file mmquota.c.

Referenced by MiCauseOverCommitPopup(), and MiReturnCommitment().

SIZE_T MmPageFileFullExtendPages
 

Definition at line 43 of file mmquota.c.

Referenced by MiCauseOverCommitPopup(), MiChargeCommitment(), MiExtendPagingFiles(), MiPageFileFull(), and MiReturnCommitment().

SIZE_T MmPeakCommitment
 

Definition at line 33 of file mmquota.c.

SIZE_T MmTotalNonPagedPoolQuota
 

Definition at line 1115 of file mmquota.c.

Referenced by MmRaisePoolQuota(), and MmReturnPoolQuota().

SIZE_T MmTotalPagedPoolQuota
 

Definition at line 1114 of file mmquota.c.

Referenced by MmRaisePoolQuota(), and MmReturnPoolQuota().

EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock
 

Definition at line 46 of file mmquota.c.

Referenced by MiChargePageFileQuota(), MiReturnPageFileQuota(), ObInitSystem(), PsChargePoolQuota(), PsChargeSharedPoolQuota(), PspInheritQuota(), PspQueryQuotaLimits(), PspSetQuotaLimits(), and PsReturnPoolQuota().


Generated on Sat May 15 19:44:47 2004 for test by doxygen 1.3.7